[PATCH] ARM: ptrace: keep ARM_ORIG_r0 consistent with ARM_r0 after ptrace writes

Jinjie Ruan ruanjinjie at huawei.com
Thu Aug 6 19:14:10 PDT 2026



在 2026/7/27 17:38, Jinjie Ruan 写道:
> 
> 
> 在 2026/7/25 17:44, Russell King 写道:
>> On Sat, Jul 25, 2026 at 05:14:52PM +0800, Jinjie Ruan wrote:
>>> When ptrace modifies r0 during a syscall-entry stop via PTRACE_SETREGS or
>>> PTRACE_POKEUSR, ARM_ORIG_r0 is not updated.  This causes seccomp filters
>>> and tracepoints to read stale arguments, which disagree with the actual
>>> value dispatched by the kernel.  This is particularly critical for the
>>> SECCOMP_RET_TRACE re-evaluation path.
>>>
>>> Fix it by synchronizing ARM_ORIG_r0 after every arch-level ptrace register
>>> write.  The update safely skips syscall-exit stops (where r0 holds the
>>> return value) and NO_SYSCALL states to avoid corrupting non-syscall
>>> contexts. And use ARM_ORIG_r0 in audit_syscall_entry to fix data
>>> inconsistency with seccomp/tracepoints
>>
>> ARM_ORIG_r0 is intentionally not always the same as ARM_r0, just as
> 
> Hi Russell,
> 
> +Cc Kees.
> 
> In my view, the fundamental issue here is not that orig_r0 must be
> consistent with r0, or that orig_ax must be consistent with eax, but
> rather that the parameters or system call numbers used by seccomp,
> audit, and tracepoint during system call execution are consistent
> (reflecting modifications made by ptrace).
> 
> After checking the x86 implementation based on your suggestions, I still
> think there is a slight issue with the arm32 implementation. In my
> rudimentary understanding, the differences are as follows:
> 
> On x86, orig_ax is used uniformly everywhere on syscall entry path as
> below, therefore, I think the code related to x86 32-bit is not problematic:
> 
> do_int80_emulation()
>     -> regs->orig_ax = regs->ax & GENMASK(31, 0) // backup syscall
> number to orig_ax
>     -> syscall_32_enter()
>         -> regs->orig_ax
>     -> nr = syscall_enter_from_user_mode_work() // return orig_ax which
> may have been modified by ptrace
>         -> __secure_computing()
>            -> syscall_get_nr() -> regs->orig_ax
>         -> trace_syscall_enter()
>            -> syscall_get_nr() -> regs->orig_ax
>         -> syscall_enter_audit()
>            -> syscall_get_nr() -> regs->orig_ax
>     -> do_syscall_32_irqs_on() // Use orig_ax as the system call number
> to execute the system call. This is consistent with seccomp, audit, and
> tracepoint.
> 
> But on arm32, the usage of orig_r0 and r0 is not consistent at the
> system call entry point.
> 
> -> str r0, [sp, #S_OLD_R0] // backup r0 to ARM_ORIG_r0.
> __sys_trace
>    -> syscall_trace_enter()
>       -> secure_computing()
>          -> syscall_get_arguments() -> regs->ARM_ORIG_r0
>       -> trace_sys_enter()
>          -> syscall_get_arguments() -> regs->ARM_ORIG_r0
>       -> audit_syscall_entry()
>          -> regs->ARM_r0
>          ^^^^^^^^^^^^^^^
>    -> use r0 to invoke_syscall()
>          ^^^^
> 
> Based on a fix patch by Kees six years ago, I understand that system
> call parameters are similar to system call numbers. If ptrace or seccomp
> modifies the system call parameters, then at that time, the tracing and
> auditing mechanisms also need to be able to see this change.
> 
> I understand that the semantics of seccomp and trace/audit are intended
> to reflect the latest relevant data of system calls that are "actually
> executed".
> 
> Link: https://lkml.org/lkml/2020/9/11/1282

Hi all,

Is there any new thoughts or opinions? Any feedback or suggestions would
be greatly appreciated.

Thanks,
Jinjie Ruan

> 
>> orig_eax is not always the same as eax in x86. These exist to allow
>> syscall restart as ARM_r0 / eax will be overwritten when a syscall
>> returns. I don't see arch/x86/kernel/ptrace.c::putreg32() needing
>> this kind of fixup, so why does ARM?
>>
>> ARM_ORIG_r0 is set to the value of ARM_r0 when a syscall is entered,
> 
> Yes, that's true.
> 
>> otherwise it is set to ~0 as for other exception cases, the value is
>> meaningless (there is no syscall restart in that path.)
>>
>> If one changes both ARM_ORIG_r0 and ARM_r0 during the syscall exit
>> path to e.g. -ERESTARTSYS and then raises a signal against the user
>> program, then is it not possible that do_signal() to then see that
>> case, and as regs->ARM_ORIG_r0 would now also contain -ERESTARTSYS,
>> call the syscall with the first argument set to -ERESTARTSYS rather
>> than the user's actual value?
> 
> We should not modify orig r0 on the system call exit path ; instead, we
> should modify r0 to change the return value.
> 
> Best regards,
> Jinjie
> 
>>
>> Userspace has full access to both ARM_r0 and ARM_ORIG_r0, and can
>> decide what it wants to do in the same way that userspace has
>> access to eax and orig_eax on x86.
>>
>> Please check how this is handled on x86.
>>
> 




More information about the linux-arm-kernel mailing list