1*d30c1683SDeepak Gupta // SPDX-License-Identifier: GPL-2.0-only 2*d30c1683SDeepak Gupta 3*d30c1683SDeepak Gupta #include "../../kselftest.h" 4*d30c1683SDeepak Gupta #include <sys/signal.h> 5*d30c1683SDeepak Gupta #include <asm/ucontext.h> 6*d30c1683SDeepak Gupta #include <linux/prctl.h> 7*d30c1683SDeepak Gupta #include <errno.h> 8*d30c1683SDeepak Gupta #include <linux/ptrace.h> 9*d30c1683SDeepak Gupta #include <sys/wait.h> 10*d30c1683SDeepak Gupta #include <linux/elf.h> 11*d30c1683SDeepak Gupta #include <sys/uio.h> 12*d30c1683SDeepak Gupta #include <asm-generic/unistd.h> 13*d30c1683SDeepak Gupta 14*d30c1683SDeepak Gupta #include "cfi_rv_test.h" 15*d30c1683SDeepak Gupta 16*d30c1683SDeepak Gupta /* do not optimize cfi related test functions */ 17*d30c1683SDeepak Gupta #pragma GCC push_options 18*d30c1683SDeepak Gupta #pragma GCC optimize("O0") 19*d30c1683SDeepak Gupta 20*d30c1683SDeepak Gupta void sigsegv_handler(int signum, siginfo_t *si, void *uc) 21*d30c1683SDeepak Gupta { 22*d30c1683SDeepak Gupta struct ucontext *ctx = (struct ucontext *)uc; 23*d30c1683SDeepak Gupta 24*d30c1683SDeepak Gupta if (si->si_code == SEGV_CPERR) { 25*d30c1683SDeepak Gupta ksft_print_msg("Control flow violation happened somewhere\n"); 26*d30c1683SDeepak Gupta ksft_print_msg("PC where violation happened %lx\n", ctx->uc_mcontext.gregs[0]); 27*d30c1683SDeepak Gupta exit(-1); 28*d30c1683SDeepak Gupta } 29*d30c1683SDeepak Gupta 30*d30c1683SDeepak Gupta /* all other cases are expected to be of shadow stack write case */ 31*d30c1683SDeepak Gupta exit(CHILD_EXIT_CODE_SSWRITE); 32*d30c1683SDeepak Gupta } 33*d30c1683SDeepak Gupta 34*d30c1683SDeepak Gupta bool register_signal_handler(void) 35*d30c1683SDeepak Gupta { 36*d30c1683SDeepak Gupta struct sigaction sa = {}; 37*d30c1683SDeepak Gupta 38*d30c1683SDeepak Gupta sa.sa_sigaction = sigsegv_handler; 39*d30c1683SDeepak Gupta sa.sa_flags = SA_SIGINFO; 40*d30c1683SDeepak Gupta if (sigaction(SIGSEGV, &sa, NULL)) { 41*d30c1683SDeepak Gupta ksft_print_msg("Registering signal handler for landing pad violation failed\n"); 42*d30c1683SDeepak Gupta return false; 43*d30c1683SDeepak Gupta } 44*d30c1683SDeepak Gupta 45*d30c1683SDeepak Gupta return true; 46*d30c1683SDeepak Gupta } 47*d30c1683SDeepak Gupta 48*d30c1683SDeepak Gupta long ptrace(int request, pid_t pid, void *addr, void *data); 49*d30c1683SDeepak Gupta 50*d30c1683SDeepak Gupta bool cfi_ptrace_test(void) 51*d30c1683SDeepak Gupta { 52*d30c1683SDeepak Gupta pid_t pid; 53*d30c1683SDeepak Gupta int status, ret = 0; 54*d30c1683SDeepak Gupta unsigned long ptrace_test_num = 0, total_ptrace_tests = 2; 55*d30c1683SDeepak Gupta 56*d30c1683SDeepak Gupta struct user_cfi_state cfi_reg; 57*d30c1683SDeepak Gupta struct iovec iov; 58*d30c1683SDeepak Gupta 59*d30c1683SDeepak Gupta pid = fork(); 60*d30c1683SDeepak Gupta 61*d30c1683SDeepak Gupta if (pid == -1) { 62*d30c1683SDeepak Gupta ksft_exit_fail_msg("%s: fork failed\n", __func__); 63*d30c1683SDeepak Gupta exit(1); 64*d30c1683SDeepak Gupta } 65*d30c1683SDeepak Gupta 66*d30c1683SDeepak Gupta if (pid == 0) { 67*d30c1683SDeepak Gupta /* allow to be traced */ 68*d30c1683SDeepak Gupta ptrace(PTRACE_TRACEME, 0, NULL, NULL); 69*d30c1683SDeepak Gupta raise(SIGSTOP); 70*d30c1683SDeepak Gupta asm volatile ("la a5, 1f\n" 71*d30c1683SDeepak Gupta "jalr a5\n" 72*d30c1683SDeepak Gupta "nop\n" 73*d30c1683SDeepak Gupta "nop\n" 74*d30c1683SDeepak Gupta "1: nop\n" 75*d30c1683SDeepak Gupta : : : "a5"); 76*d30c1683SDeepak Gupta exit(11); 77*d30c1683SDeepak Gupta /* child shouldn't go beyond here */ 78*d30c1683SDeepak Gupta } 79*d30c1683SDeepak Gupta 80*d30c1683SDeepak Gupta /* parent's code goes here */ 81*d30c1683SDeepak Gupta iov.iov_base = &cfi_reg; 82*d30c1683SDeepak Gupta iov.iov_len = sizeof(cfi_reg); 83*d30c1683SDeepak Gupta 84*d30c1683SDeepak Gupta while (ptrace_test_num < total_ptrace_tests) { 85*d30c1683SDeepak Gupta memset(&cfi_reg, 0, sizeof(cfi_reg)); 86*d30c1683SDeepak Gupta waitpid(pid, &status, 0); 87*d30c1683SDeepak Gupta if (WIFSTOPPED(status)) { 88*d30c1683SDeepak Gupta errno = 0; 89*d30c1683SDeepak Gupta ret = ptrace(PTRACE_GETREGSET, pid, (void *)NT_RISCV_USER_CFI, &iov); 90*d30c1683SDeepak Gupta if (ret == -1 && errno) 91*d30c1683SDeepak Gupta ksft_exit_fail_msg("%s: PTRACE_GETREGSET failed\n", __func__); 92*d30c1683SDeepak Gupta } else { 93*d30c1683SDeepak Gupta ksft_exit_fail_msg("%s: child didn't stop, failed\n", __func__); 94*d30c1683SDeepak Gupta } 95*d30c1683SDeepak Gupta 96*d30c1683SDeepak Gupta switch (ptrace_test_num) { 97*d30c1683SDeepak Gupta #define CFI_ENABLE_MASK (PTRACE_CFI_LP_EN_STATE | \ 98*d30c1683SDeepak Gupta PTRACE_CFI_SS_EN_STATE | \ 99*d30c1683SDeepak Gupta PTRACE_CFI_SS_PTR_STATE) 100*d30c1683SDeepak Gupta case 0: 101*d30c1683SDeepak Gupta if ((cfi_reg.cfi_status.cfi_state & CFI_ENABLE_MASK) != CFI_ENABLE_MASK) 102*d30c1683SDeepak Gupta ksft_exit_fail_msg("%s: ptrace_getregset failed, %llu\n", __func__, 103*d30c1683SDeepak Gupta cfi_reg.cfi_status.cfi_state); 104*d30c1683SDeepak Gupta if (!cfi_reg.shstk_ptr) 105*d30c1683SDeepak Gupta ksft_exit_fail_msg("%s: NULL shadow stack pointer, test failed\n", 106*d30c1683SDeepak Gupta __func__); 107*d30c1683SDeepak Gupta break; 108*d30c1683SDeepak Gupta case 1: 109*d30c1683SDeepak Gupta if (!(cfi_reg.cfi_status.cfi_state & PTRACE_CFI_ELP_STATE)) 110*d30c1683SDeepak Gupta ksft_exit_fail_msg("%s: elp must have been set\n", __func__); 111*d30c1683SDeepak Gupta /* clear elp state. not interested in anything else */ 112*d30c1683SDeepak Gupta cfi_reg.cfi_status.cfi_state = 0; 113*d30c1683SDeepak Gupta 114*d30c1683SDeepak Gupta ret = ptrace(PTRACE_SETREGSET, pid, (void *)NT_RISCV_USER_CFI, &iov); 115*d30c1683SDeepak Gupta if (ret == -1 && errno) 116*d30c1683SDeepak Gupta ksft_exit_fail_msg("%s: PTRACE_GETREGSET failed\n", __func__); 117*d30c1683SDeepak Gupta break; 118*d30c1683SDeepak Gupta default: 119*d30c1683SDeepak Gupta ksft_exit_fail_msg("%s: unreachable switch case\n", __func__); 120*d30c1683SDeepak Gupta break; 121*d30c1683SDeepak Gupta } 122*d30c1683SDeepak Gupta ptrace(PTRACE_CONT, pid, NULL, NULL); 123*d30c1683SDeepak Gupta ptrace_test_num++; 124*d30c1683SDeepak Gupta } 125*d30c1683SDeepak Gupta 126*d30c1683SDeepak Gupta waitpid(pid, &status, 0); 127*d30c1683SDeepak Gupta if (WEXITSTATUS(status) != 11) 128*d30c1683SDeepak Gupta ksft_print_msg("%s, bad return code from child\n", __func__); 129*d30c1683SDeepak Gupta 130*d30c1683SDeepak Gupta ksft_print_msg("%s, ptrace test succeeded\n", __func__); 131*d30c1683SDeepak Gupta return true; 132*d30c1683SDeepak Gupta } 133*d30c1683SDeepak Gupta 134*d30c1683SDeepak Gupta int main(int argc, char *argv[]) 135*d30c1683SDeepak Gupta { 136*d30c1683SDeepak Gupta int ret = 0; 137*d30c1683SDeepak Gupta unsigned long lpad_status = 0, ss_status = 0; 138*d30c1683SDeepak Gupta 139*d30c1683SDeepak Gupta ksft_print_header(); 140*d30c1683SDeepak Gupta 141*d30c1683SDeepak Gupta ksft_print_msg("Starting risc-v tests\n"); 142*d30c1683SDeepak Gupta 143*d30c1683SDeepak Gupta /* 144*d30c1683SDeepak Gupta * Landing pad test. Not a lot of kernel changes to support landing 145*d30c1683SDeepak Gupta * pads for user mode except lighting up a bit in senvcfg via a prctl. 146*d30c1683SDeepak Gupta * Enable landing pad support throughout the execution of the test binary. 147*d30c1683SDeepak Gupta */ 148*d30c1683SDeepak Gupta ret = my_syscall5(__NR_prctl, PR_GET_INDIR_BR_LP_STATUS, &lpad_status, 0, 0, 0); 149*d30c1683SDeepak Gupta if (ret) 150*d30c1683SDeepak Gupta ksft_exit_fail_msg("Get landing pad status failed with %d\n", ret); 151*d30c1683SDeepak Gupta 152*d30c1683SDeepak Gupta if (!(lpad_status & PR_INDIR_BR_LP_ENABLE)) 153*d30c1683SDeepak Gupta ksft_exit_fail_msg("Landing pad is not enabled, should be enabled via glibc\n"); 154*d30c1683SDeepak Gupta 155*d30c1683SDeepak Gupta ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0); 156*d30c1683SDeepak Gupta if (ret) 157*d30c1683SDeepak Gupta ksft_exit_fail_msg("Get shadow stack failed with %d\n", ret); 158*d30c1683SDeepak Gupta 159*d30c1683SDeepak Gupta if (!(ss_status & PR_SHADOW_STACK_ENABLE)) 160*d30c1683SDeepak Gupta ksft_exit_fail_msg("Shadow stack is not enabled, should be enabled via glibc\n"); 161*d30c1683SDeepak Gupta 162*d30c1683SDeepak Gupta if (!register_signal_handler()) 163*d30c1683SDeepak Gupta ksft_exit_fail_msg("Registering signal handler for SIGSEGV failed\n"); 164*d30c1683SDeepak Gupta 165*d30c1683SDeepak Gupta ksft_print_msg("Landing pad and shadow stack are enabled for binary\n"); 166*d30c1683SDeepak Gupta cfi_ptrace_test(); 167*d30c1683SDeepak Gupta 168*d30c1683SDeepak Gupta execute_shadow_stack_tests(); 169*d30c1683SDeepak Gupta 170*d30c1683SDeepak Gupta return 0; 171*d30c1683SDeepak Gupta } 172*d30c1683SDeepak Gupta 173*d30c1683SDeepak Gupta #pragma GCC pop_options 174