From 35c3dcb1ac2c7e347b38f3b0bccb0a2d1dbda25c Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 1 Dec 2025 20:06:32 +0800 Subject: [PATCH 1/5] syscall.h: Remove unused SYSCALL_MAX_ARGS The "SYSCALL_MAX_ARGS" appears to have been unused since commit 32d92586629a ("syscalls: Remove start and number from syscall_set_arguments() args"), so remove it. Fixes: 32d92586629a ("syscalls: Remove start and number from syscall_set_arguments() args") Signed-off-by: Jinjie Ruan Reviewed-by: Russell King (Oracle) Signed-off-by: Will Deacon --- arch/arm/include/asm/syscall.h | 2 -- arch/arm64/include/asm/syscall.h | 2 -- arch/xtensa/include/asm/syscall.h | 1 - 3 files changed, 5 deletions(-) diff --git a/arch/arm/include/asm/syscall.h b/arch/arm/include/asm/syscall.h index 18b102a30741..574bbcc55382 100644 --- a/arch/arm/include/asm/syscall.h +++ b/arch/arm/include/asm/syscall.h @@ -92,8 +92,6 @@ static inline void syscall_set_nr(struct task_struct *task, (nr & __NR_SYSCALL_MASK); } -#define SYSCALL_MAX_ARGS 7 - static inline void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, unsigned long *args) diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h index 712daa90e643..f3853047c28e 100644 --- a/arch/arm64/include/asm/syscall.h +++ b/arch/arm64/include/asm/syscall.h @@ -77,8 +77,6 @@ static inline void syscall_set_nr(struct task_struct *task, } } -#define SYSCALL_MAX_ARGS 6 - static inline void syscall_get_arguments(struct task_struct *task, struct pt_regs *regs, unsigned long *args) diff --git a/arch/xtensa/include/asm/syscall.h b/arch/xtensa/include/asm/syscall.h index 7db3b489c8ad..bab7cdd96cbe 100644 --- a/arch/xtensa/include/asm/syscall.h +++ b/arch/xtensa/include/asm/syscall.h @@ -61,7 +61,6 @@ static inline void syscall_set_return_value(struct task_struct *task, regs->areg[2] = (long) error ? error : val; } -#define SYSCALL_MAX_ARGS 6 #define XTENSA_SYSCALL_ARGUMENT_REGS {6, 3, 4, 5, 8, 9} static inline void syscall_get_arguments(struct task_struct *task, From 98cc091262effcdbdeb1c2ee0a25981aefd2274c Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 1 Dec 2025 20:06:33 +0800 Subject: [PATCH 2/5] arm64: Avoid memcpy() for syscall_get_arguments() MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Do not use memcpy() to extract syscall arguments from struct pt_regs but rather just perform direct assignments. Update syscall_set_arguments() too to keep syscall_get_arguments() and syscall_set_arguments() in sync. With Generic Entry patch[1] and turn on audit, the performance benchmarks from perf bench basic syscall on kunpeng920 gives roughly a 1% performance uplift. | Metric | W/O this patch | With this patch | Change | | ---------- | -------------- | --------------- | --------- | | Total time | 2.241 [sec] | 2.211 [sec] | ↓1.36% | | usecs/op | 0.224157 | 0.221146 | ↓1.36% | | ops/sec | 4,461,157 | 4,501,409 | ↑0.9% | Disassembly shows that using direct assignment causes syscall_set_arguments() to be inlined and cuts the instruction count by five or six compared to memcpy(). Because __audit_syscall_entry() only uses four syscall arguments, the compiler has also elided the copy of regs->regs[4] and regs->regs[5]. Before: : aa0103e2 mov x2, x1 91002003 add x3, x0, #0x8 f9408804 ldr x4, [x0, #272] f8008444 str x4, [x2], #8 a9409404 ldp x4, x5, [x0, #8] a9009424 stp x4, x5, [x1, #8] a9418400 ldp x0, x1, [x0, #24] a9010440 stp x0, x1, [x2, #16] f9401060 ldr x0, [x3, #32] f9001040 str x0, [x2, #32] d65f03c0 ret d503201f nop After: a9408e82 ldp x2, x3, [x20, #8] 2a1603e0 mov w0, w22 f9400e84 ldr x4, [x20, #24] f9408a81 ldr x1, [x20, #272] 9401c4ba bl ffff800080215ca8 <__audit_syscall_entry> This also aligns the implementation with x86 and RISC-V. [1]: https://lore.kernel.org/all/20251126071446.3234218-1-ruanjinjie@huawei.com/ Signed-off-by: Jinjie Ruan Signed-off-by: Will Deacon --- arch/arm64/include/asm/syscall.h | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) diff --git a/arch/arm64/include/asm/syscall.h b/arch/arm64/include/asm/syscall.h index f3853047c28e..5e4c7fc44f73 100644 --- a/arch/arm64/include/asm/syscall.h +++ b/arch/arm64/include/asm/syscall.h @@ -82,16 +82,24 @@ static inline void syscall_get_arguments(struct task_struct *task, unsigned long *args) { args[0] = regs->orig_x0; - args++; - - memcpy(args, ®s->regs[1], 5 * sizeof(args[0])); + args[1] = regs->regs[1]; + args[2] = regs->regs[2]; + args[3] = regs->regs[3]; + args[4] = regs->regs[4]; + args[5] = regs->regs[5]; } static inline void syscall_set_arguments(struct task_struct *task, struct pt_regs *regs, const unsigned long *args) { - memcpy(®s->regs[0], args, 6 * sizeof(args[0])); + regs->regs[0] = args[0]; + regs->regs[1] = args[1]; + regs->regs[2] = args[2]; + regs->regs[3] = args[3]; + regs->regs[4] = args[4]; + regs->regs[5] = args[5]; + /* * Also copy the first argument into orig_x0 * so that syscall_get_arguments() would return it From e7e7afdc7c141227f2ce29aca85969e050da1ab9 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 22 Dec 2025 19:47:22 +0800 Subject: [PATCH 3/5] arm64: Remove unused _TIF_WORK_MASK Since commit b3cf07851b6c ("arm64: entry: Switch to generic IRQ entry"), _TIF_WORK_MASK is never used, so remove it. Reviewed-by: Anshuman Khandual Reviewed-by: Kevin Brodsky Signed-off-by: Jinjie Ruan Signed-off-by: Will Deacon --- arch/arm64/include/asm/thread_info.h | 6 ------ 1 file changed, 6 deletions(-) diff --git a/arch/arm64/include/asm/thread_info.h b/arch/arm64/include/asm/thread_info.h index a803b887b0b4..24fcd6adaa33 100644 --- a/arch/arm64/include/asm/thread_info.h +++ b/arch/arm64/include/asm/thread_info.h @@ -106,12 +106,6 @@ void arch_setup_new_exec(void); #define _TIF_NOTIFY_SIGNAL (1 << TIF_NOTIFY_SIGNAL) #define _TIF_TSC_SIGSEGV (1 << TIF_TSC_SIGSEGV) -#define _TIF_WORK_MASK (_TIF_NEED_RESCHED | _TIF_NEED_RESCHED_LAZY | \ - _TIF_NOTIFY_RESUME | _TIF_FOREIGN_FPSTATE | \ - _TIF_UPROBE | _TIF_MTE_ASYNC_FAULT | \ - _TIF_NOTIFY_SIGNAL | _TIF_SIGPENDING | \ - _TIF_PATCH_PENDING) - #define _TIF_SYSCALL_WORK (_TIF_SYSCALL_TRACE | _TIF_SYSCALL_AUDIT | \ _TIF_SYSCALL_TRACEPOINT | _TIF_SECCOMP | \ _TIF_SYSCALL_EMU) From 741a9000173a036526eb2374e1ba34c466754f1c Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 22 Dec 2025 19:47:23 +0800 Subject: [PATCH 4/5] arm64/ptrace: Split report_syscall() The generic syscall entry code has the form: | syscall_trace_enter() | { | ptrace_report_syscall_entry() | } | | syscall_exit_work() | { | ptrace_report_syscall_exit() | } In preparation for moving arm64 over to the generic entry code, split report_syscall() to two separate enter and exit functions to align the structure of the arm64 code with syscall_trace_enter() and syscall_exit_work() from the generic entry code. No functional changes. Reviewed-by: Anshuman Khandual Reviewed-by: Kevin Brodsky Suggested-by: Mark Rutland Signed-off-by: Jinjie Ruan Signed-off-by: Will Deacon --- arch/arm64/kernel/ptrace.c | 41 +++++++++++++++++++++++++++----------- 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index b9bdd83fbbca..03fe2f8a4d54 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -2343,9 +2343,10 @@ enum ptrace_syscall_dir { PTRACE_SYSCALL_EXIT, }; -static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir) +static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs, + enum ptrace_syscall_dir dir, + int *regno) { - int regno; unsigned long saved_reg; /* @@ -2364,15 +2365,31 @@ static void report_syscall(struct pt_regs *regs, enum ptrace_syscall_dir dir) * - Syscall stops behave differently to seccomp and pseudo-step traps * (the latter do not nobble any registers). */ - regno = (is_compat_task() ? 12 : 7); - saved_reg = regs->regs[regno]; - regs->regs[regno] = dir; + *regno = (is_compat_task() ? 12 : 7); + saved_reg = regs->regs[*regno]; + regs->regs[*regno] = dir; - if (dir == PTRACE_SYSCALL_ENTER) { - if (ptrace_report_syscall_entry(regs)) - forget_syscall(regs); - regs->regs[regno] = saved_reg; - } else if (!test_thread_flag(TIF_SINGLESTEP)) { + return saved_reg; +} + +static void report_syscall_entry(struct pt_regs *regs) +{ + unsigned long saved_reg; + int regno; + + saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, ®no); + if (ptrace_report_syscall_entry(regs)) + forget_syscall(regs); + regs->regs[regno] = saved_reg; +} + +static void report_syscall_exit(struct pt_regs *regs) +{ + unsigned long saved_reg; + int regno; + + saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_EXIT, ®no); + if (!test_thread_flag(TIF_SINGLESTEP)) { ptrace_report_syscall_exit(regs, 0); regs->regs[regno] = saved_reg; } else { @@ -2392,7 +2409,7 @@ int syscall_trace_enter(struct pt_regs *regs) unsigned long flags = read_thread_flags(); if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) { - report_syscall(regs, PTRACE_SYSCALL_ENTER); + report_syscall_entry(regs); if (flags & _TIF_SYSCALL_EMU) return NO_SYSCALL; } @@ -2420,7 +2437,7 @@ void syscall_trace_exit(struct pt_regs *regs) trace_sys_exit(regs, syscall_get_return_value(current, regs)); if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP)) - report_syscall(regs, PTRACE_SYSCALL_EXIT); + report_syscall_exit(regs); rseq_syscall(regs); } From a3386301667ed03ba9baeb6a2629e726714cc9a7 Mon Sep 17 00:00:00 2001 From: Jinjie Ruan Date: Mon, 22 Dec 2025 19:47:24 +0800 Subject: [PATCH 5/5] arm64/ptrace: Return early for ptrace_report_syscall_entry() error The generic entry abort the syscall_trace_enter() sequence if ptrace_report_syscall_entry() errors out, but arm64 not. When ptrace requests interception, it should prevent all subsequent system-call processing, including audit and seccomp. In preparation for moving arm64 over to the generic entry code, return early if ptrace_report_syscall_entry() encounters an error. Reviewed-by: Kevin Brodsky Signed-off-by: Jinjie Ruan Signed-off-by: Will Deacon --- arch/arm64/kernel/ptrace.c | 14 +++++++++----- 1 file changed, 9 insertions(+), 5 deletions(-) diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 03fe2f8a4d54..f333791ffba6 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -2372,15 +2372,18 @@ static __always_inline unsigned long ptrace_save_reg(struct pt_regs *regs, return saved_reg; } -static void report_syscall_entry(struct pt_regs *regs) +static int report_syscall_entry(struct pt_regs *regs) { unsigned long saved_reg; - int regno; + int regno, ret; saved_reg = ptrace_save_reg(regs, PTRACE_SYSCALL_ENTER, ®no); - if (ptrace_report_syscall_entry(regs)) + ret = ptrace_report_syscall_entry(regs); + if (ret) forget_syscall(regs); regs->regs[regno] = saved_reg; + + return ret; } static void report_syscall_exit(struct pt_regs *regs) @@ -2407,10 +2410,11 @@ static void report_syscall_exit(struct pt_regs *regs) int syscall_trace_enter(struct pt_regs *regs) { unsigned long flags = read_thread_flags(); + int ret; if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) { - report_syscall_entry(regs); - if (flags & _TIF_SYSCALL_EMU) + ret = report_syscall_entry(regs); + if (ret || (flags & _TIF_SYSCALL_EMU)) return NO_SYSCALL; }