projects/linux·blob v6.19 · refs

104 lines · 2.7 KiB

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