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