diff --git a/tests/kernel/stackprot/Makefile b/tests/kernel/stackprot/Makefile new file mode 100644 index 00000000000..4de50f93d4d --- /dev/null +++ b/tests/kernel/stackprot/Makefile @@ -0,0 +1,4 @@ +BOARD ?= qemu_x86 +CONF_FILE = prj.conf + +include ${ZEPHYR_BASE}/Makefile.inc diff --git a/tests/kernel/stackprot/README.txt b/tests/kernel/stackprot/README.txt new file mode 100644 index 00000000000..101979d8bd4 --- /dev/null +++ b/tests/kernel/stackprot/README.txt @@ -0,0 +1,54 @@ +Title: Stack Protection Support + +Description: + +This test verifies that stack canaries operate as expected in the microkernel. + +-------------------------------------------------------------------------------- + +Building and Running Project: + +This microkernel project outputs to the console. It can be built and executed +on QEMU as follows: + + make qemu + +-------------------------------------------------------------------------------- + +Troubleshooting: + +Problems caused by out-dated project information can be addressed by +issuing one of the following commands then rebuilding the project: + + make clean # discard results of previous builds + # but keep existing configuration info +or + make pristine # discard results of previous builds + # and restore pre-defined configuration info + +-------------------------------------------------------------------------------- + +Sample Output: +tc_start() - Test Stack Protection Canary + +Starts main +Starts alternate_thread +alternate_thread: Input string is too long and stack overflowed! + +***** Stack Check Fail! ***** +Current thread ID = 0x00103180 +Faulting segment:address = 0xdead:0xdeaddead +eax: 0xdeaddead, ebx: 0xdeaddead, ecx: 0xdeaddead, edx: 0xdeaddead +esi: 0xdeaddead, edi: 0xdeaddead, ebp: 0deaddead, esp: 0xdeaddead +eflags: 0xdeaddead +Fatal fault in thread 0x00103180! Aborting. +main: Stack ok +main: Stack ok +main: Stack ok +main: Stack ok +main: Stack ok +main: Stack ok +=================================================================== +PASS - main. +=================================================================== +PROJECT EXECUTION SUCCESSFUL diff --git a/tests/kernel/stackprot/prj.conf b/tests/kernel/stackprot/prj.conf new file mode 100644 index 00000000000..e1a8496f311 --- /dev/null +++ b/tests/kernel/stackprot/prj.conf @@ -0,0 +1,4 @@ +CONFIG_STACK_CANARIES=y +CONFIG_RANDOM_GENERATOR=y +CONFIG_TEST_RANDOM_GENERATOR=y +CONFIG_MAIN_THREAD_PRIORITY=7 diff --git a/tests/kernel/stackprot/src/Makefile b/tests/kernel/stackprot/src/Makefile new file mode 100644 index 00000000000..2b356966312 --- /dev/null +++ b/tests/kernel/stackprot/src/Makefile @@ -0,0 +1,3 @@ +ccflags-y += -I${ZEPHYR_BASE}/tests/include + +obj-y = main.o diff --git a/tests/kernel/stackprot/src/main.c b/tests/kernel/stackprot/src/main.c new file mode 100644 index 00000000000..db0162a0871 --- /dev/null +++ b/tests/kernel/stackprot/src/main.c @@ -0,0 +1,144 @@ +/* + * Copyright (c) 2012-2014 Wind River Systems, Inc. + * Copyright (c) 2016 Intel Corporation + * + * Licensed under the Apache License, Version 2.0 (the "License"); + * you may not use this file except in compliance with the License. + * You may obtain a copy of the License at + * + * http://www.apache.org/licenses/LICENSE-2.0 + * + * Unless required by applicable law or agreed to in writing, software + * distributed under the License is distributed on an "AS IS" BASIS, + * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. + * See the License for the specific language governing permissions and + * limitations under the License. + */ + + +/** + * @brief test Stack Protector feature using canary + * + * This is the test program to test stack protection using canary. + * + * The main thread starts a second thread, which generates a stack check + * failure. + * By design, the second thread will not complete its execution and + * will not set ret to TC_FAIL. + */ + +#include + +#include + + +#define STACKSIZE 2048 +#define PRIORITY 5 + +static int count; +static int ret = TC_PASS; + +void check_input(const char *name, const char *input); + +/** + * + * print_loop + * + * This function calls check_input 6 times with the input name and a short + * string, which is printed properly by check_input. + * + * @param name caller identification string + * + * @return N/A + */ + +void print_loop(const char *name) +{ + while (count < 6) { + /* A short input string to check_input. It will pass. */ + check_input(name, "Stack ok"); + count++; + } +} + +/** + * + * check_input + * + * This function copies the input string to a buffer of 16 characters and + * prints the name and buffer as a string. If the input string is longer + * than the buffer, an error condition is detected. + * + * When stack protection feature is enabled (see prj.conf file), the + * system error handler is invoked and reports a "Stack Check Fail" error. + * When stack protection feature is not enabled, the system crashes with + * error like: Trying to execute code outside RAM or ROM. + * + * @return N/A + */ + +void check_input(const char *name, const char *input) +{ + /* Stack will overflow when input is more than 16 characters */ + char buf[16]; + + strcpy(buf, input); + TC_PRINT("%s: %s\n", name, buf); +} + +/** + * + * This thread passes a long string to check_input function. It terminates due + * to stack overflow and reports "Stack Check Fail" when stack protection + * feature is enabled. Hence it will not execute the print_loop function + * and will not set ret to TC_FAIL. + * + * @return N/A + */ +void alternate_thread(void) +{ + TC_PRINT("Starts %s\n", __func__); + check_input(__func__, + "Input string is too long and stack overflowed!\n"); + /* + * Expect this thread to terminate due to stack check fail and will not + * execute pass here. + */ + print_loop(__func__); + + ret = TC_FAIL; +} + + + +char __noinit __stack alt_thread_stack_area[STACKSIZE]; + +/** + * + * This is the entry point to the test stack protection feature. + * It starts the thread that tests stack protection, then prints out + * a few messages before terminating. + * + * @return N/A + */ + +void main(void) +{ + TC_START("Test Stack Protection Canary\n"); + TC_PRINT("Starts %s\n", __func__); + + /* Start thread */ + k_thread_spawn(alt_thread_stack_area, STACKSIZE, + (k_thread_entry_t)alternate_thread, NULL, NULL, NULL, + K_PRIO_PREEMPT(PRIORITY), 0, K_NO_WAIT); + + if (ret == TC_FAIL) { + goto errorExit; + } + + print_loop(__func__); + +errorExit: + TC_END_RESULT(ret); + TC_END_REPORT(ret); +} diff --git a/tests/kernel/stackprot/testcase.ini b/tests/kernel/stackprot/testcase.ini new file mode 100644 index 00000000000..a9a0dc596cd --- /dev/null +++ b/tests/kernel/stackprot/testcase.ini @@ -0,0 +1,3 @@ +[test] +tags = bat_commit core +arch_exclude = nios2