kernel: introduce initial stack randomization

This is a component of address space layout randomization that we can
implement even though we have a physical address space.

Support for upward-growing stacks omitted for now, it's not done
currently on any of our current or planned architectures.

Signed-off-by: Andrew Boie <andrew.p.boie@intel.com>
This commit is contained in:
Andrew Boie 2018-03-02 07:54:13 -08:00 committed by Andrew Boie
commit 83752c1cfe
6 changed files with 109 additions and 0 deletions

View file

@ -564,6 +564,26 @@ config EXECUTE_XOR_WRITE
If unsure, say Y.
config STACK_POINTER_RANDOM
int
prompt "Initial stack pointer randomization bounds"
depends on !STACK_GROWS_UP
default 0
help
This option performs a limited form of Address Space Layout
Randomization by offsetting some random value to a thread's
initial stack pointer upon creation. This hinders some types of
security attacks by making the location of any given stack frame
non-deterministic.
This feature can waste up to the specified size in bytes the stack
region, which is carved out of the total size of the stack region.
A reasonable minimum value would be around 100 bytes if this can
be spared.
This is currently only implemented for systems whose stack pointers
grow towards lower memory addresses.
endmenu
config MAX_DOMAIN_PARTITIONS

View file

@ -270,6 +270,19 @@ void _setup_new_thread(struct k_thread *new_thread,
void *p1, void *p2, void *p3,
int prio, u32_t options)
{
#if CONFIG_STACK_POINTER_RANDOM
#if defined(CONFIG_STACK_GROWS_UP)
/* This is so rare not bothering for now */
#error "Stack pointer randomization not implemented for upward growing stacks"
#endif
/* Don't need to worry about alignment of the size here, _new_thread()
* is required to do it
*
* FIXME: Not the best way to get a random number in a range.
* See #6493
*/
stack_size -= sys_rand32_get() % CONFIG_STACK_POINTER_RANDOM;
#endif /* CONFIG_STACK_POINTER_RANDOM */
_new_thread(new_thread, stack, stack_size, entry, p1, p2, p3,
prio, options);
#ifdef CONFIG_USERSPACE

View file

@ -0,0 +1,5 @@
include($ENV{ZEPHYR_BASE}/cmake/app/boilerplate.cmake NO_POLICY_SCOPE)
project(NONE)
FILE(GLOB app_sources src/*.c)
target_sources(app PRIVATE ${app_sources})

View file

@ -0,0 +1,4 @@
CONFIG_TEST=y
CONFIG_STACK_POINTER_RANDOM=64
CONFIG_ENTROPY_GENERATOR=y
CONFIG_TEST_RANDOM_GENERATOR=y

View file

@ -0,0 +1,63 @@
/*
* Copyright (c) 2018 Intel Corporation
*
* SPDX-License-Identifier: Apache-2.0
*/
#include <tc_util.h>
#include <zephyr.h>
#define STACKSIZE 2048
#define THREAD_COUNT 64
#define VERBOSE 0
void *last_sp = (void *)0xFFFFFFFF;
unsigned int changed;
void alternate_thread(void)
{
int i;
void *sp_val;
/* If the stack isn't being randomized then sp_val will never change */
sp_val = &i;
#if VERBOSE
printk("stack pointer: %p last: %p\n", sp_val, last_sp);
#endif
if (last_sp != (void *)0xFFFFFFFF && sp_val != last_sp) {
changed++;
}
last_sp = sp_val;
}
K_THREAD_STACK_DEFINE(alt_thread_stack_area, STACKSIZE);
static struct k_thread alt_thread_data;
void main(void)
{
int i, ret = TC_FAIL;
TC_START("Test Stack pointer randomization\n");
/* Start thread */
for (i = 0; i < THREAD_COUNT; i++) {
k_thread_create(&alt_thread_data, alt_thread_stack_area,
STACKSIZE, (k_thread_entry_t)alternate_thread,
NULL, NULL, NULL, K_HIGHEST_THREAD_PRIO, 0,
K_NO_WAIT);
}
printk("stack pointer changed %d times out of %d tests\n",
changed, THREAD_COUNT);
if (changed) {
ret = TC_PASS;
}
TC_END_RESULT(ret);
TC_END_REPORT(ret);
}

View file

@ -0,0 +1,4 @@
tests:
kernel.memory_protection.stack_random:
arch_exclude: posix
tags: core