blob: b36708b3402c9517d656fb38197db8664a537d5c [file] [log] [blame]
/*
* SafeStack unsafe stack management
*
* Copyright (C) 2017 Google, Inc.
*/
#include <linux/sched.h>
#include <linux/safestack.h>
#include <linux/mm.h>
#include <linux/memcontrol.h>
#include <linux/slab.h>
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;
}