Re: [PATCH v1 6/9] uretprobes: Return probe exit, invoke handlers

2013-04-13 Thread Oleg Nesterov
On 04/13, Srikar Dronamraju wrote:
>
> > > Oh yes, this should be documented more explicitly in the changelog of
> > > this patch or 7/9 (which tries to document the limitations but should
> > > be more clear).
> > >
> > > Currently we do not support longjmp() and we assume that the probed
> > > function should do the regular return. We should certainly try to improve
> > > this, but I really think that this should go into the next series.
> > >
> > > Because this is nontrivial, needs more discussion, and I'm afraid should
> > > be per-arch. Even on x86 (which can check the stack) this is not simple,
> > > in general we can't know how to check that (to simplify) the first frame
> > > is already invalid. Just for example, we could check regs->sp and detect
> > > that longjmp() was called but sigaltstack() can easily fool this logic.
> > >
>
> Yes, its perfectly fine to keep this logic for the next patchset.

OK, great.

> Can you tell me why sigaltstack() can fool us if we rely on regs->sp.

Because we can't simply compare resg->sp and ret_instance->sp and decide
if we should ignore this ri or not, the task can hit retprobe, then take
a signal, switch to altstack and hit another rp. I'll write another email
(hopefully patches) later.

> Acked-by: Srikar Dronamraju 

Thanks Srikar.

OK. Everything is acked, I'll send git-pull-request.

Oleg.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v1 6/9] uretprobes: Return probe exit, invoke handlers

2013-04-13 Thread Srikar Dronamraju
* Oleg Nesterov  [2013-04-09 22:13:02]:

> On 04/09, Oleg Nesterov wrote:
> >
> > > Should we a check here before using top most ri.
> > > What if the application had done a longjmp and the trampoline he hit
> > > corresponds to something thats below in the stack?
> > >
> > > Not sure if this what you meant by leaking return instances in your next
> > > patch.
> >
> > Oh yes, this should be documented more explicitly in the changelog of
> > this patch or 7/9 (which tries to document the limitations but should
> > be more clear).
> >
> > Currently we do not support longjmp() and we assume that the probed
> > function should do the regular return. We should certainly try to improve
> > this, but I really think that this should go into the next series.
> >
> > Because this is nontrivial, needs more discussion, and I'm afraid should
> > be per-arch. Even on x86 (which can check the stack) this is not simple,
> > in general we can't know how to check that (to simplify) the first frame
> > is already invalid. Just for example, we could check regs->sp and detect
> > that longjmp() was called but sigaltstack() can easily fool this logic.
> >

Yes, its perfectly fine to keep this logic for the next patchset.
Can you tell me why sigaltstack() can fool us if we rely on regs->sp.
I should admit that I am not too familiar with sigaltstack.

> > Or we can change prepare_uretprobe() to alloc the new slot for the
> > trampoline every time (and mark it as "trampoline" for handle_swbp() of
> > course), this way we can easily discard the invalid ret_instance's in
> > handler_uretprobe(). But this doesn't solve all problems and this is
> > not really nice/simple.
> >
> > In short. I think we should document the limitations more clearly, push
> > this functionality, then try to improve things. Do you agree?
> 
> IOW. Will you agree with v2 below?
> 
> Changes:
> 
>   - s/handler_uretprobe/handle_trampoline/
> 
>   - s/handler_uretprobe_chain/handle_uretprobe_chain/
> 
>   - add the TODO: comments into the changelog and
> handle_trampoline().
> 
> 
> ---
> [PATCH v2] uretprobes: Return probe exit, invoke handlers
> 
> 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.
> 
> TODO: handle_trampoline() assumes that ->return_instances is always valid.
> We should teach it to handle longjmp() which can invalidate the pending
> return_instance's. This is nontrivial, we will try to do this in a separate
> series.
> 
> Signed-off-by: Anton Arapov 
> Signed-off-by: Oleg Nesterov 

Acked-by: Srikar Dronamraju 

