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