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