diff options
| author | Ingo Molnar <mingo@kernel.org> | 2012-09-19 11:03:07 -0400 |
|---|---|---|
| committer | Ingo Molnar <mingo@kernel.org> | 2012-09-19 11:03:07 -0400 |
| commit | d0616c1775035496fb355248d296fb16ea7fb235 (patch) | |
| tree | 7a6cbefa1ba8ed3fd1e03d3267b196d074c47279 | |
| parent | bea8f35421628266658c14ea990d18b0969c4c0b (diff) | |
| parent | baedbf02b1912225d60dd7403acb4b4e003088b5 (diff) | |
Merge branch 'uprobes/core' of git://git.kernel.org/pub/scm/linux/kernel/git/oleg/misc into perf/core
Pull uprobes fixes + cleanups from Oleg Nesterov.
Signed-off-by: Ingo Molnar <mingo@kernel.org>
| -rw-r--r-- | arch/x86/include/asm/processor.h | 2 | ||||
| -rw-r--r-- | arch/x86/include/asm/uprobes.h | 3 | ||||
| -rw-r--r-- | arch/x86/kernel/step.c | 53 | ||||
| -rw-r--r-- | arch/x86/kernel/uprobes.c | 52 | ||||
| -rw-r--r-- | include/linux/sched.h | 3 | ||||
| -rw-r--r-- | include/linux/uprobes.h | 2 | ||||
| -rw-r--r-- | kernel/events/uprobes.c | 99 |
7 files changed, 171 insertions, 43 deletions
diff --git a/arch/x86/include/asm/processor.h b/arch/x86/include/asm/processor.h index d048cad9bcad..433d2e5c98a7 100644 --- a/arch/x86/include/asm/processor.h +++ b/arch/x86/include/asm/processor.h | |||
| @@ -759,6 +759,8 @@ static inline void update_debugctlmsr(unsigned long debugctlmsr) | |||
| 759 | wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); | 759 | wrmsrl(MSR_IA32_DEBUGCTLMSR, debugctlmsr); |
| 760 | } | 760 | } |
| 761 | 761 | ||
| 762 | extern void set_task_blockstep(struct task_struct *task, bool on); | ||
| 763 | |||
| 762 | /* | 764 | /* |
| 763 | * from system description table in BIOS. Mostly for MCA use, but | 765 | * from system description table in BIOS. Mostly for MCA use, but |
| 764 | * others may find it useful: | 766 | * others may find it useful: |
diff --git a/arch/x86/include/asm/uprobes.h b/arch/x86/include/asm/uprobes.h index f3971bbcd1de..8ff8be7835ab 100644 --- a/arch/x86/include/asm/uprobes.h +++ b/arch/x86/include/asm/uprobes.h | |||
| @@ -42,10 +42,11 @@ struct arch_uprobe { | |||
| 42 | }; | 42 | }; |
| 43 | 43 | ||
| 44 | struct arch_uprobe_task { | 44 | struct arch_uprobe_task { |
| 45 | unsigned long saved_trap_nr; | ||
| 46 | #ifdef CONFIG_X86_64 | 45 | #ifdef CONFIG_X86_64 |
| 47 | unsigned long saved_scratch_register; | 46 | unsigned long saved_scratch_register; |
| 48 | #endif | 47 | #endif |
| 48 | unsigned int saved_trap_nr; | ||
| 49 | unsigned int saved_tf; | ||
| 49 | }; | 50 | }; |
| 50 | 51 | ||
| 51 | extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); | 52 | extern int arch_uprobe_analyze_insn(struct arch_uprobe *aup, struct mm_struct *mm, unsigned long addr); |
diff --git a/arch/x86/kernel/step.c b/arch/x86/kernel/step.c index c346d1161488..cd3b2438a980 100644 --- a/arch/x86/kernel/step.c +++ b/arch/x86/kernel/step.c | |||
| @@ -157,6 +157,33 @@ static int enable_single_step(struct task_struct *child) | |||
| 157 | return 1; | 157 | return 1; |
| 158 | } | 158 | } |
| 159 | 159 | ||
| 160 | void set_task_blockstep(struct task_struct *task, bool on) | ||
| 161 | { | ||
| 162 | unsigned long debugctl; | ||
| 163 | |||
| 164 | /* | ||
| 165 | * Ensure irq/preemption can't change debugctl in between. | ||
| 166 | * Note also that both TIF_BLOCKSTEP and debugctl should | ||
| 167 | * be changed atomically wrt preemption. | ||
| 168 | * FIXME: this means that set/clear TIF_BLOCKSTEP is simply | ||
| 169 | * wrong if task != current, SIGKILL can wakeup the stopped | ||
| 170 | * tracee and set/clear can play with the running task, this | ||
| 171 | * can confuse the next __switch_to_xtra(). | ||
| 172 | */ | ||
| 173 | local_irq_disable(); | ||
| 174 | debugctl = get_debugctlmsr(); | ||
| 175 | if (on) { | ||
| 176 | debugctl |= DEBUGCTLMSR_BTF; | ||
| 177 | set_tsk_thread_flag(task, TIF_BLOCKSTEP); | ||
| 178 | } else { | ||
| 179 | debugctl &= ~DEBUGCTLMSR_BTF; | ||
| 180 | clear_tsk_thread_flag(task, TIF_BLOCKSTEP); | ||
| 181 | } | ||
| 182 | if (task == current) | ||
| 183 | update_debugctlmsr(debugctl); | ||
| 184 | local_irq_enable(); | ||
| 185 | } | ||
| 186 | |||
| 160 | /* | 187 | /* |
| 161 | * Enable single or block step. | 188 | * Enable single or block step. |
| 162 | */ | 189 | */ |
| @@ -169,19 +196,10 @@ static void enable_step(struct task_struct *child, bool block) | |||
| 169 | * So no one should try to use debugger block stepping in a program | 196 | * So no one should try to use debugger block stepping in a program |
| 170 | * that uses user-mode single stepping itself. | 197 | * that uses user-mode single stepping itself. |
| 171 | */ | 198 | */ |
| 172 | if (enable_single_step(child) && block) { | 199 | if (enable_single_step(child) && block) |
| 173 | unsigned long debugctl = get_debugctlmsr(); | 200 | set_task_blockstep(child, true); |
| 174 | 201 | else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) | |
| 175 | debugctl |= DEBUGCTLMSR_BTF; | 202 | set_task_blockstep(child, false); |
| 176 | update_debugctlmsr(debugctl); | ||
| 177 | set_tsk_thread_flag(child, TIF_BLOCKSTEP); | ||
| 178 | } else if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { | ||
| 179 | unsigned long debugctl = get_debugctlmsr(); | ||
| 180 | |||
| 181 | debugctl &= ~DEBUGCTLMSR_BTF; | ||
| 182 | update_debugctlmsr(debugctl); | ||
| 183 | clear_tsk_thread_flag(child, TIF_BLOCKSTEP); | ||
| 184 | } | ||
| 185 | } | 203 | } |
| 186 | 204 | ||
| 187 | void user_enable_single_step(struct task_struct *child) | 205 | void user_enable_single_step(struct task_struct *child) |
| @@ -199,13 +217,8 @@ void user_disable_single_step(struct task_struct *child) | |||
| 199 | /* | 217 | /* |
| 200 | * Make sure block stepping (BTF) is disabled. | 218 | * Make sure block stepping (BTF) is disabled. |
| 201 | */ | 219 | */ |
| 202 | if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) { | 220 | if (test_tsk_thread_flag(child, TIF_BLOCKSTEP)) |
| 203 | unsigned long debugctl = get_debugctlmsr(); | 221 | set_task_blockstep(child, false); |
| 204 | |||
| 205 | debugctl &= ~DEBUGCTLMSR_BTF; | ||
| 206 | update_debugctlmsr(debugctl); | ||
| 207 | clear_tsk_thread_flag(child, TIF_BLOCKSTEP); | ||
| 208 | } | ||
| 209 | 222 | ||
| 210 | /* Always clear TIF_SINGLESTEP... */ | 223 | /* Always clear TIF_SINGLESTEP... */ |
| 211 | clear_tsk_thread_flag(child, TIF_SINGLESTEP); | 224 | clear_tsk_thread_flag(child, TIF_SINGLESTEP); |
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c index 36fd42091fa7..9538f00827a9 100644 --- a/arch/x86/kernel/uprobes.c +++ b/arch/x86/kernel/uprobes.c | |||
| @@ -41,6 +41,9 @@ | |||
| 41 | /* Adjust the return address of a call insn */ | 41 | /* Adjust the return address of a call insn */ |
| 42 | #define UPROBE_FIX_CALL 0x2 | 42 | #define UPROBE_FIX_CALL 0x2 |
| 43 | 43 | ||
| 44 | /* Instruction will modify TF, don't change it */ | ||
| 45 | #define UPROBE_FIX_SETF 0x4 | ||
| 46 | |||
| 44 | #define UPROBE_FIX_RIP_AX 0x8000 | 47 | #define UPROBE_FIX_RIP_AX 0x8000 |
| 45 | #define UPROBE_FIX_RIP_CX 0x4000 | 48 | #define UPROBE_FIX_RIP_CX 0x4000 |
| 46 | 49 | ||
| @@ -239,6 +242,10 @@ static void prepare_fixups(struct arch_uprobe *auprobe, struct insn *insn) | |||
| 239 | insn_get_opcode(insn); /* should be a nop */ | 242 | insn_get_opcode(insn); /* should be a nop */ |
| 240 | 243 | ||
| 241 | switch (OPCODE1(insn)) { | 244 | switch (OPCODE1(insn)) { |
| 245 | case 0x9d: | ||
| 246 | /* popf */ | ||
| 247 | auprobe->fixups |= UPROBE_FIX_SETF; | ||
| 248 | break; | ||
| 242 | case 0xc3: /* ret/lret */ | 249 | case 0xc3: /* ret/lret */ |
| 243 | case 0xcb: | 250 | case 0xcb: |
| 244 | case 0xc2: | 251 | case 0xc2: |
| @@ -646,7 +653,7 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
| 646 | * Skip these instructions as per the currently known x86 ISA. | 653 | * Skip these instructions as per the currently known x86 ISA. |
| 647 | * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } | 654 | * 0x66* { 0x90 | 0x0f 0x1f | 0x0f 0x19 | 0x87 0xc0 } |
| 648 | */ | 655 | */ |
| 649 | bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | 656 | static bool __skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) |
| 650 | { | 657 | { |
| 651 | int i; | 658 | int i; |
| 652 | 659 | ||
| @@ -673,3 +680,46 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | |||
| 673 | } | 680 | } |
| 674 | return false; | 681 | return false; |
| 675 | } | 682 | } |
| 683 | |||
| 684 | bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs) | ||
| 685 | { | ||
| 686 | bool ret = __skip_sstep(auprobe, regs); | ||
| 687 | if (ret && (regs->flags & X86_EFLAGS_TF)) | ||
| 688 | send_sig(SIGTRAP, current, 0); | ||
| 689 | return ret; | ||
| 690 | } | ||
| 691 | |||
| 692 | void arch_uprobe_enable_step(struct arch_uprobe *auprobe) | ||
| 693 | { | ||
| 694 | struct task_struct *task = current; | ||
| 695 | struct arch_uprobe_task *autask = &task->utask->autask; | ||
| 696 | struct pt_regs *regs = task_pt_regs(task); | ||
| 697 | |||
| 698 | autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF); | ||
| 699 | |||
| 700 | regs->flags |= X86_EFLAGS_TF; | ||
| 701 | if (test_tsk_thread_flag(task, TIF_BLOCKSTEP)) | ||
| 702 | set_task_blockstep(task, false); | ||
| 703 | } | ||
| 704 | |||
| 705 | void arch_uprobe_disable_step(struct arch_uprobe *auprobe) | ||
| 706 | { | ||
| 707 | struct task_struct *task = current; | ||
| 708 | struct arch_uprobe_task *autask = &task->utask->autask; | ||
| 709 | bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED); | ||
| 710 | struct pt_regs *regs = task_pt_regs(task); | ||
| 711 | /* | ||
| 712 | * The state of TIF_BLOCKSTEP was not saved so we can get an extra | ||
| 713 | * SIGTRAP if we do not clear TF. We need to examine the opcode to | ||
| 714 | * make it right. | ||
| 715 | */ | ||
| 716 | if (unlikely(trapped)) { | ||
| 717 | if (!autask->saved_tf) | ||
| 718 | regs->flags &= ~X86_EFLAGS_TF; | ||
| 719 | } else { | ||
| 720 | if (autask->saved_tf) | ||
| 721 | send_sig(SIGTRAP, task, 0); | ||
| 722 | else if (!(auprobe->fixups & UPROBE_FIX_SETF)) | ||
| 723 | regs->flags &= ~X86_EFLAGS_TF; | ||
| 724 | } | ||
| 725 | } | ||
diff --git a/include/linux/sched.h b/include/linux/sched.h index 3667c332e61d..255661d48834 100644 --- a/include/linux/sched.h +++ b/include/linux/sched.h | |||
| @@ -446,7 +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 */ | 449 | #define MMF_HAS_UPROBES 19 /* has uprobes */ |
| 450 | #define MMF_RECALC_UPROBES 20 /* MMF_HAS_UPROBES can be wrong */ | ||
| 450 | 451 | ||
| 451 | #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) | 452 | #define MMF_INIT_MASK (MMF_DUMPABLE_MASK | MMF_DUMP_FILTER_MASK) |
| 452 | 453 | ||
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h index 6d4fe79a1a6a..e6f0331e3d45 100644 --- a/include/linux/uprobes.h +++ b/include/linux/uprobes.h | |||
| @@ -112,6 +112,8 @@ extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); | |||
| 112 | extern void uprobe_free_utask(struct task_struct *t); | 112 | extern void uprobe_free_utask(struct task_struct *t); |
| 113 | extern void uprobe_copy_process(struct task_struct *t); | 113 | extern void uprobe_copy_process(struct task_struct *t); |
| 114 | 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); |
| 115 | extern void __weak arch_uprobe_enable_step(struct arch_uprobe *arch); | ||
| 116 | extern void __weak arch_uprobe_disable_step(struct arch_uprobe *arch); | ||
| 115 | extern int uprobe_post_sstep_notifier(struct pt_regs *regs); | 117 | extern int uprobe_post_sstep_notifier(struct pt_regs *regs); |
| 116 | extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); | 118 | extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); |
| 117 | extern void uprobe_notify_resume(struct pt_regs *regs); | 119 | extern void uprobe_notify_resume(struct pt_regs *regs); |
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c index 1666632e6edf..912ef48d28ab 100644 --- a/kernel/events/uprobes.c +++ b/kernel/events/uprobes.c | |||
| @@ -411,11 +411,10 @@ static struct uprobe *__find_uprobe(struct inode *inode, loff_t offset) | |||
| 411 | static struct uprobe *find_uprobe(struct inode *inode, loff_t offset) | 411 | static struct uprobe *find_uprobe(struct inode *inode, loff_t offset) |
| 412 | { | 412 | { |
| 413 | struct uprobe *uprobe; | 413 | struct uprobe *uprobe; |
| 414 | unsigned long flags; | ||
| 415 | 414 | ||
| 416 | spin_lock_irqsave(&uprobes_treelock, flags); | 415 | spin_lock(&uprobes_treelock); |
| 417 | uprobe = __find_uprobe(inode, offset); | 416 | uprobe = __find_uprobe(inode, offset); |
| 418 | spin_unlock_irqrestore(&uprobes_treelock, flags); | 417 | spin_unlock(&uprobes_treelock); |
| 419 | 418 | ||
| 420 | return uprobe; | 419 | return uprobe; |
| 421 | } | 420 | } |
| @@ -462,12 +461,11 @@ static struct uprobe *__insert_uprobe(struct uprobe *uprobe) | |||
| 462 | */ | 461 | */ |
| 463 | static struct uprobe *insert_uprobe(struct uprobe *uprobe) | 462 | static struct uprobe *insert_uprobe(struct uprobe *uprobe) |
| 464 | { | 463 | { |
| 465 | unsigned long flags; | ||
| 466 | struct uprobe *u; | 464 | struct uprobe *u; |
| 467 | 465 | ||
| 468 | spin_lock_irqsave(&uprobes_treelock, flags); | 466 | spin_lock(&uprobes_treelock); |
| 469 | u = __insert_uprobe(uprobe); | 467 | u = __insert_uprobe(uprobe); |
| 470 | spin_unlock_irqrestore(&uprobes_treelock, flags); | 468 | spin_unlock(&uprobes_treelock); |
| 471 | 469 | ||
| 472 | /* For now assume that the instruction need not be single-stepped */ | 470 | /* For now assume that the instruction need not be single-stepped */ |
| 473 | uprobe->flags |= UPROBE_SKIP_SSTEP; | 471 | uprobe->flags |= UPROBE_SKIP_SSTEP; |
| @@ -686,7 +684,9 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
| 686 | set_bit(MMF_HAS_UPROBES, &mm->flags); | 684 | set_bit(MMF_HAS_UPROBES, &mm->flags); |
| 687 | 685 | ||
| 688 | ret = set_swbp(&uprobe->arch, mm, vaddr); | 686 | ret = set_swbp(&uprobe->arch, mm, vaddr); |
| 689 | if (ret && first_uprobe) | 687 | if (!ret) |
| 688 | clear_bit(MMF_RECALC_UPROBES, &mm->flags); | ||
| 689 | else if (first_uprobe) | ||
| 690 | clear_bit(MMF_HAS_UPROBES, &mm->flags); | 690 | clear_bit(MMF_HAS_UPROBES, &mm->flags); |
| 691 | 691 | ||
| 692 | return ret; | 692 | return ret; |
| @@ -695,6 +695,11 @@ install_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, | |||
| 695 | static void | 695 | static void |
| 696 | remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) | 696 | remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vaddr) |
| 697 | { | 697 | { |
| 698 | /* can happen if uprobe_register() fails */ | ||
| 699 | if (!test_bit(MMF_HAS_UPROBES, &mm->flags)) | ||
| 700 | return; | ||
| 701 | |||
| 702 | set_bit(MMF_RECALC_UPROBES, &mm->flags); | ||
| 698 | set_orig_insn(&uprobe->arch, mm, vaddr); | 703 | set_orig_insn(&uprobe->arch, mm, vaddr); |
| 699 | } | 704 | } |
| 700 | 705 | ||
| @@ -705,11 +710,9 @@ remove_breakpoint(struct uprobe *uprobe, struct mm_struct *mm, unsigned long vad | |||
| 705 | */ | 710 | */ |
| 706 | static void delete_uprobe(struct uprobe *uprobe) | 711 | static void delete_uprobe(struct uprobe *uprobe) |
| 707 | { | 712 | { |
| 708 | unsigned long flags; | 713 | spin_lock(&uprobes_treelock); |
| 709 | |||
| 710 | spin_lock_irqsave(&uprobes_treelock, flags); | ||
| 711 | rb_erase(&uprobe->rb_node, &uprobes_tree); | 714 | rb_erase(&uprobe->rb_node, &uprobes_tree); |
| 712 | spin_unlock_irqrestore(&uprobes_treelock, flags); | 715 | spin_unlock(&uprobes_treelock); |
| 713 | iput(uprobe->inode); | 716 | iput(uprobe->inode); |
| 714 | put_uprobe(uprobe); | 717 | put_uprobe(uprobe); |
| 715 | atomic_dec(&uprobe_events); | 718 | atomic_dec(&uprobe_events); |
| @@ -897,7 +900,8 @@ int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_consumer * | |||
| 897 | } | 900 | } |
| 898 | 901 | ||
| 899 | mutex_unlock(uprobes_hash(inode)); | 902 | mutex_unlock(uprobes_hash(inode)); |
| 900 | put_uprobe(uprobe); | 903 | if (uprobe) |
| 904 | put_uprobe(uprobe); | ||
| 901 | 905 | ||
| 902 | return ret; | 906 | return ret; |
| 903 | } | 907 | } |
| @@ -967,7 +971,6 @@ static void build_probe_list(struct inode *inode, | |||
| 967 | struct list_head *head) | 971 | struct list_head *head) |
| 968 | { | 972 | { |
| 969 | loff_t min, max; | 973 | loff_t min, max; |
| 970 | unsigned long flags; | ||
| 971 | struct rb_node *n, *t; | 974 | struct rb_node *n, *t; |
| 972 | struct uprobe *u; | 975 | struct uprobe *u; |
| 973 | 976 | ||
| @@ -975,7 +978,7 @@ static void build_probe_list(struct inode *inode, | |||
| 975 | min = vaddr_to_offset(vma, start); | 978 | min = vaddr_to_offset(vma, start); |
| 976 | max = min + (end - start) - 1; | 979 | max = min + (end - start) - 1; |
| 977 | 980 | ||
| 978 | spin_lock_irqsave(&uprobes_treelock, flags); | 981 | spin_lock(&uprobes_treelock); |
| 979 | n = find_node_in_range(inode, min, max); | 982 | n = find_node_in_range(inode, min, max); |
| 980 | if (n) { | 983 | if (n) { |
| 981 | for (t = n; t; t = rb_prev(t)) { | 984 | for (t = n; t; t = rb_prev(t)) { |
| @@ -993,7 +996,7 @@ static void build_probe_list(struct inode *inode, | |||
| 993 | atomic_inc(&u->ref); | 996 | atomic_inc(&u->ref); |
| 994 | } | 997 | } |
| 995 | } | 998 | } |
| 996 | spin_unlock_irqrestore(&uprobes_treelock, flags); | 999 | spin_unlock(&uprobes_treelock); |
| 997 | } | 1000 | } |
| 998 | 1001 | ||
| 999 | /* | 1002 | /* |
| @@ -1030,6 +1033,25 @@ int uprobe_mmap(struct vm_area_struct *vma) | |||
| 1030 | return 0; | 1033 | return 0; |
| 1031 | } | 1034 | } |
| 1032 | 1035 | ||
| 1036 | static bool | ||
| 1037 | vma_has_uprobes(struct vm_area_struct *vma, unsigned long start, unsigned long end) | ||
| 1038 | { | ||
| 1039 | loff_t min, max; | ||
| 1040 | struct inode *inode; | ||
| 1041 | struct rb_node *n; | ||
| 1042 | |||
| 1043 | inode = vma->vm_file->f_mapping->host; | ||
| 1044 | |||
| 1045 | min = vaddr_to_offset(vma, start); | ||
| 1046 | max = min + (end - start) - 1; | ||
| 1047 | |||
| 1048 | spin_lock(&uprobes_treelock); | ||
| 1049 | n = find_node_in_range(inode, min, max); | ||
| 1050 | spin_unlock(&uprobes_treelock); | ||
| 1051 | |||
| 1052 | return !!n; | ||
| 1053 | } | ||
| 1054 | |||
| 1033 | /* | 1055 | /* |
| 1034 | * Called in context of a munmap of a vma. | 1056 | * Called in context of a munmap of a vma. |
| 1035 | */ | 1057 | */ |
| @@ -1041,10 +1063,12 @@ void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned lon | |||
| 1041 | if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */ | 1063 | if (!atomic_read(&vma->vm_mm->mm_users)) /* called by mmput() ? */ |
| 1042 | return; | 1064 | return; |
| 1043 | 1065 | ||
| 1044 | if (!test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags)) | 1066 | if (!test_bit(MMF_HAS_UPROBES, &vma->vm_mm->flags) || |
| 1067 | test_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags)) | ||
| 1045 | return; | 1068 | return; |
| 1046 | 1069 | ||
| 1047 | /* TODO: unmapping uprobe(s) will need more work */ | 1070 | if (vma_has_uprobes(vma, start, end)) |
| 1071 | set_bit(MMF_RECALC_UPROBES, &vma->vm_mm->flags); | ||
| 1048 | } | 1072 | } |
| 1049 | 1073 | ||
| 1050 | /* Slot allocation for XOL */ | 1074 | /* Slot allocation for XOL */ |
| @@ -1150,8 +1174,11 @@ void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) | |||
| 1150 | { | 1174 | { |
| 1151 | newmm->uprobes_state.xol_area = NULL; | 1175 | newmm->uprobes_state.xol_area = NULL; |
| 1152 | 1176 | ||
| 1153 | if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) | 1177 | if (test_bit(MMF_HAS_UPROBES, &oldmm->flags)) { |
| 1154 | set_bit(MMF_HAS_UPROBES, &newmm->flags); | 1178 | set_bit(MMF_HAS_UPROBES, &newmm->flags); |
| 1179 | /* unconditionally, dup_mmap() skips VM_DONTCOPY vmas */ | ||
| 1180 | set_bit(MMF_RECALC_UPROBES, &newmm->flags); | ||
| 1181 | } | ||
| 1155 | } | 1182 | } |
| 1156 | 1183 | ||
| 1157 | /* | 1184 | /* |
| @@ -1369,6 +1396,25 @@ static bool can_skip_sstep(struct uprobe *uprobe, struct pt_regs *regs) | |||
| 1369 | return false; | 1396 | return false; |
| 1370 | } | 1397 | } |
| 1371 | 1398 | ||
| 1399 | static void mmf_recalc_uprobes(struct mm_struct *mm) | ||
| 1400 | { | ||
| 1401 | struct vm_area_struct *vma; | ||
| 1402 | |||
| 1403 | for (vma = mm->mmap; vma; vma = vma->vm_next) { | ||
| 1404 | if (!valid_vma(vma, false)) | ||
| 1405 | continue; | ||
| 1406 | /* | ||
| 1407 | * This is not strictly accurate, we can race with | ||
| 1408 | * uprobe_unregister() and see the already removed | ||
| 1409 | * uprobe if delete_uprobe() was not yet called. | ||
| 1410 | */ | ||
| 1411 | if (vma_has_uprobes(vma, vma->vm_start, vma->vm_end)) | ||
| 1412 | return; | ||
| 1413 | } | ||
| 1414 | |||
| 1415 | clear_bit(MMF_HAS_UPROBES, &mm->flags); | ||
| 1416 | } | ||
| 1417 | |||
| 1372 | static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) | 1418 | static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) |
| 1373 | { | 1419 | { |
| 1374 | struct mm_struct *mm = current->mm; | 1420 | struct mm_struct *mm = current->mm; |
| @@ -1390,11 +1436,24 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp) | |||
| 1390 | } else { | 1436 | } else { |
| 1391 | *is_swbp = -EFAULT; | 1437 | *is_swbp = -EFAULT; |
| 1392 | } | 1438 | } |
| 1439 | |||
| 1440 | if (!uprobe && test_and_clear_bit(MMF_RECALC_UPROBES, &mm->flags)) | ||
| 1441 | mmf_recalc_uprobes(mm); | ||
| 1393 | up_read(&mm->mmap_sem); | 1442 | up_read(&mm->mmap_sem); |
| 1394 | 1443 | ||
| 1395 | return uprobe; | 1444 | return uprobe; |
| 1396 | } | 1445 | } |
| 1397 | 1446 | ||
| 1447 | void __weak arch_uprobe_enable_step(struct arch_uprobe *arch) | ||
| 1448 | { | ||
| 1449 | user_enable_single_step(current); | ||
| 1450 | } | ||
| 1451 | |||
| 1452 | void __weak arch_uprobe_disable_step(struct arch_uprobe *arch) | ||
| 1453 | { | ||
| 1454 | user_disable_single_step(current); | ||
| 1455 | } | ||
| 1456 | |||
| 1398 | /* | 1457 | /* |
| 1399 | * Run handler and ask thread to singlestep. | 1458 | * Run handler and ask thread to singlestep. |
| 1400 | * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. | 1459 | * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. |
| @@ -1441,7 +1500,7 @@ static void handle_swbp(struct pt_regs *regs) | |||
| 1441 | 1500 | ||
| 1442 | utask->state = UTASK_SSTEP; | 1501 | utask->state = UTASK_SSTEP; |
| 1443 | if (!pre_ssout(uprobe, regs, bp_vaddr)) { | 1502 | if (!pre_ssout(uprobe, regs, bp_vaddr)) { |
| 1444 | user_enable_single_step(current); | 1503 | arch_uprobe_enable_step(&uprobe->arch); |
| 1445 | return; | 1504 | return; |
| 1446 | } | 1505 | } |
| 1447 | 1506 | ||
| @@ -1477,10 +1536,10 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs) | |||
| 1477 | else | 1536 | else |
| 1478 | WARN_ON_ONCE(1); | 1537 | WARN_ON_ONCE(1); |
| 1479 | 1538 | ||
| 1539 | arch_uprobe_disable_step(&uprobe->arch); | ||
| 1480 | put_uprobe(uprobe); | 1540 | put_uprobe(uprobe); |
| 1481 | utask->active_uprobe = NULL; | 1541 | utask->active_uprobe = NULL; |
| 1482 | utask->state = UTASK_RUNNING; | 1542 | utask->state = UTASK_RUNNING; |
| 1483 | user_disable_single_step(current); | ||
| 1484 | xol_free_insn_slot(current); | 1543 | xol_free_insn_slot(current); |
| 1485 | 1544 | ||
| 1486 | spin_lock_irq(¤t->sighand->siglock); | 1545 | spin_lock_irq(¤t->sighand->siglock); |
