Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit c5784de2 authored by Peter Zijlstra's avatar Peter Zijlstra Committed by Ingo Molnar
Browse files

uprobes: Document uprobe_register() vs uprobe_mmap() race



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

Signed-off-by: default avatarPeter Zijlstra <a.p.zijlstra@chello.nl>
Signed-off-by: default avatarOleg Nesterov <oleg@redhat.com>
Cc: Ananth N Mavinakayanahalli <ananth@in.ibm.com>
Cc: Anton Arapov <anton@redhat.com>
Cc: Peter Zijlstra <peterz@infradead.org>
Cc: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
Link: http://lkml.kernel.org/r/20120615154339.GA9591@redhat.com


Signed-off-by: default avatarIngo Molnar <mingo@kernel.org>
parent 7a5bfb66
Loading
Loading
Loading
Loading
+28 −3
Original line number Original line Diff line number Diff line
@@ -44,6 +44,23 @@ static DEFINE_SPINLOCK(uprobes_treelock); /* serialize rbtree access */


#define UPROBES_HASH_SZ	13
#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 */
/* serialize (un)register */
static struct mutex uprobes_mutex[UPROBES_HASH_SZ];
static struct mutex uprobes_mutex[UPROBES_HASH_SZ];


@@ -339,7 +356,9 @@ out:
int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
int __weak set_swbp(struct arch_uprobe *auprobe, struct mm_struct *mm, unsigned long vaddr)
{
{
	int result;
	int result;

	/*
	 * See the comment near uprobes_hash().
	 */
	result = is_swbp_at_addr(mm, vaddr);
	result = is_swbp_at_addr(mm, vaddr);
	if (result == 1)
	if (result == 1)
		return -EEXIST;
		return -EEXIST;
@@ -845,6 +864,10 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)


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


			ret = install_breakpoint(uprobe, vma->vm_mm, vma, vaddr);
			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) {
			if (ret == -EEXIST) {
				ret = 0;
				ret = 0;