> ---
>  kernel/events/uprobes.c |   65 
> ++-
>  1 files changed, 64 insertions(+), 1 deletions(-)
> 
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index e352e18..b9c4325 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -1633,6 +1633,62 @@ static void handler_chain(struct uprobe *uprobe, 
> struct pt_regs *regs)
>   up_read(&uprobe->register_rwsem);
>  }
> 
> +static void
> +handle_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)
> +{
> + struct uprobe *uprobe = ri->uprobe;
> + struct uprobe_consumer *uc;
> +
> + down_read(&uprobe->register_rwsem);
> + for (uc = uprobe->consumers; uc; uc = uc->next) {
> + if (uc->ret_handler)
> + uc->ret_handler(uc, ri->func, regs);
> + }
> + up_read(&uprobe->register_rwsem);
> +}
> +
> +static bool handle_trampoline(struct pt_regs *regs)
> +{
> + struct uprobe_task *utask;
> + struct return_instance *ri, *tmp;
> + bool chained;
> +
> + utask = current->utask;
> + if (!utask)
> + return false;
> +
> + ri = utask->return_instances;
> + if (!ri)
> + return false;
> +
> + /*
> +  * TODO: we should throw out return_instance's invalidated by
> +  * longjmp(), currently we assume that the probed function always
> +  * returns.
> +  */
> + instruction_pointer_set(regs, ri->orig_ret_vaddr);
> +
> + for (;;) {
> + handle_uretprobe_chain(ri, regs);
> +
> + chained = ri->chained;
> + put_uprobe(ri->uprobe);
> +
> + tmp = ri;
> + ri = ri->next;
> + kfree(tmp);
> +
> + if (!chained)
> + break;
> +
> + BUG_ON(!ri);
> + }
> +
> + utask->return_instances = ri;
> +
> + return true;
> +}
> +
>  /*
>   * Run handler and ask thread to singlestep.
>   * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
> @@ -1644,8 +1700,15 @@ static void handle_swbp(struct pt_regs *regs)
>   int uninitialized_var(is_swbp);
> 
>   bp_vaddr = uprobe_get_swbp_addr(regs);
> - uprobe = find_active_uprobe(bp_vaddr, &is_swb

Re: [PATCH v1 6/9] uretprobes: Return probe exit, invoke handlers

2013-04-09 Thread Oleg Nesterov
On 04/09, Oleg Nesterov wrote:
>
> > Should we a check here before using top most ri.
> > What if the application had done a longjmp and the trampoline he hit
> > corresponds to something thats below in the stack?
> >
> > Not sure if this what you meant by leaking return instances in your next
> > patch.
>
> Oh yes, this should be documented more explicitly in the changelog of
> this patch or 7/9 (which tries to document the limitations but should
> be more clear).
>
> Currently we do not support longjmp() and we assume that the probed
> function should do the regular return. We should certainly try to improve
> this, but I really think that this should go into the next series.
>
> Because this is nontrivial, needs more discussion, and I'm afraid should
> be per-arch. Even on x86 (which can check the stack) this is not simple,
> in general we can't know how to check that (to simplify) the first frame
> is already invalid. Just for example, we could check regs->sp and detect
> that longjmp() was called but sigaltstack() can easily fool this logic.
>
> Or we can change prepare_uretprobe() to alloc the new slot for the
> trampoline every time (and mark it as "trampoline" for handle_swbp() of
> course), this way we can easily discard the invalid ret_instance's in
> handler_uretprobe(). But this doesn't solve all problems and this is
> not really nice/simple.
>
> In short. I think we should document the limitations more clearly, push
> this functionality, then try to improve things. Do you agree?

IOW. Will you agree with v2 below?

Changes:

- s/handler_uretprobe/handle_trampoline/

- s/handler_uretprobe_chain/handle_uretprobe_chain/

- add the TODO: comments into the changelog and
  handle_trampoline().


---
[PATCH v2] uretprobes: Return probe exit, invoke handlers

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.

TODO: handle_trampoline() assumes that ->return_instances is always valid.
We should teach it to handle longjmp() which can invalidate the pending
return_instance's. This is nontrivial, we will try to do this in a separate
series.

Signed-off-by: Anton Arapov 
Signed-off-by: Oleg Nesterov 
---
 kernel/events/uprobes.c |   65 ++-
 1 files changed, 64 insertions(+), 1 deletions(-)

diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index e352e18..b9c4325 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1633,6 +1633,62 @@ static void handler_chain(struct uprobe *uprobe, struct 
pt_regs *regs)
up_read(&uprobe->register_rwsem);
 }
 
+static void
+handle_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)
+{
+   struct uprobe *uprobe = ri->uprobe;
+   struct uprobe_consumer *uc;
+
+   down_read(&uprobe->register_rwsem);
+   for (uc = uprobe->consumers; uc; uc = uc->next) {
+   if (uc->ret_handler)
+   uc->ret_handler(uc, ri->func, regs);
+   }
+   up_read(&uprobe->register_rwsem);
+}
+
+static bool handle_trampoline(struct pt_regs *regs)
+{
+   struct uprobe_task *utask;
+   struct return_instance *ri, *tmp;
+   bool chained;
+
+   utask = current->utask;
+   if (!utask)
+   return false;
+
+   ri = utask->return_instances;
+   if (!ri)
+   return false;
+
+   /*
+* TODO: we should throw out return_instance's invalidated by
+* longjmp(), currently we assume that the probed function always
+* returns.
+*/
+   instruction_pointer_set(regs, ri->orig_ret_vaddr);
+
+   for (;;) {
+   handle_uretprobe_chain(ri, regs);
+
+   chained = ri->chained;
+   put_uprobe(ri->uprobe);
+
+   tmp = ri;
+   ri = ri->next;
+   kfree(tmp);
+
+   if (!chained)
+   break;
+
+   BUG_ON(!ri);
+   }
+
+   utask->return_instances = ri;
+
+   return true;
+}
+
 /*
  * Run handler and ask thread to singlestep.
  * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
@@ -1644,8 +1700,15 @@ static void handle_swbp(struct pt_regs *regs)
int uninitialized_var(is_swbp);
 
bp_vaddr = uprobe_get_swbp_addr(regs);
-   uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
+   if (bp_vaddr == get_trampoline_vaddr()) {
+   if (handle_trampoline(regs))
+   return;
 
+   pr_warn("uprobe: unable to handle uretprobe pid/tgid=%d/%d\n",
+   current->pid, current->tgid);
+   }
+
+   uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
if (!uprobe) {
if (is_swbp > 0) {
/* No matchi

Re: [PATCH v1 6/9] uretprobes: Return probe exit, invoke handlers

2013-04-09 Thread Oleg Nesterov
On 04/07, Srikar Dronamraju wrote:
>
> > +static void
> > +handler_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)
>
> > +{
> > +   struct uprobe *uprobe = ri->uprobe;
> > +   struct uprobe_consumer *uc;
> > +
> > +   down_read(&uprobe->register_rwsem);
> > +   for (uc = uprobe->consumers; uc; uc = uc->next) {
> > +   if (uc->ret_handler)
> > +   uc->ret_handler(uc, ri->func, regs);
> > +   }
> > +   up_read(&uprobe->register_rwsem);
> > +}
> > +
> > +static bool handler_uretprobe(struct pt_regs *regs)
>
> Nit: can this be renamed to handle_trampoline

Agreed.

And probably handler_uretprobe_chain() should be ret_handler_chain()
to match handler_chain().

> > +{
> > +   struct uprobe_task *utask;
> > +   struct return_instance *ri, *tmp;
> > +   bool chained;
> > +
> > +   utask = current->utask;
> > +   if (!utask)
> > +   return false;
> > +
> > +   ri = utask->return_instances;
> > +   if (!ri)
> > +   return false;
> > +
> > +   instruction_pointer_set(regs, ri->orig_ret_vaddr);
>
> Should we a check here before using top most ri.
> What if the application had done a longjmp and the trampoline he hit
> corresponds to something thats below in the stack?
>
> Not sure if this what you meant by leaking return instances in your next
> patch.

Oh yes, this should be documented more explicitly in the changelog of
this patch or 7/9 (which tries to document the limitations but should
be more clear).

Currently we do not support longjmp() and we assume that the probed
function should do the regular return. We should certainly try to improve
this, but I really think that this should go into the next series.

Because this is nontrivial, needs more discussion, and I'm afraid should
be per-arch. Even on x86 (which can check the stack) this is not simple,
in general we can't know how to check that (to simplify) the first frame
is already invalid. Just for example, we could check regs->sp and detect
that longjmp() was called but sigaltstack() can easily fool this logic.

Or we can change prepare_uretprobe() to alloc the new slot for the
trampoline every time (and mark it as "trampoline" for handle_swbp() of
course), this way we can easily discard the invalid ret_instance's in
handler_uretprobe(). But this doesn't solve all problems and this is
not really nice/simple.

In short. I think we should document the limitations more clearly, push
this functionality, then try to improve things. Do you agree?

Oleg.

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


Re: [PATCH v1 6/9] uretprobes: Return probe exit, invoke handlers

2013-04-07 Thread Srikar Dronamraju
* Anton Arapov  [2013-04-03 18:00:36]:

> 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.
> 
> v1 changes:
> * pass bp_vaddr to ret_handler()
> * simplify handle_uretprobe()
> 
> RFCv6 changes:
> * rework handle_uretprobe()
> 
> RFCv5 changes:
> * switch to simply linked list ->return_uprobes
> * rework handle_uretprobe()
> 
> RFCv4 changes:
> * check, whether utask is not NULL in handle_uretprobe()
> * get rid of area->rp_trampoline_vaddr
> * minor handle_uretprobe() fixups
> 
> RFCv3 changes:
> * protected uprobe with refcounter. See put_uprobe() in handle_uretprobe()
>   that reflects increment in prepare_uretprobe()
> 
> RFCv2 changes:
> * get rid of ->return_consumers member from struct uprobe, introduce
>   ret_handler() in consumer instead
> 
> Signed-off-by: Anton Arapov 
> ---
>  kernel/events/uprobes.c | 60 
> -
>  1 file changed, 59 insertions(+), 1 deletion(-)
> 
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index 08ecfff..d129c1d 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -1609,6 +1609,57 @@ static void handler_chain(struct uprobe *uprobe, 
> struct pt_regs *regs)
>   up_read(&uprobe->register_rwsem);
>  }
> 
> +static void
> +handler_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)

> +{
> + struct uprobe *uprobe = ri->uprobe;
> + struct uprobe_consumer *uc;
> +
> + down_read(&uprobe->register_rwsem);
> + for (uc = uprobe->consumers; uc; uc = uc->next) {
> + if (uc->ret_handler)
> + uc->ret_handler(uc, ri->func, regs);
> + }
> + up_read(&uprobe->register_rwsem);
> +}
> +
> +static bool handler_uretprobe(struct pt_regs *regs)

Nit: can this be renamed to handle_trampoline

> +{
> + struct uprobe_task *utask;
> + struct return_instance *ri, *tmp;
> + bool chained;
> +
> + utask = current->utask;
> + if (!utask)
> + return false;
> +
> + ri = utask->return_instances;
> + if (!ri)
> + return false;
> +
> + instruction_pointer_set(regs, ri->orig_ret_vaddr);

Should we a check here before using top most ri.
What if the application had done a longjmp and the trampoline he hit
corresponds to something thats below in the stack?

Not sure if this what you meant by leaking return instances in your next
patch.


> +
> + for (;;) {
> + handler_uretprobe_chain(ri, regs);
> +
> + chained = ri->chained;
> + put_uprobe(ri->uprobe);
> +
> + tmp = ri;
> + ri = ri->next;
> + kfree(tmp);
> +
> + if (!chained)
> + break;
> +
> + BUG_ON(!ri);
> + }
> +
> + utask->return_instances = ri;
> +
> + return true;
> +}
> +
>  /*
>   * Run handler and ask thread to singlestep.
>   * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
> @@ -1620,8 +1671,15 @@ static void handle_swbp(struct pt_regs *regs)
>   int uninitialized_var(is_swbp);
> 
>   bp_vaddr = uprobe_get_swbp_addr(regs);
> - uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
> + if (bp_vaddr == get_trampoline_vaddr()) {
> + if (handler_uretprobe(regs))
> + return;
> 
> + pr_warn("uprobe: unable to handle uretprobe pid/tgid=%d/%d\n",
> + current->pid, current->tgid);
> + }
> +
> + uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
>   if (!uprobe) {
>   if (is_swbp > 0) {
>   /* No matching uprobe; signal SIGTRAP. */
> -- 
> 1.8.1.4
> 

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/


