[PATCH v3 2/2] powerpc/syscall: Return the preset value of skipped syscalls
From: Renzo Davoli
Date: Fri Oct 30 2026 - 04:51:55 EST
When ptrace or seccomp skip a system call, r3 (and CR0.SO for "sc")
already hold its return value, set either through
syscall_set_return_value() or directly by a tracer, e.g. with
PTRACE_POKEUSER at a PTRACE_EVENT_SECCOMP stop.
Since commit 05c033db7e9a ("entry, treewide: Make
syscall_enter_from_user_mode[_work]() indicate syscall execution"),
system_call_exception() returns syscall_get_error() for a skipped system
call. syscall_get_error() is 0 for any non-error value, so a success
value is replaced with 0: the value set by a tracer, or the val of a
SECCOMP_RET_USER_NOTIF response. Among others, the seccomp_bpf
user_notification_* and TRACE_syscall.seccomp.syscall_faked selftests
fail.
Return the error from syscall_get_error() if there is one, and the value
in r3 otherwise. The error path is unchanged, and a success value is
returned as it was before the conversion to GENERIC_ENTRY, when
system_call_exception() returned regs->gpr[3] for a skipped system call.
Fixes: 05c033db7e9a ("entry, treewide: Make syscall_enter_from_user_mode[_work]() indicate syscall execution")
Cc: stable@xxxxxxxxxxxxxxx # v7.3
Suggested-by: Mukesh Kumar Chaurasiya (IBM) <mkchauras@xxxxxxxxx>
Assisted-by: claude-opus-5-5
Signed-off-by: Renzo Davoli <renzo@xxxxxxxxxxx>
---
arch/powerpc/kernel/syscall.c | 9 ++++++++-
1 file changed, 8 insertions(+), 1 deletion(-)
diff --git a/arch/powerpc/kernel/syscall.c b/arch/powerpc/kernel/syscall.c
index f7412556a9e8..7b35b895b70c 100644
--- a/arch/powerpc/kernel/syscall.c
+++ b/arch/powerpc/kernel/syscall.c
@@ -19,7 +19,14 @@ notrace long system_call_exception(struct pt_regs *regs, unsigned long r0)
syscall_fn f;
if (unlikely(!syscall_enter_from_user_mode_randomize_stack(regs, &r0))) {
- return syscall_get_error(current, regs);
+ /*
+ * The syscall was skipped by seccomp or ptrace. r3 (and CR0.SO
+ * for "sc") already hold the return value, set either through
+ * syscall_set_return_value() or directly by the tracer. Hand
+ * it back in the form syscall_exit_prepare() expects: -errno
+ * on failure, else the value in r3.
+ */
+ return syscall_get_error(current, regs) ?: regs->gpr[3];
}
if (unlikely(r0 >= NR_syscalls)) {
--
2.55.0