Login | Register For Free | Help
Search for: (Advanced)

Mailing List Archive: Linux: Kernel

[PATCH 3/3] uprobes: document uprobe_register() vs uprobe_mmap() race

 

 

Linux kernel RSS feed   Index | Next | Previous | View Threaded


oleg at redhat

Jun 4, 2012, 7:53 AM

Post #1 of 3 (42 views)
Permalink
[PATCH 3/3] uprobes: document uprobe_register() vs uprobe_mmap() race

From: Peter Zijlstra <a.p.zijlstra [at] chello>

Because the mind is treacherous and makes us forget we need to write
stuff down.

Signed-off-by: Peter Zijlstra <a.p.zijlstra [at] chello>
Signed-off-by: Oleg Nesterov <oleg [at] redhat>
---
kernel/events/uprobes.c | 31 ++++++++++++++++++++++++++++---
1 files changed, 28 insertions(+), 3 deletions(-)

diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index c9836ae..87a47c6 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -44,6 +44,23 @@ static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */

#define UPROBES_HASH_SZ 13

+/*
+ * We need separate register/unregister and mmap/munmap lock hashes because
+ * of mmap_sem nesting.
+ *
+ * uprobe_register() needs to install probes on (potentially) all processes
+ * and thus needs to acquire multiple mmap_sems (consequtively, not
+ * concurrently), whereas uprobe_mmap() is called while holding mmap_sem
+ * for the particular process doing the mmap.
+ *
+ * uprobe_register()->register_for_each_vma() needs to drop/acquire mmap_sem
+ * because of lock order against i_mmap_mutex. This means there's a hole in
+ * the register vma iteration where a mmap() can happen.
+ *
+ * Thus uprobe_register() can race with uprobe_mmap() and we can try and
+ * install a probe where one is already installed.
+ */
+
/* serialize (un)register */
static struct mutex uprobes_mutex[UPROBES_HASH_SZ];

@@ -353,7 +370,9 @@ out:
int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
{
int result;
-
+ /*
+ * See the comment near uprobes_hash().
+ */
result = is_swbp_at_addr(mm, vaddr);
if (result == 1)
return -EEXIST;
@@ -850,6 +869,10 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)

if (is_register) {
err = install_breakpoint(uprobe, mm, vma, info->vaddr);
+ /*
+ * We can race against uprobe_register(), see the
+ * comment near uprobe_hash().
+ */
if (err == -EEXIST)
err = 0;
} else {
@@ -1058,8 +1081,10 @@ int uprobe_mmap(struct vm_area_struct *vma)
}

ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
-
- /* Ignore double add: */
+ /*
+ * We can race against uprobe_register(), see the
+ * comment near uprobe_hash().
+ */
if (ret == -EEXIST) {
ret = 0;

--
1.5.5.1


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


peterz at infradead

Jun 4, 2012, 8:00 AM

Post #2 of 3 (43 views)
Permalink
Re: [PATCH 3/3] uprobes: document uprobe_register() vs uprobe_mmap() race [In reply to]

On Mon, 2012-06-04 at 16:53 +0200, Oleg Nesterov wrote:

I didn't check if its my error or not, however:

> @@ -850,6 +869,10 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
>
> if (is_register) {
> err = install_breakpoint(uprobe, mm, vma, info->vaddr);
> + /*
> + * We can race against uprobe_register(), see the

that should be uprobe_mmap(), since this is the register path ;-)

> + * comment near uprobe_hash().
> + */
> if (err == -EEXIST)
> err = 0;
> } else {
> @@ -1058,8 +1081,10 @@ int uprobe_mmap(struct vm_area_struct *vma)
> }
>
> ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
> -
> - /* Ignore double add: */
> + /*
> + * We can race against uprobe_register(), see the
> + * comment near uprobe_hash().
> + */
> if (ret == -EEXIST) {
> ret = 0;
>

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


oleg at redhat

Jun 4, 2012, 8:40 AM

Post #3 of 3 (42 views)
Permalink
Re: [PATCH 3/3] uprobes: document uprobe_register() vs uprobe_mmap() race [In reply to]

On 06/04, Peter Zijlstra wrote:
>
> On Mon, 2012-06-04 at 16:53 +0200, Oleg Nesterov wrote:
>
> I didn't check if its my error or not, however:
>
> > @@ -850,6 +869,10 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
> >
> > if (is_register) {
> > err = install_breakpoint(uprobe, mm, vma, info->vaddr);
> > + /*
> > + * We can race against uprobe_register(), see the
>
> that should be uprobe_mmap(), since this is the register path ;-)

Oops. Fixed. 2/2 is also changed as you suggested.

I'll wait a bit to collect more comments/reviews and resend.

Thanks!

Oleg.

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

Linux kernel RSS feed   Index | Next | Previous | View Threaded
 
 


Interested in having your list archived? Contact Gossamer Threads
 
  Web Applications & Managed Hosting Powered by Gossamer Threads Inc.