1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2023 ARM Limited.
4 */
5
6 #include <limits.h>
7 #include <stdbool.h>
8
9 #include <linux/prctl.h>
10
11 #include <sys/mman.h>
12 #include <asm/mman.h>
13 #include <asm/hwcap.h>
14 #include <linux/sched.h>
15
16 #include "kselftest.h"
17 #include "gcs-util.h"
18
19 /* nolibc doesn't have sysconf(), just hard code the maximum */
20 static size_t page_size = 65536;
21
valid_gcs_function(void)22 static __attribute__((noinline)) void valid_gcs_function(void)
23 {
24 /* Do something the compiler can't optimise out */
25 my_syscall1(__NR_prctl, PR_SVE_GET_VL);
26 }
27
gcs_set_status(unsigned long mode)28 static inline int gcs_set_status(unsigned long mode)
29 {
30 bool enabling = mode & PR_SHADOW_STACK_ENABLE;
31 int ret;
32 unsigned long new_mode;
33
34 /*
35 * The prctl takes 1 argument but we need to ensure that the
36 * other 3 values passed in registers to the syscall are zero
37 * since the kernel validates them.
38 */
39 ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, mode,
40 0, 0, 0);
41
42 if (ret == 0) {
43 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
44 &new_mode, 0, 0, 0);
45 if (ret == 0) {
46 if (new_mode != mode) {
47 ksft_print_msg("Mode set to %lx not %lx\n",
48 new_mode, mode);
49 ret = -EINVAL;
50 }
51 } else {
52 ksft_print_msg("Failed to validate mode: %d\n", ret);
53 }
54
55 if (enabling != chkfeat_gcs()) {
56 ksft_print_msg("%senabled by prctl but %senabled in CHKFEAT\n",
57 enabling ? "" : "not ",
58 chkfeat_gcs() ? "" : "not ");
59 ret = -EINVAL;
60 }
61 }
62
63 return ret;
64 }
65
66 /* Try to read the status */
read_status(void)67 static bool read_status(void)
68 {
69 unsigned long state;
70 int ret;
71
72 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
73 &state, 0, 0, 0);
74 if (ret != 0) {
75 ksft_print_msg("Failed to read state: %d\n", ret);
76 return false;
77 }
78
79 return state & PR_SHADOW_STACK_ENABLE;
80 }
81
82 /* Just a straight enable */
base_enable(void)83 static bool base_enable(void)
84 {
85 int ret;
86
87 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
88 if (ret) {
89 ksft_print_msg("PR_SHADOW_STACK_ENABLE failed %d\n", ret);
90 return false;
91 }
92
93 return true;
94 }
95
96 /* Check we can read GCSPR_EL0 when GCS is enabled */
read_gcspr_el0(void)97 static bool read_gcspr_el0(void)
98 {
99 unsigned long *gcspr_el0;
100
101 ksft_print_msg("GET GCSPR\n");
102 gcspr_el0 = get_gcspr();
103 ksft_print_msg("GCSPR_EL0 is %p\n", gcspr_el0);
104
105 return true;
106 }
107
108 /* Also allow writes to stack */
enable_writeable(void)109 static bool enable_writeable(void)
110 {
111 int ret;
112
113 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_WRITE);
114 if (ret) {
115 ksft_print_msg("PR_SHADOW_STACK_ENABLE writeable failed: %d\n", ret);
116 return false;
117 }
118
119 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
120 if (ret) {
121 ksft_print_msg("failed to restore plain enable %d\n", ret);
122 return false;
123 }
124
125 return true;
126 }
127
128 /* Also allow writes to stack */
enable_push_pop(void)129 static bool enable_push_pop(void)
130 {
131 int ret;
132
133 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH);
134 if (ret) {
135 ksft_print_msg("PR_SHADOW_STACK_ENABLE with push failed: %d\n",
136 ret);
137 return false;
138 }
139
140 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
141 if (ret) {
142 ksft_print_msg("failed to restore plain enable %d\n", ret);
143 return false;
144 }
145
146 return true;
147 }
148
149 /* Enable GCS and allow everything */
enable_all(void)150 static bool enable_all(void)
151 {
152 int ret;
153
154 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE | PR_SHADOW_STACK_PUSH |
155 PR_SHADOW_STACK_WRITE);
156 if (ret) {
157 ksft_print_msg("PR_SHADOW_STACK_ENABLE with everything failed: %d\n",
158 ret);
159 return false;
160 }
161
162 ret = gcs_set_status(PR_SHADOW_STACK_ENABLE);
163 if (ret) {
164 ksft_print_msg("failed to restore plain enable %d\n", ret);
165 return false;
166 }
167
168 return true;
169 }
170
enable_invalid(void)171 static bool enable_invalid(void)
172 {
173 int ret = gcs_set_status(ULONG_MAX);
174 if (ret == 0) {
175 ksft_print_msg("GCS_SET_STATUS %lx succeeded\n", ULONG_MAX);
176 return false;
177 }
178
179 return true;
180 }
181
182 /* Map a GCS */
map_guarded_stack(void)183 static bool map_guarded_stack(void)
184 {
185 int ret;
186 uint64_t *buf;
187 uint64_t expected_cap;
188 int elem;
189 bool pass = true;
190
191 buf = (void *)my_syscall3(__NR_map_shadow_stack, 0, page_size,
192 SHADOW_STACK_SET_MARKER |
193 SHADOW_STACK_SET_TOKEN);
194 if (buf == MAP_FAILED) {
195 ksft_print_msg("Failed to map %lu byte GCS: %d\n",
196 page_size, errno);
197 return false;
198 }
199 ksft_print_msg("Mapped GCS at %p-%p\n", buf,
200 (void *)((uint64_t)buf + page_size));
201
202 /* The top of the newly allocated region should be 0 */
203 elem = (page_size / sizeof(uint64_t)) - 1;
204 if (buf[elem]) {
205 ksft_print_msg("Last entry is 0x%llx not 0x0\n", buf[elem]);
206 pass = false;
207 }
208
209 /* Then a valid cap token */
210 elem--;
211 expected_cap = ((uint64_t)buf + page_size - 16);
212 expected_cap &= GCS_CAP_ADDR_MASK;
213 expected_cap |= GCS_CAP_VALID_TOKEN;
214 if (buf[elem] != expected_cap) {
215 ksft_print_msg("Cap entry is 0x%llx not 0x%llx\n",
216 buf[elem], expected_cap);
217 pass = false;
218 }
219 ksft_print_msg("cap token is 0x%llx\n", buf[elem]);
220
221 /* The rest should be zeros */
222 for (elem = 0; elem < page_size / sizeof(uint64_t) - 2; elem++) {
223 if (!buf[elem])
224 continue;
225 ksft_print_msg("GCS slot %d is 0x%llx not 0x0\n",
226 elem, buf[elem]);
227 pass = false;
228 }
229
230 ret = munmap(buf, page_size);
231 if (ret != 0) {
232 ksft_print_msg("Failed to unmap %ld byte GCS: %d\n",
233 page_size, errno);
234 pass = false;
235 }
236
237 return pass;
238 }
239
240 /* A fork()ed process can run */
test_fork(void)241 static bool test_fork(void)
242 {
243 unsigned long child_mode;
244 int ret, status;
245 pid_t pid;
246 bool pass = true;
247
248 pid = fork();
249 if (pid == -1) {
250 ksft_print_msg("fork() failed: %d\n", errno);
251 pass = false;
252 goto out;
253 }
254 if (pid == 0) {
255 /* In child, make sure we can call a function, read
256 * the GCS pointer and status and then exit */
257 valid_gcs_function();
258 get_gcspr();
259
260 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
261 &child_mode, 0, 0, 0);
262 if (ret == 0 && !(child_mode & PR_SHADOW_STACK_ENABLE)) {
263 ksft_print_msg("GCS not enabled in child\n");
264 ret = -EINVAL;
265 }
266
267 exit(ret);
268 }
269
270 /*
271 * In parent, check we can still do function calls then block
272 * for the child.
273 */
274 valid_gcs_function();
275
276 ksft_print_msg("Waiting for child %d\n", pid);
277
278 ret = waitpid(pid, &status, 0);
279 if (ret == -1) {
280 ksft_print_msg("Failed to wait for child: %d\n",
281 errno);
282 return false;
283 }
284
285 if (!WIFEXITED(status)) {
286 ksft_print_msg("Child exited due to signal %d\n",
287 WTERMSIG(status));
288 pass = false;
289 } else {
290 if (WEXITSTATUS(status)) {
291 ksft_print_msg("Child exited with status %d\n",
292 WEXITSTATUS(status));
293 pass = false;
294 }
295 }
296
297 out:
298
299 return pass;
300 }
301
302 /* A vfork()ed process can run and exit */
test_vfork(void)303 static bool test_vfork(void)
304 {
305 unsigned long child_mode;
306 int ret, status;
307 pid_t pid;
308 bool pass = true;
309
310 pid = vfork();
311 if (pid == -1) {
312 ksft_print_msg("vfork() failed: %d\n", errno);
313 pass = false;
314 goto out;
315 }
316 if (pid == 0) {
317 /*
318 * In child, make sure we can call a function, read
319 * the GCS pointer and status and then exit.
320 */
321 valid_gcs_function();
322 get_gcspr();
323
324 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
325 &child_mode, 0, 0, 0);
326 if (ret == 0 && !(child_mode & PR_SHADOW_STACK_ENABLE)) {
327 ksft_print_msg("GCS not enabled in child\n");
328 ret = EXIT_FAILURE;
329 }
330
331 _exit(ret);
332 }
333
334 /*
335 * In parent, check we can still do function calls then check
336 * on the child.
337 */
338 valid_gcs_function();
339
340 ksft_print_msg("Waiting for child %d\n", pid);
341
342 ret = waitpid(pid, &status, 0);
343 if (ret == -1) {
344 ksft_print_msg("Failed to wait for child: %d\n",
345 errno);
346 return false;
347 }
348
349 if (!WIFEXITED(status)) {
350 ksft_print_msg("Child exited due to signal %d\n",
351 WTERMSIG(status));
352 pass = false;
353 } else if (WEXITSTATUS(status)) {
354 ksft_print_msg("Child exited with status %d\n",
355 WEXITSTATUS(status));
356 pass = false;
357 }
358
359 out:
360
361 return pass;
362 }
363
364 typedef bool (*gcs_test)(void);
365
366 static struct {
367 char *name;
368 gcs_test test;
369 bool needs_enable;
370 } tests[] = {
371 { "read_status", read_status },
372 { "base_enable", base_enable, true },
373 { "read_gcspr_el0", read_gcspr_el0 },
374 { "enable_writeable", enable_writeable, true },
375 { "enable_push_pop", enable_push_pop, true },
376 { "enable_all", enable_all, true },
377 { "enable_invalid", enable_invalid, true },
378 { "map_guarded_stack", map_guarded_stack },
379 { "fork", test_fork },
380 { "vfork", test_vfork },
381 };
382
main(void)383 int main(void)
384 {
385 int i, ret;
386 unsigned long gcs_mode;
387
388 ksft_print_header();
389
390 if (!(getauxval(AT_HWCAP) & HWCAP_GCS))
391 ksft_exit_skip("SKIP GCS not supported\n");
392
393 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS,
394 &gcs_mode, 0, 0, 0);
395 if (ret != 0)
396 ksft_exit_fail_msg("Failed to read GCS state: %d\n", ret);
397
398 if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) {
399 gcs_mode = PR_SHADOW_STACK_ENABLE;
400 ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
401 gcs_mode, 0, 0, 0);
402 if (ret != 0)
403 ksft_exit_fail_msg("Failed to enable GCS: %d\n", ret);
404 }
405
406 ksft_set_plan(ARRAY_SIZE(tests));
407
408 for (i = 0; i < ARRAY_SIZE(tests); i++) {
409 ksft_test_result((*tests[i].test)(), "%s\n", tests[i].name);
410 }
411
412 /* One last test: disable GCS, we can do this one time */
413 ret = my_syscall5(__NR_prctl, PR_SET_SHADOW_STACK_STATUS, 0, 0, 0, 0);
414 if (ret != 0)
415 ksft_print_msg("Failed to disable GCS: %d\n", ret);
416
417 ksft_finished();
418
419 return 0;
420 }
421