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 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*/ 56 TEST(can_call_function) 57 { 58 gcs_recurse(0); 59 } 60 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 */ 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 */ 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 */ 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 301 FIXTURE(map_gcs) 302 { 303 unsigned long *stack; 304 }; 305 306 FIXTURE_VARIANT(map_gcs) 307 { 308 size_t stack_size; 309 unsigned long flags; 310 }; 311 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 318 FIXTURE_VARIANT_ADD(map_gcs, s2k_cap) 319 { 320 .stack_size = 2 * 1024, 321 .flags = SHADOW_STACK_SET_TOKEN, 322 }; 323 324 FIXTURE_VARIANT_ADD(map_gcs, s2k_marker) 325 { 326 .stack_size = 2 * 1024, 327 .flags = SHADOW_STACK_SET_MARKER, 328 }; 329 330 FIXTURE_VARIANT_ADD(map_gcs, s2k) 331 { 332 .stack_size = 2 * 1024, 333 .flags = 0, 334 }; 335 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 342 FIXTURE_VARIANT_ADD(map_gcs, s4k_cap) 343 { 344 .stack_size = 4 * 1024, 345 .flags = SHADOW_STACK_SET_TOKEN, 346 }; 347 348 FIXTURE_VARIANT_ADD(map_gcs, s3k_marker) 349 { 350 .stack_size = 4 * 1024, 351 .flags = SHADOW_STACK_SET_MARKER, 352 }; 353 354 FIXTURE_VARIANT_ADD(map_gcs, s4k) 355 { 356 .stack_size = 4 * 1024, 357 .flags = 0, 358 }; 359 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 366 FIXTURE_VARIANT_ADD(map_gcs, s16k_cap) 367 { 368 .stack_size = 16 * 1024, 369 .flags = SHADOW_STACK_SET_TOKEN, 370 }; 371 372 FIXTURE_VARIANT_ADD(map_gcs, s16k_marker) 373 { 374 .stack_size = 16 * 1024, 375 .flags = SHADOW_STACK_SET_MARKER, 376 }; 377 378 FIXTURE_VARIANT_ADD(map_gcs, s16k) 379 { 380 .stack_size = 16 * 1024, 381 .flags = 0, 382 }; 383 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 390 FIXTURE_VARIANT_ADD(map_gcs, s64k_cap) 391 { 392 .stack_size = 64 * 1024, 393 .flags = SHADOW_STACK_SET_TOKEN, 394 }; 395 396 FIXTURE_VARIANT_ADD(map_gcs, s64k_marker) 397 { 398 .stack_size = 64 * 1024, 399 .flags = SHADOW_STACK_SET_MARKER, 400 }; 401 402 FIXTURE_VARIANT_ADD(map_gcs, s64k) 403 { 404 .stack_size = 64 * 1024, 405 .flags = 0, 406 }; 407 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 414 FIXTURE_VARIANT_ADD(map_gcs, s128k_cap) 415 { 416 .stack_size = 128 * 1024, 417 .flags = SHADOW_STACK_SET_TOKEN, 418 }; 419 420 FIXTURE_VARIANT_ADD(map_gcs, s128k_marker) 421 { 422 .stack_size = 128 * 1024, 423 .flags = SHADOW_STACK_SET_MARKER, 424 }; 425 426 FIXTURE_VARIANT_ADD(map_gcs, s128k) 427 { 428 .stack_size = 128 * 1024, 429 .flags = 0, 430 }; 431 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 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 */ 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 */ 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 */ 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 */ 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 */ 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 599 FIXTURE(map_invalid_gcs) 600 { 601 }; 602 603 FIXTURE_VARIANT(map_invalid_gcs) 604 { 605 size_t stack_size; 606 }; 607 608 FIXTURE_SETUP(map_invalid_gcs) 609 { 610 } 611 612 FIXTURE_TEARDOWN(map_invalid_gcs) 613 { 614 } 615 616 /* GCS must be larger than 16 bytes */ 617 FIXTURE_VARIANT_ADD(map_invalid_gcs, too_small) 618 { 619 .stack_size = 8, 620 }; 621 622 /* GCS size must be 16 byte aligned */ 623 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_1) { .stack_size = 1024 + 1 }; 624 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_2) { .stack_size = 1024 + 2 }; 625 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_3) { .stack_size = 1024 + 3 }; 626 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_4) { .stack_size = 1024 + 4 }; 627 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_5) { .stack_size = 1024 + 5 }; 628 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_6) { .stack_size = 1024 + 6 }; 629 FIXTURE_VARIANT_ADD(map_invalid_gcs, unligned_7) { .stack_size = 1024 + 7 }; 630 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 642 FIXTURE(invalid_mprotect) 643 { 644 unsigned long *stack; 645 size_t stack_size; 646 }; 647 648 FIXTURE_VARIANT(invalid_mprotect) 649 { 650 unsigned long flags; 651 }; 652 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 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 673 FIXTURE_VARIANT_ADD(invalid_mprotect, exec) 674 { 675 .flags = PROT_EXEC, 676 }; 677 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 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 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