]> git.proxmox.com Git - mirror_ubuntu-hirsute-kernel.git/blob - kernel/entry/common.c
entry: Provide generic syscall entry functionality
[mirror_ubuntu-hirsute-kernel.git] / kernel / entry / common.c
1 // SPDX-License-Identifier: GPL-2.0
2
3 #include <linux/context_tracking.h>
4 #include <linux/entry-common.h>
5
6 #define CREATE_TRACE_POINTS
7 #include <trace/events/syscalls.h>
8
9 /**
10 * enter_from_user_mode - Establish state when coming from user mode
11 *
12 * Syscall/interrupt entry disables interrupts, but user mode is traced as
13 * interrupts enabled. Also with NO_HZ_FULL RCU might be idle.
14 *
15 * 1) Tell lockdep that interrupts are disabled
16 * 2) Invoke context tracking if enabled to reactivate RCU
17 * 3) Trace interrupts off state
18 */
19 static __always_inline void enter_from_user_mode(struct pt_regs *regs)
20 {
21 arch_check_user_regs(regs);
22 lockdep_hardirqs_off(CALLER_ADDR0);
23
24 CT_WARN_ON(ct_state() != CONTEXT_USER);
25 user_exit_irqoff();
26
27 instrumentation_begin();
28 trace_hardirqs_off_finish();
29 instrumentation_end();
30 }
31
32 static inline void syscall_enter_audit(struct pt_regs *regs, long syscall)
33 {
34 if (unlikely(audit_context())) {
35 unsigned long args[6];
36
37 syscall_get_arguments(current, regs, args);
38 audit_syscall_entry(syscall, args[0], args[1], args[2], args[3]);
39 }
40 }
41
42 static long syscall_trace_enter(struct pt_regs *regs, long syscall,
43 unsigned long ti_work)
44 {
45 long ret = 0;
46
47 /* Handle ptrace */
48 if (ti_work & (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_EMU)) {
49 ret = arch_syscall_enter_tracehook(regs);
50 if (ret || (ti_work & _TIF_SYSCALL_EMU))
51 return -1L;
52 }
53
54 /* Do seccomp after ptrace, to catch any tracer changes. */
55 if (ti_work & _TIF_SECCOMP) {
56 ret = __secure_computing(NULL);
57 if (ret == -1L)
58 return ret;
59 }
60
61 if (unlikely(ti_work & _TIF_SYSCALL_TRACEPOINT))
62 trace_sys_enter(regs, syscall);
63
64 syscall_enter_audit(regs, syscall);
65
66 return ret ? : syscall;
67 }
68
69 noinstr long syscall_enter_from_user_mode(struct pt_regs *regs, long syscall)
70 {
71 unsigned long ti_work;
72
73 enter_from_user_mode(regs);
74 instrumentation_begin();
75
76 local_irq_enable();
77 ti_work = READ_ONCE(current_thread_info()->flags);
78 if (ti_work & SYSCALL_ENTER_WORK)
79 syscall = syscall_trace_enter(regs, syscall, ti_work);
80 instrumentation_end();
81
82 return syscall;
83 }
84
85 noinstr void irqentry_enter_from_user_mode(struct pt_regs *regs)
86 {
87 enter_from_user_mode(regs);
88 }