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