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
19static volatile unsigned long long sigreturn_addr;
20static volatile unsigned long long sigreturn_msr_mask;
21
22static 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
33static 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
46static 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
58int 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
129int main(void)
130{
131 return test_harness(test_sigreturn_kernel, "sigreturn_kernel");
132}
133

source code of linux/tools/testing/selftests/powerpc/signal/sigreturn_kernel.c