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 static 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 34 bool syscall_user_dispatch(struct pt_regs *regs) 35 { 36 struct syscall_user_dispatch *sd = ¤t->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 71 static int task_set_syscall_user_dispatch(struct task_struct *task, unsigned long mode, 72 unsigned long offset, unsigned long len, 73 char __user *selector) 74 { 75 switch (mode) { 76 case PR_SYS_DISPATCH_OFF: 77 if (offset || len || selector) 78 return -EINVAL; 79 break; 80 case PR_SYS_DISPATCH_ON: 81 /* 82 * Validate the direct dispatcher region just for basic 83 * sanity against overflow and a 0-sized dispatcher 84 * region. If the user is able to submit a syscall from 85 * an address, that address is obviously valid. 86 */ 87 if (offset && offset + len <= offset) 88 return -EINVAL; 89 90 if (selector && !access_ok(selector, sizeof(*selector))) 91 return -EFAULT; 92 93 break; 94 default: 95 return -EINVAL; 96 } 97 98 task->syscall_dispatch.selector = selector; 99 task->syscall_dispatch.offset = offset; 100 task->syscall_dispatch.len = len; 101 task->syscall_dispatch.on_dispatch = false; 102 103 if (mode == PR_SYS_DISPATCH_ON) 104 set_task_syscall_work(task, SYSCALL_USER_DISPATCH); 105 else 106 clear_task_syscall_work(task, SYSCALL_USER_DISPATCH); 107 108 return 0; 109 } 110 111 int set_syscall_user_dispatch(unsigned long mode, unsigned long offset, 112 unsigned long len, char __user *selector) 113 { 114 return task_set_syscall_user_dispatch(current, mode, offset, len, selector); 115 } 116