aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorFernando Luis Vázquez Cao <fernando@oss.ntt.co.jp>2006-09-26 04:52:36 -0400
committerAndi Kleen <andi@basil.nowhere.org>2006-09-26 04:52:36 -0400
commit06039754d775d3e48e4a292e4f353321205eff53 (patch)
treea6abdd9ca0efb34006792e7275c4a2c954b229be
parent6f6b1e0477ccb2f25a9b045e38440347d2ce21c8 (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.S3
-rw-r--r--arch/i386/kernel/nmi.c6
-rw-r--r--arch/i386/kernel/traps.c15
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 */
732ENTRY(nmi) 732KPROBE_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
808KPROBE_END(nmi)
808 809
809KPROBE_ENTRY(int3) 810KPROBE_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
883extern void die_nmi(struct pt_regs *, const char *msg); 884extern void die_nmi(struct pt_regs *, const char *msg);
884 885
885int 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 }
968done: 968done:
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
692static void mem_parity_error(unsigned char reason, struct pt_regs * regs) 692static __kprobes void
693mem_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
707static void io_check_error(unsigned char reason, struct pt_regs * regs) 708static __kprobes void
709io_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
723static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) 725static __kprobes void
726unknown_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
742static DEFINE_SPINLOCK(nmi_print_lock); 745static DEFINE_SPINLOCK(nmi_print_lock);
743 746
744void die_nmi (struct pt_regs *regs, const char *msg) 747void __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
776static void default_do_nmi(struct pt_regs * regs) 779static __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
814fastcall void do_nmi(struct pt_regs * regs, long error_code) 817fastcall __kprobes void do_nmi(struct pt_regs * regs, long error_code)
815{ 818{
816 int cpu; 819 int cpu;
817 820