From: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
To: Oleg Nesterov <oleg@redhat.com>
Cc: Ingo Molnar <mingo@elte.hu>,
Peter Zijlstra <peterz@infradead.org>,
Ananth N Mavinakayanahalli <ananth@in.ibm.com>,
Anton Arapov <anton@redhat.com>, Frank Eigler <fche@redhat.com>,
Josh Stone <jistone@redhat.com>,
"Suzuki K. Poulose" <suzuki@in.ibm.com>,
linux-kernel@vger.kernel.org
Subject: Re: [PATCH 1/1] uprobes: Teach handler_chain() to filter out the probed task
Date: Tue, 8 Jan 2013 16:48:14 +0530 [thread overview]
Message-ID: <20130108111814.GA1325@linux.vnet.ibm.com> (raw)
In-Reply-To: <20121229173614.GA2154@redhat.com>
* Oleg Nesterov <oleg@redhat.com> [2012-12-29 18:36:14]:
> Currrently the are 2 problems with pre-filtering:
>
> 1. It is not possible to add/remove a task (mm) after uprobe_register()
>
> 2. A forked child inherits all breakpoints and uprobe_consumer can not
> control this.
>
> This patch does the first step to improve the filtering. handler_chain()
> removes the breakpoints installed by this uprobe from current->mm if all
> handlers return UPROBE_HANDLER_REMOVE.
>
I am thinking of tid based filter, If let say a tracer is just
interested in a particular thread of a process, should such a hanlder
always return 0.
In general, does this mean if the handler is not interested for this
particular task, but not sure if other tasks in the same process could
be interested, then such a handler should always return 0?
If yes, should we document it (either in handler_chain() or
near uprobe_consumer definition)
> Note that handler_chain() relies on ->register_rwsem to avoid the race
> with uprobe_register/unregister which can add/del a consumer, or even
> remove and then insert the new uprobe at the same address.
>
> Perhaps we will add uprobe_apply_mm(uprobe, mm, is_register) and teach
> copy_mm() to do filter(UPROBE_FILTER_FORK), but I think this change makes
> sense anyway.
>
> Note: instead of checking the retcode from uc->handler, we could add
> uc->filter(UPROBE_FILTER_BPHIT). But I think this is not optimal to
> call 2 hooks in a row. This buys nothing, and if handler/filter do
> something nontrivial they will probably do the same work twice.
I was for having the filter called explicitly. But I am okay with it
being called internally by the handler. My only small concern was
- Given that we have an explicit filter, handlers (or folks writing
handlers can misunderstand and miss filtering assuming that handlers
would be called after filtering.
VG
> Signed-off-by: Oleg Nesterov <oleg@redhat.com>
> ---
> include/linux/uprobes.h | 3 ++
> kernel/events/uprobes.c | 58 ++++++++++++++++++++++++++++++++++++++--------
> 2 files changed, 51 insertions(+), 10 deletions(-)
>
> diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
> index c2df693..95d0002 100644
> --- a/include/linux/uprobes.h
> +++ b/include/linux/uprobes.h
> @@ -35,6 +35,9 @@ struct inode;
> # include <asm/uprobes.h>
> #endif
>
> +#define UPROBE_HANDLER_REMOVE 1
> +#define UPROBE_HANDLER_MASK 1
> +
> enum uprobe_filter_ctx {
> UPROBE_FILTER_REGISTER,
> UPROBE_FILTER_UNREGISTER,
> diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
> index e2ebb6f..59b6e97 100644
> --- a/kernel/events/uprobes.c
> +++ b/kernel/events/uprobes.c
> @@ -440,16 +440,6 @@ static struct uprobe *alloc_uprobe(struct inode *inode, loff_t offset)
> return uprobe;
> }
>
> -static void handler_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)
> - uc->handler(uc, regs);
> - up_read(&uprobe->register_rwsem);
> -}
> -
> static void consumer_add(struct uprobe *uprobe, struct uprobe_consumer *uc)
> {
> down_write(&uprobe->consumer_rwsem);
> @@ -882,6 +872,33 @@ void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consume
> put_uprobe(uprobe);
> }
>
> +static int unapply_uprobe(struct uprobe *uprobe, struct mm_struct *mm)
> +{
> + struct vm_area_struct *vma;
> + int err = 0;
> +
> + down_read(&mm->mmap_sem);
> + for (vma = mm->mmap; vma; vma = vma->vm_next) {
> + unsigned long vaddr;
> + loff_t offset;
> +
> + if (!valid_vma(vma, false) ||
> + vma->vm_file->f_mapping->host != uprobe->inode)
> + continue;
> +
> + offset = (loff_t)vma->vm_pgoff << PAGE_SHIFT;
> + if (uprobe->offset < offset ||
> + uprobe->offset >= offset + vma->vm_end - vma->vm_start)
> + continue;
> +
> + vaddr = offset_to_vaddr(vma, uprobe->offset);
> + err |= remove_breakpoint(uprobe, mm, vaddr);
> + }
> + up_read(&mm->mmap_sem);
> +
> + return err;
> +}
> +
> static struct rb_node *
> find_node_in_range(struct inode *inode, loff_t min, loff_t max)
> {
> @@ -1435,6 +1452,27 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
> return uprobe;
> }
>
> +static void handler_chain(struct uprobe *uprobe, struct pt_regs *regs)
> +{
> + 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);
> +
> + WARN(rc & ~UPROBE_HANDLER_MASK,
> + "bad rc=0x%x from %pf()\n", rc, uc->handler);
Is this warning required?
> + remove &= rc;
> + }
> +
> + if (remove && uprobe->consumers) {
> + WARN_ON(!uprobe_is_active(uprobe));
> + unapply_uprobe(uprobe, current->mm);
> + }
> + up_read(&uprobe->register_rwsem);
> +}
> +
The rest looks good.
--
Thanks and Regards
Srikar
next prev parent reply other threads:[~2013-01-08 11:18 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2012-12-29 17:35 [PATCH 0/1] uprobes: Teach handler_chain() to filter out the probed task Oleg Nesterov
2012-12-29 17:36 ` [PATCH 1/1] " Oleg Nesterov
2013-01-08 11:18 ` Srikar Dronamraju [this message]
2013-01-08 19:00 ` Oleg Nesterov
2013-01-09 17:39 ` Srikar Dronamraju
2013-01-09 18:13 ` Oleg Nesterov
2013-01-10 5:35 ` Srikar Dronamraju
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20130108111814.GA1325@linux.vnet.ibm.com \
--to=srikar@linux.vnet.ibm.com \
--cc=ananth@in.ibm.com \
--cc=anton@redhat.com \
--cc=fche@redhat.com \
--cc=jistone@redhat.com \
--cc=linux-kernel@vger.kernel.org \
--cc=mingo@elte.hu \
--cc=oleg@redhat.com \
--cc=peterz@infradead.org \
--cc=suzuki@in.ibm.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).