aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/traps.c
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2007-05-02 13:27:05 -0400
committerAndi Kleen <andi@basil.nowhere.org>2007-05-02 13:27:05 -0400
commitd18951834216eae82e2f9112416111b4f55f1849 (patch)
tree50df6c7ebd261de01c0cc311d3eccd5b234720d9 /arch/x86_64/kernel/traps.c
parent00e065ea587363e538d9624eea8cacad12cb7397 (diff)
[PATCH] x86: Fix i386 and x86_64 fault information pollution
a userspace fault or a kernelspace fault which will result in the immediate death of the process. They should not be filled in as a result of a kernelspace fault which can be fixed up. Otherwise, if the process is handling SIGSEGV and examining the fault information, this can result in the kernel space fault trashing the previously stored fault information if it arrives between the userspace fault happening and the SIGSEGV being delivered to the process. Signed-off-by: Jeff Dike <jdike@addtoit.com> Signed-off-by: Andi Kleen <ak@suse.de> Acked-by: Jan Beulich <jbeulich@novell.com> -- arch/i386/kernel/traps.c | 24 ++++++++++++++++++------ arch/x86_64/kernel/traps.c | 30 +++++++++++++++++++++++------- 2 files changed, 41 insertions(+), 13 deletions(-)
Diffstat (limited to 'arch/x86_64/kernel/traps.c')
-rw-r--r--arch/x86_64/kernel/traps.c30
1 files changed, 23 insertions, 7 deletions
diff --git a/arch/x86_64/kernel/traps.c b/arch/x86_64/kernel/traps.c
index 09d2e8a10a49..cceef5bd7302 100644
--- a/arch/x86_64/kernel/traps.c
+++ b/arch/x86_64/kernel/traps.c
@@ -581,10 +581,20 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
581{ 581{
582 struct task_struct *tsk = current; 582 struct task_struct *tsk = current;
583 583
584 tsk->thread.error_code = error_code;
585 tsk->thread.trap_no = trapnr;
586
587 if (user_mode(regs)) { 584 if (user_mode(regs)) {
585 /*
586 * We want error_code and trap_no set for userspace
587 * faults and kernelspace faults which result in
588 * die(), but not kernelspace faults which are fixed
589 * up. die() gives the process no chance to handle
590 * the signal and notice the kernel fault information,
591 * so that won't result in polluting the information
592 * about previously queued, but not yet delivered,
593 * faults. See also do_general_protection below.
594 */
595 tsk->thread.error_code = error_code;
596 tsk->thread.trap_no = trapnr;
597
588 if (exception_trace && unhandled_signal(tsk, signr)) 598 if (exception_trace && unhandled_signal(tsk, signr))
589 printk(KERN_INFO 599 printk(KERN_INFO
590 "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n", 600 "%s[%d] trap %s rip:%lx rsp:%lx error:%lx\n",
@@ -605,8 +615,11 @@ static void __kprobes do_trap(int trapnr, int signr, char *str,
605 fixup = search_exception_tables(regs->rip); 615 fixup = search_exception_tables(regs->rip);
606 if (fixup) 616 if (fixup)
607 regs->rip = fixup->fixup; 617 regs->rip = fixup->fixup;
608 else 618 else {
619 tsk->thread.error_code = error_code;
620 tsk->thread.trap_no = trapnr;
609 die(str, regs, error_code); 621 die(str, regs, error_code);
622 }
610 return; 623 return;
611 } 624 }
612} 625}
@@ -682,10 +695,10 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
682 695
683 conditional_sti(regs); 696 conditional_sti(regs);
684 697
685 tsk->thread.error_code = error_code;
686 tsk->thread.trap_no = 13;
687
688 if (user_mode(regs)) { 698 if (user_mode(regs)) {
699 tsk->thread.error_code = error_code;
700 tsk->thread.trap_no = 13;
701
689 if (exception_trace && unhandled_signal(tsk, SIGSEGV)) 702 if (exception_trace && unhandled_signal(tsk, SIGSEGV))
690 printk(KERN_INFO 703 printk(KERN_INFO
691 "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n", 704 "%s[%d] general protection rip:%lx rsp:%lx error:%lx\n",
@@ -704,6 +717,9 @@ asmlinkage void __kprobes do_general_protection(struct pt_regs * regs,
704 regs->rip = fixup->fixup; 717 regs->rip = fixup->fixup;
705 return; 718 return;
706 } 719 }
720
721 tsk->thread.error_code = error_code;
722 tsk->thread.trap_no = 13;
707 if (notify_die(DIE_GPF, "general protection fault", regs, 723 if (notify_die(DIE_GPF, "general protection fault", regs,
708 error_code, 13, SIGSEGV) == NOTIFY_STOP) 724 error_code, 13, SIGSEGV) == NOTIFY_STOP)
709 return; 725 return;