From: Hirokazu Takata [PATCH 2.6.10-rc3-mm1] m32r: Cause SIGSEGV for nonexec page execution (1/3) - Cause a segmentation fault for an illegal execution of a code on non-executable memory page. Signed-off-by: Naoto Sugai Signed-off-by: Hirokazu Takata --- Signed-off-by: Andrew Morton --- 25-akpm/arch/m32r/mm/fault.c | 37 ++++++++++++++++++++++++------------- 25-akpm/include/asm-m32r/pgtable.h | 21 ++++++++++----------- 2 files changed, 34 insertions(+), 24 deletions(-) diff -puN arch/m32r/mm/fault.c~m32r-cause-sigsegv-for-nonexec-page arch/m32r/mm/fault.c --- 25/arch/m32r/mm/fault.c~m32r-cause-sigsegv-for-nonexec-page Thu Dec 16 15:40:11 2004 +++ 25-akpm/arch/m32r/mm/fault.c Thu Dec 16 15:40:11 2004 @@ -96,6 +96,11 @@ void bust_spinlocks(int yes) * bit 2 == 0 means kernel, 1 means user-mode * bit 3 == 0 means data, 1 means instruction *======================================================================*/ +#define ACE_PROTECTION 1 +#define ACE_WRITE 2 +#define ACE_USERMODE 4 +#define ACE_INSTRUCTION 8 + asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code, unsigned long address) { @@ -126,10 +131,10 @@ asmlinkage void do_page_fault(struct pt_ * nothing more. * * This verifies that the fault happens in kernel space - * (error_code & 4) == 0, and that the fault was not a - * protection error (error_code & 1) == 0. + * (error_code & ACE_USEMODE) == 0, and that the fault was not a + * protection error (error_code & ACE_PROTECTION) == 0. */ - if (address >= TASK_SIZE && !(error_code & 4)) + if (address >= TASK_SIZE && !(error_code & ACE_USERMODE)) goto vmalloc_fault; mm = tsk->mm; @@ -157,7 +162,7 @@ asmlinkage void do_page_fault(struct pt_ * thus avoiding the deadlock. */ if (!down_read_trylock(&mm->mmap_sem)) { - if ((error_code & 4) == 0 && + if ((error_code & ACE_USERMODE) == 0 && !search_exception_tables(regs->psw)) goto bad_area_nosemaphore; down_read(&mm->mmap_sem); @@ -171,7 +176,7 @@ asmlinkage void do_page_fault(struct pt_ if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; #if 0 - if (error_code & 4) { + if (error_code & ACE_USERMODE) { /* * accessing the stack below "spu" is always a bug. * The "+ 4" is there due to the push instruction @@ -191,27 +196,33 @@ asmlinkage void do_page_fault(struct pt_ good_area: info.si_code = SEGV_ACCERR; write = 0; - switch (error_code & 3) { + switch (error_code & (ACE_WRITE|ACE_PROTECTION)) { default: /* 3: write, present */ /* fall through */ - case 2: /* write, not present */ + case ACE_WRITE: /* write, not present */ if (!(vma->vm_flags & VM_WRITE)) goto bad_area; write++; break; - case 1: /* read, present */ + case ACE_PROTECTION: /* read, present */ case 0: /* read, not present */ if (!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; } + /* + * For instruction access exception, check if the area is executable + */ + if ((error_code & ACE_INSTRUCTION) && !(vma->vm_flags & VM_EXEC)) + goto bad_area; + survive: /* * If for any reason at all we couldn't handle the fault, * make sure we exit gracefully rather than endlessly redo * the fault. */ - addr = (address & PAGE_MASK) | (error_code & 8); + addr = (address & PAGE_MASK) | (error_code & ACE_INSTRUCTION); switch (handle_mm_fault(mm, vma, addr, write)) { case VM_FAULT_MINOR: tsk->min_flt++; @@ -239,7 +250,7 @@ bad_area: bad_area_nosemaphore: /* User mode accesses just cause a SIGSEGV */ - if (error_code & 4) { + if (error_code & ACE_USERMODE) { tsk->thread.address = address; tsk->thread.error_code = error_code | (address >= TASK_SIZE); tsk->thread.trap_no = 14; @@ -295,7 +306,7 @@ out_of_memory: goto survive; } printk("VM: killing process %s\n", tsk->comm); - if (error_code & 4) + if (error_code & ACE_USERMODE) do_exit(SIGKILL); goto no_context; @@ -303,7 +314,7 @@ do_sigbus: up_read(&mm->mmap_sem); /* Kernel mode? Handle exception or die */ - if (!(error_code & 4)) + if (!(error_code & ACE_USERMODE)) goto no_context; tsk->thread.address = address; @@ -352,7 +363,7 @@ vmalloc_fault: if (!pte_present(*pte_k)) goto no_context; - addr = (address & PAGE_MASK) | (error_code & 8); + addr = (address & PAGE_MASK) | (error_code & ACE_INSTRUCTION); update_mmu_cache(NULL, addr, *pte_k); return; } diff -puN include/asm-m32r/pgtable.h~m32r-cause-sigsegv-for-nonexec-page include/asm-m32r/pgtable.h --- 25/include/asm-m32r/pgtable.h~m32r-cause-sigsegv-for-nonexec-page Thu Dec 16 15:40:11 2004 +++ 25-akpm/include/asm-m32r/pgtable.h Thu Dec 16 15:40:11 2004 @@ -146,8 +146,7 @@ extern unsigned long empty_zero_page[102 __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_WRITE | _PAGE_READ \ | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_COPY \ - __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_USER \ - | _PAGE_ACCESSED) + __pgprot(_PAGE_PRESENT | _PAGE_READ | _PAGE_USER | _PAGE_ACCESSED) #define PAGE_COPY_X \ __pgprot(_PAGE_PRESENT | _PAGE_EXEC | _PAGE_READ | _PAGE_USER \ | _PAGE_ACCESSED) @@ -188,23 +187,23 @@ extern unsigned long empty_zero_page[102 * the same are read. Also, write permissions imply read permissions. * This is the closest we can get.. */ - /* rwx */ + /* xwr */ #define __P000 PAGE_NONE -#define __P001 PAGE_READONLY_X -#define __P010 PAGE_COPY_X -#define __P011 PAGE_COPY_X -#define __P100 PAGE_READONLY +#define __P001 PAGE_READONLY +#define __P010 PAGE_COPY +#define __P011 PAGE_COPY +#define __P100 PAGE_READONLY_X #define __P101 PAGE_READONLY_X #define __P110 PAGE_COPY_X #define __P111 PAGE_COPY_X #define __S000 PAGE_NONE -#define __S001 PAGE_READONLY_X +#define __S001 PAGE_READONLY #define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED_X -#define __S100 PAGE_READONLY +#define __S011 PAGE_SHARED +#define __S100 PAGE_READONLY_X #define __S101 PAGE_READONLY_X -#define __S110 PAGE_SHARED +#define __S110 PAGE_SHARED_X #define __S111 PAGE_SHARED_X /* page table for 0-4MB for everybody */ _