aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2006-02-03 15:50:41 -0500
committerLinus Torvalds <torvalds@g5.osdl.org>2006-02-04 19:43:12 -0500
commiteddb6fb9a54cdc8c7c37e056a2b4bbbc8a128a36 (patch)
treec8b9a0773518f45aa86d861fce959c3c4f946b06 /arch/x86_64
parent2f01942536d8c686a3f6b3b38f1257caa2fb763e (diff)
[PATCH] x86_64: Disallow kprobes on NMI handlers
A kprobe executes IRET early and that could cause NMI recursion and stack corruption. Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@osdl.org>
Diffstat (limited to 'arch/x86_64')
-rw-r--r--arch/x86_64/kernel/entry.S3
-rw-r--r--arch/x86_64/kernel/nmi.c7
-rw-r--r--arch/x86_64/kernel/traps.c21
3 files changed, 18 insertions, 13 deletions
diff --git a/arch/x86_64/kernel/entry.S b/arch/x86_64/kernel/entry.S
index dbdba56e8faa..cdf9cb1288c1 100644
--- a/arch/x86_64/kernel/entry.S
+++ b/arch/x86_64/kernel/entry.S
@@ -922,7 +922,7 @@ KPROBE_ENTRY(debug)
922 .previous .text 922 .previous .text
923 923
924 /* runs on exception stack */ 924 /* runs on exception stack */
925ENTRY(nmi) 925KPROBE_ENTRY(nmi)
926 INTR_FRAME 926 INTR_FRAME
927 pushq $-1 927 pushq $-1
928 CFI_ADJUST_CFA_OFFSET 8 928 CFI_ADJUST_CFA_OFFSET 8
@@ -969,6 +969,7 @@ paranoid_schedule:
969 cli 969 cli
970 jmp paranoid_userspace 970 jmp paranoid_userspace
971 CFI_ENDPROC 971 CFI_ENDPROC
972 .previous .text
972 973
973KPROBE_ENTRY(int3) 974KPROBE_ENTRY(int3)
974 INTR_FRAME 975 INTR_FRAME
diff --git a/arch/x86_64/kernel/nmi.c b/arch/x86_64/kernel/nmi.c
index 5fae6f0cd994..8be407a1f62d 100644
--- a/arch/x86_64/kernel/nmi.c
+++ b/arch/x86_64/kernel/nmi.c
@@ -24,6 +24,7 @@
24#include <linux/sysdev.h> 24#include <linux/sysdev.h>
25#include <linux/nmi.h> 25#include <linux/nmi.h>
26#include <linux/sysctl.h> 26#include <linux/sysctl.h>
27#include <linux/kprobes.h>
27 28
28#include <asm/smp.h> 29#include <asm/smp.h>
29#include <asm/mtrr.h> 30#include <asm/mtrr.h>
@@ -468,7 +469,7 @@ void touch_nmi_watchdog (void)
468 touch_softlockup_watchdog(); 469 touch_softlockup_watchdog();
469} 470}
470 471
471void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason) 472void __kprobes nmi_watchdog_tick(struct pt_regs * regs, unsigned reason)
472{ 473{
473 int sum; 474 int sum;
474 int touched = 0; 475 int touched = 0;
@@ -512,14 +513,14 @@ void nmi_watchdog_tick (struct pt_regs * regs, unsigned reason)
512 } 513 }
513} 514}
514 515
515static int dummy_nmi_callback(struct pt_regs * regs, int cpu) 516static __kprobes int dummy_nmi_callback(struct pt_regs * regs, int cpu)
516{ 517{
517 return 0; 518 return 0;
518} 519}
519 520
520static nmi_callback_t nmi_callback = dummy_nmi_callback; 521static nmi_callback_t nmi_callback = dummy_nmi_callback;
521 522
522asmlinkage void do_nmi(struct pt_regs * regs, long error_code) 523asmlinkage __kprobes void do_nmi(struct pt_regs * regs, long error_code)
523{ 524{
524 int cpu = safe_smp_processor_id(); 525 int cpu = safe_smp_processor_id();
525 526
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 8bb0aeda78b9..ee1b2da9e5e7 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -372,7 +372,7 @@ void out_of_line_bug(void)
372static DEFINE_SPINLOCK(die_lock); 372static DEFINE_SPINLOCK(die_lock);
373static int die_owner = -1; 373static int die_owner = -1;
374 374
375unsigned long oops_begin(void) 375unsigned __kprobes long oops_begin(void)
376{ 376{
377 int cpu = safe_smp_processor_id(); 377 int cpu = safe_smp_processor_id();
378 unsigned long flags; 378 unsigned long flags;
@@ -391,7 +391,7 @@ unsigned long oops_begin(void)
391 return flags; 391 return flags;
392} 392}
393 393
394void oops_end(unsigned long flags) 394void __kprobes oops_end(unsigned long flags)
395{ 395{
396 die_owner = -1; 396 die_owner = -1;
397 bust_spinlocks(0); 397 bust_spinlocks(0);
@@ -400,7 +400,7 @@ void oops_end(unsigned long flags)
400 panic("Oops"); 400 panic("Oops");
401} 401}
402 402
403void __die(const char * str, struct pt_regs * regs, long err) 403void __kprobes __die(const char * str, struct pt_regs * regs, long err)
404{ 404{
405 static int die_counter; 405 static int die_counter;
406 printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter); 406 printk(KERN_EMERG "%s: %04lx [%u] ", str, err & 0xffff,++die_counter);
@@ -432,7 +432,7 @@ void die(const char * str, struct pt_regs * regs, long err)
432 do_exit(SIGSEGV); 432 do_exit(SIGSEGV);
433} 433}
434 434
435void die_nmi(char *str, struct pt_regs *regs) 435void __kprobes die_nmi(char *str, struct pt_regs *regs)
436{ 436{
437 unsigned long flags = oops_begin(); 437 unsigned long flags = oops_begin();
438 438
@@ -575,7 +575,8 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
575 } 575 }
576} 576}
577 577
578static void mem_parity_error(unsigned char reason, struct pt_regs * regs) 578static __kprobes void
579mem_parity_error(unsigned char reason, struct pt_regs * regs)
579{ 580{
580 printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n"); 581 printk("Uhhuh. NMI received. Dazed and confused, but trying to continue\n");
581 printk("You probably have a hardware problem with your RAM chips\n"); 582 printk("You probably have a hardware problem with your RAM chips\n");
@@ -585,7 +586,8 @@ static void mem_parity_error(unsigned char reason, struct pt_regs * regs)
585 outb(reason, 0x61); 586 outb(reason, 0x61);
586} 587}
587 588
588static void io_check_error(unsigned char reason, struct pt_regs * regs) 589static __kprobes void
590io_check_error(unsigned char reason, struct pt_regs * regs)
589{ 591{
590 printk("NMI: IOCK error (debug interrupt?)\n"); 592 printk("NMI: IOCK error (debug interrupt?)\n");
591 show_registers(regs); 593 show_registers(regs);
@@ -598,7 +600,8 @@ static void io_check_error(unsigned char reason, struct pt_regs * regs)
598 outb(reason, 0x61); 600 outb(reason, 0x61);
599} 601}
600 602
601static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) 603static __kprobes void
604unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
602{ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason); 605{ printk("Uhhuh. NMI received for unknown reason %02x.\n", reason);
603 printk("Dazed and confused, but trying to continue\n"); 606 printk("Dazed and confused, but trying to continue\n");
604 printk("Do you have a strange power saving mode enabled?\n"); 607 printk("Do you have a strange power saving mode enabled?\n");
@@ -606,7 +609,7 @@ static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs)
606 609
607/* Runs on IST stack. This code must keep interrupts off all the time. 610/* Runs on IST stack. This code must keep interrupts off all the time.
608 Nested NMIs are prevented by the CPU. */ 611 Nested NMIs are prevented by the CPU. */
609asmlinkage void default_do_nmi(struct pt_regs *regs) 612asmlinkage __kprobes void default_do_nmi(struct pt_regs *regs)
610{ 613{
611 unsigned char reason = 0; 614 unsigned char reason = 0;
612 int cpu; 615 int cpu;
@@ -658,7 +661,7 @@ asmlinkage void __kprobes do_int3(struct pt_regs * regs, long error_code)
658/* Help handler running on IST stack to switch back to user stack 661/* Help handler running on IST stack to switch back to user stack
659 for scheduling or signal handling. The actual stack switch is done in 662 for scheduling or signal handling. The actual stack switch is done in
660 entry.S */ 663 entry.S */
661asmlinkage struct pt_regs *sync_regs(struct pt_regs *eregs) 664asmlinkage __kprobes struct pt_regs *sync_regs(struct pt_regs *eregs)
662{ 665{
663 struct pt_regs *regs = eregs; 666 struct pt_regs *regs = eregs;
664 /* Did already sync */ 667 /* Did already sync */