Skip to content

Commit 6f6343f

Browse files
mhiramathitachiIngo Molnar
authored andcommitted
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 <[email protected]> Reviewed-by: Steven Rostedt <[email protected]> Cc: Andrew Morton <[email protected]> Cc: Borislav Petkov <[email protected]> Cc: Jiri Kosina <[email protected]> Cc: Jonathan Lebon <[email protected]> Cc: Kees Cook <[email protected]> Cc: Rusty Russell <[email protected]> Cc: Seiji Aguchi <[email protected]> Link: http://lkml.kernel.org/r/[email protected] Signed-off-by: Ingo Molnar <[email protected]>
1 parent 98def1d commit 6f6343f

File tree

3 files changed

+15
-21
lines changed

3 files changed

+15
-21
lines changed

arch/x86/include/asm/kprobes.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -116,4 +116,6 @@ struct kprobe_ctlblk {
116116
extern int kprobe_fault_handler(struct pt_regs *regs, int trapnr);
117117
extern int kprobe_exceptions_notify(struct notifier_block *self,
118118
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);
119121
#endif /* _ASM_X86_KPROBES_H */

arch/x86/kernel/kprobes/core.c

Lines changed: 3 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -559,7 +559,7 @@ reenter_kprobe(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *kcb
559559
* Interrupts are disabled on entry as trap3 is an interrupt gate and they
560560
* remain disabled throughout this function.
561561
*/
562-
static int __kprobes kprobe_handler(struct pt_regs *regs)
562+
int __kprobes kprobe_int3_handler(struct pt_regs *regs)
563563
{
564564
kprobe_opcode_t *addr;
565565
struct kprobe *p;
@@ -857,7 +857,7 @@ resume_execution(struct kprobe *p, struct pt_regs *regs, struct kprobe_ctlblk *k
857857
* Interrupts are disabled on entry as trap1 is an interrupt gate and they
858858
* remain disabled throughout this function.
859859
*/
860-
static int __kprobes post_kprobe_handler(struct pt_regs *regs)
860+
int __kprobes kprobe_debug_handler(struct pt_regs *regs)
861861
{
862862
struct kprobe *cur = kprobe_running();
863863
struct kprobe_ctlblk *kcb = get_kprobe_ctlblk();
@@ -963,22 +963,7 @@ kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *d
963963
if (args->regs && user_mode_vm(args->regs))
964964
return ret;
965965

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) {
982967
/*
983968
* To be potentially processing a kprobe fault and to
984969
* trust the result from kprobe_running(), we have
@@ -987,9 +972,6 @@ kprobe_exceptions_notify(struct notifier_block *self, unsigned long val, void *d
987972
if (!preemptible() && kprobe_running() &&
988973
kprobe_fault_handler(args->regs, args->trapnr))
989974
ret = NOTIFY_STOP;
990-
break;
991-
default:
992-
break;
993975
}
994976
return ret;
995977
}

arch/x86/kernel/traps.c

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -334,6 +334,11 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co
334334
goto exit;
335335
#endif /* CONFIG_KGDB_LOW_LEVEL_TRAP */
336336

337+
#ifdef CONFIG_KPROBES
338+
if (kprobe_int3_handler(regs))
339+
return;
340+
#endif
341+
337342
if (notify_die(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP,
338343
SIGTRAP) == NOTIFY_STOP)
339344
goto exit;
@@ -440,6 +445,11 @@ dotraplinkage void __kprobes do_debug(struct pt_regs *regs, long error_code)
440445
/* Store the virtualized DR6 value */
441446
tsk->thread.debugreg6 = dr6;
442447

448+
#ifdef CONFIG_KPROBES
449+
if (kprobe_debug_handler(regs))
450+
goto exit;
451+
#endif
452+
443453
if (notify_die(DIE_DEBUG, "debug", regs, (long)&dr6, error_code,
444454
SIGTRAP) == NOTIFY_STOP)
445455
goto exit;

0 commit comments

Comments
 (0)