xref: /linux/kernel/entry/syscall-common.c (revision 24f171c7e145f43b9f187578e89b0982ce87e54c)
1*a70e9f64SJinjie Ruan // SPDX-License-Identifier: GPL-2.0
2*a70e9f64SJinjie Ruan 
3*a70e9f64SJinjie Ruan #include <linux/audit.h>
4*a70e9f64SJinjie Ruan #include <linux/entry-common.h>
5*a70e9f64SJinjie Ruan #include "common.h"
6*a70e9f64SJinjie Ruan 
7*a70e9f64SJinjie Ruan #define CREATE_TRACE_POINTS
8*a70e9f64SJinjie Ruan #include <trace/events/syscalls.h>
9*a70e9f64SJinjie Ruan 
10*a70e9f64SJinjie Ruan static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
11*a70e9f64SJinjie Ruan {
12*a70e9f64SJinjie Ruan 	if (unlikely(audit_context())) {
13*a70e9f64SJinjie Ruan 		unsigned long args[6];
14*a70e9f64SJinjie Ruan 
15*a70e9f64SJinjie Ruan 		syscall_get_arguments(current, regs, args);
16*a70e9f64SJinjie Ruan 		audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
17*a70e9f64SJinjie Ruan 	}
18*a70e9f64SJinjie Ruan }
19*a70e9f64SJinjie Ruan 
20*a70e9f64SJinjie Ruan long syscall_trace_enter(struct pt_regs *regs, long syscall,
21*a70e9f64SJinjie Ruan 				unsigned long work)
22*a70e9f64SJinjie Ruan {
23*a70e9f64SJinjie Ruan 	long ret = 0;
24*a70e9f64SJinjie Ruan 
25*a70e9f64SJinjie Ruan 	/*
26*a70e9f64SJinjie Ruan 	 * Handle Syscall User Dispatch.  This must comes first, since
27*a70e9f64SJinjie Ruan 	 * the ABI here can be something that doesn't make sense for
28*a70e9f64SJinjie Ruan 	 * other syscall_work features.
29*a70e9f64SJinjie Ruan 	 */
30*a70e9f64SJinjie Ruan 	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
31*a70e9f64SJinjie Ruan 		if (syscall_user_dispatch(regs))
32*a70e9f64SJinjie Ruan 			return -1L;
33*a70e9f64SJinjie Ruan 	}
34*a70e9f64SJinjie Ruan 
35*a70e9f64SJinjie Ruan 	/* Handle ptrace */
36*a70e9f64SJinjie Ruan 	if (work & (SYSCALL_WORK_SYSCALL_TRACE | SYSCALL_WORK_SYSCALL_EMU)) {
37*a70e9f64SJinjie Ruan 		ret = ptrace_report_syscall_entry(regs);
38*a70e9f64SJinjie Ruan 		if (ret || (work & SYSCALL_WORK_SYSCALL_EMU))
39*a70e9f64SJinjie Ruan 			return -1L;
40*a70e9f64SJinjie Ruan 	}
41*a70e9f64SJinjie Ruan 
42*a70e9f64SJinjie Ruan 	/* Do seccomp after ptrace, to catch any tracer changes. */
43*a70e9f64SJinjie Ruan 	if (work & SYSCALL_WORK_SECCOMP) {
44*a70e9f64SJinjie Ruan 		ret = __secure_computing();
45*a70e9f64SJinjie Ruan 		if (ret == -1L)
46*a70e9f64SJinjie Ruan 			return ret;
47*a70e9f64SJinjie Ruan 	}
48*a70e9f64SJinjie Ruan 
49*a70e9f64SJinjie Ruan 	/* Either of the above might have changed the syscall number */
50*a70e9f64SJinjie Ruan 	syscall = syscall_get_nr(current, regs);
51*a70e9f64SJinjie Ruan 
52*a70e9f64SJinjie Ruan 	if (unlikely(work & SYSCALL_WORK_SYSCALL_TRACEPOINT)) {
53*a70e9f64SJinjie Ruan 		trace_sys_enter(regs, syscall);
54*a70e9f64SJinjie Ruan 		/*
55*a70e9f64SJinjie Ruan 		 * Probes or BPF hooks in the tracepoint may have changed the
56*a70e9f64SJinjie Ruan 		 * system call number as well.
57*a70e9f64SJinjie Ruan 		 */
58*a70e9f64SJinjie Ruan 		syscall = syscall_get_nr(current, regs);
59*a70e9f64SJinjie Ruan 	}
60*a70e9f64SJinjie Ruan 
61*a70e9f64SJinjie Ruan 	syscall_enter_audit(regs, syscall);
62*a70e9f64SJinjie Ruan 
63*a70e9f64SJinjie Ruan 	return ret ? : syscall;
64*a70e9f64SJinjie Ruan }
65*a70e9f64SJinjie Ruan 
66*a70e9f64SJinjie Ruan /*
67*a70e9f64SJinjie Ruan  * If SYSCALL_EMU is set, then the only reason to report is when
68*a70e9f64SJinjie Ruan  * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP).  This syscall
69*a70e9f64SJinjie Ruan  * instruction has been already reported in syscall_enter_from_user_mode().
70*a70e9f64SJinjie Ruan  */
71*a70e9f64SJinjie Ruan static inline bool report_single_step(unsigned long work)
72*a70e9f64SJinjie Ruan {
73*a70e9f64SJinjie Ruan 	if (work & SYSCALL_WORK_SYSCALL_EMU)
74*a70e9f64SJinjie Ruan 		return false;
75*a70e9f64SJinjie Ruan 
76*a70e9f64SJinjie Ruan 	return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP;
77*a70e9f64SJinjie Ruan }
78*a70e9f64SJinjie Ruan 
79*a70e9f64SJinjie Ruan void syscall_exit_work(struct pt_regs *regs, unsigned long work)
80*a70e9f64SJinjie Ruan {
81*a70e9f64SJinjie Ruan 	bool step;
82*a70e9f64SJinjie Ruan 
83*a70e9f64SJinjie Ruan 	/*
84*a70e9f64SJinjie Ruan 	 * If the syscall was rolled back due to syscall user dispatching,
85*a70e9f64SJinjie Ruan 	 * then the tracers below are not invoked for the same reason as
86*a70e9f64SJinjie Ruan 	 * the entry side was not invoked in syscall_trace_enter(): The ABI
87*a70e9f64SJinjie Ruan 	 * of these syscalls is unknown.
88*a70e9f64SJinjie Ruan 	 */
89*a70e9f64SJinjie Ruan 	if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) {
90*a70e9f64SJinjie Ruan 		if (unlikely(current->syscall_dispatch.on_dispatch)) {
91*a70e9f64SJinjie Ruan 			current->syscall_dispatch.on_dispatch = false;
92*a70e9f64SJinjie Ruan 			return;
93*a70e9f64SJinjie Ruan 		}
94*a70e9f64SJinjie Ruan 	}
95*a70e9f64SJinjie Ruan 
96*a70e9f64SJinjie Ruan 	audit_syscall_exit(regs);
97*a70e9f64SJinjie Ruan 
98*a70e9f64SJinjie Ruan 	if (work & SYSCALL_WORK_SYSCALL_TRACEPOINT)
99*a70e9f64SJinjie Ruan 		trace_sys_exit(regs, syscall_get_return_value(current, regs));
100*a70e9f64SJinjie Ruan 
101*a70e9f64SJinjie Ruan 	step = report_single_step(work);
102*a70e9f64SJinjie Ruan 	if (step || work & SYSCALL_WORK_SYSCALL_TRACE)
103*a70e9f64SJinjie Ruan 		ptrace_report_syscall_exit(regs, step);
104*a70e9f64SJinjie Ruan }
105