1 /*
2 * Copyright (c) 2021, Google Inc. All rights reserved
3 *
4 * Permission is hereby granted, free of charge, to any person obtaining
5 * a copy of this software and associated documentation files
6 * (the "Software"), to deal in the Software without restriction,
7 * including without limitation the rights to use, copy, modify, merge,
8 * publish, distribute, sublicense, and/or sell copies of the Software,
9 * and to permit persons to whom the Software is furnished to do so,
10 * subject to the following conditions:
11 *
12 * The above copyright notice and this permission notice shall be
13 * included in all copies or substantial portions of the Software.
14 *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
16 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
18 * IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
19 * CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
20 * TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
21 * SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
22 */
23
24 #include <err.h>
25 #include <kernel/thread.h>
26 #include <kernel/vm.h>
27 #include <lib/unittest/unittest.h>
28 #include <lib/mmutest/mmutest.h>
29
30 #if KERNEL_SCS_ENABLED
31 #define FEATURE_GATED_TEST_NAME(name) name
32
33 /**
34 * inspect_thread() - Inspect the shadow stack of a thread
35 *
36 * @t: thread to test
37 * @ss_sz: expected shadow stack size
38 */
inspect_thread(thread_t * t,size_t ss_sz)39 static void inspect_thread(thread_t *t, size_t ss_sz) {
40 /* all threads have a shadow stack when the feature is enabled */
41 ASSERT_NE(NULL, t->shadow_stack, "Shadow call stack missing");
42 ASSERT_EQ(true, is_kernel_address((vaddr_t)t->shadow_stack),
43 "Shadow call stack does not point to kernel memory");
44 EXPECT_EQ(t->shadow_stack_size,
45 round_up(t->shadow_stack_size, sizeof(vaddr_t)),
46 "Shadow call stack size was not rounded to the pointer size");
47 EXPECT_NE(t->stack, t->shadow_stack,
48 "Shadow call stack aliases the regular stack");
49 EXPECT_EQ(ss_sz, t->shadow_stack_size,
50 "Shadow call stack did not have the expected size");
51
52 /* check the shadow stack size by inverting the last element */
53 void* last_elem = t->shadow_stack + t->shadow_stack_size - sizeof(vaddr_t);
54 EXPECT_EQ(NO_ERROR,
55 mmutest_arch_store_uint32((uint32_t*)last_elem, false),
56 "Actual size of shadow call stack differs from recorded size");
57 /* restore last_elem by calling mmutest_arch_store_uint32 a second time */
58 EXPECT_EQ(NO_ERROR,
59 mmutest_arch_store_uint32((uint32_t*)last_elem, false),
60 "Restoring last element of shadow stack failed");
61
62 const size_t extra_space = round_up(t->shadow_stack_size, PAGE_SIZE) -
63 t->shadow_stack_size;
64 void *const guard_region = t->shadow_stack - extra_space;
65 EXPECT_EQ(0, (vaddr_t)guard_region & (PAGE_SIZE - 1),
66 "Shadow call stack guard region is not page aligned");
67
68 /* check for guard page before the shadow stack */
69 void* before_guard_end = guard_region - sizeof(uint32_t);
70 ASSERT_EQ(ERR_GENERIC,
71 mmutest_arch_store_uint32((uint32_t*)before_guard_end, false),
72 "Expected guard page after shadow call stack");
73
74 /* check for guard page after the shadow stack */
75 void *after_guard_begin = t->shadow_stack + t->shadow_stack_size;
76 ASSERT_EQ(ERR_GENERIC,
77 mmutest_arch_store_uint32((uint32_t*)after_guard_begin, false),
78 "Expected guard page after shadow call stack");
79
80 /*
81 * this test will not run on idle threads which are the only
82 * threads that do not have the free shadow stack flag set.
83 */
84 ASSERT_EQ(0, t->flags & THREAD_FLAG_IDLE, "Thread is an idle thread");
85 EXPECT_NE(0, t->flags & THREAD_FLAG_FREE_SHADOW_STACK,
86 "Shadow call stack did not have the free flag set");
87
88 /*
89 * Shadow stacks grow up. Test that the shadow stack is set up such that
90 * we'll hit the guard page once we use the number of bytes corresponding
91 * to the shadow stack size even if more bytes were allocated. We do so
92 * by checking that all bytes are zero (i.e., unused) in the interval
93 * [guard_region...t->shadow_stack).
94 */
95 vaddr_t *slot = (vaddr_t *)guard_region;
96 while (slot < (vaddr_t*)t->shadow_stack) {
97 ASSERT_EQ(0, *slot++, "Expected unused shadow call stack slot");
98 }
99
100 /* shadow stack slots are either unused or point to kernel memory */
101 while (slot < (vaddr_t*)after_guard_begin) {
102 vaddr_t ret_addr = *slot++;
103 if (!ret_addr)
104 continue; /* slot is unused */
105 ASSERT_EQ(true, is_kernel_address(ret_addr),
106 "Expected pointer to kernel memory");
107 }
108
109 test_abort:;
110 }
111 #else
112 #define FEATURE_GATED_TEST_NAME(name) DISABLED_##name
113
inspect_thread(thread_t * t,size_t ss_sz)114 static void inspect_thread(thread_t *t, size_t ss_sz) { }
115 #endif
116
TEST(scstest,FEATURE_GATED_TEST_NAME (current_kernel_thread_has_scs))117 TEST(scstest, FEATURE_GATED_TEST_NAME(current_kernel_thread_has_scs)) {
118 thread_t *curr_thread = get_current_thread();
119 inspect_thread(curr_thread, DEFAULT_SHADOW_STACK_SIZE);
120 }
121
new_thread_func(void * arg)122 static int new_thread_func(void* arg) {
123 size_t expected_shadow_stack_size = *(size_t*)arg;
124 thread_t *curr_thread = get_current_thread();
125 inspect_thread(curr_thread, expected_shadow_stack_size);
126 return 0;
127 }
128
TEST(scstest,FEATURE_GATED_TEST_NAME (new_kernel_thread_has_scs))129 TEST(scstest, FEATURE_GATED_TEST_NAME(new_kernel_thread_has_scs)) {
130 int test_thread_ret;
131 size_t shadow_stack_size = DEFAULT_SHADOW_STACK_SIZE;
132 thread_t* test_thread =
133 thread_create("scstest_thread", new_thread_func,
134 &shadow_stack_size, DEFAULT_PRIORITY,
135 DEFAULT_STACK_SIZE);
136 ASSERT_NE(NULL, test_thread, "Failed to create test thread");
137
138 ASSERT_EQ(NO_ERROR, thread_resume(test_thread), "Failed to start thread");
139
140 ASSERT_EQ(NO_ERROR,
141 thread_join(test_thread, &test_thread_ret, INFINITE_TIME),
142 "Failed to wait on test thread");
143 /* test_thread is deallocated here, do inspection in new_thread_func */
144
145 test_abort:;
146 }
147
TEST(scstest,FEATURE_GATED_TEST_NAME (new_kernel_thread_has_custom_size))148 TEST(scstest, FEATURE_GATED_TEST_NAME(new_kernel_thread_has_custom_size)) {
149 int test_thread_ret;
150 size_t expected_shadow_stack_size = 128;
151 thread_t* test_thread =
152 thread_create_etc(NULL, "scstest_thread", new_thread_func,
153 &expected_shadow_stack_size, DEFAULT_PRIORITY,
154 NULL, DEFAULT_STACK_SIZE,
155 expected_shadow_stack_size);
156 ASSERT_NE(NULL, test_thread, "Failed to create test thread");
157
158 ASSERT_EQ(NO_ERROR, thread_resume(test_thread), "Failed to start thread");
159
160 ASSERT_EQ(NO_ERROR,
161 thread_join(test_thread, &test_thread_ret, INFINITE_TIME),
162 "Failed to wait on test thread");
163
164 test_abort:;
165 }
166
167 PORT_TEST(scstest, "com.android.kernel.scstest");
168