cachepc-linux

Fork of AMDESE/linux with modifications for CachePC side-channel attack
git clone https://git.sinitax.com/sinitax/cachepc-linux
Log | Files | Refs | README | LICENSE | sfeed.txt

sud_test.c (7151B)


      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
     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 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 */
    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
    163TEST(dispatch_and_return)
    164{
    165	long ret;
    166	struct sigaction act;
    167	sigset_t mask;
    168
    169	glob_sel = 0;
    170	nr_syscalls_emulated = 0;
    171	si_code = 0;
    172	si_errno = 0;
    173
    174	memset(&act, 0, sizeof(act));
    175	sigemptyset(&mask);
    176
    177	act.sa_sigaction = handle_sigsys;
    178	act.sa_flags = SA_SIGINFO;
    179	act.sa_mask = mask;
    180
    181	ret = sigaction(SIGSYS, &act, NULL);
    182	ASSERT_EQ(0, ret);
    183
    184	/* Make sure selector is good prior to prctl. */
    185	SYSCALL_DISPATCH_OFF(glob_sel);
    186
    187	ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &glob_sel);
    188	ASSERT_EQ(0, ret) {
    189		TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
    190	}
    191
    192	/* MAGIC_SYSCALL_1 doesn't exist. */
    193	SYSCALL_DISPATCH_OFF(glob_sel);
    194	ret = syscall(MAGIC_SYSCALL_1);
    195	EXPECT_EQ(-1, ret) {
    196		TH_LOG("Dispatch triggered unexpectedly");
    197	}
    198
    199	/* MAGIC_SYSCALL_1 should be emulated. */
    200	nr_syscalls_emulated = 0;
    201	SYSCALL_DISPATCH_ON(glob_sel);
    202
    203	ret = syscall(MAGIC_SYSCALL_1);
    204	EXPECT_EQ(MAGIC_SYSCALL_1, ret) {
    205		TH_LOG("Failed to intercept syscall");
    206	}
    207	EXPECT_EQ(1, nr_syscalls_emulated) {
    208		TH_LOG("Failed to emulate syscall");
    209	}
    210	ASSERT_EQ(SYS_USER_DISPATCH, si_code) {
    211		TH_LOG("Bad si_code in SIGSYS");
    212	}
    213	ASSERT_EQ(0, si_errno) {
    214		TH_LOG("Bad si_errno in SIGSYS");
    215	}
    216}
    217
    218TEST_SIGNAL(bad_selector, SIGSYS)
    219{
    220	long ret;
    221	struct sigaction act;
    222	sigset_t mask;
    223	struct sysinfo info;
    224
    225	glob_sel = SYSCALL_DISPATCH_FILTER_ALLOW;
    226	nr_syscalls_emulated = 0;
    227	si_code = 0;
    228	si_errno = 0;
    229
    230	memset(&act, 0, sizeof(act));
    231	sigemptyset(&mask);
    232
    233	act.sa_sigaction = handle_sigsys;
    234	act.sa_flags = SA_SIGINFO;
    235	act.sa_mask = mask;
    236
    237	ret = sigaction(SIGSYS, &act, NULL);
    238	ASSERT_EQ(0, ret);
    239
    240	/* Make sure selector is good prior to prctl. */
    241	SYSCALL_DISPATCH_OFF(glob_sel);
    242
    243	ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &glob_sel);
    244	ASSERT_EQ(0, ret) {
    245		TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
    246	}
    247
    248	glob_sel = -1;
    249
    250	sysinfo(&info);
    251
    252	/* Even though it is ready to catch SIGSYS, the signal is
    253	 * supposed to be uncatchable.
    254	 */
    255
    256	EXPECT_FALSE(true) {
    257		TH_LOG("Unreachable!");
    258	}
    259}
    260
    261TEST(disable_dispatch)
    262{
    263	int ret;
    264	struct sysinfo info;
    265	char sel = 0;
    266
    267	ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, 0, &sel);
    268	ASSERT_EQ(0, ret) {
    269		TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
    270	}
    271
    272	/* MAGIC_SYSCALL_1 doesn't exist. */
    273	SYSCALL_DISPATCH_OFF(glob_sel);
    274
    275	ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_OFF, 0, 0, 0);
    276	EXPECT_EQ(0, ret) {
    277		TH_LOG("Failed to unset syscall user dispatch");
    278	}
    279
    280	/* Shouldn't have any effect... */
    281	SYSCALL_DISPATCH_ON(glob_sel);
    282
    283	ret = syscall(__NR_sysinfo, &info);
    284	EXPECT_EQ(0, ret) {
    285		TH_LOG("Dispatch triggered unexpectedly");
    286	}
    287}
    288
    289TEST(direct_dispatch_range)
    290{
    291	int ret = 0;
    292	struct sysinfo info;
    293	char sel = SYSCALL_DISPATCH_FILTER_ALLOW;
    294
    295	/*
    296	 * Instead of calculating libc addresses; allow the entire
    297	 * memory map and lock the selector.
    298	 */
    299	ret = prctl(PR_SET_SYSCALL_USER_DISPATCH, PR_SYS_DISPATCH_ON, 0, -1L, &sel);
    300	ASSERT_EQ(0, ret) {
    301		TH_LOG("Kernel does not support CONFIG_SYSCALL_USER_DISPATCH");
    302	}
    303
    304	SYSCALL_DISPATCH_ON(sel);
    305
    306	ret = sysinfo(&info);
    307	ASSERT_EQ(0, ret) {
    308		TH_LOG("Dispatch triggered unexpectedly");
    309	}
    310}
    311
    312TEST_HARNESS_MAIN