/* * SafeStack unsafe stack management * * Copyright (C) 2017 Google, Inc. */ #include #include #include #include #include static struct kmem_cache *unsafe_stack_cache; void init_unsafe_stack_cache() { unsafe_stack_cache = kmem_cache_create("unsafe_stack", UNSAFE_STACK_SIZE, UNSAFE_STACK_ALIGN, 0, NULL); BUG_ON(unsafe_stack_cache == NULL); } int alloc_unsafe_stack(struct task_struct *tsk, int node) { struct page *first; void *stack; stack = kmem_cache_alloc_node(unsafe_stack_cache, THREADINFO_GFP | __GFP_ZERO, node); if (unlikely(!stack)) return -ENOMEM; first = virt_to_page(stack); /* account as kernel stack */ mod_zone_page_state(page_zone(first), NR_KERNEL_STACK_KB, UNSAFE_STACK_SIZE / 1024); memcg_kmem_update_page_stat(first, MEMCG_KERNEL_STACK_KB, UNSAFE_STACK_SIZE / 1024); tsk->unsafe_stack = stack; tsk->unsafe_stack_ptr = stack + UNSAFE_STACK_SIZE; tsk->unsafe_saved_ptr = NULL; return 0; } void free_unsafe_stack(struct task_struct *tsk) { struct page *first; if (unlikely(!tsk->unsafe_stack)) return; first = virt_to_page(tsk->unsafe_stack); mod_zone_page_state(page_zone(first), NR_KERNEL_STACK_KB, -(long)UNSAFE_STACK_SIZE / 1024); memcg_kmem_update_page_stat(first, MEMCG_KERNEL_STACK_KB, -(long)UNSAFE_STACK_SIZE / 1024); kmem_cache_free(unsafe_stack_cache, tsk->unsafe_stack); tsk->unsafe_stack = NULL; tsk->unsafe_stack_ptr = NULL; tsk->unsafe_saved_ptr = NULL; }