Commit 06039754d775d3e48e4a292e4f353321205eff53
Committed by
Andi Kleen
1 parent
6f6b1e0477
[PATCH] i386: Disallow kprobes on NMI handlers
A kprobe executes IRET early and that could cause NMI recursion and stack corruption. Note: This problem was originally spotted and solved by Andi Kleen in the x86_64 architecture. This patch is an adaption of his patch for i386. AK: Merged with current code which was a bit different. AK: Removed printk in nmi handler that shouldn't be there in the first time AK: Added missing include. AK: added KPROBES_END Signed-off-by: Fernando Vazquez <fernando@intellilink.co.jp> Signed-off-by: Andi Kleen <ak@suse.de>
Showing 3 changed files with 14 additions and 10 deletions Side-by-side Diff
arch/i386/kernel/entry.S
... | ... | @@ -729,7 +729,7 @@ |
729 | 729 | * check whether we got an NMI on the debug path where the debug |
730 | 730 | * fault happened on the sysenter path. |
731 | 731 | */ |
732 | -ENTRY(nmi) | |
732 | +KPROBE_ENTRY(nmi) | |
733 | 733 | RING0_INT_FRAME |
734 | 734 | pushl %eax |
735 | 735 | CFI_ADJUST_CFA_OFFSET 4 |
... | ... | @@ -805,6 +805,7 @@ |
805 | 805 | .align 4 |
806 | 806 | .long 1b,iret_exc |
807 | 807 | .previous |
808 | +KPROBE_END(nmi) | |
808 | 809 | |
809 | 810 | KPROBE_ENTRY(int3) |
810 | 811 | RING0_INT_FRAME |
arch/i386/kernel/nmi.c
... | ... | @@ -22,6 +22,7 @@ |
22 | 22 | #include <linux/sysctl.h> |
23 | 23 | #include <linux/percpu.h> |
24 | 24 | #include <linux/dmi.h> |
25 | +#include <linux/kprobes.h> | |
25 | 26 | |
26 | 27 | #include <asm/smp.h> |
27 | 28 | #include <asm/nmi.h> |
... | ... | @@ -882,7 +883,7 @@ |
882 | 883 | |
883 | 884 | extern void die_nmi(struct pt_regs *, const char *msg); |
884 | 885 | |
885 | -int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) | |
886 | +__kprobes int nmi_watchdog_tick(struct pt_regs * regs, unsigned reason) | |
886 | 887 | { |
887 | 888 | |
888 | 889 | /* |
... | ... | @@ -962,8 +963,7 @@ |
962 | 963 | * This matches the old behaviour. |
963 | 964 | */ |
964 | 965 | rc = 1; |
965 | - } else | |
966 | - printk(KERN_WARNING "Unknown enabled NMI hardware?!\n"); | |
966 | + } | |
967 | 967 | } |
968 | 968 | done: |
969 | 969 | return rc; |
arch/i386/kernel/traps.c
... | ... | @@ -689,7 +689,8 @@ |
689 | 689 | } |
690 | 690 | } |
691 | 691 | |
692 | -static void mem_parity_error(unsigned char reason, struct pt_regs * regs) | |
692 | +static __kprobes void | |
693 | +mem_parity_error(unsigned char reason, struct pt_regs * regs) | |
693 | 694 | { |
694 | 695 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " |
695 | 696 | "CPU %d.\n", reason, smp_processor_id()); |
... | ... | @@ -704,7 +705,8 @@ |
704 | 705 | clear_mem_error(reason); |
705 | 706 | } |
706 | 707 | |
707 | -static void io_check_error(unsigned char reason, struct pt_regs * regs) | |
708 | +static __kprobes void | |
709 | +io_check_error(unsigned char reason, struct pt_regs * regs) | |
708 | 710 | { |
709 | 711 | unsigned long i; |
710 | 712 | |
... | ... | @@ -720,7 +722,8 @@ |
720 | 722 | outb(reason, 0x61); |
721 | 723 | } |
722 | 724 | |
723 | -static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) | |
725 | +static __kprobes void | |
726 | +unknown_nmi_error(unsigned char reason, struct pt_regs * regs) | |
724 | 727 | { |
725 | 728 | #ifdef CONFIG_MCA |
726 | 729 | /* Might actually be able to figure out what the guilty party |
... | ... | @@ -741,7 +744,7 @@ |
741 | 744 | |
742 | 745 | static DEFINE_SPINLOCK(nmi_print_lock); |
743 | 746 | |
744 | -void die_nmi (struct pt_regs *regs, const char *msg) | |
747 | +void __kprobes die_nmi(struct pt_regs *regs, const char *msg) | |
745 | 748 | { |
746 | 749 | if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == |
747 | 750 | NOTIFY_STOP) |
... | ... | @@ -773,7 +776,7 @@ |
773 | 776 | do_exit(SIGSEGV); |
774 | 777 | } |
775 | 778 | |
776 | -static void default_do_nmi(struct pt_regs * regs) | |
779 | +static __kprobes void default_do_nmi(struct pt_regs * regs) | |
777 | 780 | { |
778 | 781 | unsigned char reason = 0; |
779 | 782 | |
... | ... | @@ -811,7 +814,7 @@ |
811 | 814 | reassert_nmi(); |
812 | 815 | } |
813 | 816 | |
814 | -fastcall void do_nmi(struct pt_regs * regs, long error_code) | |
817 | +fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code) | |
815 | 818 | { |
816 | 819 | int cpu; |
817 | 820 |