Linux Audio

Check our new training course

Loading...
Note: File does not exist in v4.17.
  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			do_exit(SIGSEGV);
 52
 53		if (likely(state == SYSCALL_DISPATCH_FILTER_ALLOW))
 54			return false;
 55
 56		if (state != SYSCALL_DISPATCH_FILTER_BLOCK)
 57			do_exit(SIGSYS);
 58	}
 59
 60	sd->on_dispatch = true;
 61	syscall_rollback(current, regs);
 62	trigger_sigsys(regs);
 63
 64	return true;
 65}
 66
 67int set_syscall_user_dispatch(unsigned long mode, unsigned long offset,
 68			      unsigned long len, char __user *selector)
 69{
 70	switch (mode) {
 71	case PR_SYS_DISPATCH_OFF:
 72		if (offset || len || selector)
 73			return -EINVAL;
 74		break;
 75	case PR_SYS_DISPATCH_ON:
 76		/*
 77		 * Validate the direct dispatcher region just for basic
 78		 * sanity against overflow and a 0-sized dispatcher
 79		 * region.  If the user is able to submit a syscall from
 80		 * an address, that address is obviously valid.
 81		 */
 82		if (offset && offset + len <= offset)
 83			return -EINVAL;
 84
 85		if (selector && !access_ok(selector, sizeof(*selector)))
 86			return -EFAULT;
 87
 88		break;
 89	default:
 90		return -EINVAL;
 91	}
 92
 93	current->syscall_dispatch.selector = selector;
 94	current->syscall_dispatch.offset = offset;
 95	current->syscall_dispatch.len = len;
 96	current->syscall_dispatch.on_dispatch = false;
 97
 98	if (mode == PR_SYS_DISPATCH_ON)
 99		set_syscall_work(SYSCALL_USER_DISPATCH);
100	else
101		clear_syscall_work(SYSCALL_USER_DISPATCH);
102
103	return 0;
104}