Skip to contentSkip to conversation

arm64: Fix single-step handling and syscall tracing

PATCH In review Will Deacon 4 participants 16 messages Jul 10, 2020 – Jul 16, 2020

Subsystems (3)
lore
Share & tools
lore

Will Deacon

author maintainer
#0 lore raw

v3 cover arm64: Fix single-step handling and syscall tracing

Hi folks,

This is version three of the patches I previous posted here:

v1: https://lore.kernel.org/r/[email protected]
v2: https://lore.kernel.org/r/[email protected]

This version includes some changes I've been hacking on in relation to syscall entry/exit, as it seemed worth lumping all this together. I've also reordered the series to put the fixes at the start.

Luis -- did you manage to test v2? I'd quite like to queue some of this soon. If you don't have time, how can I run the GDB testsuite myself? I tried doing it a _long_ time ago but I remember there being a lot of failures and flakey tests, so it wasn't very helpful. I have arm64 hardware running Debian so it's just a question of which buttons to press :)

Cheers,

Will

Cc Mark Rutland <[email protected]>
Cc Luis Machado <[email protected]>
Cc Keno Fischer <[email protected]>
Cc Kees Cook <[email protected]>

--->8

Will Deacon (7):
arm64: ptrace: Consistently use pseudo-singlestep exceptions
arm64: ptrace: Override SPSR.SS when single-stepping is enabled
arm64: compat: Ensure upper 32 bits of x0 are zero on syscall return
arm64: ptrace: Add a comment describing our syscall entry/exit trap
ABI
arm64: syscall: Expand the comment about ptrace and syscall(-1)
arm64: ptrace: Use NO_SYSCALL instead of -1 in syscall_trace_enter()
arm64: Use test_tsk_thread_flag() for checking TIF_SINGLESTEP

 arch/arm64/include/asm/debug-monitors.h |  2 +
 arch/arm64/include/asm/syscall.h        | 12 +++++-
 arch/arm64/include/asm/thread_info.h    |  1 +
 arch/arm64/kernel/debug-monitors.c      | 24 +++++++++---
 arch/arm64/kernel/ptrace.c              | 49 +++++++++++++++++++------
 arch/arm64/kernel/signal.c              | 11 +-----
 arch/arm64/kernel/syscall.c             | 21 ++++++++++-
 7 files changed, 90 insertions(+), 30 deletions(-)
Signature · 7 lines
2.27.0.383.g050319c2ae-goog


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
author maintainer
#1 lore raw

PATCH v3 1/7 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 +
 arch/arm64/kernel/ptrace.c           | 25 +++++++++++++++++++------
 arch/arm64/kernel/signal.c           | 11 ++---------
 arch/arm64/kernel/syscall.c          |  2 +-
 4 files changed, 23 insertions(+), 16 deletions(-)
