Line data Source code
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 : 19 0 : static void trigger_sigsys(struct pt_regs *regs) 20 : { 21 0 : struct kernel_siginfo info; 22 : 23 0 : clear_siginfo(&info); 24 0 : info.si_signo = SIGSYS; 25 0 : info.si_code = SYS_USER_DISPATCH; 26 0 : info.si_call_addr = (void __user *)KSTK_EIP(current); 27 0 : info.si_errno = 0; 28 0 : info.si_arch = syscall_get_arch(current); 29 0 : info.si_syscall = syscall_get_nr(current, regs); 30 : 31 0 : force_sig_info(&info); 32 0 : } 33 : 34 0 : bool syscall_user_dispatch(struct pt_regs *regs) 35 : { 36 0 : struct syscall_user_dispatch *sd = ¤t->syscall_dispatch; 37 0 : char state; 38 : 39 0 : if (likely(instruction_pointer(regs) - sd->offset < sd->len)) 40 : return false; 41 : 42 0 : if (unlikely(arch_syscall_is_vdso_sigreturn(regs))) 43 : return false; 44 : 45 0 : if (likely(sd->selector)) { 46 : /* 47 : * access_ok() is performed once, at prctl time, when 48 : * the selector is loaded by userspace. 49 : */ 50 0 : if (unlikely(__get_user(state, sd->selector))) 51 0 : do_exit(SIGSEGV); 52 : 53 0 : if (likely(state == SYSCALL_DISPATCH_FILTER_ALLOW)) 54 : return false; 55 : 56 0 : if (state != SYSCALL_DISPATCH_FILTER_BLOCK) 57 0 : do_exit(SIGSYS); 58 : } 59 : 60 0 : sd->on_dispatch = true; 61 0 : syscall_rollback(current, regs); 62 0 : trigger_sigsys(regs); 63 : 64 0 : return true; 65 : } 66 : 67 0 : int set_syscall_user_dispatch(unsigned long mode, unsigned long offset, 68 : unsigned long len, char __user *selector) 69 : { 70 0 : switch (mode) { 71 0 : case PR_SYS_DISPATCH_OFF: 72 0 : if (offset || len || selector) 73 : return -EINVAL; 74 : break; 75 0 : 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 0 : if (offset && offset + len <= offset) 83 : return -EINVAL; 84 : 85 0 : if (selector && !access_ok(selector, sizeof(*selector))) 86 : return -EFAULT; 87 : 88 : break; 89 : default: 90 : return -EINVAL; 91 : } 92 : 93 0 : current->syscall_dispatch.selector = selector; 94 0 : current->syscall_dispatch.offset = offset; 95 0 : current->syscall_dispatch.len = len; 96 0 : current->syscall_dispatch.on_dispatch = false; 97 : 98 0 : if (mode == PR_SYS_DISPATCH_ON) 99 0 : set_syscall_work(SYSCALL_USER_DISPATCH); 100 : else 101 0 : clear_syscall_work(SYSCALL_USER_DISPATCH); 102 : 103 : return 0; 104 : }