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 noinstr void syscall_enter_from_user_mode_prepare(struct pt_regs *regs) 67*a70e9f64SJinjie Ruan { 68*a70e9f64SJinjie Ruan enter_from_user_mode(regs); 69*a70e9f64SJinjie Ruan instrumentation_begin(); 70*a70e9f64SJinjie Ruan local_irq_enable(); 71*a70e9f64SJinjie Ruan instrumentation_end(); 72*a70e9f64SJinjie Ruan } 73*a70e9f64SJinjie Ruan 74*a70e9f64SJinjie Ruan /* 75*a70e9f64SJinjie Ruan * If SYSCALL_EMU is set, then the only reason to report is when 76*a70e9f64SJinjie Ruan * SINGLESTEP is set (i.e. PTRACE_SYSEMU_SINGLESTEP). This syscall 77*a70e9f64SJinjie Ruan * instruction has been already reported in syscall_enter_from_user_mode(). 78*a70e9f64SJinjie Ruan */ 79*a70e9f64SJinjie Ruan static inline bool report_single_step(unsigned long work) 80*a70e9f64SJinjie Ruan { 81*a70e9f64SJinjie Ruan if (work & SYSCALL_WORK_SYSCALL_EMU) 82*a70e9f64SJinjie Ruan return false; 83*a70e9f64SJinjie Ruan 84*a70e9f64SJinjie Ruan return work & SYSCALL_WORK_SYSCALL_EXIT_TRAP; 85*a70e9f64SJinjie Ruan } 86*a70e9f64SJinjie Ruan 87*a70e9f64SJinjie Ruan void syscall_exit_work(struct pt_regs *regs, unsigned long work) 88*a70e9f64SJinjie Ruan { 89*a70e9f64SJinjie Ruan bool step; 90*a70e9f64SJinjie Ruan 91*a70e9f64SJinjie Ruan /* 92*a70e9f64SJinjie Ruan * If the syscall was rolled back due to syscall user dispatching, 93*a70e9f64SJinjie Ruan * then the tracers below are not invoked for the same reason as 94*a70e9f64SJinjie Ruan * the entry side was not invoked in syscall_trace_enter(): The ABI 95*a70e9f64SJinjie Ruan * of these syscalls is unknown. 96*a70e9f64SJinjie Ruan */ 97*a70e9f64SJinjie Ruan if (work & SYSCALL_WORK_SYSCALL_USER_DISPATCH) { 98*a70e9f64SJinjie Ruan if (unlikely(current->syscall_dispatch.on_dispatch)) { 99*a70e9f64SJinjie Ruan current->syscall_dispatch.on_dispatch = false; 100*a70e9f64SJinjie Ruan return; 101*a70e9f64SJinjie Ruan } 102*a70e9f64SJinjie Ruan } 103*a70e9f64SJinjie Ruan 104*a70e9f64SJinjie Ruan audit_syscall_exit(regs); 105*a70e9f64SJinjie Ruan 106*a70e9f64SJinjie Ruan if (work & SYSCALL_WORK_SYSCALL_TRACEPOINT) 107*a70e9f64SJinjie Ruan trace_sys_exit(regs, syscall_get_return_value(current, regs)); 108*a70e9f64SJinjie Ruan 109*a70e9f64SJinjie Ruan step = report_single_step(work); 110*a70e9f64SJinjie Ruan if (step || work & SYSCALL_WORK_SYSCALL_TRACE) 111*a70e9f64SJinjie Ruan ptrace_report_syscall_exit(regs, step); 112*a70e9f64SJinjie Ruan } 113