linux-kernel.vger.kernel.org archive mirror
 help / color / mirror / Atom feed
* [RFC PATCH v2 0/4] uprobes: return probe implementation
@ 2013-01-09 11:24 Anton Arapov
  2013-01-09 11:24 ` [RFC PATCH v2 1/4] uretprobes/x86: hijack return address Anton Arapov
                   ` (4 more replies)
  0 siblings, 5 replies; 11+ messages in thread
From: Anton Arapov @ 2013-01-09 11:24 UTC (permalink / raw)
  To: Oleg Nesterov, Srikar Dronamraju
  Cc: LKML, Josh Stone, Frank Eigler, Peter Zijlstra, Ingo Molnar,
	Ananth N Mavinakayanahalli, Anton Arapov

There are RFC uretprobes implementation. I'd be grateful for review.

  RFCv1: https://lkml.org/lkml/2012/12/21/133

I've intentionally removed the retprobe bypass logic, it requires 
a bit more work.

not fixed since last prior RFC review:
  unify xol_get_trampoline_slot() and xol_take_insn_slot()
  protect uprobe in prepare_uretprobe()

v2 changes:
  introduced rp_handler(), get rid of return_consumers
  get rid of uretprobe_[un]register()
  introduced arch_uretprobe_get_sp()
  removed uprobe_task->doomed, kill task immediately
  fix arch_uretprobe_hijack_return_addr()'s returns
  address the v1 minor issues

thanks,

Anton Arapov (5):
  uretprobes/x86: hijack return address
  uretprobes: trampoline implementation
  uretprobes: return probe entry, prepare uretprobe
  uretprobes: invoke return probe handlers

 arch/x86/include/asm/uprobes.h |   6 ++
 arch/x86/kernel/uprobes.c      |  48 +++++++++++
 include/linux/uprobes.h        |   9 ++
 kernel/events/uprobes.c        | 181 ++++++++++++++++++++++++++++++++++++++++-
 4 files changed, 241 insertions(+), 3 deletions(-)

-- 
1.8.0.2


^ permalink raw reply	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 1/4] uretprobes/x86: hijack return address
  2013-01-09 11:24 [RFC PATCH v2 0/4] uprobes: return probe implementation Anton Arapov
@ 2013-01-09 11:24 ` Anton Arapov
  2013-01-09 11:24 ` [RFC PATCH v2 2/4] uretprobes: trampoline implementation Anton Arapov
                   ` (3 subsequent siblings)
  4 siblings, 0 replies; 11+ messages in thread
From: Anton Arapov @ 2013-01-09 11:24 UTC (permalink / raw)
  To: Oleg Nesterov, Srikar Dronamraju
  Cc: LKML, Josh Stone, Frank Eigler, Peter Zijlstra, Ingo Molnar,
	Ananth N Mavinakayanahalli, Anton Arapov

Function to hijack the return address, replace it with a "trampoline"
and function to predict the stack pointer address value at return.

v2:
  remove ->doomed flag, kill task immediately

Signed-off-by: Anton Arapov <anton@redhat.com>
---
 arch/x86/include/asm/uprobes.h |  1 +
 arch/x86/kernel/uprobes.c      | 29 +++++++++++++++++++++++++++++
 2 files changed, 30 insertions(+)

diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index 8ff8be7..c353555 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -55,4 +55,5 @@ extern int  arch_uprobe_post_xol(struct arch_uprobe *aup, struct pt_regs *regs);
 extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
 extern int  arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
 extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
+extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long rp_trampoline_vaddr, struct pt_regs *regs);
 #endif	/* _ASM_UPROBES_H */
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index 0ba4cfb..85e2153 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -697,3 +697,32 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
 		send_sig(SIGTRAP, current, 0);
 	return ret;
 }
+
+extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long
+		rp_trampoline_vaddr, struct pt_regs *regs)
+{
+	int rasize, ncopied;
+	unsigned long orig_ret_vaddr = 0; /* clear high bits for 32-bit apps */
+
+	rasize = is_ia32_task() ? 4 : 8;
+	ncopied = copy_from_user(&orig_ret_vaddr, (void __user *)regs->sp, rasize);
+	if (unlikely(ncopied))
+		return 0;
+
+	/* check whether address has been already hijacked */
+	if (orig_ret_vaddr == rp_trampoline_vaddr)
+		return orig_ret_vaddr;
+
+	ncopied = copy_to_user((void __user *)regs->sp, &rp_trampoline_vaddr, rasize);
+	if (unlikely(ncopied)) {
+		if (ncopied != rasize) {
+			printk(KERN_ERR "uretprobe: return address clobbered: "
+					"pid=%d, %%sp=%#lx, %%ip=%#lx\n",
+					current->pid, regs->sp, regs->ip);
+			/* kill task immediately */
+			send_sig(SIGSEGV, current, 0);
+		}
+	}
+
+	return orig_ret_vaddr;
+}
-- 
1.8.0.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 2/4] uretprobes: trampoline implementation
  2013-01-09 11:24 [RFC PATCH v2 0/4] uprobes: return probe implementation Anton Arapov
  2013-01-09 11:24 ` [RFC PATCH v2 1/4] uretprobes/x86: hijack return address Anton Arapov
