aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorMasami Hiramatsu <masami.hiramatsu.pt@hitachi.com>2014-04-17 04:17:33 -0400
committerIngo Molnar <mingo@kernel.org>2014-04-24 04:02:59 -0400
commit6f6343f53d133bae516caf3d254bce37d8774625 (patch)
tree78beecd00443bd166982c3de9c44a624b7196c7f /arch
parent98def1dedd00f42ded8423c418c971751f46aad2 (diff)
kprobes/x86: Call exception handlers directly from do_int3/do_debug
To avoid a kernel crash by probing on lockdep code, call kprobe_int3_handler() and kprobe_debug_handler()(which was formerly called post_kprobe_handler()) directly from do_int3 and do_debug. Currently kprobes uses notify_die() to hook the int3/debug exceptoins. Since there is a locking code in notify_die, the lockdep code can be invoked. And because the lockdep involves printk() related things, theoretically, we need to prohibit probing on such code, which means much longer blacklist we'll have. Instead, hooking the int3/debug for kprobes before notify_die() can avoid this problem. Anyway, most of the int3 handlers in the kernel are already called from do_int3 directly, e.g. ftrace_int3_handler, poke_int3_handler, kgdb_ll_trap. Actually only kprobe_exceptions_notify is on the notifier_call_chain. Signed-off-by: Masami Hiramatsu <masami.hiramatsu.pt@hitachi.com> Reviewed-by: Steven Rostedt <rostedt@goodmis.org> Cc: Andrew Morton <akpm@linux-foundation.org> Cc: Borislav Petkov <bp@suse.de> Cc: Jiri Kosina <jkosina@suse.cz> Cc: Jonathan Lebon <jlebon@redhat.com> Cc: Kees Cook <keescook@chromium.org> Cc: Rusty Russell <rusty@rustcorp.com.au> Cc: Seiji Aguchi <seiji.aguchi@hds.com> Link: http://lkml.kernel.org/r/20140417081733.26341.24423.stgit@ltc230.yrl.intra.hitachi.co.jp Signed-off-by: Ingo Molnar <mingo@kernel.org>
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/kprobes.h2
-rw-r--r--arch/x86/kernel/kprobes/core.c24
-rw-r--r--arch/x86/kernel/traps.c10
3 files changed, 15 insertions, 21 deletions
diff --git a/arch/x86/include/asm/kprobes.h b/arch/x86/include/asm/kprobes.h
index 9454c167629f..53cdfb2857ab 100644
--- a/arch/x86/include/asm/kprobes.h
+++ b/arch/x86/include/asm/kprobes.h
@@ -116,4 +116,6 @@ struct kprobe_ctlblk {
116extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); 116extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
117extern int kprobe_exceptions_notify(struct notifier_block *self, 117extern int kprobe_exceptions_notify(struct notifier_block *self,
118 unsigned long val, void *data); 118 unsigned long val, void *data);
119extern int kprobe_int3_handler(struct pt_regs *regs);
120extern int kprobe_debug_handler(struct pt_regs *regs);
119#endif /* _ASM_X86_KPROBES_H */ 121#endif /* _ASM_X86_KPROBES_H */
diff --git a/arch/x86/kernel/kprobes/core.c b/arch/x86/kernel/kprobes/core.c
index 7751b3dee53a..9b80aec1ea1a 100644
--- a/arch/x86/kernel/kprobes/core.c
+++ b/arch/x86/kernel/kprobes/core.c
@@ -559,7 +559,7 @@ reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb
559 * Interrupts are disabled on entry as trap3 is an interrupt gate and they 559 * Interrupts are disabled on entry as trap3 is an interrupt gate and they
560 * remain disabled throughout this function. 560 * remain disabled throughout this function.
561 */ 561 */
562static int __kprobes kprobe_handler(struct pt_regs *regs) 562int __kprobes kprobe_int3_handler(struct pt_regs *regs)
563{ 563{
564 kprobe_opcode_t *addr; 564 kprobe_opcode_t *addr;
565 struct kprobe *p; 565 struct kprobe *p;
@@ -857,7 +857,7 @@ no_change:
857 * Interrupts are disabled on entry as trap1 is an interrupt gate and they 857 * Interrupts are disabled on entry as trap1 is an interrupt gate and they
858 * remain disabled throughout this function. 858 * remain disabled throughout this function.
859 */ 859 */
860static int __kprobes post_kprobe_handler(struct pt_regs *regs) 860int __kprobes kprobe_debug_handler(struct pt_regs *regs)
861{ 861{
862 struct kprobe *cur = kprobe_running(); 862 struct kprobe *cur = kprobe_running();
863 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); 863 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -963,22 +963,7 @@ kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *d
963 if (args->regs && user_mode_vm(args->regs)) 963 if (args->regs && user_mode_vm(args->regs))
964 return ret; 964 return ret;
965 965
966 switch (val) { 966 if (val == DIE_GPF) {
967 case DIE_INT3:
968 if (kprobe_handler(args->regs))
969 ret = NOTIFY_STOP;
970 break;
971 case DIE_DEBUG:
972 if (post_kprobe_handler(args->regs)) {
973 /*
974 * Reset the BS bit in dr6 (pointed by args->err) to
975 * denote completion of processing
976 */
977 (*(unsigned long *)ERR_PTR(args->err)) &= ~DR_STEP;
978 ret = NOTIFY_STOP;
979 }
980 break;
981 case DIE_GPF:
982 /* 967 /*
983 * To be potentially processing a kprobe fault and to 968 * To be potentially processing a kprobe fault and to
984 * trust the result from kprobe_running(), we have 969 * trust the result from kprobe_running(), we have
@@ -987,9 +972,6 @@ kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *d
987 if (!preemptible() && kprobe_running() && 972 if (!preemptible() && kprobe_running() &&
988 kprobe_fault_handler(args->regs, args->trapnr)) 973 kprobe_fault_handler(args->regs, args->trapnr))
989 ret = NOTIFY_STOP; 974 ret = NOTIFY_STOP;
990 break;
991 default:
992 break;
993 } 975 }
994 return ret; 976 return ret;
995} 977}
diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c
index 57409f6b8c62..e5d4a70814d7 100644
--- a/arch/x86/kernel/traps.c
+++ b/arch/x86/kernel/traps.c
@@ -334,6 +334,11 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
334 goto exit; 334 goto exit;
335#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */ 335#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
336 336
337#ifdef CONFIG_KPROBES
338 if (kprobe_int3_handler(regs))
339 return;
340#endif
341
337 if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, 342 if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
338 SIGTRAP) == NOTIFY_STOP) 343 SIGTRAP) == NOTIFY_STOP)
339 goto exit; 344 goto exit;
@@ -440,6 +445,11 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
440 /* Store the virtualized DR6 value */ 445 /* Store the virtualized DR6 value */
441 tsk->thread.debugreg6 = dr6; 446 tsk->thread.debugreg6 = dr6;
442 447
448#ifdef CONFIG_KPROBES
449 if (kprobe_debug_handler(regs))
450 goto exit;
451#endif
452
443 if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code, 453 if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code,
444 SIGTRAP) == NOTIFY_STOP) 454 SIGTRAP) == NOTIFY_STOP)
445 goto exit; 455 goto exit;