Commit a570f419 authored by Linus Torvalds's avatar Linus Torvalds
Browse files

Merge tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux into master

Pull arm64 fixes from Will Deacon:
 "A batch of arm64 fixes.

  Although the diffstat is a bit larger than we'd usually have at this
  stage, a decent amount of it is the addition of comments describing
  our syscall tracing behaviour, and also a sweep across all the modular
  arm64 PMU drivers to make them rebust against unloading and unbinding.

  There are a couple of minor things kicking around at the moment (CPU
  errata and module PLTs for very large modules), but I'm not expecting
  any significant changes now for us in 5.8.

   - Fix kernel text addresses for relocatable images booting using EFI
     and with KASLR disabled so that they match the vmlinux ELF binary.

   - Fix unloading and unbinding of PMU driver modules.

   - Fix generic mmiowb() when writeX() is called from preemptible
     context (reported by the riscv folks).

   - Fix ptrace hardware single-step interactions with signal handlers,
     system calls and reverse debugging.

   - Fix reporting of 64-bit x0 register for 32-bit tasks via
     'perf_regs'.

   - Add comments describing syscall entry/exit tracing ABI"

* tag 'arm64-fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/arm64/linux:
  drivers/perf: Prevent forced unbinding of PMU drivers
  asm-generic/mmiowb: Allow mmiowb_set_pending() when preemptible()
  arm64: Use test_tsk_thread_flag() for checking TIF_SINGLESTEP
  arm64: ptrace: Use NO_SYSCALL instead of -1 in syscall_trace_enter()
  arm64: syscall: Expand the comment about ptrace and syscall(-1)
  arm64: ptrace: Add a comment describing our syscall entry/exit trap ABI
  arm64: compat: Ensure upper 32 bits of x0 are zero on syscall return
  arm64: ptrace: Override SPSR.SS when single-stepping is enabled
  arm64: ptrace: Consistently use pseudo-singlestep exceptions
  drivers/perf: Fix kernel panic when rmmod PMU modules during perf sampling
  efi/libstub/arm64: Retain 2MB kernel Image alignment if !KASLR
parents 4ebf8d76 f32ed8eb
Loading
Loading
Loading
Loading
+2 −0
Original line number Diff line number Diff line
@@ -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);
+11 −1
Original line number Diff line number Diff line
@@ -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
+1 −0
Original line number Diff line number Diff line
@@ -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)

+18 −6
Original line number Diff line number Diff line
@@ -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);
@@ -391,17 +394,26 @@ 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));
}

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)
{
+37 −12
Original line number Diff line number Diff line
@@ -1811,19 +1811,42 @@ 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];
	regs->regs[regno] = dir;

	if (dir == PTRACE_SYSCALL_EXIT)
		tracehook_report_syscall_exit(regs, 0);
	else if (tracehook_report_syscall_entry(regs))
	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);
		regs->regs[regno] = saved_reg;
	} else {
		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)
@@ -1833,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);
@@ -1851,12 +1874,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);
@@ -1934,8 +1959,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);
Loading