1089 lines · c
1// SPDX-License-Identifier: GPL-2.02/*3 * This program test's basic kernel shadow stack support. It enables shadow4 * stack manual via the arch_prctl(), instead of relying on glibc. It's5 * Makefile doesn't compile with shadow stack support, so it doesn't rely on6 * any particular glibc. As a result it can't do any operations that require7 * special glibc shadow stack support (longjmp(), swapcontext(), etc). Just8 * stick to the basics and hope the compiler doesn't do anything strange.9 */10 11#define _GNU_SOURCE12 13#include <sys/syscall.h>14#include <asm/mman.h>15#include <sys/mman.h>16#include <sys/stat.h>17#include <sys/wait.h>18#include <stdio.h>19#include <stdlib.h>20#include <fcntl.h>21#include <unistd.h>22#include <string.h>23#include <errno.h>24#include <stdbool.h>25#include <x86intrin.h>26#include <asm/prctl.h>27#include <sys/prctl.h>28#include <stdint.h>29#include <signal.h>30#include <pthread.h>31#include <sys/ioctl.h>32#include <linux/userfaultfd.h>33#include <setjmp.h>34#include <sys/ptrace.h>35#include <sys/signal.h>36#include <linux/elf.h>37#include <linux/perf_event.h>38 39/*40 * Define the ABI defines if needed, so people can run the tests41 * without building the headers.42 */43#ifndef __NR_map_shadow_stack44#define __NR_map_shadow_stack 45345 46#define SHADOW_STACK_SET_TOKEN (1ULL << 0)47 48#define ARCH_SHSTK_ENABLE 0x500149#define ARCH_SHSTK_DISABLE 0x500250#define ARCH_SHSTK_LOCK 0x500351#define ARCH_SHSTK_UNLOCK 0x500452#define ARCH_SHSTK_STATUS 0x500553 54#define ARCH_SHSTK_SHSTK (1ULL << 0)55#define ARCH_SHSTK_WRSS (1ULL << 1)56 57#define NT_X86_SHSTK 0x20458#endif59 60#define SS_SIZE 0x20000061#define PAGE_SIZE 0x100062 63#if (__GNUC__ < 8) || (__GNUC__ == 8 && __GNUC_MINOR__ < 5)64int main(int argc, char *argv[])65{66 printf("[SKIP]\tCompiler does not support CET.\n");67 return 0;68}69#else70void write_shstk(unsigned long *addr, unsigned long val)71{72 asm volatile("wrssq %[val], (%[addr])\n"73 : "=m" (addr)74 : [addr] "r" (addr), [val] "r" (val));75}76 77static inline unsigned long __attribute__((always_inline)) get_ssp(void)78{79 unsigned long ret = 0;80 81 asm volatile("xor %0, %0; rdsspq %0" : "=r" (ret));82 return ret;83}84 85/*86 * For use in inline enablement of shadow stack.87 *88 * The program can't return from the point where shadow stack gets enabled89 * because there will be no address on the shadow stack. So it can't use90 * syscall() for enablement, since it is a function.91 *92 * Based on code from nolibc.h. Keep a copy here because this can't pull in all93 * of nolibc.h.94 */95#define ARCH_PRCTL(arg1, arg2) \96({ \97 long _ret; \98 register long _num asm("eax") = __NR_arch_prctl; \99 register long _arg1 asm("rdi") = (long)(arg1); \100 register long _arg2 asm("rsi") = (long)(arg2); \101 \102 asm volatile ( \103 "syscall\n" \104 : "=a"(_ret) \105 : "r"(_arg1), "r"(_arg2), \106 "0"(_num) \107 : "rcx", "r11", "memory", "cc" \108 ); \109 _ret; \110})111 112void *create_shstk(void *addr)113{114 return (void *)syscall(__NR_map_shadow_stack, addr, SS_SIZE, SHADOW_STACK_SET_TOKEN);115}116 117void *create_normal_mem(void *addr)118{119 return mmap(addr, SS_SIZE, PROT_READ | PROT_WRITE,120 MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);121}122 123void free_shstk(void *shstk)124{125 munmap(shstk, SS_SIZE);126}127 128int reset_shstk(void *shstk)129{130 return madvise(shstk, SS_SIZE, MADV_DONTNEED);131}132 133void try_shstk(unsigned long new_ssp)134{135 unsigned long ssp;136 137 printf("[INFO]\tnew_ssp = %lx, *new_ssp = %lx\n",138 new_ssp, *((unsigned long *)new_ssp));139 140 ssp = get_ssp();141 printf("[INFO]\tchanging ssp from %lx to %lx\n", ssp, new_ssp);142 143 asm volatile("rstorssp (%0)\n":: "r" (new_ssp));144 asm volatile("saveprevssp");145 printf("[INFO]\tssp is now %lx\n", get_ssp());146 147 /* Switch back to original shadow stack */148 ssp -= 8;149 asm volatile("rstorssp (%0)\n":: "r" (ssp));150 asm volatile("saveprevssp");151}152 153int test_shstk_pivot(void)154{155 void *shstk = create_shstk(0);156 157 if (shstk == MAP_FAILED) {158 printf("[FAIL]\tError creating shadow stack: %d\n", errno);159 return 1;160 }161 try_shstk((unsigned long)shstk + SS_SIZE - 8);162 free_shstk(shstk);163 164 printf("[OK]\tShadow stack pivot\n");165 return 0;166}167 168int test_shstk_faults(void)169{170 unsigned long *shstk = create_shstk(0);171 172 /* Read shadow stack, test if it's zero to not get read optimized out */173 if (*shstk != 0)174 goto err;175 176 /* Wrss memory that was already read. */177 write_shstk(shstk, 1);178 if (*shstk != 1)179 goto err;180 181 /* Page out memory, so we can wrss it again. */182 if (reset_shstk((void *)shstk))183 goto err;184 185 write_shstk(shstk, 1);186 if (*shstk != 1)187 goto err;188 189 printf("[OK]\tShadow stack faults\n");190 return 0;191 192err:193 return 1;194}195 196unsigned long saved_ssp;197unsigned long saved_ssp_val;198volatile bool segv_triggered;199 200void __attribute__((noinline)) violate_ss(void)201{202 saved_ssp = get_ssp();203 saved_ssp_val = *(unsigned long *)saved_ssp;204 205 /* Corrupt shadow stack */206 printf("[INFO]\tCorrupting shadow stack\n");207 write_shstk((void *)saved_ssp, 0);208}209 210void segv_handler(int signum, siginfo_t *si, void *uc)211{212 printf("[INFO]\tGenerated shadow stack violation successfully\n");213 214 segv_triggered = true;215 216 /* Fix shadow stack */217 write_shstk((void *)saved_ssp, saved_ssp_val);218}219 220int test_shstk_violation(void)221{222 struct sigaction sa = {};223 224 sa.sa_sigaction = segv_handler;225 sa.sa_flags = SA_SIGINFO;226 if (sigaction(SIGSEGV, &sa, NULL))227 return 1;228 229 segv_triggered = false;230 231 /* Make sure segv_triggered is set before violate_ss() */232 asm volatile("" : : : "memory");233 234 violate_ss();235 236 signal(SIGSEGV, SIG_DFL);237 238 printf("[OK]\tShadow stack violation test\n");239 240 return !segv_triggered;241}242 243/* Gup test state */244#define MAGIC_VAL 0x12345678245bool is_shstk_access;246void *shstk_ptr;247int fd;248 249void reset_test_shstk(void *addr)250{251 if (shstk_ptr)252 free_shstk(shstk_ptr);253 shstk_ptr = create_shstk(addr);254}255 256void test_access_fix_handler(int signum, siginfo_t *si, void *uc)257{258 printf("[INFO]\tViolation from %s\n", is_shstk_access ? "shstk access" : "normal write");259 260 segv_triggered = true;261 262 /* Fix shadow stack */263 if (is_shstk_access) {264 reset_test_shstk(shstk_ptr);265 return;266 }267 268 free_shstk(shstk_ptr);269 create_normal_mem(shstk_ptr);270}271 272bool test_shstk_access(void *ptr)273{274 is_shstk_access = true;275 segv_triggered = false;276 write_shstk(ptr, MAGIC_VAL);277 278 asm volatile("" : : : "memory");279 280 return segv_triggered;281}282 283bool test_write_access(void *ptr)284{285 is_shstk_access = false;286 segv_triggered = false;287 *(unsigned long *)ptr = MAGIC_VAL;288 289 asm volatile("" : : : "memory");290 291 return segv_triggered;292}293 294bool gup_write(void *ptr)295{296 unsigned long val;297 298 lseek(fd, (unsigned long)ptr, SEEK_SET);299 if (write(fd, &val, sizeof(val)) < 0)300 return 1;301 302 return 0;303}304 305bool gup_read(void *ptr)306{307 unsigned long val;308 309 lseek(fd, (unsigned long)ptr, SEEK_SET);310 if (read(fd, &val, sizeof(val)) < 0)311 return 1;312 313 return 0;314}315 316int test_gup(void)317{318 struct sigaction sa = {};319 int status;320 pid_t pid;321 322 sa.sa_sigaction = test_access_fix_handler;323 sa.sa_flags = SA_SIGINFO;324 if (sigaction(SIGSEGV, &sa, NULL))325 return 1;326 327 segv_triggered = false;328 329 fd = open("/proc/self/mem", O_RDWR);330 if (fd == -1)331 return 1;332 333 reset_test_shstk(0);334 if (gup_read(shstk_ptr))335 return 1;336 if (test_shstk_access(shstk_ptr))337 return 1;338 printf("[INFO]\tGup read -> shstk access success\n");339 340 reset_test_shstk(0);341 if (gup_write(shstk_ptr))342 return 1;343 if (test_shstk_access(shstk_ptr))344 return 1;345 printf("[INFO]\tGup write -> shstk access success\n");346 347 reset_test_shstk(0);348 if (gup_read(shstk_ptr))349 return 1;350 if (!test_write_access(shstk_ptr))351 return 1;352 printf("[INFO]\tGup read -> write access success\n");353 354 reset_test_shstk(0);355 if (gup_write(shstk_ptr))356 return 1;357 if (!test_write_access(shstk_ptr))358 return 1;359 printf("[INFO]\tGup write -> write access success\n");360 361 close(fd);362 363 /* COW/gup test */364 reset_test_shstk(0);365 pid = fork();366 if (!pid) {367 fd = open("/proc/self/mem", O_RDWR);368 if (fd == -1)369 exit(1);370 371 if (gup_write(shstk_ptr)) {372 close(fd);373 exit(1);374 }375 close(fd);376 exit(0);377 }378 waitpid(pid, &status, 0);379 if (WEXITSTATUS(status)) {380 printf("[FAIL]\tWrite in child failed\n");381 return 1;382 }383 if (*(unsigned long *)shstk_ptr == MAGIC_VAL) {384 printf("[FAIL]\tWrite in child wrote through to shared memory\n");385 return 1;386 }387 388 printf("[INFO]\tCow gup write -> write access success\n");389 390 free_shstk(shstk_ptr);391 392 signal(SIGSEGV, SIG_DFL);393 394 printf("[OK]\tShadow gup test\n");395 396 return 0;397}398 399int test_mprotect(void)400{401 struct sigaction sa = {};402 403 sa.sa_sigaction = test_access_fix_handler;404 sa.sa_flags = SA_SIGINFO;405 if (sigaction(SIGSEGV, &sa, NULL))406 return 1;407 408 segv_triggered = false;409 410 /* mprotect a shadow stack as read only */411 reset_test_shstk(0);412 if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) {413 printf("[FAIL]\tmprotect(PROT_READ) failed\n");414 return 1;415 }416 417 /* try to wrss it and fail */418 if (!test_shstk_access(shstk_ptr)) {419 printf("[FAIL]\tShadow stack access to read-only memory succeeded\n");420 return 1;421 }422 423 /*424 * The shadow stack was reset above to resolve the fault, make the new one425 * read-only.426 */427 if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) {428 printf("[FAIL]\tmprotect(PROT_READ) failed\n");429 return 1;430 }431 432 /* then back to writable */433 if (mprotect(shstk_ptr, SS_SIZE, PROT_WRITE | PROT_READ) < 0) {434 printf("[FAIL]\tmprotect(PROT_WRITE) failed\n");435 return 1;436 }437 438 /* then wrss to it and succeed */439 if (test_shstk_access(shstk_ptr)) {440 printf("[FAIL]\tShadow stack access to mprotect() writable memory failed\n");441 return 1;442 }443 444 free_shstk(shstk_ptr);445 446 signal(SIGSEGV, SIG_DFL);447 448 printf("[OK]\tmprotect() test\n");449 450 return 0;451}452 453char zero[4096];454 455static void *uffd_thread(void *arg)456{457 struct uffdio_copy req;458 int uffd = *(int *)arg;459 struct uffd_msg msg;460 int ret;461 462 while (1) {463 ret = read(uffd, &msg, sizeof(msg));464 if (ret > 0)465 break;466 else if (errno == EAGAIN)467 continue;468 return (void *)1;469 }470 471 req.dst = msg.arg.pagefault.address;472 req.src = (__u64)zero;473 req.len = 4096;474 req.mode = 0;475 476 if (ioctl(uffd, UFFDIO_COPY, &req))477 return (void *)1;478 479 return (void *)0;480}481 482int test_userfaultfd(void)483{484 struct uffdio_register uffdio_register;485 struct uffdio_api uffdio_api;486 struct sigaction sa = {};487 pthread_t thread;488 void *res;489 int uffd;490 491 sa.sa_sigaction = test_access_fix_handler;492 sa.sa_flags = SA_SIGINFO;493 if (sigaction(SIGSEGV, &sa, NULL))494 return 1;495 496 uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK);497 if (uffd < 0) {498 printf("[SKIP]\tUserfaultfd unavailable.\n");499 return 0;500 }501 502 reset_test_shstk(0);503 504 uffdio_api.api = UFFD_API;505 uffdio_api.features = 0;506 if (ioctl(uffd, UFFDIO_API, &uffdio_api))507 goto err;508 509 uffdio_register.range.start = (__u64)shstk_ptr;510 uffdio_register.range.len = 4096;511 uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING;512 if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register))513 goto err;514 515 if (pthread_create(&thread, NULL, &uffd_thread, &uffd))516 goto err;517 518 reset_shstk(shstk_ptr);519 test_shstk_access(shstk_ptr);520 521 if (pthread_join(thread, &res))522 goto err;523 524 if (test_shstk_access(shstk_ptr))525 goto err;526 527 free_shstk(shstk_ptr);528 529 signal(SIGSEGV, SIG_DFL);530 531 if (!res)532 printf("[OK]\tUserfaultfd test\n");533 return !!res;534err:535 free_shstk(shstk_ptr);536 close(uffd);537 signal(SIGSEGV, SIG_DFL);538 return 1;539}540 541/* Simple linked list for keeping track of mappings in test_guard_gap() */542struct node {543 struct node *next;544 void *mapping;545};546 547/*548 * This tests whether mmap will place other mappings in a shadow stack's guard549 * gap. The steps are:550 * 1. Finds an empty place by mapping and unmapping something.551 * 2. Map a shadow stack in the middle of the known empty area.552 * 3. Map a bunch of PAGE_SIZE mappings. These will use the search down553 * direction, filling any gaps until it encounters the shadow stack's554 * guard gap.555 * 4. When a mapping lands below the shadow stack from step 2, then all556 * of the above gaps are filled. The search down algorithm will have557 * looked at the shadow stack gaps.558 * 5. See if it landed in the gap.559 */560int test_guard_gap_other_gaps(void)561{562 void *free_area, *shstk, *test_map = (void *)0xFFFFFFFFFFFFFFFF;563 struct node *head = NULL, *cur;564 565 free_area = mmap(0, SS_SIZE * 3, PROT_READ | PROT_WRITE,566 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);567 munmap(free_area, SS_SIZE * 3);568 569 shstk = create_shstk(free_area + SS_SIZE);570 if (shstk == MAP_FAILED)571 return 1;572 573 while (test_map > shstk) {574 test_map = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE,575 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);576 if (test_map == MAP_FAILED)577 return 1;578 cur = malloc(sizeof(*cur));579 cur->mapping = test_map;580 581 cur->next = head;582 head = cur;583 }584 585 while (head) {586 cur = head;587 head = cur->next;588 munmap(cur->mapping, PAGE_SIZE);589 free(cur);590 }591 592 free_shstk(shstk);593 594 if (shstk - test_map - PAGE_SIZE != PAGE_SIZE)595 return 1;596 597 printf("[OK]\tGuard gap test, other mapping's gaps\n");598 599 return 0;600}601 602/* Tests respecting the guard gap of the mapping getting placed */603int test_guard_gap_new_mappings_gaps(void)604{605 void *free_area, *shstk_start, *test_map = (void *)0xFFFFFFFFFFFFFFFF;606 struct node *head = NULL, *cur;607 int ret = 0;608 609 free_area = mmap(0, PAGE_SIZE * 4, PROT_READ | PROT_WRITE,610 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);611 munmap(free_area, PAGE_SIZE * 4);612 613 /* Test letting map_shadow_stack find a free space */614 shstk_start = mmap(free_area, PAGE_SIZE, PROT_READ | PROT_WRITE,615 MAP_PRIVATE | MAP_ANONYMOUS, -1, 0);616 if (shstk_start == MAP_FAILED || shstk_start != free_area)617 return 1;618 619 while (test_map > shstk_start) {620 test_map = (void *)syscall(__NR_map_shadow_stack, 0, PAGE_SIZE, 0);621 if (test_map == MAP_FAILED) {622 printf("[INFO]\tmap_shadow_stack MAP_FAILED\n");623 ret = 1;624 break;625 }626 627 cur = malloc(sizeof(*cur));628 cur->mapping = test_map;629 630 cur->next = head;631 head = cur;632 633 if (test_map == free_area + PAGE_SIZE) {634 printf("[INFO]\tNew mapping has other mapping in guard gap!\n");635 ret = 1;636 break;637 }638 }639 640 while (head) {641 cur = head;642 head = cur->next;643 munmap(cur->mapping, PAGE_SIZE);644 free(cur);645 }646 647 munmap(shstk_start, PAGE_SIZE);648 649 if (!ret)650 printf("[OK]\tGuard gap test, placement mapping's gaps\n");651 652 return ret;653}654 655/*656 * Too complicated to pull it out of the 32 bit header, but also get the657 * 64 bit one needed above. Just define a copy here.658 */659#define __NR_compat_sigaction 67660 661/*662 * Call 32 bit signal handler to get 32 bit signals ABI. Make sure663 * to push the registers that will get clobbered.664 */665int sigaction32(int signum, const struct sigaction *restrict act,666 struct sigaction *restrict oldact)667{668 register long syscall_reg asm("eax") = __NR_compat_sigaction;669 register long signum_reg asm("ebx") = signum;670 register long act_reg asm("ecx") = (long)act;671 register long oldact_reg asm("edx") = (long)oldact;672 int ret = 0;673 674 asm volatile ("int $0x80;"675 : "=a"(ret), "=m"(oldact)676 : "r"(syscall_reg), "r"(signum_reg), "r"(act_reg),677 "r"(oldact_reg)678 : "r8", "r9", "r10", "r11"679 );680 681 return ret;682}683 684sigjmp_buf jmp_buffer;685 686void segv_gp_handler(int signum, siginfo_t *si, void *uc)687{688 segv_triggered = true;689 690 /*691 * To work with old glibc, this can't rely on siglongjmp working with692 * shadow stack enabled, so disable shadow stack before siglongjmp().693 */694 ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);695 siglongjmp(jmp_buffer, -1);696}697 698/*699 * Transition to 32 bit mode and check that a #GP triggers a segfault.700 */701int test_32bit(void)702{703 struct sigaction sa = {};704 struct sigaction *sa32;705 706 /* Create sigaction in 32 bit address range */707 sa32 = mmap(0, 4096, PROT_READ | PROT_WRITE,708 MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0);709 sa32->sa_flags = SA_SIGINFO;710 711 sa.sa_sigaction = segv_gp_handler;712 sa.sa_flags = SA_SIGINFO;713 if (sigaction(SIGSEGV, &sa, NULL))714 return 1;715 716 717 segv_triggered = false;718 719 /* Make sure segv_triggered is set before triggering the #GP */720 asm volatile("" : : : "memory");721 722 /*723 * Set handler to somewhere in 32 bit address space724 */725 sa32->sa_handler = (void *)sa32;726 if (sigaction32(SIGUSR1, sa32, NULL))727 return 1;728 729 if (!sigsetjmp(jmp_buffer, 1))730 raise(SIGUSR1);731 732 if (segv_triggered)733 printf("[OK]\t32 bit test\n");734 735 return !segv_triggered;736}737 738static int parse_uint_from_file(const char *file, const char *fmt)739{740 int err, ret;741 FILE *f;742 743 f = fopen(file, "re");744 if (!f) {745 err = -errno;746 printf("failed to open '%s': %d\n", file, err);747 return err;748 }749 err = fscanf(f, fmt, &ret);750 if (err != 1) {751 err = err == EOF ? -EIO : -errno;752 printf("failed to parse '%s': %d\n", file, err);753 fclose(f);754 return err;755 }756 fclose(f);757 return ret;758}759 760static int determine_uprobe_perf_type(void)761{762 const char *file = "/sys/bus/event_source/devices/uprobe/type";763 764 return parse_uint_from_file(file, "%d\n");765}766 767static int determine_uprobe_retprobe_bit(void)768{769 const char *file = "/sys/bus/event_source/devices/uprobe/format/retprobe";770 771 return parse_uint_from_file(file, "config:%d\n");772}773 774static ssize_t get_uprobe_offset(const void *addr)775{776 size_t start, end, base;777 char buf[256];778 bool found = false;779 FILE *f;780 781 f = fopen("/proc/self/maps", "r");782 if (!f)783 return -errno;784 785 while (fscanf(f, "%zx-%zx %s %zx %*[^\n]\n", &start, &end, buf, &base) == 4) {786 if (buf[2] == 'x' && (uintptr_t)addr >= start && (uintptr_t)addr < end) {787 found = true;788 break;789 }790 }791 792 fclose(f);793 794 if (!found)795 return -ESRCH;796 797 return (uintptr_t)addr - start + base;798}799 800static __attribute__((noinline)) void uretprobe_trigger(void)801{802 asm volatile ("");803}804 805/*806 * This test setups return uprobe, which is sensitive to shadow stack807 * (crashes without extra fix). After executing the uretprobe we fail808 * the test if we receive SIGSEGV, no crash means we're good.809 *810 * Helper functions above borrowed from bpf selftests.811 */812static int test_uretprobe(void)813{814 const size_t attr_sz = sizeof(struct perf_event_attr);815 const char *file = "/proc/self/exe";816 int bit, fd = 0, type, err = 1;817 struct perf_event_attr attr;818 struct sigaction sa = {};819 ssize_t offset;820 821 type = determine_uprobe_perf_type();822 if (type < 0) {823 if (type == -ENOENT)824 printf("[SKIP]\tUretprobe test, uprobes are not available\n");825 return 0;826 }827 828 offset = get_uprobe_offset(uretprobe_trigger);829 if (offset < 0)830 return 1;831 832 bit = determine_uprobe_retprobe_bit();833 if (bit < 0)834 return 1;835 836 sa.sa_sigaction = segv_gp_handler;837 sa.sa_flags = SA_SIGINFO;838 if (sigaction(SIGSEGV, &sa, NULL))839 return 1;840 841 /* Setup return uprobe through perf event interface. */842 memset(&attr, 0, attr_sz);843 attr.size = attr_sz;844 attr.type = type;845 attr.config = 1 << bit;846 attr.config1 = (__u64) (unsigned long) file;847 attr.config2 = offset;848 849 fd = syscall(__NR_perf_event_open, &attr, 0 /* pid */, -1 /* cpu */,850 -1 /* group_fd */, PERF_FLAG_FD_CLOEXEC);851 if (fd < 0)852 goto out;853 854 if (sigsetjmp(jmp_buffer, 1))855 goto out;856 857 ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK);858 859 /*860 * This either segfaults and goes through sigsetjmp above861 * or succeeds and we're good.862 */863 uretprobe_trigger();864 865 printf("[OK]\tUretprobe test\n");866 err = 0;867 868out:869 ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK);870 signal(SIGSEGV, SIG_DFL);871 if (fd)872 close(fd);873 return err;874}875 876void segv_handler_ptrace(int signum, siginfo_t *si, void *uc)877{878 /* The SSP adjustment caused a segfault. */879 exit(0);880}881 882int test_ptrace(void)883{884 unsigned long saved_ssp, ssp = 0;885 struct sigaction sa= {};886 struct iovec iov;887 int status;888 int pid;889 890 iov.iov_base = &ssp;891 iov.iov_len = sizeof(ssp);892 893 pid = fork();894 if (!pid) {895 ssp = get_ssp();896 897 sa.sa_sigaction = segv_handler_ptrace;898 sa.sa_flags = SA_SIGINFO;899 if (sigaction(SIGSEGV, &sa, NULL))900 return 1;901 902 ptrace(PTRACE_TRACEME, NULL, NULL, NULL);903 /*904 * The parent will tweak the SSP and return from this function905 * will #CP.906 */907 raise(SIGTRAP);908 909 exit(1);910 }911 912 while (waitpid(pid, &status, 0) != -1 && WSTOPSIG(status) != SIGTRAP);913 914 if (ptrace(PTRACE_GETREGSET, pid, NT_X86_SHSTK, &iov)) {915 printf("[INFO]\tFailed to PTRACE_GETREGS\n");916 goto out_kill;917 }918 919 if (!ssp) {920 printf("[INFO]\tPtrace child SSP was 0\n");921 goto out_kill;922 }923 924 saved_ssp = ssp;925 926 iov.iov_len = 0;927 if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {928 printf("[INFO]\tToo small size accepted via PTRACE_SETREGS\n");929 goto out_kill;930 }931 932 iov.iov_len = sizeof(ssp) + 1;933 if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {934 printf("[INFO]\tToo large size accepted via PTRACE_SETREGS\n");935 goto out_kill;936 }937 938 ssp += 1;939 if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {940 printf("[INFO]\tUnaligned SSP written via PTRACE_SETREGS\n");941 goto out_kill;942 }943 944 ssp = 0xFFFFFFFFFFFF0000;945 if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {946 printf("[INFO]\tKernel range SSP written via PTRACE_SETREGS\n");947 goto out_kill;948 }949 950 /*951 * Tweak the SSP so the child with #CP when it resumes and returns952 * from raise()953 */954 ssp = saved_ssp + 8;955 iov.iov_len = sizeof(ssp);956 if (ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) {957 printf("[INFO]\tFailed to PTRACE_SETREGS\n");958 goto out_kill;959 }960 961 if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) {962 printf("[INFO]\tFailed to PTRACE_DETACH\n");963 goto out_kill;964 }965 966 waitpid(pid, &status, 0);967 if (WEXITSTATUS(status))968 return 1;969 970 printf("[OK]\tPtrace test\n");971 return 0;972 973out_kill:974 kill(pid, SIGKILL);975 return 1;976}977 978int main(int argc, char *argv[])979{980 int ret = 0;981 982 if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {983 printf("[SKIP]\tCould not enable Shadow stack\n");984 return 1;985 }986 987 if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {988 ret = 1;989 printf("[FAIL]\tDisabling shadow stack failed\n");990 }991 992 if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) {993 printf("[SKIP]\tCould not re-enable Shadow stack\n");994 return 1;995 }996 997 if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_WRSS)) {998 printf("[SKIP]\tCould not enable WRSS\n");999 ret = 1;1000 goto out;1001 }1002 1003 /* Should have succeeded if here, but this is a test, so double check. */1004 if (!get_ssp()) {1005 printf("[FAIL]\tShadow stack disabled\n");1006 return 1;1007 }1008 1009 if (test_shstk_pivot()) {1010 ret = 1;1011 printf("[FAIL]\tShadow stack pivot\n");1012 goto out;1013 }1014 1015 if (test_shstk_faults()) {1016 ret = 1;1017 printf("[FAIL]\tShadow stack fault test\n");1018 goto out;1019 }1020 1021 if (test_shstk_violation()) {1022 ret = 1;1023 printf("[FAIL]\tShadow stack violation test\n");1024 goto out;1025 }1026 1027 if (test_gup()) {1028 ret = 1;1029 printf("[FAIL]\tShadow shadow stack gup\n");1030 goto out;1031 }1032 1033 if (test_mprotect()) {1034 ret = 1;1035 printf("[FAIL]\tShadow shadow mprotect test\n");1036 goto out;1037 }1038 1039 if (test_userfaultfd()) {1040 ret = 1;1041 printf("[FAIL]\tUserfaultfd test\n");1042 goto out;1043 }1044 1045 if (test_guard_gap_other_gaps()) {1046 ret = 1;1047 printf("[FAIL]\tGuard gap test, other mappings' gaps\n");1048 goto out;1049 }1050 1051 if (test_guard_gap_new_mappings_gaps()) {1052 ret = 1;1053 printf("[FAIL]\tGuard gap test, placement mapping's gaps\n");1054 goto out;1055 }1056 1057 if (test_ptrace()) {1058 ret = 1;1059 printf("[FAIL]\tptrace test\n");1060 }1061 1062 if (test_32bit()) {1063 ret = 1;1064 printf("[FAIL]\t32 bit test\n");1065 goto out;1066 }1067 1068 if (test_uretprobe()) {1069 ret = 1;1070 printf("[FAIL]\turetprobe test\n");1071 goto out;1072 }1073 1074 return ret;1075 1076out:1077 /*1078 * Disable shadow stack before the function returns, or there will be a1079 * shadow stack violation.1080 */1081 if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) {1082 ret = 1;1083 printf("[FAIL]\tDisabling shadow stack failed\n");1084 }1085 1086 return ret;1087}1088#endif1089