@ 2013-01-09 11:24 ` Anton Arapov
  2013-01-09 16:13   ` Oleg Nesterov
  2013-01-09 11:24 ` [RFC PATCH v2 3/4] uretprobes: return probe entry, prepare uretprobe Anton Arapov
                   ` (2 subsequent siblings)
  4 siblings, 1 reply; 11+ messages in thread
From: Anton Arapov @ 2013-01-09 11:24 UTC (permalink / raw)
  To: Oleg Nesterov, Srikar Dronamraju
  Cc: LKML, Josh Stone, Frank Eigler, Peter Zijlstra, Ingo Molnar,
	Ananth N Mavinakayanahalli, Anton Arapov

The first time a uprobe with return consumer is hit for a process, a
trampoline slot is obtained in the xol_area and initialized with a
breakpoint instruction. This slot is subsequently used by all
uretprobes.

todo:
  unify with xol_take_insn_slot()

Signed-off-by: Anton Arapov <anton@redhat.com>
---
 include/linux/uprobes.h |  1 +
 kernel/events/uprobes.c | 33 +++++++++++++++++++++++++++++++++
 2 files changed, 34 insertions(+)

diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index 95d0002..bddfad6 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -91,6 +91,7 @@ struct xol_area {
 	 * the vma go away, and we must handle that reasonably gracefully.
 	 */
 	unsigned long 		vaddr;		/* Page(s) of instruction slots */
+	unsigned long		rp_trampoline_vaddr; /* address of trampolines */
 };
 
 struct uprobes_state {
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 473db3f..0ad2ac3 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1208,6 +1208,39 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
 	return xol_vaddr;
 }
 
