11446e1dfSGabriel Krisman Bertazi // SPDX-License-Identifier: GPL-2.0
21446e1dfSGabriel Krisman Bertazi /*
31446e1dfSGabriel Krisman Bertazi * Copyright (C) 2020 Collabora Ltd.
41446e1dfSGabriel Krisman Bertazi */
51446e1dfSGabriel Krisman Bertazi #include <linux/sched.h>
61446e1dfSGabriel Krisman Bertazi #include <linux/prctl.h>
7*3f67987cSGregory Price #include <linux/ptrace.h>
81446e1dfSGabriel Krisman Bertazi #include <linux/syscall_user_dispatch.h>
91446e1dfSGabriel Krisman Bertazi #include <linux/uaccess.h>
101446e1dfSGabriel Krisman Bertazi #include <linux/signal.h>
111446e1dfSGabriel Krisman Bertazi #include <linux/elf.h>
121446e1dfSGabriel Krisman Bertazi
131446e1dfSGabriel Krisman Bertazi #include <linux/sched/signal.h>
141446e1dfSGabriel Krisman Bertazi #include <linux/sched/task_stack.h>
151446e1dfSGabriel Krisman Bertazi
161446e1dfSGabriel Krisman Bertazi #include <asm/syscall.h>
171446e1dfSGabriel Krisman Bertazi
181446e1dfSGabriel Krisman Bertazi #include "common.h"
191446e1dfSGabriel Krisman Bertazi
trigger_sigsys(struct pt_regs * regs)201446e1dfSGabriel Krisman Bertazi static void trigger_sigsys(struct pt_regs *regs)
211446e1dfSGabriel Krisman Bertazi {
221446e1dfSGabriel Krisman Bertazi struct kernel_siginfo info;
231446e1dfSGabriel Krisman Bertazi
241446e1dfSGabriel Krisman Bertazi clear_siginfo(&info);
251446e1dfSGabriel Krisman Bertazi info.si_signo = SIGSYS;
261446e1dfSGabriel Krisman Bertazi info.si_code = SYS_USER_DISPATCH;
271446e1dfSGabriel Krisman Bertazi info.si_call_addr = (void __user *)KSTK_EIP(current);
281446e1dfSGabriel Krisman Bertazi info.si_errno = 0;
291446e1dfSGabriel Krisman Bertazi info.si_arch = syscall_get_arch(current);
301446e1dfSGabriel Krisman Bertazi info.si_syscall = syscall_get_nr(current, regs);
311446e1dfSGabriel Krisman Bertazi
321446e1dfSGabriel Krisman Bertazi force_sig_info(&info);
331446e1dfSGabriel Krisman Bertazi }
341446e1dfSGabriel Krisman Bertazi
syscall_user_dispatch(struct pt_regs * regs)351446e1dfSGabriel Krisman Bertazi bool syscall_user_dispatch(struct pt_regs *regs)
361446e1dfSGabriel Krisman Bertazi {
371446e1dfSGabriel Krisman Bertazi struct syscall_user_dispatch *sd = ¤t->syscall_dispatch;
381446e1dfSGabriel Krisman Bertazi char state;
391446e1dfSGabriel Krisman Bertazi
401446e1dfSGabriel Krisman Bertazi if (likely(instruction_pointer(regs) - sd->offset < sd->len))
411446e1dfSGabriel Krisman Bertazi return false;
421446e1dfSGabriel Krisman Bertazi
431446e1dfSGabriel Krisman Bertazi if (unlikely(arch_syscall_is_vdso_sigreturn(regs)))
441446e1dfSGabriel Krisman Bertazi return false;
451446e1dfSGabriel Krisman Bertazi
461446e1dfSGabriel Krisman Bertazi if (likely(sd->selector)) {
471446e1dfSGabriel Krisman Bertazi /*
481446e1dfSGabriel Krisman Bertazi * access_ok() is performed once, at prctl time, when
491446e1dfSGabriel Krisman Bertazi * the selector is loaded by userspace.
501446e1dfSGabriel Krisman Bertazi */
51941edc5bSEric W. Biederman if (unlikely(__get_user(state, sd->selector))) {
52fcb116bcSEric W. Biederman force_exit_sig(SIGSEGV);
53941edc5bSEric W. Biederman return true;
54941edc5bSEric W. Biederman }
551446e1dfSGabriel Krisman Bertazi
5636a6c843SGabriel Krisman Bertazi if (likely(state == SYSCALL_DISPATCH_FILTER_ALLOW))
571446e1dfSGabriel Krisman Bertazi return false;
581446e1dfSGabriel Krisman Bertazi
59941edc5bSEric W. Biederman if (state != SYSCALL_DISPATCH_FILTER_BLOCK) {
60fcb116bcSEric W. Biederman force_exit_sig(SIGSYS);
61941edc5bSEric W. Biederman return true;
62941edc5bSEric W. Biederman }
631446e1dfSGabriel Krisman Bertazi }
641446e1dfSGabriel Krisman Bertazi
651446e1dfSGabriel Krisman Bertazi sd->on_dispatch = true;
661446e1dfSGabriel Krisman Bertazi syscall_rollback(current, regs);
671446e1dfSGabriel Krisman Bertazi trigger_sigsys(regs);
681446e1dfSGabriel Krisman Bertazi
691446e1dfSGabriel Krisman Bertazi return true;
701446e1dfSGabriel Krisman Bertazi }
711446e1dfSGabriel Krisman Bertazi
task_set_syscall_user_dispatch(struct task_struct * task,unsigned long mode,unsigned long offset,unsigned long len,char __user * selector)7243360686SGregory Price static int task_set_syscall_user_dispatch(struct task_struct *task, unsigned long mode,
7343360686SGregory Price unsigned long offset, unsigned long len,
7443360686SGregory Price char __user *selector)
751446e1dfSGabriel Krisman Bertazi {
761446e1dfSGabriel Krisman Bertazi switch (mode) {
771446e1dfSGabriel Krisman Bertazi case PR_SYS_DISPATCH_OFF:
781446e1dfSGabriel Krisman Bertazi if (offset || len || selector)
791446e1dfSGabriel Krisman Bertazi return -EINVAL;
801446e1dfSGabriel Krisman Bertazi break;
811446e1dfSGabriel Krisman Bertazi case PR_SYS_DISPATCH_ON:
821446e1dfSGabriel Krisman Bertazi /*
831446e1dfSGabriel Krisman Bertazi * Validate the direct dispatcher region just for basic
841446e1dfSGabriel Krisman Bertazi * sanity against overflow and a 0-sized dispatcher
851446e1dfSGabriel Krisman Bertazi * region. If the user is able to submit a syscall from
861446e1dfSGabriel Krisman Bertazi * an address, that address is obviously valid.
871446e1dfSGabriel Krisman Bertazi */
881446e1dfSGabriel Krisman Bertazi if (offset && offset + len <= offset)
891446e1dfSGabriel Krisman Bertazi return -EINVAL;
901446e1dfSGabriel Krisman Bertazi
91463b7715SGregory Price /*
92463b7715SGregory Price * access_ok() will clear memory tags for tagged addresses
93463b7715SGregory Price * if current has memory tagging enabled.
94463b7715SGregory Price
95463b7715SGregory Price * To enable a tracer to set a tracees selector the
96463b7715SGregory Price * selector address must be untagged for access_ok(),
97463b7715SGregory Price * otherwise an untagged tracer will always fail to set a
98463b7715SGregory Price * tagged tracees selector.
99463b7715SGregory Price */
100463b7715SGregory Price if (selector && !access_ok(untagged_addr(selector), sizeof(*selector)))
1011446e1dfSGabriel Krisman Bertazi return -EFAULT;
1021446e1dfSGabriel Krisman Bertazi
1031446e1dfSGabriel Krisman Bertazi break;
1041446e1dfSGabriel Krisman Bertazi default:
1051446e1dfSGabriel Krisman Bertazi return -EINVAL;
1061446e1dfSGabriel Krisman Bertazi }
1071446e1dfSGabriel Krisman Bertazi
10843360686SGregory Price task->syscall_dispatch.selector = selector;
10943360686SGregory Price task->syscall_dispatch.offset = offset;
11043360686SGregory Price task->syscall_dispatch.len = len;
11143360686SGregory Price task->syscall_dispatch.on_dispatch = false;
1121446e1dfSGabriel Krisman Bertazi
1131446e1dfSGabriel Krisman Bertazi if (mode == PR_SYS_DISPATCH_ON)
11443360686SGregory Price set_task_syscall_work(task, SYSCALL_USER_DISPATCH);
1151446e1dfSGabriel Krisman Bertazi else
11643360686SGregory Price clear_task_syscall_work(task, SYSCALL_USER_DISPATCH);
1171446e1dfSGabriel Krisman Bertazi
1181446e1dfSGabriel Krisman Bertazi return 0;
1191446e1dfSGabriel Krisman Bertazi }
12043360686SGregory Price
set_syscall_user_dispatch(unsigned long mode,unsigned long offset,unsigned long len,char __user * selector)12143360686SGregory Price int set_syscall_user_dispatch(unsigned long mode, unsigned long offset,
12243360686SGregory Price unsigned long len, char __user *selector)
12343360686SGregory Price {
12443360686SGregory Price return task_set_syscall_user_dispatch(current, mode, offset, len, selector);
12543360686SGregory Price }
126*3f67987cSGregory Price
syscall_user_dispatch_get_config(struct task_struct * task,unsigned long size,void __user * data)127*3f67987cSGregory Price int syscall_user_dispatch_get_config(struct task_struct *task, unsigned long size,
128*3f67987cSGregory Price void __user *data)
129*3f67987cSGregory Price {
130*3f67987cSGregory Price struct syscall_user_dispatch *sd = &task->syscall_dispatch;
131*3f67987cSGregory Price struct ptrace_sud_config cfg;
132*3f67987cSGregory Price
133*3f67987cSGregory Price if (size != sizeof(cfg))
134*3f67987cSGregory Price return -EINVAL;
135*3f67987cSGregory Price
136*3f67987cSGregory Price if (test_task_syscall_work(task, SYSCALL_USER_DISPATCH))
137*3f67987cSGregory Price cfg.mode = PR_SYS_DISPATCH_ON;
138*3f67987cSGregory Price else
139*3f67987cSGregory Price cfg.mode = PR_SYS_DISPATCH_OFF;
140*3f67987cSGregory Price
141*3f67987cSGregory Price cfg.offset = sd->offset;
142*3f67987cSGregory Price cfg.len = sd->len;
143*3f67987cSGregory Price cfg.selector = (__u64)(uintptr_t)sd->selector;
144*3f67987cSGregory Price
145*3f67987cSGregory Price if (copy_to_user(data, &cfg, sizeof(cfg)))
146*3f67987cSGregory Price return -EFAULT;
147*3f67987cSGregory Price
148*3f67987cSGregory Price return 0;
149*3f67987cSGregory Price }
150*3f67987cSGregory Price
syscall_user_dispatch_set_config(struct task_struct * task,unsigned long size,void __user * data)151*3f67987cSGregory Price int syscall_user_dispatch_set_config(struct task_struct *task, unsigned long size,
152*3f67987cSGregory Price void __user *data)
153*3f67987cSGregory Price {
154*3f67987cSGregory Price struct ptrace_sud_config cfg;
155*3f67987cSGregory Price
156*3f67987cSGregory Price if (size != sizeof(cfg))
157*3f67987cSGregory Price return -EINVAL;
158*3f67987cSGregory Price
159*3f67987cSGregory Price if (copy_from_user(&cfg, data, sizeof(cfg)))
160*3f67987cSGregory Price return -EFAULT;
161*3f67987cSGregory Price
162*3f67987cSGregory Price return task_set_syscall_user_dispatch(task, cfg.mode, cfg.offset, cfg.len,
163*3f67987cSGregory Price (char __user *)(uintptr_t)cfg.selector);
164*3f67987cSGregory Price }
165