diff --git a/arch/arm64/kernel/ptrace.c b/arch/arm64/kernel/ptrace.c index 4d08598e2891..390c9b2bd966 100644 --- a/arch/arm64/kernel/ptrace.c +++ b/arch/arm64/kernel/ptrace.c @@ -2408,6 +2408,21 @@ static void report_syscall_exit(struct pt_regs *regs) } } +static void update_syscall_orig_x0_after_ptrace(struct pt_regs *regs) +{ + /* + * Keep orig_x0 authoritative so that seccomp (via + * syscall_get_arguments()), audit and the restart path all see the same + * first argument the syscall is dispatched with, even if it has been + * updated by a tracer. Skip this for NO_SYSCALL (set either by the user + * or the tracer), as regs[0] holds the return value (see the comment in + * el0_svc_common()) and can be unwound using syscall_rollback(). + * For compat tasks, orig_r0 is provided directly through GPR index 17. + */ + if (!is_compat_task() && regs->syscallno != NO_SYSCALL) + regs->orig_x0 = regs->regs[0]; +} + int syscall_trace_enter(struct pt_regs *regs) { unsigned long flags = read_thread_flags(); @@ -2417,12 +2432,26 @@ int syscall_trace_enter(struct pt_regs *regs) ret = report_syscall_entry(regs); if (ret || (flags & _TIF_SYSCALL_EMU)) return NO_SYSCALL; + + /* + * Ensure ptrace changes to x0 during a regular + * syscall-enter-stop (PTRACE_SYSCALL) are visible to + * subsequent seccomp checks, tracepoints and audit. + */ + update_syscall_orig_x0_after_ptrace(regs); } /* Do the secure computing after ptrace; failures should be fast. */ if (secure_computing() == -1) return NO_SYSCALL; + /* + * Ensure tracer changes to x0 during seccomp ptrace exit + * processing (SECCOMP_RET_TRACE) are visible to tracepoints and + * audit. + */ + update_syscall_orig_x0_after_ptrace(regs); + if (test_thread_flag(TIF_SYSCALL_TRACEPOINT)) trace_sys_enter(regs, regs->syscallno);