arch/arm64/include/asm/thread_info.h +1 -0
index 6ea8b6a26ae9..5e784e16ee89 100644
@@ -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
index 68b7f34a08f5..057d4aa1af4d 100644
@@ -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
index 801d56cdf701..3b4f31f35e45 100644
@@ -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(&regs->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
index 5f5b868292f5..7c14466a12af 100644
@@ -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
Signature · 1 line
2.27.0.383.g050319c2ae-goog
maintainer
#2 lore raw

Re: [PATCH v3 1/7] arm64: ptrace: Consistently use pseudo-singlestep exceptions

Hi

[This is an automated email]

This commit has been processed because it contains a -stable tag. The stable tag indicates that it's relevant for the following trees: all

The bot has tested the following trees: v5.7.8, v5.4.51, v4.19.132, v4.14.188, v4.9.230, v4.4.230.

v5.7.8: Build OK!
v5.4.51: Build OK!
v4.19.132: Build OK!
v4.14.188: Failed to apply! Possible dependencies:
0013aceb30748 ("xtensa: clean up fixups in assembly code")
1af1e8a39dc0f ("xtensa: move fixmap and kmap just above the KSEG") 2a61f4747eeaa ("stack-protector: test compiler capability in Kconfig and drop AUTO mode") 2b8383927525d ("Makefile: move stack-protector compiler breakage test earlier") 2bc2f688fdf88 ("Makefile: move stack-protector availability out of Kconfig") 409d5db49867c ("arm64: rseq: Implement backend rseq calls and select HAVE_RSEQ") 40d1a07b333ef ("xtensa: enable stack protector")
44c6dc940b190 ("Makefile: introduce CONFIG_CC_STACKPROTECTOR_AUTO") 5cf97ebd8b40e ("xtensa: clean up functions in assembly code")
8d66772e869e7 ("arm64: Mask all exceptions during kernel_exit")
9800b9dc13cdf ("arm: Add restartable sequences support")
a92d4d1454ab8 ("arm64: entry.S: move SError handling into a C function for future expansion") c2edb35ae342f ("xtensa: extract init_kio")
c633544a61541 ("xtensa: add support for KASAN")
d148eac0e70f0 ("Kbuild: rename HAVE_CC_STACKPROTECTOR config variable") f37099b6992a0 ("arm64: convert syscall trace logic to C")
f4431396be5b2 ("xtensa: consolidate kernel stack size related definitions")

v4.9.230: Failed to apply! Possible dependencies:

    096683724cb2e ("arm64: unwind: avoid percpu indirection for irq stack")
    12964443e8d19 ("arm64: add on_accessible_stack()")
    17c2895860092 ("arm64: Abstract syscallno manipulation")
    34be98f4944f9 ("arm64: kernel: remove {THREAD,IRQ_STACK}_START_SP")
    35d0e6fb4d219 ("arm64: syscallno is secretly an int, make it official")
    8018ba4edfd3a ("arm64: move SEGMENT_ALIGN to <asm/memory.h>")
    872d8327ce898 ("arm64: add VMAP_STACK overflow detection")
    9842ceae9fa8d ("arm64: Add uprobe support")
    a92d4d1454ab8 ("arm64: entry.S: move SError handling into a C function for future expansion")
    a9ea0017ebe88 ("arm64: factor out current_stack_pointer")
    c02433dd6de32 ("arm64: split thread_info from task stack")
    c7365330753c5 ("arm64: unwind: disregard frame.sp when validating frame pointer")
    cf7de27ab3517 ("arm64/syscalls: Check address limit on user-mode return")
    dbc9344a68e50 ("arm64: clean up THREAD_* definitions")
    f37099b6992a0 ("arm64: convert syscall trace logic to C")
    f60ad4edcf072 ("arm64: clean up irq stack definitions")

v4.4.230: Failed to apply! Possible dependencies:

    0a28714c53fd4 ("arm64: Use PoU cache instr for I/D coherency")
    0a8ea52c3eb15 ("arm64: Add HAVE_REGS_AND_STACK_ACCESS_API feature")
    17c2895860092 ("arm64: Abstract syscallno manipulation")
    2dd0e8d2d2a15 ("arm64: Kprobes with single stepping support")
    35d0e6fb4d219 ("arm64: syscallno is secretly an int, make it official")
    39a67d49ba353 ("arm64: kprobes instruction simulation support")
    421dd6fa6709e ("arm64: factor work_pending state machine to C")
    57f4959bad0a1 ("arm64: kernel: Add support for User Access Override")
    872d8327ce898 ("arm64: add VMAP_STACK overflow detection")
    9842ceae9fa8d ("arm64: Add uprobe support")
    a92d4d1454ab8 ("arm64: entry.S: move SError handling into a C function for future expansion")
    b11e5759bfac0 ("arm64: factor out entry stack manipulation")
    cf7de27ab3517 ("arm64/syscalls: Check address limit on user-mode return")
    d5370f7548754 ("arm64: prefetch: add alternative pattern for CPUs without a prefetcher")
    d59bee8872311 ("arm64: Add more test functions to insn.c")
    e04a28d45ff34 ("arm64: debug: re-enable irqs before sending breakpoint SIGTRAP")
    f37099b6992a0 ("arm64: convert syscall trace logic to C")

NOTE: The patch will not be queued to stable trees until it is upstream.

How should we proceed with this patch?

Signature · 2 lines
Thanks
Sasha
author maintainer
#3 lore raw

PATCH v3 2/7 arm64: ptrace: Override SPSR.SS when single-stepping is enabled

In reply to Will Deacon

Luis reports that, when reverse debugging with GDB, single-step does not function as expected on arm64:

  | I've noticed, under very specific conditions, that a PTRACE_SINGLESTEP
  | request by GDB won't execute the underlying instruction. As a consequence,
  | the PC doesn't move, but we return a SIGTRAP just like we would for a
  | regular successful PTRACE_SINGLESTEP request.

The underlying problem is that when the CPU register state is restored as part of a reverse step, the SPSR.SS bit is cleared and so the hardware single-step state can transition to the "active-pending" state, causing an unexpected step exception to be taken immediately if a step operation is attempted.

In hindsight, we probably shouldn't have exposed SPSR.SS in the pstate accessible by the GPR regset, but it's a bit late for that now. Instead, simply prevent userspace from configuring the bit to a value which is inconsistent with the TIF_SINGLESTEP state for the task being traced.

---
 arch/arm64/include/asm/debug-monitors.h |  2 ++
 arch/arm64/kernel/debug-monitors.c      | 20 ++++++++++++++++----
 arch/arm64/kernel/ptrace.c              |  4 ++--
 3 files changed, 20 insertions(+), 6 deletions(-)
arch/arm64/include/asm/debug-monitors.h +2 -0
index e5ceea213e39..0b298f48f5bf 100644
@@ -109,6 +109,8 @@ void disable_debug_monitors(enum dbg_active_el el);
 
 void user_rewind_single_step(struct task_struct *task);
 void user_fastforward_single_step(struct task_struct *task);
+void user_regs_reset_single_step(struct user_pt_regs *regs,
+				 struct task_struct *task);
 
 void kernel_enable_single_step(struct pt_regs *regs);
 void kernel_disable_single_step(void);
arch/arm64/kernel/debug-monitors.c +16 -4
index 5df49366e9ab..91146c0a3691 100644
@@ -141,17 +141,20 @@ postcore_initcall(debug_monitors_init);
 /*
  * Single step API and exception handling.
  */
-static void set_regs_spsr_ss(struct pt_regs *regs)
+static void set_user_regs_spsr_ss(struct user_pt_regs *regs)
 {
 	regs->pstate |= DBG_SPSR_SS;
 }
-NOKPROBE_SYMBOL(set_regs_spsr_ss);
+NOKPROBE_SYMBOL(set_user_regs_spsr_ss);
 
-static void clear_regs_spsr_ss(struct pt_regs *regs)
+static void clear_user_regs_spsr_ss(struct user_pt_regs *regs)
 {
 	regs->pstate &= ~DBG_SPSR_SS;
 }
-NOKPROBE_SYMBOL(clear_regs_spsr_ss);
+NOKPROBE_SYMBOL(clear_user_regs_spsr_ss);
+
+#define set_regs_spsr_ss(r)	set_user_regs_spsr_ss(&(r)->user_regs)
+#define clear_regs_spsr_ss(r)	clear_user_regs_spsr_ss(&(r)->user_regs)
 
 static DEFINE_SPINLOCK(debug_hook_lock);
 static LIST_HEAD(user_step_hook);
@@ -402,6 +405,15 @@ void user_fastforward_single_step(struct task_struct *task)
 		clear_regs_spsr_ss(task_pt_regs(task));
 }
 
