FAILED: patch "[PATCH] arm64: ptrace: Consistently use pseudo-singlestep exceptions" failed to apply to 4.4-stable tree
Subsystems (3)
[email protected]
maintainerThe patch below does not apply to the 4.4-stable tree.
If someone wants it applied there, or to any other stable or longterm tree, then please email the backport, including the original git commit id to <[email protected]>.
thanks,
greg k-h
------------------ original commit in Linus's tree ------------------
From ac2081cdc4d99c57f219c1a6171526e0fa0a6fff Mon Sep 17 00:00:00 2001
From: Will Deacon <[email protected]>
Date: Thu, 2 Jul 2020 21:16:20 +0100
Subject: [PATCH] arm64: ptrace: Consistently use pseudo-singlestep exceptions
Although the arm64 single-step state machine can be fast-forwarded in cases where we wish to generate a SIGTRAP without actually executing an instruction, this has two major limitations outside of simply skipping an instruction due to emulation.
1. Stepping out of a ptrace signal stop into a signal handler where SIGTRAP is blocked. Fast-forwarding the stepping state machine in this case will result in a forced SIGTRAP, with the handler reset to SIG_DFL.
2. The hardware implicitly fast-forwards the state machine when executing an SVC instruction for issuing a system call. This can interact badly with subsequent ptrace stops signalled during the execution of the system call (e.g. SYSCALL_EXIT or seccomp traps), as they may corrupt the stepping state by updating the PSTATE for the tracee.
Resolve both of these issues by injecting a pseudo-singlestep exception on entry to a signal handler and also on return to userspace following a system call.
arch/arm64/include/asm/thread_info.h +1 -0
@@ -93,6 +93,7 @@ void arch_release_task_struct(struct task_struct *tsk);#define _TIF_SYSCALL_EMU (1 << TIF_SYSCALL_EMU)#define _TIF_UPROBE (1 << TIF_UPROBE)#define _TIF_FSCHECK (1 << TIF_FSCHECK) +#define _TIF_SINGLESTEP (1 << TIF_SINGLESTEP)#define _TIF_32BIT (1 << TIF_32BIT)#define _TIF_SVE (1 << TIF_SVE)
arch/arm64/kernel/ptrace.c +19 -6
@@ -1818,12 +1818,23 @@ static void tracehook_report_syscall(struct pt_regs *regs, saved_reg = regs->regs[regno]; regs->regs[regno] = dir; -if (dir ==PTRACE_SYSCALL_EXIT ) +if (dir ==PTRACE_SYSCALL_ENTER ) { +if (tracehook_report_syscall_entry (regs)) +forget_syscall (regs); + regs->regs[regno] = saved_reg; + }else if (!test_thread_flag (TIF_SINGLESTEP )) {tracehook_report_syscall_exit (regs,0 ); -else if (tracehook_report_syscall_entry (regs)) -forget_syscall (regs); + regs->regs[regno] = saved_reg; + }else { + regs->regs[regno] = saved_reg; - regs->regs[regno] = saved_reg; +/* +* Signal a pseudo-step exception since we are stepping but +* tracer modifications to the registers may have rewound the +* state machine. +*/ +tracehook_report_syscall_exit (regs,1 ); + } }int syscall_trace_enter (struct pt_regs *regs)
@@ -1851,12 +1862,14 @@ int syscall_trace_enter(struct pt_regs *regs)void syscall_trace_exit (struct pt_regs *regs) { +unsigned long flags =READ_ONCE (current_thread_info ()->flags); +audit_syscall_exit (regs); -if (test_thread_flag (TIF_SYSCALL_TRACEPOINT )) +if (flags & _TIF_SYSCALL_TRACEPOINT)trace_sys_exit (regs,regs_return_value (regs)); -if (test_thread_flag (TIF_SYSCALL_TRACE )) +if (flags & (_TIF_SYSCALL_TRACE | _TIF_SINGLESTEP))tracehook_report_syscall (regs,PTRACE_SYSCALL_EXIT );rseq_syscall (regs);
arch/arm64/kernel/signal.c +2 -9
@@ -800,7 +800,6 @@ static void setup_restart_syscall(struct pt_regs *regs)*/ static void handle_signal (struct ksignal *ksig,struct pt_regs *regs) { -struct task_struct *tsk = current;sigset_t *oldset =sigmask_to_save ();int usig = ksig->sig;int ret;
@@ -824,14 +823,8 @@ static void handle_signal(struct ksignal *ksig, struct pt_regs *regs)*/ ret |= !valid_user_regs (®s->user_regs, current); -/* -* Fast forward the stepping logic so we step into the signal -* handler. -*/ -if (!ret) -user_fastforward_single_step (tsk); - -signal_setup_done (ret, ksig,0 ); +/* Step into the signal handler if we are stepping */ +signal_setup_done (ret, ksig,test_thread_flag (TIF_SINGLESTEP )); }/*
arch/arm64/kernel/syscall.c +1 -1
@@ -139,7 +139,7 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,if (!has_syscall_work (flags) && !IS_ENABLED (CONFIG_DEBUG_RSEQ )) {local_daif_mask (); flags =current_thread_info ()->flags; -if (!has_syscall_work (flags)) { +if (!has_syscall_work (flags) && !(flags & _TIF_SINGLESTEP)) {/* * We're off to userspace, where interrupts are * always enabled after we restore the flags from