+/*
+ * xol_get_trampoline_slot - A trampoline slot is obtained the first
+ * time a uprobe with return consumer is hit for a process. Use one
+ * trampoline slot for all probes pertaining to a process, i.e.
+ * one per xol_area.
+ */
+static unsigned long xol_get_trampoline_slot(void)
+{
+	struct xol_area *area;
+	unsigned long offset;
+	uprobe_opcode_t bp_insn = UPROBE_SWBP_INSN;
+	void *vaddr;
+
+	area = get_xol_area();
+	if (!area)
+		return 0;
+
+	if (!area->rp_trampoline_vaddr)
+		area->rp_trampoline_vaddr = xol_take_insn_slot(area);
+
+	if (unlikely(!area->rp_trampoline_vaddr))
+		return 0;
+
+	offset = area->rp_trampoline_vaddr & ~PAGE_MASK;
+	vaddr = kmap_atomic(area->page);
+	memcpy(vaddr + offset, &bp_insn, UPROBE_SWBP_INSN_SIZE);
+	kunmap_atomic(vaddr);
+
+	flush_dcache_page(area->page);
+
+	return area->rp_trampoline_vaddr;
+}
+
 /*
  * xol_free_insn_slot - If slot was earlier allocated by
  * @xol_get_insn_slot(), make the slot available for
-- 
1.8.0.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 3/4] uretprobes: return probe entry, prepare uretprobe
  2013-01-09 11:24 [RFC PATCH v2 0/4] uprobes: return probe implementation Anton Arapov
  2013-01-09 11:24 ` [RFC PATCH v2 1/4] uretprobes/x86: hijack return address Anton Arapov
  2013-01-09 11:24 ` [RFC PATCH v2 2/4] uretprobes: trampoline implementation Anton Arapov
@ 2013-01-09 11:24 ` Anton Arapov
  2013-01-09 16:17   ` Oleg Nesterov
  2013-01-09 11:24 ` [RFC PATCH v2 4/4] uretprobes: invoke return probe handlers Anton Arapov
  2013-01-09 16:12 ` [RFC PATCH v2 0/4] uprobes: return probe implementation Oleg Nesterov
  4 siblings, 1 reply; 11+ messages in thread
From: Anton Arapov @ 2013-01-09 11:24 UTC (permalink / raw)
  To: Oleg Nesterov, Srikar Dronamraju
  Cc: LKML, Josh Stone, Frank Eigler, Peter Zijlstra, Ingo Molnar,
	Ananth N Mavinakayanahalli, Anton Arapov

When a uprobe with return consumer is hit, prepare_uretprobe function is
invoked. It creates return_instance, hijacks return address and replaces
it with the trampoline.

v2:
  get rid of ->return_consumers

todo:
  protect uprobe

Signed-off-by: Anton Arapov <anton@redhat.com>
---
 include/linux/uprobes.h |  4 ++++
 kernel/events/uprobes.c | 48 ++++++++++++++++++++++++++++++++++++++++++++++--
 2 files changed, 50 insertions(+), 2 deletions(-)

diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index bddfad6..cdc4d53 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -68,6 +68,10 @@ struct uprobe_task {
 	enum uprobe_task_state		state;
 	struct arch_uprobe_task		autask;
 
+	/*
+	 * list for tracking uprobes with return consumers
+	 */
+	struct hlist_head		return_uprobes;
 	struct uprobe			*active_uprobe;
 
 	unsigned long			xol_vaddr;
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 0ad2ac3..d6fa497 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -74,6 +74,12 @@ struct uprobe {
 	struct arch_uprobe	arch;
 };
 
+struct return_uprobe_i {
+	struct uprobe		*uprobe;
+	struct hlist_node	hlist;		/* node in list */
+	unsigned long		orig_ret_vaddr; /* original return address */
+};
+
 /*
  * valid_vma: Verify if the specified vma is an executable vma
  * Relax restrictions while unregistering: vm_flags might have
@@ -1327,11 +1333,44 @@ void uprobe_copy_process(struct task_struct *t)
  */
 static struct uprobe_task *get_utask(void)
 {
-	if (!current->utask)
+	if (!current->utask) {
 		current->utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL);
+		INIT_HLIST_HEAD(&current->utask->return_uprobes);
+	}
 	return current->utask;
 }
 
+static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
+{
+	struct return_uprobe_i *ri;
+	struct uprobe_task *utask;
+	struct xol_area *area;
+	unsigned long rp_trampoline_vaddr = 0;
+
+	area = get_xol_area();
+	if (area)
+		rp_trampoline_vaddr = area->rp_trampoline_vaddr;
+	if (!rp_trampoline_vaddr) {
+		rp_trampoline_vaddr = xol_get_trampoline_slot();
+		if (!rp_trampoline_vaddr)
+			return;
+	}
+
+	ri = (struct return_uprobe_i *)kzalloc(sizeof(struct return_uprobe_i),
+			GFP_KERNEL);
+	if (!ri)
+		return;
+
+	utask = get_utask();
+	ri->orig_ret_vaddr = arch_uretprobe_hijack_return_addr(rp_trampoline_vaddr, regs);
+	if (likely(ri->orig_ret_vaddr)) {
+		ri->uprobe = uprobe;
+		INIT_HLIST_NODE(&ri->hlist);
+		hlist_add_head(&ri->hlist, &utask->return_uprobes);
+	} else
+		kfree(ri);
+}
+
 /* Prepare to single-step probed instruction out of line. */
 static int
 pre_ssout(struct uprobe *uprobe, struct pt_regs *regs, unsigned long bp_vaddr)
