1 /*
2  * Copyright (c) 2012-2014 Wind River Systems, Inc.
3  * Copyright (c) 2016 Intel Corporation
4  *
5  * SPDX-License-Identifier: Apache-2.0
6  */
7 
8 
9 #include <zephyr/kernel.h>
10 #include <zephyr/toolchain.h>
11 #include <zephyr/ztest.h>
12 
13 
14 #define STACKSIZE       (2048 + CONFIG_TEST_EXTRA_STACK_SIZE)
15 
16 ZTEST_BMEM static int count;
17 ZTEST_BMEM static int ret = TC_PASS;
18 
k_sys_fatal_error_handler(unsigned int reason,const struct arch_esf * esf)19 void k_sys_fatal_error_handler(unsigned int reason, const struct arch_esf *esf)
20 {
21 	if (reason != K_ERR_STACK_CHK_FAIL) {
22 		printk("wrong error type\n");
23 		TC_END_REPORT(TC_FAIL);
24 		k_fatal_halt(reason);
25 	}
26 }
27 
28 void check_input(const char *name, const char *input);
29 
30 /**
31  *
32  * print_loop
33  *
34  * This function calls check_input 6 times with the input name and a short
35  * string, which is printed properly by check_input.
36  *
37  * @param name    caller identification string
38  *
39  */
40 
print_loop(const char * name)41 void print_loop(const char *name)
42 {
43 	while (count < 6) {
44 		/* A short input string to check_input.  It will pass. */
45 		check_input(name, "Stack ok");
46 		count++;
47 	}
48 }
49 
50 /**
51  *
52  * check_input
53  *
54  * This function copies the input string to a buffer of 16 characters and
55  * prints the name and buffer as a string.  If the input string is longer
56  * than the buffer, an error condition is detected.
57  *
58  * When stack protection feature is enabled (see prj.conf file), the
59  * system error handler is invoked and reports a "Stack Check Fail" error.
60  * When stack protection feature is not enabled, the system crashes with
61  * error like: Trying to execute code outside RAM or ROM.
62  *
63  */
64 
check_input(const char * name,const char * input)65 void __noinline check_input(const char *name, const char *input)
66 {
67 	/* Stack will overflow when input is more than 16 characters */
68 	char buf[16];
69 
70 	strcpy(buf, input);
71 	TC_PRINT("%s: %s\n", name, buf);
72 }
73 
74 /**
75  *
76  * This thread passes a long string to check_input function.  It terminates due
77  * to stack overflow and reports "Stack Check Fail" when stack protection
78  * feature is enabled.  Hence it will not execute the print_loop function
79  * and will not set ret to TC_FAIL.
80  *
81  */
alternate_thread(void * p1,void * p2,void * p3)82 void alternate_thread(void *p1, void *p2, void *p3)
83 {
84 	ARG_UNUSED(p1);
85 	ARG_UNUSED(p2);
86 	ARG_UNUSED(p3);
87 	/*
88 	 * Padding buffer to absorb the intentional overflow inside the thread stack.
89 	 * This prevents writes from crossing the thread stack boundary into the next
90 	 * MPU-protected region. Required to make the test independent of compiler-
91 	 * specific stack frame layouts.
92 	 */
93 	volatile __unused char overflow_guard_area[32] = "Forcing Initialization!";
94 
95 	TC_PRINT("Starts %s\n", __func__);
96 	check_input(__func__,
97 		    "Input string is too long and stack overflowed!\n");
98 	/*
99 	 * Expect this thread to terminate due to stack check fail and will not
100 	 * execute pass here.
101 	 */
102 	print_loop(__func__);
103 
104 	ret = TC_FAIL;
105 }
106 
107 
108 
109 K_THREAD_STACK_DEFINE(alt_thread_stack_area, STACKSIZE);
110 static struct k_thread alt_thread_data;
111 
112 /**
113  * @brief test Stack Protector feature using canary
114  *
115  * @details This is the test program to test stack protection using canary.
116  * The main thread starts a second thread, which generates a stack check
117  * failure.
118  * By design, the second thread will not complete its execution and
119  * will not set ret to TC_FAIL.
120  * This is the entry point to the test stack protection feature.
121  * It starts the thread that tests stack protection, then prints out
122  * a few messages before terminating.
123  *
124  * @ingroup kernel_memprotect_tests
125  */
ZTEST_USER(stackprot,test_stackprot)126 ZTEST_USER(stackprot, test_stackprot)
127 {
128 	zassert_true(ret == TC_PASS);
129 	print_loop(__func__);
130 }
131 
132 /**
133  * @brief Test optional mechanism to detect stack overflow
134  *
135  * @details Test that the system provides an optional mechanism to detect
136  * when supervisor threads overflow stack memory buffer.
137  *
138  * @ingroup kernel_memprotect_tests
139  */
ZTEST(stackprot,test_create_alt_thread)140 ZTEST(stackprot, test_create_alt_thread)
141 {
142 	/* Start thread */
143 	k_thread_create(&alt_thread_data, alt_thread_stack_area, STACKSIZE,
144 			alternate_thread, NULL, NULL, NULL,
145 			K_PRIO_COOP(1), K_USER, K_NO_WAIT);
146 
147 	/* Note that this sleep is required on SMP platforms where
148 	 * that thread will execute asynchronously!
149 	 */
150 	k_sleep(K_MSEC(100));
151 }
152 
153 #ifdef CONFIG_STACK_CANARIES_TLS
154 extern Z_THREAD_LOCAL volatile uintptr_t __stack_chk_guard;
155 #else
156 extern volatile uintptr_t __stack_chk_guard;
157 #endif
158 
159 /**
160  * This thread checks its canary value against its parent canary.
161  * If CONFIG_STACK_CANARIES_TLS is enabled, it is expected that the
162  * canaries have different values, otherwise there is only one global
163  * canary and the value should be the same.
164  */
alternate_thread_canary(void * arg1,void * arg2,void * arg3)165 void alternate_thread_canary(void *arg1, void *arg2, void *arg3)
166 {
167 	ARG_UNUSED(arg2);
168 	ARG_UNUSED(arg3);
169 
170 	TC_PRINT("Starts %s\n", __func__);
171 
172 #ifdef CONFIG_STACK_CANARIES_TLS
173 	zassert_false(__stack_chk_guard == (uintptr_t)arg1);
174 #else
175 	zassert_true(__stack_chk_guard == (uintptr_t)arg1);
176 #endif
177 }
178 
179 /**
180  * @brief Test stack canaries behavior
181  *
182  * @details Test that canaries value are different between threads when
183  * CONFIG_STACK_CANARIES_TLS is enabled.
184  *
185  * @ingroup kernel_memprotect_tests
186  */
ZTEST(stackprot,test_canary_value)187 ZTEST(stackprot, test_canary_value)
188 {
189 	/* Start thread */
190 	k_thread_create(&alt_thread_data, alt_thread_stack_area, STACKSIZE,
191 			alternate_thread_canary,
192 			(void *)__stack_chk_guard, NULL, NULL,
193 			K_PRIO_COOP(1), K_USER, K_NO_WAIT);
194 
195 	/* Note that this sleep is required on SMP platforms where
196 	 * that thread will execute asynchronously!
197 	 */
198 	k_sleep(K_MSEC(100));
199 }
200 
201 ZTEST_SUITE(stackprot, NULL, NULL, NULL, NULL, NULL);
202