diff options
-rw-r--r-- | kernel/events/uprobes.c | 73 |
1 files changed, 24 insertions, 49 deletions
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 9248ee76b4bb..6136854da6c6 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -282,32 +282,6 @@ put_old: | |||
282 | return ret; | 282 | return ret; |
283 | } | 283 | } |
284 | 284 | ||
285 | static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) | ||
286 | { | ||
287 | struct page *page; | ||
288 | uprobe_opcode_t opcode; | ||
289 | int result; | ||
290 | |||
291 | if (current->mm == mm) { | ||
292 | pagefault_disable(); | ||
293 | result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr, | ||
294 | sizeof(opcode)); | ||
295 | pagefault_enable(); | ||
296 | |||
297 | if (likely(result == 0)) | ||
298 | goto out; | ||
299 | } | ||
300 | |||
301 | result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); | ||
302 | if (result < 0) | ||
303 | return result; | ||
304 | |||
305 | copy_opcode(page, vaddr, &opcode); | ||
306 | put_page(page); | ||
307 | out: | ||
308 | return is_swbp_insn(&opcode); | ||
309 | } | ||
310 | |||
311 | /** | 285 | /** |
312 | * set_swbp - store breakpoint at a given address. | 286 | * set_swbp - store breakpoint at a given address. |
313 | * @auprobe: arch specific probepoint information. | 287 | * @auprobe: arch specific probepoint information. |
@@ -589,29 +563,6 @@ static int copy_insn(struct uprobe *uprobe, struct file *filp) | |||
589 | return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset); | 563 | return __copy_insn(mapping, filp, uprobe->arch.insn, bytes, uprobe->offset); |
590 | } | 564 | } |
591 | 565 | ||
592 | /* | ||
593 | * How mm->uprobes_state.count gets updated | ||
594 | * uprobe_mmap() increments the count if | ||
595 | * - it successfully adds a breakpoint. | ||
596 | * - it cannot add a breakpoint, but sees that there is a underlying | ||
597 | * breakpoint (via a is_swbp_at_addr()). | ||
598 | * | ||
599 | * uprobe_munmap() decrements the count if | ||
600 | * - it sees a underlying breakpoint, (via is_swbp_at_addr) | ||
601 | * (Subsequent uprobe_unregister wouldnt find the breakpoint | ||
602 | * unless a uprobe_mmap kicks in, since the old vma would be | ||
603 | * dropped just after uprobe_munmap.) | ||
604 | * | ||
605 | * uprobe_register increments the count if: | ||
606 | * - it successfully adds a breakpoint. | ||
607 | * | ||
608 | * uprobe_unregister decrements the count if: | ||
609 | * - it sees a underlying breakpoint and removes successfully. | ||
610 | * (via is_swbp_at_addr) | ||
611 | * (Subsequent uprobe_munmap wouldnt find the breakpoint | ||
612 | * since there is no underlying breakpoint after the | ||
613 | * breakpoint removal.) | ||
614 | */ | ||
615 | static int | 566 | static int |
616 | install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | 567 | install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, |
617 | struct vm_area_struct *vma, unsigned long vaddr) | 568 | struct vm_area_struct *vma, unsigned long vaddr) |
@@ -1389,6 +1340,30 @@ static void mmf_recalc_uprobes(struct mm_struct *mm) | |||
1389 | clear_bit(MMF_HAS_UPROBES, &mm->flags); | 1340 | clear_bit(MMF_HAS_UPROBES, &mm->flags); |
1390 | } | 1341 | } |
1391 | 1342 | ||
1343 | static int is_swbp_at_addr(struct mm_struct *mm, unsigned long vaddr) | ||
1344 | { | ||
1345 | struct page *page; | ||
1346 | uprobe_opcode_t opcode; | ||
1347 | int result; | ||
1348 | |||
1349 | pagefault_disable(); | ||
1350 | result = __copy_from_user_inatomic(&opcode, (void __user*)vaddr, | ||
1351 | sizeof(opcode)); | ||
1352 | pagefault_enable(); | ||
1353 | |||
1354 | if (likely(result == 0)) | ||
1355 | goto out; | ||
1356 | |||
1357 | result = get_user_pages(NULL, mm, vaddr, 1, 0, 1, &page, NULL); | ||
1358 | if (result < 0) | ||
1359 | return result; | ||
1360 | |||
1361 | copy_opcode(page, vaddr, &opcode); | ||
1362 | put_page(page); | ||
1363 | out: | ||
1364 | return is_swbp_insn(&opcode); | ||
1365 | } | ||
1366 | |||
1392 | static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) | 1367 | static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) |
1393 | { | 1368 | { |
1394 | struct mm_struct *mm = current->mm; | 1369 | struct mm_struct *mm = current->mm; |