Commit 91bd008d authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull probes updates from Masami Hiramatsu:
 "Uprobes:

   - x86/shstk: Make return uprobe work with shadow stack

   - Add uretprobe syscall which speeds up the uretprobe 10-30% faster.
     This syscall is automatically used from user-space trampolines
     which are generated by the uretprobe. If this syscall is used by
     normal user program, it will cause SIGILL. Note that this is
     currently only implemented on x86_64.

     (This also has two fixes for adjusting the syscall number to avoid
     conflict with new *attrat syscalls.)

   - uprobes/perf: fix user stack traces in the presence of pending
     uretprobe. This corrects the uretprobe's trampoline address in the
     stacktrace with correct return address

   - selftests/x86: Add a return uprobe with shadow stack test

   - selftests/bpf: Add uretprobe syscall related tests.
      - test case for register integrity check
      - test case with register changing case
      - test case for uretprobe syscall without uprobes (expected to fail)
      - test case for uretprobe with shadow stack

   - selftests/bpf: add test validating uprobe/uretprobe stack traces

   - MAINTAINERS: Add uprobes entry. This does not specify the tree but
     to clarify who maintains and reviews the uprobes

  Kprobes:

   - tracing/kprobes: Test case cleanups.

     Replace redundant WARN_ON_ONCE() + pr_warn() with WARN_ONCE() and
     remove unnecessary code from selftest

   - tracing/kprobes: Add symbol counting check when module loads.

     This checks the uniqueness of the probed symbol on modules. The
     same check has already done for kernel symbols

     (This also has a fix for build error with CONFIG_MODULES=n)

  Cleanup:

   - Add MODULE_DESCRIPTION() macros for fprobe and kprobe examples"

* tag 'probes-v6.11' of git://git.kernel.org/pub/scm/linux/kernel/git/trace/linux-trace:
  MAINTAINERS: Add uprobes entry
  selftests/bpf: Change uretprobe syscall number in uprobe_syscall test
  uprobe: Change uretprobe syscall scope and number
  tracing/kprobes: Fix build error when find_module() is not available
  tracing/kprobes: Add symbol counting check when module loads
  selftests/bpf: add test validating uprobe/uretprobe stack traces
  perf,uprobes: fix user stack traces in the presence of pending uretprobes
  tracing/kprobe: Remove cleanup code unrelated to selftest
  tracing/kprobe: Integrate test warnings into WARN_ONCE
  selftests/bpf: Add uretprobe shadow stack test
  selftests/bpf: Add uretprobe syscall call from user space test
  selftests/bpf: Add uretprobe syscall test for regs changes
  selftests/bpf: Add uretprobe syscall test for regs integrity
  selftests/x86: Add return uprobe shadow stack test
  uprobe: Add uretprobe syscall to speed up return probe
  uprobe: Wire up uretprobe system call
  x86/shstk: Make return uprobe work with shadow stack
  samples: kprobes: add missing MODULE_DESCRIPTION() macros
  fprobe: add missing MODULE_DESCRIPTION() macro
parents cb273eb7 c26b1b89
Loading
Loading
Loading
Loading
+13 −0
Original line number Diff line number Diff line
@@ -23367,6 +23367,19 @@ F: drivers/mtd/ubi/
F:	include/linux/mtd/ubi.h
F:	include/uapi/mtd/ubi-user.h
UPROBES
M:	Masami Hiramatsu <mhiramat@kernel.org>
M:	Oleg Nesterov <oleg@redhat.com>
M:	Peter Zijlstra <peterz@infradead.org>
L:	linux-kernel@vger.kernel.org
L:	linux-trace-kernel@vger.kernel.org
S:	Maintained
F:	arch/*/include/asm/uprobes.h
F:	arch/*/kernel/probes/uprobes.c
F:	arch/*/kernel/uprobes.c
F:	include/linux/uprobes.h
F:	kernel/events/uprobes.c
USB "USBNET" DRIVER FRAMEWORK
M:	Oliver Neukum <oneukum@suse.com>
L:	netdev@vger.kernel.org
+1 −0
Original line number Diff line number Diff line
@@ -385,6 +385,7 @@
460	common	lsm_set_self_attr	sys_lsm_set_self_attr
461	common	lsm_list_modules	sys_lsm_list_modules
462 	common  mseal			sys_mseal
467	common	uretprobe		sys_uretprobe

#
# Due to a historical design error, certain syscalls are numbered differently
+4 −0
Original line number Diff line number Diff line
@@ -21,6 +21,8 @@ unsigned long shstk_alloc_thread_stack(struct task_struct *p, unsigned long clon
void shstk_free(struct task_struct *p);
int setup_signal_shadow_stack(struct ksignal *ksig);
int restore_signal_shadow_stack(void);
int shstk_update_last_frame(unsigned long val);
bool shstk_is_enabled(void);
#else
static inline long shstk_prctl(struct task_struct *task, int option,
			       unsigned long arg2) { return -EINVAL; }
@@ -31,6 +33,8 @@ static inline unsigned long shstk_alloc_thread_stack(struct task_struct *p,
static inline void shstk_free(struct task_struct *p) {}
static inline int setup_signal_shadow_stack(struct ksignal *ksig) { return 0; }
static inline int restore_signal_shadow_stack(void) { return 0; }
static inline int shstk_update_last_frame(unsigned long val) { return 0; }
static inline bool shstk_is_enabled(void) { return false; }
#endif /* CONFIG_X86_USER_SHADOW_STACK */

