Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 37b6cb47 authored by Ingo Molnar's avatar Ingo Molnar
Browse files

Merge branch 'uprobes/core' of...

Merge branch 'uprobes/core' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc

 into perf/core

Pull uprobes fixes and cleanups from Oleg Nesterov:

  "Any probed jmp/call can kill the application, see the changelog in 11/15."

Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parents b3d5fc3c 6cc5e7ff
Loading
Loading
Loading
Loading
+14 −2
Original line number Diff line number Diff line
@@ -33,15 +33,27 @@ typedef u8 uprobe_opcode_t;
#define UPROBE_SWBP_INSN		0xcc
#define UPROBE_SWBP_INSN_SIZE		   1

struct uprobe_xol_ops;

struct arch_uprobe {
	u16				fixups;
	union {
		u8			insn[MAX_UINSN_BYTES];
		u8			ixol[MAX_UINSN_BYTES];
	};

	u16				fixups;
	const struct uprobe_xol_ops	*ops;

	union {
#ifdef CONFIG_X86_64
		unsigned long			rip_rela_target_address;
#endif
		struct {
			s32	offs;
			u8	ilen;
			u8	opc1;
		}				branch;
	};
};

struct arch_uprobe_task {
+349 −202

File changed.

Preview size limit exceeded, changes collapsed.

+9 −22
Original line number Diff line number Diff line
@@ -60,8 +60,6 @@ static struct percpu_rw_semaphore dup_mmap_sem;

/* Have a copy of original instruction */
#define UPROBE_COPY_INSN	0
/* Can skip singlestep */
#define UPROBE_SKIP_SSTEP	1

struct uprobe {
	struct rb_node		rb_node;	/* node in the rb tree */
@@ -491,12 +489,9 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
	uprobe->offset = offset;
	init_rwsem(&uprobe->register_rwsem);
	init_rwsem(&uprobe->consumer_rwsem);
	/* For now assume that the instruction need not be single-stepped */
	__set_bit(UPROBE_SKIP_SSTEP, &uprobe->flags);

	/* add to uprobes_tree, sorted on inode:offset */
	cur_uprobe = insert_uprobe(uprobe);

	/* a uprobe exists for this inode:offset combination */
	if (cur_uprobe) {
		kfree(uprobe);
@@ -1628,20 +1623,6 @@ bool uprobe_deny_signal(void)
	return true;
}

/*
 * Avoid singlestepping the original instruction if the original instruction
 * is a NOP or can be emulated.
 */
static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs)
{
	if (test_bit(UPROBE_SKIP_SSTEP, &uprobe->flags)) {
		if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
			return true;
		clear_bit(UPROBE_SKIP_SSTEP, &uprobe->flags);
	}
	return false;
}

static void mmf_recalc_uprobes(struct mm_struct *mm)
{
	struct vm_area_struct *vma;
@@ -1868,13 +1849,13 @@ static void handle_swbp(struct pt_regs *regs)

	handler_chain(uprobe, regs);

	if (can_skip_sstep(uprobe, regs))
	if (arch_uprobe_skip_sstep(&uprobe->arch, regs))
		goto out;

	if (!pre_ssout(uprobe, regs, bp_vaddr))
		return;

	/* can_skip_sstep() succeeded, or restart if can't singlestep */
	/* arch_uprobe_skip_sstep() succeeded, or restart if can't singlestep */
out:
	put_uprobe(uprobe);
}
@@ -1886,10 +1867,11 @@ static void handle_swbp(struct pt_regs *regs)
static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
{
	struct uprobe *uprobe;
	int err = 0;

	uprobe = utask->active_uprobe;
	if (utask->state == UTASK_SSTEP_ACK)
		arch_uprobe_post_xol(&uprobe->arch, regs);
		err = arch_uprobe_post_xol(&uprobe->arch, regs);
	else if (utask->state == UTASK_SSTEP_TRAPPED)
		arch_uprobe_abort_xol(&uprobe->arch, regs);
	else
@@ -1903,6 +1885,11 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
	spin_lock_irq(&current->sighand->siglock);
	recalc_sigpending(); /* see uprobe_deny_signal() */
	spin_unlock_irq(&current->sighand->siglock);

	if (unlikely(err)) {
		uprobe_warn(current, "execute the probed insn, sending SIGILL.");
		force_sig_info(SIGILL, SEND_SIG_FORCED, current);
	}
}

/*