cifs: fix creating sockets when using sfu mount options
[sfrench/cifs-2.6.git] / tools / testing / selftests / syscall_user_dispatch / sud_test.c
1 // SPDX-License-Identifier: GPL-2.0-only
2 /*
3  * Copyright (c) 2020 Collabora Ltd.
4  *
5  * Test code for syscall user dispatch
6  */
7
8 #define _GNU_SOURCE
9 #include <sys/prctl.h>
10 #include <sys/sysinfo.h>
11 #include <sys/syscall.h>
12 #include <signal.h>
13
14 #include <asm/unistd.h>
15 #include "../kselftest_harness.h"
16
17 #ifndef PR_SET_SYSCALL_USER_DISPATCH
18 # define PR_SET_SYSCALL_USER_DISPATCH   59
19 # define PR_SYS_DISPATCH_OFF    0
20 # define PR_SYS_DISPATCH_ON     1
21 # define SYSCALL_DISPATCH_FILTER_ALLOW  0
22 # define SYSCALL_DISPATCH_FILTER_BLOCK  1
23 #endif
24
25 #ifndef SYS_USER_DISPATCH
26 # define SYS_USER_DISPATCH      2
27 #endif
28
29 #ifdef __NR_syscalls
30 # define MAGIC_SYSCALL_1 (__NR_syscalls + 1) /* Bad Linux syscall number */
31 #else
32 # define MAGIC_SYSCALL_1 (0xff00)  /* Bad Linux syscall number */
33 #endif
34
35 #define SYSCALL_DISPATCH_ON(x) ((x) = SYSCALL_DISPATCH_FILTER_BLOCK)
36 #define SYSCALL_DISPATCH_OFF(x) ((x) = SYSCALL_DISPATCH_FILTER_ALLOW)
37
38 /* Test Summary:
39  *
40  * - dispatch_trigger_sigsys: Verify if PR_SET_SYSCALL_USER_DISPATCH is
41  *   able to trigger SIGSYS on a syscall.
42  *
43  * - bad_selector: Test that a bad selector value triggers SIGSYS with
44  *   si_errno EINVAL.
45  *
46  * - bad_prctl_param: Test that the API correctly rejects invalid
47  *   parameters on prctl
48  *
49  * - dispatch_and_return: Test that a syscall is selectively dispatched
50  *   to userspace depending on the value of selector.
51  *
52  * - disable_dispatch: Test that the PR_SYS_DISPATCH_OFF correctly
53  *   disables the dispatcher
54  *
55  * - direct_dispatch_range: Test that a syscall within the allowed range
56  *   can bypass the dispatcher.
57  */
58
59 TEST_SIGNAL(dispatch_trigger_sigsys, SIGSYS)
60 {
61         char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
62         struct sysinfo info;
63         int ret;
64
65         ret = sysinfo(&info);
66         ASSERT_EQ(0, ret);
67
68         ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &sel);
69         ASSERT_EQ(0, ret) {
70                 TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
71         }
72
73         SYSCALL_DISPATCH_ON(sel);
74
75         sysinfo(&info);
76
77         EXPECT_FALSE(true) {
78                 TH_LOG("Unreachable!");
79         }
80 }
81
82 TEST(bad_prctl_param)
83 {
84         char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
85         int op;
86
87         /* Invalid op */
88         op = -1;
89         prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0, 0, &sel);
90         ASSERT_EQ(EINVAL, errno);
91
92         /* PR_SYS_DISPATCH_OFF */
93         op = PR_SYS_DISPATCH_OFF;
94
95         /* offset != 0 */
96         prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x1, 0x0, 0);
97         EXPECT_EQ(EINVAL, errno);
98
99         /* len != 0 */
100         prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x0, 0xff, 0);
101         EXPECT_EQ(EINVAL, errno);
102
103         /* sel != NULL */
104         prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x0, 0x0, &sel);
105         EXPECT_EQ(EINVAL, errno);
106
107         /* Valid parameter */
108         errno = 0;
109         prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x0, 0x0, 0x0);
110         EXPECT_EQ(0, errno);
111
112         /* PR_SYS_DISPATCH_ON */
113         op = PR_SYS_DISPATCH_ON;
114
115         /* Dispatcher region is bad (offset > 0 && len == 0) */
116         prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x1, 0x0, &sel);
117         EXPECT_EQ(EINVAL, errno);
118         prctl(PR_SET_SYSCALL_USER_DISPATCH, op, -1L, 0x0, &sel);
119         EXPECT_EQ(EINVAL, errno);
120
121         /* Invalid selector */
122         prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x0, 0x1, (void *) -1);
123         ASSERT_EQ(EFAULT, errno);
124
125         /*
126          * Dispatcher range overflows unsigned long
127          */
128         prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 1, -1L, &sel);
129         ASSERT_EQ(EINVAL, errno) {
130                 TH_LOG("Should reject bad syscall range");
131         }
132
133         /*
134          * Allowed range overflows usigned long
135          */
136         prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, -1L, 0x1, &sel);
137         ASSERT_EQ(EINVAL, errno) {
138                 TH_LOG("Should reject bad syscall range");
139         }
140 }
141
142 /*
143  * Use global selector for handle_sigsys tests, to avoid passing
144  * selector to signal handler
145  */
146 char glob_sel;
147 int nr_syscalls_emulated;
148 int si_code;
149 int si_errno;
150
151 static void handle_sigsys(int sig, siginfo_t *info, void *ucontext)
152 {
153         si_code = info->si_code;
154         si_errno = info->si_errno;
155
156         if (info->si_syscall == MAGIC_SYSCALL_1)
157                 nr_syscalls_emulated++;
158
159         /* In preparation for sigreturn. */
160         SYSCALL_DISPATCH_OFF(glob_sel);
161
162         /*
163          * The tests for argument handling assume that `syscall(x) == x`. This
164          * is a NOP on x86 because the syscall number is passed in %rax, which
165          * happens to also be the function ABI return register.  Other
166          * architectures may need to swizzle the arguments around.
167          */
168 #if defined(__riscv)
169 /* REG_A7 is not defined in libc headers */
170 # define REG_A7 (REG_A0 + 7)
171
172         ((ucontext_t *)ucontext)->uc_mcontext.__gregs[REG_A0] =
173                         ((ucontext_t *)ucontext)->uc_mcontext.__gregs[REG_A7];
174 #endif
175 }
176
177 TEST(dispatch_and_return)
178 {
179         long ret;
180         struct sigaction act;
181         sigset_t mask;
182
183         glob_sel = 0;
184         nr_syscalls_emulated = 0;
185         si_code = 0;
186         si_errno = 0;
187
188         memset(&act, 0, sizeof(act));
189         sigemptyset(&mask);
190
191         act.sa_sigaction = handle_sigsys;
192         act.sa_flags = SA_SIGINFO;
193         act.sa_mask = mask;
194
195         ret = sigaction(SIGSYS, &act, NULL);
196         ASSERT_EQ(0, ret);
197
198         /* Make sure selector is good prior to prctl. */
199         SYSCALL_DISPATCH_OFF(glob_sel);
200
201         ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &glob_sel);
202         ASSERT_EQ(0, ret) {
203                 TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
204         }
205
206         /* MAGIC_SYSCALL_1 doesn't exist. */
207         SYSCALL_DISPATCH_OFF(glob_sel);
208         ret = syscall(MAGIC_SYSCALL_1);
209         EXPECT_EQ(-1, ret) {
210                 TH_LOG("Dispatch triggered unexpectedly");
211         }
212
213         /* MAGIC_SYSCALL_1 should be emulated. */
214         nr_syscalls_emulated = 0;
215         SYSCALL_DISPATCH_ON(glob_sel);
216
217         ret = syscall(MAGIC_SYSCALL_1);
218         EXPECT_EQ(MAGIC_SYSCALL_1, ret) {
219                 TH_LOG("Failed to intercept syscall");
220         }
221         EXPECT_EQ(1, nr_syscalls_emulated) {
222                 TH_LOG("Failed to emulate syscall");
223         }
224         ASSERT_EQ(SYS_USER_DISPATCH, si_code) {
225                 TH_LOG("Bad si_code in SIGSYS");
226         }
227         ASSERT_EQ(0, si_errno) {
228                 TH_LOG("Bad si_errno in SIGSYS");
229         }
230 }
231
232 TEST_SIGNAL(bad_selector, SIGSYS)
233 {
234         long ret;
235         struct sigaction act;
236         sigset_t mask;
237         struct sysinfo info;
238
239         glob_sel = SYSCALL_DISPATCH_FILTER_ALLOW;
240         nr_syscalls_emulated = 0;
241         si_code = 0;
242         si_errno = 0;
243
244         memset(&act, 0, sizeof(act));
245         sigemptyset(&mask);
246
247         act.sa_sigaction = handle_sigsys;
248         act.sa_flags = SA_SIGINFO;
249         act.sa_mask = mask;
250
251         ret = sigaction(SIGSYS, &act, NULL);
252         ASSERT_EQ(0, ret);
253
254         /* Make sure selector is good prior to prctl. */
255         SYSCALL_DISPATCH_OFF(glob_sel);
256
257         ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &glob_sel);
258         ASSERT_EQ(0, ret) {
259                 TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
260         }
261
262         glob_sel = -1;
263
264         sysinfo(&info);
265
266         /* Even though it is ready to catch SIGSYS, the signal is
267          * supposed to be uncatchable.
268          */
269
270         EXPECT_FALSE(true) {
271                 TH_LOG("Unreachable!");
272         }
273 }
274
275 TEST(disable_dispatch)
276 {
277         int ret;
278         struct sysinfo info;
279         char sel = 0;
280
281         ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &sel);
282         ASSERT_EQ(0, ret) {
283                 TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
284         }
285
286         /* MAGIC_SYSCALL_1 doesn't exist. */
287         SYSCALL_DISPATCH_OFF(glob_sel);
288
289         ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_OFF, 0, 0, 0);
290         EXPECT_EQ(0, ret) {
291                 TH_LOG("Failed to unset syscall user dispatch");
292         }
293
294         /* Shouldn't have any effect... */
295         SYSCALL_DISPATCH_ON(glob_sel);
296
297         ret = syscall(__NR_sysinfo, &info);
298         EXPECT_EQ(0, ret) {
299                 TH_LOG("Dispatch triggered unexpectedly");
300         }
301 }
302
303 TEST(direct_dispatch_range)
304 {
305         int ret = 0;
306         struct sysinfo info;
307         char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
308
309         /*
310          * Instead of calculating libc addresses; allow the entire
311          * memory map and lock the selector.
312          */
313         ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, -1L, &sel);
314         ASSERT_EQ(0, ret) {
315                 TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
316         }
317
318         SYSCALL_DISPATCH_ON(sel);
319
320         ret = sysinfo(&info);
321         ASSERT_EQ(0, ret) {
322                 TH_LOG("Dispatch triggered unexpectedly");
323         }
324 }
325
326 TEST_HARNESS_MAIN