Re: [PATCH] ARM: ptrace: keep ARM_ORIG_r0 consistent with ARM_r0 after ptrace writes
Jinjie Ruan <[email protected]>
| Newsgroups | gmane.linux.kernel,gmane.linux.ports.arm.kernel |
|---|---|
| Message-ID | <[email protected]> |
在 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. >> >