]> git.hungrycats.org Git - linux/commitdiff
x86: don't send SIGBUS for kernel page faults
authorGreg Kroah-Hartman <gregkh@suse.de>
Fri, 13 Aug 2010 20:46:26 +0000 (13:46 -0700)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 20 Aug 2010 18:25:11 +0000 (11:25 -0700)
Based on commit 96054569190bdec375fe824e48ca1f4e3b53dd36 upstream,
authored by Linus Torvalds.

This is my backport to the .27 kernel tree, hopefully preserving
the same functionality.

Original commit message:
It's wrong for several reasons, but the most direct one is that the
fault may be for the stack accesses to set up a previous SIGBUS.  When
we have a kernel exception, the kernel exception handler does all the
fixups, not some user-level signal handler.

Even apart from the nested SIGBUS issue, it's also wrong to give out
kernel fault addresses in the signal handler info block, or to send a
SIGBUS when a system call already returns EFAULT.

Cc: Linus Torvalds <torvalds@linux-foundation.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
arch/x86/mm/fault.c

index 33842556ce70828eaabf88854ca25fede937667e..9d3c576a6b2e85f0d14a3073a6745d6af2df60db 100644 (file)
@@ -589,6 +589,7 @@ void __kprobes do_page_fault(struct pt_regs *regs, unsigned long error_code)
        unsigned long address;
        int write, si_code;
        int fault;
+       int should_exit_no_context = 0;
 #ifdef CONFIG_X86_64
        unsigned long flags;
 #endif
@@ -876,6 +877,9 @@ no_context:
        oops_end(flags, regs, SIGKILL);
 #endif
 
+       if (should_exit_no_context)
+               return;
+
 /*
  * We ran out of memory, or some other thing happened to us that made
  * us unable to handle the page fault gracefully.
@@ -901,8 +905,11 @@ do_sigbus:
        up_read(&mm->mmap_sem);
 
        /* Kernel mode? Handle exceptions or die */
-       if (!(error_code & PF_USER))
+       if (!(error_code & PF_USER)) {
+               should_exit_no_context = 1;
                goto no_context;
+       }
+
 #ifdef CONFIG_X86_32
        /* User space => ok to do another page fault */
        if (is_prefetch(regs, address, error_code))