Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/kernel/entry/syscall-common.c
29267 views
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
114