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