diff --git a/arch/x86/include/asm/alternative.h b/arch/x86/include/asm/alternative.h index 4daf8c501239..0a3f9c9f98d5 100644 --- a/arch/x86/include/asm/alternative.h +++ b/arch/x86/include/asm/alternative.h @@ -5,6 +5,7 @@ #include #include #include +#include /* * Alternative inline assembly for SMP. @@ -224,6 +225,7 @@ extern void *text_poke_early(void *addr, const void *opcode, size_t len); * inconsistent instruction while you patch. */ extern void *text_poke(void *addr, const void *opcode, size_t len); +extern int poke_int3_handler(struct pt_regs *regs); extern void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler); #endif /* _ASM_X86_ALTERNATIVE_H */ diff --git a/arch/x86/kernel/alternative.c b/arch/x86/kernel/alternative.c index 5d8782ee3dd7..15e8563e5c24 100644 --- a/arch/x86/kernel/alternative.c +++ b/arch/x86/kernel/alternative.c @@ -605,26 +605,24 @@ static void do_sync_core(void *info) static bool bp_patching_in_progress; static void *bp_int3_handler, *bp_int3_addr; -static int int3_notify(struct notifier_block *self, unsigned long val, void *data) +int poke_int3_handler(struct pt_regs *regs) { - struct die_args *args = data; - /* bp_patching_in_progress */ smp_rmb(); if (likely(!bp_patching_in_progress)) - return NOTIFY_DONE; + return 0; - /* we are not interested in non-int3 faults and ring > 0 faults */ - if (val != DIE_INT3 || !args->regs || user_mode_vm(args->regs) - || args->regs->ip != (unsigned long)bp_int3_addr) - return NOTIFY_DONE; + if (user_mode_vm(regs) || regs->ip != (unsigned long)bp_int3_addr) + return 0; /* set up the specified breakpoint handler */ - args->regs->ip = (unsigned long) bp_int3_handler; + regs->ip = (unsigned long) bp_int3_handler; + + return 1; - return NOTIFY_STOP; } + /** * text_poke_bp() -- update instructions on live kernel on SMP * @addr: address to patch @@ -689,16 +687,3 @@ void *text_poke_bp(void *addr, const void *opcode, size_t len, void *handler) return addr; } -/* this one needs to run before anything else handles it as a - * regular exception */ -static struct notifier_block int3_nb = { - .priority = 0x7fffffff, - .notifier_call = int3_notify -}; - -static int __init int3_init(void) -{ - return register_die_notifier(&int3_nb); -} - -arch_initcall(int3_init); diff --git a/arch/x86/kernel/traps.c b/arch/x86/kernel/traps.c index 1b23a1c92746..8c8093b146ca 100644 --- a/arch/x86/kernel/traps.c +++ b/arch/x86/kernel/traps.c @@ -58,6 +58,7 @@ #include #include #include +#include #ifdef CONFIG_X86_64 #include @@ -327,6 +328,9 @@ dotraplinkage void __kprobes notrace do_int3(struct pt_regs *regs, long error_co ftrace_int3_handler(regs)) return; #endif + if (poke_int3_handler(regs)) + return; + prev_state = exception_enter(); #ifdef CONFIG_KGDB_LOW_LEVEL_TRAP if (kgdb_ll_trap(DIE_INT3, "int3", regs, error_code, X86_TRAP_BP, diff --git a/kernel/kprobes.c b/kernel/kprobes.c index b58b490fa439..6e33498d665c 100644 --- a/kernel/kprobes.c +++ b/kernel/kprobes.c @@ -1709,7 +1709,7 @@ EXPORT_SYMBOL_GPL(unregister_kprobes); static struct notifier_block kprobe_exceptions_nb = { .notifier_call = kprobe_exceptions_notify, - .priority = 0x7ffffff0 /* High priority, but not first. */ + .priority = 0x7fffffff /* we need to be notified first */ }; unsigned long __weak arch_deref_entry_point(void *entry)