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