[PATCH v16 11/18] arm64: ptrace: Align syscall exit work semantics with generic entry
From: Jinjie Ruan <hidden>
Date: 2026-06-29 13:07:26
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), ptrace support, the rest · Maintainers:
Catalin Marinas, Will Deacon, Oleg Nesterov, Linus Torvalds
Streamline syscall_exit_to_user_mode_work() to align arm64's syscall exit behavior with the generic entry framework. [Rationale] 1. Unconditional RSEQ Execution: Relocate rseq_syscall() from the slow-path helper to the very beginning of syscall_exit_to_user_mode_work(). This ensures that RSEQ validation executes unconditionally across all exit scenarios, preventing it from being incorrectly bypassed on fast paths when CONFIG_DEBUG_RSEQ is active. 2. Centralized Exit Work Gating: Introduce the `_TIF_SYSCALL_EXIT_WORK` mask to aggregate exit thread flags and gate the execution of syscall_exit_work(). Gating audit_syscall_exit() behind this exit-time check introduces no functional changes. The `SYSCALL_AUDIT` flag and its context are statically allocated via audit_alloc() at fork time and only freed via audit_free() at do_exit(). Since the flag remains persistent and static throughout syscall execution, checking `_TIF_SYSCALL_AUDIT` in the mask is fully equivalent to evaluating audit_context() inside audit_syscall_exit(). [Changes] - Introduce the `_TIF_SYSCALL_EXIT_WORK` mask to bundle exit-specific flags. - Relocate rseq_syscall() to run unconditionally on the outermost layer. - Gate syscall_exit_work() via the new aggregated flag check to mirror the generic entry loop behavior. 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> Signed-off-by: Jinjie Ruan <redacted> --- arch/arm64/include/asm/syscall.h | 6 +++++- arch/arm64/include/asm/thread_info.h | 3 +++ arch/arm64/kernel/ptrace.c | 3 --- 3 files changed, 8 insertions(+), 4 deletions(-)
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 72461c22bb5e..b982398f8765 100644
--- a/arch/arm64/include/asm/syscall.h
+++ b/arch/arm64/include/asm/syscall.h@@ -8,6 +8,7 @@ #include <uapi/linux/audit.h> #include <linux/compat.h> #include <linux/err.h> +#include <linux/rseq.h> typedef long (*syscall_fn_t)(const struct pt_regs *regs);
@@ -127,7 +128,10 @@ static __always_inline void syscall_exit_to_user_mode_work(struct pt_regs *regs) { unsigned long flags = read_thread_flags(); - syscall_exit_work(regs, flags); + rseq_syscall(regs); + + if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP) + syscall_exit_work(regs, flags); } #endif /* __ASM_SYSCALL_H */
diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h
index 5d7fe3e153c8..56a2c9426a32 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h@@ -112,6 +112,9 @@ void arch_setup_new_exec(void); _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ _TIF_SYSCALL_EMU) +#define _TIF_SYSCALL_EXIT_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ + _TIF_SYSCALL_TRACEPOINT) + #ifdef CONFIG_SHADOW_CALL_STACK #define INIT_SCS \ .scs_base = init_shadow_call_stack, \
diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c
index 9ebe3389451c..05ceb9f2d038 100644
--- a/arch/arm64/kernel/ptrace.c
+++ b/arch/arm64/kernel/ptrace.c@@ -28,7 +28,6 @@ #include <linux/hw_breakpoint.h> #include <linux/regset.h> #include <linux/elf.h> -#include <linux/rseq.h> #include <asm/compat.h> #include <asm/cpufeature.h>
@@ -2455,8 +2454,6 @@ int syscall_trace_enter(struct pt_regs *regs, unsigned long flags) void syscall_exit_work(struct pt_regs *regs, unsigned long flags) { - rseq_syscall(regs); - audit_syscall_exit(regs); if (flags & _TIF_SYSCALL_TRACEPOINT)
--
2.34.1