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