+void user_regs_reset_single_step(struct user_pt_regs *regs,
+				 struct task_struct *task)
+{
+	if (test_tsk_thread_flag(task, TIF_SINGLESTEP))
+		set_user_regs_spsr_ss(regs);
+	else
+		clear_user_regs_spsr_ss(regs);
+}
+
 /* Kernel API */
 void kernel_enable_single_step(struct pt_regs *regs)
 {
arch/arm64/kernel/ptrace.c +2 -2
index 057d4aa1af4d..22f9053b55b6 100644
@@ -1947,8 +1947,8 @@ static int valid_native_regs(struct user_pt_regs *regs)
  */
 int valid_user_regs(struct user_pt_regs *regs, struct task_struct *task)
 {
-	if (!test_tsk_thread_flag(task, TIF_SINGLESTEP))
-		regs->pstate &= ~DBG_SPSR_SS;
+	/* https://lore.kernel.org/lkml/20191118131525.GA4180@willie-the-truck */
+	user_regs_reset_single_step(regs, task);
 
 	if (is_compat_thread(task_thread_info(task)))
 		return valid_compat_regs(regs);
Signature · 1 line
2.27.0.383.g050319c2ae-goog
maintainer
#4 lore raw

Re: [PATCH v3 2/7] arm64: ptrace: Override SPSR.SS when single-stepping is enabled

Hi

[This is an automated email]

This commit has been processed because it contains a -stable tag. The stable tag indicates that it's relevant for the following trees: all

The bot has tested the following trees: v5.7.8, v5.4.51, v4.19.132, v4.14.188, v4.9.230, v4.4.230.

v5.7.8: Build OK!
v5.4.51: Build OK!
v4.19.132: Build OK!
v4.14.188: Build OK!
v4.9.230: Build OK!
v4.4.230: Failed to apply! Possible dependencies:

    44b53f67c99d0 ("arm64: Blacklist non-kprobe-able symbol")

NOTE: The patch will not be queued to stable trees until it is upstream.

How should we proceed with this patch?

Signature · 2 lines
Thanks
Sasha
author maintainer
#5 lore raw

PATCH v3 3/7 arm64: compat: Ensure upper 32 bits of x0 are zero on syscall return

In reply to Will Deacon

Although we zero the upper bits of x0 on entry to the kernel from an AArch32 task, we do not clear them on the exception return path and can therefore expose 64-bit sign extended syscall return values to userspace via interfaces such as the 'perf_regs' ABI, which deal exclusively with 64-bit registers.

Explicitly clear the upper 32 bits of x0 on return from a compat system call.

Cc Mark Rutland <[email protected]>
Cc Keno Fischer <[email protected]>
Cc Luis Machado <[email protected]>
---
 arch/arm64/include/asm/syscall.h | 12 +++++++++++-
 arch/arm64/kernel/syscall.c      |  3 +++
 2 files changed, 14 insertions(+), 1 deletion(-)
arch/arm64/include/asm/syscall.h +11 -1
index 65299a2dcf9c..cfc0672013f6 100644
@@ -34,6 +34,10 @@ static inline long syscall_get_error(struct task_struct *task,
 				     struct pt_regs *regs)
 {
 	unsigned long error = regs->regs[0];
+
+	if (is_compat_thread(task_thread_info(task)))
+		error = sign_extend64(error, 31);
+
 	return IS_ERR_VALUE(error) ? error : 0;
 }
 
@@ -47,7 +51,13 @@ static inline void syscall_set_return_value(struct task_struct *task,
 					    struct pt_regs *regs,
 					    int error, long val)
 {
-	regs->regs[0] = (long) error ? error : val;
+	if (error)
+		val = error;
+
+	if (is_compat_thread(task_thread_info(task)))
+		val = lower_32_bits(val);
+
+	regs->regs[0] = val;
 }
 
 #define SYSCALL_MAX_ARGS 6
arch/arm64/kernel/syscall.c +3 -0
index 7c14466a12af..98a26d4e7b0c 100644
@@ -50,6 +50,9 @@ static void invoke_syscall(struct pt_regs *regs, unsigned int scno,
 		ret = do_ni_syscall(regs, scno);
 	}
 
+	if (is_compat_task())
+		ret = lower_32_bits(ret);
+
 	regs->regs[0] = ret;
 }
 
Signature · 1 line
2.27.0.383.g050319c2ae-goog
maintainer
#6 lore raw

Re: [PATCH v3 3/7] arm64: compat: Ensure upper 32 bits of x0 are zero on syscall return

Hi

[This is an automated email]

This commit has been processed because it contains a -stable tag. The stable tag indicates that it's relevant for the following trees: all

The bot has tested the following trees: v5.7.8, v5.4.51, v4.19.132, v4.14.188, v4.9.230, v4.4.230.

v5.7.8: Build OK!
v5.4.51: Build OK!
v4.19.132: Build OK!
v4.14.188: Failed to apply! Possible dependencies:
0013aceb30748 ("xtensa: clean up fixups in assembly code")
1af1e8a39dc0f ("xtensa: move fixmap and kmap just above the KSEG") 2a61f4747eeaa ("stack-protector: test compiler capability in Kconfig and drop AUTO mode") 2b8383927525d ("Makefile: move stack-protector compiler breakage test earlier") 2bc2f688fdf88 ("Makefile: move stack-protector availability out of Kconfig") 409d5db49867c ("arm64: rseq: Implement backend rseq calls and select HAVE_RSEQ") 40d1a07b333ef ("xtensa: enable stack protector")
4141c857fd09d ("arm64: convert raw syscall invocation to C")
44c6dc940b190 ("Makefile: introduce CONFIG_CC_STACKPROTECTOR_AUTO") 5cf97ebd8b40e ("xtensa: clean up functions in assembly code") 8d66772e869e7 ("arm64: Mask all exceptions during kernel_exit") 9800b9dc13cdf ("arm: Add restartable sequences support")
c2edb35ae342f ("xtensa: extract init_kio")
c633544a61541 ("xtensa: add support for KASAN")
d148eac0e70f0 ("Kbuild: rename HAVE_CC_STACKPROTECTOR config variable") f4431396be5b2 ("xtensa: consolidate kernel stack size related definitions")

v4.9.230: Failed to apply! Possible dependencies:

    12597988319c8 ("MIPS: Sort MIPS Kconfig Alphabetically.")
    2a61f4747eeaa ("stack-protector: test compiler capability in Kconfig and drop AUTO mode")
    2b8383927525d ("Makefile: move stack-protector compiler breakage test earlier")
    2bc2f688fdf88 ("Makefile: move stack-protector availability out of Kconfig")
    313dd1b629219 ("gcc-plugins: Add the randstruct plugin")
    39c13c204bb11 ("arm: eBPF JIT compiler")
    409d5db49867c ("arm64: rseq: Implement backend rseq calls and select HAVE_RSEQ")
    4141c857fd09d ("arm64: convert raw syscall invocation to C")
    44c6dc940b190 ("Makefile: introduce CONFIG_CC_STACKPROTECTOR_AUTO")
    74d86a70636a0 ("arm: use set_memory.h header")
    8d66772e869e7 ("arm64: Mask all exceptions during kernel_exit")
    9800b9dc13cdf ("arm: Add restartable sequences support")
    c02433dd6de32 ("arm64: split thread_info from task stack")
    c61f13eaa1ee1 ("gcc-plugins: Add structleak for more stack initialization")
    c763ea2650dfa ("x86/kconfig: Sort the 'config X86' selects alphabetically")
    d148eac0e70f0 ("Kbuild: rename HAVE_CC_STACKPROTECTOR config variable")
    f381bf6d82f03 ("MIPS: Add support for eBPF JIT.")

v4.4.230: Failed to apply! Possible dependencies:

    218cfe4ed8885 ("perf/x86: Move perf_event_amd_ibs.c ....... => x86/events/amd/ibs.c")
    25a77b55e74c4 ("xtensa/perf: Convert the hotplug notifier to state machine callbacks")
    2a803c4db615d ("arm64: head.S: use memset to clear BSS")
    2bf31a4a05f5b ("arm64: avoid dynamic relocations in early boot code")
    3600c2fdc09a4 ("arm64: Add macros to read/write system registers")
    39b0332a21583 ("perf/x86: Move perf_event_amd.c ........... => x86/events/amd/core.c")
    4141c857fd09d ("arm64: convert raw syscall invocation to C")
    499c81507f599 ("arm64/debug: Remove superfluous SMP function call")
    49de0493e5f67 ("x86/perf/intel/cstate: Make cstate hotplug handling actually work")
    4b6e2571bf000 ("x86/perf/intel/rapl: Make the Intel RAPL PMU driver modular")
    5b26547dd7faa ("perf/x86: Move perf_event_amd_iommu.[ch] .. => x86/events/amd/iommu.[ch]")
    609116d202a8c ("arm64: add function to install the idmap")
    6cdf9c7ca687e ("arm64: Store struct thread_info in sp_el0")
    77c34ef1c3194 ("perf/x86/intel/cstate: Convert Intel CSTATE to hotplug state machine")
    8d66772e869e7 ("arm64: Mask all exceptions during kernel_exit")
    9e8e865bbe294 ("arm64: unify idmap removal")
    a563f7598198b ("arm64: Reuse TCR field definitions for EL1 and EL2")
    adf7589997927 ("arm64: simplify sysreg manipulation")
    ae7e27fe6834d ("arm64: hw_breakpoint: Allow EL2 breakpoints if running in HYP")
    bb9052744f4b7 ("arm64: Handle early CPU boot failures")
    c02433dd6de32 ("arm64: split thread_info from task stack")
    c4bc34d20273d ("arm64: Add a helper for parking CPUs in a loop")
    c7afba320e91c ("x86/perf/intel/cstate: Modularize driver")
    e5b61bafe7047 ("arm: Convert VFP hotplug notifiers to state machine")
    e633c65a1d585 ("x86/perf/intel/uncore: Make the Intel uncore PMU driver modular")
    e937dd5782688 ("arm64: debug: convert OS lock CPU hotplug notifier to new infrastructure")
    ee02a15919cf8 ("arm64: Introduce cpu_die_early")
    fa9cbf320e996 ("perf/x86: Move perf_event.c ............... => x86/events/core.c")
    fce6361fe9b0c ("arm64: Move cpu_die_early to smp.c")

NOTE: The patch will not be queued to stable trees until it is upstream.

How should we proceed with this patch?

Signature · 2 lines
Thanks
Sasha
author maintainer
#7 lore raw

PATCH v3 4/7 arm64: ptrace: Add a comment describing our syscall entry/exit trap ABI

In reply to Will Deacon

Our tracehook logic for syscall entry/exit raises a SIGTRAP back to the tracer following a ptrace request such as PTRACE_SYSCALL. As part of this procedure, we clobber the reported value of one of the tracee's general purpose registers (x7 for native tasks, r12 for compat) to indicate whether the stop occurred on syscall entry or exit. This is a slightly unfortunate ABI, as it prevents the tracer from accessing the real register value and is at odds with other similar stops such as seccomp traps.

Since we're stuck with this ABI, expand the comment in our tracehook logic to acknowledge the issue and descibe the behaviour in more detail.

---
 arch/arm64/kernel/ptrace.c | 16 ++++++++++++++--
 1 file changed, 14 insertions(+), 2 deletions(-)
arch/arm64/kernel/ptrace.c +14 -2
index 22f9053b55b6..89fbee3991a2 100644
@@ -1811,8 +1811,20 @@ static void tracehook_report_syscall(struct pt_regs *regs,
 	unsigned long saved_reg;
 
 	/*
-	 * A scratch register (ip(r12) on AArch32, x7 on AArch64) is
-	 * used to denote syscall entry/exit:
+	 * We have some ABI weirdness here in the way that we handle syscall
+	 * exit stops because we indicate whether or not the stop has been
+	 * signalled from syscall entry or syscall exit by clobbering a general
+	 * purpose register (ip/r12 for AArch32, x7 for AArch64) in the tracee
+	 * and restoring its old value after the stop. This means that:
+	 *
+	 * - Any writes by the tracer to this register during the stop are
+	 *   ignored/discarded.
+	 *
+	 * - The actual value of the register is not available during the stop,
+	 *   so the tracer cannot save it and restore it later.
+	 *
+	 * - Syscall stops behave differently to seccomp and pseudo-step traps
+	 *   (the latter do not nobble any registers).
 	 */
 	regno = (is_compat_task() ? 12 : 7);
 	saved_reg = regs->regs[regno];
Signature · 7 lines
2.27.0.383.g050319c2ae-goog


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
author maintainer
#8 lore raw

PATCH v3 5/7 arm64: syscall: Expand the comment about ptrace and syscall(-1)

In reply to Will Deacon

If a task executes syscall(-1), we intercept this early and force x0 to be -ENOSYS so that we don't need to distinguish this scenario from one where the scno is -1 because a tracer wants to skip the system call using ptrace. With the return value set, the return path is the same as the skip case.

Although there is a one-line comment noting this in el0_svc_common(), it misses out most of the detail. Expand the comment to describe a bit more about what is going on.

Cc Mark Rutland <[email protected]>
Cc Keno Fischer <[email protected]>
Cc Luis Machado <[email protected]>
---
 arch/arm64/kernel/syscall.c | 16 +++++++++++++++-
 1 file changed, 15 insertions(+), 1 deletion(-)
arch/arm64/kernel/syscall.c +15 -1
index 98a26d4e7b0c..5f0c04863d2c 100644
@@ -124,7 +124,21 @@ static void el0_svc_common(struct pt_regs *regs, int scno, int sc_nr,
 	user_exit();
 
 	if (has_syscall_work(flags)) {
-		/* set default errno for user-issued syscall(-1) */
+		/*
+		 * The de-facto standard way to skip a system call using ptrace
+		 * is to set the system call to -1 (NO_SYSCALL) and set x0 to a
+		 * suitable error code for consumption by userspace. However,
+		 * this cannot be distinguished from a user-issued syscall(-1)
+		 * and so we must set x0 to -ENOSYS here in case the tracer doesn't
+		 * issue the skip and we fall into trace_exit with x0 preserved.
+		 *
+		 * This is slightly odd because it also means that if a tracer
+		 * sets the system call number to -1 but does not initialise x0,
+		 * then x0 will be preserved for all system calls apart from a
+		 * user-issued syscall(-1). However, requesting a skip and not
+		 * setting the return value is unlikely to do anything sensible
+		 * anyway.
+		 */
 		if (scno == NO_SYSCALL)
 			regs->regs[0] = -ENOSYS;
 		scno = syscall_trace_enter(regs);
Signature · 7 lines
2.27.0.383.g050319c2ae-goog


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
author maintainer
#9 lore raw

PATCH v3 6/7 arm64: ptrace: Use NO_SYSCALL instead of -1 in syscall_trace_enter()

In reply to Will Deacon

Setting a system call number of -1 is special, as it indicates that the current system call should be skipped.

Use NO_SYSCALL instead of -1 when checking for this scenario, which is different from the -1 returned due to a seccomp failure.

Cc Mark Rutland <[email protected]>
Cc Keno Fischer <[email protected]>
Cc Luis Machado <[email protected]>
---
 arch/arm64/kernel/ptrace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/kernel/ptrace.c +2 -2
index 89fbee3991a2..1e02e98e68dd 100644
@@ -1856,12 +1856,12 @@ int syscall_trace_enter(struct pt_regs *regs)
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
 		tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
 		if (!in_syscall(regs) || (flags & _TIF_SYSCALL_EMU))
-			return -1;
+			return NO_SYSCALL;
 	}
 
 	/* Do the secure computing after ptrace; failures should be fast. */
 	if (secure_computing() == -1)
-		return -1;
+		return NO_SYSCALL;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 		trace_sys_enter(regs, regs->syscallno);
Signature · 7 lines
2.27.0.383.g050319c2ae-goog


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#10 lore raw

Re: [PATCH v3 6/7] arm64: ptrace: Use NO_SYSCALL instead of -1 in syscall_trace_enter()

Quoted 5 lines · Will Deacon

Setting a system call number of -1 is special, as it indicates that the current system call should be skipped.

Use NO_SYSCALL instead of -1 when checking for this scenario, which is different from the -1 returned due to a seccomp failure.

I can't understand this paragraph. NO_SYSCALL is -1, so how is this "different"?

arch/arm64/include/asm/ptrace.h:#define NO_SYSCALL (-1)

Do you just mean "stop using a literal '-1'"?

-Kees

Quoted 31 lines
Cc Mark Rutland <[email protected]>
Cc Keno Fischer <[email protected]>
Cc Luis Machado <[email protected]>
---
 arch/arm64/kernel/ptrace.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/kernel/ptrace.c +2 -2
index 89fbee3991a2..1e02e98e68dd 100644
@@ -1856,12 +1856,12 @@ int syscall_trace_enter(struct pt_regs *regs)
 	if (flags & (_TIF_SYSCALL_EMU | _TIF_SYSCALL_TRACE)) {
 		tracehook_report_syscall(regs, PTRACE_SYSCALL_ENTER);
 		if (!in_syscall(regs) || (flags & _TIF_SYSCALL_EMU))
-			return -1;
+			return NO_SYSCALL;
 	}
 
 	/* Do the secure computing after ptrace; failures should be fast. */
 	if (secure_computing() == -1)
-		return -1;
+		return NO_SYSCALL;
 
 	if (test_thread_flag(TIF_SYSCALL_TRACEPOINT))
 		trace_sys_enter(regs, regs->syscallno);
Signature · 1 line
2.27.0.383.g050319c2ae-goog
Signature · 6 lines
Kees Cook

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
author maintainer
#11 lore raw

Re: [PATCH v3 6/7] arm64: ptrace: Use NO_SYSCALL instead of -1 in syscall_trace_enter()

Quoted 7 lines · Kees Cook
Quoted 5 lines · Will Deacon

Setting a system call number of -1 is special, as it indicates that the current system call should be skipped.

Use NO_SYSCALL instead of -1 when checking for this scenario, which is different from the -1 returned due to a seccomp failure.

Quoted 6 lines

I can't understand this paragraph. NO_SYSCALL is -1, so how is this "different"?

arch/arm64/include/asm/ptrace.h:#define NO_SYSCALL (-1)

Do you just mean "stop using a literal '-1'"?

Yes, I'm trying to distinguish '-1' when used as a system call number from '-1' when used as the return value of secure_computing() on failure. It's currently all mixed up, and I think it's confusing trying to realise what is a system call number and what is an error code.

Will

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#12 lore raw

Re: [PATCH v3 6/7] arm64: ptrace: Use NO_SYSCALL instead of -1 in syscall_trace_enter()

Quoted 11 lines · Will Deacon
Quoted 10 lines · Kees Cook
Quoted 5 lines · Will Deacon

Setting a system call number of -1 is special, as it indicates that the current system call should be skipped.

Use NO_SYSCALL instead of -1 when checking for this scenario, which is different from the -1 returned due to a seccomp failure.

I can't understand this paragraph. NO_SYSCALL is -1, so how is this "different"?

Quoted 8 lines
Quoted 3 lines

arch/arm64/include/asm/ptrace.h:#define NO_SYSCALL (-1)

Do you just mean "stop using a literal '-1'"?

Yes, I'm trying to distinguish '-1' when used as a system call number from '-1' when used as the return value of secure_computing() on failure. It's currently all mixed up, and I think it's confusing trying to realise what is a system call number and what is an error code.

Okay, I gotcha now. Yes, that's entirely reasonable. (It's perhaps an artifact of x86's implementation that they get directly passed through.)

Signature · 6 lines
Kees Cook

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
author maintainer
#13 lore raw

PATCH v3 7/7 arm64: Use test_tsk_thread_flag() for checking TIF_SINGLESTEP

In reply to Will Deacon

Rather than open-code test_tsk_thread_flag() at each callsite, simply replace the couple of offenders with calls to test_tsk_thread_flag() directly.

---
 arch/arm64/kernel/debug-monitors.c | 4 ++--
 1 file changed, 2 insertions(+), 2 deletions(-)
arch/arm64/kernel/debug-monitors.c +2 -2
index 91146c0a3691..7310a4f7f993 100644
@@ -394,14 +394,14 @@ void user_rewind_single_step(struct task_struct *task)
 	 * If single step is active for this thread, then set SPSR.SS
 	 * to 1 to avoid returning to the active-pending state.
 	 */
-	if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP))
+	if (test_tsk_thread_flag(task, TIF_SINGLESTEP))
 		set_regs_spsr_ss(task_pt_regs(task));
 }
 NOKPROBE_SYMBOL(user_rewind_single_step);
 
 void user_fastforward_single_step(struct task_struct *task)
 {
-	if (test_ti_thread_flag(task_thread_info(task), TIF_SINGLESTEP))
+	if (test_tsk_thread_flag(task, TIF_SINGLESTEP))
 		clear_regs_spsr_ss(task_pt_regs(task));
 }
 
