xref: /linux/tools/testing/selftests/riscv/cfi/cfitests.c (revision d30c1683aaecb93d2ab95685dc4300a33d3cea7a)
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