* [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
* 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
* [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(¤t->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
* 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(¤t->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 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(¤t->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
* [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 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 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