@@ -1485,12 +1524,17 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
 
 static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
 {
+	int rc = 0;
 	struct uprobe_consumer *uc;
 	int remove = UPROBE_HANDLER_REMOVE;
 
 	down_read(&uprobe->register_rwsem);
 	for (uc = uprobe->consumers; uc; uc = uc->next) {
-		int rc = uc->handler(uc, regs);
+		if (uc->handler)
+			rc = uc->handler(uc, regs);
+
+		if (uc->rp_handler)
+			prepare_uretprobe(uprobe, regs); /* put bp at return */
 
 		WARN(rc & ~UPROBE_HANDLER_MASK,
 			"bad rc=0x%x from %pf()\n", rc, uc->handler);
-- 
1.8.0.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* [RFC PATCH v2 4/4] uretprobes: invoke return probe handlers
  2013-01-09 11:24 [RFC PATCH v2 0/4] uprobes: return probe implementation Anton Arapov
                   ` (2 preceding siblings ...)
  2013-01-09 11:24 ` [RFC PATCH v2 3/4] uretprobes: return probe entry, prepare uretprobe Anton Arapov
@ 2013-01-09 11:24 ` Anton Arapov
  2013-01-09 16:28   ` Oleg Nesterov
  2013-01-09 16:12 ` [RFC PATCH v2 0/4] uprobes: return probe implementation Oleg Nesterov
  4 siblings, 1 reply; 11+ messages in thread
From: Anton Arapov @ 2013-01-09 11:24 UTC (permalink / raw)
  To: Oleg Nesterov, Srikar Dronamraju
  Cc: LKML, Josh Stone, Frank Eigler, Peter Zijlstra, Ingo Molnar,
	Ananth N Mavinakayanahalli, Anton Arapov

uretprobe handlers are invoked when the trampoline is hit, on completion
the trampoline is replaced with the saved return address and the
uretprobe instance deleted.

v2:
  get rid of ->return_consumers
  use rp_handler()

Signed-off-by: Anton Arapov <anton@redhat.com>
---
 arch/x86/include/asm/uprobes.h |  5 ++++
 include/linux/uprobes.h        |  4 +++
 kernel/events/uprobes.c        | 61 +++++++++++++++++++++++++++++++++++++++++-
 3 files changed, 69 insertions(+), 1 deletion(-)

diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h
index c353555..9a605b8 100644
--- a/arch/x86/include/asm/uprobes.h
+++ b/arch/x86/include/asm/uprobes.h
@@ -56,4 +56,9 @@ extern bool arch_uprobe_xol_was_trapped(struct task_struct *tsk);
 extern int  arch_uprobe_exception_notify(struct notifier_block *self, unsigned long val, void *data);
 extern void arch_uprobe_abort_xol(struct arch_uprobe *aup, struct pt_regs *regs);
 extern unsigned long arch_uretprobe_hijack_return_addr(unsigned long rp_trampoline_vaddr, struct pt_regs *regs);
+
+static inline unsigned long arch_uretprobe_get_sp(struct pt_regs *regs)
+{
+	return (unsigned long)regs->sp;
+}
 #endif	/* _ASM_UPROBES_H */
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index cdc4d53..1a229db 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -45,7 +45,11 @@ enum uprobe_filter_ctx {
 };
 
 struct uprobe_consumer {
+	/* probe handler */
 	int (*handler)(struct uprobe_consumer *self, struct pt_regs *regs);
+	/* return probe handler */
+	int (*rp_handler)(struct uprobe_consumer *self, struct pt_regs *regs);
+
 	bool (*filter)(struct uprobe_consumer *self,
 				enum uprobe_filter_ctx ctx,
 				struct mm_struct *mm);
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index d6fa497..8232c29 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1548,6 +1548,57 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
 	up_read(&uprobe->register_rwsem);
 }
 
+static void handler_rp_chain(struct uprobe *uprobe, struct pt_regs *regs)
+{
+	struct uprobe_consumer *uc;
+
+	down_read(&uprobe->register_rwsem);
+	for (uc = uprobe->consumers; uc; uc = uc->next) {
+		if (uc->rp_handler)
+			uc->rp_handler(uc, regs);
+	}
+	up_read(&uprobe->register_rwsem);
+}
+
+static void handle_rp_swbp(struct pt_regs *regs)
+{
+	struct hlist_head *head;
+	struct hlist_node *r1, *r2;
+
+	struct return_uprobe_i *ri;
+	struct uprobe_task *utask;
+
+	struct xol_area *area;
+	unsigned long rp_trampoline_vaddr;
+	unsigned long orig_ret_vaddr, cur_sp;
+
+	cur_sp = arch_uretprobe_get_sp(regs);
+	utask = current->utask;
+	head = &utask->return_uprobes;
+
+	area = get_xol_area();
+	rp_trampoline_vaddr = area->vaddr;
+
+	hlist_for_each_entry_safe(ri, r1, r2, head, hlist) {
+		orig_ret_vaddr = ri->orig_ret_vaddr;
+
+		if (ri->uprobe->consumers) {
+			instruction_pointer_set(regs, orig_ret_vaddr);
+			handler_rp_chain(ri->uprobe, regs);
+		}
+
+		hlist_del(&ri->hlist);
+		kfree(ri);
+
+		if (orig_ret_vaddr != rp_trampoline_vaddr)
+			return;
+	}
+
+	printk(KERN_ERR "uretprobe: no instance with original return address!"
+			" pid/tgid=%d/%d", current->pid, current->tgid);
+	send_sig(SIGSEGV, current, 0);
+}
+
 /*
  * Run handler and ask thread to singlestep.
  * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
@@ -1555,12 +1606,20 @@ static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
 static void handle_swbp(struct pt_regs *regs)
 {
 	struct uprobe *uprobe;
+	struct xol_area *area;
 	unsigned long bp_vaddr;
 	int uninitialized_var(is_swbp);
 
 	bp_vaddr = uprobe_get_swbp_addr(regs);
-	uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
+	area = get_xol_area();
+	if (area) {
+		if (bp_vaddr == area->vaddr) {
+			handle_rp_swbp(regs);
+			return;
+		}
+	}
 
+	uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
 	if (!uprobe) {
 		if (is_swbp > 0) {
 			/* No matching uprobe; signal SIGTRAP. */
-- 
1.8.0.2


^ permalink raw reply related	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 0/4] uprobes: return probe implementation
  2013-01-09 11:24 [RFC PATCH v2 0/4] uprobes: return probe implementation Anton Arapov
                   ` (3 preceding siblings ...)
  2013-01-09 11:24 ` [RFC PATCH v2 4/4] uretprobes: invoke return probe handlers Anton Arapov
@ 2013-01-09 16:12 ` Oleg Nesterov
  4 siblings, 0 replies; 11+ messages in thread
From: Oleg Nesterov @ 2013-01-09 16:12 UTC (permalink / raw)
  To: Anton Arapov
  Cc: Srikar Dronamraju, LKML, Josh Stone, Frank Eigler, Peter Zijlstra,
	Ingo Molnar, Ananth N Mavinakayanahalli

On 01/09, Anton Arapov wrote:
>
> There are RFC uretprobes implementation. I'd be grateful for review.
>
>   RFCv1: https://lkml.org/lkml/2012/12/21/133
>
> I've intentionally removed the retprobe bypass logic, it requires
> a bit more work.

Yes, this is not trivial, lets do this separately.

> not fixed since last prior RFC review:
>   unify xol_get_trampoline_slot() and xol_take_insn_slot()

This was of the reasons for "Do not play with utask in xol_get_insn_slot()"
I sent. After this patch you only need the trivial change

	- static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
	+ static unsigned long xol_get_insn_slot(unsigned char *insn)

and now you do not need xol_get_trampoline_slot().

However. Why do you need it at all? Let me quote myself:

	Or. Perhaps even better, do not add this helper at all. xol_alloc_area()
	could reserve the first slot/bit for trampoline. And note that in this
	case we do not need xol_area->rp_trampoline_vaddr, it is always equal
	to xol_area->vaddr.

?

>   protect uprobe in prepare_uretprobe()

This should be fixed ;)

Oleg.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 2/4] uretprobes: trampoline implementation
  2013-01-09 11:24 ` [RFC PATCH v2 2/4] uretprobes: trampoline implementation Anton Arapov
@ 2013-01-09 16:13   ` Oleg Nesterov
  0 siblings, 0 replies; 11+ messages in thread