Signature · 7 lines
2.27.0.383.g050319c2ae-goog


_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel
#14 lore raw
In reply to Will Deacon

Hi Will,

Quoted 11 lines · Will Deacon

Hi folks,

This is version three of the patches I previous posted here:

   v1: https://lore.kernel.org/r/[email protected]
   v2: https://lore.kernel.org/r/[email protected]

This version includes some changes I've been hacking on in relation to syscall entry/exit, as it seemed worth lumping all this together. I've also reordered the series to put the fixes at the start.

Quoted 6 lines

Luis -- did you manage to test v2? I'd quite like to queue some of this soon. If you don't have time, how can I run the GDB testsuite myself? I tried doing it a _long_ time ago but I remember there being a lot of failures and flakey tests, so it wasn't very helpful. I have arm64 hardware running Debian so it's just a question of which buttons to press :)

I didn't manage to test it yet. I was going to try v3 today.

If you have hardware though, that would be best. You just need to build GDB from sources (configure and make) and give the testsuite a try (make check-gdb). I can look at the result/summary and OK it.

There are still flakey tests unfortunately, but those shouldn't be a big problem.

You can ping me on IRC if you want to address any issues you have with building/running the tests.

I'll give it a try with QEMU anyway.

Quoted 23 lines

Cheers,

