Move the rseq_syscall() check earlier in the syscall exit path to ensure it operates on the original instruction pointer (regs->pc) before any potential modification by a tracer.
[Background] When CONFIG_DEBUG_RSEQ is enabled, rseq_syscall() verifies that a system call was not executed within an rseq critical section by examining regs->pc. If a violation is detected, it triggers a SIGSEGV. [Problem] Currently, arm64 invokes rseq_syscall() after report_syscall_exit(). However, during report_syscall_exit(), a ptrace tracer can modify the task's instruction pointer via PTRACE_SETREGSET (with NT_PRSTATUS). This leads to an inconsistency where rseq may analyze a post-trace PC instead of the actual PC at the time of syscall exit. [Why this matters] The rseq check is intended to validate the execution context of the syscall itself. Analyzing a tracer-modified PC can lead to incorrect detection or missed violations. Moving the check earlier ensures rseq sees the authentic state of the task. [Alignment] This change aligns arm64 with: - Generic entry, which calls rseq_syscall() first. - arm32 implementation, which also performs the check before audit. [Impact] There is no functional change to signal delivery; SIGSEGV will still be processed in arm64_exit_to_user_mode() at the end of the exit path. Cc: Mark Rutland <[email protected]> Cc: Thomas Gleixner <[email protected]> Cc: Will Deacon <[email protected]> Cc: Catalin Marinas <[email protected]> Reviewed-by: Ada Couprie Diaz <[email protected]> Reviewed-by: Linus Walleij <[email protected]> Reviewed-by: Yeoreum Yun <[email protected]> Reviewed-by: Kevin Brodsky <[email protected]> Signed-off-by: Jinjie Ruan <[email protected]> --- arch/arm64/kernel/ptrace.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 96c03922baa5..72df4b84ec9a 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -2513,6 +2513,8 @@ void syscall_trace_exit(struct pt_regs *regs) unsigned long flags = read_thread_flags(); bool step; + rseq_syscall(regs); + audit_syscall_exit(regs); if (flags & _TIF_SYSCALL_TRACEPOINT) @@ -2521,8 +2523,6 @@ void syscall_trace_exit(struct pt_regs *regs) step = report_single_step(flags); if (step || flags & _TIF_SYSCALL_TRACE) report_syscall_exit(regs); - - rseq_syscall(regs); } /* -- 2.34.1

