1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3 * Copyright (C) 2023 ARM Limited.
4 */
5
6 #define _GNU_SOURCE
7
8 #include <pthread.h>
9 #include <stdbool.h>
10
11 #include <sys/auxv.h>
12 #include <sys/mman.h>
13 #include <sys/prctl.h>
14 #include <sys/ptrace.h>
15 #include <sys/uio.h>
16
17 #include <asm/hwcap.h>
18 #include <asm/mman.h>
19
20 #include <linux/compiler.h>
21
22 #include "kselftest_harness.h"
23
24 #include "gcs-util.h"
25
26 #define my_syscall2(num, arg1, arg2) \
27 ({ \
28 register long _num __asm__ ("x8") = (num); \
29 register long _arg1 __asm__ ("x0") = (long)(arg1); \
30 register long _arg2 __asm__ ("x1") = (long)(arg2); \
31 register long _arg3 __asm__ ("x2") = 0; \
32 register long _arg4 __asm__ ("x3") = 0; \
33 register long _arg5 __asm__ ("x4") = 0; \
34 \
35 __asm__ volatile ( \
36 "svc #0\n" \
37 : "=r"(_arg1) \
38 : "r"(_arg1), "r"(_arg2), \
39 "r"(_arg3), "r"(_arg4), \
40 "r"(_arg5), "r"(_num) \
41 : "memory", "cc" \
42 ); \
43 _arg1; \
44 })
45
gcs_recurse(int depth)46 static noinline void gcs_recurse(int depth)
47 {
48 if (depth)
49 gcs_recurse(depth - 1);
50
51 /* Prevent tail call optimization so we actually recurse */
52 asm volatile("dsb sy" : : : "memory");
53 }
54
55 /* Smoke test that a function call and return works*/
TEST(can_call_function)56 TEST(can_call_function)
57 {
58 gcs_recurse(0);
59 }
60
gcs_test_thread(void * arg)61 static void *gcs_test_thread(void *arg)
62 {
63 int ret;
64 unsigned long mode;
65
66 /*
67 * Some libcs don't seem to fill unused arguments with 0 but
68 * the kernel validates this so we supply all 5 arguments.
69 */
70 ret = prctl(PR_GET_SHADOW_STACK_STATUS, &mode, 0, 0, 0);
71 if (ret != 0) {
72 ksft_print_msg("PR_GET_SHADOW_STACK_STATUS failed: %d\n", ret);
73 return NULL;
74 }
75
76 if (!(mode & PR_SHADOW_STACK_ENABLE)) {
77 ksft_print_msg("GCS not enabled in thread, mode is %lu\n",
78 mode);
79 return NULL;
80 }
81
82 /* Just in case... */
83 gcs_recurse(0);
84
85 /* Use a non-NULL value to indicate a pass */
86 return &gcs_test_thread;
87 }
88
89 /* Verify that if we start a new thread it has GCS enabled */
TEST(gcs_enabled_thread)90 TEST(gcs_enabled_thread)
91 {
92 pthread_t thread;
93 void *thread_ret;
94 int ret;
95
96 ret = pthread_create(&thread, NULL, gcs_test_thread, NULL);
97 ASSERT_TRUE(ret == 0);
98 if (ret != 0)
99 return;
100
101 ret = pthread_join(thread, &thread_ret);
102 ASSERT_TRUE(ret == 0);
103 if (ret != 0)
104 return;
105
106 ASSERT_TRUE(thread_ret != NULL);
107 }
108
109 /* Read the GCS until we find the terminator */
TEST(gcs_find_terminator)110 TEST(gcs_find_terminator)
111 {
112 unsigned long *gcs, *cur;
113
114 gcs = get_gcspr();
115 cur = gcs;
116 while (*cur)
117 cur++;
118
119 ksft_print_msg("GCS in use from %p-%p\n", gcs, cur);
120
121 /*
122 * We should have at least whatever called into this test so
123 * the two pointer should differ.
124 */
125 ASSERT_TRUE(gcs != cur);
126 }
127
128 /*
129 * We can access a GCS via ptrace
130 *
131 * This could usefully have a fixture but note that each test is
132 * fork()ed into a new child whcih causes issues. Might be better to
133 * lift at least some of this out into a separate, non-harness, test
134 * program.
135 */
TEST(ptrace_read_write)136 TEST(ptrace_read_write)
137 {
138 pid_t child, pid;
139 int ret, status;
140 siginfo_t si;
141 uint64_t val, rval, gcspr;
142 struct user_gcs child_gcs;
143 struct iovec iov, local_iov, remote_iov;
144
145 child = fork();
146 if (child == -1) {
147 ksft_print_msg("fork() failed: %d (%s)\n",
148 errno, strerror(errno));
149 ASSERT_NE(child, -1);
150 }
151
152 if (child == 0) {
153 /*
154 * In child, make sure there's something on the stack and
155 * ask to be traced.
156 */
157 gcs_recurse(0);
158 if (ptrace(PTRACE_TRACEME, -1, NULL, NULL))
159 ksft_exit_fail_msg("PTRACE_TRACEME %s",
160 strerror(errno));
161
162 if (raise(SIGSTOP))
163 ksft_exit_fail_msg("raise(SIGSTOP) %s",
164 strerror(errno));
165
166 return;
167 }
168
169 ksft_print_msg("Child: %d\n", child);
170
171 /* Attach to the child */
172 while (1) {
173 int sig;
174
175 pid = wait(&status);
176 if (pid == -1) {
177 ksft_print_msg("wait() failed: %s",
178 strerror(errno));
179 goto error;
180 }
181
182 /*
183 * This should never happen but it's hard to flag in
184 * the framework.
185 */
186 if (pid != child)
187 continue;
188
189 if (WIFEXITED(status) || WIFSIGNALED(status))
190 ksft_exit_fail_msg("Child died unexpectedly\n");
191
192 if (!WIFSTOPPED(status))
193 goto error;
194
195 sig = WSTOPSIG(status);
196
197 if (ptrace(PTRACE_GETSIGINFO, pid, NULL, &si)) {
198 if (errno == ESRCH) {
199 ASSERT_NE(errno, ESRCH);
200 return;
201 }
202
203 if (errno == EINVAL) {
204 sig = 0; /* bust group-stop */
205 goto cont;
206 }
207
208 ksft_print_msg("PTRACE_GETSIGINFO: %s\n",
209 strerror(errno));
210 goto error;
211 }
212
213 if (sig == SIGSTOP && si.si_code == SI_TKILL &&
214 si.si_pid == pid)
215 break;
216
217 cont:
218 if (ptrace(PTRACE_CONT, pid, NULL, sig)) {
219 if (errno == ESRCH) {
220 ASSERT_NE(errno, ESRCH);
221 return;
222 }
223
224 ksft_print_msg("PTRACE_CONT: %s\n", strerror(errno));
225 goto error;
226 }
227 }
228
229 /* Where is the child GCS? */
230 iov.iov_base = &child_gcs;
231 iov.iov_len = sizeof(child_gcs);
232 ret = ptrace(PTRACE_GETREGSET, child, NT_ARM_GCS, &iov);
233 if (ret != 0) {
234 ksft_print_msg("Failed to read child GCS state: %s (%d)\n",
235 strerror(errno), errno);
236 goto error;
237 }
238
239 /* We should have inherited GCS over fork(), confirm */
240 if (!(child_gcs.features_enabled & PR_SHADOW_STACK_ENABLE)) {
241 ASSERT_TRUE(child_gcs.features_enabled &
242 PR_SHADOW_STACK_ENABLE);
243 goto error;
244 }
245
246 gcspr = child_gcs.gcspr_el0;
247 ksft_print_msg("Child GCSPR 0x%lx, flags %llx, locked %llx\n",
248 gcspr, child_gcs.features_enabled,
249 child_gcs.features_locked);
250
251 /* Ideally we'd cross check with the child memory map */
252
253 errno = 0;
254 val = ptrace(PTRACE_PEEKDATA, child, (void *)gcspr, NULL);
255 ret = errno;
256 if (ret != 0)
257 ksft_print_msg("PTRACE_PEEKDATA failed: %s (%d)\n",
258 strerror(ret), ret);
259 EXPECT_EQ(ret, 0);
260
261 /* The child should be in a function, the GCSPR shouldn't be 0 */
262 EXPECT_NE(val, 0);
263
264 /* Same thing via process_vm_readv() */
265 local_iov.iov_base = &rval;
266 local_iov.iov_len = sizeof(rval);
267 remote_iov.iov_base = (void *)gcspr;
268 remote_iov.iov_len = sizeof(rval);
269 ret = process_vm_readv(child, &local_iov, 1, &remote_iov, 1, 0);
270 if (ret == -1)
271 ksft_print_msg("process_vm_readv() failed: %s (%d)\n",
272 strerror(errno), errno);
273 EXPECT_EQ(ret, sizeof(rval));
274 EXPECT_EQ(val, rval);
275
276 /* Write data via a peek */
277 ret = ptrace(PTRACE_POKEDATA, child, (void *)gcspr, NULL);
278 if (ret == -1)
279 ksft_print_msg("PTRACE_POKEDATA failed: %s (%d)\n",
280 strerror(errno), errno);
281 EXPECT_EQ(ret, 0);
282 EXPECT_EQ(0, ptrace(PTRACE_PEEKDATA, child, (void *)gcspr, NULL));
283
284 /* Restore what we had before */
285 ret = ptrace(PTRACE_POKEDATA, child, (void *)gcspr, val);
286 if (ret == -1)
287 ksft_print_msg("PTRACE_POKEDATA failed: %s (%d)\n",
288 strerror(errno), errno);
289 EXPECT_EQ(ret, 0);
290 EXPECT_EQ(val, ptrace(PTRACE_PEEKDATA, child, (void *)gcspr, NULL));
291
292 /* That's all, folks */
293 kill(child, SIGKILL);
294 return;
295
296 error:
297 kill(child, SIGKILL);
298 ASSERT_FALSE(true);
299 }
300
FIXTURE(map_gcs)301 FIXTURE(map_gcs)
302 {
303 unsigned long *stack;
304 };
305
FIXTURE_VARIANT(map_gcs)306 FIXTURE_VARIANT(map_gcs)
307 {
308 size_t stack_size;
309 unsigned long flags;
310 };
311
FIXTURE_VARIANT_ADD(map_gcs,s2k_cap_marker)312 FIXTURE_VARIANT_ADD(map_gcs, s2k_cap_marker)
313 {
314 .stack_size = 2 * 1024,
315 .flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
316 };
317
FIXTURE_VARIANT_ADD(map_gcs,s2k_cap)318 FIXTURE_VARIANT_ADD(map_gcs, s2k_cap)
319 {
320 .stack_size = 2 * 1024,
321 .flags = SHADOW_STACK_SET_TOKEN,
322 };
323
FIXTURE_VARIANT_ADD(map_gcs,s2k_marker)324 FIXTURE_VARIANT_ADD(map_gcs, s2k_marker)
325 {
326 .stack_size = 2 * 1024,
327 .flags = SHADOW_STACK_SET_MARKER,
328 };
329
FIXTURE_VARIANT_ADD(map_gcs,s2k)330 FIXTURE_VARIANT_ADD(map_gcs, s2k)
331 {
332 .stack_size = 2 * 1024,
333 .flags = 0,
334 };
335
FIXTURE_VARIANT_ADD(map_gcs,s4k_cap_marker)336 FIXTURE_VARIANT_ADD(map_gcs, s4k_cap_marker)
337 {
338 .stack_size = 4 * 1024,
339 .flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
340 };
341
FIXTURE_VARIANT_ADD(map_gcs,s4k_cap)342 FIXTURE_VARIANT_ADD(map_gcs, s4k_cap)
343 {
344 .stack_size = 4 * 1024,
345 .flags = SHADOW_STACK_SET_TOKEN,
346 };
347
FIXTURE_VARIANT_ADD(map_gcs,s3k_marker)348 FIXTURE_VARIANT_ADD(map_gcs, s3k_marker)
349 {
350 .stack_size = 4 * 1024,
351 .flags = SHADOW_STACK_SET_MARKER,
352 };
353
FIXTURE_VARIANT_ADD(map_gcs,s4k)354 FIXTURE_VARIANT_ADD(map_gcs, s4k)
355 {
356 .stack_size = 4 * 1024,
357 .flags = 0,
358 };
359
FIXTURE_VARIANT_ADD(map_gcs,s16k_cap_marker)360 FIXTURE_VARIANT_ADD(map_gcs, s16k_cap_marker)
361 {
362 .stack_size = 16 * 1024,
363 .flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
364 };
365
FIXTURE_VARIANT_ADD(map_gcs,s16k_cap)366 FIXTURE_VARIANT_ADD(map_gcs, s16k_cap)
367 {
368 .stack_size = 16 * 1024,
369 .flags = SHADOW_STACK_SET_TOKEN,
370 };
371
FIXTURE_VARIANT_ADD(map_gcs,s16k_marker)372 FIXTURE_VARIANT_ADD(map_gcs, s16k_marker)
373 {
374 .stack_size = 16 * 1024,
375 .flags = SHADOW_STACK_SET_MARKER,
376 };
377
FIXTURE_VARIANT_ADD(map_gcs,s16k)378 FIXTURE_VARIANT_ADD(map_gcs, s16k)
379 {
380 .stack_size = 16 * 1024,
381 .flags = 0,
382 };
383
FIXTURE_VARIANT_ADD(map_gcs,s64k_cap_marker)384 FIXTURE_VARIANT_ADD(map_gcs, s64k_cap_marker)
385 {
386 .stack_size = 64 * 1024,
387 .flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
388 };
389
FIXTURE_VARIANT_ADD(map_gcs,s64k_cap)390 FIXTURE_VARIANT_ADD(map_gcs, s64k_cap)
391 {
392 .stack_size = 64 * 1024,
393 .flags = SHADOW_STACK_SET_TOKEN,
394 };
395
FIXTURE_VARIANT_ADD(map_gcs,s64k_marker)396 FIXTURE_VARIANT_ADD(map_gcs, s64k_marker)
397 {
398 .stack_size = 64 * 1024,
399 .flags = SHADOW_STACK_SET_MARKER,
400 };
401
FIXTURE_VARIANT_ADD(map_gcs,s64k)402 FIXTURE_VARIANT_ADD(map_gcs, s64k)
403 {
404 .stack_size = 64 * 1024,
405 .flags = 0,
406 };
407
FIXTURE_VARIANT_ADD(map_gcs,s128k_cap_marker)408 FIXTURE_VARIANT_ADD(map_gcs, s128k_cap_marker)
409 {
410 .stack_size = 128 * 1024,
411 .flags = SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN,
412 };
413
FIXTURE_VARIANT_ADD(map_gcs,s128k_cap)414 FIXTURE_VARIANT_ADD(map_gcs, s128k_cap)
415 {
416 .stack_size = 128 * 1024,
417 .flags = SHADOW_STACK_SET_TOKEN,
418 };
419
FIXTURE_VARIANT_ADD(map_gcs,s128k_marker)420 FIXTURE_VARIANT_ADD(map_gcs, s128k_marker)
421 {
422 .stack_size = 128 * 1024,
423 .flags = SHADOW_STACK_SET_MARKER,
424 };
425
FIXTURE_VARIANT_ADD(map_gcs,s128k)426 FIXTURE_VARIANT_ADD(map_gcs, s128k)
427 {
428 .stack_size = 128 * 1024,
429 .flags = 0,
430 };
431
FIXTURE_SETUP(map_gcs)432 FIXTURE_SETUP(map_gcs)
433 {
434 self->stack = (void *)syscall(__NR_map_shadow_stack, 0,
435 variant->stack_size,
436 variant->flags);
437 ASSERT_FALSE(self->stack == MAP_FAILED);
438 ksft_print_msg("Allocated stack from %p-%p\n", self->stack,
439 self->stack + variant->stack_size);
440 }
441
FIXTURE_TEARDOWN(map_gcs)442 FIXTURE_TEARDOWN(map_gcs)
443 {
444 int ret;
445
446 if (self->stack != MAP_FAILED) {
447 ret = munmap(self->stack, variant->stack_size);
448 ASSERT_EQ(ret, 0);
449 }
450 }
451
452 /* The stack has a cap token */
TEST_F(map_gcs,stack_capped)453 TEST_F(map_gcs, stack_capped)
454 {
455 unsigned long *stack = self->stack;
456 size_t cap_index;
457
458 cap_index = (variant->stack_size / sizeof(unsigned long));
459
460 switch (variant->flags & (SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN)) {
461 case SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN:
462 cap_index -= 2;
463 break;
464 case SHADOW_STACK_SET_TOKEN:
465 cap_index -= 1;
466 break;
467 case SHADOW_STACK_SET_MARKER:
468 case 0:
469 /* No cap, no test */
470 return;
471 }
472
473 ASSERT_EQ(stack[cap_index], GCS_CAP(&stack[cap_index]));
474 }
475
476 /* The top of the stack is 0 */
TEST_F(map_gcs,stack_terminated)477 TEST_F(map_gcs, stack_terminated)
478 {
479 unsigned long *stack = self->stack;
480 size_t term_index;
481
482 if (!(variant->flags & SHADOW_STACK_SET_MARKER))
483 return;
484
485 term_index = (variant->stack_size / sizeof(unsigned long)) - 1;
486
487 ASSERT_EQ(stack[term_index], 0);
488 }
489
490 /* Writes should fault */
TEST_F_SIGNAL(map_gcs,not_writeable,SIGSEGV)491 TEST_F_SIGNAL(map_gcs, not_writeable, SIGSEGV)
492 {
493 self->stack[0] = 0;
494 }
495
496 /* Put it all together, we can safely switch to and from the stack */
TEST_F(map_gcs,stack_switch)497 TEST_F(map_gcs, stack_switch)
498 {
499 size_t cap_index;
500 cap_index = (variant->stack_size / sizeof(unsigned long));
501 unsigned long *orig_gcspr_el0, *pivot_gcspr_el0;
502
503 /* Skip over the stack terminator and point at the cap */
504 switch (variant->flags & (SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN)) {
505 case SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN:
506 cap_index -= 2;
507 break;
508 case SHADOW_STACK_SET_TOKEN:
509 cap_index -= 1;
510 break;
511 case SHADOW_STACK_SET_MARKER:
512 case 0:
513 /* No cap, no test */
514 return;
515 }
516 pivot_gcspr_el0 = &self->stack[cap_index];
517
518 /* Pivot to the new GCS */
519 ksft_print_msg("Pivoting to %p from %p, target has value 0x%lx\n",
520 pivot_gcspr_el0, get_gcspr(),
521 *pivot_gcspr_el0);
522 gcsss1(pivot_gcspr_el0);
523 orig_gcspr_el0 = gcsss2();
524 ksft_print_msg("Pivoted to %p from %p, target has value 0x%lx\n",
525 get_gcspr(), orig_gcspr_el0,
526 *pivot_gcspr_el0);
527
528 ksft_print_msg("Pivoted, GCSPR_EL0 now %p\n", get_gcspr());
529
530 /* New GCS must be in the new buffer */
531 ASSERT_TRUE((unsigned long)get_gcspr() > (unsigned long)self->stack);
532 ASSERT_TRUE((unsigned long)get_gcspr() <=
533 (unsigned long)self->stack + variant->stack_size);
534
535 /* We should be able to use all but 2 slots of the new stack */
536 ksft_print_msg("Recursing %zu levels\n", cap_index - 1);
537 gcs_recurse(cap_index - 1);
538
539 /* Pivot back to the original GCS */
540 gcsss1(orig_gcspr_el0);
541 pivot_gcspr_el0 = gcsss2();
542
543 gcs_recurse(0);
544 ksft_print_msg("Pivoted back to GCSPR_EL0 0x%p\n", get_gcspr());
545 }
546
547 /* We fault if we try to go beyond the end of the stack */
TEST_F_SIGNAL(map_gcs,stack_overflow,SIGSEGV)548 TEST_F_SIGNAL(map_gcs, stack_overflow, SIGSEGV)
549 {
550 size_t cap_index;
551 cap_index = (variant->stack_size / sizeof(unsigned long));
552 unsigned long *orig_gcspr_el0, *pivot_gcspr_el0;
553
554 /* Skip over the stack terminator and point at the cap */
555 switch (variant->flags & (SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN)) {
556 case SHADOW_STACK_SET_MARKER | SHADOW_STACK_SET_TOKEN:
557 cap_index -= 2;
558 break;
559 case SHADOW_STACK_SET_TOKEN:
560 cap_index -= 1;
561 break;
562 case SHADOW_STACK_SET_MARKER:
563 case 0:
564 /* No cap, no test but we need to SEGV to avoid a false fail */
565 orig_gcspr_el0 = get_gcspr();
566 *orig_gcspr_el0 = 0;
567 return;
568 }
569 pivot_gcspr_el0 = &self->stack[cap_index];
570
571 /* Pivot to the new GCS */
572 ksft_print_msg("Pivoting to %p from %p, target has value 0x%lx\n",
573 pivot_gcspr_el0, get_gcspr(),
574 *pivot_gcspr_el0);
575 gcsss1(pivot_gcspr_el0);
576 orig_gcspr_el0 = gcsss2();
577 ksft_print_msg("Pivoted to %p from %p, target has value 0x%lx\n",
578 pivot_gcspr_el0, orig_gcspr_el0,
579 *pivot_gcspr_el0);
580
581 ksft_print_msg("Pivoted, GCSPR_EL0 now %p\n", get_gcspr());
582
583 /* New GCS must be in the new buffer */
584 ASSERT_TRUE((unsigned long)get_gcspr() > (unsigned long)self->stack);
585 ASSERT_TRUE((unsigned long)get_gcspr() <=
586 (unsigned long)self->stack + variant->stack_size);
587
588 /* Now try to recurse, we should fault doing this. */
589 ksft_print_msg("Recursing %zu levels...\n", cap_index + 1);
590 gcs_recurse(cap_index + 1);
591 ksft_print_msg("...done\n");
592
593 /* Clean up properly to try to guard against spurious passes. */
594 gcsss1(orig_gcspr_el0);
595 pivot_gcspr_el0 = gcsss2();
596 ksft_print_msg("Pivoted back to GCSPR_EL0 0x%p\n", get_gcspr());
597 }
598
FIXTURE(map_invalid_gcs)599 FIXTURE(map_invalid_gcs)
600 {
601 };
602
FIXTURE_VARIANT(map_invalid_gcs)603 FIXTURE_VARIANT(map_invalid_gcs)
604 {
605 size_t stack_size;
606 };
607
FIXTURE_SETUP(map_invalid_gcs)608 FIXTURE_SETUP(map_invalid_gcs)
609 {
610 }
611
FIXTURE_TEARDOWN(map_invalid_gcs)612 FIXTURE_TEARDOWN(map_invalid_gcs)
613 {
614 }
615
616 /* GCS must be larger than 16 bytes */
FIXTURE_VARIANT_ADD(map_invalid_gcs,too_small)617 FIXTURE_VARIANT_ADD(map_invalid_gcs, too_small)
618 {
619 .stack_size = 8,
620 };
621
622 /* GCS size must be 16 byte aligned */
FIXTURE_VARIANT_ADD(map_invalid_gcs,unligned_1)623 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_1) { .stack_size = 1024 + 1 };
FIXTURE_VARIANT_ADD(map_invalid_gcs,unligned_2)624 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_2) { .stack_size = 1024 + 2 };
FIXTURE_VARIANT_ADD(map_invalid_gcs,unligned_3)625 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_3) { .stack_size = 1024 + 3 };
FIXTURE_VARIANT_ADD(map_invalid_gcs,unligned_4)626 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_4) { .stack_size = 1024 + 4 };
FIXTURE_VARIANT_ADD(map_invalid_gcs,unligned_5)627 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_5) { .stack_size = 1024 + 5 };
FIXTURE_VARIANT_ADD(map_invalid_gcs,unligned_6)628 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_6) { .stack_size = 1024 + 6 };
FIXTURE_VARIANT_ADD(map_invalid_gcs,unligned_7)629 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_7) { .stack_size = 1024 + 7 };
630
TEST_F(map_invalid_gcs,do_map)631 TEST_F(map_invalid_gcs, do_map)
632 {
633 void *stack;
634
635 stack = (void *)syscall(__NR_map_shadow_stack, 0,
636 variant->stack_size, 0);
637 ASSERT_TRUE(stack == MAP_FAILED);
638 if (stack != MAP_FAILED)
639 munmap(stack, variant->stack_size);
640 }
641
FIXTURE(invalid_mprotect)642 FIXTURE(invalid_mprotect)
643 {
644 unsigned long *stack;
645 size_t stack_size;
646 };
647
FIXTURE_VARIANT(invalid_mprotect)648 FIXTURE_VARIANT(invalid_mprotect)
649 {
650 unsigned long flags;
651 };
652
FIXTURE_SETUP(invalid_mprotect)653 FIXTURE_SETUP(invalid_mprotect)
654 {
655 self->stack_size = sysconf(_SC_PAGE_SIZE);
656 self->stack = (void *)syscall(__NR_map_shadow_stack, 0,
657 self->stack_size, 0);
658 ASSERT_FALSE(self->stack == MAP_FAILED);
659 ksft_print_msg("Allocated stack from %p-%p\n", self->stack,
660 self->stack + self->stack_size);
661 }
662
FIXTURE_TEARDOWN(invalid_mprotect)663 FIXTURE_TEARDOWN(invalid_mprotect)
664 {
665 int ret;
666
667 if (self->stack != MAP_FAILED) {
668 ret = munmap(self->stack, self->stack_size);
669 ASSERT_EQ(ret, 0);
670 }
671 }
672
FIXTURE_VARIANT_ADD(invalid_mprotect,exec)673 FIXTURE_VARIANT_ADD(invalid_mprotect, exec)
674 {
675 .flags = PROT_EXEC,
676 };
677
TEST_F(invalid_mprotect,do_map)678 TEST_F(invalid_mprotect, do_map)
679 {
680 int ret;
681
682 ret = mprotect(self->stack, self->stack_size, variant->flags);
683 ASSERT_EQ(ret, -1);
684 }
685
TEST_F(invalid_mprotect,do_map_read)686 TEST_F(invalid_mprotect, do_map_read)
687 {
688 int ret;
689
690 ret = mprotect(self->stack, self->stack_size,
691 variant->flags | PROT_READ);
692 ASSERT_EQ(ret, -1);
693 }
694
main(int argc,char ** argv)695 int main(int argc, char **argv)
696 {
697 unsigned long gcs_mode;
698 int ret;
699
700 if (!(getauxval(AT_HWCAP) & HWCAP_GCS))
701 ksft_exit_skip("SKIP GCS not supported\n");
702
703 /*
704 * Force shadow stacks on, our tests *should* be fine with or
705 * without libc support and with or without this having ended
706 * up tagged for GCS and enabled by the dynamic linker. We
707 * can't use the libc prctl() function since we can't return
708 * from enabling the stack.
709 */
710 ret = my_syscall2(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &gcs_mode);
711 if (ret) {
712 ksft_print_msg("Failed to read GCS state: %d\n", ret);
713 return EXIT_FAILURE;
714 }
715
716 if (!(gcs_mode & PR_SHADOW_STACK_ENABLE)) {
717 gcs_mode = PR_SHADOW_STACK_ENABLE;
718 ret = my_syscall2(__NR_prctl, PR_SET_SHADOW_STACK_STATUS,
719 gcs_mode);
720 if (ret) {
721 ksft_print_msg("Failed to configure GCS: %d\n", ret);
722 return EXIT_FAILURE;
723 }
724 }
725
726 /* Avoid returning in case libc doesn't understand GCS */
727 exit(test_harness_run(argc, argv));
728 }
729