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