From: sashiko-bot@kernel.org
To: "Jinjie Ruan" <ruanjinjie@huawei.com>, bpf@vger.kernel.org
Subject: Re: [PATCH v2 1/2] ARM: ptrace: Fix seccomp seeing stale syscall arguments
Date: Fri, 30 Oct 2026 06:53:04 +0000 [thread overview]
Message-ID: <sashiko-outbox-190616@kernel.org> (raw)
In-Reply-To: <20261030063630.1218302-2-ruanjinjie@huawei.com>
Thank you for your contribution! Sashiko AI review found 3 potential issue(s) to consider:
- [High] ARM: ptrace: missing syscall-entry match in stopped_in_syscall_entry()
- [High] ARM: ptrace: ARM_ORIG_r0 desync in put_user_reg() via PTRACE_POKEUSR
- [High] ARM: ptrace: ARM_ORIG_r0 clobbered in update_syscall_orig_r0_after_ptrace()
--
commit 83d7d1ba6dcc0fb6cba778b5030dfb3da61a6531
Author: Jinjie Ruan <ruanjinjie@huawei.com>
ARM: ptrace: Fix seccomp seeing stale syscall arguments
This commit synchronizes ARM_ORIG_r0 with ARM_r0 after ptrace register writes
when the tracee is stopped in syscall entry or SECCOMP_RET_TRACE, and updates
audit_syscall_entry() to read ARM_ORIG_r0.
Link: https://lore.kernel.org/all/al98jdcleu-6tMDL@willie-the-truck/
Link: https://lkml.org/lkml/2020/9/11/1282
> diff --git a/arch/arm/kernel/ptrace.c b/arch/arm/kernel/ptrace.c
> index ed7a2a87a6707..6ec81e5a205e7 100644
> --- a/arch/arm/kernel/ptrace.c
> +++ b/arch/arm/kernel/ptrace.c
> @@ -163,6 +163,42 @@ static inline long get_user_reg(struct task_struct *task, int offset)
> return task_pt_regs(task)->uregs[offset];
> }
>
> +/*
> + * Is @target stopped after entering a syscall, but before it has been
> + * dispatched? This is the same classification that
> + * ptrace_get_syscall_info_op() performs for PTRACE_GET_SYSCALL_INFO.
> + */
> +static bool stopped_in_syscall_entry(struct task_struct *target)
> +{
> + struct kernel_siginfo *info = target->last_siginfo;
> +
> + if (!info)
> + return false;
> +
> + if (info->si_code == (SIGTRAP | 0x80))
> + return target->ptrace_message == PTRACE_EVENTMSG_SYSCALL_ENTRY;
[Severity: High]
What happens when a tracer stops a tracee at syscall entry via PTRACE_SYSCALL
without enabling PTRACE_O_TRACESYSGOOD?
In include/linux/ptrace.h:ptrace_report_syscall(), bit 0x80 is only set in
si_code when PT_TRACESYSGOOD is enabled:
signr = ptrace_notify(SIGTRAP | ((ptrace & PT_TRACESYSGOOD) ? 0x80 : 0),
message);
When PTRACE_O_TRACESYSGOOD is not set, info->si_code is plain SIGTRAP while
target->ptrace_message is PTRACE_EVENTMSG_SYSCALL_ENTRY. Checking for
info->si_code == (SIGTRAP | 0x80) causes stopped_in_syscall_entry() to return
false in that case, leaving regs->ARM_ORIG_r0 unsynchronized when the tracer
updates ARM_r0.
When the tracee resumes in syscall_trace_enter(), seccomp_permit_syscall(),
trace_sys_enter(), and audit_syscall_entry() (which this patch switches from
regs->ARM_r0 to regs->ARM_ORIG_r0) will all observe the stale
regs->ARM_ORIG_r0 while invoke_syscall runs with the modified regs->ARM_r0.
Should this check (info->si_code & ~0x80) == SIGTRAP, matching arm64's
stopped_in_syscall_entry()?
> +
> + return info->si_code == (SIGTRAP | (PTRACE_EVENT_SECCOMP << 8));
> +}
> +
> +static void update_syscall_orig_r0_after_ptrace(struct task_struct *target)
> +{
> + struct pt_regs *regs = task_pt_regs(target);
> +
> + /*
> + * ARM_r0 holds the first syscall argument only before the syscall is
> + * dispatched; seccomp, the syscall tracepoints and the syscall restart
> + * code all read that argument from ARM_ORIG_r0 instead. At a syscall
> + * exit stop ARM_r0 holds the return value and must not be copied, and
> + * for other exceptions ARM_ORIG_r0 is set to ~0 and carries no
> + * meaning.
> + */
> + if (!stopped_in_syscall_entry(target))
> + return;
> +
> + regs->ARM_ORIG_r0 = regs->ARM_r0;
> +}
[Severity: High]
Can update_syscall_orig_r0_after_ptrace() clobber the saved first argument
when a tracer skips a syscall?
On 32-bit ARM, skipping a syscall at a syscall-entry or PTRACE_EVENT_SECCOMP
stop sets task_thread_info(target)->abi_syscall to -1 via PTRACE_SET_SYSCALL
in arch_ptrace() or via syscall_set_nr():
if (nr == -1) {
task_thread_info(task)->abi_syscall = -1;
syscall_set_return_value(task, regs, -ENOSYS, 0);
return;
}
Once the syscall number is -1, regs->ARM_r0 holds the return value (such as
-ENOSYS or a tracer-supplied return value), while regs->ARM_ORIG_r0 preserves
the original first argument. Because update_syscall_orig_r0_after_ptrace()
does not check whether syscall_get_nr(target, regs) == -1 (unlike arm64,
which returns early when regs->syscallno == NO_SYSCALL), any subsequent
GPR write via put_user_reg() or gpr_set() overwrites regs->ARM_ORIG_r0 with
the return value.
That corrupts the first argument reported by syscall_get_arguments() (used by
PTRACE_GET_SYSCALL_INFO, trace_sys_enter(), and seccomp) and
audit_syscall_entry(), breaks syscall_rollback() if a later seccomp filter
triggers SECCOMP_RET_TRAP or SECCOMP_RET_KILL_PROCESS, and causes do_signal()
on the __sys_trace_return_nosave -> ret_slow_syscall path to copy an injected
-ERESTART* return value into ARM_r0 as the restarted syscall's first argument.
Conversely, in arch_ptrace(), PTRACE_SET_SYSCALL does not call
update_syscall_orig_r0_after_ptrace(child) when changing abi_syscall from -1
to a valid syscall number, leaving ARM_ORIG_r0 and ARM_r0 out of sync if
syscall_set_nr() had previously set ARM_r0 to -ENOSYS.
Should update_syscall_orig_r0_after_ptrace() return early when
syscall_get_nr(target, regs) == -1, and should PTRACE_SET_SYSCALL call
update_syscall_orig_r0_after_ptrace(child)?
> +
> /*
> * this routine will put a word on the processes privileged stack.
> * the offset is how far from the base addr as stored in the THREAD.
> @@ -180,6 +216,8 @@ put_user_reg(struct task_struct *task, int offset, long data)
>
> if (valid_user_regs(&newregs)) {
> regs->uregs[offset] = data;
> + if (offset == 0)
> + update_syscall_orig_r0_after_ptrace(task);
> ret = 0;
> }
[Severity: High]
Could a tracer still desynchronize regs->ARM_ORIG_r0 and regs->ARM_r0 via
PTRACE_POKEUSR in put_user_reg()?
On 32-bit ARM, struct pt_regs exposes all 18 words (uregs[0..17]) to
ptrace_write_user() -> put_user_reg(), where offset 0 is ARM_r0 and offset 17
is ARM_ORIG_r0. At the same time, invoke_syscall in
arch/arm/kernel/entry-header.S dispatches the syscall by reloading r0-r6 from
regs->ARM_r0:
add r1, sp, #S_R0 + S_OFF @ pointer to regs
ldmiacc r1, {r0 - r6} @ reload r0-r6
Because put_user_reg() only calls update_syscall_orig_r0_after_ptrace(task)
when offset == 0, a tracer stopped at syscall entry or PTRACE_EVENT_SECCOMP
can poke offset 17 (ARM_ORIG_r0) directly (or modify
target->last_siginfo->si_code via PTRACE_SETSIGINFO before writing ARM_r0).
In that case, seccomp_permit_syscall(), trace_sys_enter(), and now
audit_syscall_entry() all inspect the value written to regs->ARM_ORIG_r0,
while invoke_syscall executes the syscall with regs->ARM_r0.
--
Sashiko AI review · https://sashiko.dev/#/patchset/20261030063630.1218302-1-ruanjinjie@huawei.com?part=1
next prev parent reply other threads:[~2026-10-30 6:53 UTC|newest]
Thread overview: 8+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-10-30 6:36 [PATCH v2 0/2] ARM: ptrace: Fix seccomp seeing stale syscall arguments Jinjie Ruan
2026-10-30 6:36 ` Jinjie Ruan
2026-10-30 6:36 ` [PATCH v2 1/2] " Jinjie Ruan
2026-10-30 6:36 ` Jinjie Ruan
2026-10-30 6:53 ` sashiko-bot [this message]
2026-10-30 6:36 ` [PATCH v2 2/2] selftests/seccomp: Add tests for syscall argument rewrite Jinjie Ruan
2026-10-30 6:36 ` Jinjie Ruan
2026-10-30 6:55 ` sashiko-bot
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=sashiko-outbox-190616@kernel.org \
--to=sashiko-bot@kernel.org \
--cc=bpf@vger.kernel.org \
--cc=ruanjinjie@huawei.com \
--cc=sashiko-reviews@lists.linux.dev \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.