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

syscall_user_dispatch.c (2500B)


      1// SPDX-License-Identifier: GPL-2.0
      2/*
      3 * Copyright (C) 2020 Collabora Ltd.
      4 */
      5#include <linux/sched.h>
      6#include <linux/prctl.h>
      7#include <linux/syscall_user_dispatch.h>
      8#include <linux/uaccess.h>
      9#include <linux/signal.h>
     10#include <linux/elf.h>
     11
     12#include <linux/sched/signal.h>
     13#include <linux/sched/task_stack.h>
     14
     15#include <asm/syscall.h>
     16
     17#include "common.h"
     18
     19static void trigger_sigsys(struct pt_regs *regs)
     20{
     21	struct kernel_siginfo info;
     22
     23	clear_siginfo(&info);
     24	info.si_signo = SIGSYS;
     25	info.si_code = SYS_USER_DISPATCH;
     26	info.si_call_addr = (void __user *)KSTK_EIP(current);
     27	info.si_errno = 0;
     28	info.si_arch = syscall_get_arch(current);
     29	info.si_syscall = syscall_get_nr(current, regs);
     30
     31	force_sig_info(&info);
     32}
     33
     34bool syscall_user_dispatch(struct pt_regs *regs)
     35{
     36	struct syscall_user_dispatch *sd = &current->syscall_dispatch;
     37	char state;
     38
     39	if (likely(instruction_pointer(regs) - sd->offset < sd->len))
     40		return false;
     41
     42	if (unlikely(arch_syscall_is_vdso_sigreturn(regs)))
     43		return false;
     44
     45	if (likely(sd->selector)) {
     46		/*
     47		 * access_ok() is performed once, at prctl time, when
     48		 * the selector is loaded by userspace.
     49		 */
     50		if (unlikely(__get_user(state, sd->selector))) {
     51			force_exit_sig(SIGSEGV);
     52			return true;
     53		}
     54
     55		if (likely(state == SYSCALL_DISPATCH_FILTER_ALLOW))
     56			return false;
     57
     58		if (state != SYSCALL_DISPATCH_FILTER_BLOCK) {
     59			force_exit_sig(SIGSYS);
     60			return true;
     61		}
     62	}
     63
     64	sd->on_dispatch = true;
     65	syscall_rollback(current, regs);
     66	trigger_sigsys(regs);
     67
     68	return true;
     69}
     70
     71int set_syscall_user_dispatch(unsigned long mode, unsigned long offset,
     72			      unsigned long len, char __user *selector)
     73{
     74	switch (mode) {
     75	case PR_SYS_DISPATCH_OFF:
     76		if (offset || len || selector)
     77			return -EINVAL;
     78		break;
     79	case PR_SYS_DISPATCH_ON:
     80		/*
     81		 * Validate the direct dispatcher region just for basic
     82		 * sanity against overflow and a 0-sized dispatcher
     83		 * region.  If the user is able to submit a syscall from
     84		 * an address, that address is obviously valid.
     85		 */
     86		if (offset && offset + len <= offset)
     87			return -EINVAL;
     88
     89		if (selector && !access_ok(selector, sizeof(*selector)))
     90			return -EFAULT;
     91
     92		break;
     93	default:
     94		return -EINVAL;
     95	}
     96
     97	current->syscall_dispatch.selector = selector;
     98	current->syscall_dispatch.offset = offset;
     99	current->syscall_dispatch.len = len;
    100	current->syscall_dispatch.on_dispatch = false;
    101
    102	if (mode == PR_SYS_DISPATCH_ON)
    103		set_syscall_work(SYSCALL_USER_DISPATCH);
    104	else
    105		clear_syscall_work(SYSCALL_USER_DISPATCH);
    106
    107	return 0;
    108}