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