#endif /* __ASSEMBLY__ */
+16 −0
Original line number Diff line number Diff line
@@ -577,3 +577,19 @@ long shstk_prctl(struct task_struct *task, int option, unsigned long arg2)
		return wrss_control(true);
	return -EINVAL;
}

int shstk_update_last_frame(unsigned long val)
{
	unsigned long ssp;

	if (!features_enabled(ARCH_SHSTK_SHSTK))
		return 0;

	ssp = get_user_shstk_addr();
	return write_user_shstk_64((u64 __user *)ssp, (u64)val);
}

bool shstk_is_enabled(void)
{
	return features_enabled(ARCH_SHSTK_SHSTK);
}
+123 −1
Original line number Diff line number Diff line
@@ -12,6 +12,7 @@
#include <linux/ptrace.h>
#include <linux/uprobes.h>
#include <linux/uaccess.h>
#include <linux/syscalls.h>

#include <linux/kdebug.h>
#include <asm/processor.h>
@@ -308,6 +309,122 @@ static int uprobe_init_insn(struct arch_uprobe *auprobe, struct insn *insn, bool
}

#ifdef CONFIG_X86_64

asm (
	".pushsection .rodata\n"
	".global uretprobe_trampoline_entry\n"
	"uretprobe_trampoline_entry:\n"
	"pushq %rax\n"
	"pushq %rcx\n"
	"pushq %r11\n"
	"movq $" __stringify(__NR_uretprobe) ", %rax\n"
	"syscall\n"
	".global uretprobe_syscall_check\n"
	"uretprobe_syscall_check:\n"
	"popq %r11\n"
	"popq %rcx\n"

	/* The uretprobe syscall replaces stored %rax value with final
	 * return address, so we don't restore %rax in here and just
	 * call ret.
	 */
	"retq\n"
	".global uretprobe_trampoline_end\n"
	"uretprobe_trampoline_end:\n"
	".popsection\n"
);

extern u8 uretprobe_trampoline_entry[];
extern u8 uretprobe_trampoline_end[];
extern u8 uretprobe_syscall_check[];

void *arch_uprobe_trampoline(unsigned long *psize)
{
	static uprobe_opcode_t insn = UPROBE_SWBP_INSN;
	struct pt_regs *regs = task_pt_regs(current);

	/*
	 * At the moment the uretprobe syscall trampoline is supported
	 * only for native 64-bit process, the compat process still uses
	 * standard breakpoint.
	 */
	if (user_64bit_mode(regs)) {
		*psize = uretprobe_trampoline_end - uretprobe_trampoline_entry;
		return uretprobe_trampoline_entry;
	}

	*psize = UPROBE_SWBP_INSN_SIZE;
	return &insn;
}

static unsigned long trampoline_check_ip(void)
{
	unsigned long tramp = uprobe_get_trampoline_vaddr();

	return tramp + (uretprobe_syscall_check - uretprobe_trampoline_entry);
}

SYSCALL_DEFINE0(uretprobe)
{
	struct pt_regs *regs = task_pt_regs(current);
	unsigned long err, ip, sp, r11_cx_ax[3];

	if (regs->ip != trampoline_check_ip())
		goto sigill;

	err = copy_from_user(r11_cx_ax, (void __user *)regs->sp, sizeof(r11_cx_ax));
	if (err)
		goto sigill;

	/* expose the "right" values of r11/cx/ax/sp to uprobe_consumer/s */
	regs->r11 = r11_cx_ax[0];
	regs->cx  = r11_cx_ax[1];
	regs->ax  = r11_cx_ax[2];
	regs->sp += sizeof(r11_cx_ax);
	regs->orig_ax = -1;

	ip = regs->ip;
	sp = regs->sp;

	uprobe_handle_trampoline(regs);

	/*
	 * Some of the uprobe consumers has changed sp, we can do nothing,
	 * just return via iret.
	 * .. or shadow stack is enabled, in which case we need to skip
	 * return through the user space stack address.
	 */
	if (regs->sp != sp || shstk_is_enabled())
		return regs->ax;
	regs->sp -= sizeof(r11_cx_ax);

	/* for the case uprobe_consumer has changed r11/cx */
	r11_cx_ax[0] = regs->r11;
	r11_cx_ax[1] = regs->cx;

	/*
	 * ax register is passed through as return value, so we can use
	 * its space on stack for ip value and jump to it through the
	 * trampoline's ret instruction
	 */
	r11_cx_ax[2] = regs->ip;
	regs->ip = ip;

	err = copy_to_user((void __user *)regs->sp, r11_cx_ax, sizeof(r11_cx_ax));
	if (err)
		goto sigill;

	/* ensure sysret, see do_syscall_64() */
	regs->r11 = regs->flags;
	regs->cx  = regs->ip;

	return regs->ax;

sigill:
	force_sig(SIGILL);
	return -1;
}

/*
 * If arch_uprobe->insn doesn't use rip-relative addressing, return
 * immediately.  Otherwise, rewrite the instruction so that it accesses
@@ -1076,8 +1193,13 @@ arch_uretprobe_hijack_return_addr(unsigned long trampoline_vaddr, struct pt_regs
		return orig_ret_vaddr;

	nleft = copy_to_user((void __user *)regs->sp, &trampoline_vaddr, rasize);
	if (likely(!nleft))
	if (likely(!nleft)) {
		if (shstk_update_last_frame(trampoline_vaddr)) {
			force_sig(SIGSEGV);
			return -1;
		}
		return orig_ret_vaddr;
	}

	if (nleft != rasize) {
		pr_err("return address clobbered: pid=%d, %%sp=%#lx, %%ip=%#lx\n",
Loading