Will

Cc Mark Rutland <[email protected]>
Cc Luis Machado <[email protected]>
Cc Keno Fischer <[email protected]>
Cc Kees Cook <[email protected]>

--->8

Will Deacon (7):
arm64: ptrace: Consistently use pseudo-singlestep exceptions
arm64: ptrace: Override SPSR.SS when single-stepping is enabled
arm64: compat: Ensure upper 32 bits of x0 are zero on syscall return
arm64: ptrace: Add a comment describing our syscall entry/exit trap
ABI
arm64: syscall: Expand the comment about ptrace and syscall(-1)
arm64: ptrace: Use NO_SYSCALL instead of -1 in syscall_trace_enter()
arm64: Use test_tsk_thread_flag() for checking TIF_SINGLESTEP

Quoted 9 lines
  arch/arm64/include/asm/debug-monitors.h |  2 +
  arch/arm64/include/asm/syscall.h        | 12 +++++-
  arch/arm64/include/asm/thread_info.h    |  1 +
  arch/arm64/kernel/debug-monitors.c      | 24 +++++++++---
  arch/arm64/kernel/ptrace.c              | 49 +++++++++++++++++++------
  arch/arm64/kernel/signal.c              | 11 +-----
  arch/arm64/kernel/syscall.c             | 21 ++++++++++-
  7 files changed, 90 insertions(+), 30 deletions(-)

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel

