1 /*
2  * Copyright (c) 2018 Intel Corporation
3  *
4  * SPDX-License-Identifier: Apache-2.0
5  */
6 
7 #include <zephyr/ztest.h>
8 #include <zephyr/kernel.h>
9 #include <zephyr/test_toolchain.h>
10 
11 #define STACKSIZE       2048
12 #define THREAD_COUNT	64
13 #define VERBOSE		0
14 
15 void *last_sp = (void *)0xFFFFFFFF;
16 volatile unsigned int changed;
17 
18 /*
19  * The `alternate_thread` function deliberately makes use of a dangling pointer
20  * in order to test stack randomisation.
21  */
TOOLCHAIN_DISABLE_GCC_WARNING(TOOLCHAIN_WARNING_DANGLING_POINTER)22 TOOLCHAIN_DISABLE_GCC_WARNING(TOOLCHAIN_WARNING_DANGLING_POINTER)
23 
24 void alternate_thread(void *p1, void *p2, void *p3)
25 {
26 	ARG_UNUSED(p1);
27 	ARG_UNUSED(p2);
28 	ARG_UNUSED(p3);
29 
30 	int i;
31 	void *sp_val;
32 
33 	/* If the stack isn't being randomized then sp_val will never change */
34 	sp_val = &i;
35 
36 #if VERBOSE
37 	printk("stack pointer: %p last: %p\n", sp_val, last_sp);
38 #endif
39 
40 	if (last_sp != (void *)0xFFFFFFFF && sp_val != last_sp) {
41 		changed++;
42 	}
43 	last_sp = sp_val;
44 }
45 
46 TOOLCHAIN_ENABLE_GCC_WARNING(TOOLCHAIN_WARNING_DANGLING_POINTER)
47 
48 K_THREAD_STACK_DEFINE(alt_thread_stack_area, STACKSIZE);
49 static struct k_thread alt_thread_data;
50 
51 /**
52  * @brief Test stack pointer randomization
53  *
54  * @ingroup kernel_memprotect_tests
55  *
56  */
ZTEST(stack_pointer_randomness,test_stack_pt_randomization)57 ZTEST(stack_pointer_randomness, test_stack_pt_randomization)
58 {
59 	int i, sp_changed;
60 	int old_prio = k_thread_priority_get(k_current_get());
61 
62 	/* Set preemptable priority */
63 	k_thread_priority_set(k_current_get(), K_PRIO_PREEMPT(1));
64 
65 	printk("Test Stack pointer randomization\n");
66 
67 	/* Start thread */
68 	for (i = 0; i < THREAD_COUNT; i++) {
69 		k_thread_create(&alt_thread_data, alt_thread_stack_area,
70 				STACKSIZE, alternate_thread,
71 				NULL, NULL, NULL, K_HIGHEST_THREAD_PRIO, 0,
72 				K_NO_WAIT);
73 		k_sleep(K_MSEC(10));
74 	}
75 
76 
77 	printk("stack pointer changed %d times out of %d tests\n",
78 	       changed, THREAD_COUNT);
79 
80 	sp_changed = changed;
81 	zassert_not_equal(sp_changed, 0, "Stack pointer is not randomized");
82 
83 	/* Restore priority */
84 	k_thread_priority_set(k_current_get(), old_prio);
85 }
86 
87 ZTEST_SUITE(stack_pointer_randomness, NULL, NULL,
88 		ztest_simple_1cpu_before, ztest_simple_1cpu_after, NULL);
89