Skip to content

Commit

Permalink
uprobes: Do not delete uprobe if uprobe_unregister() fails
Browse files Browse the repository at this point in the history
delete_uprobe() must not be called if register_for_each_vma(false)
fails to remove all breakpoints, __uprobe_unregister() is correct.
The problem is that register_for_each_vma(false) always returns 0
and thus this logic does not work.

1. Change verify_opcode() to return 0 rather than -EINVAL when
   unregister detects the !is_swbp insn, we can treat this case
   as success and currently unregister paths ignore the error
   code anyway.

2. Change remove_breakpoint() to propagate the error code from
   write_opcode().

3. Change register_for_each_vma(is_register => false) to remove
   as much breakpoints as possible but return non-zero if
   remove_breakpoint() fails at least once.

Signed-off-by: Oleg Nesterov <[email protected]>
Acked-by: Srikar Dronamraju <[email protected]>
  • Loading branch information
oleg-nesterov committed Oct 7, 2012
1 parent a5f658b commit 076a365
Showing 1 changed file with 6 additions and 6 deletions.
12 changes: 6 additions & 6 deletions kernel/events/uprobes.c
Original file line number Diff line number Diff line change
Expand Up @@ -203,7 +203,7 @@ static int verify_opcode(struct page *page, unsigned long vaddr, uprobe_opcode_t
return 0;
} else {
if (!is_swbp) /* unregister: was it changed by us? */
return -EINVAL;
return 0;
}

return 1;
Expand Down Expand Up @@ -616,15 +616,15 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm,
return ret;
}

static void
static int
remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr)
{
/* can happen if uprobe_register() fails */
if (!test_bit(MMF_HAS_UPROBES, &mm->flags))
return;
return 0;

set_bit(MMF_RECALC_UPROBES, &mm->flags);
set_orig_insn(&uprobe->arch, mm, vaddr);
return set_orig_insn(&uprobe->arch, mm, vaddr);
}

/*
Expand Down Expand Up @@ -740,7 +740,7 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
struct mm_struct *mm = info->mm;
struct vm_area_struct *vma;

if (err)
if (err && is_register)
goto free;

down_write(&mm->mmap_sem);
Expand All @@ -756,7 +756,7 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
if (is_register)
err = install_breakpoint(uprobe, mm, vma, info->vaddr);
else
remove_breakpoint(uprobe, mm, info->vaddr);
err |= remove_breakpoint(uprobe, mm, info->vaddr);

unlock:
up_write(&mm->mmap_sem);
Expand Down

0 comments on commit 076a365

Please sign in to comment.