1*843fff42SMichael Ellerman // SPDX-License-Identifier: GPL-2.0
2*843fff42SMichael Ellerman /*
3*843fff42SMichael Ellerman  * Test that we can't sigreturn to kernel addresses, or to kernel mode.
4*843fff42SMichael Ellerman  */
5*843fff42SMichael Ellerman 
6*843fff42SMichael Ellerman #define _GNU_SOURCE
7*843fff42SMichael Ellerman 
8*843fff42SMichael Ellerman #include <stdio.h>
9*843fff42SMichael Ellerman #include <signal.h>
10*843fff42SMichael Ellerman #include <stdlib.h>
11*843fff42SMichael Ellerman #include <sys/types.h>
12*843fff42SMichael Ellerman #include <sys/wait.h>
13*843fff42SMichael Ellerman #include <unistd.h>
14*843fff42SMichael Ellerman 
15*843fff42SMichael Ellerman #include "utils.h"
16*843fff42SMichael Ellerman 
17*843fff42SMichael Ellerman #define MSR_PR (1ul << 14)
18*843fff42SMichael Ellerman 
19*843fff42SMichael Ellerman static volatile unsigned long long sigreturn_addr;
20*843fff42SMichael Ellerman static volatile unsigned long long sigreturn_msr_mask;
21*843fff42SMichael Ellerman 
sigusr1_handler(int signo,siginfo_t * si,void * uc_ptr)22*843fff42SMichael Ellerman static void sigusr1_handler(int signo, siginfo_t *si, void *uc_ptr)
23*843fff42SMichael Ellerman {
24*843fff42SMichael Ellerman 	ucontext_t *uc = (ucontext_t *)uc_ptr;
25*843fff42SMichael Ellerman 
26*843fff42SMichael Ellerman 	if (sigreturn_addr)
27*843fff42SMichael Ellerman 		UCONTEXT_NIA(uc) = sigreturn_addr;
28*843fff42SMichael Ellerman 
29*843fff42SMichael Ellerman 	if (sigreturn_msr_mask)
30*843fff42SMichael Ellerman 		UCONTEXT_MSR(uc) &= sigreturn_msr_mask;
31*843fff42SMichael Ellerman }
32*843fff42SMichael Ellerman 
fork_child(void)33*843fff42SMichael Ellerman static pid_t fork_child(void)
34*843fff42SMichael Ellerman {
35*843fff42SMichael Ellerman 	pid_t pid;
36*843fff42SMichael Ellerman 
37*843fff42SMichael Ellerman 	pid = fork();
38*843fff42SMichael Ellerman 	if (pid == 0) {
39*843fff42SMichael Ellerman 		raise(SIGUSR1);
40*843fff42SMichael Ellerman 		exit(0);
41*843fff42SMichael Ellerman 	}
42*843fff42SMichael Ellerman 
43*843fff42SMichael Ellerman 	return pid;
44*843fff42SMichael Ellerman }
45*843fff42SMichael Ellerman 
expect_segv(pid_t pid)46*843fff42SMichael Ellerman static int expect_segv(pid_t pid)
47*843fff42SMichael Ellerman {
48*843fff42SMichael Ellerman 	int child_ret;
49*843fff42SMichael Ellerman 
50*843fff42SMichael Ellerman 	waitpid(pid, &child_ret, 0);
51*843fff42SMichael Ellerman 	FAIL_IF(WIFEXITED(child_ret));
52*843fff42SMichael Ellerman 	FAIL_IF(!WIFSIGNALED(child_ret));
53*843fff42SMichael Ellerman 	FAIL_IF(WTERMSIG(child_ret) != 11);
54*843fff42SMichael Ellerman 
55*843fff42SMichael Ellerman 	return 0;
56*843fff42SMichael Ellerman }
57*843fff42SMichael Ellerman 
test_sigreturn_kernel(void)58*843fff42SMichael Ellerman int test_sigreturn_kernel(void)
59*843fff42SMichael Ellerman {
60*843fff42SMichael Ellerman 	struct sigaction act;
61*843fff42SMichael Ellerman 	int child_ret, i;
62*843fff42SMichael Ellerman 	pid_t pid;
63*843fff42SMichael Ellerman 
64*843fff42SMichael Ellerman 	act.sa_sigaction = sigusr1_handler;
65*843fff42SMichael Ellerman 	act.sa_flags = SA_SIGINFO;
66*843fff42SMichael Ellerman 	sigemptyset(&act.sa_mask);
67*843fff42SMichael Ellerman 
68*843fff42SMichael Ellerman 	FAIL_IF(sigaction(SIGUSR1, &act, NULL));
69*843fff42SMichael Ellerman 
70*843fff42SMichael Ellerman 	for (i = 0; i < 2; i++) {
71*843fff42SMichael Ellerman 		// Return to kernel
72*843fff42SMichael Ellerman 		sigreturn_addr = 0xcull << 60;
73*843fff42SMichael Ellerman 		pid = fork_child();
74*843fff42SMichael Ellerman 		expect_segv(pid);
75*843fff42SMichael Ellerman 
76*843fff42SMichael Ellerman 		// Return to kernel virtual
77*843fff42SMichael Ellerman 		sigreturn_addr = 0xc008ull << 48;
78*843fff42SMichael Ellerman 		pid = fork_child();
79*843fff42SMichael Ellerman 		expect_segv(pid);
80*843fff42SMichael Ellerman 
81*843fff42SMichael Ellerman 		// Return out of range
82*843fff42SMichael Ellerman 		sigreturn_addr = 0xc010ull << 48;
83*843fff42SMichael Ellerman 		pid = fork_child();
84*843fff42SMichael Ellerman 		expect_segv(pid);
85*843fff42SMichael Ellerman 
86*843fff42SMichael Ellerman 		// Return to no-man's land, just below PAGE_OFFSET
87*843fff42SMichael Ellerman 		sigreturn_addr = (0xcull << 60) - (64 * 1024);
88*843fff42SMichael Ellerman 		pid = fork_child();
89*843fff42SMichael Ellerman 		expect_segv(pid);
90*843fff42SMichael Ellerman 
91*843fff42SMichael Ellerman 		// Return to no-man's land, above TASK_SIZE_4PB
92*843fff42SMichael Ellerman 		sigreturn_addr = 0x1ull << 52;
93*843fff42SMichael Ellerman 		pid = fork_child();
94*843fff42SMichael Ellerman 		expect_segv(pid);
95*843fff42SMichael Ellerman 
96*843fff42SMichael Ellerman 		// Return to 0xd space
97*843fff42SMichael Ellerman 		sigreturn_addr = 0xdull << 60;
98*843fff42SMichael Ellerman 		pid = fork_child();
99*843fff42SMichael Ellerman 		expect_segv(pid);
100*843fff42SMichael Ellerman 
101*843fff42SMichael Ellerman 		// Return to 0xe space
102*843fff42SMichael Ellerman 		sigreturn_addr = 0xeull << 60;
103*843fff42SMichael Ellerman 		pid = fork_child();
104*843fff42SMichael Ellerman 		expect_segv(pid);
105*843fff42SMichael Ellerman 
106*843fff42SMichael Ellerman 		// Return to 0xf space
107*843fff42SMichael Ellerman 		sigreturn_addr = 0xfull << 60;
108*843fff42SMichael Ellerman 		pid = fork_child();
109*843fff42SMichael Ellerman 		expect_segv(pid);
110*843fff42SMichael Ellerman 
111*843fff42SMichael Ellerman 		// Attempt to set PR=0 for 2nd loop (should be blocked by kernel)
112*843fff42SMichael Ellerman 		sigreturn_msr_mask = ~MSR_PR;
113*843fff42SMichael Ellerman 	}
114*843fff42SMichael Ellerman 
115*843fff42SMichael Ellerman 	printf("All children killed as expected\n");
116*843fff42SMichael Ellerman 
117*843fff42SMichael Ellerman 	// Don't change address, just MSR, should return to user as normal
118*843fff42SMichael Ellerman 	sigreturn_addr = 0;
119*843fff42SMichael Ellerman 	sigreturn_msr_mask = ~MSR_PR;
120*843fff42SMichael Ellerman 	pid = fork_child();
121*843fff42SMichael Ellerman 	waitpid(pid, &child_ret, 0);
122*843fff42SMichael Ellerman 	FAIL_IF(!WIFEXITED(child_ret));
123*843fff42SMichael Ellerman 	FAIL_IF(WIFSIGNALED(child_ret));
124*843fff42SMichael Ellerman 	FAIL_IF(WEXITSTATUS(child_ret) != 0);
125*843fff42SMichael Ellerman 
126*843fff42SMichael Ellerman 	return 0;
127*843fff42SMichael Ellerman }
128*843fff42SMichael Ellerman 
main(void)129*843fff42SMichael Ellerman int main(void)
130*843fff42SMichael Ellerman {
131*843fff42SMichael Ellerman 	return test_harness(test_sigreturn_kernel, "sigreturn_kernel");
132*843fff42SMichael Ellerman }
133