aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86
diff options
context:
space:
mode:
authorMasami Hiramatsu <mhiramat@redhat.com>2010-04-27 18:33:49 -0400
committerIngo Molnar <mingo@elte.hu>2010-05-11 03:14:25 -0400
commit829e92458532b1dbfeb972435d45bb060cdbf5a3 (patch)
tree755f5c5e590aec21730afc2bcd680629fe075770 /arch/x86
parentde068ec048f807d4f62b7dda100c23a1365f086f (diff)
kprobes/x86: Fix removed int3 checking order
Fix kprobe/x86 to check removed int3 when failing to get kprobe from hlist. Since we have a time window between checking int3 exists on probed address and getting kprobe on that address, we can have following scenario: ------- CPU1 CPU2 hit int3 check int3 exists remove int3 remove kprobe from hlist get kprobe from hlist no kprobe->OOPS! ------- This patch moves int3 checking if there is no kprobe on that address for fixing this problem as follows: ------ CPU1 CPU2 hit int3 remove int3 remove kprobe from hlist get kprobe from hlist no kprobe->check int3 exists ->rollback&retry ------ Signed-off-by: Masami Hiramatsu <mhiramat@redhat.com> Acked-by: Ananth N Mavinakayanahalli <ananth@in.ibm.com> Cc: systemtap <systemtap@sources.redhat.com> Cc: DLE <dle-develop@lists.sourceforge.net> Cc: Dave Anderson <anderson@redhat.com> Cc: Peter Zijlstra <a.p.zijlstra@chello.nl> Cc: Mike Galbraith <efault@gmx.de> Cc: Paul Mackerras <paulus@samba.org> Cc: Arnaldo Carvalho de Melo <acme@redhat.com> Cc: Frederic Weisbecker <fweisbec@gmail.com> LKML-Reference: <20100427223348.2322.9112.stgit@localhost6.localdomain6> Signed-off-by: Ingo Molnar <mingo@elte.hu>
Diffstat (limited to 'arch/x86')
-rw-r--r--arch/x86/kernel/kprobes.c27
1 files changed, 13 insertions, 14 deletions
diff --git a/arch/x86/kernel/kprobes.c b/arch/x86/kernel/kprobes.c
index b43bbaebe2c0..1658efdfb4e5 100644
--- a/arch/x86/kernel/kprobes.c
+++ b/arch/x86/kernel/kprobes.c
@@ -534,20 +534,6 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
534 struct kprobe_ctlblk *kcb; 534 struct kprobe_ctlblk *kcb;
535 535
536 addr = (kprobe_opcode_t *)(regs->ip - sizeof(kprobe_opcode_t)); 536 addr = (kprobe_opcode_t *)(regs->ip - sizeof(kprobe_opcode_t));
537 if (*addr != BREAKPOINT_INSTRUCTION) {
538 /*
539 * The breakpoint instruction was removed right
540 * after we hit it. Another cpu has removed
541 * either a probepoint or a debugger breakpoint
542 * at this address. In either case, no further
543 * handling of this interrupt is appropriate.
544 * Back up over the (now missing) int3 and run
545 * the original instruction.
546 */
547 regs->ip = (unsigned long)addr;
548 return 1;
549 }
550
551 /* 537 /*
552 * We don't want to be preempted for the entire 538 * We don't want to be preempted for the entire
553 * duration of kprobe processing. We conditionally 539 * duration of kprobe processing. We conditionally
@@ -579,6 +565,19 @@ static int __kprobes kprobe_handler(struct pt_regs *regs)
579 setup_singlestep(p, regs, kcb, 0); 565 setup_singlestep(p, regs, kcb, 0);
580 return 1; 566 return 1;
581 } 567 }
568 } else if (*addr != BREAKPOINT_INSTRUCTION) {
569 /*
570 * The breakpoint instruction was removed right
571 * after we hit it. Another cpu has removed
572 * either a probepoint or a debugger breakpoint
573 * at this address. In either case, no further
574 * handling of this interrupt is appropriate.
575 * Back up over the (now missing) int3 and run
576 * the original instruction.
577 */
578 regs->ip = (unsigned long)addr;
579 preempt_enable_no_resched();
580 return 1;
582 } else if (kprobe_running()) { 581 } else if (kprobe_running()) {
583 p = __get_cpu_var(current_kprobe); 582 p = __get_cpu_var(current_kprobe);
584 if (p->break_handler && p->break_handler(p, regs)) { 583 if (p->break_handler && p->break_handler(p, regs)) {