entry: Provide generic syscall entry functionality
[linux-block.git] / kernel / entry / common.c
CommitLineData
142781e1
TG
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 */
19static __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
32static 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
42static 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
69noinstr 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
85noinstr void irqentry_enter_from_user_mode(struct pt_regs *regs)
86{
87 enter_from_user_mode(regs);
88}