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: 5+ 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 ` [PATCH v2 1/2] " 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: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 a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox