diff options
author | Fernando Luis Vázquez Cao <fernando@oss.ntt.co.jp> | 2006-09-26 04:52:36 -0400 |
---|---|---|
committer | Andi Kleen <andi@basil.nowhere.org> | 2006-09-26 04:52:36 -0400 |
commit | 06039754d775d3e48e4a292e4f353321205eff53 (patch) | |
tree | a6abdd9ca0efb34006792e7275c4a2c954b229be | |
parent | 6f6b1e0477ccb2f25a9b045e38440347d2ce21c8 (diff) |
[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>
-rw-r--r-- | arch/i386/kernel/entry.S | 3 | ||||
-rw-r--r-- | arch/i386/kernel/nmi.c | 6 | ||||
-rw-r--r-- | arch/i386/kernel/traps.c | 15 |
3 files changed, 14 insertions, 10 deletions
diff --git a/arch/i386/kernel/entry.S b/arch/i386/kernel/entry.S index dede506e5bd0..0928f70639aa 100644 --- a/arch/i386/kernel/entry.S +++ b/arch/i386/kernel/entry.S | |||
@@ -729,7 +729,7 @@ KPROBE_END(debug) | |||
729 | * check whether we got an NMI on the debug path where the debug | 729 | * check whether we got an NMI on the debug path where the debug |
730 | * fault happened on the sysenter path. | 730 | * fault happened on the sysenter path. |
731 | */ | 731 | */ |
732 | ENTRY(nmi) | 732 | KPROBE_ENTRY(nmi) |
733 | RING0_INT_FRAME | 733 | RING0_INT_FRAME |
734 | pushl %eax | 734 | pushl %eax |
735 | CFI_ADJUST_CFA_OFFSET 4 | 735 | CFI_ADJUST_CFA_OFFSET 4 |
@@ -805,6 +805,7 @@ nmi_16bit_stack: | |||
805 | .align 4 | 805 | .align 4 |
806 | .long 1b,iret_exc | 806 | .long 1b,iret_exc |
807 | .previous | 807 | .previous |
808 | KPROBE_END(nmi) | ||
808 | 809 | ||
809 | KPROBE_ENTRY(int3) | 810 | KPROBE_ENTRY(int3) |
810 | RING0_INT_FRAME | 811 | RING0_INT_FRAME |
diff --git a/arch/i386/kernel/nmi.c b/arch/i386/kernel/nmi.c index 7b9a053effa3..dbda706fdd14 100644 --- a/arch/i386/kernel/nmi.c +++ b/arch/i386/kernel/nmi.c | |||
@@ -22,6 +22,7 @@ | |||
22 | #include <linux/sysctl.h> | 22 | #include <linux/sysctl.h> |
23 | #include <linux/percpu.h> | 23 | #include <linux/percpu.h> |
24 | #include <linux/dmi.h> | 24 | #include <linux/dmi.h> |
25 | #include <linux/kprobes.h> | ||
25 | 26 | ||
26 | #include <asm/smp.h> | 27 | #include <asm/smp.h> |
27 | #include <asm/nmi.h> | 28 | #include <asm/nmi.h> |
@@ -882,7 +883,7 @@ EXPORT_SYMBOL(touch_nmi_watchdog); | |||
882 | 883 | ||
883 | extern void die_nmi(struct pt_regs *, const char *msg); | 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 @@ int nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) | |||
962 | * This matches the old behaviour. | 963 | * This matches the old behaviour. |
963 | */ | 964 | */ |
964 | rc = 1; | 965 | rc = 1; |
965 | } else | 966 | } |
966 | printk(KERN_WARNING "Unknown enabled NMI hardware?!\n"); | ||
967 | } | 967 | } |
968 | done: | 968 | done: |
969 | return rc; | 969 | return rc; |
diff --git a/arch/i386/kernel/traps.c b/arch/i386/kernel/traps.c index 00d643f3de41..5c0f4960c67d 100644 --- a/arch/i386/kernel/traps.c +++ b/arch/i386/kernel/traps.c | |||
@@ -689,7 +689,8 @@ gp_in_kernel: | |||
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 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " | 695 | printk(KERN_EMERG "Uhhuh. NMI received for unknown reason %02x on " |
695 | "CPU %d.\n", reason, smp_processor_id()); | 696 | "CPU %d.\n", reason, smp_processor_id()); |
@@ -704,7 +705,8 @@ static void mem_parity_error(unsigned char reason, struct pt_regs * regs) | |||
704 | clear_mem_error(reason); | 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 | unsigned long i; | 711 | unsigned long i; |
710 | 712 | ||
@@ -720,7 +722,8 @@ static void io_check_error(unsigned char reason, struct pt_regs * regs) | |||
720 | outb(reason, 0x61); | 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 | #ifdef CONFIG_MCA | 728 | #ifdef CONFIG_MCA |
726 | /* Might actually be able to figure out what the guilty party | 729 | /* Might actually be able to figure out what the guilty party |
@@ -741,7 +744,7 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) | |||
741 | 744 | ||
742 | static DEFINE_SPINLOCK(nmi_print_lock); | 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 | if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == | 749 | if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == |
747 | NOTIFY_STOP) | 750 | NOTIFY_STOP) |
@@ -773,7 +776,7 @@ void die_nmi (struct pt_regs *regs, const char *msg) | |||
773 | do_exit(SIGSEGV); | 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 | unsigned char reason = 0; | 781 | unsigned char reason = 0; |
779 | 782 | ||
@@ -811,7 +814,7 @@ static void default_do_nmi(struct pt_regs * regs) | |||
811 | reassert_nmi(); | 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 | int cpu; | 819 | int cpu; |
817 | 820 | ||