diff -NurX nopatch linux-2.2.17/arch/i386/kernel/entry.S linux-2.2.17-pax/arch/ i386/kernel/entry.S --- linux-2.2.17/arch/i386/kernel/entry.S Mon Sep 4 19:39:16 2000 +++ linux-2.2.17-pax/arch/i386/kernel/entry.S Sun Nov 5 14:05:19 2000 @@ -280,6 +280,36 @@ addl $8,%esp jmp ret_from_exception + ALIGN +error_code_page_fault: + pushl %ds + pushl %eax + xorl %eax,%eax + pushl %ebp + pushl %edi + pushl %esi + pushl %edx + decl %eax # eax = -1 + pushl %ecx + pushl %ebx + cld + movl %es,%cx + xchgl %eax, ORIG_EAX(%esp) # orig_eax (get the error code. ) + movl %esp,%edx + xchgl %ecx, ES(%esp) # get the address and save es. + pushl %eax # push the error code + pushl %edx + movl $(__KERNEL_DS),%edx + movl %dx,%ds + movl %dx,%es + GET_CURRENT(%ebx) + call *%ecx + addl $8,%esp + test %eax,%eax + jz ret_from_exception + jmp restore_all + + ENTRY(coprocessor_error) pushl $0 pushl $ SYMBOL_NAME(do_coprocessor_error) @@ -364,7 +394,7 @@ ENTRY(page_fault) pushl $ SYMBOL_NAME(do_page_fault) - jmp error_code + jmp error_code_page_fault ENTRY(machine_check) pushl $0 diff -NurX nopatch linux-2.2.17/arch/i386/kernel/signal.c linux-2.2.17-pax/arch /i386/kernel/signal.c --- linux-2.2.17/arch/i386/kernel/signal.c Tue Jan 4 19:12:11 2000 +++ linux-2.2.17-pax/arch/i386/kernel/signal.c Mon Oct 9 23:02:47 2000 @@ -399,7 +399,7 @@ esp = (unsigned long) ka->sa.sa_restorer; } - return (void *)((esp - frame_size) & -8ul); + return (void *)((esp - frame_size) & -16ul); } static void setup_frame(int sig, struct k_sigaction *ka, Binary files linux-2.2.17/arch/i386/mm/core and linux-2.2.17-pax/arch/i386/mm/c ore differ diff -NurX nopatch linux-2.2.17/arch/i386/mm/fault.c linux-2.2.17-pax/arch/i386 /mm/fault.c --- linux-2.2.17/arch/i386/mm/fault.c Thu May 4 02:16:31 2000 +++ linux-2.2.17-pax/arch/i386/mm/fault.c Mon Nov 13 15:56:56 2000 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -108,7 +109,7 @@ * bit 1 == 0 means read, 1 means write * bit 2 == 0 means kernel, 1 means user-mode */ -asmlinkage void do_page_fault(struct pt_regs *regs, unsigned long error_code) +asmlinkage int do_page_fault(struct pt_regs *regs, unsigned long error_code) { struct task_struct *tsk; struct mm_struct *mm; @@ -117,6 +118,9 @@ unsigned long page; unsigned long fixup; int write; + pgd_t *pgd; + pmd_t *pmd; + pte_t *pte; /* get the address */ __asm__("movl %%cr2,%0":"=r" (address)); @@ -136,8 +140,79 @@ vma = find_vma(mm, address); if (!vma) goto bad_area; - if (vma->vm_start <= address) + if (vma->vm_start <= address) { + if ((error_code & 5) == 5) { + pgd = pgd_offset(vma->vm_mm, address); + pmd = pmd_offset(pgd, address); + pte = pte_offset(pmd, address); + } else { + goto good_area; + } + if ((error_code & 7) == 5 && !pte_exec(*pte)) { + /* read/instruction fetch attempt from a protected page in user mode */ + unsigned long linear_cseip = regs->eip; + + if (VM_MASK & regs->eflags) { + linear_cseip = (((regs->xcs)&0xFFFF)<<4) + ((re gs->eip)&0xFFFF); + } else if (regs->xcs != __USER_CS) { /* hmmm, unknown p rotected mode code segment... */ + printk(KERN_ERR "PAX: wtf, task: %s:%d, CS:EIP: %04X:%08lX, SS:ESP: %04X:%08lX\n", tsk->comm, tsk->pid, regs->xcs, regs->eip, regs->xss, regs->esp); + goto pax_emu; + } else if (linear_cseip == address) { + if (((regs->eip & 0xF) <= 8) && + (*(unsigned short*)(regs->eip) == 0xb858) & & + (*(unsigned int*)(regs->eip+2) == __NR_sigr eturn) && + (*(unsigned short*)(regs->eip+6) == 0x80cd) ) + { + goto pax_emu; + } + if ((((regs->eip-1) & 0xF) <= 8) && + (*(unsigned short*)(regs->eip-1) == 0xb858) && + (*(unsigned int*)(regs->eip+2-1) == __NR_si greturn) && + (*(unsigned short*)(regs->eip+6-1) == 0x80c d)) + { + goto pax_emu; + } + if ((((regs->eip-1-5) & 0xF) <= 8) && + (regs->eax == __NR_sigreturn) && + (*(unsigned short*)(regs->eip-1-5) == 0xb85 8) && + (*(unsigned int*)(regs->eip+2-1-5) == __NR_ sigreturn) && + (*(unsigned short*)(regs->eip+6-1-5) == 0x8 0cd)) + { + goto pax_emu; + } + + if (((regs->eip & 0xF) <= 8) && + (*(unsigned char*)(regs->eip) == 0xb8) && + (*(unsigned int*)(regs->eip+1) == __NR_rt_s igreturn) && + (*(unsigned short*)(regs->eip+5) == 0x80cd) ) + { + goto pax_emu; + } + if ((((regs->eip-5) & 0xF) <= 8) && + (regs->eax == __NR_rt_sigreturn) && + (*(unsigned char*)(regs->eip-5) == 0xb8) && + (*(unsigned int*)(regs->eip+1-5) == __NR_rt _sigreturn) && + (*(unsigned short*)(regs->eip+5-5) == 0x80c d)) + { + goto pax_emu; + } + } + if (linear_cseip == address) { /* PAX in action */ + up(&mm->mmap_sem); + printk(KERN_ERR "PAX: terminating task: %s:%d, EIP: %08lX, ESP: %08lX\n", tsk->comm, tsk->pid, regs->eip, regs->esp); + tsk->tss.cr2 = address; + tsk->tss.error_code = error_code; + tsk->tss.trap_no = 14; + force_sig(SIGKILL,tsk); + return 0; + } + goto pax_emu; + } else if ((error_code & 7) == 7 && !pte_exec(*pte) && pte_writ e(*pte)) { + /* write attempt to a protected page in user mode */ + goto pax_emu; + } goto good_area; + } if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; if (error_code & 4) { @@ -200,7 +275,20 @@ tsk->tss.screen_bitmap |= 1 << bit; } up(&mm->mmap_sem); - return; + return 0; + + /* + * PAX: fill DTLB with user rights and retry + */ +pax_emu: + __asm__ __volatile__ ( + "invlpg %0\n" + "orb $0x4,%1\n" + "testb $0,%0\n" + "andb $0xFB,%1\n" + : : "g" (*(char*)address), "g" (*(char*)pte) : "memory", "cc"); + up(&mm->mmap_sem); + return 1; /* * Something tried to access memory that isn't in our memory map.. @@ -215,7 +303,7 @@ tsk->tss.error_code = error_code; tsk->tss.trap_no = 14; force_sig(SIGSEGV, tsk); - return; + return 0; } /* @@ -228,7 +316,7 @@ if (nr == 6) { do_invalid_op(regs, 0); - return; + return 0; } } @@ -236,7 +324,7 @@ /* Are we prepared to handle this kernel fault? */ if ((fixup = search_exception_table(regs->eip)) != 0) { regs->eip = fixup; - return; + return 0; } /* @@ -255,7 +343,7 @@ * CPU state on certain buggy processors. */ printk("Ok"); - return; + return 0; } if (address < PAGE_SIZE) @@ -310,7 +398,7 @@ tsk->policy |= SCHED_YIELD; schedule(); } - return; + return 0; } } goto no_context; @@ -330,4 +418,5 @@ /* Kernel mode? Handle exceptions or die */ if (!(error_code & 4)) goto no_context; + return 0; } diff -NurX nopatch linux-2.2.17/arch/i386/mm/init.c linux-2.2.17-pax/arch/i386/ mm/init.c --- linux-2.2.17/arch/i386/mm/init.c Wed Oct 27 02:53:39 1999 +++ linux-2.2.17-pax/arch/i386/mm/init.c Sat Sep 30 16:13:40 2000 @@ -141,7 +141,7 @@ "0" ((long) empty_bad_page), "1" (PAGE_SIZE/4) : "memory"); - return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED)) ; + return pte_mkdirty(mk_pte((unsigned long) empty_bad_page, PAGE_SHARED_E XEC)); } void show_mem(void) @@ -359,7 +359,7 @@ unsigned long old = pg0[0]; printk("Checking if this processor honours the WP bit even in superviso r mode... "); - pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY)); + pg0[0] = pte_val(mk_pte(PAGE_OFFSET, PAGE_READONLY_EXEC)); local_flush_tlb(); current->mm->mmap->vm_start += PAGE_SIZE; __asm__ __volatile__( diff -NurX nopatch linux-2.2.17/drivers/char/bttv.c linux-2.2.17-pax/drivers/ch ar/bttv.c --- linux-2.2.17/drivers/char/bttv.c Mon Sep 4 19:39:17 2000 +++ linux-2.2.17-pax/drivers/char/bttv.c Thu Nov 9 22:48:58 2000 @@ -2325,7 +2325,7 @@ while (size > 0) { page = kvirt_to_pa(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) return -EAGAIN; start+=PAGE_SIZE; pos+=PAGE_SIZE; diff -NurX nopatch linux-2.2.17/drivers/char/buz.c linux-2.2.17-pax/drivers/cha r/buz.c --- linux-2.2.17/drivers/char/buz.c Thu May 4 02:16:33 2000 +++ linux-2.2.17-pax/drivers/char/buz.c Thu Nov 9 22:49:12 2000 @@ -2989,7 +2989,7 @@ todo = fraglen; pos = (unsigned long) zr->jpg_gbuf[i].frag_tab[ 2 * j]; page = virt_to_phys(bus_to_virt(pos)); /* shou ld just be pos on i386 */ - if (remap_page_range(start, page, todo, PAGE_SH ARED)) { + if (remap_page_range(start, page, todo, PAGE_SH ARED_EXEC)) { printk(KERN_ERR "%s: zoran_mmap(V4L): r emap_page_range failed\n", zr->name); return -EAGAIN; } @@ -3016,7 +3016,7 @@ todo = v4l_bufsize; page = zr->v4l_gbuf[i].fbuffer_phys; DEBUG(printk("V4L remap page range %d 0x%x %d to 0x%x\n ", i, page, todo, start)); - if (remap_page_range(start, page, todo, PAGE_SHARED)) { + if (remap_page_range(start, page, todo, PAGE_SHARED_EXE C)) { printk(KERN_ERR "%s: zoran_mmap(V4L): remap_pag e_range failed\n", zr->name); return -EAGAIN; } diff -NurX nopatch linux-2.2.17/drivers/char/cpia.c linux-2.2.17-pax/drivers/ch ar/cpia.c --- linux-2.2.17/drivers/char/cpia.c Wed Jun 7 23:26:42 2000 +++ linux-2.2.17-pax/drivers/char/cpia.c Thu Nov 9 22:49:24 2000 @@ -3065,7 +3065,7 @@ pos = (unsigned long)(cam->frame_buf); while (size > 0) { page = kvirt_to_phys(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) { + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) { up(&cam->busy_lock); return -EAGAIN; } diff -NurX nopatch linux-2.2.17/drivers/char/mem.c linux-2.2.17-pax/drivers/cha r/mem.c --- linux-2.2.17/drivers/char/mem.c Tue Jan 4 19:12:14 2000 +++ linux-2.2.17-pax/drivers/char/mem.c Thu Nov 9 22:49:59 2000 @@ -353,7 +353,11 @@ flush_cache_range(mm, addr, addr + count); zap_page_range(mm, addr, count); - zeromap_page_range(addr, count, PAGE_COPY); + if (vma->vm_flags & VM_EXEC) { + zeromap_page_range(addr, count, PAGE_COPY_EXEC); + } else { + zeromap_page_range(addr, count, PAGE_COPY_NOEXEC); + } flush_tlb_range(mm, addr, addr + count); size -= count; diff -NurX nopatch linux-2.2.17/drivers/char/planb.c linux-2.2.17-pax/drivers/c har/planb.c --- linux-2.2.17/drivers/char/planb.c Thu Aug 26 02:29:47 1999 +++ linux-2.2.17-pax/drivers/char/planb.c Thu Nov 9 22:50:25 2000 @@ -2085,7 +2085,7 @@ while (size > 0) { page = vmalloc_to_phys(pos); - if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED)) + if (remap_page_range(start, page, PAGE_SIZE, PAGE_SHARED_EXEC)) return -EAGAIN; start+=PAGE_SIZE; pos+=PAGE_SIZE; diff -NurX nopatch linux-2.2.17/fs/binfmt_aout.c linux-2.2.17-pax/fs/binfmt_aou t.c --- linux-2.2.17/fs/binfmt_aout.c Tue Jan 4 19:12:22 2000 +++ linux-2.2.17-pax/fs/binfmt_aout.c Mon Nov 6 19:08:14 2000 @@ -50,7 +50,7 @@ if (end <= start) return; do_mmap(NULL, start, end - start, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, 0); } @@ -441,7 +441,7 @@ } error = do_mmap(file, N_DATADDR(ex), ex.a_data, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_E XECUTABLE, fd_offset + ex.a_text); fput(file); @@ -560,7 +560,7 @@ bss = ex.a_text + ex.a_data + ex.a_bss; if (bss > len) { error = do_mmap(NULL, start_addr + len, bss - len, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_PRIVATE | MAP_FIXED, 0); retval = error; if (error != start_addr + len) diff -NurX nopatch linux-2.2.17/fs/binfmt_elf.c linux-2.2.17-pax/fs/binfmt_elf. c --- linux-2.2.17/fs/binfmt_elf.c Wed Jun 7 23:26:43 2000 +++ linux-2.2.17-pax/fs/binfmt_elf.c Mon Nov 6 19:18:36 2000 @@ -78,7 +78,7 @@ if (end <= start) return; do_mmap(NULL, start, end - start, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE, 0); } @@ -330,7 +330,7 @@ /* Map the last of the bss segment */ if (last_bss > elf_bss) do_mmap(NULL, elf_bss, last_bss - elf_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, + PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0); *interp_load_addr = load_addr; @@ -389,7 +389,7 @@ do_mmap(NULL, ELF_PAGESTART(text_data + ELF_EXEC_PAGESIZE - 1), interp_ex->a_bss, - PROT_READ|PROT_WRITE|PROT_EXEC, MAP_FIXED|MAP_PRIVATE, 0); + PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0); elf_entry = interp_ex->a_entry; out: @@ -907,7 +907,7 @@ bss = elf_phdata->p_memsz + elf_phdata->p_vaddr; if (bss > len) do_mmap(NULL, len, bss - len, - PROT_READ|PROT_WRITE|PROT_EXEC, + PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0); error = 0; diff -NurX nopatch linux-2.2.17/fs/exec.c linux-2.2.17-pax/fs/exec.c --- linux-2.2.17/fs/exec.c Mon Sep 4 19:39:22 2000 +++ linux-2.2.17-pax/fs/exec.c Mon Nov 6 19:12:17 2000 @@ -314,7 +314,7 @@ mpnt->vm_mm = current->mm; mpnt->vm_start = PAGE_MASK & (unsigned long) p; mpnt->vm_end = STACK_TOP; - mpnt->vm_page_prot = PAGE_COPY; + mpnt->vm_page_prot = PAGE_COPY_NOEXEC; mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_ops = NULL; mpnt->vm_offset = 0; diff -NurX nopatch linux-2.2.17/include/asm-i386/pgtable.h linux-2.2.17-pax/inc lude/asm-i386/pgtable.h --- linux-2.2.17/include/asm-i386/pgtable.h Sun Oct 1 22:10:25 2000 +++ linux-2.2.17-pax/include/asm-i386/pgtable.h Sat Oct 21 22:52:15 2000 @@ -235,33 +235,37 @@ #define _PAGE_CHG_MASK (PAGE_MASK | _PAGE_ACCESSED | _PAGE_DIRTY) #define PAGE_NONE __pgprot(_PAGE_PROTNONE | _PAGE_ACCESSED) -#define PAGE_SHARED __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ ACCESSED) -#define PAGE_COPY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) -#define PAGE_READONLY __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_SHARED_EXEC __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_USER | _PAGE_ACCESSED) +#define PAGE_COPY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACC ESSED) +#define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_ACC ESSED) #define PAGE_KERNEL __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE _ACCESSED) #define PAGE_KERNEL_RO __pgprot(_PAGE_PRESENT | _PAGE_DIRTY | _PAGE_ACCESSED) +#define PAGE_SHARED_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_RW | _PAGE_ACCES SED) +#define PAGE_COPY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) +#define PAGE_READONLY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_ACCESSED) + /* * The i386 can't do page protection for execute, and considers that the same are read. * Also, write permissions imply read permissions. This is the closest we can get.. */ #define __P000 PAGE_NONE -#define __P001 PAGE_READONLY -#define __P010 PAGE_COPY -#define __P011 PAGE_COPY -#define __P100 PAGE_READONLY -#define __P101 PAGE_READONLY -#define __P110 PAGE_COPY -#define __P111 PAGE_COPY +#define __P001 PAGE_READONLY_NOEXEC +#define __P010 PAGE_COPY_NOEXEC +#define __P011 PAGE_COPY_NOEXEC +#define __P100 PAGE_READONLY_EXEC +#define __P101 PAGE_READONLY_EXEC +#define __P110 PAGE_COPY_EXEC +#define __P111 PAGE_COPY_EXEC #define __S000 PAGE_NONE -#define __S001 PAGE_READONLY -#define __S010 PAGE_SHARED -#define __S011 PAGE_SHARED -#define __S100 PAGE_READONLY -#define __S101 PAGE_READONLY -#define __S110 PAGE_SHARED -#define __S111 PAGE_SHARED +#define __S001 PAGE_READONLY_NOEXEC +#define __S010 PAGE_SHARED_NOEXEC +#define __S011 PAGE_SHARED_NOEXEC +#define __S100 PAGE_READONLY_EXEC +#define __S101 PAGE_READONLY_EXEC +#define __S110 PAGE_SHARED_EXEC +#define __S111 PAGE_SHARED_EXEC /* * Define this if things work differently on an i386 and an i486: diff -NurX nopatch linux-2.2.17/include/asm-i386/processor.h linux-2.2.17-pax/i nclude/asm-i386/processor.h --- linux-2.2.17/include/asm-i386/processor.h Mon Sep 4 19:39:28 2000 +++ linux-2.2.17-pax/include/asm-i386/processor.h Sat Oct 21 22:52:15 200 0 @@ -247,7 +247,7 @@ }; #define INIT_MMAP \ -{ &init_mm, 0, 0, NULL, PAGE_SHARED, VM_READ | VM_WRITE | VM_EXEC, 1, NULL, NU LL } +{ &init_mm, 0, 0, NULL, PAGE_SHARED_EXEC, VM_READ | VM_WRITE | VM_EXEC, 1, NUL L, NULL } #define INIT_TSS { \ 0,0, /* back_link, __blh */ \ diff -NurX nopatch linux-2.2.17/include/linux/mm.h linux-2.2.17-pax/include/lin ux/mm.h --- linux-2.2.17/include/linux/mm.h Sun Oct 1 22:10:25 2000 +++ linux-2.2.17-pax/include/linux/mm.h Sat Oct 21 22:52:15 2000 @@ -81,7 +81,7 @@ #define VM_LOCKED 0x2000 #define VM_IO 0x4000 /* Memory mapped I/O or similar */ -#define VM_STACK_FLAGS 0x0177 +#define VM_STACK_FLAGS 0x0133 /* PAX */ /* * mapping from the currently active vm_flags protection bits (the diff -NurX nopatch linux-2.2.17/ipc/shm.c linux-2.2.17-pax/ipc/shm.c --- linux-2.2.17/ipc/shm.c Wed Jun 7 23:26:44 2000 +++ linux-2.2.17-pax/ipc/shm.c Sun Nov 5 13:41:39 2000 @@ -509,9 +509,9 @@ shmd->vm_start = addr; shmd->vm_end = addr + shp->shm_npages * PAGE_SIZE; shmd->vm_mm = current->mm; - shmd->vm_page_prot = (shmflg & SHM_RDONLY) ? PAGE_READONLY : PAGE_SHARE D; + shmd->vm_page_prot = (shmflg & SHM_RDONLY) ? PAGE_READONLY_NOEXEC : PAG E_SHARED_NOEXEC; shmd->vm_flags = VM_SHM | VM_MAYSHARE | VM_SHARED - | VM_MAYREAD | VM_MAYEXEC | VM_READ | VM_EXEC + | VM_MAYREAD | VM_READ | ((shmflg & SHM_RDONLY) ? 0 : VM_MAYWRITE | VM_WRITE) ; shmd->vm_file = NULL; shmd->vm_offset = 0; @@ -667,7 +667,7 @@ shm_swp--; } shm_rss++; - pte = pte_mkdirty(mk_pte(page, PAGE_SHARED)); + pte = pte_mkdirty(mk_pte(page, PAGE_SHARED_NOEXEC)); shp->shm_pages[idx] = pte_val(pte); } else --current->maj_flt; /* was incremented in do_no_page */ @@ -748,7 +748,7 @@ { pte_t pte; - pte = pte_mkdirty(mk_pte(page, PAGE_SHARED)); + pte = pte_mkdirty(mk_pte(page, PAGE_SHARED_NOEXEC)); shp->shm_pages[idx] = pte_val(pte); atomic_inc(&mem_map[MAP_NR(page)].count); shm_rss++; diff -NurX nopatch linux-2.2.17/mm/memory.c linux-2.2.17-pax/mm/memory.c --- linux-2.2.17/mm/memory.c Tue Jan 4 19:12:26 2000 +++ linux-2.2.17-pax/mm/memory.c Sat Sep 30 16:10:36 2000 @@ -583,7 +583,7 @@ return 0; } flush_page_to_ram(page); - set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY)))); + set_pte(pte, pte_mkwrite(pte_mkdirty(mk_pte(page, PAGE_COPY_NOEXEC)))); /* no need for flush_tlb */ return page; } diff -NurX nopatch linux-2.2.17/mm/mmap.c linux-2.2.17-pax/mm/mmap.c --- linux-2.2.17/mm/mmap.c Wed Jun 7 23:26:44 2000 +++ linux-2.2.17-pax/mm/mmap.c Mon Nov 6 19:54:17 2000 @@ -135,7 +135,7 @@ /* Ok, looks good - let it rip. */ if (do_mmap(NULL, oldbrk, newbrk-oldbrk, - PROT_READ|PROT_WRITE|PROT_EXEC, + PROT_READ|PROT_WRITE, MAP_FIXED|MAP_PRIVATE, 0) != oldbrk) goto out; set_brk: @@ -161,6 +161,10 @@ _trans(prot, PROT_READ, VM_READ) | _trans(prot, PROT_WRITE, VM_WRITE) | _trans(prot, PROT_EXEC, VM_EXEC); + prot_bits |= + _trans(prot, PROT_READ, VM_MAYREAD) | + _trans(prot, PROT_WRITE, VM_MAYWRITE) | + _trans(prot, PROT_EXEC, VM_MAYEXEC); flag_bits = _trans(flags, MAP_GROWSDOWN, VM_GROWSDOWN) | _trans(flags, MAP_DENYWRITE, VM_DENYWRITE) | @@ -260,8 +264,17 @@ vma->vm_flags = vm_flags(prot,flags) | mm->def_flags; if (file) { - if (file->f_mode & 1) - vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; + /* PaX: grant write access to executable mappings, even if it w asn't + explicitly requested (hint: relocation). mprotect() will rem ove + VM_MAYWRITE after the first request for PROT_WRITE (after wh ich + the loader is expected to remove PROT_WRITE for good). + */ + if (file->f_mode & 1) { + if (prot & PROT_EXEC) + vma->vm_flags |= VM_MAYWRITE; + } else { + vma->vm_flags &= ~(VM_MAYREAD | VM_MAYWRITE | VM_MAYEXE C); + } if (flags & MAP_SHARED) { vma->vm_flags |= VM_SHARED | VM_MAYSHARE; @@ -277,8 +290,7 @@ if (!(file->f_mode & 2)) vma->vm_flags &= ~(VM_MAYWRITE | VM_SHARED); } - } else - vma->vm_flags |= VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; + } vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f]; vma->vm_ops = NULL; vma->vm_offset = off; @@ -325,6 +337,14 @@ file->f_dentry->d_inode->i_writecount++; if (error) goto unmap_and_free_vma; + /* if it turns out to be device memory (eg. video RAM), don't a pply PaX */ + if ((vma->vm_flags & VM_IO) && !(vma->vm_flags & VM_EXEC)) { + vma->vm_flags |= VM_EXEC | VM_MAYEXEC; + vma->vm_page_prot = protection_map[vma->vm_flags & 0x0f ]; + error = remap_page_range(vma->vm_start, vma->vm_offset, vma->vm_end-vma->vm_start, vma->vm_page_prot); + if (error) + goto unmap_and_free_vma; + } vma->vm_file = file; file->f_count++; } diff -NurX nopatch linux-2.2.17/mm/mprotect.c linux-2.2.17-pax/mm/mprotect.c --- linux-2.2.17/mm/mprotect.c Fri Nov 20 20:43:19 1998 +++ linux-2.2.17-pax/mm/mprotect.c Sat Nov 11 19:43:01 2000 @@ -229,6 +229,10 @@ error = -EACCES; break; } + /* PaX: disallow write access after relocs are done, hopefully noone else needs it... */ + if ((prot & PROT_WRITE) && (vma->vm_flags & VM_MAYEXEC)) { + newflags &= ~VM_MAYWRITE; + } if (vma->vm_end >= end) { error = mprotect_fixup(vma, nstart, end, newflags);