1*81f30337SRick Edgecombe // SPDX-License-Identifier: GPL-2.0 2*81f30337SRick Edgecombe /* 3*81f30337SRick Edgecombe * This program test's basic kernel shadow stack support. It enables shadow 4*81f30337SRick Edgecombe * stack manual via the arch_prctl(), instead of relying on glibc. It's 5*81f30337SRick Edgecombe * Makefile doesn't compile with shadow stack support, so it doesn't rely on 6*81f30337SRick Edgecombe * any particular glibc. As a result it can't do any operations that require 7*81f30337SRick Edgecombe * special glibc shadow stack support (longjmp(), swapcontext(), etc). Just 8*81f30337SRick Edgecombe * stick to the basics and hope the compiler doesn't do anything strange. 9*81f30337SRick Edgecombe */ 10*81f30337SRick Edgecombe 11*81f30337SRick Edgecombe #define _GNU_SOURCE 12*81f30337SRick Edgecombe 13*81f30337SRick Edgecombe #include <sys/syscall.h> 14*81f30337SRick Edgecombe #include <asm/mman.h> 15*81f30337SRick Edgecombe #include <sys/mman.h> 16*81f30337SRick Edgecombe #include <sys/stat.h> 17*81f30337SRick Edgecombe #include <sys/wait.h> 18*81f30337SRick Edgecombe #include <stdio.h> 19*81f30337SRick Edgecombe #include <stdlib.h> 20*81f30337SRick Edgecombe #include <fcntl.h> 21*81f30337SRick Edgecombe #include <unistd.h> 22*81f30337SRick Edgecombe #include <string.h> 23*81f30337SRick Edgecombe #include <errno.h> 24*81f30337SRick Edgecombe #include <stdbool.h> 25*81f30337SRick Edgecombe #include <x86intrin.h> 26*81f30337SRick Edgecombe #include <asm/prctl.h> 27*81f30337SRick Edgecombe #include <sys/prctl.h> 28*81f30337SRick Edgecombe #include <stdint.h> 29*81f30337SRick Edgecombe #include <signal.h> 30*81f30337SRick Edgecombe #include <pthread.h> 31*81f30337SRick Edgecombe #include <sys/ioctl.h> 32*81f30337SRick Edgecombe #include <linux/userfaultfd.h> 33*81f30337SRick Edgecombe #include <setjmp.h> 34*81f30337SRick Edgecombe #include <sys/ptrace.h> 35*81f30337SRick Edgecombe #include <sys/signal.h> 36*81f30337SRick Edgecombe #include <linux/elf.h> 37*81f30337SRick Edgecombe 38*81f30337SRick Edgecombe /* 39*81f30337SRick Edgecombe * Define the ABI defines if needed, so people can run the tests 40*81f30337SRick Edgecombe * without building the headers. 41*81f30337SRick Edgecombe */ 42*81f30337SRick Edgecombe #ifndef __NR_map_shadow_stack 43*81f30337SRick Edgecombe #define __NR_map_shadow_stack 452 44*81f30337SRick Edgecombe 45*81f30337SRick Edgecombe #define SHADOW_STACK_SET_TOKEN (1ULL << 0) 46*81f30337SRick Edgecombe 47*81f30337SRick Edgecombe #define ARCH_SHSTK_ENABLE 0x5001 48*81f30337SRick Edgecombe #define ARCH_SHSTK_DISABLE 0x5002 49*81f30337SRick Edgecombe #define ARCH_SHSTK_LOCK 0x5003 50*81f30337SRick Edgecombe #define ARCH_SHSTK_UNLOCK 0x5004 51*81f30337SRick Edgecombe #define ARCH_SHSTK_STATUS 0x5005 52*81f30337SRick Edgecombe 53*81f30337SRick Edgecombe #define ARCH_SHSTK_SHSTK (1ULL << 0) 54*81f30337SRick Edgecombe #define ARCH_SHSTK_WRSS (1ULL << 1) 55*81f30337SRick Edgecombe 56*81f30337SRick Edgecombe #define NT_X86_SHSTK 0x204 57*81f30337SRick Edgecombe #endif 58*81f30337SRick Edgecombe 59*81f30337SRick Edgecombe #define SS_SIZE 0x200000 60*81f30337SRick Edgecombe #define PAGE_SIZE 0x1000 61*81f30337SRick Edgecombe 62*81f30337SRick Edgecombe #if (__GNUC__ < 8) || (__GNUC__ == 8 && __GNUC_MINOR__ < 5) 63*81f30337SRick Edgecombe int main(int argc, char *argv[]) 64*81f30337SRick Edgecombe { 65*81f30337SRick Edgecombe printf("[SKIP]\tCompiler does not support CET.\n"); 66*81f30337SRick Edgecombe return 0; 67*81f30337SRick Edgecombe } 68*81f30337SRick Edgecombe #else 69*81f30337SRick Edgecombe void write_shstk(unsigned long *addr, unsigned long val) 70*81f30337SRick Edgecombe { 71*81f30337SRick Edgecombe asm volatile("wrssq %[val], (%[addr])\n" 72*81f30337SRick Edgecombe : "=m" (addr) 73*81f30337SRick Edgecombe : [addr] "r" (addr), [val] "r" (val)); 74*81f30337SRick Edgecombe } 75*81f30337SRick Edgecombe 76*81f30337SRick Edgecombe static inline unsigned long __attribute__((always_inline)) get_ssp(void) 77*81f30337SRick Edgecombe { 78*81f30337SRick Edgecombe unsigned long ret = 0; 79*81f30337SRick Edgecombe 80*81f30337SRick Edgecombe asm volatile("xor %0, %0; rdsspq %0" : "=r" (ret)); 81*81f30337SRick Edgecombe return ret; 82*81f30337SRick Edgecombe } 83*81f30337SRick Edgecombe 84*81f30337SRick Edgecombe /* 85*81f30337SRick Edgecombe * For use in inline enablement of shadow stack. 86*81f30337SRick Edgecombe * 87*81f30337SRick Edgecombe * The program can't return from the point where shadow stack gets enabled 88*81f30337SRick Edgecombe * because there will be no address on the shadow stack. So it can't use 89*81f30337SRick Edgecombe * syscall() for enablement, since it is a function. 90*81f30337SRick Edgecombe * 91*81f30337SRick Edgecombe * Based on code from nolibc.h. Keep a copy here because this can't pull in all 92*81f30337SRick Edgecombe * of nolibc.h. 93*81f30337SRick Edgecombe */ 94*81f30337SRick Edgecombe #define ARCH_PRCTL(arg1, arg2) \ 95*81f30337SRick Edgecombe ({ \ 96*81f30337SRick Edgecombe long _ret; \ 97*81f30337SRick Edgecombe register long _num asm("eax") = __NR_arch_prctl; \ 98*81f30337SRick Edgecombe register long _arg1 asm("rdi") = (long)(arg1); \ 99*81f30337SRick Edgecombe register long _arg2 asm("rsi") = (long)(arg2); \ 100*81f30337SRick Edgecombe \ 101*81f30337SRick Edgecombe asm volatile ( \ 102*81f30337SRick Edgecombe "syscall\n" \ 103*81f30337SRick Edgecombe : "=a"(_ret) \ 104*81f30337SRick Edgecombe : "r"(_arg1), "r"(_arg2), \ 105*81f30337SRick Edgecombe "0"(_num) \ 106*81f30337SRick Edgecombe : "rcx", "r11", "memory", "cc" \ 107*81f30337SRick Edgecombe ); \ 108*81f30337SRick Edgecombe _ret; \ 109*81f30337SRick Edgecombe }) 110*81f30337SRick Edgecombe 111*81f30337SRick Edgecombe void *create_shstk(void *addr) 112*81f30337SRick Edgecombe { 113*81f30337SRick Edgecombe return (void *)syscall(__NR_map_shadow_stack, addr, SS_SIZE, SHADOW_STACK_SET_TOKEN); 114*81f30337SRick Edgecombe } 115*81f30337SRick Edgecombe 116*81f30337SRick Edgecombe void *create_normal_mem(void *addr) 117*81f30337SRick Edgecombe { 118*81f30337SRick Edgecombe return mmap(addr, SS_SIZE, PROT_READ | PROT_WRITE, 119*81f30337SRick Edgecombe MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 120*81f30337SRick Edgecombe } 121*81f30337SRick Edgecombe 122*81f30337SRick Edgecombe void free_shstk(void *shstk) 123*81f30337SRick Edgecombe { 124*81f30337SRick Edgecombe munmap(shstk, SS_SIZE); 125*81f30337SRick Edgecombe } 126*81f30337SRick Edgecombe 127*81f30337SRick Edgecombe int reset_shstk(void *shstk) 128*81f30337SRick Edgecombe { 129*81f30337SRick Edgecombe return madvise(shstk, SS_SIZE, MADV_DONTNEED); 130*81f30337SRick Edgecombe } 131*81f30337SRick Edgecombe 132*81f30337SRick Edgecombe void try_shstk(unsigned long new_ssp) 133*81f30337SRick Edgecombe { 134*81f30337SRick Edgecombe unsigned long ssp; 135*81f30337SRick Edgecombe 136*81f30337SRick Edgecombe printf("[INFO]\tnew_ssp = %lx, *new_ssp = %lx\n", 137*81f30337SRick Edgecombe new_ssp, *((unsigned long *)new_ssp)); 138*81f30337SRick Edgecombe 139*81f30337SRick Edgecombe ssp = get_ssp(); 140*81f30337SRick Edgecombe printf("[INFO]\tchanging ssp from %lx to %lx\n", ssp, new_ssp); 141*81f30337SRick Edgecombe 142*81f30337SRick Edgecombe asm volatile("rstorssp (%0)\n":: "r" (new_ssp)); 143*81f30337SRick Edgecombe asm volatile("saveprevssp"); 144*81f30337SRick Edgecombe printf("[INFO]\tssp is now %lx\n", get_ssp()); 145*81f30337SRick Edgecombe 146*81f30337SRick Edgecombe /* Switch back to original shadow stack */ 147*81f30337SRick Edgecombe ssp -= 8; 148*81f30337SRick Edgecombe asm volatile("rstorssp (%0)\n":: "r" (ssp)); 149*81f30337SRick Edgecombe asm volatile("saveprevssp"); 150*81f30337SRick Edgecombe } 151*81f30337SRick Edgecombe 152*81f30337SRick Edgecombe int test_shstk_pivot(void) 153*81f30337SRick Edgecombe { 154*81f30337SRick Edgecombe void *shstk = create_shstk(0); 155*81f30337SRick Edgecombe 156*81f30337SRick Edgecombe if (shstk == MAP_FAILED) { 157*81f30337SRick Edgecombe printf("[FAIL]\tError creating shadow stack: %d\n", errno); 158*81f30337SRick Edgecombe return 1; 159*81f30337SRick Edgecombe } 160*81f30337SRick Edgecombe try_shstk((unsigned long)shstk + SS_SIZE - 8); 161*81f30337SRick Edgecombe free_shstk(shstk); 162*81f30337SRick Edgecombe 163*81f30337SRick Edgecombe printf("[OK]\tShadow stack pivot\n"); 164*81f30337SRick Edgecombe return 0; 165*81f30337SRick Edgecombe } 166*81f30337SRick Edgecombe 167*81f30337SRick Edgecombe int test_shstk_faults(void) 168*81f30337SRick Edgecombe { 169*81f30337SRick Edgecombe unsigned long *shstk = create_shstk(0); 170*81f30337SRick Edgecombe 171*81f30337SRick Edgecombe /* Read shadow stack, test if it's zero to not get read optimized out */ 172*81f30337SRick Edgecombe if (*shstk != 0) 173*81f30337SRick Edgecombe goto err; 174*81f30337SRick Edgecombe 175*81f30337SRick Edgecombe /* Wrss memory that was already read. */ 176*81f30337SRick Edgecombe write_shstk(shstk, 1); 177*81f30337SRick Edgecombe if (*shstk != 1) 178*81f30337SRick Edgecombe goto err; 179*81f30337SRick Edgecombe 180*81f30337SRick Edgecombe /* Page out memory, so we can wrss it again. */ 181*81f30337SRick Edgecombe if (reset_shstk((void *)shstk)) 182*81f30337SRick Edgecombe goto err; 183*81f30337SRick Edgecombe 184*81f30337SRick Edgecombe write_shstk(shstk, 1); 185*81f30337SRick Edgecombe if (*shstk != 1) 186*81f30337SRick Edgecombe goto err; 187*81f30337SRick Edgecombe 188*81f30337SRick Edgecombe printf("[OK]\tShadow stack faults\n"); 189*81f30337SRick Edgecombe return 0; 190*81f30337SRick Edgecombe 191*81f30337SRick Edgecombe err: 192*81f30337SRick Edgecombe return 1; 193*81f30337SRick Edgecombe } 194*81f30337SRick Edgecombe 195*81f30337SRick Edgecombe unsigned long saved_ssp; 196*81f30337SRick Edgecombe unsigned long saved_ssp_val; 197*81f30337SRick Edgecombe volatile bool segv_triggered; 198*81f30337SRick Edgecombe 199*81f30337SRick Edgecombe void __attribute__((noinline)) violate_ss(void) 200*81f30337SRick Edgecombe { 201*81f30337SRick Edgecombe saved_ssp = get_ssp(); 202*81f30337SRick Edgecombe saved_ssp_val = *(unsigned long *)saved_ssp; 203*81f30337SRick Edgecombe 204*81f30337SRick Edgecombe /* Corrupt shadow stack */ 205*81f30337SRick Edgecombe printf("[INFO]\tCorrupting shadow stack\n"); 206*81f30337SRick Edgecombe write_shstk((void *)saved_ssp, 0); 207*81f30337SRick Edgecombe } 208*81f30337SRick Edgecombe 209*81f30337SRick Edgecombe void segv_handler(int signum, siginfo_t *si, void *uc) 210*81f30337SRick Edgecombe { 211*81f30337SRick Edgecombe printf("[INFO]\tGenerated shadow stack violation successfully\n"); 212*81f30337SRick Edgecombe 213*81f30337SRick Edgecombe segv_triggered = true; 214*81f30337SRick Edgecombe 215*81f30337SRick Edgecombe /* Fix shadow stack */ 216*81f30337SRick Edgecombe write_shstk((void *)saved_ssp, saved_ssp_val); 217*81f30337SRick Edgecombe } 218*81f30337SRick Edgecombe 219*81f30337SRick Edgecombe int test_shstk_violation(void) 220*81f30337SRick Edgecombe { 221*81f30337SRick Edgecombe struct sigaction sa = {}; 222*81f30337SRick Edgecombe 223*81f30337SRick Edgecombe sa.sa_sigaction = segv_handler; 224*81f30337SRick Edgecombe sa.sa_flags = SA_SIGINFO; 225*81f30337SRick Edgecombe if (sigaction(SIGSEGV, &sa, NULL)) 226*81f30337SRick Edgecombe return 1; 227*81f30337SRick Edgecombe 228*81f30337SRick Edgecombe segv_triggered = false; 229*81f30337SRick Edgecombe 230*81f30337SRick Edgecombe /* Make sure segv_triggered is set before violate_ss() */ 231*81f30337SRick Edgecombe asm volatile("" : : : "memory"); 232*81f30337SRick Edgecombe 233*81f30337SRick Edgecombe violate_ss(); 234*81f30337SRick Edgecombe 235*81f30337SRick Edgecombe signal(SIGSEGV, SIG_DFL); 236*81f30337SRick Edgecombe 237*81f30337SRick Edgecombe printf("[OK]\tShadow stack violation test\n"); 238*81f30337SRick Edgecombe 239*81f30337SRick Edgecombe return !segv_triggered; 240*81f30337SRick Edgecombe } 241*81f30337SRick Edgecombe 242*81f30337SRick Edgecombe /* Gup test state */ 243*81f30337SRick Edgecombe #define MAGIC_VAL 0x12345678 244*81f30337SRick Edgecombe bool is_shstk_access; 245*81f30337SRick Edgecombe void *shstk_ptr; 246*81f30337SRick Edgecombe int fd; 247*81f30337SRick Edgecombe 248*81f30337SRick Edgecombe void reset_test_shstk(void *addr) 249*81f30337SRick Edgecombe { 250*81f30337SRick Edgecombe if (shstk_ptr) 251*81f30337SRick Edgecombe free_shstk(shstk_ptr); 252*81f30337SRick Edgecombe shstk_ptr = create_shstk(addr); 253*81f30337SRick Edgecombe } 254*81f30337SRick Edgecombe 255*81f30337SRick Edgecombe void test_access_fix_handler(int signum, siginfo_t *si, void *uc) 256*81f30337SRick Edgecombe { 257*81f30337SRick Edgecombe printf("[INFO]\tViolation from %s\n", is_shstk_access ? "shstk access" : "normal write"); 258*81f30337SRick Edgecombe 259*81f30337SRick Edgecombe segv_triggered = true; 260*81f30337SRick Edgecombe 261*81f30337SRick Edgecombe /* Fix shadow stack */ 262*81f30337SRick Edgecombe if (is_shstk_access) { 263*81f30337SRick Edgecombe reset_test_shstk(shstk_ptr); 264*81f30337SRick Edgecombe return; 265*81f30337SRick Edgecombe } 266*81f30337SRick Edgecombe 267*81f30337SRick Edgecombe free_shstk(shstk_ptr); 268*81f30337SRick Edgecombe create_normal_mem(shstk_ptr); 269*81f30337SRick Edgecombe } 270*81f30337SRick Edgecombe 271*81f30337SRick Edgecombe bool test_shstk_access(void *ptr) 272*81f30337SRick Edgecombe { 273*81f30337SRick Edgecombe is_shstk_access = true; 274*81f30337SRick Edgecombe segv_triggered = false; 275*81f30337SRick Edgecombe write_shstk(ptr, MAGIC_VAL); 276*81f30337SRick Edgecombe 277*81f30337SRick Edgecombe asm volatile("" : : : "memory"); 278*81f30337SRick Edgecombe 279*81f30337SRick Edgecombe return segv_triggered; 280*81f30337SRick Edgecombe } 281*81f30337SRick Edgecombe 282*81f30337SRick Edgecombe bool test_write_access(void *ptr) 283*81f30337SRick Edgecombe { 284*81f30337SRick Edgecombe is_shstk_access = false; 285*81f30337SRick Edgecombe segv_triggered = false; 286*81f30337SRick Edgecombe *(unsigned long *)ptr = MAGIC_VAL; 287*81f30337SRick Edgecombe 288*81f30337SRick Edgecombe asm volatile("" : : : "memory"); 289*81f30337SRick Edgecombe 290*81f30337SRick Edgecombe return segv_triggered; 291*81f30337SRick Edgecombe } 292*81f30337SRick Edgecombe 293*81f30337SRick Edgecombe bool gup_write(void *ptr) 294*81f30337SRick Edgecombe { 295*81f30337SRick Edgecombe unsigned long val; 296*81f30337SRick Edgecombe 297*81f30337SRick Edgecombe lseek(fd, (unsigned long)ptr, SEEK_SET); 298*81f30337SRick Edgecombe if (write(fd, &val, sizeof(val)) < 0) 299*81f30337SRick Edgecombe return 1; 300*81f30337SRick Edgecombe 301*81f30337SRick Edgecombe return 0; 302*81f30337SRick Edgecombe } 303*81f30337SRick Edgecombe 304*81f30337SRick Edgecombe bool gup_read(void *ptr) 305*81f30337SRick Edgecombe { 306*81f30337SRick Edgecombe unsigned long val; 307*81f30337SRick Edgecombe 308*81f30337SRick Edgecombe lseek(fd, (unsigned long)ptr, SEEK_SET); 309*81f30337SRick Edgecombe if (read(fd, &val, sizeof(val)) < 0) 310*81f30337SRick Edgecombe return 1; 311*81f30337SRick Edgecombe 312*81f30337SRick Edgecombe return 0; 313*81f30337SRick Edgecombe } 314*81f30337SRick Edgecombe 315*81f30337SRick Edgecombe int test_gup(void) 316*81f30337SRick Edgecombe { 317*81f30337SRick Edgecombe struct sigaction sa = {}; 318*81f30337SRick Edgecombe int status; 319*81f30337SRick Edgecombe pid_t pid; 320*81f30337SRick Edgecombe 321*81f30337SRick Edgecombe sa.sa_sigaction = test_access_fix_handler; 322*81f30337SRick Edgecombe sa.sa_flags = SA_SIGINFO; 323*81f30337SRick Edgecombe if (sigaction(SIGSEGV, &sa, NULL)) 324*81f30337SRick Edgecombe return 1; 325*81f30337SRick Edgecombe 326*81f30337SRick Edgecombe segv_triggered = false; 327*81f30337SRick Edgecombe 328*81f30337SRick Edgecombe fd = open("/proc/self/mem", O_RDWR); 329*81f30337SRick Edgecombe if (fd == -1) 330*81f30337SRick Edgecombe return 1; 331*81f30337SRick Edgecombe 332*81f30337SRick Edgecombe reset_test_shstk(0); 333*81f30337SRick Edgecombe if (gup_read(shstk_ptr)) 334*81f30337SRick Edgecombe return 1; 335*81f30337SRick Edgecombe if (test_shstk_access(shstk_ptr)) 336*81f30337SRick Edgecombe return 1; 337*81f30337SRick Edgecombe printf("[INFO]\tGup read -> shstk access success\n"); 338*81f30337SRick Edgecombe 339*81f30337SRick Edgecombe reset_test_shstk(0); 340*81f30337SRick Edgecombe if (gup_write(shstk_ptr)) 341*81f30337SRick Edgecombe return 1; 342*81f30337SRick Edgecombe if (test_shstk_access(shstk_ptr)) 343*81f30337SRick Edgecombe return 1; 344*81f30337SRick Edgecombe printf("[INFO]\tGup write -> shstk access success\n"); 345*81f30337SRick Edgecombe 346*81f30337SRick Edgecombe reset_test_shstk(0); 347*81f30337SRick Edgecombe if (gup_read(shstk_ptr)) 348*81f30337SRick Edgecombe return 1; 349*81f30337SRick Edgecombe if (!test_write_access(shstk_ptr)) 350*81f30337SRick Edgecombe return 1; 351*81f30337SRick Edgecombe printf("[INFO]\tGup read -> write access success\n"); 352*81f30337SRick Edgecombe 353*81f30337SRick Edgecombe reset_test_shstk(0); 354*81f30337SRick Edgecombe if (gup_write(shstk_ptr)) 355*81f30337SRick Edgecombe return 1; 356*81f30337SRick Edgecombe if (!test_write_access(shstk_ptr)) 357*81f30337SRick Edgecombe return 1; 358*81f30337SRick Edgecombe printf("[INFO]\tGup write -> write access success\n"); 359*81f30337SRick Edgecombe 360*81f30337SRick Edgecombe close(fd); 361*81f30337SRick Edgecombe 362*81f30337SRick Edgecombe /* COW/gup test */ 363*81f30337SRick Edgecombe reset_test_shstk(0); 364*81f30337SRick Edgecombe pid = fork(); 365*81f30337SRick Edgecombe if (!pid) { 366*81f30337SRick Edgecombe fd = open("/proc/self/mem", O_RDWR); 367*81f30337SRick Edgecombe if (fd == -1) 368*81f30337SRick Edgecombe exit(1); 369*81f30337SRick Edgecombe 370*81f30337SRick Edgecombe if (gup_write(shstk_ptr)) { 371*81f30337SRick Edgecombe close(fd); 372*81f30337SRick Edgecombe exit(1); 373*81f30337SRick Edgecombe } 374*81f30337SRick Edgecombe close(fd); 375*81f30337SRick Edgecombe exit(0); 376*81f30337SRick Edgecombe } 377*81f30337SRick Edgecombe waitpid(pid, &status, 0); 378*81f30337SRick Edgecombe if (WEXITSTATUS(status)) { 379*81f30337SRick Edgecombe printf("[FAIL]\tWrite in child failed\n"); 380*81f30337SRick Edgecombe return 1; 381*81f30337SRick Edgecombe } 382*81f30337SRick Edgecombe if (*(unsigned long *)shstk_ptr == MAGIC_VAL) { 383*81f30337SRick Edgecombe printf("[FAIL]\tWrite in child wrote through to shared memory\n"); 384*81f30337SRick Edgecombe return 1; 385*81f30337SRick Edgecombe } 386*81f30337SRick Edgecombe 387*81f30337SRick Edgecombe printf("[INFO]\tCow gup write -> write access success\n"); 388*81f30337SRick Edgecombe 389*81f30337SRick Edgecombe free_shstk(shstk_ptr); 390*81f30337SRick Edgecombe 391*81f30337SRick Edgecombe signal(SIGSEGV, SIG_DFL); 392*81f30337SRick Edgecombe 393*81f30337SRick Edgecombe printf("[OK]\tShadow gup test\n"); 394*81f30337SRick Edgecombe 395*81f30337SRick Edgecombe return 0; 396*81f30337SRick Edgecombe } 397*81f30337SRick Edgecombe 398*81f30337SRick Edgecombe int test_mprotect(void) 399*81f30337SRick Edgecombe { 400*81f30337SRick Edgecombe struct sigaction sa = {}; 401*81f30337SRick Edgecombe 402*81f30337SRick Edgecombe sa.sa_sigaction = test_access_fix_handler; 403*81f30337SRick Edgecombe sa.sa_flags = SA_SIGINFO; 404*81f30337SRick Edgecombe if (sigaction(SIGSEGV, &sa, NULL)) 405*81f30337SRick Edgecombe return 1; 406*81f30337SRick Edgecombe 407*81f30337SRick Edgecombe segv_triggered = false; 408*81f30337SRick Edgecombe 409*81f30337SRick Edgecombe /* mprotect a shadow stack as read only */ 410*81f30337SRick Edgecombe reset_test_shstk(0); 411*81f30337SRick Edgecombe if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) { 412*81f30337SRick Edgecombe printf("[FAIL]\tmprotect(PROT_READ) failed\n"); 413*81f30337SRick Edgecombe return 1; 414*81f30337SRick Edgecombe } 415*81f30337SRick Edgecombe 416*81f30337SRick Edgecombe /* try to wrss it and fail */ 417*81f30337SRick Edgecombe if (!test_shstk_access(shstk_ptr)) { 418*81f30337SRick Edgecombe printf("[FAIL]\tShadow stack access to read-only memory succeeded\n"); 419*81f30337SRick Edgecombe return 1; 420*81f30337SRick Edgecombe } 421*81f30337SRick Edgecombe 422*81f30337SRick Edgecombe /* 423*81f30337SRick Edgecombe * The shadow stack was reset above to resolve the fault, make the new one 424*81f30337SRick Edgecombe * read-only. 425*81f30337SRick Edgecombe */ 426*81f30337SRick Edgecombe if (mprotect(shstk_ptr, SS_SIZE, PROT_READ) < 0) { 427*81f30337SRick Edgecombe printf("[FAIL]\tmprotect(PROT_READ) failed\n"); 428*81f30337SRick Edgecombe return 1; 429*81f30337SRick Edgecombe } 430*81f30337SRick Edgecombe 431*81f30337SRick Edgecombe /* then back to writable */ 432*81f30337SRick Edgecombe if (mprotect(shstk_ptr, SS_SIZE, PROT_WRITE | PROT_READ) < 0) { 433*81f30337SRick Edgecombe printf("[FAIL]\tmprotect(PROT_WRITE) failed\n"); 434*81f30337SRick Edgecombe return 1; 435*81f30337SRick Edgecombe } 436*81f30337SRick Edgecombe 437*81f30337SRick Edgecombe /* then wrss to it and succeed */ 438*81f30337SRick Edgecombe if (test_shstk_access(shstk_ptr)) { 439*81f30337SRick Edgecombe printf("[FAIL]\tShadow stack access to mprotect() writable memory failed\n"); 440*81f30337SRick Edgecombe return 1; 441*81f30337SRick Edgecombe } 442*81f30337SRick Edgecombe 443*81f30337SRick Edgecombe free_shstk(shstk_ptr); 444*81f30337SRick Edgecombe 445*81f30337SRick Edgecombe signal(SIGSEGV, SIG_DFL); 446*81f30337SRick Edgecombe 447*81f30337SRick Edgecombe printf("[OK]\tmprotect() test\n"); 448*81f30337SRick Edgecombe 449*81f30337SRick Edgecombe return 0; 450*81f30337SRick Edgecombe } 451*81f30337SRick Edgecombe 452*81f30337SRick Edgecombe char zero[4096]; 453*81f30337SRick Edgecombe 454*81f30337SRick Edgecombe static void *uffd_thread(void *arg) 455*81f30337SRick Edgecombe { 456*81f30337SRick Edgecombe struct uffdio_copy req; 457*81f30337SRick Edgecombe int uffd = *(int *)arg; 458*81f30337SRick Edgecombe struct uffd_msg msg; 459*81f30337SRick Edgecombe int ret; 460*81f30337SRick Edgecombe 461*81f30337SRick Edgecombe while (1) { 462*81f30337SRick Edgecombe ret = read(uffd, &msg, sizeof(msg)); 463*81f30337SRick Edgecombe if (ret > 0) 464*81f30337SRick Edgecombe break; 465*81f30337SRick Edgecombe else if (errno == EAGAIN) 466*81f30337SRick Edgecombe continue; 467*81f30337SRick Edgecombe return (void *)1; 468*81f30337SRick Edgecombe } 469*81f30337SRick Edgecombe 470*81f30337SRick Edgecombe req.dst = msg.arg.pagefault.address; 471*81f30337SRick Edgecombe req.src = (__u64)zero; 472*81f30337SRick Edgecombe req.len = 4096; 473*81f30337SRick Edgecombe req.mode = 0; 474*81f30337SRick Edgecombe 475*81f30337SRick Edgecombe if (ioctl(uffd, UFFDIO_COPY, &req)) 476*81f30337SRick Edgecombe return (void *)1; 477*81f30337SRick Edgecombe 478*81f30337SRick Edgecombe return (void *)0; 479*81f30337SRick Edgecombe } 480*81f30337SRick Edgecombe 481*81f30337SRick Edgecombe int test_userfaultfd(void) 482*81f30337SRick Edgecombe { 483*81f30337SRick Edgecombe struct uffdio_register uffdio_register; 484*81f30337SRick Edgecombe struct uffdio_api uffdio_api; 485*81f30337SRick Edgecombe struct sigaction sa = {}; 486*81f30337SRick Edgecombe pthread_t thread; 487*81f30337SRick Edgecombe void *res; 488*81f30337SRick Edgecombe int uffd; 489*81f30337SRick Edgecombe 490*81f30337SRick Edgecombe sa.sa_sigaction = test_access_fix_handler; 491*81f30337SRick Edgecombe sa.sa_flags = SA_SIGINFO; 492*81f30337SRick Edgecombe if (sigaction(SIGSEGV, &sa, NULL)) 493*81f30337SRick Edgecombe return 1; 494*81f30337SRick Edgecombe 495*81f30337SRick Edgecombe uffd = syscall(__NR_userfaultfd, O_CLOEXEC | O_NONBLOCK); 496*81f30337SRick Edgecombe if (uffd < 0) { 497*81f30337SRick Edgecombe printf("[SKIP]\tUserfaultfd unavailable.\n"); 498*81f30337SRick Edgecombe return 0; 499*81f30337SRick Edgecombe } 500*81f30337SRick Edgecombe 501*81f30337SRick Edgecombe reset_test_shstk(0); 502*81f30337SRick Edgecombe 503*81f30337SRick Edgecombe uffdio_api.api = UFFD_API; 504*81f30337SRick Edgecombe uffdio_api.features = 0; 505*81f30337SRick Edgecombe if (ioctl(uffd, UFFDIO_API, &uffdio_api)) 506*81f30337SRick Edgecombe goto err; 507*81f30337SRick Edgecombe 508*81f30337SRick Edgecombe uffdio_register.range.start = (__u64)shstk_ptr; 509*81f30337SRick Edgecombe uffdio_register.range.len = 4096; 510*81f30337SRick Edgecombe uffdio_register.mode = UFFDIO_REGISTER_MODE_MISSING; 511*81f30337SRick Edgecombe if (ioctl(uffd, UFFDIO_REGISTER, &uffdio_register)) 512*81f30337SRick Edgecombe goto err; 513*81f30337SRick Edgecombe 514*81f30337SRick Edgecombe if (pthread_create(&thread, NULL, &uffd_thread, &uffd)) 515*81f30337SRick Edgecombe goto err; 516*81f30337SRick Edgecombe 517*81f30337SRick Edgecombe reset_shstk(shstk_ptr); 518*81f30337SRick Edgecombe test_shstk_access(shstk_ptr); 519*81f30337SRick Edgecombe 520*81f30337SRick Edgecombe if (pthread_join(thread, &res)) 521*81f30337SRick Edgecombe goto err; 522*81f30337SRick Edgecombe 523*81f30337SRick Edgecombe if (test_shstk_access(shstk_ptr)) 524*81f30337SRick Edgecombe goto err; 525*81f30337SRick Edgecombe 526*81f30337SRick Edgecombe free_shstk(shstk_ptr); 527*81f30337SRick Edgecombe 528*81f30337SRick Edgecombe signal(SIGSEGV, SIG_DFL); 529*81f30337SRick Edgecombe 530*81f30337SRick Edgecombe if (!res) 531*81f30337SRick Edgecombe printf("[OK]\tUserfaultfd test\n"); 532*81f30337SRick Edgecombe return !!res; 533*81f30337SRick Edgecombe err: 534*81f30337SRick Edgecombe free_shstk(shstk_ptr); 535*81f30337SRick Edgecombe close(uffd); 536*81f30337SRick Edgecombe signal(SIGSEGV, SIG_DFL); 537*81f30337SRick Edgecombe return 1; 538*81f30337SRick Edgecombe } 539*81f30337SRick Edgecombe 540*81f30337SRick Edgecombe /* Simple linked list for keeping track of mappings in test_guard_gap() */ 541*81f30337SRick Edgecombe struct node { 542*81f30337SRick Edgecombe struct node *next; 543*81f30337SRick Edgecombe void *mapping; 544*81f30337SRick Edgecombe }; 545*81f30337SRick Edgecombe 546*81f30337SRick Edgecombe /* 547*81f30337SRick Edgecombe * This tests whether mmap will place other mappings in a shadow stack's guard 548*81f30337SRick Edgecombe * gap. The steps are: 549*81f30337SRick Edgecombe * 1. Finds an empty place by mapping and unmapping something. 550*81f30337SRick Edgecombe * 2. Map a shadow stack in the middle of the known empty area. 551*81f30337SRick Edgecombe * 3. Map a bunch of PAGE_SIZE mappings. These will use the search down 552*81f30337SRick Edgecombe * direction, filling any gaps until it encounters the shadow stack's 553*81f30337SRick Edgecombe * guard gap. 554*81f30337SRick Edgecombe * 4. When a mapping lands below the shadow stack from step 2, then all 555*81f30337SRick Edgecombe * of the above gaps are filled. The search down algorithm will have 556*81f30337SRick Edgecombe * looked at the shadow stack gaps. 557*81f30337SRick Edgecombe * 5. See if it landed in the gap. 558*81f30337SRick Edgecombe */ 559*81f30337SRick Edgecombe int test_guard_gap(void) 560*81f30337SRick Edgecombe { 561*81f30337SRick Edgecombe void *free_area, *shstk, *test_map = (void *)0xFFFFFFFFFFFFFFFF; 562*81f30337SRick Edgecombe struct node *head = NULL, *cur; 563*81f30337SRick Edgecombe 564*81f30337SRick Edgecombe free_area = mmap(0, SS_SIZE * 3, PROT_READ | PROT_WRITE, 565*81f30337SRick Edgecombe MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 566*81f30337SRick Edgecombe munmap(free_area, SS_SIZE * 3); 567*81f30337SRick Edgecombe 568*81f30337SRick Edgecombe shstk = create_shstk(free_area + SS_SIZE); 569*81f30337SRick Edgecombe if (shstk == MAP_FAILED) 570*81f30337SRick Edgecombe return 1; 571*81f30337SRick Edgecombe 572*81f30337SRick Edgecombe while (test_map > shstk) { 573*81f30337SRick Edgecombe test_map = mmap(0, PAGE_SIZE, PROT_READ | PROT_WRITE, 574*81f30337SRick Edgecombe MAP_PRIVATE | MAP_ANONYMOUS, -1, 0); 575*81f30337SRick Edgecombe if (test_map == MAP_FAILED) 576*81f30337SRick Edgecombe return 1; 577*81f30337SRick Edgecombe cur = malloc(sizeof(*cur)); 578*81f30337SRick Edgecombe cur->mapping = test_map; 579*81f30337SRick Edgecombe 580*81f30337SRick Edgecombe cur->next = head; 581*81f30337SRick Edgecombe head = cur; 582*81f30337SRick Edgecombe } 583*81f30337SRick Edgecombe 584*81f30337SRick Edgecombe while (head) { 585*81f30337SRick Edgecombe cur = head; 586*81f30337SRick Edgecombe head = cur->next; 587*81f30337SRick Edgecombe munmap(cur->mapping, PAGE_SIZE); 588*81f30337SRick Edgecombe free(cur); 589*81f30337SRick Edgecombe } 590*81f30337SRick Edgecombe 591*81f30337SRick Edgecombe free_shstk(shstk); 592*81f30337SRick Edgecombe 593*81f30337SRick Edgecombe if (shstk - test_map - PAGE_SIZE != PAGE_SIZE) 594*81f30337SRick Edgecombe return 1; 595*81f30337SRick Edgecombe 596*81f30337SRick Edgecombe printf("[OK]\tGuard gap test\n"); 597*81f30337SRick Edgecombe 598*81f30337SRick Edgecombe return 0; 599*81f30337SRick Edgecombe } 600*81f30337SRick Edgecombe 601*81f30337SRick Edgecombe /* 602*81f30337SRick Edgecombe * Too complicated to pull it out of the 32 bit header, but also get the 603*81f30337SRick Edgecombe * 64 bit one needed above. Just define a copy here. 604*81f30337SRick Edgecombe */ 605*81f30337SRick Edgecombe #define __NR_compat_sigaction 67 606*81f30337SRick Edgecombe 607*81f30337SRick Edgecombe /* 608*81f30337SRick Edgecombe * Call 32 bit signal handler to get 32 bit signals ABI. Make sure 609*81f30337SRick Edgecombe * to push the registers that will get clobbered. 610*81f30337SRick Edgecombe */ 611*81f30337SRick Edgecombe int sigaction32(int signum, const struct sigaction *restrict act, 612*81f30337SRick Edgecombe struct sigaction *restrict oldact) 613*81f30337SRick Edgecombe { 614*81f30337SRick Edgecombe register long syscall_reg asm("eax") = __NR_compat_sigaction; 615*81f30337SRick Edgecombe register long signum_reg asm("ebx") = signum; 616*81f30337SRick Edgecombe register long act_reg asm("ecx") = (long)act; 617*81f30337SRick Edgecombe register long oldact_reg asm("edx") = (long)oldact; 618*81f30337SRick Edgecombe int ret = 0; 619*81f30337SRick Edgecombe 620*81f30337SRick Edgecombe asm volatile ("int $0x80;" 621*81f30337SRick Edgecombe : "=a"(ret), "=m"(oldact) 622*81f30337SRick Edgecombe : "r"(syscall_reg), "r"(signum_reg), "r"(act_reg), 623*81f30337SRick Edgecombe "r"(oldact_reg) 624*81f30337SRick Edgecombe : "r8", "r9", "r10", "r11" 625*81f30337SRick Edgecombe ); 626*81f30337SRick Edgecombe 627*81f30337SRick Edgecombe return ret; 628*81f30337SRick Edgecombe } 629*81f30337SRick Edgecombe 630*81f30337SRick Edgecombe sigjmp_buf jmp_buffer; 631*81f30337SRick Edgecombe 632*81f30337SRick Edgecombe void segv_gp_handler(int signum, siginfo_t *si, void *uc) 633*81f30337SRick Edgecombe { 634*81f30337SRick Edgecombe segv_triggered = true; 635*81f30337SRick Edgecombe 636*81f30337SRick Edgecombe /* 637*81f30337SRick Edgecombe * To work with old glibc, this can't rely on siglongjmp working with 638*81f30337SRick Edgecombe * shadow stack enabled, so disable shadow stack before siglongjmp(). 639*81f30337SRick Edgecombe */ 640*81f30337SRick Edgecombe ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK); 641*81f30337SRick Edgecombe siglongjmp(jmp_buffer, -1); 642*81f30337SRick Edgecombe } 643*81f30337SRick Edgecombe 644*81f30337SRick Edgecombe /* 645*81f30337SRick Edgecombe * Transition to 32 bit mode and check that a #GP triggers a segfault. 646*81f30337SRick Edgecombe */ 647*81f30337SRick Edgecombe int test_32bit(void) 648*81f30337SRick Edgecombe { 649*81f30337SRick Edgecombe struct sigaction sa = {}; 650*81f30337SRick Edgecombe struct sigaction *sa32; 651*81f30337SRick Edgecombe 652*81f30337SRick Edgecombe /* Create sigaction in 32 bit address range */ 653*81f30337SRick Edgecombe sa32 = mmap(0, 4096, PROT_READ | PROT_WRITE, 654*81f30337SRick Edgecombe MAP_32BIT | MAP_PRIVATE | MAP_ANONYMOUS, 0, 0); 655*81f30337SRick Edgecombe sa32->sa_flags = SA_SIGINFO; 656*81f30337SRick Edgecombe 657*81f30337SRick Edgecombe sa.sa_sigaction = segv_gp_handler; 658*81f30337SRick Edgecombe sa.sa_flags = SA_SIGINFO; 659*81f30337SRick Edgecombe if (sigaction(SIGSEGV, &sa, NULL)) 660*81f30337SRick Edgecombe return 1; 661*81f30337SRick Edgecombe 662*81f30337SRick Edgecombe 663*81f30337SRick Edgecombe segv_triggered = false; 664*81f30337SRick Edgecombe 665*81f30337SRick Edgecombe /* Make sure segv_triggered is set before triggering the #GP */ 666*81f30337SRick Edgecombe asm volatile("" : : : "memory"); 667*81f30337SRick Edgecombe 668*81f30337SRick Edgecombe /* 669*81f30337SRick Edgecombe * Set handler to somewhere in 32 bit address space 670*81f30337SRick Edgecombe */ 671*81f30337SRick Edgecombe sa32->sa_handler = (void *)sa32; 672*81f30337SRick Edgecombe if (sigaction32(SIGUSR1, sa32, NULL)) 673*81f30337SRick Edgecombe return 1; 674*81f30337SRick Edgecombe 675*81f30337SRick Edgecombe if (!sigsetjmp(jmp_buffer, 1)) 676*81f30337SRick Edgecombe raise(SIGUSR1); 677*81f30337SRick Edgecombe 678*81f30337SRick Edgecombe if (segv_triggered) 679*81f30337SRick Edgecombe printf("[OK]\t32 bit test\n"); 680*81f30337SRick Edgecombe 681*81f30337SRick Edgecombe return !segv_triggered; 682*81f30337SRick Edgecombe } 683*81f30337SRick Edgecombe 684*81f30337SRick Edgecombe void segv_handler_ptrace(int signum, siginfo_t *si, void *uc) 685*81f30337SRick Edgecombe { 686*81f30337SRick Edgecombe /* The SSP adjustment caused a segfault. */ 687*81f30337SRick Edgecombe exit(0); 688*81f30337SRick Edgecombe } 689*81f30337SRick Edgecombe 690*81f30337SRick Edgecombe int test_ptrace(void) 691*81f30337SRick Edgecombe { 692*81f30337SRick Edgecombe unsigned long saved_ssp, ssp = 0; 693*81f30337SRick Edgecombe struct sigaction sa= {}; 694*81f30337SRick Edgecombe struct iovec iov; 695*81f30337SRick Edgecombe int status; 696*81f30337SRick Edgecombe int pid; 697*81f30337SRick Edgecombe 698*81f30337SRick Edgecombe iov.iov_base = &ssp; 699*81f30337SRick Edgecombe iov.iov_len = sizeof(ssp); 700*81f30337SRick Edgecombe 701*81f30337SRick Edgecombe pid = fork(); 702*81f30337SRick Edgecombe if (!pid) { 703*81f30337SRick Edgecombe ssp = get_ssp(); 704*81f30337SRick Edgecombe 705*81f30337SRick Edgecombe sa.sa_sigaction = segv_handler_ptrace; 706*81f30337SRick Edgecombe sa.sa_flags = SA_SIGINFO; 707*81f30337SRick Edgecombe if (sigaction(SIGSEGV, &sa, NULL)) 708*81f30337SRick Edgecombe return 1; 709*81f30337SRick Edgecombe 710*81f30337SRick Edgecombe ptrace(PTRACE_TRACEME, NULL, NULL, NULL); 711*81f30337SRick Edgecombe /* 712*81f30337SRick Edgecombe * The parent will tweak the SSP and return from this function 713*81f30337SRick Edgecombe * will #CP. 714*81f30337SRick Edgecombe */ 715*81f30337SRick Edgecombe raise(SIGTRAP); 716*81f30337SRick Edgecombe 717*81f30337SRick Edgecombe exit(1); 718*81f30337SRick Edgecombe } 719*81f30337SRick Edgecombe 720*81f30337SRick Edgecombe while (waitpid(pid, &status, 0) != -1 && WSTOPSIG(status) != SIGTRAP); 721*81f30337SRick Edgecombe 722*81f30337SRick Edgecombe if (ptrace(PTRACE_GETREGSET, pid, NT_X86_SHSTK, &iov)) { 723*81f30337SRick Edgecombe printf("[INFO]\tFailed to PTRACE_GETREGS\n"); 724*81f30337SRick Edgecombe goto out_kill; 725*81f30337SRick Edgecombe } 726*81f30337SRick Edgecombe 727*81f30337SRick Edgecombe if (!ssp) { 728*81f30337SRick Edgecombe printf("[INFO]\tPtrace child SSP was 0\n"); 729*81f30337SRick Edgecombe goto out_kill; 730*81f30337SRick Edgecombe } 731*81f30337SRick Edgecombe 732*81f30337SRick Edgecombe saved_ssp = ssp; 733*81f30337SRick Edgecombe 734*81f30337SRick Edgecombe iov.iov_len = 0; 735*81f30337SRick Edgecombe if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) { 736*81f30337SRick Edgecombe printf("[INFO]\tToo small size accepted via PTRACE_SETREGS\n"); 737*81f30337SRick Edgecombe goto out_kill; 738*81f30337SRick Edgecombe } 739*81f30337SRick Edgecombe 740*81f30337SRick Edgecombe iov.iov_len = sizeof(ssp) + 1; 741*81f30337SRick Edgecombe if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) { 742*81f30337SRick Edgecombe printf("[INFO]\tToo large size accepted via PTRACE_SETREGS\n"); 743*81f30337SRick Edgecombe goto out_kill; 744*81f30337SRick Edgecombe } 745*81f30337SRick Edgecombe 746*81f30337SRick Edgecombe ssp += 1; 747*81f30337SRick Edgecombe if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) { 748*81f30337SRick Edgecombe printf("[INFO]\tUnaligned SSP written via PTRACE_SETREGS\n"); 749*81f30337SRick Edgecombe goto out_kill; 750*81f30337SRick Edgecombe } 751*81f30337SRick Edgecombe 752*81f30337SRick Edgecombe ssp = 0xFFFFFFFFFFFF0000; 753*81f30337SRick Edgecombe if (!ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) { 754*81f30337SRick Edgecombe printf("[INFO]\tKernel range SSP written via PTRACE_SETREGS\n"); 755*81f30337SRick Edgecombe goto out_kill; 756*81f30337SRick Edgecombe } 757*81f30337SRick Edgecombe 758*81f30337SRick Edgecombe /* 759*81f30337SRick Edgecombe * Tweak the SSP so the child with #CP when it resumes and returns 760*81f30337SRick Edgecombe * from raise() 761*81f30337SRick Edgecombe */ 762*81f30337SRick Edgecombe ssp = saved_ssp + 8; 763*81f30337SRick Edgecombe iov.iov_len = sizeof(ssp); 764*81f30337SRick Edgecombe if (ptrace(PTRACE_SETREGSET, pid, NT_X86_SHSTK, &iov)) { 765*81f30337SRick Edgecombe printf("[INFO]\tFailed to PTRACE_SETREGS\n"); 766*81f30337SRick Edgecombe goto out_kill; 767*81f30337SRick Edgecombe } 768*81f30337SRick Edgecombe 769*81f30337SRick Edgecombe if (ptrace(PTRACE_DETACH, pid, NULL, NULL)) { 770*81f30337SRick Edgecombe printf("[INFO]\tFailed to PTRACE_DETACH\n"); 771*81f30337SRick Edgecombe goto out_kill; 772*81f30337SRick Edgecombe } 773*81f30337SRick Edgecombe 774*81f30337SRick Edgecombe waitpid(pid, &status, 0); 775*81f30337SRick Edgecombe if (WEXITSTATUS(status)) 776*81f30337SRick Edgecombe return 1; 777*81f30337SRick Edgecombe 778*81f30337SRick Edgecombe printf("[OK]\tPtrace test\n"); 779*81f30337SRick Edgecombe return 0; 780*81f30337SRick Edgecombe 781*81f30337SRick Edgecombe out_kill: 782*81f30337SRick Edgecombe kill(pid, SIGKILL); 783*81f30337SRick Edgecombe return 1; 784*81f30337SRick Edgecombe } 785*81f30337SRick Edgecombe 786*81f30337SRick Edgecombe int main(int argc, char *argv[]) 787*81f30337SRick Edgecombe { 788*81f30337SRick Edgecombe int ret = 0; 789*81f30337SRick Edgecombe 790*81f30337SRick Edgecombe if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) { 791*81f30337SRick Edgecombe printf("[SKIP]\tCould not enable Shadow stack\n"); 792*81f30337SRick Edgecombe return 1; 793*81f30337SRick Edgecombe } 794*81f30337SRick Edgecombe 795*81f30337SRick Edgecombe if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) { 796*81f30337SRick Edgecombe ret = 1; 797*81f30337SRick Edgecombe printf("[FAIL]\tDisabling shadow stack failed\n"); 798*81f30337SRick Edgecombe } 799*81f30337SRick Edgecombe 800*81f30337SRick Edgecombe if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_SHSTK)) { 801*81f30337SRick Edgecombe printf("[SKIP]\tCould not re-enable Shadow stack\n"); 802*81f30337SRick Edgecombe return 1; 803*81f30337SRick Edgecombe } 804*81f30337SRick Edgecombe 805*81f30337SRick Edgecombe if (ARCH_PRCTL(ARCH_SHSTK_ENABLE, ARCH_SHSTK_WRSS)) { 806*81f30337SRick Edgecombe printf("[SKIP]\tCould not enable WRSS\n"); 807*81f30337SRick Edgecombe ret = 1; 808*81f30337SRick Edgecombe goto out; 809*81f30337SRick Edgecombe } 810*81f30337SRick Edgecombe 811*81f30337SRick Edgecombe /* Should have succeeded if here, but this is a test, so double check. */ 812*81f30337SRick Edgecombe if (!get_ssp()) { 813*81f30337SRick Edgecombe printf("[FAIL]\tShadow stack disabled\n"); 814*81f30337SRick Edgecombe return 1; 815*81f30337SRick Edgecombe } 816*81f30337SRick Edgecombe 817*81f30337SRick Edgecombe if (test_shstk_pivot()) { 818*81f30337SRick Edgecombe ret = 1; 819*81f30337SRick Edgecombe printf("[FAIL]\tShadow stack pivot\n"); 820*81f30337SRick Edgecombe goto out; 821*81f30337SRick Edgecombe } 822*81f30337SRick Edgecombe 823*81f30337SRick Edgecombe if (test_shstk_faults()) { 824*81f30337SRick Edgecombe ret = 1; 825*81f30337SRick Edgecombe printf("[FAIL]\tShadow stack fault test\n"); 826*81f30337SRick Edgecombe goto out; 827*81f30337SRick Edgecombe } 828*81f30337SRick Edgecombe 829*81f30337SRick Edgecombe if (test_shstk_violation()) { 830*81f30337SRick Edgecombe ret = 1; 831*81f30337SRick Edgecombe printf("[FAIL]\tShadow stack violation test\n"); 832*81f30337SRick Edgecombe goto out; 833*81f30337SRick Edgecombe } 834*81f30337SRick Edgecombe 835*81f30337SRick Edgecombe if (test_gup()) { 836*81f30337SRick Edgecombe ret = 1; 837*81f30337SRick Edgecombe printf("[FAIL]\tShadow shadow stack gup\n"); 838*81f30337SRick Edgecombe goto out; 839*81f30337SRick Edgecombe } 840*81f30337SRick Edgecombe 841*81f30337SRick Edgecombe if (test_mprotect()) { 842*81f30337SRick Edgecombe ret = 1; 843*81f30337SRick Edgecombe printf("[FAIL]\tShadow shadow mprotect test\n"); 844*81f30337SRick Edgecombe goto out; 845*81f30337SRick Edgecombe } 846*81f30337SRick Edgecombe 847*81f30337SRick Edgecombe if (test_userfaultfd()) { 848*81f30337SRick Edgecombe ret = 1; 849*81f30337SRick Edgecombe printf("[FAIL]\tUserfaultfd test\n"); 850*81f30337SRick Edgecombe goto out; 851*81f30337SRick Edgecombe } 852*81f30337SRick Edgecombe 853*81f30337SRick Edgecombe if (test_guard_gap()) { 854*81f30337SRick Edgecombe ret = 1; 855*81f30337SRick Edgecombe printf("[FAIL]\tGuard gap test\n"); 856*81f30337SRick Edgecombe goto out; 857*81f30337SRick Edgecombe } 858*81f30337SRick Edgecombe 859*81f30337SRick Edgecombe if (test_ptrace()) { 860*81f30337SRick Edgecombe ret = 1; 861*81f30337SRick Edgecombe printf("[FAIL]\tptrace test\n"); 862*81f30337SRick Edgecombe } 863*81f30337SRick Edgecombe 864*81f30337SRick Edgecombe if (test_32bit()) { 865*81f30337SRick Edgecombe ret = 1; 866*81f30337SRick Edgecombe printf("[FAIL]\t32 bit test\n"); 867*81f30337SRick Edgecombe goto out; 868*81f30337SRick Edgecombe } 869*81f30337SRick Edgecombe 870*81f30337SRick Edgecombe return ret; 871*81f30337SRick Edgecombe 872*81f30337SRick Edgecombe out: 873*81f30337SRick Edgecombe /* 874*81f30337SRick Edgecombe * Disable shadow stack before the function returns, or there will be a 875*81f30337SRick Edgecombe * shadow stack violation. 876*81f30337SRick Edgecombe */ 877*81f30337SRick Edgecombe if (ARCH_PRCTL(ARCH_SHSTK_DISABLE, ARCH_SHSTK_SHSTK)) { 878*81f30337SRick Edgecombe ret = 1; 879*81f30337SRick Edgecombe printf("[FAIL]\tDisabling shadow stack failed\n"); 880*81f30337SRick Edgecombe } 881*81f30337SRick Edgecombe 882*81f30337SRick Edgecombe return ret; 883*81f30337SRick Edgecombe } 884*81f30337SRick Edgecombe #endif 885