From: Oleg Nesterov @ 2013-01-09 16:13 UTC (permalink / raw)
  To: Anton Arapov
  Cc: Srikar Dronamraju, LKML, Josh Stone, Frank Eigler, Peter Zijlstra,
	Ingo Molnar, Ananth N Mavinakayanahalli

On 01/09, Anton Arapov wrote:
>
> The first time a uprobe with return consumer is hit for a process, a
> trampoline slot is obtained in the xol_area and initialized with a
> breakpoint instruction. This slot is subsequently used by all
> uretprobes.

See my reply to 0/4, I think we do not really need this.

> todo:
>   unify with xol_take_insn_slot()
> 
> Signed-off-by: Anton Arapov <anton@redhat.com>
> ---
>  include/linux/uprobes.h |  1 +
>  kernel/events/uprobes.c | 33 +++++++++++++++++++++++++++++++++
>  2 files changed, 34 insertions(+)
> 
> diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
> index 95d0002..bddfad6 100644
> --- a/include/linux/uprobes.h
> +++ b/include/linux/uprobes.h
> @@ -91,6 +91,7 @@ struct xol_area {
>  	 * the vma go away, and we must handle that reasonably gracefully.
>  	 */
>  	unsigned long 		vaddr;		/* Page(s) of instruction slots */
> +	unsigned long		rp_trampoline_vaddr; /* address of trampolines */
>  };
>  
>  struct uprobes_state {
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index 473db3f..0ad2ac3 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -1208,6 +1208,39 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe)
>  	return xol_vaddr;
>  }
>  
> +/*
> + * xol_get_trampoline_slot - A trampoline slot is obtained the first
> + * time a uprobe with return consumer is hit for a process. Use one
> + * trampoline slot for all probes pertaining to a process, i.e.
> + * one per xol_area.
> + */
> +static unsigned long xol_get_trampoline_slot(void)
> +{
> +	struct xol_area *area;
> +	unsigned long offset;
> +	uprobe_opcode_t bp_insn = UPROBE_SWBP_INSN;
> +	void *vaddr;
> +
> +	area = get_xol_area();
> +	if (!area)
> +		return 0;
> +
> +	if (!area->rp_trampoline_vaddr)
> +		area->rp_trampoline_vaddr = xol_take_insn_slot(area);
> +
> +	if (unlikely(!area->rp_trampoline_vaddr))
> +		return 0;
> +
> +	offset = area->rp_trampoline_vaddr & ~PAGE_MASK;
> +	vaddr = kmap_atomic(area->page);
> +	memcpy(vaddr + offset, &bp_insn, UPROBE_SWBP_INSN_SIZE);
> +	kunmap_atomic(vaddr);
> +
> +	flush_dcache_page(area->page);
> +
> +	return area->rp_trampoline_vaddr;
> +}
> +
>  /*
>   * xol_free_insn_slot - If slot was earlier allocated by
>   * @xol_get_insn_slot(), make the slot available for
> -- 
> 1.8.0.2
> 


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 3/4] uretprobes: return probe entry, prepare uretprobe
  2013-01-09 11:24 ` [RFC PATCH v2 3/4] uretprobes: return probe entry, prepare uretprobe Anton Arapov
@ 2013-01-09 16:17   ` Oleg Nesterov
  2013-01-10 11:44     ` Anton Arapov
  0 siblings, 1 reply; 11+ messages in thread
From: Oleg Nesterov @ 2013-01-09 16:17 UTC (permalink / raw)
  To: Anton Arapov
  Cc: Srikar Dronamraju, LKML, Josh Stone, Frank Eigler, Peter Zijlstra,
	Ingo Molnar, Ananth N Mavinakayanahalli

On 01/09, Anton Arapov wrote:
>
> todo:
>   protect uprobe

Yep ;)

>  static struct uprobe_task *get_utask(void)
>  {
> -	if (!current->utask)
> +	if (!current->utask) {
>  		current->utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL);
> +		INIT_HLIST_HEAD(&current->utask->return_uprobes);

What if kzalloc() fails?

> +static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
> +{
> +	struct return_uprobe_i *ri;
> +	struct uprobe_task *utask;
> +	struct xol_area *area;
> +	unsigned long rp_trampoline_vaddr = 0;
> +
> +	area = get_xol_area();
> +	if (area)
> +		rp_trampoline_vaddr = area->rp_trampoline_vaddr;
> +	if (!rp_trampoline_vaddr) {
> +		rp_trampoline_vaddr = xol_get_trampoline_slot();

This is obviously racy. But again, so far I think we can simply remove
this.

>  static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
>  {
> +	int rc = 0;
>  	struct uprobe_consumer *uc;
>  	int remove = UPROBE_HANDLER_REMOVE;
>  
>  	down_read(&uprobe->register_rwsem);
>  	for (uc = uprobe->consumers; uc; uc = uc->next) {
> -		int rc = uc->handler(uc, regs);
> +		if (uc->handler)
> +			rc = uc->handler(uc, regs);
> +
> +		if (uc->rp_handler)
> +			prepare_uretprobe(uprobe, regs); /* put bp at return */

