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
sigsegv_handler(int signum,siginfo_t * si,void * uc)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
register_signal_handler(void)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
cfi_ptrace_test(void)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_BRANCH_LANDING_PAD_EN_STATE | \
98 PTRACE_CFI_SHADOW_STACK_EN_STATE | \
99 PTRACE_CFI_SHADOW_STACK_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 &
110 PTRACE_CFI_BRANCH_EXPECTED_LANDING_PAD_STATE))
111 ksft_exit_fail_msg("%s: elp must have been set\n", __func__);
112 /* clear elp state. not interested in anything else */
113 cfi_reg.cfi_status.cfi_state = 0;
114
115 ret = ptrace(PTRACE_SETREGSET, pid, (void *)NT_RISCV_USER_CFI, &iov);
116 if (ret == -1 && errno)
117 ksft_exit_fail_msg("%s: PTRACE_GETREGSET failed\n", __func__);
118 break;
119 default:
120 ksft_exit_fail_msg("%s: unreachable switch case\n", __func__);
121 break;
122 }
123 ptrace(PTRACE_CONT, pid, NULL, NULL);
124 ptrace_test_num++;
125 }
126
127 waitpid(pid, &status, 0);
128 if (WEXITSTATUS(status) != 11)
129 ksft_print_msg("%s, bad return code from child\n", __func__);
130
131 ksft_print_msg("%s, ptrace test succeeded\n", __func__);
132 return true;
133 }
134
main(int argc,char * argv[])135 int main(int argc, char *argv[])
136 {
137 int ret = 0;
138 unsigned long lpad_status = 0, ss_status = 0;
139
140 ksft_print_header();
141
142 ksft_print_msg("Starting risc-v tests\n");
143
144 /*
145 * Landing pad test. Not a lot of kernel changes to support landing
146 * pads for user mode except lighting up a bit in senvcfg via a prctl.
147 * Enable landing pad support throughout the execution of the test binary.
148 */
149 ret = my_syscall5(__NR_prctl, PR_GET_CFI, PR_CFI_BRANCH_LANDING_PADS, &lpad_status, 0, 0);
150 if (ret)
151 ksft_exit_fail_msg("Get landing pad status failed with %d\n", ret);
152
153 if (!(lpad_status & PR_CFI_ENABLE))
154 ksft_exit_fail_msg("Landing pad is not enabled, should be enabled via glibc\n");
155
156 ret = my_syscall5(__NR_prctl, PR_GET_SHADOW_STACK_STATUS, &ss_status, 0, 0, 0);
157 if (ret)
158 ksft_exit_fail_msg("Get shadow stack failed with %d\n", ret);
159
160 if (!(ss_status & PR_SHADOW_STACK_ENABLE))
161 ksft_exit_fail_msg("Shadow stack is not enabled, should be enabled via glibc\n");
162
163 if (!register_signal_handler())
164 ksft_exit_fail_msg("Registering signal handler for SIGSEGV failed\n");
165
166 ksft_print_msg("Landing pad and shadow stack are enabled for binary\n");
167 cfi_ptrace_test();
168
169 execute_shadow_stack_tests();
170
171 return 0;
172 }
173
174 #pragma GCC pop_options
175