Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0-only
0002 /*
0003  * Copyright (c) 2020 Collabora Ltd.
0004  *
0005  * Test code for syscall user dispatch
0006  */
0007 
0008 #define _GNU_SOURCE
0009 #include <sys/prctl.h>
0010 #include <sys/sysinfo.h>
0011 #include <sys/syscall.h>
0012 #include <signal.h>
0013 
0014 #include <asm/unistd.h>
0015 #include "../kselftest_harness.h"
0016 
0017 #ifndef PR_SET_SYSCALL_USER_DISPATCH
0018 # define PR_SET_SYSCALL_USER_DISPATCH   59
0019 # define PR_SYS_DISPATCH_OFF    0
0020 # define PR_SYS_DISPATCH_ON 1
0021 # define SYSCALL_DISPATCH_FILTER_ALLOW  0
0022 # define SYSCALL_DISPATCH_FILTER_BLOCK  1
0023 #endif
0024 
0025 #ifndef SYS_USER_DISPATCH
0026 # define SYS_USER_DISPATCH  2
0027 #endif
0028 
0029 #ifdef __NR_syscalls
0030 # define MAGIC_SYSCALL_1 (__NR_syscalls + 1) /* Bad Linux syscall number */
0031 #else
0032 # define MAGIC_SYSCALL_1 (0xff00)  /* Bad Linux syscall number */
0033 #endif
0034 
0035 #define SYSCALL_DISPATCH_ON(x) ((x) = SYSCALL_DISPATCH_FILTER_BLOCK)
0036 #define SYSCALL_DISPATCH_OFF(x) ((x) = SYSCALL_DISPATCH_FILTER_ALLOW)
0037 
0038 /* Test Summary:
0039  *
0040  * - dispatch_trigger_sigsys: Verify if PR_SET_SYSCALL_USER_DISPATCH is
0041  *   able to trigger SIGSYS on a syscall.
0042  *
0043  * - bad_selector: Test that a bad selector value triggers SIGSYS with
0044  *   si_errno EINVAL.
0045  *
0046  * - bad_prctl_param: Test that the API correctly rejects invalid
0047  *   parameters on prctl
0048  *
0049  * - dispatch_and_return: Test that a syscall is selectively dispatched
0050  *   to userspace depending on the value of selector.
0051  *
0052  * - disable_dispatch: Test that the PR_SYS_DISPATCH_OFF correctly
0053  *   disables the dispatcher
0054  *
0055  * - direct_dispatch_range: Test that a syscall within the allowed range
0056  *   can bypass the dispatcher.
0057  */
0058 
0059 TEST_SIGNAL(dispatch_trigger_sigsys, SIGSYS)
0060 {
0061     char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
0062     struct sysinfo info;
0063     int ret;
0064 
0065     ret = sysinfo(&info);
0066     ASSERT_EQ(0, ret);
0067 
0068     ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &sel);
0069     ASSERT_EQ(0, ret) {
0070         TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
0071     }
0072 
0073     SYSCALL_DISPATCH_ON(sel);
0074 
0075     sysinfo(&info);
0076 
0077     EXPECT_FALSE(true) {
0078         TH_LOG("Unreachable!");
0079     }
0080 }
0081 
0082 TEST(bad_prctl_param)
0083 {
0084     char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
0085     int op;
0086 
0087     /* Invalid op */
0088     op = -1;
0089     prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0, 0, &sel);
0090     ASSERT_EQ(EINVAL, errno);
0091 
0092     /* PR_SYS_DISPATCH_OFF */
0093     op = PR_SYS_DISPATCH_OFF;
0094 
0095     /* offset != 0 */
0096     prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x1, 0x0, 0);
0097     EXPECT_EQ(EINVAL, errno);
0098 
0099     /* len != 0 */
0100     prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x0, 0xff, 0);
0101     EXPECT_EQ(EINVAL, errno);
0102 
0103     /* sel != NULL */
0104     prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x0, 0x0, &sel);
0105     EXPECT_EQ(EINVAL, errno);
0106 
0107     /* Valid parameter */
0108     errno = 0;
0109     prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x0, 0x0, 0x0);
0110     EXPECT_EQ(0, errno);
0111 
0112     /* PR_SYS_DISPATCH_ON */
0113     op = PR_SYS_DISPATCH_ON;
0114 
0115     /* Dispatcher region is bad (offset > 0 && len == 0) */
0116     prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x1, 0x0, &sel);
0117     EXPECT_EQ(EINVAL, errno);
0118     prctl(PR_SET_SYSCALL_USER_DISPATCH, op, -1L, 0x0, &sel);
0119     EXPECT_EQ(EINVAL, errno);
0120 
0121     /* Invalid selector */
0122     prctl(PR_SET_SYSCALL_USER_DISPATCH, op, 0x0, 0x1, (void *) -1);
0123     ASSERT_EQ(EFAULT, errno);
0124 
0125     /*
0126      * Dispatcher range overflows unsigned long
0127      */
0128     prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 1, -1L, &sel);
0129     ASSERT_EQ(EINVAL, errno) {
0130         TH_LOG("Should reject bad syscall range");
0131     }
0132 
0133     /*
0134      * Allowed range overflows usigned long
0135      */
0136     prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, -1L, 0x1, &sel);
0137     ASSERT_EQ(EINVAL, errno) {
0138         TH_LOG("Should reject bad syscall range");
0139     }
0140 }
0141 
0142 /*
0143  * Use global selector for handle_sigsys tests, to avoid passing
0144  * selector to signal handler
0145  */
0146 char glob_sel;
0147 int nr_syscalls_emulated;
0148 int si_code;
0149 int si_errno;
0150 
0151 static void handle_sigsys(int sig, siginfo_t *info, void *ucontext)
0152 {
0153     si_code = info->si_code;
0154     si_errno = info->si_errno;
0155 
0156     if (info->si_syscall == MAGIC_SYSCALL_1)
0157         nr_syscalls_emulated++;
0158 
0159     /* In preparation for sigreturn. */
0160     SYSCALL_DISPATCH_OFF(glob_sel);
0161 }
0162 
0163 TEST(dispatch_and_return)
0164 {
0165     long ret;
0166     struct sigaction act;
0167     sigset_t mask;
0168 
0169     glob_sel = 0;
0170     nr_syscalls_emulated = 0;
0171     si_code = 0;
0172     si_errno = 0;
0173 
0174     memset(&act, 0, sizeof(act));
0175     sigemptyset(&mask);
0176 
0177     act.sa_sigaction = handle_sigsys;
0178     act.sa_flags = SA_SIGINFO;
0179     act.sa_mask = mask;
0180 
0181     ret = sigaction(SIGSYS, &act, NULL);
0182     ASSERT_EQ(0, ret);
0183 
0184     /* Make sure selector is good prior to prctl. */
0185     SYSCALL_DISPATCH_OFF(glob_sel);
0186 
0187     ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &glob_sel);
0188     ASSERT_EQ(0, ret) {
0189         TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
0190     }
0191 
0192     /* MAGIC_SYSCALL_1 doesn't exist. */
0193     SYSCALL_DISPATCH_OFF(glob_sel);
0194     ret = syscall(MAGIC_SYSCALL_1);
0195     EXPECT_EQ(-1, ret) {
0196         TH_LOG("Dispatch triggered unexpectedly");
0197     }
0198 
0199     /* MAGIC_SYSCALL_1 should be emulated. */
0200     nr_syscalls_emulated = 0;
0201     SYSCALL_DISPATCH_ON(glob_sel);
0202 
0203     ret = syscall(MAGIC_SYSCALL_1);
0204     EXPECT_EQ(MAGIC_SYSCALL_1, ret) {
0205         TH_LOG("Failed to intercept syscall");
0206     }
0207     EXPECT_EQ(1, nr_syscalls_emulated) {
0208         TH_LOG("Failed to emulate syscall");
0209     }
0210     ASSERT_EQ(SYS_USER_DISPATCH, si_code) {
0211         TH_LOG("Bad si_code in SIGSYS");
0212     }
0213     ASSERT_EQ(0, si_errno) {
0214         TH_LOG("Bad si_errno in SIGSYS");
0215     }
0216 }
0217 
0218 TEST_SIGNAL(bad_selector, SIGSYS)
0219 {
0220     long ret;
0221     struct sigaction act;
0222     sigset_t mask;
0223     struct sysinfo info;
0224 
0225     glob_sel = SYSCALL_DISPATCH_FILTER_ALLOW;
0226     nr_syscalls_emulated = 0;
0227     si_code = 0;
0228     si_errno = 0;
0229 
0230     memset(&act, 0, sizeof(act));
0231     sigemptyset(&mask);
0232 
0233     act.sa_sigaction = handle_sigsys;
0234     act.sa_flags = SA_SIGINFO;
0235     act.sa_mask = mask;
0236 
0237     ret = sigaction(SIGSYS, &act, NULL);
0238     ASSERT_EQ(0, ret);
0239 
0240     /* Make sure selector is good prior to prctl. */
0241     SYSCALL_DISPATCH_OFF(glob_sel);
0242 
0243     ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &glob_sel);
0244     ASSERT_EQ(0, ret) {
0245         TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
0246     }
0247 
0248     glob_sel = -1;
0249 
0250     sysinfo(&info);
0251 
0252     /* Even though it is ready to catch SIGSYS, the signal is
0253      * supposed to be uncatchable.
0254      */
0255 
0256     EXPECT_FALSE(true) {
0257         TH_LOG("Unreachable!");
0258     }
0259 }
0260 
0261 TEST(disable_dispatch)
0262 {
0263     int ret;
0264     struct sysinfo info;
0265     char sel = 0;
0266 
0267     ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &sel);
0268     ASSERT_EQ(0, ret) {
0269         TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
0270     }
0271 
0272     /* MAGIC_SYSCALL_1 doesn't exist. */
0273     SYSCALL_DISPATCH_OFF(glob_sel);
0274 
0275     ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_OFF, 0, 0, 0);
0276     EXPECT_EQ(0, ret) {
0277         TH_LOG("Failed to unset syscall user dispatch");
0278     }
0279 
0280     /* Shouldn't have any effect... */
0281     SYSCALL_DISPATCH_ON(glob_sel);
0282 
0283     ret = syscall(__NR_sysinfo, &info);
0284     EXPECT_EQ(0, ret) {
0285         TH_LOG("Dispatch triggered unexpectedly");
0286     }
0287 }
0288 
0289 TEST(direct_dispatch_range)
0290 {
0291     int ret = 0;
0292     struct sysinfo info;
0293     char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
0294 
0295     /*
0296      * Instead of calculating libc addresses; allow the entire
0297      * memory map and lock the selector.
0298      */
0299     ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, -1L, &sel);
0300     ASSERT_EQ(0, ret) {
0301         TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
0302     }
0303 
0304     SYSCALL_DISPATCH_ON(sel);
0305 
0306     ret = sysinfo(&info);
0307     ASSERT_EQ(0, ret) {
0308         TH_LOG("Dispatch triggered unexpectedly");
0309     }
0310 }
0311 
0312 TEST_HARNESS_MAIN