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 <[email protected]> Cc: Will Deacon <[email protected]> Cc: Catalin Marinas <[email protected]> Cc: Ada Couprie Diaz <[email protected]> Signed-off-by: Jinjie Ruan <[email protected]> --- 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
