[PATCH v21 09/15] arm64: ptrace: Only run syscall exit work when exit work flags are set
From: Jinjie Ruan
Date: Wed Nov 11 2026 - 06:49:33 EST
Make the syscall exit path match generic entry, where
syscall_exit_work() is only called when one of the SYSCALL_WORK_EXIT
bits is set:
- Add _TIF_SYSCALL_EXIT_WORK for the thread flags that need work on
syscall exit: trace, audit and tracepoint.
- Call the exit work from arm64_syscall_exit_to_user_mode_work() only
when one of those flags or _TIF_SINGLESTEP is set.
- Rename syscall_trace_exit() to arm64_syscall_exit_work(), the arm64
counterpart of syscall_exit_work().
- Move rseq_syscall() out of arm64_syscall_exit_work() into
arm64_syscall_exit_to_user_mode_work(), so it still runs on every
syscall exit and still runs before ptrace can change the PC, as in
generic entry.
Checking _TIF_SYSCALL_AUDIT instead of calling audit_syscall_exit()
unconditionally is equivalent: the flag is set together with the audit
context at fork and neither changes while the task runs a system call.
No functional changes intended.
Cc: Mark Rutland <mark.rutland@xxxxxxx>
Cc: Will Deacon <will@xxxxxxxxxx>
Cc: Catalin Marinas <catalin.marinas@xxxxxxx>
Cc: Ada Couprie Diaz <ada.coupriediaz@xxxxxxx>
Reviewed-by: Linus Walleij <linusw@xxxxxxxxxx>
Signed-off-by: Jinjie Ruan <ruanjinjie@xxxxxxxxxx>
---
arch/arm64/include/asm/syscall.h | 8 ++++++--
arch/arm64/include/asm/thread_info.h | 3 +++
arch/arm64/kernel/ptrace.c | 5 +----
3 files changed, 10 insertions(+), 6 deletions(-)
diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h
index 3e4672ab4a4f..7cc872fde019 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);
@@ -121,13 +122,16 @@ static inline int syscall_get_arch(struct task_struct *task)
}
int arm64_syscall_trace_enter(struct pt_regs *regs, unsigned long flags);
-void syscall_trace_exit(struct pt_regs *regs, unsigned long flags);
+void arm64_syscall_exit_work(struct pt_regs *regs, unsigned long flags);
static __always_inline void arm64_syscall_exit_to_user_mode_work(struct pt_regs *regs)
{
unsigned long flags = read_thread_flags();
- syscall_trace_exit(regs, flags);
+ rseq_syscall(regs);
+
+ if (unlikely(flags & _TIF_SYSCALL_EXIT_WORK) || flags & _TIF_SINGLESTEP)
+ arm64_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 6cb976c1c693..a85c72b65b82 100644
--- a/arch/arm64/include/asm/thread_info.h
+++ b/arch/arm64/include/asm/thread_info.h
@@ -108,6 +108,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 043f48ddc168..4c2bdd37d67d 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>
@@ -2507,12 +2506,10 @@ static inline bool report_single_step(unsigned long flags)
return flags & _TIF_SINGLESTEP;
}
-void syscall_trace_exit(struct pt_regs *regs, unsigned long flags)
+void arm64_syscall_exit_work(struct pt_regs *regs, unsigned long flags)
{
bool step;
- rseq_syscall(regs);
-
audit_syscall_exit(regs);
if (flags & _TIF_SYSCALL_TRACEPOINT)
--
2.34.1