[PATCH v16 12/18] arm64: syscall: Use exit-specific flags check in el0_svc_common()
From: Jinjie Ruan <hidden>
Date: 2026-06-29 13:07:40
Also in:
linux-alpha, linux-m68k, linux-mips, linux-mm, linux-riscv, linux-s390, linux-sh, linux-um, lkml, loongarch
Subsystem:
arm64 port (aarch64 architecture), the rest · Maintainers:
Catalin Marinas, Will Deacon, Linus Torvalds
Use exit-specific _TIF_SYSCALL_EXIT_WORK mask to filter out entry-only flags during the system call exit path checks. This aligns arm64 with the generic entry framework's SYSCALL_WORK_EXIT semantics. [Rationale] The current syscall exit path re-evaluates the thread flags using the global _TIF_SYSCALL_WORK mask. However, _TIF_SYSCALL_WORK includes flags that are strictly relevant to system call entry processing: 1. _TIF_SECCOMP: Seccomp filtering (__secure_computing()) only runs on entry. There is no seccomp callback for syscall exit. 2. _TIF_SYSCALL_EMU: In PTRACE_SYSEMU mode, the syscall is intercepted and skipped on entry. Since the syscall is never fully executed, reporting a separate syscall exit stop is unnecessary. [Changes] - _TIF_SYSCALL_EXIT_WORK: A new mask containing only flags requiring exit-time processing: _TIF_SYSCALL_TRACE, _TIF_SYSCALL_AUDIT, and _TIF_SYSCALL_TRACEPOINT. - Optimize re-evaluation check: Use _TIF_SYSCALL_EXIT_WORK inside the el0_svc_common() fast-path block to prevent redundant exit work execution when entry-only flags fluctuate or are synchronously modified under the hood. The outermost gating maintains _TIF_SYSCALL_WORK to preserve architectural entry-exit symmetry for tracers. - Cleanup: Remove the has_syscall_work() helper as it is no longer needed, supporting direct flag comparison to clearly distinguish between entry and exit mandates. [Impact] Unnecessary exit tracing and auditing processing are safely bypassed when entry-specific flags fluctuate during the fast-path re-check block. This safely streamlines the syscall exit sequence to mirror the generic entry loop behaviors without breaking debugger expectations. No functional changes intended Cc: Mark Rutland <mark.rutland@arm.com> Cc: Will Deacon <will@kernel.org> Cc: Catalin Marinas <catalin.marinas@arm.com> Cc: Ada Couprie Diaz <redacted> Reviewed-by: Ada Couprie Diaz <redacted> Reviewed-by: Linus Walleij <linusw@kernel.org> Reviewed-by: Yeoreum Yun <redacted> Signed-off-by: Jinjie Ruan <redacted> --- arch/arm64/kernel/syscall.c | 11 +++-------- 1 file changed, 3 insertions(+), 8 deletions(-)
diff --git a/arch/arm64/kernel/syscall.c b/arch/arm64/kernel/syscall.c
index 6de1fe281d61..5dd94bece929 100644
--- a/arch/arm64/kernel/syscall.c
+++ b/arch/arm64/kernel/syscall.c@@ -54,11 +54,6 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno, syscall_set_return_value(current, regs, 0, ret); } -static inline bool has_syscall_work(unsigned long flags) -{ - return unlikely(flags & _TIF_SYSCALL_WORK); -} - static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr, const syscall_fn_t syscall_table[]) {
@@ -95,7 +90,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr, return; } - if (has_syscall_work(flags)) { + if (unlikely(flags & _TIF_SYSCALL_WORK)) { /* * The de-facto standard way to skip a system call using ptrace * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
@@ -125,9 +120,9 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr, * check again. However, if we were tracing entry, then we always trace * exit regardless, as the old entry assembly did. */ - if (!has_syscall_work(flags) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) { + if (!(unlikely(flags & _TIF_SYSCALL_WORK)) && !IS_ENABLED(CONFIG_DEBUG_RSEQ)) { flags = read_thread_flags(); - if (has_syscall_work(flags) || flags & _TIF_SINGLESTEP) + if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP) syscall_exit_to_user_mode_work(regs); return; }
--
2.34.1