Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Masami Hiramatsu and committed by
Ingo Molnar
6f6343f5 98def1de

+15 -21
+2
arch/x86/include/asm/kprobes.h
··· 116 116 extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr); 117 117 extern int kprobe_exceptions_notify(struct notifier_block *self, 118 118 unsigned long val, void *data); 119 + extern int kprobe_int3_handler(struct pt_regs *regs); 120 + extern int kprobe_debug_handler(struct pt_regs *regs); 119 121 #endif /* _ASM_X86_KPROBES_H */
+3 -21
arch/x86/kernel/kprobes/core.c
··· 559 559 * Interrupts are disabled on entry as trap3 is an interrupt gate and they 560 560 * remain disabled throughout this function. 561 561 */ 562 - static int __kprobes kprobe_handler(struct pt_regs *regs) 562 + int __kprobes kprobe_int3_handler(struct pt_regs *regs) 563 563 { 564 564 kprobe_opcode_t *addr; 565 565 struct kprobe *p; ··· 857 857 * Interrupts are disabled on entry as trap1 is an interrupt gate and they 858 858 * remain disabled throughout this function. 859 859 */ 860 - static int __kprobes post_kprobe_handler(struct pt_regs *regs) 860 + int __kprobes kprobe_debug_handler(struct pt_regs *regs) 861 861 { 862 862 struct kprobe *cur = kprobe_running(); 863 863 struct kprobe_ctlblk *kcb = get_kprobe_ctlblk(); ··· 963 963 if (args->regs && user_mode_vm(args->regs)) 964 964 return ret; 965 965 966 - switch (val) { 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: 966 + if (val == DIE_GPF) { 982 967 /* 983 968 * To be potentially processing a kprobe fault and to 984 969 * trust the result from kprobe_running(), we have ··· 972 987 if (!preemptible() && kprobe_running() && 973 988 kprobe_fault_handler(args->regs, args->trapnr)) 974 989 ret = NOTIFY_STOP; 975 - break; 976 - default: 977 - break; 978 990 } 979 991 return ret; 980 992 }
+10
arch/x86/kernel/traps.c
··· 334 334 goto exit; 335 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 342 if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, 338 343 SIGTRAP) == NOTIFY_STOP) 339 344 goto exit; ··· 444 439 445 440 /* Store the virtualized DR6 value */ 446 441 tsk->thread.debugreg6 = dr6; 442 + 443 + #ifdef CONFIG_KPROBES 444 + if (kprobe_debug_handler(regs)) 445 + goto exit; 446 + #endif 447 447 448 448 if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code, 449 449 SIGTRAP) == NOTIFY_STOP)