This doesn't look right. prepare_uretprobe() should not be called
multiple times.

Oleg.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 4/4] uretprobes: invoke return probe handlers
  2013-01-09 11:24 ` [RFC PATCH v2 4/4] uretprobes: invoke return probe handlers Anton Arapov
@ 2013-01-09 16:28   ` Oleg Nesterov
  2013-01-10 11:42     ` Anton Arapov
  0 siblings, 1 reply; 11+ messages in thread
From: Oleg Nesterov @ 2013-01-09 16:28 UTC (permalink / raw)
  To: Anton Arapov
  Cc: Srikar Dronamraju, LKML, Josh Stone, Frank Eigler, Peter Zijlstra,
	Ingo Molnar, Ananth N Mavinakayanahalli

On 01/09, Anton Arapov wrote:
>
>  static void handle_swbp(struct pt_regs *regs)
>  {
>  	struct uprobe *uprobe;
> +	struct xol_area *area;
>  	unsigned long bp_vaddr;
>  	int uninitialized_var(is_swbp);
>  
>  	bp_vaddr = uprobe_get_swbp_addr(regs);
> -	uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
> +	area = get_xol_area();

No, we do not need to allocate xol area here.

> +	if (area) {
> +		if (bp_vaddr == area->vaddr) {
> +			handle_rp_swbp(regs);

Can't understand... this should check bp_vaddr == rp_trampoline_vaddr ?

Again, unless you remove rp_trampoline_vaddr altogether.

Oleg.


^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 4/4] uretprobes: invoke return probe handlers
  2013-01-09 16:28   ` Oleg Nesterov
