uprobes: Do not delete uprobe if uprobe_unregister() fails
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 <oleg@redhat.com> Acked-by: Srikar Dronamraju <srikar@linux.vnet.ibm.com>
This commit is contained in:
Родитель
a5f658b71b
Коммит
076a365b3d
|
@ -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;
|
||||
|
@ -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);
|
||||
}
|
||||
|
||||
/*
|
||||
|
@ -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);
|
||||
|
@ -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);
|
||||
|
|
Загрузка…
Ссылка в новой задаче