All of lore.kernel.org
 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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.