diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/Documentation/dontdiff linux-2.6.24.7-pax/Documentation/dontdiff --- linux-2.6.24.7/Documentation/dontdiff 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/Documentation/dontdiff 2008-02-29 18:07:50.000000000 +0100 @@ -3,6 +3,7 @@ *.bin *.cpio *.css +*.dbg *.dvi *.eps *.gif @@ -183,11 +184,14 @@ version.h* vmlinux vmlinux-* vmlinux.aout -vmlinux*.lds* +vmlinux.bin.all +vmlinux*.lds +vmlinux.relocs vmlinux*.scr -vsyscall.lds +vsyscall*.lds wanxlfw.inc uImage unifdef +utsrelease.h zImage* zconf.hash.c diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/Makefile linux-2.6.24.7-pax/Makefile --- linux-2.6.24.7/Makefile 2008-05-08 12:34:37.000000000 +0200 +++ linux-2.6.24.7-pax/Makefile 2008-05-08 12:34:44.000000000 +0200 @@ -214,7 +214,7 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" HOSTCC = gcc HOSTCXX = g++ -HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCFLAGS = -Wall -W -Wno-unused -Wno-sign-compare -Wstrict-prototypes -O2 -fomit-frame-pointer HOSTCXXFLAGS = -O2 # Decide whether to build built-in, modular, or both. @@ -507,6 +507,9 @@ else KBUILD_CFLAGS += -O2 endif +# Force gcc to behave correct even for buggy distributions +KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) + include $(srctree)/arch/$(SRCARCH)/Makefile ifdef CONFIG_FRAME_POINTER @@ -520,9 +523,6 @@ KBUILD_CFLAGS += -g KBUILD_AFLAGS += -gdwarf-2 endif -# Force gcc to behave correct even for buggy distributions -KBUILD_CFLAGS += $(call cc-option, -fno-stack-protector) - # arch Makefile may override CC so keep this after arch Makefile is included NOSTDINC_FLAGS += -nostdinc -isystem $(shell $(CC) -print-file-name=include) CHECKFLAGS += $(NOSTDINC_FLAGS) diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/alpha/kernel/module.c linux-2.6.24.7-pax/arch/alpha/kernel/module.c --- linux-2.6.24.7/arch/alpha/kernel/module.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/alpha/kernel/module.c 2008-02-29 18:07:50.000000000 +0100 @@ -176,7 +176,7 @@ apply_relocate_add(Elf64_Shdr *sechdrs, /* The small sections were sorted to the end of the segment. The following should definitely cover them. */ - gp = (u64)me->module_core + me->core_size - 0x8000; + gp = (u64)me->module_core_rw + me->core_size_rw - 0x8000; got = sechdrs[me->arch.gotsecindex].sh_addr; for (i = 0; i < n; i++) { diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/alpha/kernel/osf_sys.c linux-2.6.24.7-pax/arch/alpha/kernel/osf_sys.c --- linux-2.6.24.7/arch/alpha/kernel/osf_sys.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/alpha/kernel/osf_sys.c 2008-02-29 18:07:50.000000000 +0100 @@ -1288,6 +1288,10 @@ arch_get_unmapped_area(struct file *filp merely specific addresses, but regions of memory -- perhaps this feature should be incorporated into all ports? */ +#ifdef CONFIG_PAX_RANDMMAP + if (!(current->mm->pax_flags & MF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { addr = arch_get_unmapped_area_1 (PAGE_ALIGN(addr), len, limit); if (addr != (unsigned long) -ENOMEM) @@ -1295,8 +1299,8 @@ arch_get_unmapped_area(struct file *filp } /* Next, try allocating at TASK_UNMAPPED_BASE. */ - addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE), - len, limit); + addr = arch_get_unmapped_area_1 (PAGE_ALIGN(current->mm->mmap_base), len, limit); + if (addr != (unsigned long) -ENOMEM) return addr; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/alpha/mm/fault.c linux-2.6.24.7-pax/arch/alpha/mm/fault.c --- linux-2.6.24.7/arch/alpha/mm/fault.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/alpha/mm/fault.c 2008-03-26 23:14:56.000000000 +0100 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -54,6 +55,124 @@ __load_new_mm_context(struct mm_struct * __reload_thread(pcb); } +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->pc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: patched PLT emulation #1 */ + unsigned int ldah, ldq, jmp; + + err = get_user(ldah, (unsigned int *)regs->pc); + err |= get_user(ldq, (unsigned int *)(regs->pc+4)); + err |= get_user(jmp, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((ldah & 0xFFFF0000U) == 0x277B0000U && + (ldq & 0xFFFF0000U) == 0xA77B0000U && + jmp == 0x6BFB0000U) + { + unsigned long r27, addr; + unsigned long addrh = (ldah | 0xFFFFFFFFFFFF0000UL) << 16; + unsigned long addrl = ldq | 0xFFFFFFFFFFFF0000UL; + + addr = regs->r27 + ((addrh ^ 0x80000000UL) + 0x80000000UL) + ((addrl ^ 0x8000UL) + 0x8000UL); + err = get_user(r27, (unsigned long *)addr); + if (err) + break; + + regs->r27 = r27; + regs->pc = r27; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #2 */ + unsigned int ldah, lda, br; + + err = get_user(ldah, (unsigned int *)regs->pc); + err |= get_user(lda, (unsigned int *)(regs->pc+4)); + err |= get_user(br, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((ldah & 0xFFFF0000U) == 0x277B0000U && + (lda & 0xFFFF0000U) == 0xA77B0000U && + (br & 0xFFE00000U) == 0xC3E00000U) + { + unsigned long addr = br | 0xFFFFFFFFFFE00000UL; + unsigned long addrh = (ldah | 0xFFFFFFFFFFFF0000UL) << 16; + unsigned long addrl = lda | 0xFFFFFFFFFFFF0000UL; + + regs->r27 += ((addrh ^ 0x80000000UL) + 0x80000000UL) + ((addrl ^ 0x8000UL) + 0x8000UL); + regs->pc += 12 + (((addr ^ 0x00100000UL) + 0x00100000UL) << 2); + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation */ + unsigned int br; + + err = get_user(br, (unsigned int *)regs->pc); + + if (!err && (br & 0xFFE00000U) == 0xC3800000U) { + unsigned int br2, ldq, nop, jmp; + unsigned long addr = br | 0xFFFFFFFFFFE00000UL, resolver; + + addr = regs->pc + 4 + (((addr ^ 0x00100000UL) + 0x00100000UL) << 2); + err = get_user(br2, (unsigned int *)addr); + err |= get_user(ldq, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + err |= get_user(jmp, (unsigned int *)(addr+12)); + err |= get_user(resolver, (unsigned long *)(addr+16)); + + if (err) + break; + + if (br2 == 0xC3600000U && + ldq == 0xA77B000CU && + nop == 0x47FF041FU && + jmp == 0x6B7B0000U) + { + regs->r28 = regs->pc+4; + regs->r27 = addr+16; + regs->pc = resolver; + return 3; + } + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk("???????? "); + else + printk("%08x ", c); + } + printk("\n"); +} +#endif /* * This routine handles page faults. It determines the address, @@ -131,8 +250,29 @@ do_page_fault(unsigned long address, uns good_area: si_code = SEGV_ACCERR; if (cause < 0) { - if (!(vma->vm_flags & VM_EXEC)) + if (!(vma->vm_flags & VM_EXEC)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(mm->pax_flags & MF_PAX_PAGEEXEC) || address != regs->pc) + goto bad_area; + + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void *)regs->pc, (void *)rdusp()); + do_group_exit(SIGKILL); +#else goto bad_area; +#endif + + } } else if (!cause) { /* Allow reads even for write-only mappings */ if (!(vma->vm_flags & (VM_READ | VM_WRITE))) diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/arm/mm/mmap.c linux-2.6.24.7-pax/arch/arm/mm/mmap.c --- linux-2.6.24.7/arch/arm/mm/mmap.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/arm/mm/mmap.c 2008-02-29 18:07:50.000000000 +0100 @@ -60,6 +60,10 @@ arch_get_unmapped_area(struct file *filp if (len > TASK_SIZE) return -ENOMEM; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { if (do_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -72,10 +76,10 @@ arch_get_unmapped_area(struct file *filp return addr; } if (len > mm->cached_hole_size) { - start_addr = addr = mm->free_area_cache; + start_addr = addr = mm->free_area_cache; } else { - start_addr = addr = TASK_UNMAPPED_BASE; - mm->cached_hole_size = 0; + start_addr = addr = mm->mmap_base; + mm->cached_hole_size = 0; } full_search: @@ -91,8 +95,8 @@ full_search: * Start a new search - just in case we missed * some holes. */ - if (start_addr != TASK_UNMAPPED_BASE) { - start_addr = addr = TASK_UNMAPPED_BASE; + if (start_addr != mm->mmap_base) { + start_addr = addr = mm->mmap_base; mm->cached_hole_size = 0; goto full_search; } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/avr32/mm/fault.c linux-2.6.24.7-pax/arch/avr32/mm/fault.c --- linux-2.6.24.7/arch/avr32/mm/fault.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/avr32/mm/fault.c 2008-03-26 23:15:13.000000000 +0100 @@ -41,6 +41,23 @@ static inline int notify_page_fault(stru int exception_trace = 1; +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (get_user(c, (unsigned char *)pc+i)) + printk("???????? "); + else + printk("%02x ", c); + } + printk("\n"); +} +#endif + /* * This routine handles page faults. It determines the address and the * problem, and then passes it off to one of the appropriate routines. @@ -157,6 +174,16 @@ bad_area: up_read(&mm->mmap_sem); if (user_mode(regs)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm->pax_flags & MF_PAX_PAGEEXEC) { + if (ecr == ECR_PROTECTION_X || ecr == ECR_TLB_MISS_X) { + pax_report_fault(regs, (void *)regs->pc, (void *)regs->sp); + do_group_exit(SIGKILL); + } + } +#endif + if (exception_trace && printk_ratelimit()) printk("%s%s[%d]: segfault at %08lx pc %08lx " "sp %08lx ecr %lu\n", diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/ia64/ia32/binfmt_elf32.c linux-2.6.24.7-pax/arch/ia64/ia32/binfmt_elf32.c --- linux-2.6.24.7/arch/ia64/ia32/binfmt_elf32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/ia64/ia32/binfmt_elf32.c 2008-02-29 18:07:50.000000000 +0100 @@ -45,6 +45,13 @@ randomize_stack_top(unsigned long stack_ #define elf_read_implies_exec(ex, have_pt_gnu_stack) (!(have_pt_gnu_stack)) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (current->personality == PER_LINUX32 ? 0x08048000UL : 0x4000000000000000UL) + +#define PAX_DELTA_MMAP_LEN (current->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - 13) +#define PAX_DELTA_STACK_LEN (current->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - 13) +#endif + /* Ugly but avoids duplication */ #include "../../../fs/binfmt_elf.c" diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/ia64/ia32/ia32priv.h linux-2.6.24.7-pax/arch/ia64/ia32/ia32priv.h --- linux-2.6.24.7/arch/ia64/ia32/ia32priv.h 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/ia64/ia32/ia32priv.h 2008-02-29 18:07:50.000000000 +0100 @@ -303,7 +303,14 @@ struct old_linux32_dirent { #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_386 -#define IA32_STACK_TOP IA32_PAGE_OFFSET +#ifdef CONFIG_PAX_RANDUSTACK +#define __IA32_DELTA_STACK (current->mm->delta_stack) +#else +#define __IA32_DELTA_STACK 0UL +#endif + +#define IA32_STACK_TOP (IA32_PAGE_OFFSET - __IA32_DELTA_STACK) + #define IA32_GATE_OFFSET IA32_PAGE_OFFSET #define IA32_GATE_END IA32_PAGE_OFFSET + PAGE_SIZE diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/ia64/kernel/module.c linux-2.6.24.7-pax/arch/ia64/kernel/module.c --- linux-2.6.24.7/arch/ia64/kernel/module.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/ia64/kernel/module.c 2008-05-07 23:08:12.000000000 +0200 @@ -321,7 +321,7 @@ module_alloc (unsigned long size) void module_free (struct module *mod, void *module_region) { - if (mod->arch.init_unw_table && module_region == mod->module_init) { + if (mod->arch.init_unw_table && module_region == mod->module_init_rx) { unw_remove_unwind_table(mod->arch.init_unw_table); mod->arch.init_unw_table = NULL; } @@ -499,15 +499,39 @@ module_frob_arch_sections (Elf_Ehdr *ehd } static inline int +in_init_rx (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_init_rx < mod->init_size_rx; +} + +static inline int +in_init_rw (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_init_rw < mod->init_size_rw; +} + +static inline int in_init (const struct module *mod, uint64_t addr) { - return addr - (uint64_t) mod->module_init < mod->init_size; + return in_init_rx(mod, addr) || in_init_rw(mod, addr); +} + +static inline int +in_core_rx (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_core_rx < mod->core_size_rx; +} + +static inline int +in_core_rw (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_core_rw < mod->core_size_rw; } static inline int in_core (const struct module *mod, uint64_t addr) { - return addr - (uint64_t) mod->module_core < mod->core_size; + return in_core_rx(mod, addr) || in_core_rw(mod, addr); } static inline int @@ -691,7 +715,14 @@ do_reloc (struct module *mod, uint8_t r_ break; case RV_BDREL: - val -= (uint64_t) (in_init(mod, val) ? mod->module_init : mod->module_core); + if (in_init_rx(mod, val)) + val -= (uint64_t) mod->module_init_rx; + else if (in_init_rw(mod, val)) + val -= (uint64_t) mod->module_init_rw; + else if (in_core_rx(mod, val)) + val -= (uint64_t) mod->module_core_rx; + else if (in_core_rw(mod, val)) + val -= (uint64_t) mod->module_core_rw; break; case RV_LTV: @@ -825,15 +856,15 @@ apply_relocate_add (Elf64_Shdr *sechdrs, * addresses have been selected... */ uint64_t gp; - if (mod->core_size > MAX_LTOFF) + if (mod->core_size_rx + mod->core_size_rw > MAX_LTOFF) /* * This takes advantage of fact that SHF_ARCH_SMALL gets allocated * at the end of the module. */ - gp = mod->core_size - MAX_LTOFF / 2; + gp = mod->core_size_rx + mod->core_size_rw - MAX_LTOFF / 2; else - gp = mod->core_size / 2; - gp = (uint64_t) mod->module_core + ((gp + 7) & -8); + gp = (mod->core_size_rx + mod->core_size_rw) / 2; + gp = (uint64_t) mod->module_core_rx + ((gp + 7) & -8); mod->arch.gp = gp; DEBUGP("%s: placing gp at 0x%lx\n", __FUNCTION__, gp); } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/ia64/kernel/sys_ia64.c linux-2.6.24.7-pax/arch/ia64/kernel/sys_ia64.c --- linux-2.6.24.7/arch/ia64/kernel/sys_ia64.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/ia64/kernel/sys_ia64.c 2008-02-29 18:07:50.000000000 +0100 @@ -43,6 +43,13 @@ arch_get_unmapped_area (struct file *fil if (REGION_NUMBER(addr) == RGN_HPAGE) addr = 0; #endif + +#ifdef CONFIG_PAX_RANDMMAP + if ((mm->pax_flags & MF_PAX_RANDMMAP) && addr && filp) + addr = mm->free_area_cache; + else +#endif + if (!addr) addr = mm->free_area_cache; @@ -61,9 +68,9 @@ arch_get_unmapped_area (struct file *fil for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { /* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr || RGN_MAP_LIMIT - len < REGION_OFFSET(addr)) { - if (start_addr != TASK_UNMAPPED_BASE) { + if (start_addr != mm->mmap_base) { /* Start a new search --- just in case we missed some holes. */ - addr = TASK_UNMAPPED_BASE; + addr = mm->mmap_base; goto full_search; } return -ENOMEM; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/ia64/mm/fault.c linux-2.6.24.7-pax/arch/ia64/mm/fault.c --- linux-2.6.24.7/arch/ia64/mm/fault.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/ia64/mm/fault.c 2008-03-26 23:15:32.000000000 +0100 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,23 @@ mapped_kernel_page_is_present (unsigned return pte_present(pte); } +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 8; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk("???????? "); + else + printk("%08x ", c); + } + printk("\n"); +} +#endif + void __kprobes ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { @@ -145,9 +163,23 @@ ia64_do_page_fault (unsigned long addres mask = ( (((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT) | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT)); - if ((vma->vm_flags & mask) != mask) + if ((vma->vm_flags & mask) != mask) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(vma->vm_flags & VM_EXEC) && (mask & VM_EXEC)) { + if (!(mm->pax_flags & MF_PAX_PAGEEXEC) || address != regs->cr_iip) + goto bad_area; + + up_read(&mm->mmap_sem); + pax_report_fault(regs, (void *)regs->cr_iip, (void *)regs->r12); + do_group_exit(SIGKILL); + } +#endif + goto bad_area; + } + survive: /* * If for any reason at all we couldn't handle the fault, make diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/ia64/mm/init.c linux-2.6.24.7-pax/arch/ia64/mm/init.c --- linux-2.6.24.7/arch/ia64/mm/init.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/ia64/mm/init.c 2008-02-29 18:07:50.000000000 +0100 @@ -20,8 +20,8 @@ #include #include #include +#include -#include #include #include #include @@ -128,6 +128,19 @@ ia64_init_addr_space (void) vma->vm_start = current->thread.rbs_bot & PAGE_MASK; vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_flags = VM_DATA_DEFAULT_FLAGS|VM_GROWSUP|VM_ACCOUNT; + +#ifdef CONFIG_PAX_PAGEEXEC + if (current->mm->pax_flags & MF_PAX_PAGEEXEC) { + vm->vm_flags &= ~VM_EXEC; + +#ifdef CONFIG_PAX_MPROTECT + if (current->mm->pax_flags & MF_PAX_MPROTECT) + vma->vm_flags &= ~VM_MAYEXEC; +#endif + + } +#endif + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); down_write(¤t->mm->mmap_sem); if (insert_vm_struct(current->mm, vma)) { diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/mips/kernel/binfmt_elfn32.c linux-2.6.24.7-pax/arch/mips/kernel/binfmt_elfn32.c --- linux-2.6.24.7/arch/mips/kernel/binfmt_elfn32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/mips/kernel/binfmt_elfn32.c 2008-02-29 18:07:50.000000000 +0100 @@ -50,6 +50,13 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_N #undef ELF_ET_DYN_BASE #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE ((current->thread.mflags & MF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LEN ((current->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LEN ((current->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include #include diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/mips/kernel/binfmt_elfo32.c linux-2.6.24.7-pax/arch/mips/kernel/binfmt_elfo32.c --- linux-2.6.24.7/arch/mips/kernel/binfmt_elfo32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/mips/kernel/binfmt_elfo32.c 2008-02-29 18:07:50.000000000 +0100 @@ -52,6 +52,13 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_N #undef ELF_ET_DYN_BASE #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE ((current->thread.mflags & MF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LEN ((current->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LEN ((current->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include #include diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/mips/kernel/syscall.c linux-2.6.24.7-pax/arch/mips/kernel/syscall.c --- linux-2.6.24.7/arch/mips/kernel/syscall.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/mips/kernel/syscall.c 2008-02-29 18:07:50.000000000 +0100 @@ -93,6 +93,11 @@ unsigned long arch_get_unmapped_area(str do_color_align = 0; if (filp || (flags & MAP_SHARED)) do_color_align = 1; + +#ifdef CONFIG_PAX_RANDMMAP + if (!(current->mm->pax_flags & MF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -103,7 +108,7 @@ unsigned long arch_get_unmapped_area(str (!vmm || addr + len <= vmm->vm_start)) return addr; } - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); else diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/mips/mm/fault.c linux-2.6.24.7-pax/arch/mips/mm/fault.c --- linux-2.6.24.7/arch/mips/mm/fault.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/mips/mm/fault.c 2008-02-29 18:07:50.000000000 +0100 @@ -26,6 +26,23 @@ #include #include /* For VMALLOC_END */ +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(void *pc) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk("???????? "); + else + printk("%08x ", c); + } + printk("\n"); +} +#endif + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/parisc/kernel/module.c linux-2.6.24.7-pax/arch/parisc/kernel/module.c --- linux-2.6.24.7/arch/parisc/kernel/module.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/parisc/kernel/module.c 2008-02-29 18:07:50.000000000 +0100 @@ -73,16 +73,38 @@ /* three functions to determine where in the module core * or init pieces the location is */ +static inline int in_init_rx(struct module *me, void *loc) +{ + return (loc >= me->module_init_rx && + loc < (me->module_init_rx + me->init_size_rx)); +} + +static inline int in_init_rw(struct module *me, void *loc) +{ + return (loc >= me->module_init_rw && + loc < (me->module_init_rw + me->init_size_rw)); +} + static inline int in_init(struct module *me, void *loc) { - return (loc >= me->module_init && - loc <= (me->module_init + me->init_size)); + return in_init_rx(me, loc) || in_init_rw(me, loc); +} + +static inline int in_core_rx(struct module *me, void *loc) +{ + return (loc >= me->module_core_rx && + loc < (me->module_core_rx + me->core_size_rx)); +} + +static inline int in_core_rw(struct module *me, void *loc) +{ + return (loc >= me->module_core_rw && + loc < (me->module_core_rw + me->core_size_rw)); } static inline int in_core(struct module *me, void *loc) { - return (loc >= me->module_core && - loc <= (me->module_core + me->core_size)); + return in_core_rx(me, loc) || in_core_rw(me, loc); } static inline int in_local(struct module *me, void *loc) @@ -296,21 +318,21 @@ int module_frob_arch_sections(CONST Elf_ } /* align things a bit */ - me->core_size = ALIGN(me->core_size, 16); - me->arch.got_offset = me->core_size; - me->core_size += gots * sizeof(struct got_entry); - - me->core_size = ALIGN(me->core_size, 16); - me->arch.fdesc_offset = me->core_size; - me->core_size += fdescs * sizeof(Elf_Fdesc); - - me->core_size = ALIGN(me->core_size, 16); - me->arch.stub_offset = me->core_size; - me->core_size += stubs * sizeof(struct stub_entry); - - me->init_size = ALIGN(me->init_size, 16); - me->arch.init_stub_offset = me->init_size; - me->init_size += init_stubs * sizeof(struct stub_entry); + me->core_size_rw = ALIGN(me->core_size_rw, 16); + me->arch.got_offset = me->core_size_rw; + me->core_size_rw += gots * sizeof(struct got_entry); + + me->core_size_rw = ALIGN(me->core_size_rw, 16); + me->arch.fdesc_offset = me->core_size_rw; + me->core_size_rw += fdescs * sizeof(Elf_Fdesc); + + me->core_size_rx = ALIGN(me->core_size_rx, 16); + me->arch.stub_offset = me->core_size_rx; + me->core_size_rx += stubs * sizeof(struct stub_entry); + + me->init_size_rx = ALIGN(me->init_size_rx, 16); + me->arch.init_stub_offset = me->init_size_rx; + me->init_size_rx += init_stubs * sizeof(struct stub_entry); me->arch.got_max = gots; me->arch.fdesc_max = fdescs; @@ -330,7 +352,7 @@ static Elf64_Word get_got(struct module BUG_ON(value == 0); - got = me->module_core + me->arch.got_offset; + got = me->module_core_rw + me->arch.got_offset; for (i = 0; got[i].addr; i++) if (got[i].addr == value) goto out; @@ -348,7 +370,7 @@ static Elf64_Word get_got(struct module #ifdef CONFIG_64BIT static Elf_Addr get_fdesc(struct module *me, unsigned long value) { - Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset; + Elf_Fdesc *fdesc = me->module_core_rw + me->arch.fdesc_offset; if (!value) { printk(KERN_ERR "%s: zero OPD requested!\n", me->name); @@ -366,7 +388,7 @@ static Elf_Addr get_fdesc(struct module /* Create new one */ fdesc->addr = value; - fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset; + fdesc->gp = (Elf_Addr)me->module_core_rw + me->arch.got_offset; return (Elf_Addr)fdesc; } #endif /* CONFIG_64BIT */ @@ -386,12 +408,12 @@ static Elf_Addr get_stub(struct module * if(init_section) { i = me->arch.init_stub_count++; BUG_ON(me->arch.init_stub_count > me->arch.init_stub_max); - stub = me->module_init + me->arch.init_stub_offset + + stub = me->module_init_rx + me->arch.init_stub_offset + i * sizeof(struct stub_entry); } else { i = me->arch.stub_count++; BUG_ON(me->arch.stub_count > me->arch.stub_max); - stub = me->module_core + me->arch.stub_offset + + stub = me->module_core_rx + me->arch.stub_offset + i * sizeof(struct stub_entry); } @@ -759,7 +781,7 @@ register_unwind_table(struct module *me, table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr; end = table + sechdrs[me->arch.unwind_section].sh_size; - gp = (Elf_Addr)me->module_core + me->arch.got_offset; + gp = (Elf_Addr)me->module_core_rw + me->arch.got_offset; DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n", me->arch.unwind_section, table, end, gp); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/parisc/kernel/sys_parisc.c linux-2.6.24.7-pax/arch/parisc/kernel/sys_parisc.c --- linux-2.6.24.7/arch/parisc/kernel/sys_parisc.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/parisc/kernel/sys_parisc.c 2008-02-29 18:07:50.000000000 +0100 @@ -111,7 +111,7 @@ unsigned long arch_get_unmapped_area(str if (flags & MAP_FIXED) return addr; if (!addr) - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; if (filp) { addr = get_shared_area(filp->f_mapping, addr, len, pgoff); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/parisc/kernel/traps.c linux-2.6.24.7-pax/arch/parisc/kernel/traps.c --- linux-2.6.24.7/arch/parisc/kernel/traps.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/parisc/kernel/traps.c 2008-02-29 18:07:50.000000000 +0100 @@ -713,9 +713,7 @@ void handle_interruption(int code, struc down_read(¤t->mm->mmap_sem); vma = find_vma(current->mm,regs->iaoq[0]); - if (vma && (regs->iaoq[0] >= vma->vm_start) - && (vma->vm_flags & VM_EXEC)) { - + if (vma && (regs->iaoq[0] >= vma->vm_start)) { fault_address = regs->iaoq[0]; fault_space = regs->iasq[0]; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/parisc/mm/fault.c linux-2.6.24.7-pax/arch/parisc/mm/fault.c --- linux-2.6.24.7/arch/parisc/mm/fault.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/parisc/mm/fault.c 2008-03-26 23:15:49.000000000 +0100 @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -53,7 +55,7 @@ DEFINE_PER_CPU(struct exception_data, ex static unsigned long parisc_acctyp(unsigned long code, unsigned int inst) { - if (code == 6 || code == 16) + if (code == 6 || code == 7 || code == 16) return VM_EXEC; switch (inst & 0xf0000000) { @@ -139,6 +141,116 @@ parisc_acctyp(unsigned long code, unsign } #endif +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (instruction_pointer(regs) = fault address) + * + * returns 1 when task should be killed + * 2 when rt_sigreturn trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: unpatched PLT emulation */ + unsigned int bl, depwi; + + err = get_user(bl, (unsigned int *)instruction_pointer(regs)); + err |= get_user(depwi, (unsigned int *)(instruction_pointer(regs)+4)); + + if (err) + break; + + if (bl == 0xEA9F1FDDU && depwi == 0xD6801C1EU) { + unsigned int ldw, bv, ldw2, addr = instruction_pointer(regs)-12; + + err = get_user(ldw, (unsigned int *)addr); + err |= get_user(bv, (unsigned int *)(addr+4)); + err |= get_user(ldw2, (unsigned int *)(addr+8)); + + if (err) + break; + + if (ldw == 0x0E801096U && + bv == 0xEAC0C000U && + ldw2 == 0x0E881095U) + { + unsigned int resolver, map; + + err = get_user(resolver, (unsigned int *)(instruction_pointer(regs)+8)); + err |= get_user(map, (unsigned int *)(instruction_pointer(regs)+12)); + if (err) + break; + + regs->gr[20] = instruction_pointer(regs)+8; + regs->gr[21] = map; + regs->gr[22] = resolver; + regs->iaoq[0] = resolver | 3UL; + regs->iaoq[1] = regs->iaoq[0] + 4; + return 3; + } + } + } while (0); +#endif + +#ifdef CONFIG_PAX_EMUTRAMP + +#ifndef CONFIG_PAX_EMUSIGRT + if (!(current->mm->pax_flags & MF_PAX_EMUTRAMP)) + return 1; +#endif + + do { /* PaX: rt_sigreturn emulation */ + unsigned int ldi1, ldi2, bel, nop; + + err = get_user(ldi1, (unsigned int *)instruction_pointer(regs)); + err |= get_user(ldi2, (unsigned int *)(instruction_pointer(regs)+4)); + err |= get_user(bel, (unsigned int *)(instruction_pointer(regs)+8)); + err |= get_user(nop, (unsigned int *)(instruction_pointer(regs)+12)); + + if (err) + break; + + if ((ldi1 == 0x34190000U || ldi1 == 0x34190002U) && + ldi2 == 0x3414015AU && + bel == 0xE4008200U && + nop == 0x08000240U) + { + regs->gr[25] = (ldi1 & 2) >> 1; + regs->gr[20] = __NR_rt_sigreturn; + regs->gr[31] = regs->iaoq[1] + 16; + regs->sr[0] = regs->iasq[1]; + regs->iaoq[0] = 0x100UL; + regs->iaoq[1] = regs->iaoq[0] + 4; + regs->iasq[0] = regs->sr[2]; + regs->iasq[1] = regs->sr[2]; + return 2; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk("???????? "); + else + printk("%08x ", c); + } + printk("\n"); +} +#endif + void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address) { @@ -165,8 +277,33 @@ good_area: acc_type = parisc_acctyp(code,regs->iir); - if ((vma->vm_flags & acc_type) != acc_type) + if ((vma->vm_flags & acc_type) != acc_type) { + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && (acc_type & VM_EXEC) && + (address & ~3UL) == instruction_pointer(regs)) + { + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 3: + return; +#endif + +#ifdef CONFIG_PAX_EMUTRAMP + case 2: + return; +#endif + + } + pax_report_fault(regs, (void *)instruction_pointer(regs), (void *)regs->gr[30]); + do_group_exit(SIGKILL); + } +#endif + goto bad_area; + } /* * If for any reason at all we couldn't handle the fault, make diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/powerpc/kernel/module_32.c linux-2.6.24.7-pax/arch/powerpc/kernel/module_32.c --- linux-2.6.24.7/arch/powerpc/kernel/module_32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/powerpc/kernel/module_32.c 2008-02-29 18:07:50.000000000 +0100 @@ -126,7 +126,7 @@ int module_frob_arch_sections(Elf32_Ehdr me->arch.core_plt_section = i; } if (!me->arch.core_plt_section || !me->arch.init_plt_section) { - printk("Module doesn't contain .plt or .init.plt sections.\n"); + printk("Module %s doesn't contain .plt or .init.plt sections.\n", me->name); return -ENOEXEC; } @@ -167,11 +167,16 @@ static uint32_t do_plt_call(void *locati DEBUGP("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location); /* Init, or core PLT? */ - if (location >= mod->module_core - && location < mod->module_core + mod->core_size) + if ((location >= mod->module_core_rx && location < mod->module_core_rx + mod->core_size_rx) || + (location >= mod->module_core_rw && location < mod->module_core_rw + mod->core_size_rw)) entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; - else + else if ((location >= mod->module_init_rx && location < mod->module_init_rx + mod->init_size_rx) || + (location >= mod->module_init_rw && location < mod->module_init_rw + mod->init_size_rw)) entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; + else { + printk(KERN_ERR "%s: invalid R_PPC_REL24 entry found\n", mod->name); + return ~0UL; + } /* Find this entry, or if that fails, the next avail. entry */ while (entry->jump[0]) { diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/powerpc/kernel/signal_32.c linux-2.6.24.7-pax/arch/powerpc/kernel/signal_32.c --- linux-2.6.24.7/arch/powerpc/kernel/signal_32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/powerpc/kernel/signal_32.c 2008-02-29 18:07:50.000000000 +0100 @@ -731,7 +731,7 @@ int handle_rt_signal32(unsigned long sig /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; addr = frame; - if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { + if (vdso32_rt_sigtramp && current->mm->context.vdso_base != ~0UL) { if (save_user_regs(regs, frame, 0)) goto badframe; regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/powerpc/kernel/signal_64.c linux-2.6.24.7-pax/arch/powerpc/kernel/signal_64.c --- linux-2.6.24.7/arch/powerpc/kernel/signal_64.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/powerpc/kernel/signal_64.c 2008-02-29 18:07:50.000000000 +0100 @@ -369,7 +369,7 @@ int handle_rt_signal64(int signr, struct current->thread.fpscr.val = 0; /* Set up to return from userspace. */ - if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { + if (vdso64_rt_sigtramp && current->mm->context.vdso_base != ~0UL) { regs->link = current->mm->context.vdso_base + vdso64_rt_sigtramp; } else { err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/powerpc/kernel/vdso.c linux-2.6.24.7-pax/arch/powerpc/kernel/vdso.c --- linux-2.6.24.7/arch/powerpc/kernel/vdso.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/powerpc/kernel/vdso.c 2008-02-29 18:07:50.000000000 +0100 @@ -211,7 +211,7 @@ int arch_setup_additional_pages(struct l vdso_base = VDSO32_MBASE; #endif - current->mm->context.vdso_base = 0; + current->mm->context.vdso_base = ~0UL; /* vDSO has a problem and was disabled, just don't "enable" it for the * process @@ -228,7 +228,7 @@ int arch_setup_additional_pages(struct l */ down_write(&mm->mmap_sem); vdso_base = get_unmapped_area(NULL, vdso_base, - vdso_pages << PAGE_SHIFT, 0, 0); + vdso_pages << PAGE_SHIFT, 0, MAP_PRIVATE | MAP_EXECUTABLE); if (IS_ERR_VALUE(vdso_base)) { rc = vdso_base; goto fail_mmapsem; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/powerpc/mm/fault.c linux-2.6.24.7-pax/arch/powerpc/mm/fault.c --- linux-2.6.24.7/arch/powerpc/mm/fault.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/powerpc/mm/fault.c 2008-03-26 23:16:06.000000000 +0100 @@ -29,6 +29,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -62,6 +68,363 @@ static inline int notify_page_fault(stru } #endif +#ifdef CONFIG_PAX_EMUSIGRT +void pax_syscall_close(struct vm_area_struct *vma) +{ + vma->vm_mm->call_syscall = 0UL; +} + +static struct page *pax_syscall_nopage(struct vm_area_struct *vma, unsigned long address, int *type) +{ + struct page *page; + unsigned int *kaddr; + + page = alloc_page(GFP_HIGHUSER); + if (!page) + return NOPAGE_OOM; + + kaddr = kmap(page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x44000002U; /* sc */ + __flush_dcache_icache(kaddr); + kunmap(page); + if (type) + *type = VM_FAULT_MAJOR; + return page; +} + +static struct vm_operations_struct pax_vm_ops = { + .close = pax_syscall_close, + .nopage = pax_syscall_nopage, +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} +#endif + +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->nip = fault address) + * + * returns 1 when task should be killed + * 2 when patched GOT trampoline was detected + * 3 when patched PLT trampoline was detected + * 4 when unpatched PLT trampoline was detected + * 5 when sigreturn trampoline was detected + * 6 when rt_sigreturn trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#if defined(CONFIG_PAX_EMUPLT) || defined(CONFIG_PAX_EMUSIGRT) + int err; +#endif + +#ifdef CONFIG_PAX_EMUPLT + do { /* PaX: patched GOT emulation */ + unsigned int blrl; + + err = get_user(blrl, (unsigned int *)regs->nip); + + if (!err && blrl == 0x4E800021U) { + unsigned long temp = regs->nip; + + regs->nip = regs->link & 0xFFFFFFFCUL; + regs->link = temp + 4UL; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #1 */ + unsigned int b; + + err = get_user(b, (unsigned int *)regs->nip); + + if (!err && (b & 0xFC000003U) == 0x48000000U) { + regs->nip += (((b | 0xFC000000UL) ^ 0x02000000UL) + 0x02000000UL); + return 3; + } + } while (0); + + do { /* PaX: unpatched PLT emulation #1 */ + unsigned int li, b; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(b, (unsigned int *)(regs->nip+4)); + + if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) { + unsigned int rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(rlwinm, (unsigned int *)addr); + err |= get_user(add, (unsigned int *)(addr+4)); + err |= get_user(li2, (unsigned int *)(addr+8)); + err |= get_user(addis2, (unsigned int *)(addr+12)); + err |= get_user(mtctr, (unsigned int *)(addr+16)); + err |= get_user(li3, (unsigned int *)(addr+20)); + err |= get_user(addis3, (unsigned int *)(addr+24)); + err |= get_user(bctr, (unsigned int *)(addr+28)); + + if (err) + break; + + if (rlwinm == 0x556C083CU && + add == 0x7D6C5A14U && + (li2 & 0xFFFF0000U) == 0x39800000U && + (addis2 & 0xFFFF0000U) == 0x3D8C0000U && + mtctr == 0x7D8903A6U && + (li3 & 0xFFFF0000U) == 0x39800000U && + (addis3 & 0xFFFF0000U) == 0x3D8C0000U && + bctr == 0x4E800420U) + { + regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16; + regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->ctr += (addis2 & 0xFFFFU) << 16; + regs->nip = regs->ctr; + return 4; + } + } + } while (0); + +#if 0 + do { /* PaX: unpatched PLT emulation #2 */ + unsigned int lis, lwzu, b, bctr; + + err = get_user(lis, (unsigned int *)regs->nip); + err |= get_user(lwzu, (unsigned int *)(regs->nip+4)); + err |= get_user(b, (unsigned int *)(regs->nip+8)); + err |= get_user(bctr, (unsigned int *)(regs->nip+12)); + + if (err) + break; + + if ((lis & 0xFFFF0000U) == 0x39600000U && + (lwzu & 0xU) == 0xU && + (b & 0xFC000003U) == 0x48000000U && + bctr == 0x4E800420U) + { + unsigned int addis, addi, rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 12 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(addis, (unsigned int*)addr); + err |= get_user(addi, (unsigned int*)(addr+4)); + err |= get_user(rlwinm, (unsigned int*)(addr+8)); + err |= get_user(add, (unsigned int*)(addr+12)); + err |= get_user(li2, (unsigned int*)(addr+16)); + err |= get_user(addis2, (unsigned int*)(addr+20)); + err |= get_user(mtctr, (unsigned int*)(addr+24)); + err |= get_user(li3, (unsigned int*)(addr+28)); + err |= get_user(addis3, (unsigned int*)(addr+32)); + err |= get_user(bctr, (unsigned int*)(addr+36)); + + if (err) + break; + + if ((addis & 0xFFFF0000U) == 0x3D6B0000U && + (addi & 0xFFFF0000U) == 0x396B0000U && + rlwinm == 0x556C083CU && + add == 0x7D6C5A14U && + (li2 & 0xFFFF0000U) == 0x39800000U && + (addis2 & 0xFFFF0000U) == 0x3D8C0000U && + mtctr == 0x7D8903A6U && + (li3 & 0xFFFF0000U) == 0x39800000U && + (addis3 & 0xFFFF0000U) == 0x3D8C0000U && + bctr == 0x4E800420U) + { + regs->gpr[PT_R11] = + regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16; + regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->ctr += (addis2 & 0xFFFFU) << 16; + regs->nip = regs->ctr; + return 4; + } + } + } while (0); +#endif + + do { /* PaX: unpatched PLT emulation #3 */ + unsigned int li, b; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(b, (unsigned int *)(regs->nip+4)); + + if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) { + unsigned int addis, lwz, mtctr, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(addis, (unsigned int *)addr); + err |= get_user(lwz, (unsigned int *)(addr+4)); + err |= get_user(mtctr, (unsigned int *)(addr+8)); + err |= get_user(bctr, (unsigned int *)(addr+12)); + + if (err) + break; + + if ((addis & 0xFFFF0000U) == 0x3D6B0000U && + (lwz & 0xFFFF0000U) == 0x816B0000U && + mtctr == 0x7D6903A6U && + bctr == 0x4E800420U) + { + unsigned int r11; + + addr = (addis << 16) + (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + addr += (((lwz | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + + err = get_user(r11, (unsigned int *)addr); + if (err) + break; + + regs->gpr[PT_R11] = r11; + regs->ctr = r11; + regs->nip = r11; + return 4; + } + } + } while (0); +#endif + +#ifdef CONFIG_PAX_EMUSIGRT + do { /* PaX: sigreturn emulation */ + unsigned int li, sc; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(sc, (unsigned int *)(regs->nip+4)); + + if (!err && li == 0x38000000U + __NR_sigreturn && sc == 0x44000002U) { + struct vm_area_struct *vma; + unsigned long call_syscall; + + down_read(¤t->mm->mmap_sem); + call_syscall = current->mm->call_syscall; + up_read(¤t->mm->mmap_sem); + if (likely(call_syscall)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_syscall) { + call_syscall = current->mm->call_syscall; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_syscall & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_syscall)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_syscall = call_syscall; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->gpr[PT_R0] = __NR_sigreturn; + regs->nip = call_syscall; + return 5; + } + } while (0); + + do { /* PaX: rt_sigreturn emulation */ + unsigned int li, sc; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(sc, (unsigned int *)(regs->nip+4)); + + if (!err && li == 0x38000000U + __NR_rt_sigreturn && sc == 0x44000002U) { + struct vm_area_struct *vma; + unsigned int call_syscall; + + down_read(¤t->mm->mmap_sem); + call_syscall = current->mm->call_syscall; + up_read(¤t->mm->mmap_sem); + if (likely(call_syscall)) + goto rt_emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_syscall) { + call_syscall = current->mm->call_syscall; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto rt_emulate; + } + + call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_syscall & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_syscall)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_syscall = call_syscall; + up_write(¤t->mm->mmap_sem); + +rt_emulate: + regs->gpr[PT_R0] = __NR_rt_sigreturn; + regs->nip = call_syscall; + return 6; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk("???????? "); + else + printk("%08x ", c); + } + printk("\n"); +} +#endif + /* * Check whether the instruction at regs->nip is a store using * an update addressing form which will update r1. @@ -157,7 +520,7 @@ int __kprobes do_page_fault(struct pt_re * indicate errors in DSISR but can validly be set in SRR1. */ if (trap == 0x400) - error_code &= 0x48200000; + error_code &= 0x58200000; else is_write = error_code & DSISR_ISSTORE; #else @@ -357,6 +720,37 @@ bad_area: bad_area_nosemaphore: /* User mode accesses cause a SIGSEGV */ if (user_mode(regs)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm->pax_flags & MF_PAX_PAGEEXEC) { +#ifdef CONFIG_PPC64 + if (is_exec && (error_code & DSISR_PROTFAULT)) { +#else + if (is_exec && regs->nip == address) { +#endif + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + case 4: + return 0; +#endif + +#ifdef CONFIG_PAX_EMUSIGRT + case 5: + case 6: + return 0; +#endif + + } + + pax_report_fault(regs, (void*)regs->nip, (void*)regs->gpr[PT_R1]); + do_group_exit(SIGKILL); + } + } +#endif + _exception(SIGSEGV, regs, code, address); return 0; } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/powerpc/mm/mmap.c linux-2.6.24.7-pax/arch/powerpc/mm/mmap.c --- linux-2.6.24.7/arch/powerpc/mm/mmap.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/powerpc/mm/mmap.c 2008-02-29 18:07:50.000000000 +0100 @@ -75,10 +75,22 @@ void arch_pick_mmap_layout(struct mm_str */ if (mmap_is_legacy()) { mm->mmap_base = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; mm->unmap_area = arch_unmap_area; } else { mm->mmap_base = mmap_base(); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/ppc/mm/fault.c linux-2.6.24.7-pax/arch/ppc/mm/fault.c --- linux-2.6.24.7/arch/ppc/mm/fault.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/ppc/mm/fault.c 2008-03-26 23:16:50.000000000 +0100 @@ -25,6 +25,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -48,6 +53,363 @@ unsigned long pte_misses; /* updated by unsigned long pte_errors; /* updated by do_page_fault() */ unsigned int probingmem; +#ifdef CONFIG_PAX_EMUSIGRT +void pax_syscall_close(struct vm_area_struct *vma) +{ + vma->vm_mm->call_syscall = 0UL; +} + +static struct page *pax_syscall_nopage(struct vm_area_struct *vma, unsigned long address, int *type) +{ + struct page *page; + unsigned int *kaddr; + + page = alloc_page(GFP_HIGHUSER); + if (!page) + return NOPAGE_OOM; + + kaddr = kmap(page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x44000002U; /* sc */ + __flush_dcache_icache(kaddr); + kunmap(page); + if (type) + *type = VM_FAULT_MAJOR; + return page; +} + +static struct vm_operations_struct pax_vm_ops = { + .close = pax_syscall_close, + .nopage = pax_syscall_nopage, +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} +#endif + +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->nip = fault address) + * + * returns 1 when task should be killed + * 2 when patched GOT trampoline was detected + * 3 when patched PLT trampoline was detected + * 4 when unpatched PLT trampoline was detected + * 5 when sigreturn trampoline was detected + * 6 when rt_sigreturn trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#if defined(CONFIG_PAX_EMUPLT) || defined(CONFIG_PAX_EMUSIGRT) + int err; +#endif + +#ifdef CONFIG_PAX_EMUPLT + do { /* PaX: patched GOT emulation */ + unsigned int blrl; + + err = get_user(blrl, (unsigned int *)regs->nip); + + if (!err && blrl == 0x4E800021U) { + unsigned long temp = regs->nip; + + regs->nip = regs->link & 0xFFFFFFFCUL; + regs->link = temp + 4UL; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #1 */ + unsigned int b; + + err = get_user(b, (unsigned int *)regs->nip); + + if (!err && (b & 0xFC000003U) == 0x48000000U) { + regs->nip += (((b | 0xFC000000UL) ^ 0x02000000UL) + 0x02000000UL); + return 3; + } + } while (0); + + do { /* PaX: unpatched PLT emulation #1 */ + unsigned int li, b; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(b, (unsigned int *)(regs->nip+4)); + + if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) { + unsigned int rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(rlwinm, (unsigned int *)addr); + err |= get_user(add, (unsigned int *)(addr+4)); + err |= get_user(li2, (unsigned int *)(addr+8)); + err |= get_user(addis2, (unsigned int *)(addr+12)); + err |= get_user(mtctr, (unsigned int *)(addr+16)); + err |= get_user(li3, (unsigned int *)(addr+20)); + err |= get_user(addis3, (unsigned int *)(addr+24)); + err |= get_user(bctr, (unsigned int *)(addr+28)); + + if (err) + break; + + if (rlwinm == 0x556C083CU && + add == 0x7D6C5A14U && + (li2 & 0xFFFF0000U) == 0x39800000U && + (addis2 & 0xFFFF0000U) == 0x3D8C0000U && + mtctr == 0x7D8903A6U && + (li3 & 0xFFFF0000U) == 0x39800000U && + (addis3 & 0xFFFF0000U) == 0x3D8C0000U && + bctr == 0x4E800420U) + { + regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16; + regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->ctr += (addis2 & 0xFFFFU) << 16; + regs->nip = regs->ctr; + return 4; + } + } + } while (0); + +#if 0 + do { /* PaX: unpatched PLT emulation #2 */ + unsigned int lis, lwzu, b, bctr; + + err = get_user(lis, (unsigned int *)regs->nip); + err |= get_user(lwzu, (unsigned int *)(regs->nip+4)); + err |= get_user(b, (unsigned int *)(regs->nip+8)); + err |= get_user(bctr, (unsigned int *)(regs->nip+12)); + + if (err) + break; + + if ((lis & 0xFFFF0000U) == 0x39600000U && + (lwzu & 0xU) == 0xU && + (b & 0xFC000003U) == 0x48000000U && + bctr == 0x4E800420U) + { + unsigned int addis, addi, rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 12 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(addis, (unsigned int*)addr); + err |= get_user(addi, (unsigned int*)(addr+4)); + err |= get_user(rlwinm, (unsigned int*)(addr+8)); + err |= get_user(add, (unsigned int*)(addr+12)); + err |= get_user(li2, (unsigned int*)(addr+16)); + err |= get_user(addis2, (unsigned int*)(addr+20)); + err |= get_user(mtctr, (unsigned int*)(addr+24)); + err |= get_user(li3, (unsigned int*)(addr+28)); + err |= get_user(addis3, (unsigned int*)(addr+32)); + err |= get_user(bctr, (unsigned int*)(addr+36)); + + if (err) + break; + + if ((addis & 0xFFFF0000U) == 0x3D6B0000U && + (addi & 0xFFFF0000U) == 0x396B0000U && + rlwinm == 0x556C083CU && + add == 0x7D6C5A14U && + (li2 & 0xFFFF0000U) == 0x39800000U && + (addis2 & 0xFFFF0000U) == 0x3D8C0000U && + mtctr == 0x7D8903A6U && + (li3 & 0xFFFF0000U) == 0x39800000U && + (addis3 & 0xFFFF0000U) == 0x3D8C0000U && + bctr == 0x4E800420U) + { + regs->gpr[PT_R11] = + regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16; + regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->ctr += (addis2 & 0xFFFFU) << 16; + regs->nip = regs->ctr; + return 4; + } + } + } while (0); +#endif + + do { /* PaX: unpatched PLT emulation #3 */ + unsigned int li, b; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(b, (unsigned int *)(regs->nip+4)); + + if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) { + unsigned int addis, lwz, mtctr, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(addis, (unsigned int *)addr); + err |= get_user(lwz, (unsigned int *)(addr+4)); + err |= get_user(mtctr, (unsigned int *)(addr+8)); + err |= get_user(bctr, (unsigned int *)(addr+12)); + + if (err) + break; + + if ((addis & 0xFFFF0000U) == 0x3D6B0000U && + (lwz & 0xFFFF0000U) == 0x816B0000U && + mtctr == 0x7D6903A6U && + bctr == 0x4E800420U) + { + unsigned int r11; + + addr = (addis << 16) + (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + addr += (((lwz | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + + err = get_user(r11, (unsigned int *)addr); + if (err) + break; + + regs->gpr[PT_R11] = r11; + regs->ctr = r11; + regs->nip = r11; + return 4; + } + } + } while (0); +#endif + +#ifdef CONFIG_PAX_EMUSIGRT + do { /* PaX: sigreturn emulation */ + unsigned int li, sc; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(sc, (unsigned int *)(regs->nip+4)); + + if (!err && li == 0x38000000U + __NR_sigreturn && sc == 0x44000002U) { + struct vm_area_struct *vma; + unsigned long call_syscall; + + down_read(¤t->mm->mmap_sem); + call_syscall = current->mm->call_syscall; + up_read(¤t->mm->mmap_sem); + if (likely(call_syscall)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_syscall) { + call_syscall = current->mm->call_syscall; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_syscall & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_syscall)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_syscall = call_syscall; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->gpr[PT_R0] = __NR_sigreturn; + regs->nip = call_syscall; + return 5; + } + } while (0); + + do { /* PaX: rt_sigreturn emulation */ + unsigned int li, sc; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(sc, (unsigned int *)(regs->nip+4)); + + if (!err && li == 0x38000000U + __NR_rt_sigreturn && sc == 0x44000002U) { + struct vm_area_struct *vma; + unsigned int call_syscall; + + down_read(¤t->mm->mmap_sem); + call_syscall = current->mm->call_syscall; + up_read(¤t->mm->mmap_sem); + if (likely(call_syscall)) + goto rt_emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_syscall) { + call_syscall = current->mm->call_syscall; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto rt_emulate; + } + + call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_syscall & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_syscall)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_syscall = call_syscall; + up_write(¤t->mm->mmap_sem); + +rt_emulate: + regs->gpr[PT_R0] = __NR_rt_sigreturn; + regs->nip = call_syscall; + return 6; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk("???????? "); + else + printk("%08x ", c); + } + printk("\n"); +} +#endif + /* * Check whether the instruction at regs->nip is a store using * an update addressing form which will update r1. @@ -109,7 +471,7 @@ int do_page_fault(struct pt_regs *regs, * indicate errors in DSISR but can validly be set in SRR1. */ if (TRAP(regs) == 0x400) - error_code &= 0x48200000; + error_code &= 0x58200000; else is_write = error_code & 0x02000000; #endif /* CONFIG_4xx || CONFIG_BOOKE */ @@ -204,15 +566,14 @@ good_area: pte_t *ptep; pmd_t *pmdp; -#if 0 +#if 1 /* It would be nice to actually enforce the VM execute permission on CPUs which can do so, but far too much stuff in userspace doesn't get the permissions right, so we let any page be executed for now. */ if (! (vma->vm_flags & VM_EXEC)) goto bad_area; -#endif - +#else /* Since 4xx/Book-E supports per-page execute permission, * we lazily flush dcache to icache. */ ptep = NULL; @@ -235,6 +596,7 @@ good_area: pte_unmap_unlock(ptep, ptl); } #endif +#endif /* a read */ } else { /* protection fault */ @@ -278,6 +640,33 @@ bad_area: /* User mode accesses cause a SIGSEGV */ if (user_mode(regs)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm->pax_flags & MF_PAX_PAGEEXEC) { + if ((TRAP(regs) == 0x400) && (regs->nip == address)) { + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + case 4: + return 0; +#endif + +#ifdef CONFIG_PAX_EMUSIGRT + case 5: + case 6: + return 0; +#endif + + } + + pax_report_fault(regs, (void *)regs->nip, (void *)regs->gpr[1]); + do_group_exit(SIGKILL); + } + } +#endif + _exception(SIGSEGV, regs, code, address); return 0; } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/s390/kernel/module.c linux-2.6.24.7-pax/arch/s390/kernel/module.c --- linux-2.6.24.7/arch/s390/kernel/module.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/s390/kernel/module.c 2008-02-29 18:07:50.000000000 +0100 @@ -166,11 +166,11 @@ module_frob_arch_sections(Elf_Ehdr *hdr, /* Increase core size by size of got & plt and set start offsets for got and plt. */ - me->core_size = ALIGN(me->core_size, 4); - me->arch.got_offset = me->core_size; - me->core_size += me->arch.got_size; - me->arch.plt_offset = me->core_size; - me->core_size += me->arch.plt_size; + me->core_size_rw = ALIGN(me->core_size_rw, 4); + me->arch.got_offset = me->core_size_rw; + me->core_size_rw += me->arch.got_size; + me->arch.plt_offset = me->core_size_rx; + me->core_size_rx += me->arch.plt_size; return 0; } @@ -256,7 +256,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base if (info->got_initialized == 0) { Elf_Addr *gotent; - gotent = me->module_core + me->arch.got_offset + + gotent = me->module_core_rw + me->arch.got_offset + info->got_offset; *gotent = val; info->got_initialized = 1; @@ -280,7 +280,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base else if (r_type == R_390_GOTENT || r_type == R_390_GOTPLTENT) *(unsigned int *) loc = - (val + (Elf_Addr) me->module_core - loc) >> 1; + (val + (Elf_Addr) me->module_core_rw - loc) >> 1; else if (r_type == R_390_GOT64 || r_type == R_390_GOTPLT64) *(unsigned long *) loc = val; @@ -294,7 +294,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */ if (info->plt_initialized == 0) { unsigned int *ip; - ip = me->module_core + me->arch.plt_offset + + ip = me->module_core_rx + me->arch.plt_offset + info->plt_offset; #ifndef CONFIG_64BIT ip[0] = 0x0d105810; /* basr 1,0; l 1,6(1); br 1 */ @@ -316,7 +316,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base val = me->arch.plt_offset - me->arch.got_offset + info->plt_offset + rela->r_addend; else - val = (Elf_Addr) me->module_core + + val = (Elf_Addr) me->module_core_rx + me->arch.plt_offset + info->plt_offset + rela->r_addend - loc; if (r_type == R_390_PLT16DBL) @@ -336,7 +336,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base case R_390_GOTOFF32: /* 32 bit offset to GOT. */ case R_390_GOTOFF64: /* 64 bit offset to GOT. */ val = val + rela->r_addend - - ((Elf_Addr) me->module_core + me->arch.got_offset); + ((Elf_Addr) me->module_core_rw + me->arch.got_offset); if (r_type == R_390_GOTOFF16) *(unsigned short *) loc = val; else if (r_type == R_390_GOTOFF32) @@ -346,7 +346,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base break; case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ - val = (Elf_Addr) me->module_core + me->arch.got_offset + + val = (Elf_Addr) me->module_core_rw + me->arch.got_offset + rela->r_addend - loc; if (r_type == R_390_GOTPC) *(unsigned int *) loc = val; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/sparc/kernel/sys_sparc.c linux-2.6.24.7-pax/arch/sparc/kernel/sys_sparc.c --- linux-2.6.24.7/arch/sparc/kernel/sys_sparc.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/sparc/kernel/sys_sparc.c 2008-02-29 18:07:50.000000000 +0100 @@ -57,7 +57,7 @@ unsigned long arch_get_unmapped_area(str if (ARCH_SUN4C_SUN4 && len > 0x20000000) return -ENOMEM; if (!addr) - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/sparc/mm/fault.c linux-2.6.24.7-pax/arch/sparc/mm/fault.c --- linux-2.6.24.7/arch/sparc/mm/fault.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/sparc/mm/fault.c 2008-03-26 23:17:11.000000000 +0100 @@ -21,6 +21,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -216,6 +220,251 @@ static unsigned long compute_si_addr(str return safe_compute_effective_address(regs, insn); } +#ifdef CONFIG_PAX_PAGEEXEC +void pax_emuplt_close(struct vm_area_struct *vma) +{ + vma->vm_mm->call_dl_resolve = 0UL; +} + +static struct page *pax_emuplt_nopage(struct vm_area_struct *vma, unsigned long address, int *type) +{ + struct page *page; + unsigned int *kaddr; + + page = alloc_page(GFP_HIGHUSER); + if (!page) + return NOPAGE_OOM; + + kaddr = kmap(page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x9DE3BFA8U; /* save */ + flush_dcache_page(page); + kunmap(page); + if (type) + *type = VM_FAULT_MAJOR; + + return page; +} + +static struct vm_operations_struct pax_vm_ops = { + .close = pax_emuplt_close, + .nopage = pax_emuplt_nopage, +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} + +/* + * PaX: decide what to do with offenders (regs->pc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: patched PLT emulation #1 */ + unsigned int sethi1, sethi2, jmpl; + + err = get_user(sethi1, (unsigned int *)regs->pc); + err |= get_user(sethi2, (unsigned int *)(regs->pc+4)); + err |= get_user(jmpl, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U) + { + unsigned int addr; + + regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10; + addr = regs->u_regs[UREG_G1]; + addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + { /* PaX: patched PLT emulation #2 */ + unsigned int ba; + + err = get_user(ba, (unsigned int *)regs->pc); + + if (!err && (ba & 0xFFC00000U) == 0x30800000U) { + unsigned int addr; + + addr = regs->pc + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } + + do { /* PaX: patched PLT emulation #3 */ + unsigned int sethi, jmpl, nop; + + err = get_user(sethi, (unsigned int *)regs->pc); + err |= get_user(jmpl, (unsigned int *)(regs->pc+4)); + err |= get_user(nop, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U && + nop == 0x01000000U) + { + unsigned int addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 1 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->pc); + err |= get_user(ba, (unsigned int *)(regs->pc+4)); + err |= get_user(nop, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) && + nop == 0x01000000U) + { + unsigned int addr, save, call; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->pc + 4 + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2); + else + addr = regs->pc + 4 + ((((ba | 0xFFF80000U) ^ 0x00040000U) + 0x00040000U) << 2); + + err = get_user(save, (unsigned int *)addr); + err |= get_user(call, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + struct vm_area_struct *vma; + unsigned long call_dl_resolve; + + down_read(¤t->mm->mmap_sem); + call_dl_resolve = current->mm->call_dl_resolve; + up_read(¤t->mm->mmap_sem); + if (likely(call_dl_resolve)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_dl_resolve) { + call_dl_resolve = current->mm->call_dl_resolve; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_dl_resolve & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_dl_resolve)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_dl_resolve = call_dl_resolve; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->pc = call_dl_resolve; + regs->npc = addr+4; + return 3; + } + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 2 */ + unsigned int save, call, nop; + + err = get_user(save, (unsigned int *)(regs->pc-4)); + err |= get_user(call, (unsigned int *)regs->pc); + err |= get_user(nop, (unsigned int *)(regs->pc+4)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + unsigned int dl_resolve = regs->pc + ((((call | 0xC0000000U) ^ 0x20000000U) + 0x20000000U) << 2); + + regs->u_regs[UREG_RETPC] = regs->pc; + regs->pc = dl_resolve; + regs->npc = dl_resolve+4; + return 3; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk("???????? "); + else + printk("%08x ", c); + } + printk("\n"); +} +#endif + asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, unsigned long address) { @@ -280,6 +529,24 @@ good_area: if(!(vma->vm_flags & VM_WRITE)) goto bad_area; } else { + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && text_fault && !(vma->vm_flags & VM_EXEC)) { + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void *)regs->pc, (void *)regs->u_regs[UREG_FP]); + do_group_exit(SIGKILL); + } +#endif + /* Allow reads even for write-only mappings */ if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/sparc/mm/init.c linux-2.6.24.7-pax/arch/sparc/mm/init.c --- linux-2.6.24.7/arch/sparc/mm/init.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/sparc/mm/init.c 2008-02-29 18:07:50.000000000 +0100 @@ -336,17 +336,17 @@ void __init paging_init(void) /* Initialize the protection map with non-constant, MMU dependent values. */ protection_map[0] = PAGE_NONE; - protection_map[1] = PAGE_READONLY; - protection_map[2] = PAGE_COPY; - protection_map[3] = PAGE_COPY; + protection_map[1] = PAGE_READONLY_NOEXEC; + protection_map[2] = PAGE_COPY_NOEXEC; + protection_map[3] = PAGE_COPY_NOEXEC; protection_map[4] = PAGE_READONLY; protection_map[5] = PAGE_READONLY; protection_map[6] = PAGE_COPY; protection_map[7] = PAGE_COPY; protection_map[8] = PAGE_NONE; - protection_map[9] = PAGE_READONLY; - protection_map[10] = PAGE_SHARED; - protection_map[11] = PAGE_SHARED; + protection_map[9] = PAGE_READONLY_NOEXEC; + protection_map[10] = PAGE_SHARED_NOEXEC; + protection_map[11] = PAGE_SHARED_NOEXEC; protection_map[12] = PAGE_READONLY; protection_map[13] = PAGE_READONLY; protection_map[14] = PAGE_SHARED; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/sparc/mm/srmmu.c linux-2.6.24.7-pax/arch/sparc/mm/srmmu.c --- linux-2.6.24.7/arch/sparc/mm/srmmu.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/sparc/mm/srmmu.c 2008-02-29 18:07:50.000000000 +0100 @@ -2157,6 +2157,13 @@ void __init ld_mmu_srmmu(void) PAGE_SHARED = pgprot_val(SRMMU_PAGE_SHARED); BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY)); BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY)); + +#ifdef CONFIG_PAX_PAGEEXEC + PAGE_SHARED_NOEXEC = pgprot_val(SRMMU_PAGE_SHARED_NOEXEC); + BTFIXUPSET_INT(page_copy_noexec, pgprot_val(SRMMU_PAGE_COPY_NOEXEC)); + BTFIXUPSET_INT(page_readonly_noexec, pgprot_val(SRMMU_PAGE_RDONLY_NOEXEC)); +#endif + BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL)); page_kernel = pgprot_val(SRMMU_PAGE_KERNEL); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/sparc64/kernel/Makefile linux-2.6.24.7-pax/arch/sparc64/kernel/Makefile --- linux-2.6.24.7/arch/sparc64/kernel/Makefile 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/sparc64/kernel/Makefile 2008-02-29 18:07:50.000000000 +0100 @@ -3,7 +3,7 @@ # EXTRA_AFLAGS := -ansi -EXTRA_CFLAGS := -Werror +#EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/sparc64/kernel/sys_sparc.c linux-2.6.24.7-pax/arch/sparc64/kernel/sys_sparc.c --- linux-2.6.24.7/arch/sparc64/kernel/sys_sparc.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/sparc64/kernel/sys_sparc.c 2008-02-29 18:07:50.000000000 +0100 @@ -123,7 +123,7 @@ unsigned long arch_get_unmapped_area(str /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if ((filp || (flags & MAP_SHARED)) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -138,6 +138,10 @@ unsigned long arch_get_unmapped_area(str if (filp || (flags & MAP_SHARED)) do_color_align = 1; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -151,9 +155,9 @@ unsigned long arch_get_unmapped_area(str } if (len > mm->cached_hole_size) { - start_addr = addr = mm->free_area_cache; + start_addr = addr = mm->free_area_cache; } else { - start_addr = addr = TASK_UNMAPPED_BASE; + start_addr = addr = mm->mmap_base; mm->cached_hole_size = 0; } @@ -173,8 +177,8 @@ full_search: vma = find_vma(mm, VA_EXCLUDE_END); } if (unlikely(task_size < addr)) { - if (start_addr != TASK_UNMAPPED_BASE) { - start_addr = addr = TASK_UNMAPPED_BASE; + if (start_addr != mm->mmap_base) { + start_addr = addr = mm->mmap_base; mm->cached_hole_size = 0; goto full_search; } @@ -214,7 +218,7 @@ arch_get_unmapped_area_topdown(struct fi /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if ((filp || (flags & MAP_SHARED)) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -377,6 +381,12 @@ void arch_pick_mmap_layout(struct mm_str current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY || sysctl_legacy_va_layout) { mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; mm->unmap_area = arch_unmap_area; } else { @@ -391,6 +401,12 @@ void arch_pick_mmap_layout(struct mm_str gap = (task_size / 6 * 5); mm->mmap_base = PAGE_ALIGN(task_size - gap - random_factor); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/sparc64/mm/Makefile linux-2.6.24.7-pax/arch/sparc64/mm/Makefile --- linux-2.6.24.7/arch/sparc64/mm/Makefile 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/sparc64/mm/Makefile 2008-02-29 18:07:50.000000000 +0100 @@ -3,7 +3,7 @@ # EXTRA_AFLAGS := -ansi -EXTRA_CFLAGS := -Werror +#EXTRA_CFLAGS := -Werror obj-y := ultra.o tlb.o tsb.o fault.o init.o generic.o diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/sparc64/mm/fault.c linux-2.6.24.7-pax/arch/sparc64/mm/fault.c --- linux-2.6.24.7/arch/sparc64/mm/fault.c 2008-03-25 14:04:20.000000000 +0100 +++ linux-2.6.24.7-pax/arch/sparc64/mm/fault.c 2008-03-26 23:17:33.000000000 +0100 @@ -20,6 +20,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -262,6 +266,368 @@ cannot_handle: unhandled_fault (address, current, regs); } +#ifdef CONFIG_PAX_PAGEEXEC +#ifdef CONFIG_PAX_EMUPLT +static void pax_emuplt_close(struct vm_area_struct *vma) +{ + vma->vm_mm->call_dl_resolve = 0UL; +} + +static struct page *pax_emuplt_nopage(struct vm_area_struct *vma, unsigned long address, int *type) +{ + struct page *page; + unsigned int *kaddr; + + page = alloc_page(GFP_HIGHUSER); + if (!page) + return NOPAGE_OOM; + + kaddr = kmap(page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x9DE3BFA8U; /* save */ + flush_dcache_page(page); + kunmap(page); + if (type) + *type = VM_FAULT_MAJOR; + return page; +} + +static struct vm_operations_struct pax_vm_ops = { + .close = pax_emuplt_close, + .nopage = pax_emuplt_nopage, +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} +#endif + +/* + * PaX: decide what to do with offenders (regs->tpc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: patched PLT emulation #1 */ + unsigned int sethi1, sethi2, jmpl; + + err = get_user(sethi1, (unsigned int *)regs->tpc); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+4)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10; + addr = regs->u_regs[UREG_G1]; + addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + { /* PaX: patched PLT emulation #2 */ + unsigned int ba; + + err = get_user(ba, (unsigned int *)regs->tpc); + + if (!err && (ba & 0xFFC00000U) == 0x30800000U) { + unsigned long addr; + + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } + + do { /* PaX: patched PLT emulation #3 */ + unsigned int sethi, jmpl, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U && + nop == 0x01000000U) + { + unsigned long addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #4 */ + unsigned int mov1, call, mov2; + + err = get_user(mov1, (unsigned int *)regs->tpc); + err |= get_user(call, (unsigned int *)(regs->tpc+4)); + err |= get_user(mov2, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if (mov1 == 0x8210000FU && + (call & 0xC0000000U) == 0x40000000U && + mov2 == 0x9E100001U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = regs->u_regs[UREG_RETPC]; + addr = regs->tpc + 4 + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #5 */ + unsigned int sethi1, sethi2, or1, or2, sllx, jmpl, nop; + + err = get_user(sethi1, (unsigned int *)regs->tpc); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+4)); + err |= get_user(or1, (unsigned int *)(regs->tpc+8)); + err |= get_user(or2, (unsigned int *)(regs->tpc+12)); + err |= get_user(sllx, (unsigned int *)(regs->tpc+16)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+20)); + err |= get_user(nop, (unsigned int *)(regs->tpc+24)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + (or1 & 0xFFFFE000U) == 0x82106000U && + (or2 & 0xFFFFE000U) == 0x8A116000U && + sllx == 0x83287020 && + jmpl == 0x81C04005U && + nop == 0x01000000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = ((sethi1 & 0x003FFFFFU) << 10) | (or1 & 0x000003FFU); + regs->u_regs[UREG_G1] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or2 & 0x000003FFU); + addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #6 */ + unsigned int sethi1, sethi2, sllx, or, jmpl, nop; + + err = get_user(sethi1, (unsigned int *)regs->tpc); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+4)); + err |= get_user(sllx, (unsigned int *)(regs->tpc+8)); + err |= get_user(or, (unsigned int *)(regs->tpc+12)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+16)); + err |= get_user(nop, (unsigned int *)(regs->tpc+20)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + sllx == 0x83287020 && + (or & 0xFFFFE000U) == 0x8A116000U && + jmpl == 0x81C04005U && + nop == 0x01000000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = (sethi1 & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or & 0x3FFU); + addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #7 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(ba, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (ba & 0xFFF00000U) == 0x30600000U && + nop == 0x01000000U) + { + unsigned long addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 1 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(ba, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) && + nop == 0x01000000U) + { + unsigned long addr; + unsigned int save, call; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2); + else + addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + + err = get_user(save, (unsigned int *)addr); + err |= get_user(call, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + struct vm_area_struct *vma; + unsigned long call_dl_resolve; + + down_read(¤t->mm->mmap_sem); + call_dl_resolve = current->mm->call_dl_resolve; + up_read(¤t->mm->mmap_sem); + if (likely(call_dl_resolve)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_dl_resolve) { + call_dl_resolve = current->mm->call_dl_resolve; + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_dl_resolve & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_dl_resolve)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_dl_resolve = call_dl_resolve; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->tpc = call_dl_resolve; + regs->tnpc = addr+4; + return 3; + } + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 2 */ + unsigned int save, call, nop; + + err = get_user(save, (unsigned int *)(regs->tpc-4)); + err |= get_user(call, (unsigned int *)regs->tpc); + err |= get_user(nop, (unsigned int *)(regs->tpc+4)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + unsigned long dl_resolve = regs->tpc + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2); + + regs->u_regs[UREG_RETPC] = regs->tpc; + regs->tpc = dl_resolve; + regs->tnpc = dl_resolve+4; + return 3; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk("???????? "); + else + printk("%08x ", c); + } + printk("\n"); +} +#endif + asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) { struct mm_struct *mm = current->mm; @@ -303,8 +669,10 @@ asmlinkage void __kprobes do_sparc64_fau goto intr_or_no_mm; if (test_thread_flag(TIF_32BIT)) { - if (!(regs->tstate & TSTATE_PRIV)) + if (!(regs->tstate & TSTATE_PRIV)) { regs->tpc &= 0xffffffff; + regs->tnpc &= 0xffffffff; + } address &= 0xffffffff; } @@ -321,6 +689,29 @@ asmlinkage void __kprobes do_sparc64_fau if (!vma) goto bad_area; +#ifdef CONFIG_PAX_PAGEEXEC + /* PaX: detect ITLB misses on non-exec pages */ + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && vma->vm_start <= address && + !(vma->vm_flags & VM_EXEC) && (fault_code & FAULT_CODE_ITLB)) + { + if (address != regs->tpc) + goto good_area; + + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void*)regs->tpc, (void*)(regs->u_regs[UREG_FP] + STACK_BIAS)); + do_group_exit(SIGKILL); + } +#endif + /* Pure DTLB misses do not tell us whether the fault causing * load/store/atomic was a write or not, it only says that there * was no match. So in such a case we (carefully) read the diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/v850/kernel/module.c linux-2.6.24.7-pax/arch/v850/kernel/module.c --- linux-2.6.24.7/arch/v850/kernel/module.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/v850/kernel/module.c 2008-02-29 18:07:50.000000000 +0100 @@ -150,8 +150,8 @@ static uint32_t do_plt_call (void *locat tramp[1] = ((val >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */ /* Init, or core PLT? */ - if (location >= mod->module_core - && location < mod->module_core + mod->core_size) + if (location >= mod->module_core_rx + && location < mod->module_core_rx + mod->core_size_rx) entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; else entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/Kconfig linux-2.6.24.7-pax/arch/x86/Kconfig --- linux-2.6.24.7/arch/x86/Kconfig 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/Kconfig 2008-02-29 18:07:50.000000000 +0100 @@ -792,7 +792,7 @@ config PAGE_OFFSET hex default 0xB0000000 if VMSPLIT_3G_OPT default 0x80000000 if VMSPLIT_2G - default 0x78000000 if VMSPLIT_2G_OPT + default 0x70000000 if VMSPLIT_2G_OPT default 0x40000000 if VMSPLIT_1G default 0xC0000000 depends on X86_32 @@ -1096,8 +1096,7 @@ config CRASH_DUMP config PHYSICAL_START hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP) default "0x1000000" if X86_NUMAQ - default "0x200000" if X86_64 - default "0x100000" + default "0x200000" help This gives the physical address where the kernel is loaded. @@ -1190,7 +1189,7 @@ config HOTPLUG_CPU config COMPAT_VDSO bool "Compat VDSO support" - default y + default n depends on X86_32 help Map the VDSO to the predictable old-style address too. @@ -1387,7 +1386,7 @@ config PCI choice prompt "PCI access mode" depends on X86_32 && PCI && !X86_VISWS - default PCI_GOANY + default PCI_GODIRECT ---help--- On PCI systems, the BIOS can be used to detect the PCI devices and determine their configuration. However, some old PCI motherboards diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/Kconfig.cpu linux-2.6.24.7-pax/arch/x86/Kconfig.cpu --- linux-2.6.24.7/arch/x86/Kconfig.cpu 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/Kconfig.cpu 2008-04-14 12:46:53.000000000 +0200 @@ -328,7 +328,7 @@ config X86_PPRO_FENCE config X86_F00F_BUG bool - depends on M586MMX || M586TSC || M586 || M486 || M386 + depends on (M586MMX || M586TSC || M586 || M486 || M386) && !PAX_KERNEXEC default y config X86_WP_WORKS_OK @@ -353,7 +353,7 @@ config X86_POPAD_OK config X86_ALIGNMENT_16 bool - depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 + depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK8 || MK7 || MK6 || MCORE2 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 default y config X86_GOOD_APIC @@ -390,7 +390,7 @@ config X86_TSC # generates cmov. config X86_CMOV bool - depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7) + depends on (MK8 || MK7 || MCORE2 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7) default y config X86_MINIMUM_CPU_FAMILY diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/Kconfig.debug linux-2.6.24.7-pax/arch/x86/Kconfig.debug --- linux-2.6.24.7/arch/x86/Kconfig.debug 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/Kconfig.debug 2008-02-29 18:07:50.000000000 +0100 @@ -49,7 +49,7 @@ config DEBUG_PAGEALLOC config DEBUG_RODATA bool "Write protect kernel read-only data structures" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && BROKEN help Mark the kernel read-only data as write-protected in the pagetables, in order to catch accidental (and incorrect) writes to such const diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/bitops.h linux-2.6.24.7-pax/arch/x86/boot/bitops.h --- linux-2.6.24.7/arch/x86/boot/bitops.h 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/bitops.h 2008-02-29 18:07:50.000000000 +0100 @@ -28,7 +28,7 @@ static inline int variable_test_bit(int u8 v; const u32 *p = (const u32 *)addr; - asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); + asm volatile("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); return v; } @@ -39,7 +39,7 @@ static inline int variable_test_bit(int static inline void set_bit(int nr, void *addr) { - asm("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr)); + asm volatile("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr)); } #endif /* BOOT_BITOPS_H */ diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/boot.h linux-2.6.24.7-pax/arch/x86/boot/boot.h --- linux-2.6.24.7/arch/x86/boot/boot.h 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/boot.h 2008-02-29 18:07:50.000000000 +0100 @@ -78,7 +78,7 @@ static inline void io_delay(void) static inline u16 ds(void) { u16 seg; - asm("movw %%ds,%0" : "=rm" (seg)); + asm volatile("movw %%ds,%0" : "=rm" (seg)); return seg; } @@ -174,7 +174,7 @@ static inline void wrgs32(u32 v, addr_t static inline int memcmp(const void *s1, const void *s2, size_t len) { u8 diff; - asm("repe; cmpsb; setnz %0" + asm volatile("repe; cmpsb; setnz %0" : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/compressed/head_32.S linux-2.6.24.7-pax/arch/x86/boot/compressed/head_32.S --- linux-2.6.24.7/arch/x86/boot/compressed/head_32.S 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/compressed/head_32.S 2008-02-29 18:07:50.000000000 +0100 @@ -70,7 +70,7 @@ startup_32: addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx #else - movl $LOAD_PHYSICAL_ADDR, %ebx + movl $____LOAD_PHYSICAL_ADDR, %ebx #endif /* Replace the compressed data size with the uncompressed size */ @@ -105,7 +105,7 @@ startup_32: addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp #else - movl $LOAD_PHYSICAL_ADDR, %ebp + movl $____LOAD_PHYSICAL_ADDR, %ebp #endif /* @@ -159,16 +159,15 @@ relocated: * and where it was actually loaded. */ movl %ebp, %ebx - subl $LOAD_PHYSICAL_ADDR, %ebx + subl $____LOAD_PHYSICAL_ADDR, %ebx jz 2f /* Nothing to be done if loaded at compiled addr. */ /* * Process relocations. */ 1: subl $4, %edi - movl 0(%edi), %ecx - testl %ecx, %ecx - jz 2f + movl (%edi), %ecx + jecxz 2f addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) jmp 1b 2: diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/compressed/misc_32.c linux-2.6.24.7-pax/arch/x86/boot/compressed/misc_32.c --- linux-2.6.24.7/arch/x86/boot/compressed/misc_32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/compressed/misc_32.c 2008-02-29 18:07:50.000000000 +0100 @@ -113,7 +113,8 @@ typedef unsigned char uch; typedef unsigned short ush; typedef unsigned long ulg; -#define WSIZE 0x80000000 /* Window size must be at least 32k, +#define WSIZE 0x80000000 + /* Window size must be at least 32k, * and a power of two * We don't actually have a window just * a huge output buffer so I report @@ -370,7 +371,7 @@ asmlinkage void decompress_kernel(void * if (end > ((-__PAGE_OFFSET-(512 <<20)-1) & 0x7fffffff)) error("Destination address too large"); #ifndef CONFIG_RELOCATABLE - if ((u32)output != LOAD_PHYSICAL_ADDR) + if ((u32)output != ____LOAD_PHYSICAL_ADDR) error("Wrong destination address"); #endif diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/compressed/relocs.c linux-2.6.24.7-pax/arch/x86/boot/compressed/relocs.c --- linux-2.6.24.7/arch/x86/boot/compressed/relocs.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/compressed/relocs.c 2008-02-29 18:07:50.000000000 +0100 @@ -10,9 +10,13 @@ #define USE_BSD #include +#include "../../../../include/linux/autoconf.h" + +#define MAX_PHDRS 100 #define MAX_SHDRS 100 #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) static Elf32_Ehdr ehdr; +static Elf32_Phdr phdr[MAX_PHDRS]; static Elf32_Shdr shdr[MAX_SHDRS]; static Elf32_Sym *symtab[MAX_SHDRS]; static Elf32_Rel *reltab[MAX_SHDRS]; @@ -244,6 +248,34 @@ static void read_ehdr(FILE *fp) } } +static void read_phdrs(FILE *fp) +{ + int i; + if (ehdr.e_phnum > MAX_PHDRS) { + die("%d program headers supported: %d\n", + ehdr.e_phnum, MAX_PHDRS); + } + if (fseek(fp, ehdr.e_phoff, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + ehdr.e_phoff, strerror(errno)); + } + if (fread(&phdr, sizeof(phdr[0]), ehdr.e_phnum, fp) != ehdr.e_phnum) { + die("Cannot read ELF program headers: %s\n", + strerror(errno)); + } + for(i = 0; i < ehdr.e_phnum; i++) { + phdr[i].p_type = elf32_to_cpu(phdr[i].p_type); + phdr[i].p_offset = elf32_to_cpu(phdr[i].p_offset); + phdr[i].p_vaddr = elf32_to_cpu(phdr[i].p_vaddr); + phdr[i].p_paddr = elf32_to_cpu(phdr[i].p_paddr); + phdr[i].p_filesz = elf32_to_cpu(phdr[i].p_filesz); + phdr[i].p_memsz = elf32_to_cpu(phdr[i].p_memsz); + phdr[i].p_flags = elf32_to_cpu(phdr[i].p_flags); + phdr[i].p_align = elf32_to_cpu(phdr[i].p_align); + } + +} + static void read_shdrs(FILE *fp) { int i; @@ -330,6 +362,8 @@ static void read_symtabs(FILE *fp) static void read_relocs(FILE *fp) { int i,j; + uint32_t base; + for(i = 0; i < ehdr.e_shnum; i++) { if (shdr[i].sh_type != SHT_REL) { continue; @@ -347,8 +381,17 @@ static void read_relocs(FILE *fp) die("Cannot read symbol table: %s\n", strerror(errno)); } + base = 0; + for (j = 0; j < ehdr.e_phnum; j++) { + if (phdr[j].p_type != PT_LOAD ) + continue; + if (shdr[shdr[i].sh_info].sh_offset < phdr[j].p_offset || shdr[shdr[i].sh_info].sh_offset > phdr[j].p_offset + phdr[j].p_filesz) + continue; + base = CONFIG_PAGE_OFFSET + phdr[j].p_paddr - phdr[j].p_vaddr; + break; + } for(j = 0; j < shdr[i].sh_size/sizeof(reltab[0][0]); j++) { - reltab[i][j].r_offset = elf32_to_cpu(reltab[i][j].r_offset); + reltab[i][j].r_offset = elf32_to_cpu(reltab[i][j].r_offset) + base; reltab[i][j].r_info = elf32_to_cpu(reltab[i][j].r_info); } } @@ -485,6 +528,27 @@ static void walk_relocs(void (*visit)(El if (sym->st_shndx == SHN_ABS) { continue; } + /* Don't relocate actual per-cpu variables, they are absolute indices, not addresses */ + if (!strcmp(sec_name(sym->st_shndx), ".data.percpu") && strncmp(sym_name(sym_strtab, sym), "__per_cpu_", 10)) { + continue; + } +#if defined(CONFIG_PAX_KERNEXEC) && defined(CONFIG_X86_32) + /* Don't relocate actual code, they are relocated implicitly by the base address of KERNEL_CS */ + if (!strcmp(sec_name(sym->st_shndx), ".init.text")) { + continue; + } + if (!strcmp(sec_name(sym->st_shndx), ".exit.text")) { + continue; + } + if (!strcmp(sec_name(sym->st_shndx), ".text.head")) { + if (strcmp(sym_name(sym_strtab, sym), "__init_end") && + strcmp(sym_name(sym_strtab, sym), "KERNEL_TEXT_OFFSET")) + continue; + } + if (!strcmp(sec_name(sym->st_shndx), ".text")) { + continue; + } +#endif if (r_type == R_386_PC32) { /* PC relative relocations don't need to be adjusted */ } @@ -612,6 +676,7 @@ int main(int argc, char **argv) fname, strerror(errno)); } read_ehdr(fp); + read_phdrs(fp); read_shdrs(fp); read_strtabs(fp); read_symtabs(fp); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/cpucheck.c linux-2.6.24.7-pax/arch/x86/boot/cpucheck.c --- linux-2.6.24.7/arch/x86/boot/cpucheck.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/cpucheck.c 2008-02-29 18:07:50.000000000 +0100 @@ -84,7 +84,7 @@ static int has_fpu(void) u16 fcw = -1, fsw = -1; u32 cr0; - asm("movl %%cr0,%0" : "=r" (cr0)); + asm volatile("movl %%cr0,%0" : "=r" (cr0)); if (cr0 & (X86_CR0_EM|X86_CR0_TS)) { cr0 &= ~(X86_CR0_EM|X86_CR0_TS); asm volatile("movl %0,%%cr0" : : "r" (cr0)); @@ -100,7 +100,7 @@ static int has_eflag(u32 mask) { u32 f0, f1; - asm("pushfl ; " + asm volatile("pushfl ; " "pushfl ; " "popl %0 ; " "movl %0,%1 ; " @@ -125,7 +125,7 @@ static void get_flags(void) set_bit(X86_FEATURE_FPU, cpu.flags); if (has_eflag(X86_EFLAGS_ID)) { - asm("cpuid" + asm volatile("cpuid" : "=a" (max_intel_level), "=b" (cpu_vendor[0]), "=d" (cpu_vendor[1]), @@ -134,7 +134,7 @@ static void get_flags(void) if (max_intel_level >= 0x00000001 && max_intel_level <= 0x0000ffff) { - asm("cpuid" + asm volatile("cpuid" : "=a" (tfms), "=c" (cpu.flags[4]), "=d" (cpu.flags[0]) @@ -146,7 +146,7 @@ static void get_flags(void) cpu.model += ((tfms >> 16) & 0xf) << 4; } - asm("cpuid" + asm volatile("cpuid" : "=a" (max_amd_level) : "a" (0x80000000) : "ebx", "ecx", "edx"); @@ -154,7 +154,7 @@ static void get_flags(void) if (max_amd_level >= 0x80000001 && max_amd_level <= 0x8000ffff) { u32 eax = 0x80000001; - asm("cpuid" + asm volatile("cpuid" : "+a" (eax), "=c" (cpu.flags[6]), "=d" (cpu.flags[1]) @@ -213,9 +213,9 @@ int check_cpu(int *cpu_level_ptr, int *r u32 ecx = MSR_K7_HWCR; u32 eax, edx; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); eax &= ~(1 << 15); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); get_flags(); /* Make sure it really did something */ err = check_flags(); @@ -228,9 +228,9 @@ int check_cpu(int *cpu_level_ptr, int *r u32 ecx = MSR_VIA_FCR; u32 eax, edx; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); eax |= (1<<1)|(1<<7); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); set_bit(X86_FEATURE_CX8, cpu.flags); err = check_flags(); @@ -241,12 +241,12 @@ int check_cpu(int *cpu_level_ptr, int *r u32 eax, edx; u32 level = 1; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); - asm("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx)); - asm("cpuid" + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx)); + asm volatile("cpuid" : "+a" (level), "=d" (cpu.flags[0]) : : "ecx", "ebx"); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); err = check_flags(); } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/edd.c linux-2.6.24.7-pax/arch/x86/boot/edd.c --- linux-2.6.24.7/arch/x86/boot/edd.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/edd.c 2008-02-29 18:07:50.000000000 +0100 @@ -78,7 +78,7 @@ static int get_edd_info(u8 devno, struct ax = 0x4100; bx = EDDMAGIC1; dx = devno; - asm("pushfl; stc; int $0x13; setc %%al; popfl" + asm volatile("pushfl; stc; int $0x13; setc %%al; popfl" : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx) : : "esi", "edi"); @@ -97,7 +97,7 @@ static int get_edd_info(u8 devno, struct ei->params.length = sizeof(ei->params); ax = 0x4800; dx = devno; - asm("pushfl; int $0x13; popfl" + asm volatile("pushfl; int $0x13; popfl" : "+a" (ax), "+d" (dx), "=m" (ei->params) : "S" (&ei->params) : "ebx", "ecx", "edi"); @@ -108,7 +108,7 @@ static int get_edd_info(u8 devno, struct ax = 0x0800; dx = devno; di = 0; - asm("pushw %%es; " + asm volatile("pushw %%es; " "movw %%di,%%es; " "pushfl; stc; int $0x13; setc %%al; popfl; " "popw %%es" diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/main.c linux-2.6.24.7-pax/arch/x86/boot/main.c --- linux-2.6.24.7/arch/x86/boot/main.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/main.c 2008-02-29 18:07:50.000000000 +0100 @@ -75,7 +75,7 @@ static void keyboard_set_repeat(void) */ static void query_ist(void) { - asm("int $0x15" + asm volatile("int $0x15" : "=a" (boot_params.ist_info.signature), "=b" (boot_params.ist_info.command), "=c" (boot_params.ist_info.event), diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/mca.c linux-2.6.24.7-pax/arch/x86/boot/mca.c --- linux-2.6.24.7/arch/x86/boot/mca.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/mca.c 2008-02-29 18:07:50.000000000 +0100 @@ -21,7 +21,7 @@ int query_mca(void) u8 err; u16 es, bx, len; - asm("pushw %%es ; " + asm volatile("pushw %%es ; " "int $0x15 ; " "setc %0 ; " "movw %%es, %1 ; " diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/memory.c linux-2.6.24.7-pax/arch/x86/boot/memory.c --- linux-2.6.24.7/arch/x86/boot/memory.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/memory.c 2008-02-29 18:07:50.000000000 +0100 @@ -32,7 +32,7 @@ static int detect_memory_e820(void) /* Important: %edx is clobbered by some BIOSes, so it must be either used for the error output or explicitly marked clobbered. */ - asm("int $0x15; setc %0" + asm volatile("int $0x15; setc %0" : "=d" (err), "+b" (next), "=a" (id), "+c" (size), "=m" (*desc) : "D" (desc), "d" (SMAP), "a" (0xe820)); @@ -64,7 +64,7 @@ static int detect_memory_e801(void) bx = cx = dx = 0; ax = 0xe801; - asm("stc; int $0x15; setc %0" + asm volatile("stc; int $0x15; setc %0" : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx)); if (err) @@ -94,7 +94,7 @@ static int detect_memory_88(void) u8 err; ax = 0x8800; - asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); + asm volatile("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); boot_params.screen_info.ext_mem_k = ax; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/video-vesa.c linux-2.6.24.7-pax/arch/x86/boot/video-vesa.c --- linux-2.6.24.7/arch/x86/boot/video-vesa.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/video-vesa.c 2008-02-29 18:07:50.000000000 +0100 @@ -41,7 +41,7 @@ static int vesa_probe(void) ax = 0x4f00; di = (size_t)&vginfo; - asm(INT10 + asm volatile(INT10 : "+a" (ax), "+D" (di), "=m" (vginfo) : : "ebx", "ecx", "edx", "esi"); @@ -68,7 +68,7 @@ static int vesa_probe(void) ax = 0x4f01; cx = mode; di = (size_t)&vminfo; - asm(INT10 + asm volatile(INT10 : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo) : : "ebx", "edx", "esi"); @@ -115,7 +115,7 @@ static int vesa_set_mode(struct mode_inf ax = 0x4f01; cx = vesa_mode; di = (size_t)&vminfo; - asm(INT10 + asm volatile(INT10 : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo) : : "ebx", "edx", "esi"); @@ -193,19 +193,20 @@ static void vesa_dac_set_8bits(void) /* Save the VESA protected mode info */ static void vesa_store_pm_info(void) { - u16 ax, bx, di, es; + u16 ax, bx, cx, di, es; ax = 0x4f0a; - bx = di = 0; - asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es" - : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di) - : : "ecx", "esi"); + bx = cx = di = 0; + asm volatile("pushw %%es; "INT10"; movw %%es,%0; popw %%es" + : "=d" (es), "+a" (ax), "+b" (bx), "+c" (cx), "+D" (di) + : : "esi"); if (ax != 0x004f) return; boot_params.screen_info.vesapm_seg = es; boot_params.screen_info.vesapm_off = di; + boot_params.screen_info.vesapm_size = cx; } /* @@ -259,7 +260,7 @@ void vesa_store_edid(void) /* Note: The VBE DDC spec is different from the main VESA spec; we genuinely have to assume all registers are destroyed here. */ - asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es" + asm volatile("pushw %%es; movw %2,%%es; "INT10"; popw %%es" : "+a" (ax), "+b" (bx) : "c" (cx), "D" (di) : "esi"); @@ -275,7 +276,7 @@ void vesa_store_edid(void) cx = 0; /* Controller 0 */ dx = 0; /* EDID block number */ di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */ - asm(INT10 + asm volatile(INT10 : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info) : "c" (cx), "D" (di) : "esi"); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/video-vga.c linux-2.6.24.7-pax/arch/x86/boot/video-vga.c --- linux-2.6.24.7/arch/x86/boot/video-vga.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/video-vga.c 2008-02-29 18:07:50.000000000 +0100 @@ -225,7 +225,7 @@ static int vga_probe(void) }; u8 vga_flag; - asm(INT10 + asm volatile(INT10 : "=b" (boot_params.screen_info.orig_video_ega_bx) : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ : "ecx", "edx", "esi", "edi"); @@ -233,7 +233,7 @@ static int vga_probe(void) /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ if ((u8)boot_params.screen_info.orig_video_ega_bx != 0x10) { /* EGA/VGA */ - asm(INT10 + asm volatile(INT10 : "=a" (vga_flag) : "a" (0x1a00) : "ebx", "ecx", "edx", "esi", "edi"); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/video.c linux-2.6.24.7-pax/arch/x86/boot/video.c --- linux-2.6.24.7/arch/x86/boot/video.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/video.c 2008-02-29 18:07:50.000000000 +0100 @@ -40,7 +40,7 @@ static void store_cursor_position(void) ax = 0x0300; bx = 0; - asm(INT10 + asm volatile(INT10 : "=d" (curpos), "+a" (ax), "+b" (bx) : : "ecx", "esi", "edi"); @@ -55,7 +55,7 @@ static void store_video_mode(void) /* N.B.: the saving of the video page here is a bit silly, since we pretty much assume page 0 everywhere. */ ax = 0x0f00; - asm(INT10 + asm volatile(INT10 : "+a" (ax), "=b" (page) : : "ecx", "edx", "esi", "edi"); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/boot/voyager.c linux-2.6.24.7-pax/arch/x86/boot/voyager.c --- linux-2.6.24.7/arch/x86/boot/voyager.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/boot/voyager.c 2008-02-29 18:07:50.000000000 +0100 @@ -27,7 +27,7 @@ int query_voyager(void) data_ptr[0] = 0xff; /* Flag on config not found(?) */ - asm("pushw %%es ; " + asm volatile("pushw %%es ; " "int $0x15 ; " "setc %0 ; " "movw %%es, %1 ; " diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/ia32/ia32_binfmt.c linux-2.6.24.7-pax/arch/x86/ia32/ia32_binfmt.c --- linux-2.6.24.7/arch/x86/ia32/ia32_binfmt.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/ia32/ia32_binfmt.c 2008-02-29 18:07:50.000000000 +0100 @@ -47,12 +47,12 @@ #define AT_SYSINFO 32 #define AT_SYSINFO_EHDR 33 -int sysctl_vsyscall32 = 1; +int sysctl_vsyscall32; #undef ARCH_DLINFO #define ARCH_DLINFO do { \ if (sysctl_vsyscall32) { \ - current->mm->context.vdso = (void *)VSYSCALL32_BASE; \ + current->mm->context.vdso = VSYSCALL32_BASE; \ NEW_AUX_ENT(AT_SYSINFO, (u32)(u64)VSYSCALL32_VSYSCALL); \ NEW_AUX_ENT(AT_SYSINFO_EHDR, VSYSCALL32_BASE); \ } \ @@ -66,6 +66,17 @@ struct file; #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000) +#ifdef CONFIG_PAX_ASLR +#undef PAX_ELF_ET_DYN_BASE +#undef PAX_DELTA_MMAP_LEN +#undef PAX_DELTA_STACK_LEN + +#define PAX_ELF_ET_DYN_BASE 0x08048000UL + +#define PAX_DELTA_MMAP_LEN 16 +#define PAX_DELTA_STACK_LEN 16 +#endif + #define jiffies_to_timeval(a,b) do { (b)->tv_usec = 0; (b)->tv_sec = (a)/HZ; }while(0) #define _GET_SEG(x) \ @@ -263,7 +274,7 @@ static ctl_table abi_table2[] = { .mode = 0644, .proc_handler = proc_dointvec }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static ctl_table abi_root_table2[] = { @@ -273,7 +284,7 @@ static ctl_table abi_root_table2[] = { .mode = 0555, .child = abi_table2 }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static __init int ia32_binfmt_init(void) diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/ia32/ia32_signal.c linux-2.6.24.7-pax/arch/x86/ia32/ia32_signal.c --- linux-2.6.24.7/arch/x86/ia32/ia32_signal.c 2008-03-25 14:04:20.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/ia32/ia32_signal.c 2008-03-25 14:04:56.000000000 +0100 @@ -573,6 +573,7 @@ int ia32_setup_rt_frame(int sig, struct __NR_ia32_rt_sigreturn, 0x80cd, 0, + 0 }; err |= __copy_to_user(frame->retcode, &code, 8); } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/ia32/mmap32.c linux-2.6.24.7-pax/arch/x86/ia32/mmap32.c --- linux-2.6.24.7/arch/x86/ia32/mmap32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/ia32/mmap32.c 2008-02-29 18:07:50.000000000 +0100 @@ -69,10 +69,22 @@ void ia32_pick_mmap_layout(struct mm_str (current->personality & ADDR_COMPAT_LAYOUT) || current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY) { mm->mmap_base = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; mm->unmap_area = arch_unmap_area; } else { mm->mmap_base = mmap_base(mm); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/ia32/ptrace32.c linux-2.6.24.7-pax/arch/x86/ia32/ptrace32.c --- linux-2.6.24.7/arch/x86/ia32/ptrace32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/ia32/ptrace32.c 2008-02-29 18:07:50.000000000 +0100 @@ -382,7 +382,7 @@ asmlinkage long sys32_ptrace(long reques /* no checking to be bug-to-bug compatible with i386. */ /* but silence warning */ if (__copy_from_user(&child->thread.i387.fxsave, u, sizeof(*u))) - ; + {} set_stopped_child_used_math(child); child->thread.i387.fxsave.mxcsr &= mxcsr_feature_mask; ret = 0; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/ia32/syscall32.c linux-2.6.24.7-pax/arch/x86/ia32/syscall32.c --- linux-2.6.24.7/arch/x86/ia32/syscall32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/ia32/syscall32.c 2008-02-29 18:07:50.000000000 +0100 @@ -30,6 +30,9 @@ int syscall32_setup_pages(struct linux_b struct mm_struct *mm = current->mm; int ret; + if (!sysctl_vsyscall32) + return 0; + down_write(&mm->mmap_sem); /* * MAYWRITE to allow gdb to COW and set breakpoints diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/Makefile_64 linux-2.6.24.7-pax/arch/x86/kernel/Makefile_64 --- linux-2.6.24.7/arch/x86/kernel/Makefile_64 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/Makefile_64 2008-02-29 18:07:50.000000000 +0100 @@ -42,4 +42,6 @@ obj-$(CONFIG_PCI) += early-quirks.o obj-y += topology.o obj-y += pcspeaker.o -CFLAGS_vsyscall_64.o := $(PROFILING) -g0 +CFLAGS_vsyscall_64.o := $(PROFILING) -g0 -fno-stack-protector +CFLAGS_hpet.o := -fno-stack-protector +CFLAGS_tsc_64.o := -fno-stack-protector diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/acpi/boot.c linux-2.6.24.7-pax/arch/x86/kernel/acpi/boot.c --- linux-2.6.24.7/arch/x86/kernel/acpi/boot.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/acpi/boot.c 2008-02-29 18:07:50.000000000 +0100 @@ -1155,7 +1155,7 @@ static struct dmi_system_id __initdata a DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), }, }, - {} + { NULL, NULL, {{0, NULL}}, NULL} }; #endif /* __i386__ */ diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/acpi/sleep_32.c linux-2.6.24.7-pax/arch/x86/kernel/acpi/sleep_32.c --- linux-2.6.24.7/arch/x86/kernel/acpi/sleep_32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/acpi/sleep_32.c 2008-02-29 18:07:50.000000000 +0100 @@ -98,7 +98,7 @@ static __initdata struct dmi_system_id a DMI_MATCH(DMI_PRODUCT_NAME, "S4030CDT/4.3"), }, }, - {} + { NULL, NULL, {{0, NULL}}, NULL} }; static int __init acpisleep_dmi_init(void) diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/acpi/wakeup_32.S linux-2.6.24.7-pax/arch/x86/kernel/acpi/wakeup_32.S --- linux-2.6.24.7/arch/x86/kernel/acpi/wakeup_32.S 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/acpi/wakeup_32.S 2008-02-29 18:07:50.000000000 +0100 @@ -2,6 +2,7 @@ #include #include #include +#include # # wakeup_code runs in real mode, and at unknown address (determined at run-time). @@ -79,7 +80,7 @@ wakeup_code: # restore efer setting movl real_save_efer_edx - wakeup_code, %edx movl real_save_efer_eax - wakeup_code, %eax - mov $0xc0000080, %ecx + mov $MSR_EFER, %ecx wrmsr 4: # make sure %cr4 is set correctly (features, etc) @@ -196,13 +197,11 @@ wakeup_pmode_return: # and restore the stack ... but you need gdt for this to work movl saved_context_esp, %esp - movl %cs:saved_magic, %eax - cmpl $0x12345678, %eax + cmpl $0x12345678, saved_magic jne bogus_magic # jump to place where we left off - movl saved_eip,%eax - jmp *%eax + jmp *(saved_eip) bogus_magic: jmp bogus_magic @@ -233,7 +232,7 @@ ENTRY(acpi_copy_wakeup_routine) # save efer setting pushl %eax movl %eax, %ebx - mov $0xc0000080, %ecx + mov $MSR_EFER, %ecx rdmsr movl %edx, real_save_efer_edx - wakeup_start (%ebx) movl %eax, real_save_efer_eax - wakeup_start (%ebx) diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/alternative.c linux-2.6.24.7-pax/arch/x86/kernel/alternative.c --- linux-2.6.24.7/arch/x86/kernel/alternative.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/alternative.c 2008-03-08 00:42:20.000000000 +0100 @@ -389,7 +389,7 @@ void apply_paravirt(struct paravirt_patc BUG_ON(p->len > MAX_PATCH_LEN); /* prep the buffer with the original instructions */ - memcpy(insnbuf, p->instr, p->len); + memcpy(insnbuf, ktla_ktva(p->instr), p->len); used = pv_init_ops.patch(p->instrtype, p->clobbers, insnbuf, (unsigned long)p->instr, p->len); @@ -467,7 +467,19 @@ void __init alternative_instructions(voi */ void __kprobes text_poke(void *addr, unsigned char *opcode, int len) { - memcpy(addr, opcode, len); + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + + memcpy(ktla_ktva(addr), opcode, len); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + sync_core(); /* Could also do a CLFLUSH here to speed up CPU recovery; but that causes hangs on some VIA CPUs. */ diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/apm_32.c linux-2.6.24.7-pax/arch/x86/kernel/apm_32.c --- linux-2.6.24.7/arch/x86/kernel/apm_32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/apm_32.c 2008-02-29 18:07:50.000000000 +0100 @@ -407,7 +407,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitq static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user * user_list; static DEFINE_SPINLOCK(user_list_lock); -static const struct desc_struct bad_bios_desc = { 0, 0x00409200 }; +static const struct desc_struct bad_bios_desc = { 0, 0x00409300 }; static const char driver_version[] = "1.16ac"; /* no spaces */ @@ -601,19 +601,42 @@ static u8 apm_bios_call(u32 func, u32 eb struct desc_struct save_desc_40; struct desc_struct *gdt; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + cpus = apm_save_cpus(); cpu = get_cpu(); gdt = get_cpu_gdt_table(cpu); save_desc_40 = gdt[0x40 / 8]; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt[0x40 / 8] = bad_bios_desc; +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + apm_irq_save(flags); APM_DO_SAVE_SEGS; apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi); APM_DO_RESTORE_SEGS; apm_irq_restore(flags); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt[0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + put_cpu(); apm_restore_cpus(cpus); @@ -644,19 +667,42 @@ static u8 apm_bios_call_simple(u32 func, struct desc_struct save_desc_40; struct desc_struct *gdt; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + cpus = apm_save_cpus(); cpu = get_cpu(); gdt = get_cpu_gdt_table(cpu); save_desc_40 = gdt[0x40 / 8]; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt[0x40 / 8] = bad_bios_desc; +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + apm_irq_save(flags); APM_DO_SAVE_SEGS; error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax); APM_DO_RESTORE_SEGS; apm_irq_restore(flags); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt[0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + put_cpu(); apm_restore_cpus(cpus); return error; @@ -924,7 +970,7 @@ recalc: static void apm_power_off(void) { - unsigned char po_bios_call[] = { + const unsigned char po_bios_call[] = { 0xb8, 0x00, 0x10, /* movw $0x1000,ax */ 0x8e, 0xd0, /* movw ax,ss */ 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */ @@ -1864,7 +1910,10 @@ static const struct file_operations apm_ static struct miscdevice apm_device = { APM_MINOR_DEV, "apm_bios", - &apm_bios_fops + &apm_bios_fops, + {NULL, NULL}, + NULL, + NULL }; @@ -2177,7 +2226,7 @@ static struct dmi_system_id __initdata a { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL} }; /* @@ -2196,6 +2245,10 @@ static int __init apm_init(void) struct desc_struct *gdt; int err; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + dmi_check_system(apm_dmi_table); if (apm_info.bios.version == 0 || paravirt_enabled()) { @@ -2269,9 +2322,18 @@ static int __init apm_init(void) * This is for buggy BIOS's that refer to (real mode) segment 0x40 * even though they are called in protected mode. */ + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* * Set up the long jump entry point to the APM BIOS, which is called * from inline assembly. @@ -2290,6 +2352,11 @@ static int __init apm_init(void) * code to that CPU. */ gdt = get_cpu_gdt_table(0); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + set_base(gdt[APM_CS >> 3], __va((unsigned long)apm_info.bios.cseg << 4)); set_base(gdt[APM_CS_16 >> 3], @@ -2297,6 +2364,10 @@ static int __init apm_init(void) set_base(gdt[APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + apm_proc = create_proc_entry("apm", 0, NULL); if (apm_proc) apm_proc->proc_fops = &apm_file_ops; diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/asm-offsets_32.c linux-2.6.24.7-pax/arch/x86/kernel/asm-offsets_32.c --- linux-2.6.24.7/arch/x86/kernel/asm-offsets_32.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/asm-offsets_32.c 2008-02-29 18:07:50.000000000 +0100 @@ -110,6 +110,7 @@ void foo(void) DEFINE(PTRS_PER_PTE, PTRS_PER_PTE); DEFINE(PTRS_PER_PMD, PTRS_PER_PMD); DEFINE(PTRS_PER_PGD, PTRS_PER_PGD); + DEFINE(PERCPU_MODULE_RESERVE, PERCPU_MODULE_RESERVE); DEFINE(VDSO_PRELINK_asm, VDSO_PRELINK); @@ -125,6 +126,7 @@ void foo(void) OFFSET(PV_CPU_iret, pv_cpu_ops, iret); OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit); OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0); + OFFSET(PV_CPU_write_cr0, pv_cpu_ops, write_cr0); #endif #ifdef CONFIG_XEN diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/asm-offsets_64.c linux-2.6.24.7-pax/arch/x86/kernel/asm-offsets_64.c --- linux-2.6.24.7/arch/x86/kernel/asm-offsets_64.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/asm-offsets_64.c 2008-02-29 18:07:50.000000000 +0100 @@ -108,6 +108,7 @@ int main(void) ENTRY(cr8); BLANK(); #undef ENTRY + DEFINE(TSS_size, sizeof(struct tss_struct)); DEFINE(TSS_ist, offsetof(struct tss_struct, ist)); BLANK(); DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); diff -NurpX linux-2.6.24.7-pax/Documentation/dontdiff linux-2.6.24.7/arch/x86/kernel/cpu/common.c linux-2.6.24.7-pax/arch/x86/kernel/cpu/common.c --- linux-2.6.24.7/arch/x86/kernel/cpu/common.c 2008-01-24 23:58:37.000000000 +0100 +++ linux-2.6.24.7-pax/arch/x86/kernel/cpu/common.c 2008-02-29 18:07:50.000000000 +0100 @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -21,39 +20,15 @@ #include "cpu.h" -DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { - [GDT_ENTRY_KERNEL_CS] = { 0x0000ffff, 0x00cf9a00 }, - [GDT_ENTRY_KERNEL_DS] = { 0x0000ffff, 0x00cf9200 }, - [GDT_ENTRY_DEFAULT_USER_CS] = { 0x0000ffff, 0x00cffa00 }, - [GDT_ENTRY_DEFAULT_USER_DS] = { 0x0000ffff, 0x00cff200 }, - /* - * Segments used for calling PnP BIOS have byte granularity. - * They code segments and data segments have fixed 64k limits, - * the transfer segment sizes are set at run time. - */ - [GDT_ENTRY_PNPBIOS_CS32] = { 0x0000ffff, 0x00409a00 },/* 32-bit code */ - [GDT_ENTRY_PNPBIOS_CS16] = { 0x0000ffff, 0x00009a00 },/* 16-bit code */ - [GDT_ENTRY_PNPBIOS_DS] = { 0x0000ffff, 0x00009200 }, /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS1] = { 0x00000000, 0x00009200 },/* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS2] = { 0x00000000, 0x00009200 },/* 16-bit data */ - /* -