327 lines · c
1// SPDX-License-Identifier: GPL-2.0-only2/*3 * Copyright (c) 2020 Collabora Ltd.4 *5 * Test code for syscall user dispatch6 */7 8#define _GNU_SOURCE9#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_DISPATCH18# define PR_SET_SYSCALL_USER_DISPATCH 5919# define PR_SYS_DISPATCH_OFF 020# define PR_SYS_DISPATCH_ON 121# define SYSCALL_DISPATCH_FILTER_ALLOW 022# define SYSCALL_DISPATCH_FILTER_BLOCK 123#endif24 25#ifndef SYS_USER_DISPATCH26# define SYS_USER_DISPATCH 227#endif28 29#ifdef __NR_syscalls30# define MAGIC_SYSCALL_1 (__NR_syscalls + 1) /* Bad Linux syscall number */31#else32# define MAGIC_SYSCALL_1 (0xff00) /* Bad Linux syscall number */33#endif34 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 is41 * able to trigger SIGSYS on a syscall.42 *43 * - bad_selector: Test that a bad selector value triggers SIGSYS with44 * si_errno EINVAL.45 *46 * - bad_prctl_param: Test that the API correctly rejects invalid47 * parameters on prctl48 *49 * - dispatch_and_return: Test that a syscall is selectively dispatched50 * to userspace depending on the value of selector.51 *52 * - disable_dispatch: Test that the PR_SYS_DISPATCH_OFF correctly53 * disables the dispatcher54 *55 * - direct_dispatch_range: Test that a syscall within the allowed range56 * can bypass the dispatcher.57 */58 59TEST_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 82TEST(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 long127 */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 long135 */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 passing144 * selector to signal handler145 */146char glob_sel;147int nr_syscalls_emulated;148int si_code;149int si_errno;150 151static 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`. This164 * is a NOP on x86 because the syscall number is passed in %rax, which165 * happens to also be the function ABI return register. Other166 * 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#endif175}176 177TEST(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 232TEST_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 is267 * supposed to be uncatchable.268 */269 270 EXPECT_FALSE(true) {271 TH_LOG("Unreachable!");272 }273}274 275TEST(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 303TEST(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 entire311 * 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 326TEST_HARNESS_MAIN327