upgrade to fedora-2.6.12-1.1398.FC4 + vserver 2.0.rc7
[linux-2.6.git] / arch / ppc64 / mm / fault.c
index b78e7f4..20b0f37 100644 (file)
@@ -36,6 +36,7 @@
 #include <asm/mmu_context.h>
 #include <asm/system.h>
 #include <asm/uaccess.h>
+#include <asm/kdebug.h>
 
 /*
  * Check whether the instruction at regs->nip is a store using
@@ -90,11 +91,16 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
        struct mm_struct *mm = current->mm;
        siginfo_t info;
        unsigned long code = SEGV_MAPERR;
-       unsigned long is_write = error_code & 0x02000000;
+       unsigned long is_write = error_code & DSISR_ISSTORE;
        unsigned long trap = TRAP(regs);
+       unsigned long is_exec = trap == 0x400;
 
        BUG_ON((trap == 0x380) || (trap == 0x480));
 
+       if (notify_die(DIE_PAGE_FAULT, "page_fault", regs, error_code,
+                               11, SIGSEGV) == NOTIFY_STOP)
+               return 0;
+
        if (trap == 0x300) {
                if (debugger_fault_handler(regs))
                        return 0;
@@ -104,7 +110,10 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
        if (!user_mode(regs) && (address >= TASK_SIZE))
                return SIGSEGV;
 
-       if (error_code & 0x00400000) {
+       if (error_code & DSISR_DABRMATCH) {
+               if (notify_die(DIE_DABR_MATCH, "dabr_match", regs, error_code,
+                                       11, SIGSEGV) == NOTIFY_STOP)
+                       return 0;
                if (debugger_dabr_match(regs))
                        return 0;
        }
@@ -191,16 +200,19 @@ int do_page_fault(struct pt_regs *regs, unsigned long address,
 good_area:
        code = SEGV_ACCERR;
 
+       if (is_exec) {
+               /* protection fault */
+               if (error_code & DSISR_PROTFAULT)
+                       goto bad_area;
+               if (!(vma->vm_flags & VM_EXEC))
+                       goto bad_area;
        /* a write */
-       if (is_write) {
+       } else if (is_write) {
                if (!(vma->vm_flags & VM_WRITE))
                        goto bad_area;
        /* a read */
        } else {
-               /* protection fault */
-               if (error_code & 0x08000000)
-                       goto bad_area;
-               if (!(vma->vm_flags & (VM_READ | VM_EXEC)))
+               if (!(vma->vm_flags & VM_READ))
                        goto bad_area;
        }
 
@@ -243,6 +255,12 @@ bad_area_nosemaphore:
                return 0;
        }
 
+       if (trap == 0x400 && (error_code & DSISR_PROTFAULT)
+           && printk_ratelimit())
+               printk(KERN_CRIT "kernel tried to execute NX-protected"
+                      " page (%lx) - exploit attempt? (uid: %d)\n",
+                      address, current->uid);
+
        return SIGSEGV;
 
 /*