@ 2013-01-10 11:42     ` Anton Arapov
  0 siblings, 0 replies; 11+ messages in thread
From: Anton Arapov @ 2013-01-10 11:42 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Srikar Dronamraju, LKML, Josh Stone, Frank Eigler, Peter Zijlstra,
	Ingo Molnar, Ananth N Mavinakayanahalli

On Wed, Jan 09, 2013 at 05:28:42PM +0100, Oleg Nesterov wrote:
> On 01/09, Anton Arapov wrote:
> >
> >  static void handle_swbp(struct pt_regs *regs)
> >  {
> >  	struct uprobe *uprobe;
> > +	struct xol_area *area;
> >  	unsigned long bp_vaddr;
> >  	int uninitialized_var(is_swbp);
> >  
> >  	bp_vaddr = uprobe_get_swbp_addr(regs);
> > -	uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
> > +	area = get_xol_area();
> 
> No, we do not need to allocate xol area here.
> 
> > +	if (area) {
> > +		if (bp_vaddr == area->vaddr) {
> > +			handle_rp_swbp(regs);
> 
> Can't understand... this should check bp_vaddr == rp_trampoline_vaddr ?
> 
> Again, unless you remove rp_trampoline_vaddr altogether.

yeah, forgot to correct this chunk before I sent it here. I was working on
xol_get_trampoline_slot removal as you suggested.

thanks for valuable comments, seems you are okay with approach to add
rp_handler into uprobe_consumer struct.

Anton.

^ permalink raw reply	[flat|nested] 11+ messages in thread

* Re: [RFC PATCH v2 3/4] uretprobes: return probe entry, prepare uretprobe
  2013-01-09 16:17   ` Oleg Nesterov
