aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/powerpc/kernel/signal.c4
-rw-r--r--arch/powerpc/kernel/uprobes.c6
-rw-r--r--arch/x86/kernel/uprobes.c54
-rw-r--r--include/linux/uprobes.h10
-rw-r--r--kernel/events/uprobes.c43
-rw-r--r--kernel/fork.c2
-rw-r--r--kernel/trace/trace_uprobe.c2
7 files changed, 65 insertions, 56 deletions
diff --git a/arch/powerpc/kernel/signal.c b/arch/powerpc/kernel/signal.c
index a2dc75793bd5..3b997118df50 100644
--- a/arch/powerpc/kernel/signal.c
+++ b/arch/powerpc/kernel/signal.c
@@ -158,10 +158,8 @@ static int do_signal(struct pt_regs *regs)
158 158
159void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags) 159void do_notify_resume(struct pt_regs *regs, unsigned long thread_info_flags)
160{ 160{
161 if (thread_info_flags & _TIF_UPROBE) { 161 if (thread_info_flags & _TIF_UPROBE)
162 clear_thread_flag(TIF_UPROBE);
163 uprobe_notify_resume(regs); 162 uprobe_notify_resume(regs);
164 }
165 163
166 if (thread_info_flags & _TIF_SIGPENDING) 164 if (thread_info_flags & _TIF_SIGPENDING)
167 do_signal(regs); 165 do_signal(regs);
diff --git a/arch/powerpc/kernel/uprobes.c b/arch/powerpc/kernel/uprobes.c
index d2d46d1014f8..bc77834dbf43 100644
--- a/arch/powerpc/kernel/uprobes.c
+++ b/arch/powerpc/kernel/uprobes.c
@@ -64,6 +64,8 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
64 autask->saved_trap_nr = current->thread.trap_nr; 64 autask->saved_trap_nr = current->thread.trap_nr;
65 current->thread.trap_nr = UPROBE_TRAP_NR; 65 current->thread.trap_nr = UPROBE_TRAP_NR;
66 regs->nip = current->utask->xol_vaddr; 66 regs->nip = current->utask->xol_vaddr;
67
68 user_enable_single_step(current);
67 return 0; 69 return 0;
68} 70}
69 71
@@ -119,6 +121,8 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
119 * to be executed. 121 * to be executed.
120 */ 122 */
121 regs->nip = utask->vaddr + MAX_UINSN_BYTES; 123 regs->nip = utask->vaddr + MAX_UINSN_BYTES;
124
125 user_disable_single_step(current);
122 return 0; 126 return 0;
123} 127}
124 128
@@ -162,6 +166,8 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
162 166
163 current->thread.trap_nr = utask->autask.saved_trap_nr; 167 current->thread.trap_nr = utask->autask.saved_trap_nr;
164 instruction_pointer_set(regs, utask->vaddr); 168 instruction_pointer_set(regs, utask->vaddr);
169
170 user_disable_single_step(current);
165} 171}
166 172
167/* 173/*
diff --git a/arch/x86/kernel/uprobes.c b/arch/x86/kernel/uprobes.c
index aafa5557b396..c71025b67462 100644
--- a/arch/x86/kernel/uprobes.c
+++ b/arch/x86/kernel/uprobes.c
@@ -478,6 +478,11 @@ int arch_uprobe_pre_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
478 regs->ip = current->utask->xol_vaddr; 478 regs->ip = current->utask->xol_vaddr;
479 pre_xol_rip_insn(auprobe, regs, autask); 479 pre_xol_rip_insn(auprobe, regs, autask);
480 480
481 autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF);
482 regs->flags |= X86_EFLAGS_TF;
483 if (test_tsk_thread_flag(current, TIF_BLOCKSTEP))
484 set_task_blockstep(current, false);
485
481 return 0; 486 return 0;
482} 487}
483 488
@@ -603,6 +608,16 @@ int arch_uprobe_post_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
603 if (auprobe->fixups & UPROBE_FIX_CALL) 608 if (auprobe->fixups & UPROBE_FIX_CALL)
604 result = adjust_ret_addr(regs->sp, correction); 609 result = adjust_ret_addr(regs->sp, correction);
605 610
611 /*
612 * arch_uprobe_pre_xol() doesn't save the state of TIF_BLOCKSTEP
613 * so we can get an extra SIGTRAP if we do not clear TF. We need
614 * to examine the opcode to make it right.
615 */
616 if (utask->autask.saved_tf)
617 send_sig(SIGTRAP, current, 0);
618 else if (!(auprobe->fixups & UPROBE_FIX_SETF))
619 regs->flags &= ~X86_EFLAGS_TF;
620
606 return result; 621 return result;
607} 622}
608 623
@@ -647,6 +662,10 @@ void arch_uprobe_abort_xol(struct arch_uprobe *auprobe, struct pt_regs *regs)
647 current->thread.trap_nr = utask->autask.saved_trap_nr; 662 current->thread.trap_nr = utask->autask.saved_trap_nr;
648 handle_riprel_post_xol(auprobe, regs, NULL); 663 handle_riprel_post_xol(auprobe, regs, NULL);
649 instruction_pointer_set(regs, utask->vaddr); 664 instruction_pointer_set(regs, utask->vaddr);
665
666 /* clear TF if it was set by us in arch_uprobe_pre_xol() */
667 if (!utask->autask.saved_tf)
668 regs->flags &= ~X86_EFLAGS_TF;
650} 669}
651 670
652/* 671/*
@@ -676,38 +695,3 @@ bool arch_uprobe_skip_sstep(struct arch_uprobe *auprobe, struct pt_regs *regs)
676 send_sig(SIGTRAP, current, 0); 695 send_sig(SIGTRAP, current, 0);
677 return ret; 696 return ret;
678} 697}
679
680void arch_uprobe_enable_step(struct arch_uprobe *auprobe)
681{
682 struct task_struct *task = current;
683 struct arch_uprobe_task *autask = &task->utask->autask;
684 struct pt_regs *regs = task_pt_regs(task);
685
686 autask->saved_tf = !!(regs->flags & X86_EFLAGS_TF);
687
688 regs->flags |= X86_EFLAGS_TF;
689 if (test_tsk_thread_flag(task, TIF_BLOCKSTEP))
690 set_task_blockstep(task, false);
691}
692
693void arch_uprobe_disable_step(struct arch_uprobe *auprobe)
694{
695 struct task_struct *task = current;
696 struct arch_uprobe_task *autask = &task->utask->autask;
697 bool trapped = (task->utask->state == UTASK_SSTEP_TRAPPED);
698 struct pt_regs *regs = task_pt_regs(task);
699 /*
700 * The state of TIF_BLOCKSTEP was not saved so we can get an extra
701 * SIGTRAP if we do not clear TF. We need to examine the opcode to
702 * make it right.
703 */
704 if (unlikely(trapped)) {
705 if (!autask->saved_tf)
706 regs->flags &= ~X86_EFLAGS_TF;
707 } else {
708 if (autask->saved_tf)
709 send_sig(SIGTRAP, task, 0);
710 else if (!(auprobe->fixups & UPROBE_FIX_SETF))
711 regs->flags &= ~X86_EFLAGS_TF;
712 }
713}
diff --git a/include/linux/uprobes.h b/include/linux/uprobes.h
index 24594571c5a3..4f628a6fc5b4 100644
--- a/include/linux/uprobes.h
+++ b/include/linux/uprobes.h
@@ -97,12 +97,12 @@ extern int uprobe_register(struct inode *inode, loff_t offset, struct uprobe_con
97extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc); 97extern void uprobe_unregister(struct inode *inode, loff_t offset, struct uprobe_consumer *uc);
98extern int uprobe_mmap(struct vm_area_struct *vma); 98extern int uprobe_mmap(struct vm_area_struct *vma);
99extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end); 99extern void uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end);
100extern void uprobe_start_dup_mmap(void);
101extern void uprobe_end_dup_mmap(void);
100extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm); 102extern void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm);
101extern void uprobe_free_utask(struct task_struct *t); 103extern void uprobe_free_utask(struct task_struct *t);
102extern void uprobe_copy_process(struct task_struct *t); 104extern void uprobe_copy_process(struct task_struct *t);
103extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs); 105extern unsigned long __weak uprobe_get_swbp_addr(struct pt_regs *regs);
104extern void __weak arch_uprobe_enable_step(struct arch_uprobe *arch);
105extern void __weak arch_uprobe_disable_step(struct arch_uprobe *arch);
106extern int uprobe_post_sstep_notifier(struct pt_regs *regs); 106extern int uprobe_post_sstep_notifier(struct pt_regs *regs);
107extern int uprobe_pre_sstep_notifier(struct pt_regs *regs); 107extern int uprobe_pre_sstep_notifier(struct pt_regs *regs);
108extern void uprobe_notify_resume(struct pt_regs *regs); 108extern void uprobe_notify_resume(struct pt_regs *regs);
@@ -129,6 +129,12 @@ static inline void
129uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end) 129uprobe_munmap(struct vm_area_struct *vma, unsigned long start, unsigned long end)
130{ 130{
131} 131}
132static inline void uprobe_start_dup_mmap(void)
133{
134}
135static inline void uprobe_end_dup_mmap(void)
136{
137}
132static inline void 138static inline void
133uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) 139uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
134{ 140{
diff --git a/kernel/events/uprobes.c b/kernel/events/uprobes.c
index 5cc4e7e42e68..dea7acfbb071 100644
--- a/kernel/events/uprobes.c
+++ b/kernel/events/uprobes.c
@@ -33,6 +33,7 @@
33#include <linux/ptrace.h> /* user_enable_single_step */ 33#include <linux/ptrace.h> /* user_enable_single_step */
34#include <linux/kdebug.h> /* notifier mechanism */ 34#include <linux/kdebug.h> /* notifier mechanism */
35#include "../../mm/internal.h" /* munlock_vma_page */ 35#include "../../mm/internal.h" /* munlock_vma_page */
36#include <linux/percpu-rwsem.h>
36 37
37#include <linux/uprobes.h> 38#include <linux/uprobes.h>
38 39
@@ -71,6 +72,8 @@ static struct mutex uprobes_mutex[UPROBES_HASH_SZ];
71static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ]; 72static struct mutex uprobes_mmap_mutex[UPROBES_HASH_SZ];
72#define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ]) 73#define uprobes_mmap_hash(v) (&uprobes_mmap_mutex[((unsigned long)(v)) % UPROBES_HASH_SZ])
73 74
75static struct percpu_rw_semaphore dup_mmap_sem;
76
74/* 77/*
75 * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe 78 * uprobe_events allows us to skip the uprobe_mmap if there are no uprobe
76 * events active at this time. Probably a fine grained per inode count is 79 * events active at this time. Probably a fine grained per inode count is
@@ -766,10 +769,13 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
766 struct map_info *info; 769 struct map_info *info;
767 int err = 0; 770 int err = 0;
768 771
772 percpu_down_write(&dup_mmap_sem);
769 info = build_map_info(uprobe->inode->i_mapping, 773 info = build_map_info(uprobe->inode->i_mapping,
770 uprobe->offset, is_register); 774 uprobe->offset, is_register);
771 if (IS_ERR(info)) 775 if (IS_ERR(info)) {
772 return PTR_ERR(info); 776 err = PTR_ERR(info);
777 goto out;
778 }
773 779
774 while (info) { 780 while (info) {
775 struct mm_struct *mm = info->mm; 781 struct mm_struct *mm = info->mm;
@@ -799,7 +805,8 @@ static int register_for_each_vma(struct uprobe *uprobe, bool is_register)
799 mmput(mm); 805 mmput(mm);
800 info = free_map_info(info); 806 info = free_map_info(info);
801 } 807 }
802 808 out:
809 percpu_up_write(&dup_mmap_sem);
803 return err; 810 return err;
804} 811}
805 812
@@ -1131,6 +1138,16 @@ void uprobe_clear_state(struct mm_struct *mm)
1131 kfree(area); 1138 kfree(area);
1132} 1139}
1133 1140
1141void uprobe_start_dup_mmap(void)
1142{
1143 percpu_down_read(&dup_mmap_sem);
1144}
1145
1146void uprobe_end_dup_mmap(void)
1147{
1148 percpu_up_read(&dup_mmap_sem);
1149}
1150
1134void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm) 1151void uprobe_dup_mmap(struct mm_struct *oldmm, struct mm_struct *newmm)
1135{ 1152{
1136 newmm->uprobes_state.xol_area = NULL; 1153 newmm->uprobes_state.xol_area = NULL;
@@ -1199,6 +1216,11 @@ static unsigned long xol_get_insn_slot(struct uprobe *uprobe, unsigned long slot
1199 vaddr = kmap_atomic(area->page); 1216 vaddr = kmap_atomic(area->page);
1200 memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES); 1217 memcpy(vaddr + offset, uprobe->arch.insn, MAX_UINSN_BYTES);
1201 kunmap_atomic(vaddr); 1218 kunmap_atomic(vaddr);
1219 /*
1220 * We probably need flush_icache_user_range() but it needs vma.
1221 * This should work on supported architectures too.
1222 */
1223 flush_dcache_page(area->page);
1202 1224
1203 return current->utask->xol_vaddr; 1225 return current->utask->xol_vaddr;
1204} 1226}
@@ -1430,16 +1452,6 @@ static struct uprobe *find_active_uprobe(unsigned long bp_vaddr, int *is_swbp)
1430 return uprobe; 1452 return uprobe;
1431} 1453}
1432 1454
1433void __weak arch_uprobe_enable_step(struct arch_uprobe *arch)
1434{
1435 user_enable_single_step(current);
1436}
1437
1438void __weak arch_uprobe_disable_step(struct arch_uprobe *arch)
1439{
1440 user_disable_single_step(current);
1441}
1442
1443/* 1455/*
1444 * Run handler and ask thread to singlestep. 1456 * Run handler and ask thread to singlestep.
1445 * Ensure all non-fatal signals cannot interrupt thread while it singlesteps. 1457 * Ensure all non-fatal signals cannot interrupt thread while it singlesteps.
@@ -1493,7 +1505,6 @@ static void handle_swbp(struct pt_regs *regs)
1493 goto out; 1505 goto out;
1494 1506
1495 if (!pre_ssout(uprobe, regs, bp_vaddr)) { 1507 if (!pre_ssout(uprobe, regs, bp_vaddr)) {
1496 arch_uprobe_enable_step(&uprobe->arch);
1497 utask->active_uprobe = uprobe; 1508 utask->active_uprobe = uprobe;
1498 utask->state = UTASK_SSTEP; 1509 utask->state = UTASK_SSTEP;
1499 return; 1510 return;
@@ -1525,7 +1536,6 @@ static void handle_singlestep(struct uprobe_task *utask, struct pt_regs *regs)
1525 else 1536 else
1526 WARN_ON_ONCE(1); 1537 WARN_ON_ONCE(1);
1527 1538
1528 arch_uprobe_disable_step(&uprobe->arch);
1529 put_uprobe(uprobe); 1539 put_uprobe(uprobe);
1530 utask->active_uprobe = NULL; 1540 utask->active_uprobe = NULL;
1531 utask->state = UTASK_RUNNING; 1541 utask->state = UTASK_RUNNING;
@@ -1604,6 +1614,9 @@ static int __init init_uprobes(void)
1604 mutex_init(&uprobes_mmap_mutex[i]); 1614 mutex_init(&uprobes_mmap_mutex[i]);
1605 } 1615 }
1606 1616
1617 if (percpu_init_rwsem(&dup_mmap_sem))
1618 return -ENOMEM;
1619
1607 return register_die_notifier(&uprobe_exception_nb); 1620 return register_die_notifier(&uprobe_exception_nb);
1608} 1621}
1609module_init(init_uprobes); 1622module_init(init_uprobes);
diff --git a/kernel/fork.c b/kernel/fork.c
index 8b20ab7d3aa2..c497e57aa654 100644
--- a/kernel/fork.c
+++ b/kernel/fork.c
@@ -352,6 +352,7 @@ static int dup_mmap(struct mm_struct *mm, struct mm_struct *oldmm)
352 unsigned long charge; 352 unsigned long charge;
353 struct mempolicy *pol; 353 struct mempolicy *pol;
354 354
355 uprobe_start_dup_mmap();
355 down_write(&oldmm->mmap_sem); 356 down_write(&oldmm->mmap_sem);
356 flush_cache_dup_mm(oldmm); 357 flush_cache_dup_mm(oldmm);
357 uprobe_dup_mmap(oldmm, mm); 358 uprobe_dup_mmap(oldmm, mm);
@@ -469,6 +470,7 @@ out:
469 up_write(&mm->mmap_sem); 470 up_write(&mm->mmap_sem);
470 flush_tlb_mm(oldmm); 471 flush_tlb_mm(oldmm);
471 up_write(&oldmm->mmap_sem); 472 up_write(&oldmm->mmap_sem);
473 uprobe_end_dup_mmap();
472 return retval; 474 return retval;
473fail_nomem_anon_vma_fork: 475fail_nomem_anon_vma_fork:
474 mpol_put(pol); 476 mpol_put(pol);
diff --git a/kernel/trace/trace_uprobe.c b/kernel/trace/trace_uprobe.c
index 4ff9ca4f359a..9614db8b0f8c 100644
--- a/kernel/trace/trace_uprobe.c
+++ b/kernel/trace/trace_uprobe.c
@@ -189,7 +189,7 @@ static int create_trace_uprobe(int argc, char **argv)
189 if (argv[0][0] == '-') 189 if (argv[0][0] == '-')
190 is_delete = true; 190 is_delete = true;
191 else if (argv[0][0] != 'p') { 191 else if (argv[0][0] != 'p') {
192 pr_info("Probe definition must be started with 'p', 'r' or" " '-'.\n"); 192 pr_info("Probe definition must be started with 'p' or '-'.\n");
193 return -EINVAL; 193 return -EINVAL;
194 } 194 }
195 195