#15 lore raw
In reply to Will Deacon

Hi Will,

This looks good from GDB's side based on the testsuite results.

Thanks for fixing it.

Regards,
Luis

Quoted 40 lines · Will Deacon

Hi folks,

This is version three of the patches I previous posted here:

   v1: https://lore.kernel.org/r/[email protected]
   v2: https://lore.kernel.org/r/[email protected]

This version includes some changes I've been hacking on in relation to syscall entry/exit, as it seemed worth lumping all this together. I've also reordered the series to put the fixes at the start.

Luis -- did you manage to test v2? I'd quite like to queue some of this soon. If you don't have time, how can I run the GDB testsuite myself? I tried doing it a _long_ time ago but I remember there being a lot of failures and flakey tests, so it wasn't very helpful. I have arm64 hardware running Debian so it's just a question of which buttons to press :)

Cheers,

Will

Cc Mark Rutland <[email protected]>
Cc Luis Machado <[email protected]>
Cc Keno Fischer <[email protected]>
Cc Kees Cook <[email protected]>

--->8

Will Deacon (7):
arm64: ptrace: Consistently use pseudo-singlestep exceptions
arm64: ptrace: Override SPSR.SS when single-stepping is enabled
arm64: compat: Ensure upper 32 bits of x0 are zero on syscall return
arm64: ptrace: Add a comment describing our syscall entry/exit trap
ABI
arm64: syscall: Expand the comment about ptrace and syscall(-1)
arm64: ptrace: Use NO_SYSCALL instead of -1 in syscall_trace_enter()
arm64: Use test_tsk_thread_flag() for checking TIF_SINGLESTEP

Quoted 9 lines
  arch/arm64/include/asm/debug-monitors.h |  2 +
  arch/arm64/include/asm/syscall.h        | 12 +++++-
  arch/arm64/include/asm/thread_info.h    |  1 +
  arch/arm64/kernel/debug-monitors.c      | 24 +++++++++---
  arch/arm64/kernel/ptrace.c              | 49 +++++++++++++++++++------
  arch/arm64/kernel/signal.c              | 11 +-----
  arch/arm64/kernel/syscall.c             | 21 ++++++++++-
  7 files changed, 90 insertions(+), 30 deletions(-)

_______________________________________________
linux-arm-kernel mailing list
[email protected]
http://lists.infradead.org/mailman/listinfo/linux-arm-kernel