@ 2013-01-10 11:44     ` Anton Arapov
  0 siblings, 0 replies; 11+ messages in thread
From: Anton Arapov @ 2013-01-10 11:44 UTC (permalink / raw)
  To: Oleg Nesterov
  Cc: Srikar Dronamraju, LKML, Josh Stone, Frank Eigler, Peter Zijlstra,
	Ingo Molnar, Ananth N Mavinakayanahalli

On Wed, Jan 09, 2013 at 05:17:01PM +0100, Oleg Nesterov wrote:
> On 01/09, Anton Arapov wrote:
> >
> > todo:
> >   protect uprobe
> 
> Yep ;)
> 
> >  static struct uprobe_task *get_utask(void)
> >  {
> > -	if (!current->utask)
> > +	if (!current->utask) {
> >  		current->utask = kzalloc(sizeof(struct uprobe_task), GFP_KERNEL);
> > +		INIT_HLIST_HEAD(&current->utask->return_uprobes);
> 
> What if kzalloc() fails?
:)

> 
> > +static void prepare_uretprobe(struct uprobe *uprobe, struct pt_regs *regs)
> > +{
> > +	struct return_uprobe_i *ri;
> > +	struct uprobe_task *utask;
> > +	struct xol_area *area;
> > +	unsigned long rp_trampoline_vaddr = 0;
> > +
> > +	area = get_xol_area();
> > +	if (area)
> > +		rp_trampoline_vaddr = area->rp_trampoline_vaddr;
> > +	if (!rp_trampoline_vaddr) {
> > +		rp_trampoline_vaddr = xol_get_trampoline_slot();
> 
> This is obviously racy. But again, so far I think we can simply remove
> this.
working on this...

> >  static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> >  {
> > +	int rc = 0;
> >  	struct uprobe_consumer *uc;
> >  	int remove = UPROBE_HANDLER_REMOVE;
> >  
> >  	down_read(&uprobe->register_rwsem);
> >  	for (uc = uprobe->consumers; uc; uc = uc->next) {
> > -		int rc = uc->handler(uc, regs);
> > +		if (uc->handler)
> > +			rc = uc->handler(uc, regs);
> > +
> > +		if (uc->rp_handler)
> > +			prepare_uretprobe(uprobe, regs); /* put bp at return */
> 
> This doesn't look right. prepare_uretprobe() should not be called
> multiple times.
Overlooked this issue, thanks for catching. 

Anton.
> 
> Oleg.
> 

^ permalink raw reply	[flat|nested] 11+ messages in thread

end of thread, other threads:[~2013-01-10 11:44 UTC | newest]

Thread overview: 11+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2013-01-09 11:24 [RFC PATCH v2 0/4] uprobes: return probe implementation Anton Arapov
2013-01-09 11:24 ` [RFC PATCH v2 1/4] uretprobes/x86: hijack return address Anton Arapov
2013-01-09 11:24 ` [RFC PATCH v2 2/4] uretprobes: trampoline implementation Anton Arapov
2013-01-09 16:13   ` Oleg Nesterov
2013-01-09 11:24 ` [RFC PATCH v2 3/4] uretprobes: return probe entry, prepare uretprobe Anton Arapov
2013-01-09 16:17   ` Oleg Nesterov
2013-01-10 11:44     ` Anton Arapov
2013-01-09 11:24 ` [RFC PATCH v2 4/4] uretprobes: invoke return probe handlers Anton Arapov
2013-01-09 16:28   ` Oleg Nesterov
2013-01-10 11:42     ` Anton Arapov
2013-01-09 16:12 ` [RFC PATCH v2 0/4] uprobes: return probe implementation Oleg Nesterov

This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).