Merge branch 'x86-mm-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6-block.git] / arch / x86 / mm / fault.c
index d393ac669cc0fe6419e3368624e2b94b06f411d0..d973e61e450dc4f4733e838c67500aa711168302 100644 (file)
@@ -3,7 +3,6 @@
  *  Copyright (C) 2001, 2002 Andi Kleen, SuSE Labs.
  *  Copyright (C) 2008-2009, Red Hat Inc., Ingo Molnar
  */
-#include <linux/magic.h>               /* STACK_END_MAGIC              */
 #include <linux/sched.h>               /* test_thread_flag(), ...      */
 #include <linux/kdebug.h>              /* oops_begin/end, ...          */
 #include <linux/module.h>              /* search_exception_table       */
@@ -649,7 +648,6 @@ no_context(struct pt_regs *regs, unsigned long error_code,
           unsigned long address, int signal, int si_code)
 {
        struct task_struct *tsk = current;
-       unsigned long *stackend;
        unsigned long flags;
        int sig;
 
@@ -709,8 +707,7 @@ no_context(struct pt_regs *regs, unsigned long error_code,
 
        show_fault_oops(regs, error_code, address);
 
-       stackend = end_of_stack(tsk);
-       if (tsk != &init_task && *stackend != STACK_END_MAGIC)
+       if (task_stack_end_corrupted(tsk))
                printk(KERN_EMERG "Thread overran stack, or stack corrupted\n");
 
        tsk->thread.cr2         = address;
@@ -933,8 +930,17 @@ static int spurious_fault_check(unsigned long error_code, pte_t *pte)
  * cross-processor TLB flush, even if no stale TLB entries exist
  * on other processors.
  *
+ * Spurious faults may only occur if the TLB contains an entry with
+ * fewer permission than the page table entry.  Non-present (P = 0)
+ * and reserved bit (R = 1) faults are never spurious.
+ *
  * There are no security implications to leaving a stale TLB when
  * increasing the permissions on a page.
+ *
+ * Returns non-zero if a spurious fault was handled, zero otherwise.
+ *
+ * See Intel Developer's Manual Vol 3 Section 4.10.4.3, bullet 3
+ * (Optional Invalidation).
  */
 static noinline int
 spurious_fault(unsigned long error_code, unsigned long address)
@@ -945,8 +951,17 @@ spurious_fault(unsigned long error_code, unsigned long address)
        pte_t *pte;
        int ret;
 
-       /* Reserved-bit violation or user access to kernel space? */
-       if (error_code & (PF_USER | PF_RSVD))
+       /*
+        * Only writes to RO or instruction fetches from NX may cause
+        * spurious faults.
+        *
+        * These could be from user or supervisor accesses but the TLB
+        * is only lazily flushed after a kernel mapping protection
+        * change, so user accesses are not expected to cause spurious
+        * faults.
+        */
+       if (error_code != (PF_WRITE | PF_PROT)
+           && error_code != (PF_INSTR | PF_PROT))
                return 0;
 
        pgd = init_mm.pgd + pgd_index(address);