diff options
-rw-r--r-- | include/linux/sched.h | 2 | ||||
-rw-r--r-- | include/linux/uprobes.h | 5 | ||||
-rw-r--r-- | kernel/events/uprobes.c | 22 | ||||
-rw-r--r-- | kernel/fork.c | 1 |
4 files changed, 29 insertions, 1 deletions
diff --git a/include/linux/sched.h b/include/linux/sched.h index b8c86648a2f..3667c332e61 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
@@ -446,6 +446,8 @@ extern int get_dumpable(struct mm_struct *mm); | |||
446 | #define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ | 446 | #define MMF_VM_HUGEPAGE 17 /* set when VM_HUGEPAGE is set on vma */ |
447 | #define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ | 447 | #define MMF_EXE_FILE_CHANGED 18 /* see prctl_set_mm_exe_file() */ |
448 | 448 | ||
449 | #define MMF_HAS_UPROBES 19 /* might have uprobes */ | ||
450 | |||
449 | #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) | 451 | #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) |
450 | 452 | ||
451 | struct sighand_struct { | 453 | struct sighand_struct { |
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 03ae547c1c3..4a37ab15324 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h | |||
@@ -108,6 +108,7 @@ extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_con | |||
108 | extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); | 108 | extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); |
109 | extern int uprobe_mmap(struct vm_area_struct *vma); | 109 | extern int uprobe_mmap(struct vm_area_struct *vma); |
110 | extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); | 110 | extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); |
111 | extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); | ||
111 | extern void uprobe_free_utask(struct task_struct *t); | 112 | extern void uprobe_free_utask(struct task_struct *t); |
112 | extern void uprobe_copy_process(struct task_struct *t); | 113 | extern void uprobe_copy_process(struct task_struct *t); |
113 | extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); | 114 | extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); |
@@ -138,6 +139,10 @@ static inline void | |||
138 | uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) | 139 | uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) |
139 | { | 140 | { |
140 | } | 141 | } |
142 | static inline void | ||
143 | uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) | ||
144 | { | ||
145 | } | ||
141 | static inline void uprobe_notify_resume(struct pt_regs *regs) | 146 | static inline void uprobe_notify_resume(struct pt_regs *regs) |
142 | { | 147 | { |
143 | } | 148 | } |
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 3e2996b809b..33870b17e1d 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
@@ -647,6 +647,7 @@ static int | |||
647 | install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | 647 | install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, |
648 | struct vm_area_struct *vma, unsigned long vaddr) | 648 | struct vm_area_struct *vma, unsigned long vaddr) |
649 | { | 649 | { |
650 | bool first_uprobe; | ||
650 | int ret; | 651 | int ret; |
651 | 652 | ||
652 | /* | 653 | /* |
@@ -678,7 +679,17 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
678 | uprobe->flags |= UPROBE_COPY_INSN; | 679 | uprobe->flags |= UPROBE_COPY_INSN; |
679 | } | 680 | } |
680 | 681 | ||
682 | /* | ||
683 | * set MMF_HAS_UPROBES in advance for uprobe_pre_sstep_notifier(), | ||
684 | * the task can hit this breakpoint right after __replace_page(). | ||
685 | */ | ||
686 | first_uprobe = !test_bit(MMF_HAS_UPROBES, &mm->flags); | ||
687 | if (first_uprobe) | ||
688 | set_bit(MMF_HAS_UPROBES, &mm->flags); | ||
689 | |||
681 | ret = set_swbp(&uprobe->arch, mm, vaddr); | 690 | ret = set_swbp(&uprobe->arch, mm, vaddr); |
691 | if (ret && first_uprobe) | ||
692 | clear_bit(MMF_HAS_UPROBES, &mm->flags); | ||
682 | 693 | ||
683 | return ret; | 694 | return ret; |
684 | } | 695 | } |
@@ -1032,6 +1043,9 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon | |||
1032 | if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */ | 1043 | if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */ |
1033 | return; | 1044 | return; |
1034 | 1045 | ||
1046 | if (!test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags)) | ||
1047 | return; | ||
1048 | |||
1035 | /* TODO: unmapping uprobe(s) will need more work */ | 1049 | /* TODO: unmapping uprobe(s) will need more work */ |
1036 | } | 1050 | } |
1037 | 1051 | ||
@@ -1142,6 +1156,12 @@ void uprobe_reset_state(struct mm_struct *mm) | |||
1142 | mm->uprobes_state.xol_area = NULL; | 1156 | mm->uprobes_state.xol_area = NULL; |
1143 | } | 1157 | } |
1144 | 1158 | ||
1159 | void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) | ||
1160 | { | ||
1161 | if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) | ||
1162 | set_bit(MMF_HAS_UPROBES, &newmm->flags); | ||
1163 | } | ||
1164 | |||
1145 | /* | 1165 | /* |
1146 | * - search for a free slot. | 1166 | * - search for a free slot. |
1147 | */ | 1167 | */ |
@@ -1507,7 +1527,7 @@ int uprobe_pre_sstep_notifier(struct pt_regs *regs) | |||
1507 | { | 1527 | { |
1508 | struct uprobe_task *utask; | 1528 | struct uprobe_task *utask; |
1509 | 1529 | ||
1510 | if (!current->mm) | 1530 | if (!current->mm || !test_bit(MMF_HAS_UPROBES, ¤t->mm->flags)) |
1511 | return 0; | 1531 | return 0; |
1512 | 1532 | ||
1513 | utask = current->utask; | 1533 | utask = current->utask; |
diff --git a/kernel/fork.c b/kernel/fork.c index 912b6f6fe5b..cbb5f9fcd3e 100644 --- a/kernel/fork.c +++ b/kernel/fork.c | |||
@@ -353,6 +353,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm) | |||
353 | 353 | ||
354 | down_write(&oldmm->mmap_sem); | 354 | down_write(&oldmm->mmap_sem); |
355 | flush_cache_dup_mm(oldmm); | 355 | flush_cache_dup_mm(oldmm); |
356 | uprobe_dup_mmap(oldmm, mm); | ||
356 | /* | 357 | /* |
357 | * Not linked in yet - no deadlock potential: | 358 | * Not linked in yet - no deadlock potential: |
358 | */ | 359 | */ |