[PATCH v1 6/9] uretprobes: Return probe exit, invoke handlers

2013-04-03 Thread 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.

v1 changes:
* pass bp_vaddr to ret_handler()
* simplify handle_uretprobe()

RFCv6 changes:
* rework handle_uretprobe()

RFCv5 changes:
* switch to simply linked list ->return_uprobes
* rework handle_uretprobe()

RFCv4 changes:
* check, whether utask is not NULL in handle_uretprobe()
* get rid of area->rp_trampoline_vaddr
* minor handle_uretprobe() fixups

RFCv3 changes:
* protected uprobe with refcounter. See put_uprobe() in handle_uretprobe()
  that reflects increment in prepare_uretprobe()

RFCv2 changes:
* get rid of ->return_consumers member from struct uprobe, introduce
  ret_handler() in consumer instead

Signed-off-by: Anton Arapov 
---
 kernel/events/uprobes.c | 60 -
 1 file changed, 59 insertions(+), 1 deletion(-)

diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 08ecfff..d129c1d 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -1609,6 +1609,57 @@ static void handler_chain(struct uprobe *uprobe, struct 
pt_regs *regs)
up_read(&uprobe->register_rwsem);
 }
 
+static void
+handler_uretprobe_chain(struct return_instance *ri, struct pt_regs *regs)
+{
+   struct uprobe *uprobe = ri->uprobe;
+   struct uprobe_consumer *uc;
+
+   down_read(&uprobe->register_rwsem);
+   for (uc = uprobe->consumers; uc; uc = uc->next) {
+   if (uc->ret_handler)
+   uc->ret_handler(uc, ri->func, regs);
+   }
+   up_read(&uprobe->register_rwsem);
+}
+
+static bool handler_uretprobe(struct pt_regs *regs)
+{
+   struct uprobe_task *utask;
+   struct return_instance *ri, *tmp;
+   bool chained;
+
+   utask = current->utask;
+   if (!utask)
+   return false;
+
+   ri = utask->return_instances;
+   if (!ri)
+   return false;
+
+   instruction_pointer_set(regs, ri->orig_ret_vaddr);
+
+   for (;;) {
+   handler_uretprobe_chain(ri, regs);
+
+   chained = ri->chained;
+   put_uprobe(ri->uprobe);
+
+   tmp = ri;
+   ri = ri->next;
+   kfree(tmp);
+
+   if (!chained)
+   break;
+
+   BUG_ON(!ri);
+   }
+
+   utask->return_instances = ri;
+
+   return true;
+}
+
 /*
  * Run handler and ask thread to singlestep.
  * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
@@ -1620,8 +1671,15 @@ static void handle_swbp(struct pt_regs *regs)
int uninitialized_var(is_swbp);
 
bp_vaddr = uprobe_get_swbp_addr(regs);
-   uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
+   if (bp_vaddr == get_trampoline_vaddr()) {
+   if (handler_uretprobe(regs))
+   return;
 
+   pr_warn("uprobe: unable to handle uretprobe pid/tgid=%d/%d\n",
+   current->pid, current->tgid);
+   }
+
+   uprobe = find_active_uprobe(bp_vaddr, &is_swbp);
if (!uprobe) {
if (is_swbp > 0) {
/* No matching uprobe; signal SIGTRAP. */
-- 
1.8.1.4

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majord...@vger.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/