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 = &current->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