From 636f609d66e82c62eba6f7df45006f5d41cf929c Mon Sep 17 00:00:00 2001 From: Andrew Boie Date: Thu, 11 May 2017 16:13:32 -0700 Subject: [PATCH] tests: kernel: fatal: check stack overflow For all arches except ARC, enable stack sentinel and test that some common stack violations trigger exceptions. For ARC, use the hardware stack checking feature. Additional testcase.ini blocks may be added to do stack bounds checking for MMU/MPU-based stack protection schemes. Signed-off-by: Andrew Boie --- tests/kernel/fatal/prj-arc.conf | 1 + tests/kernel/fatal/prj.conf | 2 +- tests/kernel/fatal/src/main.c | 90 +++++++++++++++++++++++++++++++-- tests/kernel/fatal/testcase.ini | 11 +++- 4 files changed, 99 insertions(+), 5 deletions(-) create mode 100644 tests/kernel/fatal/prj-arc.conf diff --git a/tests/kernel/fatal/prj-arc.conf b/tests/kernel/fatal/prj-arc.conf new file mode 100644 index 00000000000..0ed7ef8429d --- /dev/null +++ b/tests/kernel/fatal/prj-arc.conf @@ -0,0 +1 @@ +CONFIG_ARC_STACK_CHECKING=y diff --git a/tests/kernel/fatal/prj.conf b/tests/kernel/fatal/prj.conf index 753149797b4..1bf885697e9 100644 --- a/tests/kernel/fatal/prj.conf +++ b/tests/kernel/fatal/prj.conf @@ -1,2 +1,2 @@ -CONFIG_MAIN_THREAD_PRIORITY=7 +CONFIG_STACK_SENTINEL=y diff --git a/tests/kernel/fatal/src/main.c b/tests/kernel/fatal/src/main.c index 8590d6f8d75..160243ee6c7 100644 --- a/tests/kernel/fatal/src/main.c +++ b/tests/kernel/fatal/src/main.c @@ -9,10 +9,19 @@ #include #include -#define STACKSIZE 1024 +#define STACKSIZE 2048 +#define MAIN_PRIORITY 7 #define PRIORITY 5 static char __noinit __stack alt_stack[STACKSIZE]; + +#ifdef CONFIG_STACK_SENTINEL +#define OVERFLOW_STACKSIZE 1024 +static char *overflow_stack = alt_stack + (STACKSIZE - OVERFLOW_STACKSIZE); +#else +#define OVERFLOW_STACKSIZE STACKSIZE +#endif + static struct k_thread alt_thread; volatile int rv; @@ -39,8 +48,44 @@ void alt_thread1(void) void alt_thread2(void) { + int key; + + key = irq_lock(); k_oops(); rv = TC_FAIL; + irq_unlock(key); +} + + +void blow_up_stack(void) +{ + char buf[OVERFLOW_STACKSIZE]; + printk("posting %zu bytes of junk to stack...\n", sizeof(buf)); + memset(buf, 0xbb, sizeof(buf)); +} + +void stack_thread1(void) +{ + /* Test that stack overflow check due to timer interrupt works */ + blow_up_stack(); + printk("busy waiting...\n"); + k_busy_wait(1024 * 1024); + printk("should never see this\n"); + rv = TC_FAIL; +} + + +void stack_thread2(void) +{ + int key = irq_lock(); + + /* Test that stack overflow check due to swap works */ + blow_up_stack(); + printk("swapping...\n"); + _Swap(irq_lock()); + printk("should never see this\n"); + rv = TC_FAIL; + irq_unlock(key); } @@ -50,8 +95,10 @@ void main(void) TC_START("test_fatal"); + k_thread_priority_set(_current, K_PRIO_PREEMPT(MAIN_PRIORITY)); + printk("test alt thread 1: generic CPU exception\n"); - k_thread_create(&alt_thread, alt_stack, STACKSIZE, + k_thread_create(&alt_thread, alt_stack, sizeof(alt_stack), (k_thread_entry_t)alt_thread1, NULL, NULL, NULL, K_PRIO_PREEMPT(PRIORITY), 0, K_NO_WAIT); @@ -63,7 +110,7 @@ void main(void) } printk("test alt thread 2: initiate kernel oops\n"); - k_thread_create(&alt_thread, alt_stack, STACKSIZE, + k_thread_create(&alt_thread, alt_stack, sizeof(alt_stack), (k_thread_entry_t)alt_thread2, NULL, NULL, NULL, K_PRIO_PREEMPT(PRIORITY), 0, K_NO_WAIT); @@ -74,6 +121,43 @@ void main(void) printk("PASS\n"); } + printk("test stack overflow - timer irq\n"); +#ifdef CONFIG_STACK_SENTINEL + /* When testing stack sentinel feature, the overflow stack is a + * smaller section of alt_stack near the end. + * In this way when it gets overflowed by blow_up_stack() we don't + * corrupt anything else and prevent the test case from completing. + */ + k_thread_create(&alt_thread, overflow_stack, OVERFLOW_STACKSIZE, +#else + k_thread_create(&alt_thread, alt_stack, sizeof(alt_stack), +#endif + (k_thread_entry_t)stack_thread1, + NULL, NULL, NULL, K_PRIO_PREEMPT(PRIORITY), 0, + K_NO_WAIT); + if (rv == TC_FAIL) { + printk("thread was not aborted\n"); + goto out; + } else { + printk("PASS\n"); + } + + printk("test stack overflow - swap\n"); +#ifdef CONFIG_STACK_SENTINEL + k_thread_create(&alt_thread, overflow_stack, OVERFLOW_STACKSIZE, +#else + k_thread_create(&alt_thread, alt_stack, sizeof(alt_stack), +#endif + (k_thread_entry_t)stack_thread2, + NULL, NULL, NULL, K_PRIO_PREEMPT(PRIORITY), 0, + K_NO_WAIT); + if (rv == TC_FAIL) { + printk("thread was not aborted\n"); + goto out; + } else { + printk("PASS\n"); + } + out: TC_END_RESULT(rv); TC_END_REPORT(rv); diff --git a/tests/kernel/fatal/testcase.ini b/tests/kernel/fatal/testcase.ini index 63fbe6d020c..b97fd35be26 100644 --- a/tests/kernel/fatal/testcase.ini +++ b/tests/kernel/fatal/testcase.ini @@ -1,2 +1,11 @@ -[test] +# Uses CONFIG_STACK_SENTINEL +[stack-sentinel] tags = core ignore_faults +arch_exclude = arc + +# Uses CONFIG_ARC_STACK_CHECKING +[arc-stack-checking] +tags = core ignore_faults +extra_args = CONF_FILE=prj-arc.conf +arch_whitelist = arc +