Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Copyright (C) 2020 Collabora Ltd.
0004  */
0005 #include <linux/sched.h>
0006 #include <linux/prctl.h>
0007 #include <linux/syscall_user_dispatch.h>
0008 #include <linux/uaccess.h>
0009 #include <linux/signal.h>
0010 #include <linux/elf.h>
0011 
0012 #include <linux/sched/signal.h>
0013 #include <linux/sched/task_stack.h>
0014 
0015 #include <asm/syscall.h>
0016 
0017 #include "common.h"
0018 
0019 static void trigger_sigsys(struct pt_regs *regs)
0020 {
0021     struct kernel_siginfo info;
0022 
0023     clear_siginfo(&info);
0024     info.si_signo = SIGSYS;
0025     info.si_code = SYS_USER_DISPATCH;
0026     info.si_call_addr = (void __user *)KSTK_EIP(current);
0027     info.si_errno = 0;
0028     info.si_arch = syscall_get_arch(current);
0029     info.si_syscall = syscall_get_nr(current, regs);
0030 
0031     force_sig_info(&info);
0032 }
0033 
0034 bool syscall_user_dispatch(struct pt_regs *regs)
0035 {
0036     struct syscall_user_dispatch *sd = &current->syscall_dispatch;
0037     char state;
0038 
0039     if (likely(instruction_pointer(regs) - sd->offset < sd->len))
0040         return false;
0041 
0042     if (unlikely(arch_syscall_is_vdso_sigreturn(regs)))
0043         return false;
0044 
0045     if (likely(sd->selector)) {
0046         /*
0047          * access_ok() is performed once, at prctl time, when
0048          * the selector is loaded by userspace.
0049          */
0050         if (unlikely(__get_user(state, sd->selector))) {
0051             force_exit_sig(SIGSEGV);
0052             return true;
0053         }
0054 
0055         if (likely(state == SYSCALL_DISPATCH_FILTER_ALLOW))
0056             return false;
0057 
0058         if (state != SYSCALL_DISPATCH_FILTER_BLOCK) {
0059             force_exit_sig(SIGSYS);
0060             return true;
0061         }
0062     }
0063 
0064     sd->on_dispatch = true;
0065     syscall_rollback(current, regs);
0066     trigger_sigsys(regs);
0067 
0068     return true;
0069 }
0070 
0071 int set_syscall_user_dispatch(unsigned long mode, unsigned long offset,
0072                   unsigned long len, char __user *selector)
0073 {
0074     switch (mode) {
0075     case PR_SYS_DISPATCH_OFF:
0076         if (offset || len || selector)
0077             return -EINVAL;
0078         break;
0079     case PR_SYS_DISPATCH_ON:
0080         /*
0081          * Validate the direct dispatcher region just for basic
0082          * sanity against overflow and a 0-sized dispatcher
0083          * region.  If the user is able to submit a syscall from
0084          * an address, that address is obviously valid.
0085          */
0086         if (offset && offset + len <= offset)
0087             return -EINVAL;
0088 
0089         if (selector && !access_ok(selector, sizeof(*selector)))
0090             return -EFAULT;
0091 
0092         break;
0093     default:
0094         return -EINVAL;
0095     }
0096 
0097     current->syscall_dispatch.selector = selector;
0098     current->syscall_dispatch.offset = offset;
0099     current->syscall_dispatch.len = len;
0100     current->syscall_dispatch.on_dispatch = false;
0101 
0102     if (mode == PR_SYS_DISPATCH_ON)
0103         set_syscall_work(SYSCALL_USER_DISPATCH);
0104     else
0105         clear_syscall_work(SYSCALL_USER_DISPATCH);
0106 
0107     return 0;
0108 }