diff -NurpP --minimal linux-2.6.17.11/Makefile linux-2.6.17.11-g-v/Makefile --- linux-2.6.17.11/Makefile 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/Makefile 2006-08-28 16:11:59.000000000 +0200 @@ -518,7 +518,7 @@ export MODLIB ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ +core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ grsecurity/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ diff -NurpP --minimal linux-2.6.17.11/arch/alpha/Kconfig linux-2.6.17.11-g-v/arch/alpha/Kconfig --- linux-2.6.17.11/arch/alpha/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/alpha/Kconfig 2006-08-28 14:56:33.000000000 +0200 @@ -632,6 +632,8 @@ source "arch/alpha/oprofile/Kconfig" source "arch/alpha/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/alpha/kernel/entry.S linux-2.6.17.11-g-v/arch/alpha/kernel/entry.S --- linux-2.6.17.11/arch/alpha/kernel/entry.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/alpha/kernel/entry.S 2006-08-28 14:56:33.000000000 +0200 @@ -874,24 +874,15 @@ sys_getxgid: .globl sys_getxpid .ent sys_getxpid sys_getxpid: + lda $sp, -16($sp) + stq $26, 0($sp) .prologue 0 - ldq $2, TI_TASK($8) - /* See linux/kernel/timer.c sys_getppid for discussion - about this loop. */ - ldq $3, TASK_GROUP_LEADER($2) - ldq $4, TASK_REAL_PARENT($3) - ldl $0, TASK_TGID($2) -1: ldl $1, TASK_TGID($4) -#ifdef CONFIG_SMP - mov $4, $5 - mb - ldq $3, TASK_GROUP_LEADER($2) - ldq $4, TASK_REAL_PARENT($3) - cmpeq $4, $5, $5 - beq $5, 1b -#endif - stq $1, 80($sp) + lda $16, 96($sp) + jsr $26, do_getxpid + ldq $26, 0($sp) + + lda $sp, 16($sp) ret .end sys_getxpid diff -NurpP --minimal linux-2.6.17.11/arch/alpha/kernel/module.c linux-2.6.17.11-g-v/arch/alpha/kernel/module.c --- linux-2.6.17.11/arch/alpha/kernel/module.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/alpha/kernel/module.c 2006-08-28 14:44:48.000000000 +0200 @@ -177,7 +177,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 -NurpP --minimal linux-2.6.17.11/arch/alpha/kernel/osf_sys.c linux-2.6.17.11-g-v/arch/alpha/kernel/osf_sys.c --- linux-2.6.17.11/arch/alpha/kernel/osf_sys.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/alpha/kernel/osf_sys.c 2006-08-28 14:56:33.000000000 +0200 @@ -38,6 +38,7 @@ #include #include #include +#include #include #include @@ -399,18 +400,20 @@ asmlinkage int osf_utsname(char __user *name) { int error; + struct new_utsname *ptr; down_read(&uts_sem); + ptr = vx_new_utsname(); error = -EFAULT; - if (copy_to_user(name + 0, system_utsname.sysname, 32)) + if (copy_to_user(name + 0, ptr->sysname, 32)) goto out; - if (copy_to_user(name + 32, system_utsname.nodename, 32)) + if (copy_to_user(name + 32, ptr->nodename, 32)) goto out; - if (copy_to_user(name + 64, system_utsname.release, 32)) + if (copy_to_user(name + 64, ptr->release, 32)) goto out; - if (copy_to_user(name + 96, system_utsname.version, 32)) + if (copy_to_user(name + 96, ptr->version, 32)) goto out; - if (copy_to_user(name + 128, system_utsname.machine, 32)) + if (copy_to_user(name + 128, ptr->machine, 32)) goto out; error = 0; @@ -439,6 +442,7 @@ osf_getdomainname(char __user *name, int { unsigned len; int i; + char *domainname; if (!access_ok(VERIFY_WRITE, name, namelen)) return -EFAULT; @@ -448,9 +452,10 @@ osf_getdomainname(char __user *name, int len = 32; down_read(&uts_sem); + domainname = vx_new_uts(domainname); for (i = 0; i < len; ++i) { - __put_user(system_utsname.domainname[i], name + i); - if (system_utsname.domainname[i] == '\0') + __put_user(domainname[i], name + i); + if (domainname[i] == '\0') break; } up_read(&uts_sem); @@ -607,30 +612,30 @@ osf_sigstack(struct sigstack __user *uss asmlinkage long osf_sysinfo(int command, char __user *buf, long count) { - static char * sysinfo_table[] = { - system_utsname.sysname, - system_utsname.nodename, - system_utsname.release, - system_utsname.version, - system_utsname.machine, - "alpha", /* instruction set architecture */ - "dummy", /* hardware serial number */ - "dummy", /* hardware manufacturer */ - "dummy", /* secure RPC domain */ - }; unsigned long offset; char *res; long len, err = -EINVAL; offset = command-1; - if (offset >= sizeof(sysinfo_table)/sizeof(char *)) { + if (offset >= 9) { /* Digital UNIX has a few unpublished interfaces here */ printk("sysinfo(%d)", command); goto out; } down_read(&uts_sem); - res = sysinfo_table[offset]; + switch (offset) + { + case 0: res = vx_new_uts(sysname); break; + case 1: res = vx_new_uts(nodename); break; + case 2: res = vx_new_uts(release); break; + case 3: res = vx_new_uts(version); break; + case 4: res = vx_new_uts(machine); break; + case 5: res = "alpha"; break; + default: + res = "dummy"; + break; + } len = strlen(res)+1; if (len > count) len = count; @@ -1273,6 +1278,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) @@ -1280,8 +1289,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 -NurpP --minimal linux-2.6.17.11/arch/alpha/kernel/ptrace.c linux-2.6.17.11-g-v/arch/alpha/kernel/ptrace.c --- linux-2.6.17.11/arch/alpha/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/alpha/kernel/ptrace.c 2006-08-28 14:56:33.000000000 +0200 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -283,6 +284,14 @@ do_sys_ptrace(long request, long pid, lo goto out_notsk; } + if (gr_handle_ptrace(child, request)) + goto out; + + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { + ret = -EPERM; + goto out; + } + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out; diff -NurpP --minimal linux-2.6.17.11/arch/alpha/kernel/systbls.S linux-2.6.17.11-g-v/arch/alpha/kernel/systbls.S --- linux-2.6.17.11/arch/alpha/kernel/systbls.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/alpha/kernel/systbls.S 2006-08-28 14:56:33.000000000 +0200 @@ -447,7 +447,7 @@ sys_call_table: .quad sys_stat64 /* 425 */ .quad sys_lstat64 .quad sys_fstat64 - .quad sys_ni_syscall /* sys_vserver */ + .quad sys_vserver /* sys_vserver */ .quad sys_ni_syscall /* sys_mbind */ .quad sys_ni_syscall /* sys_get_mempolicy */ .quad sys_ni_syscall /* sys_set_mempolicy */ diff -NurpP --minimal linux-2.6.17.11/arch/alpha/mm/fault.c linux-2.6.17.11-g-v/arch/alpha/mm/fault.c --- linux-2.6.17.11/arch/alpha/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/alpha/mm/fault.c 2006-08-28 14:44:48.000000000 +0200 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -56,6 +57,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, @@ -133,8 +252,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_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 -NurpP --minimal linux-2.6.17.11/arch/alpha/mm/init.c linux-2.6.17.11-g-v/arch/alpha/mm/init.c --- linux-2.6.17.11/arch/alpha/mm/init.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/alpha/mm/init.c 2006-08-28 14:56:33.000000000 +0200 @@ -21,6 +21,7 @@ #include #include /* max_low_pfn */ #include +#include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/arm/Kconfig linux-2.6.17.11-g-v/arch/arm/Kconfig --- linux-2.6.17.11/arch/arm/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/arm/Kconfig 2006-08-28 14:56:33.000000000 +0200 @@ -873,6 +873,8 @@ source "arch/arm/oprofile/Kconfig" source "arch/arm/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/arm/kernel/calls.S linux-2.6.17.11-g-v/arch/arm/kernel/calls.S --- linux-2.6.17.11/arch/arm/kernel/calls.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/arm/kernel/calls.S 2006-08-28 14:56:33.000000000 +0200 @@ -322,7 +322,7 @@ /* 310 */ CALL(sys_request_key) CALL(sys_keyctl) CALL(ABI(sys_semtimedop, sys_oabi_semtimedop)) -/* vserver */ CALL(sys_ni_syscall) + CALL(sys_vserver) CALL(sys_ioprio_set) /* 315 */ CALL(sys_ioprio_get) CALL(sys_inotify_init) diff -NurpP --minimal linux-2.6.17.11/arch/arm/mm/mmap.c linux-2.6.17.11-g-v/arch/arm/mm/mmap.c --- linux-2.6.17.11/arch/arm/mm/mmap.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/arm/mm/mmap.c 2006-08-28 14:44:48.000000000 +0200 @@ -62,6 +62,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); @@ -76,7 +80,7 @@ arch_get_unmapped_area(struct file *filp if (len > mm->cached_hole_size) { 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; } @@ -93,8 +97,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 -NurpP --minimal linux-2.6.17.11/arch/arm26/Kconfig linux-2.6.17.11-g-v/arch/arm26/Kconfig --- linux-2.6.17.11/arch/arm26/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/arm26/Kconfig 2006-08-28 14:56:33.000000000 +0200 @@ -234,6 +234,8 @@ source "drivers/usb/Kconfig" source "arch/arm26/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/arm26/kernel/calls.S linux-2.6.17.11-g-v/arch/arm26/kernel/calls.S --- linux-2.6.17.11/arch/arm26/kernel/calls.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/arm26/kernel/calls.S 2006-08-28 14:56:33.000000000 +0200 @@ -257,6 +257,11 @@ __syscall_start: .long sys_lremovexattr .long sys_fremovexattr .long sys_tkill + + .rept 313 - (. - __syscall_start) / 4 + .long sys_ni_syscall + .endr + .long sys_vserver /* 313 */ __syscall_end: .rept NR_syscalls - (__syscall_end - __syscall_start) / 4 diff -NurpP --minimal linux-2.6.17.11/arch/arm26/kernel/traps.c linux-2.6.17.11-g-v/arch/arm26/kernel/traps.c --- linux-2.6.17.11/arch/arm26/kernel/traps.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/arm26/kernel/traps.c 2006-08-28 14:56:33.000000000 +0200 @@ -186,8 +186,9 @@ NORET_TYPE void die(const char *str, str printk("Internal error: %s: %x\n", str, err); printk("CPU: %d\n", smp_processor_id()); show_regs(regs); - printk("Process %s (pid: %d, stack limit = 0x%p)\n", - current->comm, current->pid, end_of_stack(tsk)); + printk("Process %s (pid: %d[#%u], stack limit = 0x%p)\n", + current->comm, current->pid, + current->xid, end_of_stack(tsk)); if (!user_mode(regs) || in_interrupt()) { __dump_stack(tsk, (unsigned long)(regs + 1)); diff -NurpP --minimal linux-2.6.17.11/arch/cris/Kconfig linux-2.6.17.11-g-v/arch/cris/Kconfig --- linux-2.6.17.11/arch/cris/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/cris/Kconfig 2006-08-28 14:56:33.000000000 +0200 @@ -181,6 +181,8 @@ source "drivers/usb/Kconfig" source "arch/cris/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/frv/mm/mmu-context.c linux-2.6.17.11-g-v/arch/frv/mm/mmu-context.c --- linux-2.6.17.11/arch/frv/mm/mmu-context.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/frv/mm/mmu-context.c 2006-08-28 14:56:33.000000000 +0200 @@ -11,6 +11,7 @@ #include #include +#include #include #define NR_CXN 4096 diff -NurpP --minimal linux-2.6.17.11/arch/h8300/Kconfig linux-2.6.17.11-g-v/arch/h8300/Kconfig --- linux-2.6.17.11/arch/h8300/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/h8300/Kconfig 2006-08-28 14:56:33.000000000 +0200 @@ -199,6 +199,8 @@ source "fs/Kconfig" source "arch/h8300/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/i386/Kconfig linux-2.6.17.11-g-v/arch/i386/Kconfig --- linux-2.6.17.11/arch/i386/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/Kconfig 2006-08-28 14:56:33.000000000 +0200 @@ -948,7 +948,7 @@ config PCI choice prompt "PCI access mode" depends on 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 @@ -980,7 +980,7 @@ endchoice config PCI_BIOS bool - depends on !X86_VISWS && PCI && (PCI_GOBIOS || PCI_GOANY) + depends on !X86_VISWS && PCI && PCI_GOBIOS default y config PCI_DIRECT @@ -1088,6 +1088,8 @@ endmenu source "arch/i386/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/i386/Kconfig.cpu linux-2.6.17.11-g-v/arch/i386/Kconfig.cpu --- linux-2.6.17.11/arch/i386/Kconfig.cpu 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/Kconfig.cpu 2006-08-28 14:44:48.000000000 +0200 @@ -251,7 +251,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 @@ -281,7 +281,7 @@ config X86_CMPXCHG64 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 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 default y config X86_GOOD_APIC diff -NurpP --minimal linux-2.6.17.11/arch/i386/Kconfig.debug linux-2.6.17.11-g-v/arch/i386/Kconfig.debug --- linux-2.6.17.11/arch/i386/Kconfig.debug 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/Kconfig.debug 2006-08-28 14:44:48.000000000 +0200 @@ -53,7 +53,7 @@ config DEBUG_PAGEALLOC config DEBUG_RODATA bool "Write protect kernel read-only data structures" - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && 0 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 -NurpP --minimal linux-2.6.17.11/arch/i386/boot/compressed/head.S linux-2.6.17.11-g-v/arch/i386/boot/compressed/head.S --- linux-2.6.17.11/arch/i386/boot/compressed/head.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/boot/compressed/head.S 2006-08-28 14:44:48.000000000 +0200 @@ -39,11 +39,13 @@ startup_32: movl %eax,%gs lss stack_start,%esp + movl 0x000000,%ecx xorl %eax,%eax 1: incl %eax # check that A20 really IS enabled movl %eax,0x000000 # loop forever if it isn't cmpl %eax,0x100000 je 1b + movl %ecx,0x000000 /* * Initialize eflags. Some BIOS's leave bits like NT set. This would diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/acpi/sleep.c linux-2.6.17.11-g-v/arch/i386/kernel/acpi/sleep.c --- linux-2.6.17.11/arch/i386/kernel/acpi/sleep.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/acpi/sleep.c 2006-08-28 14:44:48.000000000 +0200 @@ -10,6 +10,7 @@ #include #include #include +#include /* address in low memory of the wakeup routine. */ unsigned long acpi_wakeup_address = 0; @@ -24,11 +25,22 @@ static void init_low_mapping(pgd_t * pgd { int pgd_ofs = 0; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + while ((pgd_ofs < pgd_limit) && (pgd_ofs + USER_PTRS_PER_PGD < PTRS_PER_PGD)) { set_pgd(pgd, *(pgd + USER_PTRS_PER_PGD)); pgd_ofs++, pgd++; } + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + flush_tlb_all(); } @@ -55,7 +67,18 @@ int acpi_save_state_mem(void) */ void acpi_restore_state_mem(void) { +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + zap_low_mappings(); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } /** diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/alternative.c linux-2.6.17.11-g-v/arch/i386/kernel/alternative.c --- linux-2.6.17.11/arch/i386/kernel/alternative.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/alternative.c 2006-08-28 14:44:48.000000000 +0200 @@ -3,6 +3,7 @@ #include #include #include +#include #define DEBUG 0 #if DEBUG @@ -101,71 +102,128 @@ void apply_alternatives(struct alt_instr struct alt_instr *a; int diff, i, k; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + DPRINTK("%s: alt table %p -> %p\n", __FUNCTION__, start, end); for (a = start; a < end; a++) { BUG_ON(a->replacementlen > a->instrlen); if (!boot_cpu_has(a->cpuid)) continue; - memcpy(a->instr, a->replacement, a->replacementlen); + memcpy(a->instr + __KERNEL_TEXT_OFFSET, a->replacement, a->replacementlen); diff = a->instrlen - a->replacementlen; /* Pad the rest with nops */ for (i = a->replacementlen; diff > 0; diff -= k, i += k) { k = diff; if (k > ASM_NOP_MAX) k = ASM_NOP_MAX; - memcpy(a->instr + i, noptable[k], k); + memcpy(a->instr + i + __KERNEL_TEXT_OFFSET, noptable[k], k); } } + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static void alternatives_smp_save(struct alt_instr *start, struct alt_instr *end) { struct alt_instr *a; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + DPRINTK("%s: alt table %p-%p\n", __FUNCTION__, start, end); for (a = start; a < end; a++) { memcpy(a->replacement + a->replacementlen, - a->instr, + a->instr + __KERNEL_TEXT_OFFSET, a->instrlen); } + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static void alternatives_smp_apply(struct alt_instr *start, struct alt_instr *end) { struct alt_instr *a; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + for (a = start; a < end; a++) { - memcpy(a->instr, + memcpy(a->instr + __KERNEL_TEXT_OFFSET, a->replacement + a->replacementlen, a->instrlen); } + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static void alternatives_smp_lock(u8 **start, u8 **end, u8 *text, u8 *text_end) { - u8 **ptr; + u8 *ptr; - for (ptr = start; ptr < end; ptr++) { - if (*ptr < text) +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + + for (; start < end; start++) { + ptr = *start + __KERNEL_TEXT_OFFSET; + if (ptr < text) continue; - if (*ptr > text_end) + if (ptr > text_end) continue; - **ptr = 0xf0; /* lock prefix */ + *ptr = 0xf0; /* lock prefix */ }; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static void alternatives_smp_unlock(u8 **start, u8 **end, u8 *text, u8 *text_end) { unsigned char **noptable = find_nop_table(); - u8 **ptr; + u8 *ptr; - for (ptr = start; ptr < end; ptr++) { - if (*ptr < text) +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + + for (; start < end; start++) { + ptr = *start + __KERNEL_TEXT_OFFSET; + if (ptr < text) continue; - if (*ptr > text_end) + if (ptr > text_end) continue; - **ptr = noptable[1][0]; + *ptr = noptable[1][0]; }; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } struct smp_alt_module { diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/apic.c linux-2.6.17.11-g-v/arch/i386/kernel/apic.c --- linux-2.6.17.11/arch/i386/kernel/apic.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/apic.c 2006-08-28 14:44:48.000000000 +0200 @@ -1176,7 +1176,7 @@ inline void smp_local_timer_interrupt(st { profile_tick(CPU_PROFILING, regs); #ifdef CONFIG_SMP - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode(regs)); #endif /* diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/apm.c linux-2.6.17.11-g-v/arch/i386/kernel/apm.c --- linux-2.6.17.11/arch/i386/kernel/apm.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/apm.c 2006-08-28 14:44:48.000000000 +0200 @@ -235,7 +235,7 @@ #include "io_ports.h" extern unsigned long get_cmos_time(void); -extern void machine_real_restart(unsigned char *, int); +extern void machine_real_restart(const unsigned char *, unsigned int); #if defined(CONFIG_APM_DISPLAY_BLANK) && defined(CONFIG_VT) extern int (*console_blank_hook)(int); @@ -589,9 +589,18 @@ 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(); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt = get_cpu_gdt_table(cpu); save_desc_40 = gdt[0x40 / 8]; gdt[0x40 / 8] = bad_bios_desc; @@ -603,6 +612,11 @@ static u8 apm_bios_call(u32 func, u32 eb APM_DO_RESTORE_SEGS; local_irq_restore(flags); gdt[0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + put_cpu(); apm_restore_cpus(cpus); @@ -633,9 +647,18 @@ 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(); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt = get_cpu_gdt_table(cpu); save_desc_40 = gdt[0x40 / 8]; gdt[0x40 / 8] = bad_bios_desc; @@ -647,6 +670,11 @@ static u8 apm_bios_call_simple(u32 func, APM_DO_RESTORE_SEGS; local_irq_restore(flags); gdt[0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + put_cpu(); apm_restore_cpus(cpus); return error; @@ -910,7 +938,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 */ diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/asm-offsets.c linux-2.6.17.11-g-v/arch/i386/kernel/asm-offsets.c --- linux-2.6.17.11/arch/i386/kernel/asm-offsets.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/asm-offsets.c 2006-08-28 14:44:48.000000000 +0200 @@ -68,5 +68,6 @@ void foo(void) sizeof(struct tss_struct)); DEFINE(PAGE_SIZE_asm, PAGE_SIZE); + DEFINE(PTRS_PER_PTE_asm, PTRS_PER_PTE); DEFINE(VSYSCALL_BASE, __fix_to_virt(FIX_VSYSCALL)); } diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/cpu/common.c linux-2.6.17.11-g-v/arch/i386/kernel/cpu/common.c --- linux-2.6.17.11/arch/i386/kernel/cpu/common.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/cpu/common.c 2006-08-28 14:44:48.000000000 +0200 @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -19,16 +18,18 @@ #include "cpu.h" -DEFINE_PER_CPU(struct Xgt_desc_struct, cpu_gdt_descr); -EXPORT_PER_CPU_SYMBOL(cpu_gdt_descr); - DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack); static int cachesize_override __cpuinitdata = -1; static int disable_x86_fxsr __cpuinitdata; static int disable_x86_serial_nr __cpuinitdata = 1; + +#ifdef CONFIG_PAX_NOVSYSCALL +static int disable_x86_sep __cpuinitdata = 1; +#else static int disable_x86_sep __cpuinitdata; +#endif struct cpu_dev * cpu_devs[X86_VENDOR_NUM] = {}; @@ -590,11 +591,10 @@ void __init early_cpu_init(void) void __cpuinit cpu_init(void) { int cpu = smp_processor_id(); - struct tss_struct * t = &per_cpu(init_tss, cpu); + struct tss_struct * t = init_tss + cpu; struct thread_struct *thread = ¤t->thread; - struct desc_struct *gdt; + struct desc_struct *gdt = get_cpu_gdt_table(cpu); __u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu); - struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, cpu); if (cpu_test_and_set(cpu, cpu_initialized)) { printk(KERN_WARNING "CPU#%d already initialized!\n", cpu); @@ -612,29 +612,11 @@ void __cpuinit cpu_init(void) } /* - * This is a horrible hack to allocate the GDT. The problem - * is that cpu_init() is called really early for the boot CPU - * (and hence needs bootmem) but much later for the secondary - * CPUs, when bootmem will have gone away - */ - if (NODE_DATA(0)->bdata->node_bootmem_map) { - gdt = (struct desc_struct *)alloc_bootmem_pages(PAGE_SIZE); - /* alloc_bootmem_pages panics on failure, so no check */ - memset(gdt, 0, PAGE_SIZE); - } else { - gdt = (struct desc_struct *)get_zeroed_page(GFP_KERNEL); - if (unlikely(!gdt)) { - printk(KERN_CRIT "CPU%d failed to allocate GDT\n", cpu); - for (;;) - local_irq_enable(); - } - } - - /* * Initialize the per-CPU GDT with the boot GDT, * and set up the GDT descriptor: */ - memcpy(gdt, cpu_gdt_table, GDT_SIZE); + if (cpu) + memcpy(gdt, cpu_gdt_table, GDT_SIZE); /* Set up GDT entry for 16bit stack */ *(__u64 *)(&gdt[GDT_ENTRY_ESPFIX_SS]) |= @@ -642,10 +624,10 @@ void __cpuinit cpu_init(void) ((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) | (CPU_16BIT_STACK_SIZE - 1); - cpu_gdt_descr->size = GDT_SIZE - 1; - cpu_gdt_descr->address = (unsigned long)gdt; + cpu_gdt_descr[cpu].size = GDT_SIZE - 1; + cpu_gdt_descr[cpu].address = (unsigned long)gdt; - load_gdt(cpu_gdt_descr); + load_gdt(&cpu_gdt_descr[cpu]); load_idt(&idt_descr); /* @@ -660,7 +642,7 @@ void __cpuinit cpu_init(void) load_esp0(t, thread); set_tss_desc(cpu,t); load_TR_desc(); - load_LDT(&init_mm.context); + _load_LDT(&init_mm.context); #ifdef CONFIG_DOUBLEFAULT /* Set up doublefault TSS pointer in the GDT */ @@ -668,7 +650,7 @@ void __cpuinit cpu_init(void) #endif /* Clear %fs and %gs. */ - asm volatile ("xorl %eax, %eax; movl %eax, %fs; movl %eax, %gs"); + asm volatile ("movl %0, %%fs; movl %0, %%gs" : : "r"(0)); /* Clear all 6 debug registers: */ set_debugreg(0, 0); diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/crash.c linux-2.6.17.11-g-v/arch/i386/kernel/crash.c --- linux-2.6.17.11/arch/i386/kernel/crash.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/crash.c 2006-08-28 14:44:48.000000000 +0200 @@ -105,7 +105,7 @@ static int crash_nmi_callback(struct pt_ return 1; local_irq_disable(); - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { crash_fixup_ss_esp(&fixed_regs, regs); regs = &fixed_regs; } diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/doublefault.c linux-2.6.17.11-g-v/arch/i386/kernel/doublefault.c --- linux-2.6.17.11/arch/i386/kernel/doublefault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/doublefault.c 2006-08-28 14:44:48.000000000 +0200 @@ -11,7 +11,7 @@ #define DOUBLEFAULT_STACKSIZE (1024) static unsigned long doublefault_stack[DOUBLEFAULT_STACKSIZE]; -#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE) +#define STACK_START (unsigned long)(doublefault_stack+DOUBLEFAULT_STACKSIZE-2) #define ptr_ok(x) ((x) > PAGE_OFFSET && (x) < PAGE_OFFSET + 0x1000000) @@ -56,10 +56,10 @@ struct tss_struct doublefault_tss __cach .eip = (unsigned long) doublefault_fn, .eflags = X86_EFLAGS_SF | 0x2, /* 0x2 bit is always set */ .esp = STACK_START, - .es = __USER_DS, + .es = __KERNEL_DS, .cs = __KERNEL_CS, .ss = __KERNEL_DS, - .ds = __USER_DS, + .ds = __KERNEL_DS, .__cr3 = __pa(swapper_pg_dir) }; diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/efi.c linux-2.6.17.11-g-v/arch/i386/kernel/efi.c --- linux-2.6.17.11/arch/i386/kernel/efi.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/efi.c 2006-08-28 14:44:48.000000000 +0200 @@ -64,82 +64,43 @@ extern void * boot_ioremap(unsigned long static unsigned long efi_rt_eflags; static DEFINE_SPINLOCK(efi_rt_lock); -static pgd_t efi_bak_pg_dir_pointer[2]; +static pgd_t __initdata efi_bak_pg_dir_pointer[KERNEL_PGD_PTRS] __attribute__ ((aligned (4096))); -static void efi_call_phys_prelog(void) +static void __init efi_call_phys_prelog(void) { - unsigned long cr4; - unsigned long temp; - struct Xgt_desc_struct *cpu_gdt_descr; - spin_lock(&efi_rt_lock); local_irq_save(efi_rt_eflags); - cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0); - - /* - * If I don't have PSE, I should just duplicate two entries in page - * directory. If I have PSE, I just need to duplicate one entry in - * page directory. - */ - cr4 = read_cr4(); - - if (cr4 & X86_CR4_PSE) { - efi_bak_pg_dir_pointer[0].pgd = - swapper_pg_dir[pgd_index(0)].pgd; - swapper_pg_dir[0].pgd = - swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd; - } else { - efi_bak_pg_dir_pointer[0].pgd = - swapper_pg_dir[pgd_index(0)].pgd; - efi_bak_pg_dir_pointer[1].pgd = - swapper_pg_dir[pgd_index(0x400000)].pgd; - swapper_pg_dir[pgd_index(0)].pgd = - swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd; - temp = PAGE_OFFSET + 0x400000; - swapper_pg_dir[pgd_index(0x400000)].pgd = - swapper_pg_dir[pgd_index(temp)].pgd; - } + clone_pgd_range(efi_bak_pg_dir_pointer, swapper_pg_dir, KERNEL_PGD_PTRS); + clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, + USER_PGD_PTRS >= KERNEL_PGD_PTRS ? KERNEL_PGD_PTRS : USER_PGD_PTRS); /* * After the lock is released, the original page table is restored. */ - local_flush_tlb(); + __flush_tlb_all(); - cpu_gdt_descr->address = __pa(cpu_gdt_descr->address); - load_gdt(cpu_gdt_descr); + cpu_gdt_descr[0].address = __pa(cpu_gdt_descr[0].address); + load_gdt((struct Xgt_desc_struct *) __pa(&cpu_gdt_descr[0])); } -static void efi_call_phys_epilog(void) +static void __init efi_call_phys_epilog(void) { - unsigned long cr4; - struct Xgt_desc_struct *cpu_gdt_descr = &per_cpu(cpu_gdt_descr, 0); - - cpu_gdt_descr->address = (unsigned long)__va(cpu_gdt_descr->address); - load_gdt(cpu_gdt_descr); - - cr4 = read_cr4(); + cpu_gdt_descr[0].address = (unsigned long) __va(cpu_gdt_descr[0].address); + load_gdt(&cpu_gdt_descr[0]); - if (cr4 & X86_CR4_PSE) { - swapper_pg_dir[pgd_index(0)].pgd = - efi_bak_pg_dir_pointer[0].pgd; - } else { - swapper_pg_dir[pgd_index(0)].pgd = - efi_bak_pg_dir_pointer[0].pgd; - swapper_pg_dir[pgd_index(0x400000)].pgd = - efi_bak_pg_dir_pointer[1].pgd; - } + clone_pgd_range(swapper_pg_dir, efi_bak_pg_dir_pointer, KERNEL_PGD_PTRS); /* * After the lock is released, the original page table is restored. */ - local_flush_tlb(); + __flush_tlb_all(); local_irq_restore(efi_rt_eflags); spin_unlock(&efi_rt_lock); } -static efi_status_t +static efi_status_t __init phys_efi_set_virtual_address_map(unsigned long memory_map_size, unsigned long descriptor_size, u32 descriptor_version, @@ -155,7 +116,7 @@ phys_efi_set_virtual_address_map(unsigne return status; } -static efi_status_t +static efi_status_t __init phys_efi_get_time(efi_time_t *tm, efi_time_cap_t *tc) { efi_status_t status; diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/efi_stub.S linux-2.6.17.11-g-v/arch/i386/kernel/efi_stub.S --- linux-2.6.17.11/arch/i386/kernel/efi_stub.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/efi_stub.S 2006-08-28 14:44:48.000000000 +0200 @@ -7,6 +7,7 @@ #include #include +#include #include #include @@ -22,7 +23,7 @@ * service functions will comply with gcc calling convention, too. */ -.text +__INIT ENTRY(efi_call_phys) /* * 0. The function can only be called in Linux kernel. So CS has been @@ -38,9 +39,7 @@ ENTRY(efi_call_phys) * The mapping of lower virtual memory has been created in prelog and * epilog. */ - movl $1f, %edx - subl $__PAGE_OFFSET, %edx - jmp *%edx + jmp 1f-__PAGE_OFFSET 1: /* @@ -49,14 +48,8 @@ ENTRY(efi_call_phys) * parameter 2, ..., param n. To make things easy, we save the return * address of efi_call_phys in a global variable. */ - popl %edx - movl %edx, saved_return_addr - /* get the function pointer into ECX*/ - popl %ecx - movl %ecx, efi_rt_function_ptr - movl $2f, %edx - subl $__PAGE_OFFSET, %edx - pushl %edx + popl (saved_return_addr) + popl (efi_rt_function_ptr) /* * 3. Clear PG bit in %CR0. @@ -75,9 +68,8 @@ ENTRY(efi_call_phys) /* * 5. Call the physical function. */ - jmp *%ecx + call *(efi_rt_function_ptr-__PAGE_OFFSET) -2: /* * 6. After EFI runtime service returns, control will return to * following instruction. We'd better readjust stack pointer first. @@ -87,37 +79,29 @@ ENTRY(efi_call_phys) /* * 7. Restore PG bit */ - movl %cr0, %edx - orl $0x80000000, %edx - movl %edx, %cr0 - jmp 1f -1: /* * 8. Now restore the virtual mode from flat mode by * adding EIP with PAGE_OFFSET. */ - movl $1f, %edx - jmp *%edx + movl %cr0, %edx + orl $0x80000000, %edx + movl %edx, %cr0 + jmp 1f+__PAGE_OFFSET 1: /* * 9. Balance the stack. And because EAX contain the return value, * we'd better not clobber it. */ - leal efi_rt_function_ptr, %edx - movl (%edx), %ecx - pushl %ecx + pushl (efi_rt_function_ptr) /* - * 10. Push the saved return address onto the stack and return. + * 10. Return to the saved return address. */ - leal saved_return_addr, %edx - movl (%edx), %ecx - pushl %ecx - ret + jmpl *(saved_return_addr) .previous -.data +__INITDATA saved_return_addr: .long 0 efi_rt_function_ptr: diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/entry.S linux-2.6.17.11-g-v/arch/i386/kernel/entry.S --- linux-2.6.17.11/arch/i386/kernel/entry.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/entry.S 2006-08-28 14:44:48.000000000 +0200 @@ -82,7 +82,7 @@ VM_MASK = 0x00020000 #define resume_kernel restore_nocheck #endif -#define SAVE_ALL \ +#define __SAVE_ALL(_DS) \ cld; \ pushl %es; \ pushl %ds; \ @@ -93,10 +93,24 @@ VM_MASK = 0x00020000 pushl %edx; \ pushl %ecx; \ pushl %ebx; \ - movl $(__USER_DS), %edx; \ + movl $(_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; +#ifdef CONFIG_PAX_KERNEXEC +#define SAVE_ALL \ + __SAVE_ALL(__KERNEL_DS) \ + movl %cr0, %edx; \ + movl %edx, %esi; \ + orl $0x10000, %edx; \ + xorl %edx, %esi; \ + movl %edx, %cr0; +#elif defined(CONFIG_PAX_NOVSYSCALL) +#define SAVE_ALL __SAVE_ALL(__KERNEL_DS) +#else +#define SAVE_ALL __SAVE_ALL(__USER_DS) +#endif + #define RESTORE_INT_REGS \ popl %ebx; \ popl %ecx; \ @@ -146,7 +160,19 @@ ret_from_intr: movl EFLAGS(%esp), %eax # mix EFLAGS and CS movb CS(%esp), %al testl $(VM_MASK | 3), %eax + +#ifdef CONFIG_PAX_KERNEXEC + jnz resume_userspace + + movl %cr0, %edx + xorl %esi, %edx + movl %edx, %cr0 + jmp resume_kernel +#else jz resume_kernel +#endif + + ENTRY(resume_userspace) cli # make sure we don't miss an interrupt # setting need_resched or sigpending @@ -190,9 +216,17 @@ sysenter_past_esp: * Load the potential sixth argument from user stack. * Careful about security. */ + +#ifdef CONFIG_PAX_MEMORY_UDEREF + pushl $(__USER_DS) + pop %ds +1: movl %ds:(%ebp),%ebp +#else cmpl $__PAGE_OFFSET-3,%ebp jae syscall_fault 1: movl (%ebp),%ebp +#endif + .section __ex_table,"a" .align 4 .long 1b,syscall_fault @@ -213,13 +247,33 @@ sysenter_past_esp: movl TI_flags(%ebp), %ecx testw $_TIF_ALLWORK_MASK, %cx jne syscall_exit_work + +#ifdef CONFIG_PAX_RANDKSTACK + pushl %eax + call pax_randomize_kstack + popl %eax +#endif + /* if something modifies registers it must also disable sysexit */ movl EIP(%esp), %edx movl OLDESP(%esp), %ecx +1: mov DS(%esp), %ds +2: mov ES(%esp), %es xorl %ebp,%ebp sti sysexit +.section .fixup,"ax" +3: movl $0,DS(%esp) + jmp 1b +4: movl $0,ES(%esp) + jmp 2b +.previous +.section __ex_table,"a" + .align 4 + .long 1b,3b + .long 2b,4b +.previous # system call handler stub ENTRY(system_call) @@ -247,6 +301,10 @@ syscall_exit: testw $_TIF_ALLWORK_MASK, %cx # current->work jne syscall_exit_work +#ifdef CONFIG_PAX_RANDKSTACK + call pax_randomize_kstack +#endif + restore_all: movl EFLAGS(%esp), %eax # mix EFLAGS, SS and CS # Warning: OLDSS(%esp) contains the wrong/random values if we @@ -402,7 +460,7 @@ syscall_badsys: * Build the entry stubs and pointer table with * some assembler magic. */ -.data +.section .rodata,"a",@progbits ENTRY(interrupt) .text @@ -412,7 +470,7 @@ ENTRY(irq_entries_start) ALIGN 1: pushl $vector-256 jmp common_interrupt -.data +.section .rodata,"a",@progbits .long 1b .text vector=vector+1 @@ -459,10 +517,19 @@ error_code: movl ORIG_EAX(%esp), %edx # get the error code movl %eax, ORIG_EAX(%esp) movl %ecx, ES(%esp) - movl $(__USER_DS), %ecx + movl $(__KERNEL_DS), %ecx movl %ecx, %ds movl %ecx, %es movl %esp,%eax # pt_regs pointer + +#ifdef CONFIG_PAX_KERNEXEC + movl %cr0, %ecx + movl %ecx, %esi + orl $0x10000, %ecx + xorl %ecx, %esi + movl %ecx, %cr0 +#endif + call *%edi jmp ret_from_exception @@ -558,6 +625,13 @@ nmi_stack_correct: xorl %edx,%edx # zero error code movl %esp,%eax # pt_regs pointer call do_nmi + +#ifdef CONFIG_PAX_KERNEXEC + movl %cr0, %edx + xorl %esi, %edx + movl %edx, %cr0 +#endif + jmp restore_all nmi_stack_fixup: @@ -588,6 +662,13 @@ nmi_16bit_stack: FIXUP_ESPFIX_STACK # %eax == %esp xorl %edx,%edx # zero error code call do_nmi + +#ifdef CONFIG_PAX_KERNEXEC + movl %cr0, %edx + xorl %esi, %edx + movl %edx, %cr0 +#endif + RESTORE_REGS lss 12+4(%esp), %esp # back to 16bit stack 1: iret @@ -663,7 +744,6 @@ ENTRY(spurious_interrupt_bug) pushl $do_spurious_interrupt_bug jmp error_code -.section .rodata,"a" #include "syscall_table.S" syscall_table_size=(.-sys_call_table) diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/head.S linux-2.6.17.11-g-v/arch/i386/kernel/head.S --- linux-2.6.17.11/arch/i386/kernel/head.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/head.S 2006-09-05 09:59:03.000000000 +0200 @@ -46,6 +46,16 @@ */ #define INIT_MAP_BEYOND_END (128*1024) +#ifdef CONFIG_PAX_KERNEXEC +/* PaX: fill first page in .text with int3 to catch NULL derefs in kernel mode */ +.fill 4096,1,0xcc +#endif + +/* + * Real beginning of normal "text" segment + */ +ENTRY(stext) +ENTRY(_stext) /* * 32-bit kernel entrypoint; only used by the boot CPU. On entry, @@ -67,6 +77,26 @@ ENTRY(startup_32) movl %eax,%fs movl %eax,%gs +#ifdef CONFIG_PAX_MEMORY_UDEREF + movl $((((__PAGE_OFFSET-1) & 0xf0000000) >> 12) | 0x00c09700),%eax + movl %eax,(cpu_gdt_table - __PAGE_OFFSET + GDT_ENTRY_KERNEL_DS * 8 + 4) + movl $((((__PAGE_OFFSET-1) & 0xf0000000) >> 12) | 0x00c0f300),%eax + movl %eax,(cpu_gdt_table - __PAGE_OFFSET + GDT_ENTRY_DEFAULT_USER_DS * 8 + 4) +#endif + +#ifdef CONFIG_PAX_KERNEXEC + movl $ __KERNEL_TEXT_OFFSET,%eax + movw %ax,(cpu_gdt_table - __PAGE_OFFSET + __KERNEL_CS + 2) + rorl $16,%eax + movb %al,(cpu_gdt_table - __PAGE_OFFSET + __KERNEL_CS + 4) + movb %ah,(cpu_gdt_table - __PAGE_OFFSET + __KERNEL_CS + 7) + + movb %al,(boot_gdt_table - __PAGE_OFFSET + __BOOT_CS + 4) + movb %ah,(boot_gdt_table - __PAGE_OFFSET + __BOOT_CS + 7) + rorl $16,%eax + movw %ax,(boot_gdt_table - __PAGE_OFFSET + __BOOT_CS + 2) +#endif + /* * Clear BSS first so that there are no surprises... * No need to cld as DF is already clear from cld above... @@ -114,24 +144,42 @@ ENTRY(startup_32) * Warning: don't use %esi or the stack in this code. However, %esp * can be used as a GPR if you really need it... */ -page_pde_offset = (__PAGE_OFFSET >> 20); - +#ifdef CONFIG_X86_PAE +page_pde_offset = ((__PAGE_OFFSET >> 21) * (4096 / PTRS_PER_PTE_asm)); +#else +page_pde_offset = ((__PAGE_OFFSET >> 22) * (4096 / PTRS_PER_PTE_asm)); +#endif movl $(pg0 - __PAGE_OFFSET), %edi +#ifdef CONFIG_X86_PAE + movl $(swapper_pm_dir - __PAGE_OFFSET), %edx +#else movl $(swapper_pg_dir - __PAGE_OFFSET), %edx - movl $0x007, %eax /* 0x007 = PRESENT+RW+USER */ +#endif + movl $0x063, %eax /* 0x063 = DIRTY+ACCESSED+PRESENT+RW */ 10: - leal 0x007(%edi),%ecx /* Create PDE entry */ + leal 0x063(%edi),%ecx /* Create PDE entry */ movl %ecx,(%edx) /* Store identity PDE entry */ movl %ecx,page_pde_offset(%edx) /* Store kernel PDE entry */ +#ifdef CONFIG_X86_PAE + movl $0,4(%edx) + movl $0,page_pde_offset+4(%edx) + addl $8,%edx + movl $512, %ecx +#else addl $4,%edx movl $1024, %ecx +#endif 11: stosl +#ifdef CONFIG_X86_PAE + movl $0,(%edi) + addl $4,%edi +#endif addl $0x1000,%eax loop 11b /* End condition: we must map up to and including INIT_MAP_BEYOND_END */ - /* bytes beyond the end of our own page tables; the +0x007 is the attribute bits */ - leal (INIT_MAP_BEYOND_END+0x007)(%edi),%ebp + /* bytes beyond the end of our own page tables; the +0x063 is the attribute bits */ + leal (INIT_MAP_BEYOND_END+0x063)(%edi),%ebp cmpl %ebp,%eax jb 10b movl %edi,(init_pg_tables_end - __PAGE_OFFSET) @@ -154,6 +202,11 @@ ENTRY(startup_32_smp) movl %eax,%fs movl %eax,%gs + /* This is a secondary processor (AP) */ + xorl %ebx,%ebx + incl %ebx +#endif /* CONFIG_SMP */ + /* * New page tables may be in 4Mbyte page mode and may * be using the global pages. @@ -169,26 +222,27 @@ ENTRY(startup_32_smp) * not yet offset PAGE_OFFSET.. */ #define cr4_bits mmu_cr4_features-__PAGE_OFFSET +3: movl cr4_bits,%edx andl %edx,%edx - jz 6f + jz 5f movl %cr4,%eax # Turn on paging options (PSE,PAE,..) orl %edx,%eax movl %eax,%cr4 - btl $5, %eax # check if PAE is enabled - jnc 6f +#ifdef CONFIG_X86_PAE + movl %ebx,%edi /* Check if extended functions are implemented */ movl $0x80000000, %eax cpuid cmpl $0x80000000, %eax - jbe 6f + jbe 4f mov $0x80000001, %eax cpuid /* Execute Disable bit supported? */ btl $20, %edx - jnc 6f + jnc 4f /* Setup EFER (Extended Feature Enable Register) */ movl $0xc0000080, %ecx @@ -197,14 +251,12 @@ ENTRY(startup_32_smp) btsl $11, %eax /* Make changes effective */ wrmsr + btsl $63,__supported_pte_mask-__PAGE_OFFSET -6: - /* This is a secondary processor (AP) */ - xorl %ebx,%ebx - incl %ebx - -3: -#endif /* CONFIG_SMP */ +4: + movl %edi,%ebx +#endif +5: /* * Enable paging @@ -229,9 +281,7 @@ ENTRY(startup_32_smp) #ifdef CONFIG_SMP andl %ebx,%ebx - jz 1f /* Initial CPU cleans BSS */ - jmp checkCPUtype -1: + jnz checkCPUtype /* Initial CPU cleans BSS */ #endif /* CONFIG_SMP */ /* @@ -308,8 +358,6 @@ is386: movl $2,%ecx # set MP ljmp $(__KERNEL_CS),$1f 1: movl $(__KERNEL_DS),%eax # reload all the segment registers movl %eax,%ss # after changing gdt. - - movl $(__USER_DS),%eax # DS/ES contains default USER segment movl %eax,%ds movl %eax,%es @@ -383,63 +431,71 @@ rp_sidt: /* This is the default interrupt "handler" :-) */ ALIGN ignore_int: - cld #ifdef CONFIG_PRINTK - pushl %eax - pushl %ecx - pushl %edx - pushl %es - pushl %ds + cld movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es - pushl 16(%esp) - pushl 24(%esp) - pushl 32(%esp) - pushl 40(%esp) + pushl 12(%esp) + pushl 12(%esp) + pushl 12(%esp) + pushl 12(%esp) pushl $int_msg #ifdef CONFIG_EARLY_PRINTK call early_printk #else call printk #endif - addl $(5*4),%esp - popl %ds - popl %es - popl %edx - popl %ecx - popl %eax #endif - iret - -/* - * Real beginning of normal "text" segment - */ -ENTRY(stext) -ENTRY(_stext) +1: hlt + jmp 1b -/* - * BSS section - */ -.section ".bss.page_aligned","w" +.section .swapper_pg_dir,"a",@progbits ENTRY(swapper_pg_dir) +#ifdef CONFIG_X86_PAE + .long swapper_pm_dir-__PAGE_OFFSET+1 + .long 0 + .long swapper_pm_dir+512*8-__PAGE_OFFSET+1 + .long 0 + .long swapper_pm_dir+512*16-__PAGE_OFFSET+1 + .long 0 + .long swapper_pm_dir+512*24-__PAGE_OFFSET+1 + .long 0 +#else .fill 1024,4,0 +#endif + +#ifdef CONFIG_X86_PAE +.section .swapper_pm_dir,"a",@progbits +ENTRY(swapper_pm_dir) + .fill 512,8,0 + .fill 512,8,0 + .fill 512,8,0 + .fill 512,8,0 +#endif + +.section .empty_zero_page,"a",@progbits ENTRY(empty_zero_page) .fill 4096,1,0 /* - * This starts the data section. + * The IDT has to be page-aligned to simplify the Pentium + * F0 0F bug workaround.. We have a special link segment + * for this. */ -.data +.section .idt,"a",@progbits +ENTRY(idt_table) + .fill 256,8,0 + +.section .rodata,"a",@progbits +ready: .byte 0 ENTRY(stack_start) - .long init_thread_union+THREAD_SIZE + .long init_thread_union+THREAD_SIZE-8 .long __BOOT_DS -ready: .byte 0 - int_msg: - .asciz "Unknown interrupt or fault at EIP %p %p %p\n" + .asciz "Unknown interrupt, stack: %p %p %p %p\n" /* * The IDT and GDT 'descriptors' are a strange 48-bit object @@ -465,10 +521,12 @@ idt_descr: # boot GDT descriptor (later on used by CPU#0): .word 0 # 32 bit align gdt_desc.address -cpu_gdt_descr: +ENTRY(cpu_gdt_descr) .word GDT_ENTRIES*8-1 .long cpu_gdt_table + .fill NR_CPUS*8-6,1,0 # space for the other GDT descriptors + /* * The boot_gdt_table must mirror the equivalent in setup.S and is * used only for booting. @@ -476,13 +534,13 @@ cpu_gdt_descr: .align L1_CACHE_BYTES ENTRY(boot_gdt_table) .fill GDT_ENTRY_BOOT_CS,8,0 - .quad 0x00cf9a000000ffff /* kernel 4GB code at 0x00000000 */ - .quad 0x00cf92000000ffff /* kernel 4GB data at 0x00000000 */ + .quad 0x00cf9b000000ffff /* kernel 4GB code at 0x00000000 */ + .quad 0x00cf93000000ffff /* kernel 4GB data at 0x00000000 */ /* * The Global Descriptor Table contains 28 quadwords, per-CPU. */ - .align L1_CACHE_BYTES + .align PAGE_SIZE_asm ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* NULL descriptor */ .quad 0x0000000000000000 /* 0x0b reserved */ @@ -497,10 +555,10 @@ ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* 0x53 reserved */ .quad 0x0000000000000000 /* 0x5b reserved */ - .quad 0x00cf9a000000ffff /* 0x60 kernel 4GB code at 0x00000000 */ - .quad 0x00cf92000000ffff /* 0x68 kernel 4GB data at 0x00000000 */ - .quad 0x00cffa000000ffff /* 0x73 user 4GB code at 0x00000000 */ - .quad 0x00cff2000000ffff /* 0x7b user 4GB data at 0x00000000 */ + .quad 0x00cf9b000000ffff /* 0x60 kernel 4GB code at 0x00000000 */ + .quad 0x00cf93000000ffff /* 0x68 kernel 4GB data at 0x00000000 */ + .quad 0x00cffb000000ffff /* 0x73 user 4GB code at 0x00000000 */ + .quad 0x00cff3000000ffff /* 0x7b user 4GB data at 0x00000000 */ .quad 0x0000000000000000 /* 0x80 TSS descriptor */ .quad 0x0000000000000000 /* 0x88 LDT descriptor */ @@ -510,24 +568,30 @@ ENTRY(cpu_gdt_table) * They code segments and data segments have fixed 64k limits, * the transfer segment sizes are set at run time. */ - .quad 0x00409a000000ffff /* 0x90 32-bit code */ - .quad 0x00009a000000ffff /* 0x98 16-bit code */ - .quad 0x000092000000ffff /* 0xa0 16-bit data */ - .quad 0x0000920000000000 /* 0xa8 16-bit data */ - .quad 0x0000920000000000 /* 0xb0 16-bit data */ + .quad 0x00409b000000ffff /* 0x90 32-bit code */ + .quad 0x00009b000000ffff /* 0x98 16-bit code */ + .quad 0x000093000000ffff /* 0xa0 16-bit data */ + .quad 0x0000930000000000 /* 0xa8 16-bit data */ + .quad 0x0000930000000000 /* 0xb0 16-bit data */ /* * The APM segments have byte granularity and their bases * are set at run time. All have 64k limits. */ - .quad 0x00409a000000ffff /* 0xb8 APM CS code */ - .quad 0x00009a000000ffff /* 0xc0 APM CS 16 code (16 bit) */ - .quad 0x004092000000ffff /* 0xc8 APM DS data */ + .quad 0x00409b000000ffff /* 0xb8 APM CS code */ + .quad 0x00009b000000ffff /* 0xc0 APM CS 16 code (16 bit) */ + .quad 0x004093000000ffff /* 0xc8 APM DS data */ - .quad 0x0000920000000000 /* 0xd0 - ESPFIX 16-bit SS */ + .quad 0x0000930000000000 /* 0xd0 - ESPFIX 16-bit SS */ .quad 0x0000000000000000 /* 0xd8 - unused */ .quad 0x0000000000000000 /* 0xe0 - unused */ .quad 0x0000000000000000 /* 0xe8 - unused */ .quad 0x0000000000000000 /* 0xf0 - unused */ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ + /* Be sure this is zeroed to avoid false validations in Xen */ + .fill PAGE_SIZE_asm / 8 - GDT_ENTRIES,8,0 + +#ifdef CONFIG_SMP + .fill (NR_CPUS-1) * (PAGE_SIZE_asm / 8),8,0 /* other CPU's GDT */ +#endif diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/i386_ksyms.c linux-2.6.17.11-g-v/arch/i386/kernel/i386_ksyms.c --- linux-2.6.17.11/arch/i386/kernel/i386_ksyms.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/i386_ksyms.c 2006-08-28 14:44:48.000000000 +0200 @@ -3,12 +3,16 @@ #include #include +EXPORT_SYMBOL_GPL(cpu_gdt_table); + EXPORT_SYMBOL(__down_failed); EXPORT_SYMBOL(__down_failed_interruptible); EXPORT_SYMBOL(__down_failed_trylock); EXPORT_SYMBOL(__up_wakeup); /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); +EXPORT_SYMBOL(csum_partial_copy_generic_to_user); +EXPORT_SYMBOL(csum_partial_copy_generic_from_user); EXPORT_SYMBOL(__get_user_1); EXPORT_SYMBOL(__get_user_2); diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/init_task.c linux-2.6.17.11-g-v/arch/i386/kernel/init_task.c --- linux-2.6.17.11/arch/i386/kernel/init_task.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/init_task.c 2006-08-28 14:44:48.000000000 +0200 @@ -42,5 +42,5 @@ EXPORT_SYMBOL(init_task); * per-CPU TSS segments. Threads are completely 'soft' on Linux, * no more per-task TSS's. */ -DEFINE_PER_CPU(struct tss_struct, init_tss) ____cacheline_internodealigned_in_smp = INIT_TSS; +struct tss_struct init_tss[NR_CPUS] ____cacheline_internodealigned_in_smp = { [0 ... NR_CPUS-1] = INIT_TSS }; diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/ioport.c linux-2.6.17.11-g-v/arch/i386/kernel/ioport.c --- linux-2.6.17.11/arch/i386/kernel/ioport.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/ioport.c 2006-08-28 14:44:48.000000000 +0200 @@ -16,6 +16,7 @@ #include #include #include +#include /* Set EXTENT bits starting at BASE in BITMAP to value TURN_ON. */ static void set_bitmap(unsigned long *bitmap, unsigned int base, unsigned int extent, int new_value) @@ -64,9 +65,16 @@ asmlinkage long sys_ioperm(unsigned long if ((from + num <= from) || (from + num > IO_BITMAP_BITS)) return -EINVAL; +#ifdef CONFIG_GRKERNSEC_IO + if (turn_on) { + gr_handle_ioperm(); +#else if (turn_on && !capable(CAP_SYS_RAWIO)) +#endif return -EPERM; - +#ifdef CONFIG_GRKERNSEC_IO + } +#endif /* * If it's the first ioperm() call in this thread's lifetime, set the * IO bitmap up. ioperm() is much less timing critical than clone(), @@ -88,7 +96,7 @@ asmlinkage long sys_ioperm(unsigned long * because the ->io_bitmap_max value must match the bitmap * contents: */ - tss = &per_cpu(init_tss, get_cpu()); + tss = init_tss + get_cpu(); set_bitmap(t->io_bitmap_ptr, from, num, !turn_on); @@ -142,8 +150,13 @@ asmlinkage long sys_iopl(unsigned long u return -EINVAL; /* Trying to gain more privileges? */ if (level > old) { +#ifdef CONFIG_GRKERNSEC_IO + gr_handle_iopl(); + return -EPERM; +#else if (!capable(CAP_SYS_RAWIO)) return -EPERM; +#endif } t->iopl = level << 12; regs->eflags = (regs->eflags & ~X86_EFLAGS_IOPL) | t->iopl; diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/irq.c linux-2.6.17.11-g-v/arch/i386/kernel/irq.c --- linux-2.6.17.11/arch/i386/kernel/irq.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/irq.c 2006-08-28 14:44:48.000000000 +0200 @@ -91,7 +91,7 @@ fastcall unsigned int do_IRQ(struct pt_r int arg1, arg2, ebx; /* build the stack frame on the IRQ stack */ - isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); + isp = (u32*) ((char*)irqctx + sizeof(*irqctx)) - 2; irqctx->tinfo.task = curctx->tinfo.task; irqctx->tinfo.previous_esp = current_stack_pointer; @@ -119,10 +119,10 @@ fastcall unsigned int do_IRQ(struct pt_r * gcc's 3.0 and earlier don't handle that correctly. */ static char softirq_stack[NR_CPUS * THREAD_SIZE] - __attribute__((__aligned__(THREAD_SIZE))); + __attribute__((__aligned__(THREAD_SIZE), __section__(".bss.page_aligned"))); static char hardirq_stack[NR_CPUS * THREAD_SIZE] - __attribute__((__aligned__(THREAD_SIZE))); + __attribute__((__aligned__(THREAD_SIZE), __section__(".bss.page_aligned"))); /* * allocate per-cpu stacks for hardirq and for softirq processing @@ -182,7 +182,7 @@ asmlinkage void do_softirq(void) irqctx->tinfo.previous_esp = current_stack_pointer; /* build the stack frame on the softirq stack */ - isp = (u32*) ((char*)irqctx + sizeof(*irqctx)); + isp = (u32*) ((char*)irqctx + sizeof(*irqctx)) - 2; asm volatile( " xchgl %%ebx,%%esp \n" diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/ldt.c linux-2.6.17.11-g-v/arch/i386/kernel/ldt.c --- linux-2.6.17.11/arch/i386/kernel/ldt.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/ldt.c 2006-08-28 14:44:48.000000000 +0200 @@ -103,6 +103,19 @@ int init_new_context(struct task_struct retval = copy_ldt(&mm->context, &old_mm->context); up(&old_mm->context.sem); } + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (!mm->context.user_cs_limit) { + mm->context.user_cs_base = 0UL; + mm->context.user_cs_limit = ~0UL; + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_SMP) + cpus_clear(mm->context.cpu_user_cs_mask); +#endif + + } +#endif + return retval; } @@ -160,7 +173,7 @@ static int read_default_ldt(void __user { int err; unsigned long size; - void *address; + const void *address; err = 0; address = &default_ldt[0]; @@ -215,6 +228,13 @@ static int write_ldt(void __user * ptr, } } +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && (ldt_info.contents & MODIFY_LDT_CONTENTS_CODE)) { + error = -EINVAL; + goto out_unlock; + } +#endif + entry_1 = LDT_entry_a(&ldt_info); entry_2 = LDT_entry_b(&ldt_info); if (oldmode) diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/module.c linux-2.6.17.11-g-v/arch/i386/kernel/module.c --- linux-2.6.17.11/arch/i386/kernel/module.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/module.c 2006-08-28 14:44:48.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #if 0 #define DEBUGP printk @@ -32,9 +33,30 @@ void *module_alloc(unsigned long size) { if (size == 0) return NULL; + +#ifdef CONFIG_PAX_KERNEXEC + return vmalloc(size); +#else return vmalloc_exec(size); +#endif + } +#ifdef CONFIG_PAX_KERNEXEC +void *module_alloc_exec(unsigned long size) +{ + struct vm_struct *area; + + if (size == 0) + return NULL; + + area = __get_vm_area(size, 0, (unsigned long)&MODULES_VADDR, (unsigned long)&MODULES_END); + if (area) + return area->addr; + + return NULL; +} +#endif /* Free memory returned from module_alloc */ void module_free(struct module *mod, void *module_region) @@ -44,6 +66,45 @@ void module_free(struct module *mod, voi table entries. */ } +#ifdef CONFIG_PAX_KERNEXEC +void module_free_exec(struct module *mod, void *module_region) +{ + struct vm_struct **p, *tmp; + + if (!module_region) + return; + + if ((PAGE_SIZE-1) & (unsigned long)module_region) { + printk(KERN_ERR "Trying to module_free_exec() bad address (%p)\n", module_region); + WARN_ON(1); + return; + } + + write_lock(&vmlist_lock); + for (p = &vmlist ; (tmp = *p) != NULL ;p = &tmp->next) + if (tmp->addr == module_region) + break; + + if (tmp) { + unsigned long cr0; + + pax_open_kernel(cr0); + memset(tmp->addr, 0xCC, tmp->size); + pax_close_kernel(cr0); + + *p = tmp->next; + kfree(tmp); + } + write_unlock(&vmlist_lock); + + if (!tmp) { + printk(KERN_ERR "Trying to module_free_exec() nonexistent vm area (%p)\n", + module_region); + WARN_ON(1); + } +} +#endif + /* We don't need anything special. */ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, @@ -62,14 +123,16 @@ int apply_relocate(Elf32_Shdr *sechdrs, unsigned int i; Elf32_Rel *rel = (void *)sechdrs[relsec].sh_addr; Elf32_Sym *sym; - uint32_t *location; + uint32_t *plocation, location; DEBUGP("Applying relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); for (i = 0; i < sechdrs[relsec].sh_size / sizeof(*rel); i++) { /* This is where to make the change */ - location = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr - + rel[i].r_offset; + plocation = (void *)sechdrs[sechdrs[relsec].sh_info].sh_addr + rel[i].r_offset; + location = (uint32_t)plocation; + if (sechdrs[sechdrs[relsec].sh_info].sh_flags & SHF_EXECINSTR) + plocation = (void *)plocation + __KERNEL_TEXT_OFFSET; /* This is the symbol it is referring to. Note that all undefined symbols have been resolved. */ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr @@ -78,11 +141,11 @@ int apply_relocate(Elf32_Shdr *sechdrs, switch (ELF32_R_TYPE(rel[i].r_info)) { case R_386_32: /* We add the value into the location given */ - *location += sym->st_value; + *plocation += sym->st_value; break; case R_386_PC32: /* Add the value, subtract its postition */ - *location += sym->st_value - (uint32_t)location; + *plocation += sym->st_value - location; break; default: printk(KERN_ERR "module %s: Unknown relocation: %u\n", diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/process.c linux-2.6.17.11-g-v/arch/i386/kernel/process.c --- linux-2.6.17.11/arch/i386/kernel/process.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/process.c 2006-08-28 14:44:48.000000000 +0200 @@ -69,7 +69,7 @@ EXPORT_SYMBOL(boot_option_idle_override) */ unsigned long thread_saved_pc(struct task_struct *tsk) { - return ((unsigned long *)tsk->thread.esp)[3]; + return tsk->thread.eip; } /* @@ -294,7 +294,7 @@ void show_regs(struct pt_regs * regs) printk("EIP: %04x:[<%08lx>] CPU: %d\n",0xffff & regs->xcs,regs->eip, smp_processor_id()); print_symbol("EIP is at %s\n", regs->eip); - if (user_mode_vm(regs)) + if (user_mode(regs)) printk(" ESP: %04x:%08lx",0xffff & regs->xss,regs->esp); printk(" EFLAGS: %08lx %s (%s %.*s)\n", regs->eflags, print_tainted(), system_utsname.release, @@ -343,8 +343,8 @@ int kernel_thread(int (*fn)(void *), voi regs.ebx = (unsigned long) fn; regs.edx = (unsigned long) arg; - regs.xds = __USER_DS; - regs.xes = __USER_DS; + regs.xds = __KERNEL_DS; + regs.xes = __KERNEL_DS; regs.orig_eax = -1; regs.eip = (unsigned long) kernel_thread_helper; regs.xcs = __KERNEL_CS; @@ -366,7 +366,7 @@ void exit_thread(void) /* The process may have allocated an io port bitmap... nuke it. */ if (unlikely(NULL != t->io_bitmap_ptr)) { int cpu = get_cpu(); - struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct tss_struct *tss = init_tss + cpu; kfree(t->io_bitmap_ptr); t->io_bitmap_ptr = NULL; @@ -386,6 +386,9 @@ void flush_thread(void) { struct task_struct *tsk = current; + __asm__("mov %0,%%fs\n" + "mov %0,%%gs\n" + : : "r" (0) : "memory"); memset(tsk->thread.debugreg, 0, sizeof(unsigned long)*8); memset(tsk->thread.tls_array, 0, sizeof(tsk->thread.tls_array)); /* @@ -418,7 +421,7 @@ int copy_thread(int nr, unsigned long cl struct task_struct *tsk; int err; - childregs = task_pt_regs(p); + childregs = task_stack_page(p) + THREAD_SIZE - sizeof(struct pt_regs) - 8; *childregs = *regs; childregs->eax = 0; childregs->esp = esp; @@ -461,6 +464,11 @@ int copy_thread(int nr, unsigned long cl if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) goto out; +#ifdef CONFIG_PAX_SEGMEXEC + if ((current->mm->pax_flags & MF_PAX_SEGMEXEC) && (info.contents & MODIFY_LDT_CONTENTS_CODE)) + goto out; +#endif + desc = p->thread.tls_array + idx - GDT_ENTRY_TLS_MIN; desc->a = LDT_entry_a(&info); desc->b = LDT_entry_b(&info); @@ -625,7 +633,11 @@ struct task_struct fastcall * __switch_t struct thread_struct *prev = &prev_p->thread, *next = &next_p->thread; int cpu = smp_processor_id(); - struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct tss_struct *tss = init_tss + cpu; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ @@ -648,11 +660,23 @@ struct task_struct fastcall * __switch_t savesegment(fs, prev->fs); savesegment(gs, prev->gs); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + +#ifdef CONFIG_PAX_MEMORY_UDEREF + __set_fs(get_fs(), cpu); +#endif + /* * Load the per-thread Thread-Local Storage descriptor. */ load_TLS(next, cpu); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* * Restore %fs and %gs if needed. * @@ -806,8 +830,18 @@ asmlinkage int sys_set_thread_area(struc struct desc_struct *desc; int cpu, idx; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + if (copy_from_user(&info, u_info, sizeof(info))) return -EFAULT; + +#ifdef CONFIG_PAX_SEGMEXEC + if ((current->mm->pax_flags & MF_PAX_SEGMEXEC) && (info.contents & MODIFY_LDT_CONTENTS_CODE)) + return -EINVAL; +#endif + idx = info.entry_number; /* @@ -839,8 +873,17 @@ asmlinkage int sys_set_thread_area(struc desc->a = LDT_entry_a(&info); desc->b = LDT_entry_b(&info); } + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + load_TLS(t, cpu); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + put_cpu(); return 0; @@ -896,9 +939,27 @@ asmlinkage int sys_get_thread_area(struc return 0; } -unsigned long arch_align_stack(unsigned long sp) +#ifdef CONFIG_PAX_RANDKSTACK +asmlinkage void pax_randomize_kstack(void) { - if (randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; + struct tss_struct *tss = init_tss + smp_processor_id(); + unsigned long time; + + if (!randomize_va_space) + return; + + rdtscl(time); + + /* P4 seems to return a 0 LSB, ignore it */ +#ifdef CONFIG_MPENTIUM4 + time &= 0x1EUL; + time <<= 2; +#else + time &= 0xFUL; + time <<= 3; +#endif + + tss->esp0 ^= time; + current->thread.esp0 = tss->esp0; } +#endif diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/ptrace.c linux-2.6.17.11-g-v/arch/i386/kernel/ptrace.c --- linux-2.6.17.11/arch/i386/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/ptrace.c 2006-08-28 14:44:48.000000000 +0200 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -342,6 +343,11 @@ ptrace_set_thread_area(struct task_struc if (copy_from_user(&info, user_desc, sizeof(info))) return -EFAULT; +#ifdef CONFIG_PAX_SEGMEXEC + if ((child->mm->pax_flags & MF_PAX_SEGMEXEC) && (info.contents & MODIFY_LDT_CONTENTS_CODE)) + return -EINVAL; +#endif + if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; @@ -432,6 +438,17 @@ long arch_ptrace(struct task_struct *chi if(addr == (long) &dummy->u_debugreg[5]) break; if(addr < (long) &dummy->u_debugreg[4] && ((unsigned long) data) >= TASK_SIZE-3) break; + +#ifdef CONFIG_GRKERNSEC + if(addr >= (long) &dummy->u_debugreg[0] && + addr <= (long) &dummy->u_debugreg[3]){ + long reg = (addr - (long) &dummy->u_debugreg[0]) >> 2; + long type = (child->thread.debugreg[7] >> (DR_CONTROL_SHIFT + 4*reg)) & 3; + long align = (child->thread.debugreg[7] >> (DR_CONTROL_SHIFT + 2 + 4*reg)) & 3; + if((type & 1) && (data & align)) + break; + } +#endif /* Sanity-check data. Take one half-byte at once with * check = (val >> (16 + 4*i)) & 0xf. It contains the @@ -645,7 +662,7 @@ void send_sigtrap(struct task_struct *ts info.si_code = TRAP_BRKPT; /* User-mode eip? */ - info.si_addr = user_mode_vm(regs) ? (void __user *) regs->eip : NULL; + info.si_addr = user_mode(regs) ? (void __user *) regs->eip : NULL; /* Send us the fakey SIGTRAP */ force_sig_info(SIGTRAP, &info, tsk); diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/reboot.c linux-2.6.17.11-g-v/arch/i386/kernel/reboot.c --- linux-2.6.17.11/arch/i386/kernel/reboot.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/reboot.c 2006-08-28 14:44:48.000000000 +0200 @@ -25,7 +25,7 @@ void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); -static int reboot_mode; +static unsigned short reboot_mode; static int reboot_thru_bios; #ifdef CONFIG_SMP @@ -138,18 +138,18 @@ core_initcall(reboot_init); doesn't work with at least one type of 486 motherboard. It is easy to stop this code working; hence the copious comments. */ -static unsigned long long +static const unsigned long long real_mode_gdt_entries [3] = { 0x0000000000000000ULL, /* Null descriptor */ - 0x00009a000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ - 0x000092000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ + 0x00009b000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ + 0x000093000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ }; static struct { unsigned short size __attribute__ ((packed)); - unsigned long long * base __attribute__ ((packed)); + const unsigned long long * base __attribute__ ((packed)); } real_mode_gdt = { sizeof (real_mode_gdt_entries) - 1, real_mode_gdt_entries }, real_mode_idt = { 0x3ff, NULL }, @@ -175,7 +175,7 @@ no_idt = { 0, NULL }; More could be done here to set up the registers as if a CPU reset had occurred; hopefully real BIOSs don't assume much. */ -static unsigned char real_mode_switch [] = +static const unsigned char real_mode_switch [] = { 0x66, 0x0f, 0x20, 0xc0, /* movl %cr0,%eax */ 0x66, 0x83, 0xe0, 0x11, /* andl $0x00000011,%eax */ @@ -189,7 +189,7 @@ static unsigned char real_mode_switch [] 0x24, 0x10, /* f: andb $0x10,al */ 0x66, 0x0f, 0x22, 0xc0 /* movl %eax,%cr0 */ }; -static unsigned char jump_to_bios [] = +static const unsigned char jump_to_bios [] = { 0xea, 0x00, 0x00, 0xff, 0xff /* ljmp $0xffff,$0x0000 */ }; @@ -199,10 +199,14 @@ static unsigned char jump_to_bios [] = * specified by the code and length parameters. * We assume that length will aways be less that 100! */ -void machine_real_restart(unsigned char *code, int length) +void machine_real_restart(const unsigned char *code, unsigned int length) { unsigned long flags; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + local_irq_disable(); /* Write zero to CMOS register number 0x0f, which the BIOS POST @@ -223,8 +227,16 @@ void machine_real_restart(unsigned char from the kernel segment. This assumes the kernel segment starts at virtual address PAGE_OFFSET. */ - memcpy (swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - sizeof (swapper_pg_dir [0]) * KERNEL_PGD_PTRS); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, + USER_PGD_PTRS >= KERNEL_PGD_PTRS ? KERNEL_PGD_PTRS : USER_PGD_PTRS); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif /* * Use `swapper_pg_dir' as our page directory. @@ -237,7 +249,7 @@ void machine_real_restart(unsigned char REBOOT.COM programs, and the previous reset routine did this too. */ - *((unsigned short *)0x472) = reboot_mode; + __put_user(reboot_mode, (unsigned short __user *)0x472); /* For the switch to real mode, copy some code to low memory. It has to be in the first 64k because it is running in 16-bit mode, and it @@ -245,9 +257,9 @@ void machine_real_restart(unsigned char off paging. Copy it near the end of the first page, out of the way of BIOS variables. */ - memcpy ((void *) (0x1000 - sizeof (real_mode_switch) - 100), + flags = __copy_to_user ((void __user *) (0x1000 - sizeof (real_mode_switch) - 100), real_mode_switch, sizeof (real_mode_switch)); - memcpy ((void *) (0x1000 - 100), code, length); + flags = __copy_to_user ((void __user *) (0x1000 - 100), code, length); /* Set up the IDT for real mode. */ @@ -329,7 +341,7 @@ void machine_emergency_restart(void) __asm__ __volatile__("int3"); } /* rebooting needs to touch the page at absolute addr 0 */ - *((unsigned short *)__va(0x472)) = reboot_mode; + __put_user(reboot_mode, (unsigned short __user *)0x472); for (;;) { mach_reboot_fixups(); /* for board specific fixups */ mach_reboot(); diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/setup.c linux-2.6.17.11-g-v/arch/i386/kernel/setup.c --- linux-2.6.17.11/arch/i386/kernel/setup.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/setup.c 2006-08-28 14:44:48.000000000 +0200 @@ -88,7 +88,11 @@ struct cpuinfo_x86 new_cpu_data __initda struct cpuinfo_x86 boot_cpu_data __read_mostly = { 0, 0, 0, 0, -1, 1, 0, 0, -1 }; EXPORT_SYMBOL(boot_cpu_data); +#ifdef CONFIG_X86_PAE +unsigned long mmu_cr4_features = X86_CR4_PAE; +#else unsigned long mmu_cr4_features; +#endif #ifdef CONFIG_ACPI int acpi_disabled = 0; @@ -1493,14 +1497,14 @@ void __init setup_arch(char **cmdline_p) if (!MOUNT_ROOT_RDONLY) root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; + init_mm.start_code = (unsigned long) _text + __KERNEL_TEXT_OFFSET; + init_mm.end_code = (unsigned long) _etext + __KERNEL_TEXT_OFFSET; init_mm.end_data = (unsigned long) _edata; init_mm.brk = init_pg_tables_end + PAGE_OFFSET; - code_resource.start = virt_to_phys(_text); - code_resource.end = virt_to_phys(_etext)-1; - data_resource.start = virt_to_phys(_etext); + code_resource.start = virt_to_phys(_text + __KERNEL_TEXT_OFFSET); + code_resource.end = virt_to_phys(_etext + __KERNEL_TEXT_OFFSET)-1; + data_resource.start = virt_to_phys(_data); data_resource.end = virt_to_phys(_edata)-1; parse_cmdline_early(cmdline_p); diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/signal.c linux-2.6.17.11-g-v/arch/i386/kernel/signal.c --- linux-2.6.17.11/arch/i386/kernel/signal.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/signal.c 2006-08-28 14:44:48.000000000 +0200 @@ -351,7 +351,17 @@ static int setup_frame(int sig, struct k goto give_sigsegv; } +#ifdef CONFIG_PAX_NOVSYSCALL + restorer = frame->retcode; +#else restorer = &__kernel_sigreturn; + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) + restorer -= SEGMEXEC_TASK_SIZE; +#endif +#endif + if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; @@ -447,7 +457,18 @@ static int setup_rt_frame(int sig, struc goto give_sigsegv; /* Set up to return from userspace. */ + +#ifdef CONFIG_PAX_NOVSYSCALL + restorer = frame->retcode; +#else restorer = &__kernel_rt_sigreturn; + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) + restorer -= SEGMEXEC_TASK_SIZE; +#endif +#endif + if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; err |= __put_user(restorer, &frame->pretcode); @@ -580,7 +601,7 @@ static void fastcall do_signal(struct pt * before reaching here, so testing against kernel * CS suffices. */ - if (!user_mode(regs)) + if (!user_mode_novm(regs)) return; if (test_thread_flag(TIF_RESTORE_SIGMASK)) diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/smpboot.c linux-2.6.17.11-g-v/arch/i386/kernel/smpboot.c --- linux-2.6.17.11/arch/i386/kernel/smpboot.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/smpboot.c 2006-08-28 14:44:48.000000000 +0200 @@ -1069,7 +1069,7 @@ static int __cpuinit __smp_prepare_cpu(i /* init low mem mapping */ clone_pgd_range(swapper_pg_dir, swapper_pg_dir + USER_PGD_PTRS, - KERNEL_PGD_PTRS); + USER_PGD_PTRS >= KERNEL_PGD_PTRS ? KERNEL_PGD_PTRS : USER_PGD_PTRS); flush_tlb_all(); schedule_work(&task); wait_for_completion(&done); diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/sys_i386.c linux-2.6.17.11-g-v/arch/i386/kernel/sys_i386.c --- linux-2.6.17.11/arch/i386/kernel/sys_i386.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/sys_i386.c 2006-08-28 14:56:36.000000000 +0200 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -99,6 +100,191 @@ out: return err; } +unsigned long +arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start_addr, task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + task_size = SEGMEXEC_TASK_SIZE; +#endif + + if (len > task_size) + return -ENOMEM; + +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP) || !filp) +#endif + + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (task_size - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + if (len > mm->cached_hole_size) { + start_addr = addr = mm->free_area_cache; + } else { + start_addr = addr = mm->mmap_base; + mm->cached_hole_size = 0; + } + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && (flags & MAP_EXECUTABLE) && start_addr >= mm->mmap_base) { + start_addr = 0x00110000UL; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + start_addr += mm->delta_mmap & 0x03FFF000UL; +#endif + + if (mm->start_brk <= start_addr && start_addr < mm->mmap_base) + start_addr = addr = mm->mmap_base; + else + addr = start_addr; + } +#endif + +full_search: + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (task_size - len < addr) { + /* + * Start a new search - just in case we missed + * some holes. + */ + if (start_addr != mm->mmap_base) { + start_addr = addr = mm->mmap_base; + mm->cached_hole_size = 0; + goto full_search; + } + return -ENOMEM; + } + if (!vma || addr + len <= vma->vm_start) { + /* + * Remember the place where we stopped the search: + */ + mm->free_area_cache = addr + len; + return addr; + } + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + addr = vma->vm_end; + if (mm->start_brk <= addr && addr < mm->mmap_base) { + start_addr = addr = mm->mmap_base; + goto full_search; + } + } +} + +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + unsigned long base = mm->mmap_base, addr = addr0, task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + task_size = SEGMEXEC_TASK_SIZE; +#endif + + /* requested length too big for entire address space */ + if (len > task_size) + return -ENOMEM; + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && (flags & MAP_EXECUTABLE)) + goto bottomup; +#endif + +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP) || !filp) +#endif + + /* requesting a specific address */ + if (addr) { + addr = PAGE_ALIGN(addr); + vma = find_vma(mm, addr); + if (task_size - len >= addr && + (!vma || addr + len <= vma->vm_start)) + return addr; + } + + /* check if free_area_cache is useful for us */ + if (len <= mm->cached_hole_size) { + mm->cached_hole_size = 0; + mm->free_area_cache = mm->mmap_base; + } + + /* either no address requested or can't fit in requested address hole */ + addr = mm->free_area_cache; + + /* make sure it can fit in the remaining address space */ + if (addr > len) { + vma = find_vma(mm, addr-len); + if (!vma || addr <= vma->vm_start) + /* remember the address as a hint for next time */ + return (mm->free_area_cache = addr-len); + } + + if (mm->mmap_base < len) + goto bottomup; + + addr = mm->mmap_base-len; + + do { + /* + * Lookup failure means no vma is above this address, + * else if new region fits below vma->vm_start, + * return with success: + */ + vma = find_vma(mm, addr); + if (!vma || addr+len <= vma->vm_start) + /* remember the address as a hint for next time */ + return (mm->free_area_cache = addr); + + /* remember the largest hole we saw so far */ + if (addr + mm->cached_hole_size < vma->vm_start) + mm->cached_hole_size = vma->vm_start - addr; + + /* try just below the current vma->vm_start */ + addr = vma->vm_start-len; + } while (len < vma->vm_start); + +bottomup: + /* + * A failed mmap() very likely causes application failure, + * so fall back to the bottom-up function here. This scenario + * can happen with large stack limits and large mmap() + * allocations. + */ + 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->free_area_cache = mm->mmap_base; + mm->cached_hole_size = ~0UL; + addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); + /* + * Restore the topdown base: + */ + mm->mmap_base = base; + mm->free_area_cache = base; + mm->cached_hole_size = ~0UL; + + return addr; +} struct sel_arg_struct { unsigned long n; @@ -210,7 +396,7 @@ asmlinkage int sys_uname(struct old_utsn if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } @@ -218,6 +404,7 @@ asmlinkage int sys_uname(struct old_utsn asmlinkage int sys_olduname(struct oldold_utsname __user * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -226,15 +413,16 @@ asmlinkage int sys_olduname(struct oldol down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN); error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN); error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error |= __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN); error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error |= __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN); error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error |= __copy_to_user(&name->machine,ptr->machine,__OLD_UTS_LEN); error |= __put_user(0,name->machine+__OLD_UTS_LEN); up_read(&uts_sem); diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/syscall_table.S linux-2.6.17.11-g-v/arch/i386/kernel/syscall_table.S --- linux-2.6.17.11/arch/i386/kernel/syscall_table.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/syscall_table.S 2006-08-28 14:56:36.000000000 +0200 @@ -1,3 +1,4 @@ +.section .rodata,"a",@progbits ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit @@ -272,7 +273,7 @@ ENTRY(sys_call_table) .long sys_tgkill /* 270 */ .long sys_utimes .long sys_fadvise64_64 - .long sys_ni_syscall /* sys_vserver */ + .long sys_vserver .long sys_mbind .long sys_get_mempolicy .long sys_set_mempolicy diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/sysenter.c linux-2.6.17.11-g-v/arch/i386/kernel/sysenter.c --- linux-2.6.17.11/arch/i386/kernel/sysenter.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/sysenter.c 2006-08-28 14:44:48.000000000 +0200 @@ -24,7 +24,7 @@ extern asmlinkage void sysenter_entry(vo void enable_sep_cpu(void) { int cpu = get_cpu(); - struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct tss_struct *tss = init_tss + cpu; if (!boot_cpu_has(X86_FEATURE_SEP)) { put_cpu(); @@ -48,6 +48,7 @@ extern const char vsyscall_sysenter_star int __init sysenter_setup(void) { +#ifndef CONFIG_PAX_NOVSYSCALL void *page = (void *)get_zeroed_page(GFP_ATOMIC); __set_fixmap(FIX_VSYSCALL, __pa(page), PAGE_READONLY_EXEC); @@ -62,6 +63,7 @@ int __init sysenter_setup(void) memcpy(page, &vsyscall_sysenter_start, &vsyscall_sysenter_end - &vsyscall_sysenter_start); +#endif return 0; } diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/traps.c linux-2.6.17.11-g-v/arch/i386/kernel/traps.c --- linux-2.6.17.11/arch/i386/kernel/traps.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/traps.c 2006-09-05 09:59:03.000000000 +0200 @@ -28,6 +28,7 @@ #include #include #include +#include #ifdef CONFIG_EISA #include @@ -53,23 +54,19 @@ #include #include +#include #include "mach_traps.h" asmlinkage int system_call(void); -struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, +const struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 }, { 0, 0 } }; /* Do we ignore FPU interrupts ? */ char ignore_fpu_irq = 0; -/* - * The IDT has to be page-aligned to simplify the Pentium - * F0 0F bug workaround.. We have a special link segment - * for this. - */ -struct desc_struct idt_table[256] __attribute__((__section__(".data.idt"))) = { {0, 0}, }; +extern struct desc_struct idt_table[256]; asmlinkage void divide_error(void); asmlinkage void debug(void); @@ -144,18 +141,22 @@ static inline unsigned long print_contex { unsigned long addr; int printed = 0; /* nr of entries already printed on current line */ + int i = kstack_depth_to_print; #ifdef CONFIG_FRAME_POINTER while (valid_stack_ptr(tinfo, (void *)ebp)) { addr = *(unsigned long *)(ebp + 4); printed = print_addr_and_symbol(addr, log_lvl, printed); ebp = *(unsigned long *)ebp; + --i; } #else while (valid_stack_ptr(tinfo, stack)) { addr = *stack++; - if (__kernel_text_address(addr)) + if (__kernel_text_address(addr + __KERNEL_TEXT_OFFSET)) { printed = print_addr_and_symbol(addr, log_lvl, printed); + --i; + } } #endif if (printed) @@ -249,7 +250,7 @@ void show_registers(struct pt_regs *regs esp = (unsigned long) (®s->esp); savesegment(ss, ss); - if (user_mode_vm(regs)) { + if (user_mode(regs)) { in_kernel = 0; esp = regs->esp; ss = regs->xss & 0xffff; @@ -268,21 +269,24 @@ void show_registers(struct pt_regs *regs regs->esi, regs->edi, regs->ebp, esp); printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n", regs->xds & 0xffff, regs->xes & 0xffff, ss); - printk(KERN_EMERG "Process %s (pid: %d, threadinfo=%p task=%p)", - current->comm, current->pid, current_thread_info(), current); + printk(KERN_EMERG "Process %s (pid: %d[#%u], threadinfo=%p task=%p)", + current->comm, current->pid, current->xid, + current_thread_info(), current); /* * When in-kernel, we also print out the stack and code at the * time of the fault.. */ if (in_kernel) { u8 __user *eip; + mm_segment_t old_fs = get_fs(); printk("\n" KERN_EMERG "Stack: "); show_stack_log_lvl(NULL, (unsigned long *)esp, KERN_EMERG); printk(KERN_EMERG "Code: "); - eip = (u8 __user *)regs->eip - 43; + set_fs(KERNEL_DS); + eip = (u8 __user *)regs->eip - 43 + __KERNEL_TEXT_OFFSET; for (i = 0; i < 64; i++, eip++) { unsigned char c; @@ -290,11 +294,12 @@ void show_registers(struct pt_regs *regs printk(" Bad EIP value."); break; } - if (eip == (u8 __user *)regs->eip) + if (eip == (u8 __user *)regs->eip + __KERNEL_TEXT_OFFSET) printk("<%02x> ", c); else printk("%02x ", c); } + set_fs(old_fs); } printk("\n"); } @@ -306,29 +311,34 @@ static void handle_BUG(struct pt_regs *r char *file; char c; unsigned long eip; + mm_segment_t old_fs = get_fs(); - eip = regs->eip; + eip = regs->eip + __KERNEL_TEXT_OFFSET; + set_fs(KERNEL_DS); if (eip < PAGE_OFFSET) goto no_bug; if (__get_user(ud2, (unsigned short __user *)eip)) goto no_bug; if (ud2 != 0x0b0f) goto no_bug; - if (__get_user(line, (unsigned short __user *)(eip + 2))) + if (__get_user(line, (unsigned short __user *)(eip + 7))) goto bug; - if (__get_user(file, (char * __user *)(eip + 4)) || - (unsigned long)file < PAGE_OFFSET || __get_user(c, file)) + if (__get_user(file, (char * __user *)(eip + 3)) || file < _text + __KERNEL_TEXT_OFFSET) + goto bug; + if (__get_user(c, file)) file = ""; printk(KERN_EMERG "------------[ cut here ]------------\n"); printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); no_bug: + set_fs(old_fs); return; /* Here we know it was a BUG but file-n-line is unavailable */ bug: + set_fs(old_fs); printk(KERN_EMERG "Kernel BUG\n"); } @@ -351,6 +361,8 @@ void die(const char * str, struct pt_reg oops_enter(); + vxh_throw_oops(); + if (die.lock_owner != raw_smp_processor_id()) { console_verbose(); spin_lock_irqsave(&die.lock, flags); @@ -387,9 +399,9 @@ void die(const char * str, struct pt_reg if (nl) printk("\n"); if (notify_die(DIE_OOPS, str, regs, err, - current->thread.trap_no, SIGSEGV) != - NOTIFY_STOP) { + current->thread.trap_no, SIGSEGV) != NOTIFY_STOP) { show_registers(regs); + vxh_dump_history(); /* Executive summary in case the oops scrolled away */ esp = (unsigned long) (®s->esp); savesegment(ss, ss); @@ -430,7 +442,7 @@ void die(const char * str, struct pt_reg static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) { - if (!user_mode_vm(regs)) + if (!user_mode(regs)) die(str, regs, err); } @@ -448,7 +460,7 @@ static void __kprobes do_trap(int trapnr goto trap_signal; } - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto kernel_trap; trap_signal: { @@ -536,7 +548,7 @@ fastcall void __kprobes do_general_prote long error_code) { int cpu = get_cpu(); - struct tss_struct *tss = &per_cpu(init_tss, cpu); + struct tss_struct *tss = &init_tss[cpu]; struct thread_struct *thread = ¤t->thread; /* @@ -572,9 +584,25 @@ fastcall void __kprobes do_general_prote if (regs->eflags & VM_MASK) goto gp_in_vm86; - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto gp_in_kernel; +#ifdef CONFIG_PAX_PAGEEXEC + if (current->mm && (current->mm->pax_flags & MF_PAX_PAGEEXEC)) { + struct mm_struct *mm = current->mm; + unsigned long limit; + + down_write(&mm->mmap_sem); + limit = mm->context.user_cs_limit; + if (limit < TASK_SIZE) { + track_exec_limit(mm, limit, TASK_SIZE, PROT_EXEC); + up_write(&mm->mmap_sem); + return; + } + up_write(&mm->mmap_sem); + } +#endif + current->thread.error_code = error_code; current->thread.trap_no = 13; force_sig(SIGSEGV, current); @@ -590,6 +618,13 @@ gp_in_kernel: if (notify_die(DIE_GPF, "general protection fault", regs, error_code, 13, SIGSEGV) == NOTIFY_STOP) return; + +#ifdef CONFIG_PAX_KERNEXEC + if ((regs->xcs & 0xFFFF) == __KERNEL_CS) + die("PAX: suspicious general protection fault", regs, error_code); + else +#endif + die("general protection fault", regs, error_code); } } @@ -663,7 +698,7 @@ void die_nmi (struct pt_regs *regs, cons /* If we are in kernel we are probably nested up pretty bad * and might aswell get out now while we still can. */ - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { current->thread.trap_no = 2; crash_kexec(regs); } @@ -816,7 +851,7 @@ fastcall void __kprobes do_debug(struct * check for kernel mode by just checking the CPL * of CS. */ - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto clear_TF_reenable; } @@ -1106,7 +1141,19 @@ do { \ */ void set_intr_gate(unsigned int n, void *addr) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } /* diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/traps.c.orig linux-2.6.17.11-g-v/arch/i386/kernel/traps.c.orig --- linux-2.6.17.11/arch/i386/kernel/traps.c.orig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17.11-g-v/arch/i386/kernel/traps.c.orig 2006-08-28 16:03:19.000000000 +0200 @@ -0,0 +1,1257 @@ +/* + * linux/arch/i386/traps.c + * + * Copyright (C) 1991, 1992 Linus Torvalds + * + * Pentium III FXSR, SSE support + * Gareth Hughes , May 2000 + */ + +/* + * 'Traps.c' handles hardware traps and faults after we have saved some + * state in 'asm.s'. + */ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_EISA +#include +#include +#endif + +#ifdef CONFIG_MCA +#include +#endif + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include + +#include "mach_traps.h" + +asmlinkage int system_call(void); + +const struct desc_struct default_ldt[] = { { 0, 0 }, { 0, 0 }, { 0, 0 }, + { 0, 0 }, { 0, 0 } }; + +/* Do we ignore FPU interrupts ? */ +char ignore_fpu_irq = 0; + +extern struct desc_struct idt_table[256]; + +asmlinkage void divide_error(void); +asmlinkage void debug(void); +asmlinkage void nmi(void); +asmlinkage void int3(void); +asmlinkage void overflow(void); +asmlinkage void bounds(void); +asmlinkage void invalid_op(void); +asmlinkage void device_not_available(void); +asmlinkage void coprocessor_segment_overrun(void); +asmlinkage void invalid_TSS(void); +asmlinkage void segment_not_present(void); +asmlinkage void stack_segment(void); +asmlinkage void general_protection(void); +asmlinkage void page_fault(void); +asmlinkage void coprocessor_error(void); +asmlinkage void simd_coprocessor_error(void); +asmlinkage void alignment_check(void); +asmlinkage void spurious_interrupt_bug(void); +asmlinkage void machine_check(void); + +static int kstack_depth_to_print = 24; +ATOMIC_NOTIFIER_HEAD(i386die_chain); + +int register_die_notifier(struct notifier_block *nb) +{ + vmalloc_sync_all(); + return atomic_notifier_chain_register(&i386die_chain, nb); +} +EXPORT_SYMBOL(register_die_notifier); + +int unregister_die_notifier(struct notifier_block *nb) +{ + return atomic_notifier_chain_unregister(&i386die_chain, nb); +} +EXPORT_SYMBOL(unregister_die_notifier); + +static inline int valid_stack_ptr(struct thread_info *tinfo, void *p) +{ + return p > (void *)tinfo && + p < (void *)tinfo + THREAD_SIZE - 3; +} + +/* + * Print CONFIG_STACK_BACKTRACE_COLS address/symbol entries per line. + */ +static inline int print_addr_and_symbol(unsigned long addr, char *log_lvl, + int printed) +{ + if (!printed) + printk(log_lvl); + +#if CONFIG_STACK_BACKTRACE_COLS == 1 + printk(" [<%08lx>] ", addr); +#else + printk(" <%08lx> ", addr); +#endif + print_symbol("%s", addr); + + printed = (printed + 1) % CONFIG_STACK_BACKTRACE_COLS; + if (printed) + printk(" "); + else + printk("\n"); + + return printed; +} + +static inline unsigned long print_context_stack(struct thread_info *tinfo, + unsigned long *stack, unsigned long ebp, + char *log_lvl) +{ + unsigned long addr; + int printed = 0; /* nr of entries already printed on current line */ + int i = kstack_depth_to_print; + +#ifdef CONFIG_FRAME_POINTER + while (valid_stack_ptr(tinfo, (void *)ebp)) { + addr = *(unsigned long *)(ebp + 4); + printed = print_addr_and_symbol(addr, log_lvl, printed); + ebp = *(unsigned long *)ebp; + --i; + } +#else + while (valid_stack_ptr(tinfo, stack)) { + addr = *stack++; + if (__kernel_text_address(addr + __KERNEL_TEXT_OFFSET)) { + printed = print_addr_and_symbol(addr, log_lvl, printed); + --i; + } + } +#endif + if (printed) + printk("\n"); + + return ebp; +} + +static void show_trace_log_lvl(struct task_struct *task, + unsigned long *stack, char *log_lvl) +{ + unsigned long ebp; + + if (!task) + task = current; + + if (task == current) { + /* Grab ebp right from our regs */ + asm ("movl %%ebp, %0" : "=r" (ebp) : ); + } else { + /* ebp is the last reg pushed by switch_to */ + ebp = *(unsigned long *) task->thread.esp; + } + + while (1) { + struct thread_info *context; + context = (struct thread_info *) + ((unsigned long)stack & (~(THREAD_SIZE - 1))); + ebp = print_context_stack(context, stack, ebp, log_lvl); + stack = (unsigned long*)context->previous_esp; + if (!stack) + break; + printk("%s =======================\n", log_lvl); + } +} + +void show_trace(struct task_struct *task, unsigned long * stack) +{ + show_trace_log_lvl(task, stack, ""); +} + +static void show_stack_log_lvl(struct task_struct *task, unsigned long *esp, + char *log_lvl) +{ + unsigned long *stack; + int i; + + if (esp == NULL) { + if (task) + esp = (unsigned long*)task->thread.esp; + else + esp = (unsigned long *)&esp; + } + + stack = esp; + for(i = 0; i < kstack_depth_to_print; i++) { + if (kstack_end(stack)) + break; + if (i && ((i % 8) == 0)) + printk("\n%s ", log_lvl); + printk("%08lx ", *stack++); + } + printk("\n%sCall Trace:\n", log_lvl); + show_trace_log_lvl(task, esp, log_lvl); +} + +void show_stack(struct task_struct *task, unsigned long *esp) +{ + printk(" "); + show_stack_log_lvl(task, esp, ""); +} + +/* + * The architecture-independent dump_stack generator + */ +void dump_stack(void) +{ + unsigned long stack; + + show_trace(current, &stack); +} + +EXPORT_SYMBOL(dump_stack); + +void show_registers(struct pt_regs *regs) +{ + int i; + int in_kernel = 1; + unsigned long esp; + unsigned short ss; + + esp = (unsigned long) (®s->esp); + savesegment(ss, ss); + if (user_mode(regs)) { + in_kernel = 0; + esp = regs->esp; + ss = regs->xss & 0xffff; + } + print_modules(); + printk(KERN_EMERG "CPU: %d\nEIP: %04x:[<%08lx>] %s VLI\n" + "EFLAGS: %08lx (%s %.*s) \n", + smp_processor_id(), 0xffff & regs->xcs, regs->eip, + print_tainted(), regs->eflags, system_utsname.release, + (int)strcspn(system_utsname.version, " "), + system_utsname.version); + print_symbol(KERN_EMERG "EIP is at %s\n", regs->eip); + printk(KERN_EMERG "eax: %08lx ebx: %08lx ecx: %08lx edx: %08lx\n", + regs->eax, regs->ebx, regs->ecx, regs->edx); + printk(KERN_EMERG "esi: %08lx edi: %08lx ebp: %08lx esp: %08lx\n", + regs->esi, regs->edi, regs->ebp, esp); + printk(KERN_EMERG "ds: %04x es: %04x ss: %04x\n", + regs->xds & 0xffff, regs->xes & 0xffff, ss); + printk(KERN_EMERG "Process %s (pid: %d[#%u], threadinfo=%p task=%p)", + current->comm, current->pid, current->xid, + current_thread_info(), current); + /* + * When in-kernel, we also print out the stack and code at the + * time of the fault.. + */ + if (in_kernel) { + u8 __user *eip; + mm_segment_t old_fs = get_fs(); + + printk("\n" KERN_EMERG "Stack: "); + show_stack_log_lvl(NULL, (unsigned long *)esp, KERN_EMERG); + + printk(KERN_EMERG "Code: "); + + set_fs(KERNEL_DS); + eip = (u8 __user *)regs->eip - 43 + __KERNEL_TEXT_OFFSET; + for (i = 0; i < 64; i++, eip++) { + unsigned char c; + + if (eip < (u8 __user *)PAGE_OFFSET || __get_user(c, eip)) { + printk(" Bad EIP value."); + break; + } + if (eip == (u8 __user *)regs->eip + __KERNEL_TEXT_OFFSET) + printk("<%02x> ", c); + else + printk("%02x ", c); + } + set_fs(old_fs); + } + printk("\n"); +} + +static void handle_BUG(struct pt_regs *regs) +{ + unsigned short ud2; + unsigned short line; + char *file; + char c; + unsigned long eip; + mm_segment_t old_fs = get_fs(); + + eip = regs->eip + __KERNEL_TEXT_OFFSET; + + set_fs(KERNEL_DS); + if (eip < PAGE_OFFSET) + goto no_bug; + if (__get_user(ud2, (unsigned short __user *)eip)) + goto no_bug; + if (ud2 != 0x0b0f) + goto no_bug; + if (__get_user(line, (unsigned short __user *)(eip + 3))) + goto bug; + if (__get_user(file, (char * __user *)(eip + 8)) || file < _text + __KERNEL_TEXT_OFFSET) + goto bug; + if (__get_user(c, file)) + file = ""; + + printk(KERN_EMERG "------------[ cut here ]------------\n"); + printk(KERN_EMERG "kernel BUG at %s:%d!\n", file, line); + +no_bug: + set_fs(old_fs); + return; + + /* Here we know it was a BUG but file-n-line is unavailable */ +bug: + set_fs(old_fs); + printk(KERN_EMERG "Kernel BUG\n"); +} + +/* This is gone through when something in the kernel + * has done something bad and is about to be terminated. +*/ +void die(const char * str, struct pt_regs * regs, long err) +{ + static struct { + spinlock_t lock; + u32 lock_owner; + int lock_owner_depth; + } die = { + .lock = SPIN_LOCK_UNLOCKED, + .lock_owner = -1, + .lock_owner_depth = 0 + }; + static int die_counter; + unsigned long flags; + + oops_enter(); + + vxh_throw_oops(); + + if (die.lock_owner != raw_smp_processor_id()) { + console_verbose(); + spin_lock_irqsave(&die.lock, flags); + die.lock_owner = smp_processor_id(); + die.lock_owner_depth = 0; + bust_spinlocks(1); + } + else + local_save_flags(flags); + + if (++die.lock_owner_depth < 3) { + int nl = 0; + unsigned long esp; + unsigned short ss; + + handle_BUG(regs); + printk(KERN_EMERG "%s: %04lx [#%d]\n", str, err & 0xffff, ++die_counter); +#ifdef CONFIG_PREEMPT + printk(KERN_EMERG "PREEMPT "); + nl = 1; +#endif +#ifdef CONFIG_SMP + if (!nl) + printk(KERN_EMERG); + printk("SMP "); + nl = 1; +#endif +#ifdef CONFIG_DEBUG_PAGEALLOC + if (!nl) + printk(KERN_EMERG); + printk("DEBUG_PAGEALLOC"); + nl = 1; +#endif + if (nl) + printk("\n"); + if (notify_die(DIE_OOPS, str, regs, err, + current->thread.trap_no, SIGSEGV) != NOTIFY_STOP) { + show_registers(regs); + vxh_dump_history(); + /* Executive summary in case the oops scrolled away */ + esp = (unsigned long) (®s->esp); + savesegment(ss, ss); + if (user_mode(regs)) { + esp = regs->esp; + ss = regs->xss & 0xffff; + } + printk(KERN_EMERG "EIP: [<%08lx>] ", regs->eip); + print_symbol("%s", regs->eip); + printk(" SS:ESP %04x:%08lx\n", ss, esp); + } + else + regs = NULL; + } else + printk(KERN_EMERG "Recursive die() failure, output suppressed\n"); + + bust_spinlocks(0); + die.lock_owner = -1; + spin_unlock_irqrestore(&die.lock, flags); + + if (!regs) + return; + + if (kexec_should_crash(current)) + crash_kexec(regs); + + if (in_interrupt()) + panic("Fatal exception in interrupt"); + + if (panic_on_oops) { + printk(KERN_EMERG "Fatal exception: panic in 5 seconds\n"); + ssleep(5); + panic("Fatal exception"); + } + oops_exit(); + do_exit(SIGSEGV); +} + +static inline void die_if_kernel(const char * str, struct pt_regs * regs, long err) +{ + if (!user_mode(regs)) + die(str, regs, err); +} + +static void __kprobes do_trap(int trapnr, int signr, char *str, int vm86, + struct pt_regs * regs, long error_code, + siginfo_t *info) +{ + struct task_struct *tsk = current; + tsk->thread.error_code = error_code; + tsk->thread.trap_no = trapnr; + + if (regs->eflags & VM_MASK) { + if (vm86) + goto vm86_trap; + goto trap_signal; + } + + if (!user_mode_novm(regs)) + goto kernel_trap; + + trap_signal: { + if (info) + force_sig_info(signr, info, tsk); + else + force_sig(signr, tsk); + return; + } + + kernel_trap: { + if (!fixup_exception(regs)) + die(str, regs, error_code); + return; + } + + vm86_trap: { + int ret = handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, trapnr); + if (ret) goto trap_signal; + return; + } +} + +#define DO_ERROR(trapnr, signr, str, name) \ +fastcall void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ + do_trap(trapnr, signr, str, 0, regs, error_code, NULL); \ +} + +#define DO_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ +fastcall void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)siaddr; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ + do_trap(trapnr, signr, str, 0, regs, error_code, &info); \ +} + +#define DO_VM86_ERROR(trapnr, signr, str, name) \ +fastcall void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ + do_trap(trapnr, signr, str, 1, regs, error_code, NULL); \ +} + +#define DO_VM86_ERROR_INFO(trapnr, signr, str, name, sicode, siaddr) \ +fastcall void do_##name(struct pt_regs * regs, long error_code) \ +{ \ + siginfo_t info; \ + info.si_signo = signr; \ + info.si_errno = 0; \ + info.si_code = sicode; \ + info.si_addr = (void __user *)siaddr; \ + if (notify_die(DIE_TRAP, str, regs, error_code, trapnr, signr) \ + == NOTIFY_STOP) \ + return; \ + do_trap(trapnr, signr, str, 1, regs, error_code, &info); \ +} + +DO_VM86_ERROR_INFO( 0, SIGFPE, "divide error", divide_error, FPE_INTDIV, regs->eip) +#ifndef CONFIG_KPROBES +DO_VM86_ERROR( 3, SIGTRAP, "int3", int3) +#endif +DO_VM86_ERROR( 4, SIGSEGV, "overflow", overflow) +DO_VM86_ERROR( 5, SIGSEGV, "bounds", bounds) +DO_ERROR_INFO( 6, SIGILL, "invalid opcode", invalid_op, ILL_ILLOPN, regs->eip) +DO_ERROR( 9, SIGFPE, "coprocessor segment overrun", coprocessor_segment_overrun) +DO_ERROR(10, SIGSEGV, "invalid TSS", invalid_TSS) +DO_ERROR(11, SIGBUS, "segment not present", segment_not_present) +DO_ERROR(12, SIGBUS, "stack segment", stack_segment) +DO_ERROR_INFO(17, SIGBUS, "alignment check", alignment_check, BUS_ADRALN, 0) +DO_ERROR_INFO(32, SIGSEGV, "iret exception", iret_error, ILL_BADSTK, 0) + +fastcall void __kprobes do_general_protection(struct pt_regs * regs, + long error_code) +{ + int cpu = get_cpu(); + struct tss_struct *tss = &init_tss[cpu]; + struct thread_struct *thread = ¤t->thread; + + /* + * Perform the lazy TSS's I/O bitmap copy. If the TSS has an + * invalid offset set (the LAZY one) and the faulting thread has + * a valid I/O bitmap pointer, we copy the I/O bitmap in the TSS + * and we set the offset field correctly. Then we let the CPU to + * restart the faulting instruction. + */ + if (tss->io_bitmap_base == INVALID_IO_BITMAP_OFFSET_LAZY && + thread->io_bitmap_ptr) { + memcpy(tss->io_bitmap, thread->io_bitmap_ptr, + thread->io_bitmap_max); + /* + * If the previously set map was extending to higher ports + * than the current one, pad extra space with 0xff (no access). + */ + if (thread->io_bitmap_max < tss->io_bitmap_max) + memset((char *) tss->io_bitmap + + thread->io_bitmap_max, 0xff, + tss->io_bitmap_max - thread->io_bitmap_max); + tss->io_bitmap_max = thread->io_bitmap_max; + tss->io_bitmap_base = IO_BITMAP_OFFSET; + tss->io_bitmap_owner = thread; + put_cpu(); + return; + } + put_cpu(); + + current->thread.error_code = error_code; + current->thread.trap_no = 13; + + if (regs->eflags & VM_MASK) + goto gp_in_vm86; + + if (!user_mode_novm(regs)) + goto gp_in_kernel; + +#ifdef CONFIG_PAX_PAGEEXEC + if (current->mm && (current->mm->pax_flags & MF_PAX_PAGEEXEC)) { + struct mm_struct *mm = current->mm; + unsigned long limit; + + down_write(&mm->mmap_sem); + limit = mm->context.user_cs_limit; + if (limit < TASK_SIZE) { + track_exec_limit(mm, limit, TASK_SIZE, PROT_EXEC); + up_write(&mm->mmap_sem); + return; + } + up_write(&mm->mmap_sem); + } +#endif + + current->thread.error_code = error_code; + current->thread.trap_no = 13; + force_sig(SIGSEGV, current); + return; + +gp_in_vm86: + local_irq_enable(); + handle_vm86_fault((struct kernel_vm86_regs *) regs, error_code); + return; + +gp_in_kernel: + if (!fixup_exception(regs)) { + if (notify_die(DIE_GPF, "general protection fault", regs, + error_code, 13, SIGSEGV) == NOTIFY_STOP) + return; + +#ifdef CONFIG_PAX_KERNEXEC + if ((regs->xcs & 0xFFFF) == __KERNEL_CS) + die("PAX: suspicious general protection fault", regs, error_code); + else +#endif + + die("general protection fault", regs, error_code); + } +} + +static void mem_parity_error(unsigned char reason, struct pt_regs * regs) +{ + printk(KERN_EMERG "Uhhuh. NMI received. Dazed and confused, but trying " + "to continue\n"); + printk(KERN_EMERG "You probably have a hardware problem with your RAM " + "chips\n"); + + /* Clear and disable the memory parity error line. */ + clear_mem_error(reason); +} + +static void io_check_error(unsigned char reason, struct pt_regs * regs) +{ + unsigned long i; + + printk(KERN_EMERG "NMI: IOCK error (debug interrupt?)\n"); + show_registers(regs); + + /* Re-enable the IOCK line, wait for a few seconds */ + reason = (reason & 0xf) | 8; + outb(reason, 0x61); + i = 2000; + while (--i) udelay(1000); + reason &= ~8; + outb(reason, 0x61); +} + +static void unknown_nmi_error(unsigned char reason, struct pt_regs * regs) +{ +#ifdef CONFIG_MCA + /* Might actually be able to figure out what the guilty party + * is. */ + if( MCA_bus ) { + mca_handle_nmi(); + return; + } +#endif + printk("Uhhuh. NMI received for unknown reason %02x on CPU %d.\n", + reason, smp_processor_id()); + printk("Dazed and confused, but trying to continue\n"); + printk("Do you have a strange power saving mode enabled?\n"); +} + +static DEFINE_SPINLOCK(nmi_print_lock); + +void die_nmi (struct pt_regs *regs, const char *msg) +{ + if (notify_die(DIE_NMIWATCHDOG, msg, regs, 0, 2, SIGINT) == + NOTIFY_STOP) + return; + + spin_lock(&nmi_print_lock); + /* + * We are in trouble anyway, lets at least try + * to get a message out. + */ + bust_spinlocks(1); + printk(KERN_EMERG "%s", msg); + printk(" on CPU%d, eip %08lx, registers:\n", + smp_processor_id(), regs->eip); + show_registers(regs); + printk(KERN_EMERG "console shuts up ...\n"); + console_silent(); + spin_unlock(&nmi_print_lock); + bust_spinlocks(0); + + /* If we are in kernel we are probably nested up pretty bad + * and might aswell get out now while we still can. + */ + if (!user_mode(regs)) { + current->thread.trap_no = 2; + crash_kexec(regs); + } + + do_exit(SIGSEGV); +} + +static void default_do_nmi(struct pt_regs * regs) +{ + unsigned char reason = 0; + + /* Only the BSP gets external NMIs from the system. */ + if (!smp_processor_id()) + reason = get_nmi_reason(); + + if (!(reason & 0xc0)) { + if (notify_die(DIE_NMI_IPI, "nmi_ipi", regs, reason, 2, SIGINT) + == NOTIFY_STOP) + return; +#ifdef CONFIG_X86_LOCAL_APIC + /* + * Ok, so this is none of the documented NMI sources, + * so it must be the NMI watchdog. + */ + if (nmi_watchdog) { + nmi_watchdog_tick(regs); + return; + } +#endif + unknown_nmi_error(reason, regs); + return; + } + if (notify_die(DIE_NMI, "nmi", regs, reason, 2, SIGINT) == NOTIFY_STOP) + return; + if (reason & 0x80) + mem_parity_error(reason, regs); + if (reason & 0x40) + io_check_error(reason, regs); + /* + * Reassert NMI in case it became active meanwhile + * as it's edge-triggered. + */ + reassert_nmi(); +} + +static int dummy_nmi_callback(struct pt_regs * regs, int cpu) +{ + return 0; +} + +static nmi_callback_t nmi_callback = dummy_nmi_callback; + +fastcall void do_nmi(struct pt_regs * regs, long error_code) +{ + int cpu; + + nmi_enter(); + + cpu = smp_processor_id(); + + ++nmi_count(cpu); + + if (!rcu_dereference(nmi_callback)(regs, cpu)) + default_do_nmi(regs); + + nmi_exit(); +} + +void set_nmi_callback(nmi_callback_t callback) +{ + vmalloc_sync_all(); + rcu_assign_pointer(nmi_callback, callback); +} +EXPORT_SYMBOL_GPL(set_nmi_callback); + +void unset_nmi_callback(void) +{ + nmi_callback = dummy_nmi_callback; +} +EXPORT_SYMBOL_GPL(unset_nmi_callback); + +#ifdef CONFIG_KPROBES +fastcall void __kprobes do_int3(struct pt_regs *regs, long error_code) +{ + if (notify_die(DIE_INT3, "int3", regs, error_code, 3, SIGTRAP) + == NOTIFY_STOP) + return; + /* This is an interrupt gate, because kprobes wants interrupts + disabled. Normal trap handlers don't. */ + restore_interrupts(regs); + do_trap(3, SIGTRAP, "int3", 1, regs, error_code, NULL); +} +#endif + +/* + * Our handling of the processor debug registers is non-trivial. + * We do not clear them on entry and exit from the kernel. Therefore + * it is possible to get a watchpoint trap here from inside the kernel. + * However, the code in ./ptrace.c has ensured that the user can + * only set watchpoints on userspace addresses. Therefore the in-kernel + * watchpoint trap can only occur in code which is reading/writing + * from user space. Such code must not hold kernel locks (since it + * can equally take a page fault), therefore it is safe to call + * force_sig_info even though that claims and releases locks. + * + * Code in ./signal.c ensures that the debug control register + * is restored before we deliver any signal, and therefore that + * user code runs with the correct debug control register even though + * we clear it here. + * + * Being careful here means that we don't have to be as careful in a + * lot of more complicated places (task switching can be a bit lazy + * about restoring all the debug state, and ptrace doesn't have to + * find every occurrence of the TF bit that could be saved away even + * by user code) + */ +fastcall void __kprobes do_debug(struct pt_regs * regs, long error_code) +{ + unsigned int condition; + struct task_struct *tsk = current; + + get_debugreg(condition, 6); + + if (notify_die(DIE_DEBUG, "debug", regs, condition, error_code, + SIGTRAP) == NOTIFY_STOP) + return; + /* It's safe to allow irq's after DR6 has been saved */ + if (regs->eflags & X86_EFLAGS_IF) + local_irq_enable(); + + /* Mask out spurious debug traps due to lazy DR7 setting */ + if (condition & (DR_TRAP0|DR_TRAP1|DR_TRAP2|DR_TRAP3)) { + if (!tsk->thread.debugreg[7]) + goto clear_dr7; + } + + if (regs->eflags & VM_MASK) + goto debug_vm86; + + /* Save debug status register where ptrace can see it */ + tsk->thread.debugreg[6] = condition; + + /* + * Single-stepping through TF: make sure we ignore any events in + * kernel space (but re-enable TF when returning to user mode). + */ + if (condition & DR_STEP) { + /* + * We already checked v86 mode above, so we can + * check for kernel mode by just checking the CPL + * of CS. + */ + if (!user_mode_novm(regs)) + goto clear_TF_reenable; + } + + /* Ok, finally something we can handle */ + send_sigtrap(tsk, regs, error_code); + + /* Disable additional traps. They'll be re-enabled when + * the signal is delivered. + */ +clear_dr7: + set_debugreg(0, 7); + return; + +debug_vm86: + handle_vm86_trap((struct kernel_vm86_regs *) regs, error_code, 1); + return; + +clear_TF_reenable: + set_tsk_thread_flag(tsk, TIF_SINGLESTEP); + regs->eflags &= ~TF_MASK; + return; +} + +/* + * Note that we play around with the 'TS' bit in an attempt to get + * the correct behaviour even in the presence of the asynchronous + * IRQ13 behaviour + */ +void math_error(void __user *eip) +{ + struct task_struct * task; + siginfo_t info; + unsigned short cwd, swd; + + /* + * Save the info for the exception handler and clear the error. + */ + task = current; + save_init_fpu(task); + task->thread.trap_no = 16; + task->thread.error_code = 0; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * (~cwd & swd) will mask out exceptions that are not set to unmasked + * status. 0x3f is the exception bits in these regs, 0x200 is the + * C1 reg you need in case of a stack fault, 0x040 is the stack + * fault bit. We should only be taking one exception at a time, + * so if this combination doesn't produce any single exception, + * then we have a bad program that isn't syncronizing its FPU usage + * and it will suffer the consequences since we won't be able to + * fully reproduce the context of the exception + */ + cwd = get_fpu_cwd(task); + swd = get_fpu_swd(task); + switch (swd & ~cwd & 0x3f) { + case 0x000: /* No unmasked exception */ + return; + default: /* Multiple exceptions */ + break; + case 0x001: /* Invalid Op */ + /* + * swd & 0x240 == 0x040: Stack Underflow + * swd & 0x240 == 0x240: Stack Overflow + * User must clear the SF bit (0x40) if set + */ + info.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); +} + +fastcall void do_coprocessor_error(struct pt_regs * regs, long error_code) +{ + ignore_fpu_irq = 1; + math_error((void __user *)regs->eip); +} + +static void simd_math_error(void __user *eip) +{ + struct task_struct * task; + siginfo_t info; + unsigned short mxcsr; + + /* + * Save the info for the exception handler and clear the error. + */ + task = current; + save_init_fpu(task); + task->thread.trap_no = 19; + task->thread.error_code = 0; + info.si_signo = SIGFPE; + info.si_errno = 0; + info.si_code = __SI_FAULT; + info.si_addr = eip; + /* + * The SIMD FPU exceptions are handled a little differently, as there + * is only a single status/control register. Thus, to determine which + * unmasked exception was caught we must mask the exception mask bits + * at 0x1f80, and then use these to mask the exception bits at 0x3f. + */ + mxcsr = get_fpu_mxcsr(task); + switch (~((mxcsr & 0x1f80) >> 7) & (mxcsr & 0x3f)) { + case 0x000: + default: + break; + case 0x001: /* Invalid Op */ + info.si_code = FPE_FLTINV; + break; + case 0x002: /* Denormalize */ + case 0x010: /* Underflow */ + info.si_code = FPE_FLTUND; + break; + case 0x004: /* Zero Divide */ + info.si_code = FPE_FLTDIV; + break; + case 0x008: /* Overflow */ + info.si_code = FPE_FLTOVF; + break; + case 0x020: /* Precision */ + info.si_code = FPE_FLTRES; + break; + } + force_sig_info(SIGFPE, &info, task); +} + +fastcall void do_simd_coprocessor_error(struct pt_regs * regs, + long error_code) +{ + if (cpu_has_xmm) { + /* Handle SIMD FPU exceptions on PIII+ processors. */ + ignore_fpu_irq = 1; + simd_math_error((void __user *)regs->eip); + } else { + /* + * Handle strange cache flush from user space exception + * in all other cases. This is undocumented behaviour. + */ + if (regs->eflags & VM_MASK) { + handle_vm86_fault((struct kernel_vm86_regs *)regs, + error_code); + return; + } + current->thread.trap_no = 19; + current->thread.error_code = error_code; + die_if_kernel("cache flush denied", regs, error_code); + force_sig(SIGSEGV, current); + } +} + +fastcall void do_spurious_interrupt_bug(struct pt_regs * regs, + long error_code) +{ +#if 0 + /* No need to warn about this any longer. */ + printk("Ignoring P6 Local APIC Spurious Interrupt Bug...\n"); +#endif +} + +fastcall void setup_x86_bogus_stack(unsigned char * stk) +{ + unsigned long *switch16_ptr, *switch32_ptr; + struct pt_regs *regs; + unsigned long stack_top, stack_bot; + unsigned short iret_frame16_off; + int cpu = smp_processor_id(); + /* reserve the space on 32bit stack for the magic switch16 pointer */ + memmove(stk, stk + 8, sizeof(struct pt_regs)); + switch16_ptr = (unsigned long *)(stk + sizeof(struct pt_regs)); + regs = (struct pt_regs *)stk; + /* now the switch32 on 16bit stack */ + stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu); + stack_top = stack_bot + CPU_16BIT_STACK_SIZE; + switch32_ptr = (unsigned long *)(stack_top - 8); + iret_frame16_off = CPU_16BIT_STACK_SIZE - 8 - 20; + /* copy iret frame on 16bit stack */ + memcpy((void *)(stack_bot + iret_frame16_off), ®s->eip, 20); + /* fill in the switch pointers */ + switch16_ptr[0] = (regs->esp & 0xffff0000) | iret_frame16_off; + switch16_ptr[1] = __ESPFIX_SS; + switch32_ptr[0] = (unsigned long)stk + sizeof(struct pt_regs) + + 8 - CPU_16BIT_STACK_SIZE; + switch32_ptr[1] = __KERNEL_DS; +} + +fastcall unsigned char * fixup_x86_bogus_stack(unsigned short sp) +{ + unsigned long *switch32_ptr; + unsigned char *stack16, *stack32; + unsigned long stack_top, stack_bot; + int len; + int cpu = smp_processor_id(); + stack_bot = (unsigned long)&per_cpu(cpu_16bit_stack, cpu); + stack_top = stack_bot + CPU_16BIT_STACK_SIZE; + switch32_ptr = (unsigned long *)(stack_top - 8); + /* copy the data from 16bit stack to 32bit stack */ + len = CPU_16BIT_STACK_SIZE - 8 - sp; + stack16 = (unsigned char *)(stack_bot + sp); + stack32 = (unsigned char *) + (switch32_ptr[0] + CPU_16BIT_STACK_SIZE - 8 - len); + memcpy(stack32, stack16, len); + return stack32; +} + +/* + * 'math_state_restore()' saves the current math information in the + * old math state array, and gets the new ones from the current task + * + * Careful.. There are problems with IBM-designed IRQ13 behaviour. + * Don't touch unless you *really* know how it works. + * + * Must be called with kernel preemption disabled (in this case, + * local interrupts are disabled at the call-site in entry.S). + */ +asmlinkage void math_state_restore(struct pt_regs regs) +{ + struct thread_info *thread = current_thread_info(); + struct task_struct *tsk = thread->task; + + clts(); /* Allow maths ops (or we recurse) */ + if (!tsk_used_math(tsk)) + init_fpu(tsk); + restore_fpu(tsk); + thread->status |= TS_USEDFPU; /* So we fnsave on switch_to() */ +} + +#ifndef CONFIG_MATH_EMULATION + +asmlinkage void math_emulate(long arg) +{ + printk(KERN_EMERG "math-emulation not enabled and no coprocessor found.\n"); + printk(KERN_EMERG "killing %s.\n",current->comm); + force_sig(SIGFPE,current); + schedule(); +} + +#endif /* CONFIG_MATH_EMULATION */ + +#ifdef CONFIG_X86_F00F_BUG +void __init trap_init_f00f_bug(void) +{ + __set_fixmap(FIX_F00F_IDT, __pa(&idt_table), PAGE_KERNEL_RO); + + /* + * Update the IDT descriptor and reload the IDT so that + * it uses the read-only mapped virtual address. + */ + idt_descr.address = fix_to_virt(FIX_F00F_IDT); + load_idt(&idt_descr); +} +#endif + +#define _set_gate(gate_addr,type,dpl,addr,seg) \ +do { \ + int __d0, __d1; \ + __asm__ __volatile__ ("movw %%dx,%%ax\n\t" \ + "movw %4,%%dx\n\t" \ + "movl %%eax,%0\n\t" \ + "movl %%edx,%1" \ + :"=m" (*((long *) (gate_addr))), \ + "=m" (*(1+(long *) (gate_addr))), "=&a" (__d0), "=&d" (__d1) \ + :"i" ((short) (0x8000+(dpl<<13)+(type<<8))), \ + "3" ((char *) (addr)),"2" ((seg) << 16)); \ +} while (0) + + +/* + * This needs to use 'idt_table' rather than 'idt', and + * thus use the _nonmapped_ version of the IDT, as the + * Pentium F0 0F bugfix can have resulted in the mapped + * IDT being write-protected. + */ +void set_intr_gate(unsigned int n, void *addr) +{ + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + + _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + +} + +/* + * This routine sets up an interrupt gate at directory privilege level 3. + */ +static inline void set_system_intr_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n, 14, 3, addr, __KERNEL_CS); +} + +static void __init set_trap_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,15,0,addr,__KERNEL_CS); +} + +static void __init set_system_gate(unsigned int n, void *addr) +{ + _set_gate(idt_table+n,15,3,addr,__KERNEL_CS); +} + +static void __init set_task_gate(unsigned int n, unsigned int gdt_entry) +{ + _set_gate(idt_table+n,5,0,0,(gdt_entry<<3)); +} + + +void __init trap_init(void) +{ +#ifdef CONFIG_EISA + void __iomem *p = ioremap(0x0FFFD9, 4); + if (readl(p) == 'E'+('I'<<8)+('S'<<16)+('A'<<24)) { + EISA_bus = 1; + } + iounmap(p); +#endif + +#ifdef CONFIG_X86_LOCAL_APIC + init_apic_mappings(); +#endif + + set_trap_gate(0,÷_error); + set_intr_gate(1,&debug); + set_intr_gate(2,&nmi); + set_system_intr_gate(3, &int3); /* int3/4 can be called from all */ + set_system_gate(4,&overflow); + set_trap_gate(5,&bounds); + set_trap_gate(6,&invalid_op); + set_trap_gate(7,&device_not_available); + set_task_gate(8,GDT_ENTRY_DOUBLEFAULT_TSS); + set_trap_gate(9,&coprocessor_segment_overrun); + set_trap_gate(10,&invalid_TSS); + set_trap_gate(11,&segment_not_present); + set_trap_gate(12,&stack_segment); + set_trap_gate(13,&general_protection); + set_intr_gate(14,&page_fault); + set_trap_gate(15,&spurious_interrupt_bug); + set_trap_gate(16,&coprocessor_error); + set_trap_gate(17,&alignment_check); +#ifdef CONFIG_X86_MCE + set_trap_gate(18,&machine_check); +#endif + set_trap_gate(19,&simd_coprocessor_error); + + if (cpu_has_fxsr) { + /* + * Verify that the FXSAVE/FXRSTOR data will be 16-byte aligned. + * Generates a compile-time "error: zero width for bit-field" if + * the alignment is wrong. + */ + struct fxsrAlignAssert { + int _:!(offsetof(struct task_struct, + thread.i387.fxsave) & 15); + }; + + printk(KERN_INFO "Enabling fast FPU save and restore... "); + set_in_cr4(X86_CR4_OSFXSR); + printk("done.\n"); + } + if (cpu_has_xmm) { + printk(KERN_INFO "Enabling unmasked SIMD FPU exception " + "support... "); + set_in_cr4(X86_CR4_OSXMMEXCPT); + printk("done.\n"); + } + + set_system_gate(SYSCALL_VECTOR,&system_call); + + /* + * Should be a barrier for any external CPU state. + */ + cpu_init(); + + trap_init_hook(); +} + +static int __init kstack_setup(char *s) +{ + kstack_depth_to_print = simple_strtoul(s, NULL, 0); + return 1; +} +__setup("kstack=", kstack_setup); diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/vm86.c linux-2.6.17.11-g-v/arch/i386/kernel/vm86.c --- linux-2.6.17.11/arch/i386/kernel/vm86.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/vm86.c 2006-08-28 14:44:48.000000000 +0200 @@ -123,7 +123,7 @@ struct pt_regs * fastcall save_v86_state do_exit(SIGSEGV); } - tss = &per_cpu(init_tss, get_cpu()); + tss = init_tss + get_cpu(); current->thread.esp0 = current->thread.saved_esp0; current->thread.sysenter_cs = __KERNEL_CS; load_esp0(tss, ¤t->thread); @@ -297,7 +297,7 @@ static void do_sys_vm86(struct kernel_vm savesegment(fs, tsk->thread.saved_fs); savesegment(gs, tsk->thread.saved_gs); - tss = &per_cpu(init_tss, get_cpu()); + tss = init_tss + get_cpu(); tsk->thread.esp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; diff -NurpP --minimal linux-2.6.17.11/arch/i386/kernel/vmlinux.lds.S linux-2.6.17.11-g-v/arch/i386/kernel/vmlinux.lds.S --- linux-2.6.17.11/arch/i386/kernel/vmlinux.lds.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/kernel/vmlinux.lds.S 2006-08-28 14:44:48.000000000 +0200 @@ -4,10 +4,19 @@ #define LOAD_OFFSET __PAGE_OFFSET +#include + #include #include #include #include +#include + +#ifdef CONFIG_X86_PAE +#define PMD_SHIFT 21 +#else +#define PMD_SHIFT 22 +#endif OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) @@ -16,59 +25,14 @@ jiffies = jiffies_64; SECTIONS { . = __KERNEL_START; - phys_startup_32 = startup_32 - LOAD_OFFSET; - /* read-only */ - _text = .; /* Text and read-only data */ - .text : AT(ADDR(.text) - LOAD_OFFSET) { - *(.text) - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) - *(.gnu.warning) - } = 0x9090 - - _etext = .; /* End of text section */ - - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } - __stop___ex_table = .; - - RODATA + phys_startup_32 = startup_32 - LOAD_OFFSET + __KERNEL_TEXT_OFFSET; - /* writeable */ - .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ - *(.data) - CONSTRUCTORS + .text.startup : AT(ADDR(.text.startup) - LOAD_OFFSET) { + BYTE(0xEA) /* jmp far */ + LONG(phys_startup_32) + SHORT(__BOOT_CS) } - . = ALIGN(4096); - __nosave_begin = .; - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } - . = ALIGN(4096); - __nosave_end = .; - - . = ALIGN(4096); - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { - *(.data.idt) - } - - . = ALIGN(32); - .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { - *(.data.cacheline_aligned) - } - - /* rarely changed data like cpu maps */ - . = ALIGN(32); - .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) } - _edata = .; /* End of data section */ - - . = ALIGN(THREAD_SIZE); /* init_task */ - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { - *(.data.init_task) - } - /* might get freed after init */ . = ALIGN(4096); __smp_alt_begin = .; @@ -92,11 +56,6 @@ SECTIONS /* will be freed after init */ . = ALIGN(4096); /* Init code and data */ __init_begin = .; - .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { - _sinittext = .; - *(.init.text) - _einittext = .; - } .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { *(.init.data) } . = ALIGN(16); __setup_start = .; @@ -128,9 +87,7 @@ SECTIONS .altinstr_replacement : AT(ADDR(.altinstr_replacement) - LOAD_OFFSET) { *(.altinstr_replacement) } - /* .exit.text is discard at runtime, not link time, to deal with references - from .altinstructions and .eh_frame */ - .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET) { *(.exit.text) } + .exit.data : AT(ADDR(.exit.data) - LOAD_OFFSET) { *(.exit.data) } . = ALIGN(4096); __initramfs_start = .; @@ -140,10 +97,108 @@ SECTIONS __per_cpu_start = .; .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) } __per_cpu_end = .; + + /* read-only */ + . = ALIGN(4096); - __init_end = .; + .init.text (. - __KERNEL_TEXT_OFFSET) : AT(ADDR(.init.text) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { + _sinittext = .; + *(.init.text) + _einittext = .; + } + + /* .exit.text is discard at runtime, not link time, to deal with references + from .altinstructions and .eh_frame */ + .exit.text : AT(ADDR(.exit.text) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { *(.exit.text) } + +#ifdef CONFIG_PAX_KERNEXEC + .text.align : AT(ADDR(.text.align) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { + . = ALIGN(__KERNEL_TEXT_OFFSET - LOAD_OFFSET) - 1; + BYTE(0) + } +#else + . = ALIGN(4096); +#endif + + __init_end = . + __KERNEL_TEXT_OFFSET; /* freed after init ends here */ - + + _text = .; /* Text and read-only data */ + .text : AT(ADDR(.text) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { + *(.text) + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + *(.fixup) + *(.gnu.warning) + } = 0x9090 + + _etext = .; /* End of text section */ + . += __KERNEL_TEXT_OFFSET; + . = ALIGN(16); /* Exception table */ + __start___ex_table = .; + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } + __stop___ex_table = .; + + . = ALIGN(4096); + .rodata.page_aligned : AT(ADDR(.rodata.page_aligned) - LOAD_OFFSET) { + *(.empty_zero_page) + +#ifdef CONFIG_X86_PAE + *(.swapper_pm_dir) +#endif + + *(.swapper_pg_dir) + *(.idt) + } + + RODATA + +#ifdef CONFIG_PAX_KERNEXEC + . = ALIGN(4096); + MODULES_VADDR = .; + + .module.text : AT(ADDR(.module.text) - LOAD_OFFSET) { + . += (4 * 1024 * 1024); + . = ALIGN(1 << PMD_SHIFT) - 1; + BYTE(0) + } + + MODULES_END = .; +#else + . = ALIGN(32); +#endif + + /* writeable */ + .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ + _data = .; + *(.data) + CONSTRUCTORS + } + + . = ALIGN(4096); + __nosave_begin = .; + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } + . = ALIGN(4096); + __nosave_end = .; + + . = ALIGN(32); + .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { + *(.data.cacheline_aligned) + } + + /* rarely changed data like cpu maps */ + . = ALIGN(32); + .data.read_mostly : AT(ADDR(.data.read_mostly) - LOAD_OFFSET) { *(.data.read_mostly) } + + . = ALIGN(THREAD_SIZE); /* init_task */ + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) + } + + _edata = .; /* End of data section */ + + . = ALIGN(4096); __bss_start = .; /* BSS */ .bss.page_aligned : AT(ADDR(.bss.page_aligned) - LOAD_OFFSET) { *(.bss.page_aligned) diff -NurpP --minimal linux-2.6.17.11/arch/i386/lib/checksum.S linux-2.6.17.11-g-v/arch/i386/lib/checksum.S --- linux-2.6.17.11/arch/i386/lib/checksum.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/lib/checksum.S 2006-08-28 14:44:48.000000000 +0200 @@ -27,7 +27,8 @@ #include #include - +#include + /* * computes a partial checksum, e.g. for TCP/UDP fragments */ @@ -281,12 +282,23 @@ unsigned int csum_partial_copy_generic ( .align 4 .globl csum_partial_copy_generic - +.globl csum_partial_copy_generic_to_user +.globl csum_partial_copy_generic_from_user + #ifndef CONFIG_X86_USE_PPRO_CHECKSUM #define ARGBASE 16 #define FP 12 - + +csum_partial_copy_generic_to_user: + pushl $(__USER_DS) + popl %es + jmp csum_partial_copy_generic + +csum_partial_copy_generic_from_user: + pushl $(__USER_DS) + popl %ds + csum_partial_copy_generic: subl $4,%esp pushl %edi @@ -305,7 +317,7 @@ csum_partial_copy_generic: jmp 4f SRC(1: movw (%esi), %bx ) addl $2, %esi -DST( movw %bx, (%edi) ) +DST( movw %bx, %es:(%edi) ) addl $2, %edi addw %bx, %ax adcl $0, %eax @@ -317,30 +329,30 @@ DST( movw %bx, (%edi) ) SRC(1: movl (%esi), %ebx ) SRC( movl 4(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, (%edi) ) +DST( movl %ebx, %es:(%edi) ) adcl %edx, %eax -DST( movl %edx, 4(%edi) ) +DST( movl %edx, %es:4(%edi) ) SRC( movl 8(%esi), %ebx ) SRC( movl 12(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 8(%edi) ) +DST( movl %ebx, %es:8(%edi) ) adcl %edx, %eax -DST( movl %edx, 12(%edi) ) +DST( movl %edx, %es:12(%edi) ) SRC( movl 16(%esi), %ebx ) SRC( movl 20(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 16(%edi) ) +DST( movl %ebx, %es:16(%edi) ) adcl %edx, %eax -DST( movl %edx, 20(%edi) ) +DST( movl %edx, %es:20(%edi) ) SRC( movl 24(%esi), %ebx ) SRC( movl 28(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 24(%edi) ) +DST( movl %ebx, %es:24(%edi) ) adcl %edx, %eax -DST( movl %edx, 28(%edi) ) +DST( movl %edx, %es:28(%edi) ) lea 32(%esi), %esi lea 32(%edi), %edi @@ -354,7 +366,7 @@ DST( movl %edx, 28(%edi) ) shrl $2, %edx # This clears CF SRC(3: movl (%esi), %ebx ) adcl %ebx, %eax -DST( movl %ebx, (%edi) ) +DST( movl %ebx, %es:(%edi) ) lea 4(%esi), %esi lea 4(%edi), %edi dec %edx @@ -366,12 +378,12 @@ DST( movl %ebx, (%edi) ) jb 5f SRC( movw (%esi), %cx ) leal 2(%esi), %esi -DST( movw %cx, (%edi) ) +DST( movw %cx, %es:(%edi) ) leal 2(%edi), %edi je 6f shll $16,%ecx SRC(5: movb (%esi), %cl ) -DST( movb %cl, (%edi) ) +DST( movb %cl, %es:(%edi) ) 6: addl %ecx, %eax adcl $0, %eax 7: @@ -382,7 +394,7 @@ DST( movb %cl, (%edi) ) 6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) # zero the complete destination - computing the rest # is too much work @@ -395,11 +407,15 @@ DST( movb %cl, (%edi) ) 6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT,(%ebx) + movl $-EFAULT,%ss:(%ebx) jmp 5000b .previous + pushl %ss + popl %ds + pushl %ss + popl %es popl %ebx popl %esi popl %edi @@ -411,17 +427,28 @@ DST( movb %cl, (%edi) ) /* Version for PentiumII/PPro */ #define ROUND1(x) \ + nop; nop; nop; \ SRC(movl x(%esi), %ebx ) ; \ addl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; + DST(movl %ebx, %es:x(%edi)); #define ROUND(x) \ + nop; nop; nop; \ SRC(movl x(%esi), %ebx ) ; \ adcl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; + DST(movl %ebx, %es:x(%edi)); #define ARGBASE 12 - + +csum_partial_copy_generic_to_user: + pushl $(__USER_DS) + popl %es + jmp csum_partial_copy_generic + +csum_partial_copy_generic_from_user: + pushl $(__USER_DS) + popl %ds + csum_partial_copy_generic: pushl %ebx pushl %edi @@ -440,7 +467,7 @@ csum_partial_copy_generic: subl %ebx, %edi lea -1(%esi),%edx andl $-32,%edx - lea 3f(%ebx,%ebx), %ebx + lea 3f(%ebx,%ebx,2), %ebx testl %esi, %esi jmp *%ebx 1: addl $64,%esi @@ -461,19 +488,19 @@ csum_partial_copy_generic: jb 5f SRC( movw (%esi), %dx ) leal 2(%esi), %esi -DST( movw %dx, (%edi) ) +DST( movw %dx, %es:(%edi) ) leal 2(%edi), %edi je 6f shll $16,%edx 5: SRC( movb (%esi), %dl ) -DST( movb %dl, (%edi) ) +DST( movb %dl, %es:(%edi) ) 6: addl %edx, %eax adcl $0, %eax 7: .section .fixup, "ax" 6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) # zero the complete destination (computing the rest is too much work) movl ARGBASE+8(%esp),%edi # dst movl ARGBASE+12(%esp),%ecx # len @@ -481,10 +508,14 @@ DST( movb %dl, (%edi) ) rep; stosb jmp 7b 6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) jmp 7b .previous + pushl %ss + popl %ds + pushl %ss + popl %es popl %esi popl %edi popl %ebx diff -NurpP --minimal linux-2.6.17.11/arch/i386/lib/getuser.S linux-2.6.17.11-g-v/arch/i386/lib/getuser.S --- linux-2.6.17.11/arch/i386/lib/getuser.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/lib/getuser.S 2006-08-28 14:44:48.000000000 +0200 @@ -9,6 +9,7 @@ * return value. */ #include +#include /* @@ -30,8 +31,12 @@ __get_user_1: GET_THREAD_INFO(%edx) cmpl TI_addr_limit(%edx),%eax jae bad_get_user + pushl $(__USER_DS) + popl %ds 1: movzbl (%eax),%edx xorl %eax,%eax + pushl %ss + pop %ds ret .align 4 @@ -42,7 +47,11 @@ __get_user_2: GET_THREAD_INFO(%edx) cmpl TI_addr_limit(%edx),%eax jae bad_get_user + pushl $(__USER_DS) + popl %ds 2: movzwl -1(%eax),%edx + pushl %ss + pop %ds xorl %eax,%eax ret @@ -54,11 +63,17 @@ __get_user_4: GET_THREAD_INFO(%edx) cmpl TI_addr_limit(%edx),%eax jae bad_get_user + pushl $(__USER_DS) + popl %ds 3: movl -3(%eax),%edx + pushl %ss + pop %ds xorl %eax,%eax ret bad_get_user: + pushl %ss + pop %ds xorl %edx,%edx movl $-14,%eax ret diff -NurpP --minimal linux-2.6.17.11/arch/i386/lib/mmx.c linux-2.6.17.11-g-v/arch/i386/lib/mmx.c --- linux-2.6.17.11/arch/i386/lib/mmx.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/lib/mmx.c 2006-08-28 14:44:48.000000000 +0200 @@ -48,14 +48,30 @@ void *_mmx_memcpy(void *to, const void * " prefetch 256(%0)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " cli\n" + " movl %%cr0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " orl $0x00010000, %%eax\n" + " movl %%eax, %%cr0\n" + " sti\n" +#endif + " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 1b, 3b\n" ".previous" - : : "r" (from) ); + : : "r" (from) : "ax"); for(; i>5; i--) @@ -79,14 +95,30 @@ void *_mmx_memcpy(void *to, const void * " movq %%mm2, 48(%1)\n" " movq %%mm3, 56(%1)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " cli\n" + " movl %%cr0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " orl $0x00010000, %%eax\n" + " movl %%eax, %%cr0\n" + " sti\n" +#endif + " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 1b, 3b\n" ".previous" - : : "r" (from), "r" (to) : "memory"); + : : "r" (from), "r" (to) : "memory", "ax"); from+=64; to+=64; } @@ -179,14 +211,30 @@ static void fast_copy_page(void *to, voi " prefetch 256(%0)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " cli\n" + " movl %%cr0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " orl $0x00010000, %%eax\n" + " movl %%eax, %%cr0\n" + " sti\n" +#endif + " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 1b, 3b\n" ".previous" - : : "r" (from) ); + : : "r" (from) : "ax"); for(i=0; i<(4096-320)/64; i++) { @@ -209,14 +257,30 @@ static void fast_copy_page(void *to, voi " movq 56(%0), %%mm7\n" " movntq %%mm7, 56(%1)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " cli\n" + " movl %%cr0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " orl $0x00010000, %%eax\n" + " movl %%eax, %%cr0\n" + " sti\n" +#endif + " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 1b, 3b\n" ".previous" - : : "r" (from), "r" (to) : "memory"); + : : "r" (from), "r" (to) : "memory", "ax"); from+=64; to+=64; } @@ -309,14 +373,30 @@ static void fast_copy_page(void *to, voi " prefetch 256(%0)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " cli\n" + " movl %%cr0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " orl $0x00010000, %%eax\n" + " movl %%eax, %%cr0\n" + " sti\n" +#endif + " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 1b, 3b\n" ".previous" - : : "r" (from) ); + : : "r" (from) : "ax"); for(i=0; i<4096/64; i++) { @@ -339,14 +419,30 @@ static void fast_copy_page(void *to, voi " movq %%mm2, 48(%1)\n" " movq %%mm3, 56(%1)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " cli\n" + " movl %%cr0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " orl $0x00010000, %%eax\n" + " movl %%eax, %%cr0\n" + " sti\n" +#endif + " jmp 2b\n" ".previous\n" ".section __ex_table,\"a\"\n" " .align 4\n" " .long 1b, 3b\n" ".previous" - : : "r" (from), "r" (to) : "memory"); + : : "r" (from), "r" (to) : "memory", "ax"); from+=64; to+=64; } diff -NurpP --minimal linux-2.6.17.11/arch/i386/lib/putuser.S linux-2.6.17.11-g-v/arch/i386/lib/putuser.S --- linux-2.6.17.11/arch/i386/lib/putuser.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/lib/putuser.S 2006-08-28 14:44:48.000000000 +0200 @@ -9,6 +9,7 @@ * return value. */ #include +#include /* @@ -33,7 +34,11 @@ __put_user_1: ENTER cmpl TI_addr_limit(%ebx),%ecx jae bad_put_user + pushl $(__USER_DS) + popl %ds 1: movb %al,(%ecx) + pushl %ss + popl %ds xorl %eax,%eax EXIT @@ -45,7 +50,11 @@ __put_user_2: subl $1,%ebx cmpl %ebx,%ecx jae bad_put_user + pushl $(__USER_DS) + popl %ds 2: movw %ax,(%ecx) + pushl %ss + popl %ds xorl %eax,%eax EXIT @@ -57,7 +66,11 @@ __put_user_4: subl $3,%ebx cmpl %ebx,%ecx jae bad_put_user + pushl $(__USER_DS) + popl %ds 3: movl %eax,(%ecx) + pushl %ss + popl %ds xorl %eax,%eax EXIT @@ -69,12 +82,18 @@ __put_user_8: subl $7,%ebx cmpl %ebx,%ecx jae bad_put_user + pushl $(__USER_DS) + popl %ds 4: movl %eax,(%ecx) 5: movl %edx,4(%ecx) + pushl %ss + popl %ds xorl %eax,%eax EXIT bad_put_user: + pushl %ss + popl %ds movl $-14,%eax EXIT diff -NurpP --minimal linux-2.6.17.11/arch/i386/lib/usercopy.c linux-2.6.17.11-g-v/arch/i386/lib/usercopy.c --- linux-2.6.17.11/arch/i386/lib/usercopy.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/lib/usercopy.c 2006-08-28 14:44:48.000000000 +0200 @@ -33,6 +33,7 @@ do { \ int __d0, __d1, __d2; \ might_sleep(); \ __asm__ __volatile__( \ + " movw %w10,%%ds\n" \ " testl %1,%1\n" \ " jz 2f\n" \ "0: lodsb\n" \ @@ -43,6 +44,8 @@ do { \ " jnz 0b\n" \ "1: subl %1,%0\n" \ "2:\n" \ + " pushl %%ss\n" \ + " popl %%ds\n" \ ".section .fixup,\"ax\"\n" \ "3: movl %5,%0\n" \ " jmp 2b\n" \ @@ -53,7 +56,8 @@ do { \ ".previous" \ : "=d"(res), "=c"(count), "=&a" (__d0), "=&S" (__d1), \ "=&D" (__d2) \ - : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst),\ + "r"(__USER_DS) \ : "memory"); \ } while (0) @@ -123,10 +127,13 @@ do { \ int __d0; \ might_sleep(); \ __asm__ __volatile__( \ + " movw %w6,%%es\n" \ "0: rep; stosl\n" \ " movl %2,%0\n" \ "1: rep; stosb\n" \ "2:\n" \ + " pushl %%ss\n" \ + " popl %%es\n" \ ".section .fixup,\"ax\"\n" \ "3: lea 0(%2,%0,4),%0\n" \ " jmp 2b\n" \ @@ -137,7 +144,8 @@ do { \ " .long 1b,2b\n" \ ".previous" \ : "=&c"(size), "=&D" (__d0) \ - : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \ + : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0), \ + "r"(__USER_DS)); \ } while (0) /** @@ -198,14 +206,17 @@ long strnlen_user(const char __user *s, might_sleep(); __asm__ __volatile__( + " movw %w8,%%es\n" " testl %0, %0\n" " jz 3f\n" - " andl %0,%%ecx\n" + " movl %0,%%ecx\n" "0: repne; scasb\n" " setne %%al\n" " subl %%ecx,%0\n" " addl %0,%%eax\n" "1:\n" + " pushl %%ss\n" + " popl %%es\n" ".section .fixup,\"ax\"\n" "2: xorl %%eax,%%eax\n" " jmp 1b\n" @@ -217,7 +228,7 @@ long strnlen_user(const char __user *s, " .long 0b,2b\n" ".previous" :"=r" (n), "=D" (s), "=a" (res), "=c" (tmp) - :"0" (n), "1" (s), "2" (0), "3" (mask) + :"0" (n), "1" (s), "2" (0), "3" (mask), "r" (__USER_DS) :"cc"); return res & mask; } @@ -229,6 +240,7 @@ __copy_user_intel(void __user *to, const { int d0, d1; __asm__ __volatile__( + " movw %w6, %%es\n" " .align 2,0x90\n" "1: movl 32(%4), %%eax\n" " cmpl $67, %0\n" @@ -237,36 +249,36 @@ __copy_user_intel(void __user *to, const " .align 2,0x90\n" "3: movl 0(%4), %%eax\n" "4: movl 4(%4), %%edx\n" - "5: movl %%eax, 0(%3)\n" - "6: movl %%edx, 4(%3)\n" + "5: movl %%eax, %%es:0(%3)\n" + "6: movl %%edx, %%es:4(%3)\n" "7: movl 8(%4), %%eax\n" "8: movl 12(%4),%%edx\n" - "9: movl %%eax, 8(%3)\n" - "10: movl %%edx, 12(%3)\n" + "9: movl %%eax, %%es:8(%3)\n" + "10: movl %%edx, %%es:12(%3)\n" "11: movl 16(%4), %%eax\n" "12: movl 20(%4), %%edx\n" - "13: movl %%eax, 16(%3)\n" - "14: movl %%edx, 20(%3)\n" + "13: movl %%eax, %%es:16(%3)\n" + "14: movl %%edx, %%es:20(%3)\n" "15: movl 24(%4), %%eax\n" "16: movl 28(%4), %%edx\n" - "17: movl %%eax, 24(%3)\n" - "18: movl %%edx, 28(%3)\n" + "17: movl %%eax, %%es:24(%3)\n" + "18: movl %%edx, %%es:28(%3)\n" "19: movl 32(%4), %%eax\n" "20: movl 36(%4), %%edx\n" - "21: movl %%eax, 32(%3)\n" - "22: movl %%edx, 36(%3)\n" + "21: movl %%eax, %%es:32(%3)\n" + "22: movl %%edx, %%es:36(%3)\n" "23: movl 40(%4), %%eax\n" "24: movl 44(%4), %%edx\n" - "25: movl %%eax, 40(%3)\n" - "26: movl %%edx, 44(%3)\n" + "25: movl %%eax, %%es:40(%3)\n" + "26: movl %%edx, %%es:44(%3)\n" "27: movl 48(%4), %%eax\n" "28: movl 52(%4), %%edx\n" - "29: movl %%eax, 48(%3)\n" - "30: movl %%edx, 52(%3)\n" + "29: movl %%eax, %%es:48(%3)\n" + "30: movl %%edx, %%es:52(%3)\n" "31: movl 56(%4), %%eax\n" "32: movl 60(%4), %%edx\n" - "33: movl %%eax, 56(%3)\n" - "34: movl %%edx, 60(%3)\n" + "33: movl %%eax, %%es:56(%3)\n" + "34: movl %%edx, %%es:60(%3)\n" " addl $-64, %0\n" " addl $64, %4\n" " addl $64, %3\n" @@ -280,6 +292,8 @@ __copy_user_intel(void __user *to, const "36: movl %%eax, %0\n" "37: rep; movsb\n" "100:\n" + " pushl %%ss\n" + " popl %%es\n" ".section .fixup,\"ax\"\n" "101: lea 0(%%eax,%0,4),%0\n" " jmp 100b\n" @@ -326,7 +340,7 @@ __copy_user_intel(void __user *to, const " .long 99b,101b\n" ".previous" : "=&c"(size), "=&D" (d0), "=&S" (d1) - : "1"(to), "2"(from), "0"(size) + : "1"(to), "2"(from), "0"(size), "r"(__USER_DS) : "eax", "edx", "memory"); return size; } @@ -336,6 +350,7 @@ __copy_user_zeroing_intel(void *to, cons { int d0, d1; __asm__ __volatile__( + " movw %w6, %%ds\n" " .align 2,0x90\n" "0: movl 32(%4), %%eax\n" " cmpl $67, %0\n" @@ -344,36 +359,36 @@ __copy_user_zeroing_intel(void *to, cons " .align 2,0x90\n" "2: movl 0(%4), %%eax\n" "21: movl 4(%4), %%edx\n" - " movl %%eax, 0(%3)\n" - " movl %%edx, 4(%3)\n" + " movl %%eax, %%es:0(%3)\n" + " movl %%edx, %%es:4(%3)\n" "3: movl 8(%4), %%eax\n" "31: movl 12(%4),%%edx\n" - " movl %%eax, 8(%3)\n" - " movl %%edx, 12(%3)\n" + " movl %%eax, %%es:8(%3)\n" + " movl %%edx, %%es:12(%3)\n" "4: movl 16(%4), %%eax\n" "41: movl 20(%4), %%edx\n" - " movl %%eax, 16(%3)\n" - " movl %%edx, 20(%3)\n" + " movl %%eax, %%es:16(%3)\n" + " movl %%edx, %%es:20(%3)\n" "10: movl 24(%4), %%eax\n" "51: movl 28(%4), %%edx\n" - " movl %%eax, 24(%3)\n" - " movl %%edx, 28(%3)\n" + " movl %%eax, %%es:24(%3)\n" + " movl %%edx, %%es:28(%3)\n" "11: movl 32(%4), %%eax\n" "61: movl 36(%4), %%edx\n" - " movl %%eax, 32(%3)\n" - " movl %%edx, 36(%3)\n" + " movl %%eax, %%es:32(%3)\n" + " movl %%edx, %%es:36(%3)\n" "12: movl 40(%4), %%eax\n" "71: movl 44(%4), %%edx\n" - " movl %%eax, 40(%3)\n" - " movl %%edx, 44(%3)\n" + " movl %%eax, %%es:40(%3)\n" + " movl %%edx, %%es:44(%3)\n" "13: movl 48(%4), %%eax\n" "81: movl 52(%4), %%edx\n" - " movl %%eax, 48(%3)\n" - " movl %%edx, 52(%3)\n" + " movl %%eax, %%es:48(%3)\n" + " movl %%edx, %%es:52(%3)\n" "14: movl 56(%4), %%eax\n" "91: movl 60(%4), %%edx\n" - " movl %%eax, 56(%3)\n" - " movl %%edx, 60(%3)\n" + " movl %%eax, %%es:56(%3)\n" + " movl %%edx, %%es:60(%3)\n" " addl $-64, %0\n" " addl $64, %4\n" " addl $64, %3\n" @@ -387,6 +402,8 @@ __copy_user_zeroing_intel(void *to, cons " movl %%eax,%0\n" "7: rep; movsb\n" "8:\n" + " pushl %%ss\n" + " popl %%ds\n" ".section .fixup,\"ax\"\n" "9: lea 0(%%eax,%0,4),%0\n" "16: pushl %0\n" @@ -421,7 +438,7 @@ __copy_user_zeroing_intel(void *to, cons " .long 7b,16b\n" ".previous" : "=&c"(size), "=&D" (d0), "=&S" (d1) - : "1"(to), "2"(from), "0"(size) + : "1"(to), "2"(from), "0"(size), "r"(__USER_DS) : "eax", "edx", "memory"); return size; } @@ -441,6 +458,7 @@ __copy_user_intel(void __user *to, const do { \ int __d0, __d1, __d2; \ __asm__ __volatile__( \ + " movw %w8,%%es\n" \ " cmp $7,%0\n" \ " jbe 1f\n" \ " movl %1,%0\n" \ @@ -456,6 +474,8 @@ do { \ " movl %3,%0\n" \ "1: rep; movsb\n" \ "2:\n" \ + " pushl %%ss\n" \ + " popl %%es\n" \ ".section .fixup,\"ax\"\n" \ "5: addl %3,%0\n" \ " jmp 2b\n" \ @@ -469,7 +489,7 @@ do { \ " .long 1b,2b\n" \ ".previous" \ : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \ - : "3"(size), "0"(size), "1"(to), "2"(from) \ + : "3"(size), "0"(size), "1"(to), "2"(from), "r"(__USER_DS)\ : "memory"); \ } while (0) @@ -477,6 +497,7 @@ do { \ do { \ int __d0, __d1, __d2; \ __asm__ __volatile__( \ + " movw %w8,%%ds\n" \ " cmp $7,%0\n" \ " jbe 1f\n" \ " movl %1,%0\n" \ @@ -492,6 +513,8 @@ do { \ " movl %3,%0\n" \ "1: rep; movsb\n" \ "2:\n" \ + " pushl %%ss\n" \ + " popl %%ds\n" \ ".section .fixup,\"ax\"\n" \ "5: addl %3,%0\n" \ " jmp 6f\n" \ @@ -511,7 +534,7 @@ do { \ " .long 1b,6b\n" \ ".previous" \ : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \ - : "3"(size), "0"(size), "1"(to), "2"(from) \ + : "3"(size), "0"(size), "1"(to), "2"(from), "r"(__USER_DS)\ : "memory"); \ } while (0) @@ -640,3 +663,45 @@ copy_from_user(void *to, const void __us return n; } EXPORT_SYMBOL(copy_from_user); + +#ifdef CONFIG_PAX_MEMORY_UDEREF +void __set_fs(mm_segment_t x, int cpu) +{ + unsigned long limit = x.seg; + + current_thread_info()->addr_limit = x; + if (likely(limit)) { + limit -= 1UL; + limit >>= 12; + } + + get_cpu_gdt_table(cpu)[GDT_ENTRY_DEFAULT_USER_DS].a = (limit & 0xFFFFUL); + get_cpu_gdt_table(cpu)[GDT_ENTRY_DEFAULT_USER_DS].b = (limit & 0xF0000UL) | 0xC0F300UL; +} + +void set_fs(mm_segment_t x) +{ + int cpu = get_cpu(); + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + + __set_fs(x, cpu); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + put_cpu_no_resched(); +} +#else +void set_fs(mm_segment_t x) +{ + current_thread_info()->addr_limit = x; +} +#endif + +EXPORT_SYMBOL(set_fs); diff -NurpP --minimal linux-2.6.17.11/arch/i386/mach-voyager/voyager_smp.c linux-2.6.17.11-g-v/arch/i386/mach-voyager/voyager_smp.c --- linux-2.6.17.11/arch/i386/mach-voyager/voyager_smp.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/mach-voyager/voyager_smp.c 2006-08-28 14:44:48.000000000 +0200 @@ -1295,7 +1295,7 @@ smp_local_timer_interrupt(struct pt_regs per_cpu(prof_counter, cpu); } - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode(regs)); } if( ((1< -#undef CONFIG_X86_PAE #include #include #include #include #include -/* - * I'm cheating here. It is known that the two boot PTE pages are - * allocated next to each other. I'm pretending that they're just - * one big array. - */ - -#define BOOT_PTE_PTRS (PTRS_PER_PTE*2) -#define boot_pte_index(address) \ - (((address) >> PAGE_SHIFT) & (BOOT_PTE_PTRS - 1)) - -static inline boot_pte_t* boot_vaddr_to_pte(void *address) -{ - boot_pte_t* boot_pg = (boot_pte_t*)pg0; - return &boot_pg[boot_pte_index((unsigned long)address)]; -} /* * This is only for a caller who is clever enough to page-align * phys_addr and virtual_source, and who also has a preference * about which virtual address from which to steal ptes */ -static void __boot_ioremap(unsigned long phys_addr, unsigned long nrpages, - void* virtual_source) +static void __init __boot_ioremap(unsigned long phys_addr, unsigned int nrpages, + char* virtual_source) { - boot_pte_t* pte; - int i; - char *vaddr = virtual_source; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t* pte; + unsigned int i; + unsigned long vaddr = (unsigned long)virtual_source; + + pgd = pgd_offset_k(vaddr); + pud = pud_offset(pgd, vaddr); + pmd = pmd_offset(pud, vaddr); + pte = pte_offset_kernel(pmd, vaddr); - pte = boot_vaddr_to_pte(virtual_source); for (i=0; i < nrpages; i++, phys_addr += PAGE_SIZE, pte++) { set_pte(pte, pfn_pte(phys_addr>>PAGE_SHIFT, PAGE_KERNEL)); - __flush_tlb_one(&vaddr[i*PAGE_SIZE]); + __flush_tlb_one(&virtual_source[i*PAGE_SIZE]); } } diff -NurpP --minimal linux-2.6.17.11/arch/i386/mm/extable.c linux-2.6.17.11-g-v/arch/i386/mm/extable.c --- linux-2.6.17.11/arch/i386/mm/extable.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/mm/extable.c 2006-08-28 14:44:48.000000000 +0200 @@ -12,7 +12,7 @@ int fixup_exception(struct pt_regs *regs const struct exception_table_entry *fixup; #ifdef CONFIG_PNPBIOS - if (unlikely((regs->xcs & ~15) == (GDT_ENTRY_PNPBIOS_BASE << 3))) + if (unlikely(!(regs->eflags & VM_MASK) && ((regs->xcs & 0xFFFCU) == PNP_CS32 || (regs->xcs & 0xFFFCU) == PNP_CS16))) { extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; extern u32 pnp_bios_is_utter_crap; diff -NurpP --minimal linux-2.6.17.11/arch/i386/mm/fault.c linux-2.6.17.11-g-v/arch/i386/mm/fault.c --- linux-2.6.17.11/arch/i386/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/mm/fault.c 2006-08-28 14:44:48.000000000 +0200 @@ -22,6 +22,9 @@ #include #include #include +#include +#include +#include #include #include @@ -82,11 +85,13 @@ static inline unsigned long get_segment_ /* Unlikely, but must come before segment checks. */ if (unlikely((regs->eflags & VM_MASK) != 0)) - return eip + (seg << 4); + return (eip & 0xFFFF) + (seg << 4); /* By far the most common cases. */ - if (likely(seg == __USER_CS || seg == __KERNEL_CS)) + if (likely(seg == __USER_CS)) return eip; + if (likely(seg == __KERNEL_CS)) + return eip + __KERNEL_TEXT_OFFSET; /* Check the segment exists, is within the current LDT/GDT size, that kernel/user (ring 0..3) has the appropriate privilege, @@ -214,6 +219,30 @@ static noinline void force_sig_info_faul fastcall void do_invalid_op(struct pt_regs *, unsigned long); +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) +static int pax_handle_fetch_fault(struct pt_regs *regs); +#endif + +#ifdef CONFIG_PAX_PAGEEXEC +static inline pmd_t * pax_get_pmd(struct mm_struct *mm, unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + + pgd = pgd_offset(mm, address); + if (!pgd_present(*pgd)) + return NULL; + pud = pud_offset(pgd, address); + if (!pud_present(*pud)) + return NULL; + pmd = pmd_offset(pud, address); + if (!pmd_present(*pmd)) + return NULL; + return pmd; +} +#endif + static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) { unsigned index = pgd_index(address); @@ -295,13 +324,20 @@ fastcall void __kprobes do_page_fault(st struct mm_struct *mm; struct vm_area_struct * vma; unsigned long address; - unsigned long page; int write, si_code; +#ifdef CONFIG_PAX_PAGEEXEC + pmd_t *pmd; + pte_t *pte; + spinlock_t *ptl; + unsigned char pte_mask; +#endif + /* get the address */ address = read_cr2(); tsk = current; + mm = tsk->mm; si_code = SEGV_MAPERR; @@ -340,14 +376,12 @@ fastcall void __kprobes do_page_fault(st if (regs->eflags & (X86_EFLAGS_IF|VM_MASK)) local_irq_enable(); - mm = tsk->mm; - /* * If we're in an interrupt, have no user context or are running in an * atomic region then we must not take the fault.. */ if (in_atomic() || !mm) - goto bad_area_nosemaphore; + goto bad_area_nopax; /* When running in the kernel we expect faults to occur only to * addresses in user space. All other faults represent errors in the @@ -367,10 +401,101 @@ fastcall void __kprobes do_page_fault(st if (!down_read_trylock(&mm->mmap_sem)) { if ((error_code & 4) == 0 && !search_exception_tables(regs->eip)) - goto bad_area_nosemaphore; + goto bad_area_nopax; down_read(&mm->mmap_sem); } +#ifdef CONFIG_PAX_PAGEEXEC + if (unlikely((error_code & 5) != 5 || + (regs->eflags & X86_EFLAGS_VM) || + !(mm->pax_flags & MF_PAX_PAGEEXEC))) + goto not_pax_fault; + + /* PaX: it's our fault, let's handle it if we can */ + + /* PaX: take a look at read faults before acquiring any locks */ + if (unlikely(!(error_code & 2) && (regs->eip == address))) { + /* instruction fetch attempt from a protected page in user mode */ + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUTRAMP + case 2: + return; +#endif + + } + pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp); + do_exit(SIGKILL); + } + + pmd = pax_get_pmd(mm, address); + if (unlikely(!pmd)) + goto not_pax_fault; + + pte = pte_offset_map_lock(mm, pmd, address, &ptl); + if (unlikely(!(pte_val(*pte) & _PAGE_PRESENT) || pte_user(*pte))) { + pte_unmap_unlock(pte, ptl); + goto not_pax_fault; + } + + if (unlikely((error_code & 2) && !pte_write(*pte))) { + /* write attempt to a protected page in user mode */ + pte_unmap_unlock(pte, ptl); + goto not_pax_fault; + } + +#ifdef CONFIG_SMP + if (likely(address > get_limit(regs->xcs) && cpu_isset(smp_processor_id(), mm->context.cpu_user_cs_mask))) +#else + if (likely(address > get_limit(regs->xcs))) +#endif + { + set_pte(pte, pte_mkread(*pte)); + __flush_tlb_one(address); + pte_unmap_unlock(pte, ptl); + up_read(&mm->mmap_sem); + return; + } + + pte_mask = _PAGE_ACCESSED | _PAGE_USER | ((error_code & 2) << (_PAGE_BIT_DIRTY-1)); + + /* + * PaX: fill DTLB with user rights and retry + */ + __asm__ __volatile__ ( + "movw %w4,%%ds\n" + "orb %2,%%ss:(%1)\n" +#if defined(CONFIG_M586) || defined(CONFIG_M586TSC) +/* + * PaX: let this uncommented 'invlpg' remind us on the behaviour of Intel's + * (and AMD's) TLBs. namely, they do not cache PTEs that would raise *any* + * page fault when examined during a TLB load attempt. this is true not only + * for PTEs holding a non-present entry but also present entries that will + * raise a page fault (such as those set up by PaX, or the copy-on-write + * mechanism). in effect it means that we do *not* need to flush the TLBs + * for our target pages since their PTEs are simply not in the TLBs at all. + + * the best thing in omitting it is that we gain around 15-20% speed in the + * fast path of the page fault handler and can get rid of tracing since we + * can no longer flush unintended entries. + */ + "invlpg (%0)\n" +#endif + "testb $0,(%0)\n" + "xorb %3,%%ss:(%1)\n" + "pushl %%ss\n" + "popl %%ds\n" + : + : "q" (address), "r" (pte), "q" (pte_mask), "i" (_PAGE_USER), "r" (__USER_DS) + : "memory", "cc"); + pte_unmap_unlock(pte, ptl); + up_read(&mm->mmap_sem); + return; + +not_pax_fault: +#endif + vma = find_vma(mm, address); if (!vma) goto bad_area; @@ -456,6 +581,37 @@ bad_area: up_read(&mm->mmap_sem); bad_area_nosemaphore: + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (mm && (error_code & 4) && !(regs->eflags & X86_EFLAGS_VM)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && !(error_code & 3) && (regs->eip == address)) { + pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp); + do_exit(SIGKILL); + } +#endif + +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && !(error_code & 3) && (regs->eip + SEGMEXEC_TASK_SIZE == address)) { + + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUTRAMP + case 2: + return; +#endif + + } + pax_report_fault(regs, (void*)regs->eip, (void*)regs->esp); + do_exit(SIGKILL); + } +#endif + + } +#endif + +bad_area_nopax: /* User mode accesses just cause a SIGSEGV */ if (error_code & 4) { /* @@ -523,6 +679,21 @@ no_context: if (address < PAGE_SIZE) printk(KERN_ALERT "BUG: unable to handle kernel NULL " "pointer dereference"); + +#ifdef CONFIG_PAX_KERNEXEC +#ifdef CONFIG_MODULES + else if (init_mm.start_code <= address && address < (unsigned long)MODULES_END) +#else + else if (init_mm.start_code <= address && address < init_mm.end_code) +#endif + if (tsk->signal->curr_ip) + printk(KERN_ERR "PAX: From %u.%u.%u.%u: %s:%d, uid/euid: %u/%u, attempted to modify kernel code", + NIPQUAD(tsk->signal->curr_ip), tsk->comm, tsk->pid, tsk->uid, tsk->euid); + else + printk(KERN_ERR "PAX: %s:%d, uid/euid: %u/%u, attempted to modify kernel code", + tsk->comm, tsk->pid, tsk->uid, tsk->euid); +#endif + else printk(KERN_ALERT "BUG: unable to handle kernel paging" " request"); @@ -530,24 +701,34 @@ no_context: printk(KERN_ALERT " printing eip:\n"); printk("%08lx\n", regs->eip); } - page = read_cr3(); - page = ((unsigned long *) __va(page))[address >> 22]; - if (oops_may_print()) - printk(KERN_ALERT "*pde = %08lx\n", page); - /* - * We must not directly access the pte in the highpte - * case, the page table might be allocated in highmem. - * And lets rather not kmap-atomic the pte, just in case - * it's allocated already. - */ + + if (oops_may_print()) { + unsigned long index = pgd_index(address); + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + pte_t *pte; + + pgd = index + (pgd_t *)__va(read_cr3()); + printk(KERN_ALERT "*pgd = %*llx\n", sizeof(*pgd), (unsigned long long)pgd_val(*pgd)); + if (pgd_present(*pgd)) { + pud = pud_offset(pgd, address); + pmd = pmd_offset(pud, address); + printk(KERN_ALERT "*pmd = %*llx\n", sizeof(*pmd), (unsigned long long)pmd_val(*pmd)); + /* + * We must not directly access the pte in the highpte + * case, the page table might be allocated in highmem. + * And lets rather not kmap-atomic the pte, just in case + * it's allocated already. + */ #ifndef CONFIG_HIGHPTE - if ((page & 1) && oops_may_print()) { - page &= PAGE_MASK; - address &= 0x003ff000; - page = ((unsigned long *) __va(page))[address >> PAGE_SHIFT]; - printk(KERN_ALERT "*pte = %08lx\n", page); - } + if (pmd_present(*pmd) && !pmd_large(*pmd)) { + pte = pte_offset_kernel(pmd, address); + printk(KERN_ALERT "*pte = %*llx\n", sizeof(*pte), (unsigned long long)pte_val(*pte)); + } #endif + } + } tsk->thread.cr2 = address; tsk->thread.trap_no = 14; tsk->thread.error_code = error_code; @@ -624,3 +805,105 @@ void vmalloc_sync_all(void) } } #endif + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) +/* + * PaX: decide what to do with offenders (regs->eip = fault address) + * + * returns 1 when task should be killed + * 2 when gcc trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUTRAMP + static const unsigned char trans[8] = {6, 1, 2, 0, 13, 5, 3, 4}; + int err; +#endif + + if (regs->eflags & X86_EFLAGS_VM) + return 1; + +#ifdef CONFIG_PAX_EMUTRAMP + if (!(current->mm->pax_flags & MF_PAX_EMUTRAMP)) + return 1; + + do { /* PaX: gcc trampoline emulation #1 */ + unsigned char mov1, mov2; + unsigned short jmp; + unsigned long addr1, addr2; + + err = get_user(mov1, (unsigned char __user *)regs->eip); + err |= get_user(addr1, (unsigned long __user *)(regs->eip + 1)); + err |= get_user(mov2, (unsigned char __user *)(regs->eip + 5)); + err |= get_user(addr2, (unsigned long __user *)(regs->eip + 6)); + err |= get_user(jmp, (unsigned short __user *)(regs->eip + 10)); + + if (err) + break; + + if ((mov1 & 0xF8) == 0xB8 && + (mov2 & 0xF8) == 0xB8 && + (mov1 & 0x07) != (mov2 & 0x07) && + (jmp & 0xF8FF) == 0xE0FF && + (mov2 & 0x07) == ((jmp>>8) & 0x07)) + { + ((unsigned long *)regs)[trans[mov1 & 0x07]] = addr1; + ((unsigned long *)regs)[trans[mov2 & 0x07]] = addr2; + regs->eip = addr2; + return 2; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #2 */ + unsigned char mov, jmp; + unsigned long addr1, addr2; + + err = get_user(mov, (unsigned char __user *)regs->eip); + err |= get_user(addr1, (unsigned long __user *)(regs->eip + 1)); + err |= get_user(jmp, (unsigned char __user *)(regs->eip + 5)); + err |= get_user(addr2, (unsigned long __user *)(regs->eip + 6)); + + if (err) + break; + + if ((mov & 0xF8) == 0xB8 && + jmp == 0xE9) + { + ((unsigned long *)regs)[trans[mov & 0x07]] = addr1; + regs->eip += addr2 + 10; + return 2; + } + } while (0); +#endif + + return 1; /* PaX in action */ +} +#endif + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) +void pax_report_insns(void *pc, void *sp) +{ + long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (get_user(c, (unsigned char __user *)pc+i)) + printk("?? "); + else + printk("%02x ", c); + } + printk("\n"); + + printk(KERN_ERR "PAX: bytes at SP-4: "); + for (i = -1; i < 20; i++) { + unsigned long c; + if (get_user(c, (unsigned long __user *)sp+i)) + printk("???????? "); + else + printk("%08lx ", c); + } + printk("\n"); +} +#endif diff -NurpP --minimal linux-2.6.17.11/arch/i386/mm/hugetlbpage.c linux-2.6.17.11-g-v/arch/i386/mm/hugetlbpage.c --- linux-2.6.17.11/arch/i386/mm/hugetlbpage.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/mm/hugetlbpage.c 2006-08-28 14:44:48.000000000 +0200 @@ -121,7 +121,12 @@ static unsigned long hugetlb_get_unmappe { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; - unsigned long start_addr; + unsigned long start_addr, task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + task_size = SEGMEXEC_TASK_SIZE; +#endif if (len > mm->cached_hole_size) { start_addr = mm->free_area_cache; @@ -135,7 +140,7 @@ full_search: for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { /* At this point: (!vma || addr < vma->vm_end). */ - if (TASK_SIZE - len < addr) { + if (task_size - len < addr) { /* * Start a new search - just in case we missed * some holes. @@ -163,9 +168,8 @@ static unsigned long hugetlb_get_unmappe { struct mm_struct *mm = current->mm; struct vm_area_struct *vma, *prev_vma; - unsigned long base = mm->mmap_base, addr = addr0; + unsigned long base = mm->mmap_base, addr; unsigned long largest_hole = mm->cached_hole_size; - int first_time = 1; /* don't allow allocations above current base */ if (mm->free_area_cache > base) @@ -175,7 +179,7 @@ static unsigned long hugetlb_get_unmappe largest_hole = 0; mm->free_area_cache = base; } -try_again: + /* make sure it can fit in the remaining address space */ if (mm->free_area_cache < len) goto fail; @@ -217,16 +221,6 @@ try_again: fail: /* - * if hint left us with no space for the requested - * mapping then try again: - */ - if (first_time) { - mm->free_area_cache = base; - largest_hole = 0; - first_time = 0; - goto try_again; - } - /* * A failed mmap() very likely causes application failure, * so fall back to the bottom-up function here. This scenario * can happen with large stack limits and large mmap() @@ -252,16 +246,23 @@ hugetlb_get_unmapped_area(struct file *f { struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + unsigned long task_size = TASK_SIZE; if (len & ~HPAGE_MASK) return -EINVAL; - if (len > TASK_SIZE) + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + task_size = SEGMEXEC_TASK_SIZE; +#endif + + if (len > task_size || addr > task_size - len) return -ENOMEM; if (addr) { addr = ALIGN(addr, HPAGE_SIZE); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && + if (task_size - len >= addr && (!vma || addr + len <= vma->vm_start)) return addr; } diff -NurpP --minimal linux-2.6.17.11/arch/i386/mm/init.c linux-2.6.17.11-g-v/arch/i386/mm/init.c --- linux-2.6.17.11/arch/i386/mm/init.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/mm/init.c 2006-08-28 14:44:48.000000000 +0200 @@ -41,6 +41,7 @@ #include #include #include +#include unsigned int __VMALLOC_RESERVE = 128 << 20; @@ -50,30 +51,6 @@ unsigned long highstart_pfn, highend_pfn static int noinline do_test_wp_bit(void); /* - * Creates a middle page table and puts a pointer to it in the - * given global directory entry. This only returns the gd entry - * in non-PAE compilation mode, since the middle layer is folded. - */ -static pmd_t * __init one_md_table_init(pgd_t *pgd) -{ - pud_t *pud; - pmd_t *pmd_table; - -#ifdef CONFIG_X86_PAE - pmd_table = (pmd_t *) alloc_bootmem_low_pages(PAGE_SIZE); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - pud = pud_offset(pgd, 0); - if (pmd_table != pmd_offset(pud, 0)) - BUG(); -#else - pud = pud_offset(pgd, 0); - pmd_table = pmd_offset(pud, 0); -#endif - - return pmd_table; -} - -/* * Create a page table and place a pointer to it in a middle page * directory entry. */ @@ -81,7 +58,11 @@ static pte_t * __init one_page_table_ini { if (pmd_none(*pmd)) { pte_t *page_table = (pte_t *) alloc_bootmem_low_pages(PAGE_SIZE); +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + set_pmd(pmd, __pmd(__pa(page_table) | _KERNPG_TABLE)); +#else set_pmd(pmd, __pmd(__pa(page_table) | _PAGE_TABLE)); +#endif if (page_table != pte_offset_kernel(pmd, 0)) BUG(); @@ -116,8 +97,6 @@ static void __init page_table_range_init pgd = pgd_base + pgd_idx; for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - if (pgd_none(*pgd)) - one_md_table_init(pgd); pud = pud_offset(pgd, vaddr); pmd = pmd_offset(pud, vaddr); for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { @@ -130,11 +109,22 @@ static void __init page_table_range_init } } -static inline int is_kernel_text(unsigned long addr) +static inline int is_kernel_text(unsigned long start, unsigned long end) { - if (addr >= PAGE_OFFSET && addr <= (unsigned long)__init_end) - return 1; - return 0; + unsigned long etext; + +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + etext = (unsigned long)&MODULES_END - __KERNEL_TEXT_OFFSET; +#else + etext = (unsigned long)&_etext; +#endif + + if ((start > etext + __KERNEL_TEXT_OFFSET || + end <= (unsigned long)_stext + __KERNEL_TEXT_OFFSET) && + (start > (unsigned long)_einittext + __KERNEL_TEXT_OFFSET || + end <= (unsigned long)_sinittext + __KERNEL_TEXT_OFFSET)) + return 0; + return 1; } /* @@ -146,26 +136,24 @@ static void __init kernel_physical_mappi { unsigned long pfn; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; - int pgd_idx, pmd_idx, pte_ofs; + unsigned int pgd_idx, pmd_idx, pte_ofs; pgd_idx = pgd_index(PAGE_OFFSET); pgd = pgd_base + pgd_idx; pfn = 0; - for (; pgd_idx < PTRS_PER_PGD; pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - if (pfn >= max_low_pfn) - continue; + for (; pgd_idx < PTRS_PER_PGD && pfn < max_low_pfn; pgd++, pgd_idx++) { + pud = pud_offset(pgd, 0); + pmd = pmd_offset(pud, 0); for (pmd_idx = 0; pmd_idx < PTRS_PER_PMD && pfn < max_low_pfn; pmd++, pmd_idx++) { - unsigned int address = pfn * PAGE_SIZE + PAGE_OFFSET; + unsigned long address = pfn * PAGE_SIZE + PAGE_OFFSET; /* Map with big pages if possible, otherwise create normal page tables. */ if (cpu_has_pse) { - unsigned int address2 = (pfn + PTRS_PER_PTE - 1) * PAGE_SIZE + PAGE_OFFSET + PAGE_SIZE-1; - - if (is_kernel_text(address) || is_kernel_text(address2)) + if (is_kernel_text(address, address + PMD_SIZE)) set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE_EXEC)); else set_pmd(pmd, pfn_pmd(pfn, PAGE_KERNEL_LARGE)); @@ -174,7 +162,7 @@ static void __init kernel_physical_mappi pte = one_page_table_init(pmd); for (pte_ofs = 0; pte_ofs < PTRS_PER_PTE && pfn < max_low_pfn; pte++, pfn++, pte_ofs++) { - if (is_kernel_text(address)) + if (is_kernel_text(address, address + PAGE_SIZE)) set_pte(pte, pfn_pte(pfn, PAGE_KERNEL_EXEC)); else set_pte(pte, pfn_pte(pfn, PAGE_KERNEL)); @@ -341,13 +329,6 @@ static void __init pagetable_init (void) unsigned long vaddr; pgd_t *pgd_base = swapper_pg_dir; -#ifdef CONFIG_X86_PAE - int i; - /* Init entries of the first-level page table to the zero page */ - for (i = 0; i < PTRS_PER_PGD; i++) - set_pgd(pgd_base + i, __pgd(__pa(empty_zero_page) | _PAGE_PRESENT)); -#endif - /* Enable PSE if available */ if (cpu_has_pse) { set_in_cr4(X86_CR4_PSE); @@ -371,17 +352,6 @@ static void __init pagetable_init (void) page_table_range_init(vaddr, 0, pgd_base); permanent_kmaps_init(pgd_base); - -#ifdef CONFIG_X86_PAE - /* - * Add low memory identity-mappings - SMP needs it when - * starting up on an AP from real-mode. In the non-PAE - * case we already have these mappings through head.S. - * All user-space mappings are explicitly cleared after - * SMP startup. - */ - set_pgd(&pgd_base[0], pgd_base[USER_PTRS_PER_PGD]); -#endif } #ifdef CONFIG_SOFTWARE_SUSPEND @@ -423,7 +393,6 @@ void zap_low_mappings (void) flush_tlb_all(); } -static int disable_nx __initdata = 0; u64 __supported_pte_mask __read_mostly = ~_PAGE_NX; /* @@ -437,11 +406,9 @@ u64 __supported_pte_mask __read_mostly = void __init noexec_setup(const char *str) { if (!strncmp(str, "on",2) && cpu_has_nx) { - __supported_pte_mask |= _PAGE_NX; - disable_nx = 0; + nx_enabled = 1; } else if (!strncmp(str,"off",3)) { - disable_nx = 1; - __supported_pte_mask &= ~_PAGE_NX; + nx_enabled = 0; } } @@ -450,17 +417,13 @@ int nx_enabled = 0; static void __init set_nx(void) { - unsigned int v[4], l, h; + if (!nx_enabled && cpu_has_nx) { + unsigned l, h; - if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { - cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); - if ((v[3] & (1 << 20)) && !disable_nx) { - rdmsr(MSR_EFER, l, h); - l |= EFER_NX; - wrmsr(MSR_EFER, l, h); - nx_enabled = 1; - __supported_pte_mask |= _PAGE_NX; - } + __supported_pte_mask &= ~_PAGE_NX; + rdmsr(MSR_EFER, l, h); + l &= ~EFER_NX; + wrmsr(MSR_EFER, l, h); } } @@ -512,14 +475,6 @@ void __init paging_init(void) load_cr3(swapper_pg_dir); -#ifdef CONFIG_X86_PAE - /* - * We will bail out later - printk doesn't work right now so - * the user would just see a hanging kernel. - */ - if (cpu_has_pae) - set_in_cr4(X86_CR4_PAE); -#endif __flush_tlb_all(); kmap_init(); @@ -611,7 +566,7 @@ void __init mem_init(void) set_highmem_pages_init(bad_ppro); codesize = (unsigned long) &_etext - (unsigned long) &_text; - datasize = (unsigned long) &_edata - (unsigned long) &_etext; + datasize = (unsigned long) &_edata - (unsigned long) &_data; initsize = (unsigned long) &__init_end - (unsigned long) &__init_begin; kclist_add(&kcore_mem, __va(0), max_low_pfn << PAGE_SHIFT); @@ -628,10 +583,6 @@ void __init mem_init(void) (unsigned long) (totalhigh_pages << (PAGE_SHIFT-10)) ); -#ifdef CONFIG_X86_PAE - if (!cpu_has_pae) - panic("cannot execute a PAE-enabled kernel on a PAE-less CPU!"); -#endif if (boot_cpu_data.wp_works_ok < 0) test_wp_bit(); @@ -761,6 +712,37 @@ void free_init_pages(char *what, unsigne void free_initmem(void) { + +#ifdef CONFIG_PAX_KERNEXEC + /* PaX: limit KERNEL_CS to actual size */ + unsigned long addr, limit; + int cpu; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + +#ifdef CONFIG_MODULES + limit = (unsigned long)&MODULES_END - __KERNEL_TEXT_OFFSET; +#else + limit = (unsigned long)&_etext; +#endif + limit = (limit - 1UL) >> PAGE_SHIFT; + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + get_cpu_gdt_table(cpu)[GDT_ENTRY_KERNEL_CS].a = (get_cpu_gdt_table(cpu)[GDT_ENTRY_KERNEL_CS].a & 0xFFFF0000UL) | (limit & 0x0FFFFUL); + get_cpu_gdt_table(cpu)[GDT_ENTRY_KERNEL_CS].b = (get_cpu_gdt_table(cpu)[GDT_ENTRY_KERNEL_CS].b & 0xFFF0FFFFUL) | (limit & 0xF0000UL); + } + + /* PaX: make KERNEL_CS read-only */ + for (addr = __KERNEL_TEXT_OFFSET; addr < (unsigned long)&_data; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW)); + } + flush_tlb_all(); +#endif + free_init_pages("unused kernel memory", (unsigned long)(&__init_begin), (unsigned long)(&__init_end)); diff -NurpP --minimal linux-2.6.17.11/arch/i386/mm/mmap.c linux-2.6.17.11-g-v/arch/i386/mm/mmap.c --- linux-2.6.17.11/arch/i386/mm/mmap.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/mm/mmap.c 2006-08-28 14:44:48.000000000 +0200 @@ -34,12 +34,18 @@ * Leave an at least ~128 MB hole. */ #define MIN_GAP (128*1024*1024) -#define MAX_GAP (TASK_SIZE/6*5) +#define MAX_GAP (task_size/6*5) static inline unsigned long mmap_base(struct mm_struct *mm) { unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur; unsigned long random_factor = 0; + unsigned long task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + task_size = SEGMEXEC_TASK_SIZE; +#endif if (current->flags & PF_RANDOMIZE) random_factor = get_random_int() % (1024*1024); @@ -49,7 +55,7 @@ static inline unsigned long mmap_base(st else if (gap > MAX_GAP) gap = MAX_GAP; - return PAGE_ALIGN(TASK_SIZE - gap - random_factor); + return PAGE_ALIGN(task_size - gap - random_factor); } /* @@ -66,10 +72,22 @@ void arch_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 -NurpP --minimal linux-2.6.17.11/arch/i386/mm/pageattr.c linux-2.6.17.11-g-v/arch/i386/mm/pageattr.c --- linux-2.6.17.11/arch/i386/mm/pageattr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/mm/pageattr.c 2006-08-28 14:44:48.000000000 +0200 @@ -14,6 +14,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(cpa_lock); static struct list_head df_list = LIST_HEAD_INIT(df_list); @@ -84,7 +85,18 @@ static void set_pmd_pte(pte_t *kpte, uns struct page *page; unsigned long flags; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + set_pte_atomic(kpte, pte); /* change init_mm */ + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + if (PTRS_PER_PMD > 1) return; @@ -111,7 +123,7 @@ static inline void revert_page(struct pa pte_t *linear; ref_prot = - ((address & LARGE_PAGE_MASK) < (unsigned long)&_etext) + ((address & LARGE_PAGE_MASK) < (unsigned long)&_etext + __KERNEL_TEXT_OFFSET) ? PAGE_KERNEL_LARGE_EXEC : PAGE_KERNEL_LARGE; linear = (pte_t *) @@ -143,7 +155,7 @@ __change_page_attr(struct page *page, pg struct page *split; ref_prot = - ((address & LARGE_PAGE_MASK) < (unsigned long)&_etext) + ((address & LARGE_PAGE_MASK) < (unsigned long)&_etext + __KERNEL_TEXT_OFFSET) ? PAGE_KERNEL_EXEC : PAGE_KERNEL; split = split_large_page(address, prot, ref_prot); if (!split) diff -NurpP --minimal linux-2.6.17.11/arch/i386/oprofile/backtrace.c linux-2.6.17.11-g-v/arch/i386/oprofile/backtrace.c --- linux-2.6.17.11/arch/i386/oprofile/backtrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/oprofile/backtrace.c 2006-08-28 14:44:48.000000000 +0200 @@ -116,7 +116,7 @@ x86_backtrace(struct pt_regs * const reg head = (struct frame_head *)regs->ebp; #endif - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { while (depth-- && valid_kernel_stack(head, regs)) head = dump_kernel_backtrace(head); return; diff -NurpP --minimal linux-2.6.17.11/arch/i386/power/cpu.c linux-2.6.17.11-g-v/arch/i386/power/cpu.c --- linux-2.6.17.11/arch/i386/power/cpu.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/i386/power/cpu.c 2006-08-28 14:44:48.000000000 +0200 @@ -62,7 +62,7 @@ static void do_fpu_end(void) static void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct * t = &per_cpu(init_tss, cpu); + struct tss_struct * t = init_tss + cpu; set_tss_desc(cpu,t); /* This just modifies memory; should not be necessary. But... This is necessary, because 386 hardware has concept of busy TSS or some similar stupidity. */ diff -NurpP --minimal linux-2.6.17.11/arch/ia64/Kconfig linux-2.6.17.11-g-v/arch/ia64/Kconfig --- linux-2.6.17.11/arch/ia64/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -506,6 +506,8 @@ endmenu source "arch/ia64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/ia64/ia32/binfmt_elf32.c linux-2.6.17.11-g-v/arch/ia64/ia32/binfmt_elf32.c --- linux-2.6.17.11/arch/ia64/ia32/binfmt_elf32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/ia32/binfmt_elf32.c 2006-08-28 14:56:36.000000000 +0200 @@ -46,6 +46,17 @@ 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(tsk) ((tsk)->personality == PER_LINUX32 ? 0x08048000UL : 0x4000000000000000UL) + +#define PAX_DELTA_MMAP_LSB(tsk) IA32_PAGE_SHIFT +#define PAX_DELTA_MMAP_LEN(tsk) ((tsk)->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - IA32_PAGE_SHIFT) +#define PAX_DELTA_EXEC_LSB(tsk) IA32_PAGE_SHIFT +#define PAX_DELTA_EXEC_LEN(tsk) ((tsk)->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - IA32_PAGE_SHIFT) +#define PAX_DELTA_STACK_LSB(tsk) IA32_PAGE_SHIFT +#define PAX_DELTA_STACK_LEN(tsk) ((tsk)->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - IA32_PAGE_SHIFT) +#endif + /* Ugly but avoids duplication */ #include "../../../fs/binfmt_elf.c" @@ -239,7 +250,8 @@ ia32_setup_arg_pages (struct linux_binpr kmem_cache_free(vm_area_cachep, mpnt); return ret; } - current->mm->stack_vm = current->mm->total_vm = vma_pages(mpnt); + vx_vmpages_sub(current->mm, current->mm->total_vm - vma_pages(mpnt)); + current->mm->stack_vm = current->mm->total_vm; } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff -NurpP --minimal linux-2.6.17.11/arch/ia64/ia32/ia32_entry.S linux-2.6.17.11-g-v/arch/ia64/ia32/ia32_entry.S --- linux-2.6.17.11/arch/ia64/ia32/ia32_entry.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/ia32/ia32_entry.S 2006-08-28 14:56:36.000000000 +0200 @@ -483,7 +483,7 @@ ia32_syscall_table: data8 sys_tgkill /* 270 */ data8 compat_sys_utimes data8 sys32_fadvise64_64 - data8 sys_ni_syscall + data8 sys32_vserver data8 sys_ni_syscall data8 sys_ni_syscall /* 275 */ data8 sys_ni_syscall diff -NurpP --minimal linux-2.6.17.11/arch/ia64/ia32/ia32priv.h linux-2.6.17.11-g-v/arch/ia64/ia32/ia32priv.h --- linux-2.6.17.11/arch/ia64/ia32/ia32priv.h 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/ia32/ia32priv.h 2006-08-28 14:44:48.000000000 +0200 @@ -305,7 +305,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 -NurpP --minimal linux-2.6.17.11/arch/ia64/kernel/entry.S linux-2.6.17.11-g-v/arch/ia64/kernel/entry.S --- linux-2.6.17.11/arch/ia64/kernel/entry.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/kernel/entry.S 2006-08-28 14:56:36.000000000 +0200 @@ -1577,7 +1577,7 @@ sys_call_table: data8 sys_mq_notify data8 sys_mq_getsetattr data8 sys_ni_syscall // reserved for kexec_load - data8 sys_ni_syscall // reserved for vserver + data8 sys_vserver data8 sys_waitid // 1270 data8 sys_add_key data8 sys_request_key diff -NurpP --minimal linux-2.6.17.11/arch/ia64/kernel/module.c linux-2.6.17.11-g-v/arch/ia64/kernel/module.c --- linux-2.6.17.11/arch/ia64/kernel/module.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/kernel/module.c 2006-08-28 14:44:48.000000000 +0200 @@ -322,7 +322,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; } @@ -500,15 +500,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, value) || in_init_rw(mod, value); +} + +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, value) || in_core_rw(mod, value); } static inline int @@ -692,7 +716,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: @@ -826,15 +857,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 -NurpP --minimal linux-2.6.17.11/arch/ia64/kernel/perfmon.c linux-2.6.17.11-g-v/arch/ia64/kernel/perfmon.c --- linux-2.6.17.11/arch/ia64/kernel/perfmon.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/kernel/perfmon.c 2006-08-28 14:56:36.000000000 +0200 @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include @@ -2355,7 +2357,7 @@ pfm_smpl_buffer_alloc(struct task_struct */ insert_vm_struct(mm, vma); - mm->total_vm += size >> PAGE_SHIFT; + vx_vmpages_add(mm, size >> PAGE_SHIFT); vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, vma_pages(vma)); up_write(&task->mm->mmap_sem); diff -NurpP --minimal linux-2.6.17.11/arch/ia64/kernel/ptrace.c linux-2.6.17.11-g-v/arch/ia64/kernel/ptrace.c --- linux-2.6.17.11/arch/ia64/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/kernel/ptrace.c 2006-08-28 14:56:36.000000000 +0200 @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -1443,10 +1445,16 @@ sys_ptrace (long request, pid_t pid, uns read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; + ret = -EPERM; if (pid == 1) /* no messing around with init! */ goto out_tsk; + if (gr_handle_ptrace(child, request)) + goto out_tsk; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); goto out_tsk; diff -NurpP --minimal linux-2.6.17.11/arch/ia64/kernel/sys_ia64.c linux-2.6.17.11-g-v/arch/ia64/kernel/sys_ia64.c --- linux-2.6.17.11/arch/ia64/kernel/sys_ia64.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/kernel/sys_ia64.c 2006-08-28 14:44:49.000000000 +0200 @@ -38,6 +38,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; @@ -56,9 +63,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 -NurpP --minimal linux-2.6.17.11/arch/ia64/mm/fault.c linux-2.6.17.11-g-v/arch/ia64/mm/fault.c --- linux-2.6.17.11/arch/ia64/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/mm/fault.c 2006-08-28 14:56:36.000000000 +0200 @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -51,6 +53,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) { @@ -116,9 +135,23 @@ ia64_do_page_fault (unsigned long addres | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT) | (((isr >> IA64_ISR_R_BIT) & 1UL) << VM_READ_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_exit(SIGKILL); + } +#endif + goto bad_area; + } + survive: /* * If for any reason at all we couldn't handle the fault, make diff -NurpP --minimal linux-2.6.17.11/arch/ia64/mm/init.c linux-2.6.17.11-g-v/arch/ia64/mm/init.c --- linux-2.6.17.11/arch/ia64/mm/init.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/mm/init.c 2006-08-28 14:44:49.000000000 +0200 @@ -20,8 +20,8 @@ #include #include #include +#include -#include #include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/ia64/sn/kernel/xpc_main.c linux-2.6.17.11-g-v/arch/ia64/sn/kernel/xpc_main.c --- linux-2.6.17.11/arch/ia64/sn/kernel/xpc_main.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ia64/sn/kernel/xpc_main.c 2006-08-28 14:56:36.000000000 +0200 @@ -108,6 +108,7 @@ static ctl_table xpc_sys_xpc_hb_dir[] = 0644, NULL, &proc_dointvec_minmax, + NULL, &sysctl_intvec, NULL, &xpc_hb_min_interval, @@ -121,6 +122,7 @@ static ctl_table xpc_sys_xpc_hb_dir[] = 0644, NULL, &proc_dointvec_minmax, + NULL, &sysctl_intvec, NULL, &xpc_hb_check_min_interval, @@ -145,6 +147,7 @@ static ctl_table xpc_sys_xpc_dir[] = { 0644, NULL, &proc_dointvec_minmax, + NULL, &sysctl_intvec, NULL, &xpc_disengage_request_min_timelimit, diff -NurpP --minimal linux-2.6.17.11/arch/m32r/kernel/sys_m32r.c linux-2.6.17.11-g-v/arch/m32r/kernel/sys_m32r.c --- linux-2.6.17.11/arch/m32r/kernel/sys_m32r.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/m32r/kernel/sys_m32r.c 2006-08-28 14:56:36.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -206,7 +207,7 @@ asmlinkage int sys_uname(struct old_utsn if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } diff -NurpP --minimal linux-2.6.17.11/arch/m68k/Kconfig linux-2.6.17.11-g-v/arch/m68k/Kconfig --- linux-2.6.17.11/arch/m68k/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/m68k/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -654,6 +654,8 @@ source "fs/Kconfig" source "arch/m68k/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/m68k/kernel/ptrace.c linux-2.6.17.11-g-v/arch/m68k/kernel/ptrace.c --- linux-2.6.17.11/arch/m68k/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/m68k/kernel/ptrace.c 2006-08-28 14:56:36.000000000 +0200 @@ -280,6 +280,8 @@ long arch_ptrace(struct task_struct *chi ret = ptrace_request(child, request, addr, data); break; } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; return ret; out_eio: diff -NurpP --minimal linux-2.6.17.11/arch/m68knommu/Kconfig linux-2.6.17.11-g-v/arch/m68knommu/Kconfig --- linux-2.6.17.11/arch/m68knommu/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/m68knommu/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -654,6 +654,8 @@ source "fs/Kconfig" source "arch/m68knommu/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/mips/Kconfig linux-2.6.17.11-g-v/arch/mips/Kconfig --- linux-2.6.17.11/arch/mips/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -1852,6 +1852,8 @@ source "arch/mips/oprofile/Kconfig" source "arch/mips/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/binfmt_elfn32.c linux-2.6.17.11-g-v/arch/mips/kernel/binfmt_elfn32.c --- linux-2.6.17.11/arch/mips/kernel/binfmt_elfn32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/binfmt_elfn32.c 2006-08-28 14:44:49.000000000 +0200 @@ -50,6 +50,17 @@ 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(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_MMAP_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_EXEC_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_EXEC_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_STACK_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/binfmt_elfo32.c linux-2.6.17.11-g-v/arch/mips/kernel/binfmt_elfo32.c --- linux-2.6.17.11/arch/mips/kernel/binfmt_elfo32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/binfmt_elfo32.c 2006-08-28 14:44:49.000000000 +0200 @@ -52,6 +52,17 @@ 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(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_MMAP_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_EXEC_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_EXEC_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_STACK_LEN(tsk) (((tsk)->thread.mflags & MF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/linux32.c linux-2.6.17.11-g-v/arch/mips/kernel/linux32.c --- linux-2.6.17.11/arch/mips/kernel/linux32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/linux32.c 2006-08-28 14:56:36.000000000 +0200 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -1040,7 +1041,7 @@ asmlinkage long sys32_newuname(struct ne int ret = 0; down_read(&uts_sem); - if (copy_to_user(name,&system_utsname,sizeof *name)) + if (copy_to_user(name, vx_new_utsname(), sizeof *name)) ret = -EFAULT; up_read(&uts_sem); diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/mips-mt.c linux-2.6.17.11-g-v/arch/mips/kernel/mips-mt.c --- linux-2.6.17.11/arch/mips/kernel/mips-mt.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/mips-mt.c 2006-08-28 14:56:36.000000000 +0200 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/ptrace.c linux-2.6.17.11-g-v/arch/mips/kernel/ptrace.c --- linux-2.6.17.11/arch/mips/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/ptrace.c 2006-08-28 14:56:36.000000000 +0200 @@ -490,6 +490,8 @@ asmlinkage void do_syscall_trace(struct goto out; if (!test_thread_flag(TIF_SYSCALL_TRACE)) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; /* The 0x80 provides a way for the tracing parent to distinguish between a syscall stop and SIGTRAP delivery */ diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/scall32-o32.S linux-2.6.17.11-g-v/arch/mips/kernel/scall32-o32.S --- linux-2.6.17.11/arch/mips/kernel/scall32-o32.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/scall32-o32.S 2006-08-28 14:56:36.000000000 +0200 @@ -618,7 +618,7 @@ einval: li v0, -EINVAL sys sys_mq_timedreceive 5 sys sys_mq_notify 2 /* 4275 */ sys sys_mq_getsetattr 3 - sys sys_ni_syscall 0 /* sys_vserver */ + sys sys_vserver 3 sys sys_waitid 5 sys sys_ni_syscall 0 /* available, was setaltroot */ sys sys_add_key 5 /* 4280 */ diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/scall64-64.S linux-2.6.17.11-g-v/arch/mips/kernel/scall64-64.S --- linux-2.6.17.11/arch/mips/kernel/scall64-64.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/scall64-64.S 2006-08-28 14:56:36.000000000 +0200 @@ -433,7 +433,7 @@ sys_call_table: PTR sys_mq_timedreceive PTR sys_mq_notify PTR sys_mq_getsetattr /* 5235 */ - PTR sys_ni_syscall /* sys_vserver */ + PTR sys_vserver PTR sys_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/scall64-n32.S linux-2.6.17.11-g-v/arch/mips/kernel/scall64-n32.S --- linux-2.6.17.11/arch/mips/kernel/scall64-n32.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/scall64-n32.S 2006-08-28 14:56:36.000000000 +0200 @@ -359,7 +359,7 @@ EXPORT(sysn32_call_table) PTR compat_sys_mq_timedreceive PTR compat_sys_mq_notify PTR compat_sys_mq_getsetattr - PTR sys_ni_syscall /* 6240, sys_vserver */ + PTR sys32_vserver /* 6240 */ PTR sysn32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/scall64-o32.S linux-2.6.17.11-g-v/arch/mips/kernel/scall64-o32.S --- linux-2.6.17.11/arch/mips/kernel/scall64-o32.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/scall64-o32.S 2006-08-28 14:56:36.000000000 +0200 @@ -481,7 +481,7 @@ sys_call_table: PTR compat_sys_mq_timedreceive PTR compat_sys_mq_notify /* 4275 */ PTR compat_sys_mq_getsetattr - PTR sys_ni_syscall /* sys_vserver */ + PTR sys32_vserver PTR sys32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key /* 4280 */ diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/syscall.c linux-2.6.17.11-g-v/arch/mips/kernel/syscall.c --- linux-2.6.17.11/arch/mips/kernel/syscall.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/syscall.c 2006-08-28 14:56:36.000000000 +0200 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -89,6 +90,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); @@ -99,7 +105,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 @@ -232,7 +238,7 @@ out: */ asmlinkage int sys_uname(struct old_utsname __user * name) { - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + if (name && !copy_to_user(name, vx_new_utsname(), sizeof (*name))) return 0; return -EFAULT; } @@ -243,21 +249,23 @@ asmlinkage int sys_uname(struct old_utsn asmlinkage int sys_olduname(struct oldold_utsname __user * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; if (!access_ok(VERIFY_WRITE,name,sizeof(struct oldold_utsname))) return -EFAULT; - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN); error -= __put_user(0,name->sysname+__OLD_UTS_LEN); - error -= __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + error -= __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN); error -= __put_user(0,name->nodename+__OLD_UTS_LEN); - error -= __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + error -= __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN); error -= __put_user(0,name->release+__OLD_UTS_LEN); - error -= __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + error -= __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN); error -= __put_user(0,name->version+__OLD_UTS_LEN); - error -= __copy_to_user(&name->machine,&system_utsname.machine,__OLD_UTS_LEN); + error -= __copy_to_user(&name->machine,ptr->machine,__OLD_UTS_LEN); error = __put_user(0,name->machine+__OLD_UTS_LEN); error = error ? -EFAULT : 0; diff -NurpP --minimal linux-2.6.17.11/arch/mips/kernel/sysirix.c linux-2.6.17.11-g-v/arch/mips/kernel/sysirix.c --- linux-2.6.17.11/arch/mips/kernel/sysirix.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/kernel/sysirix.c 2006-08-28 14:56:36.000000000 +0200 @@ -31,6 +31,7 @@ #include #include #include +#include #include #include @@ -884,7 +885,7 @@ asmlinkage int irix_getdomainname(char _ down_read(&uts_sem); if (len > __NEW_UTS_LEN) len = __NEW_UTS_LEN; - err = copy_to_user(name, system_utsname.domainname, len) ? -EFAULT : 0; + err = copy_to_user(name, vx_new_uts(domainname), len) ? -EFAULT : 0; up_read(&uts_sem); return err; @@ -1127,11 +1128,11 @@ struct iuname { asmlinkage int irix_uname(struct iuname __user *buf) { down_read(&uts_sem); - if (copy_from_user(system_utsname.sysname, buf->sysname, 65) - || copy_from_user(system_utsname.nodename, buf->nodename, 65) - || copy_from_user(system_utsname.release, buf->release, 65) - || copy_from_user(system_utsname.version, buf->version, 65) - || copy_from_user(system_utsname.machine, buf->machine, 65)) { + if (copy_from_user(vx_new_uts(sysname), buf->sysname, 65) + || copy_from_user(vx_new_uts(nodename), buf->nodename, 65) + || copy_from_user(vx_new_uts(release), buf->release, 65) + || copy_from_user(vx_new_uts(version), buf->version, 65) + || copy_from_user(vx_new_uts(machine), buf->machine, 65)) { return -EFAULT; } up_read(&uts_sem); diff -NurpP --minimal linux-2.6.17.11/arch/mips/mm/fault.c linux-2.6.17.11-g-v/arch/mips/mm/fault.c --- linux-2.6.17.11/arch/mips/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/mips/mm/fault.c 2006-08-28 14:44:49.000000000 +0200 @@ -27,6 +27,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 -NurpP --minimal linux-2.6.17.11/arch/parisc/Kconfig linux-2.6.17.11-g-v/arch/parisc/Kconfig --- linux-2.6.17.11/arch/parisc/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -253,6 +253,8 @@ source "arch/parisc/oprofile/Kconfig" source "arch/parisc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/parisc/hpux/sys_hpux.c linux-2.6.17.11-g-v/arch/parisc/hpux/sys_hpux.c --- linux-2.6.17.11/arch/parisc/hpux/sys_hpux.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/hpux/sys_hpux.c 2006-08-28 14:56:36.000000000 +0200 @@ -33,6 +33,7 @@ #include #include #include +#include #include #include @@ -266,15 +267,15 @@ static int hpux_uname(struct hpux_utsnam down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,HPUX_UTSLEN-1); + error = __copy_to_user(&name->sysname,vx_new_uts(sysname),HPUX_UTSLEN-1); error |= __put_user(0,name->sysname+HPUX_UTSLEN-1); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename,HPUX_UTSLEN-1); + error |= __copy_to_user(&name->nodename,vx_new_uts(nodename),HPUX_UTSLEN-1); error |= __put_user(0,name->nodename+HPUX_UTSLEN-1); - error |= __copy_to_user(&name->release,&system_utsname.release,HPUX_UTSLEN-1); + error |= __copy_to_user(&name->release,vx_new_uts(release),HPUX_UTSLEN-1); error |= __put_user(0,name->release+HPUX_UTSLEN-1); - error |= __copy_to_user(&name->version,&system_utsname.version,HPUX_UTSLEN-1); + error |= __copy_to_user(&name->version,vx_new_uts(version),HPUX_UTSLEN-1); error |= __put_user(0,name->version+HPUX_UTSLEN-1); - error |= __copy_to_user(&name->machine,&system_utsname.machine,HPUX_UTSLEN-1); + error |= __copy_to_user(&name->machine,vx_new_uts(machine),HPUX_UTSLEN-1); error |= __put_user(0,name->machine+HPUX_UTSLEN-1); up_read(&uts_sem); @@ -373,8 +374,8 @@ int hpux_utssys(char *ubuf, int n, int t /* TODO: print a warning about using this? */ down_write(&uts_sem); error = -EFAULT; - if (!copy_from_user(system_utsname.sysname, ubuf, len)) { - system_utsname.sysname[len] = 0; + if (!copy_from_user(vx_new_uts(sysname), ubuf, len)) { + vx_new_uts(sysname)[len] = 0; error = 0; } up_write(&uts_sem); @@ -400,8 +401,8 @@ int hpux_utssys(char *ubuf, int n, int t /* TODO: print a warning about this? */ down_write(&uts_sem); error = -EFAULT; - if (!copy_from_user(system_utsname.release, ubuf, len)) { - system_utsname.release[len] = 0; + if (!copy_from_user(vx_new_uts(release), ubuf, len)) { + vx_new_uts(release)[len] = 0; error = 0; } up_write(&uts_sem); @@ -422,13 +423,13 @@ int hpux_getdomainname(char *name, int l down_read(&uts_sem); - nlen = strlen(system_utsname.domainname) + 1; + nlen = strlen(vx_new_uts(domainname)) + 1; if (nlen < len) len = nlen; if(len > __NEW_UTS_LEN) goto done; - if(copy_to_user(name, system_utsname.domainname, len)) + if(copy_to_user(name, vx_new_uts(domainname), len)) goto done; err = 0; done: diff -NurpP --minimal linux-2.6.17.11/arch/parisc/kernel/module.c linux-2.6.17.11-g-v/arch/parisc/kernel/module.c --- linux-2.6.17.11/arch/parisc/kernel/module.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/kernel/module.c 2006-08-28 14:44:49.000000000 +0200 @@ -72,16 +72,38 @@ /* three functions to determine where in the module core * or init pieces the location is */ +static inline int is_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 is_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 is_init(struct module *me, void *loc) { - return (loc >= me->module_init && - loc <= (me->module_init + me->init_size)); + return is_init_rx(me, loc) || is_init_rw(me, loc); +} + +static inline int is_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 is_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 is_core(struct module *me, void *loc) { - return (loc >= me->module_core && - loc <= (me->module_core + me->core_size)); + return is_core_rx(me, loc) || is_core_rw(me, loc); } static inline int is_local(struct module *me, void *loc) @@ -289,21 +311,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_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 = ALIGN(me->core_size, 16); - me->arch.fdesc_offset = me->core_size; - me->core_size += fdescs * sizeof(Elf_Fdesc); + 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 = ALIGN(me->core_size, 16); - me->arch.stub_offset = me->core_size; - me->core_size += stubs * sizeof(struct stub_entry); + 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 = ALIGN(me->init_size, 16); - me->arch.init_stub_offset = me->init_size; - me->init_size += init_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; @@ -323,7 +345,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; @@ -341,7 +363,7 @@ static Elf64_Word get_got(struct module #ifdef __LP64__ 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); @@ -359,7 +381,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 /* __LP64__ */ @@ -373,12 +395,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); } @@ -721,7 +743,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 -NurpP --minimal linux-2.6.17.11/arch/parisc/kernel/ptrace.c linux-2.6.17.11-g-v/arch/parisc/kernel/ptrace.c --- linux-2.6.17.11/arch/parisc/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/kernel/ptrace.c 2006-08-28 14:44:49.000000000 +0200 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/parisc/kernel/sys_parisc.c linux-2.6.17.11-g-v/arch/parisc/kernel/sys_parisc.c --- linux-2.6.17.11/arch/parisc/kernel/sys_parisc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/kernel/sys_parisc.c 2006-08-28 14:44:49.000000000 +0200 @@ -105,7 +105,7 @@ unsigned long arch_get_unmapped_area(str if (len > TASK_SIZE) return -ENOMEM; if (!addr) - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; if (filp) { addr = get_shared_area(filp->f_mapping, addr, len, pgoff); diff -NurpP --minimal linux-2.6.17.11/arch/parisc/kernel/sys_parisc32.c linux-2.6.17.11-g-v/arch/parisc/kernel/sys_parisc32.c --- linux-2.6.17.11/arch/parisc/kernel/sys_parisc32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/kernel/sys_parisc32.c 2006-08-28 14:56:36.000000000 +0200 @@ -599,6 +599,7 @@ asmlinkage int sys32_sysinfo(struct sysi do { seq = read_seqbegin(&xtime_lock); + /* FIXME: requires vx virtualization */ val.uptime = jiffies / HZ; val.loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); diff -NurpP --minimal linux-2.6.17.11/arch/parisc/kernel/syscall_table.S linux-2.6.17.11-g-v/arch/parisc/kernel/syscall_table.S --- linux-2.6.17.11/arch/parisc/kernel/syscall_table.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/kernel/syscall_table.S 2006-08-28 14:56:36.000000000 +0200 @@ -368,7 +368,7 @@ ENTRY_COMP(mbind) /* 260 */ ENTRY_COMP(get_mempolicy) ENTRY_COMP(set_mempolicy) - ENTRY_SAME(ni_syscall) /* 263: reserved for vserver */ + ENTRY_DIFF(vserver) ENTRY_SAME(add_key) ENTRY_SAME(request_key) /* 265 */ ENTRY_SAME(keyctl) diff -NurpP --minimal linux-2.6.17.11/arch/parisc/kernel/traps.c linux-2.6.17.11-g-v/arch/parisc/kernel/traps.c --- linux-2.6.17.11/arch/parisc/kernel/traps.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/kernel/traps.c 2006-08-28 14:44:49.000000000 +0200 @@ -711,9 +711,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 -NurpP --minimal linux-2.6.17.11/arch/parisc/mm/fault.c linux-2.6.17.11-g-v/arch/parisc/mm/fault.c --- linux-2.6.17.11/arch/parisc/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/parisc/mm/fault.c 2006-08-28 14:44:49.000000000 +0200 @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include #include @@ -57,7 +59,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) { @@ -143,6 +145,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) { @@ -168,8 +280,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_exit(SIGKILL); + } +#endif + goto bad_area; + } /* * If for any reason at all we couldn't handle the fault, make diff -NurpP --minimal linux-2.6.17.11/arch/powerpc/Kconfig linux-2.6.17.11-g-v/arch/powerpc/Kconfig --- linux-2.6.17.11/arch/powerpc/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/powerpc/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -1018,6 +1018,8 @@ endmenu source "arch/powerpc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" config KEYS_COMPAT diff -NurpP --minimal linux-2.6.17.11/arch/powerpc/kernel/module_32.c linux-2.6.17.11-g-v/arch/powerpc/kernel/module_32.c --- linux-2.6.17.11/arch/powerpc/kernel/module_32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/powerpc/kernel/module_32.c 2006-08-28 14:44:49.000000000 +0200 @@ -123,7 +123,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; } @@ -164,11 +164,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 -NurpP --minimal linux-2.6.17.11/arch/powerpc/kernel/process.c linux-2.6.17.11-g-v/arch/powerpc/kernel/process.c --- linux-2.6.17.11/arch/powerpc/kernel/process.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/powerpc/kernel/process.c 2006-08-28 14:56:36.000000000 +0200 @@ -432,8 +432,9 @@ void show_regs(struct pt_regs * regs) trap = TRAP(regs); if (trap == 0x300 || trap == 0x600) printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr); - printk("TASK = %p[%d] '%s' THREAD: %p", - current, current->pid, current->comm, task_thread_info(current)); + printk("TASK = %p[%d,#%u] '%s' THREAD: %p", + current, current->pid, current->xid, + current->comm, task_thread_info(current)); #ifdef CONFIG_SMP printk(" CPU: %d", smp_processor_id()); diff -NurpP --minimal linux-2.6.17.11/arch/powerpc/kernel/syscalls.c linux-2.6.17.11-g-v/arch/powerpc/kernel/syscalls.c --- linux-2.6.17.11/arch/powerpc/kernel/syscalls.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/powerpc/kernel/syscalls.c 2006-08-28 14:56:36.000000000 +0200 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -260,7 +261,7 @@ long ppc_newuname(struct new_utsname __u int err = 0; down_read(&uts_sem); - if (copy_to_user(name, &system_utsname, sizeof(*name))) + if (copy_to_user(name, vx_new_utsname(), sizeof(*name))) err = -EFAULT; up_read(&uts_sem); if (!err) @@ -273,7 +274,7 @@ int sys_uname(struct old_utsname __user int err = 0; down_read(&uts_sem); - if (copy_to_user(name, &system_utsname, sizeof(*name))) + if (copy_to_user(name, vx_new_utsname(), sizeof(*name))) err = -EFAULT; up_read(&uts_sem); if (!err) @@ -284,25 +285,22 @@ int sys_uname(struct old_utsname __user int sys_olduname(struct oldold_utsname __user *name) { int error; + struct new_utsname *ptr; if (!access_ok(VERIFY_WRITE, name, sizeof(struct oldold_utsname))) return -EFAULT; down_read(&uts_sem); - error = __copy_to_user(&name->sysname, &system_utsname.sysname, - __OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname, ptr->sysname, __OLD_UTS_LEN); error |= __put_user(0, name->sysname + __OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename, &system_utsname.nodename, - __OLD_UTS_LEN); + error |= __copy_to_user(&name->nodename, ptr->nodename, __OLD_UTS_LEN); error |= __put_user(0, name->nodename + __OLD_UTS_LEN); - error |= __copy_to_user(&name->release, &system_utsname.release, - __OLD_UTS_LEN); + error |= __copy_to_user(&name->release, ptr->release, __OLD_UTS_LEN); error |= __put_user(0, name->release + __OLD_UTS_LEN); - error |= __copy_to_user(&name->version, &system_utsname.version, - __OLD_UTS_LEN); + error |= __copy_to_user(&name->version, ptr->version, __OLD_UTS_LEN); error |= __put_user(0, name->version + __OLD_UTS_LEN); - error |= __copy_to_user(&name->machine, &system_utsname.machine, - __OLD_UTS_LEN); + error |= __copy_to_user(&name->machine, ptr->machine, __OLD_UTS_LEN); error |= override_machine(name->machine); up_read(&uts_sem); diff -NurpP --minimal linux-2.6.17.11/arch/powerpc/kernel/systbl.S linux-2.6.17.11-g-v/arch/powerpc/kernel/systbl.S --- linux-2.6.17.11/arch/powerpc/kernel/systbl.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/powerpc/kernel/systbl.S 2006-08-28 14:56:36.000000000 +0200 @@ -296,7 +296,7 @@ COMPAT_SYS(fstatfs64) SYSX(sys_ni_syscall, ppc_fadvise64_64, ppc_fadvise64_64) PPC_SYS(rtas) OLDSYS(debug_setcontext) -SYSCALL(ni_syscall) +SYSX(sys_vserver, sys32_vserver, sys_vserver) SYSCALL(ni_syscall) COMPAT_SYS(mbind) COMPAT_SYS(get_mempolicy) diff -NurpP --minimal linux-2.6.17.11/arch/powerpc/kernel/vdso.c linux-2.6.17.11-g-v/arch/powerpc/kernel/vdso.c --- linux-2.6.17.11/arch/powerpc/kernel/vdso.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/powerpc/kernel/vdso.c 2006-08-28 14:56:36.000000000 +0200 @@ -23,6 +23,7 @@ #include #include #include +#include #include #include @@ -293,7 +294,7 @@ int arch_setup_additional_pages(struct l kmem_cache_free(vm_area_cachep, vma); return -ENOMEM; } - mm->total_vm += (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; + vx_vmpages_add(mm, (vma->vm_end - vma->vm_start) >> PAGE_SHIFT); up_write(&mm->mmap_sem); return 0; diff -NurpP --minimal linux-2.6.17.11/arch/powerpc/mm/fault.c linux-2.6.17.11-g-v/arch/powerpc/mm/fault.c --- linux-2.6.17.11/arch/powerpc/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/powerpc/mm/fault.c 2006-08-28 14:44:49.000000000 +0200 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include @@ -103,6 +104,38 @@ static void do_dabr(struct pt_regs *regs } #endif /* !(CONFIG_4xx || CONFIG_BOOKE)*/ +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->nip = fault address) + * + * returns 1 when task should be killed + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#if defined(CONFIG_PAX_EMUPLT) || defined(CONFIG_PAX_EMUSIGRT) + int err; +#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 + /* * For 600- and 800-family processors, the error_code parameter is DSISR * for a data fault, SRR1 for an instruction fault. For 400-family processors @@ -335,6 +368,19 @@ 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) { + if (is_exec && (error_code & DSISR_PROTFAULT)) { + switch (pax_handle_fetch_fault(regs)) { + } + + pax_report_fault(regs, (void*)regs->nip, (void*)regs->gpr[1]); + do_exit(SIGKILL); + } + } +#endif + _exception(SIGSEGV, regs, code, address); return 0; } diff -NurpP --minimal linux-2.6.17.11/arch/powerpc/mm/mmap.c linux-2.6.17.11-g-v/arch/powerpc/mm/mmap.c --- linux-2.6.17.11/arch/powerpc/mm/mmap.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/powerpc/mm/mmap.c 2006-08-28 14:44:49.000000000 +0200 @@ -74,10 +74,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; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } diff -NurpP --minimal linux-2.6.17.11/arch/ppc/Kconfig linux-2.6.17.11-g-v/arch/ppc/Kconfig --- linux-2.6.17.11/arch/ppc/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ppc/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -1414,6 +1414,8 @@ source "arch/powerpc/oprofile/Kconfig" source "arch/ppc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/ppc/mm/fault.c linux-2.6.17.11-g-v/arch/ppc/mm/fault.c --- linux-2.6.17.11/arch/ppc/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/ppc/mm/fault.c 2006-08-28 14:44:49.000000000 +0200 @@ -26,6 +26,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -49,6 +54,364 @@ 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; + + memset(vma, 0, sizeof(*vma)); + 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 = protection_map[vma->vm_flags & 0x0f]; + 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 + * 7 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_alloc(vm_area_cachep, SLAB_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_alloc(vm_area_cachep, SLAB_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 +472,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 +567,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 +597,7 @@ good_area: pte_unmap_unlock(ptep, ptl); } #endif +#endif /* a read */ } else { /* protection fault */ @@ -280,6 +643,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_exit(SIGKILL); + } + } +#endif + _exception(SIGSEGV, regs, code, address); return 0; } diff -NurpP --minimal linux-2.6.17.11/arch/s390/Kconfig linux-2.6.17.11-g-v/arch/s390/Kconfig --- linux-2.6.17.11/arch/s390/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/s390/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -478,6 +478,8 @@ source "arch/s390/oprofile/Kconfig" source "arch/s390/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/s390/kernel/module.c linux-2.6.17.11-g-v/arch/s390/kernel/module.c --- linux-2.6.17.11/arch/s390/kernel/module.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/s390/kernel/module.c 2006-08-28 14:44:49.000000000 +0200 @@ -164,11 +164,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; } @@ -254,7 +254,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; @@ -278,7 +278,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; @@ -292,7 +292,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 */ @@ -314,7 +314,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) @@ -334,7 +334,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) @@ -344,7 +344,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 -NurpP --minimal linux-2.6.17.11/arch/s390/kernel/process.c linux-2.6.17.11-g-v/arch/s390/kernel/process.c --- linux-2.6.17.11/arch/s390/kernel/process.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/s390/kernel/process.c 2006-08-28 14:56:36.000000000 +0200 @@ -165,9 +165,9 @@ void show_regs(struct pt_regs *regs) struct task_struct *tsk = current; printk("CPU: %d %s\n", task_thread_info(tsk)->cpu, print_tainted()); - printk("Process %s (pid: %d, task: %p, ksp: %p)\n", - current->comm, current->pid, (void *) tsk, - (void *) tsk->thread.ksp); + printk("Process %s (pid: %d[#%u], task: %p, ksp: %p)\n", + current->comm, current->pid, current->xid, + (void *) tsk, (void *) tsk->thread.ksp); show_registers(regs); /* Show stack backtrace if pt_regs is from kernel mode */ diff -NurpP --minimal linux-2.6.17.11/arch/s390/kernel/ptrace.c linux-2.6.17.11-g-v/arch/s390/kernel/ptrace.c --- linux-2.6.17.11/arch/s390/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/s390/kernel/ptrace.c 2006-08-28 14:56:36.000000000 +0200 @@ -723,7 +723,13 @@ sys_ptrace(long request, long pid, long goto out; } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { + ret = -EPERM; + goto out_tsk; + } + ret = do_ptrace(child, request, addr, data); +out_tsk: put_task_struct(child); out: unlock_kernel(); diff -NurpP --minimal linux-2.6.17.11/arch/s390/kernel/syscalls.S linux-2.6.17.11-g-v/arch/s390/kernel/syscalls.S --- linux-2.6.17.11/arch/s390/kernel/syscalls.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/s390/kernel/syscalls.S 2006-08-28 14:56:36.000000000 +0200 @@ -271,7 +271,7 @@ SYSCALL(sys_clock_settime,sys_clock_sett SYSCALL(sys_clock_gettime,sys_clock_gettime,sys32_clock_gettime_wrapper) /* 260 */ SYSCALL(sys_clock_getres,sys_clock_getres,sys32_clock_getres_wrapper) SYSCALL(sys_clock_nanosleep,sys_clock_nanosleep,sys32_clock_nanosleep_wrapper) -NI_SYSCALL /* reserved for vserver */ +SYSCALL(sys_vserver,sys_vserver,sys32_vserver) SYSCALL(s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper) SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper) SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper) diff -NurpP --minimal linux-2.6.17.11/arch/sh/Kconfig linux-2.6.17.11-g-v/arch/sh/Kconfig --- linux-2.6.17.11/arch/sh/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sh/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -646,6 +646,8 @@ source "arch/sh/oprofile/Kconfig" source "arch/sh/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/sh/kernel/kgdb_stub.c linux-2.6.17.11-g-v/arch/sh/kernel/kgdb_stub.c --- linux-2.6.17.11/arch/sh/kernel/kgdb_stub.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sh/kernel/kgdb_stub.c 2006-08-28 14:56:36.000000000 +0200 @@ -412,7 +412,7 @@ static struct task_struct *get_thread(in if (pid == PID_MAX) pid = 0; /* First check via PID */ - thread = find_task_by_pid(pid); + thread = find_task_by_real_pid(pid); if (thread) return thread; diff -NurpP --minimal linux-2.6.17.11/arch/sh/kernel/setup.c linux-2.6.17.11-g-v/arch/sh/kernel/setup.c --- linux-2.6.17.11/arch/sh/kernel/setup.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sh/kernel/setup.c 2006-08-28 14:56:36.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include #include @@ -481,7 +482,7 @@ static int show_cpuinfo(struct seq_file seq_printf(m, "machine\t\t: %s\n", get_system_type()); seq_printf(m, "processor\t: %d\n", cpu); - seq_printf(m, "cpu family\t: %s\n", system_utsname.machine); + seq_printf(m, "cpu family\t: %s\n", vx_new_uts(machine)); seq_printf(m, "cpu type\t: %s\n", get_cpu_subtype()); show_cpuflags(m); diff -NurpP --minimal linux-2.6.17.11/arch/sh/kernel/sys_sh.c linux-2.6.17.11-g-v/arch/sh/kernel/sys_sh.c --- linux-2.6.17.11/arch/sh/kernel/sys_sh.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sh/kernel/sys_sh.c 2006-08-28 14:56:36.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -267,7 +268,7 @@ asmlinkage int sys_uname(struct old_utsn if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } diff -NurpP --minimal linux-2.6.17.11/arch/sh64/kernel/sys_sh64.c linux-2.6.17.11-g-v/arch/sh64/kernel/sys_sh64.c --- linux-2.6.17.11/arch/sh64/kernel/sys_sh64.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sh64/kernel/sys_sh64.c 2006-08-28 14:56:36.000000000 +0200 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -279,7 +280,7 @@ asmlinkage int sys_uname(struct old_utsn if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } diff -NurpP --minimal linux-2.6.17.11/arch/sparc/Kconfig linux-2.6.17.11-g-v/arch/sparc/Kconfig --- linux-2.6.17.11/arch/sparc/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -291,6 +291,8 @@ source "fs/Kconfig" source "arch/sparc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/sparc/Makefile linux-2.6.17.11-g-v/arch/sparc/Makefile --- linux-2.6.17.11/arch/sparc/Makefile 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/Makefile 2006-08-28 14:44:49.000000000 +0200 @@ -34,7 +34,7 @@ libs-y += arch/sparc/prom/ arch/sparc/li # Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-) INIT_Y := $(patsubst %/, %/built-in.o, $(init-y)) CORE_Y := $(core-y) -CORE_Y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ +CORE_Y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ grsecurity/ CORE_Y := $(patsubst %/, %/built-in.o, $(CORE_Y)) DRIVERS_Y := $(patsubst %/, %/built-in.o, $(drivers-y)) NET_Y := $(patsubst %/, %/built-in.o, $(net-y)) diff -NurpP --minimal linux-2.6.17.11/arch/sparc/kernel/ptrace.c linux-2.6.17.11-g-v/arch/sparc/kernel/ptrace.c --- linux-2.6.17.11/arch/sparc/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/kernel/ptrace.c 2006-08-28 14:56:36.000000000 +0200 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -300,6 +301,16 @@ asmlinkage void do_ptrace(struct pt_regs goto out; } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { + pt_error_return(regs, ESRCH); + goto out_tsk; + } + + if (gr_handle_ptrace(child, request)) { + pt_error_return(regs, EPERM); + goto out_tsk; + } + if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { if (ptrace_attach(child)) { diff -NurpP --minimal linux-2.6.17.11/arch/sparc/kernel/sys_sparc.c linux-2.6.17.11-g-v/arch/sparc/kernel/sys_sparc.c --- linux-2.6.17.11/arch/sparc/kernel/sys_sparc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/kernel/sys_sparc.c 2006-08-28 14:56:36.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include @@ -56,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); @@ -473,13 +474,13 @@ asmlinkage int sys_getdomainname(char __ down_read(&uts_sem); - nlen = strlen(system_utsname.domainname) + 1; + nlen = strlen(vx_new_uts(domainname)) + 1; if (nlen < len) len = nlen; if (len > __NEW_UTS_LEN) goto done; - if (copy_to_user(name, system_utsname.domainname, len)) + if (copy_to_user(name, vx_new_uts(domainname), len)) goto done; err = 0; done: diff -NurpP --minimal linux-2.6.17.11/arch/sparc/kernel/sys_sunos.c linux-2.6.17.11-g-v/arch/sparc/kernel/sys_sunos.c --- linux-2.6.17.11/arch/sparc/kernel/sys_sunos.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/kernel/sys_sunos.c 2006-08-28 14:56:36.000000000 +0200 @@ -35,6 +35,7 @@ #include #include #include +#include #include @@ -482,14 +483,16 @@ struct sunos_utsname { asmlinkage int sunos_uname(struct sunos_utsname __user *name) { int ret; + struct new_utsname *ptr; down_read(&uts_sem); - ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], sizeof(name->sname) - 1); + ptr = vx_new_utsname(); + ret = copy_to_user(&name->sname[0], ptr->sysname, sizeof(name->sname) - 1); if (!ret) { - ret |= __copy_to_user(&name->nname[0], &system_utsname.nodename[0], sizeof(name->nname) - 1); + ret |= __copy_to_user(&name->nname[0], ptr->nodename, sizeof(name->nname) - 1); ret |= __put_user('\0', &name->nname[8]); - ret |= __copy_to_user(&name->rel[0], &system_utsname.release[0], sizeof(name->rel) - 1); - ret |= __copy_to_user(&name->ver[0], &system_utsname.version[0], sizeof(name->ver) - 1); - ret |= __copy_to_user(&name->mach[0], &system_utsname.machine[0], sizeof(name->mach) - 1); + ret |= __copy_to_user(&name->rel[0], ptr->release, sizeof(name->rel) - 1); + ret |= __copy_to_user(&name->ver[0], ptr->version, sizeof(name->ver) - 1); + ret |= __copy_to_user(&name->mach[0], ptr->machine, sizeof(name->mach) - 1); } up_read(&uts_sem); return ret ? -EFAULT : 0; diff -NurpP --minimal linux-2.6.17.11/arch/sparc/kernel/systbls.S linux-2.6.17.11-g-v/arch/sparc/kernel/systbls.S --- linux-2.6.17.11/arch/sparc/kernel/systbls.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/kernel/systbls.S 2006-08-28 14:56:36.000000000 +0200 @@ -72,7 +72,7 @@ sys_call_table: /*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl /*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun -/*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy +/*265*/ .long sys_timer_delete, sys_timer_create, sys_vserver, sys_io_setup, sys_io_destroy /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .long sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat diff -NurpP --minimal linux-2.6.17.11/arch/sparc/mm/fault.c linux-2.6.17.11-g-v/arch/sparc/mm/fault.c --- linux-2.6.17.11/arch/sparc/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/mm/fault.c 2006-08-28 14:44:49.000000000 +0200 @@ -21,6 +21,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -217,6 +221,252 @@ 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; + + memset(vma, 0, sizeof(*vma)); + 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 = protection_map[vma->vm_flags & 0x0f]; + 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_alloc(vm_area_cachep, SLAB_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 +530,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_exit(SIGKILL); + } +#endif + /* Allow reads even for write-only mappings */ if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; diff -NurpP --minimal linux-2.6.17.11/arch/sparc/mm/init.c linux-2.6.17.11-g-v/arch/sparc/mm/init.c --- linux-2.6.17.11/arch/sparc/mm/init.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/mm/init.c 2006-08-28 14:44:49.000000000 +0200 @@ -333,17 +333,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 -NurpP --minimal linux-2.6.17.11/arch/sparc/mm/srmmu.c linux-2.6.17.11-g-v/arch/sparc/mm/srmmu.c --- linux-2.6.17.11/arch/sparc/mm/srmmu.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc/mm/srmmu.c 2006-08-28 14:44:49.000000000 +0200 @@ -2161,6 +2161,13 @@ void __init ld_mmu_srmmu(void) BTFIXUPSET_INT(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 + BTFIXUPSET_INT(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 -NurpP --minimal linux-2.6.17.11/arch/sparc64/Kconfig linux-2.6.17.11-g-v/arch/sparc64/Kconfig --- linux-2.6.17.11/arch/sparc64/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -423,6 +423,8 @@ endmenu source "arch/sparc64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/sparc64/kernel/binfmt_aout32.c linux-2.6.17.11-g-v/arch/sparc64/kernel/binfmt_aout32.c --- linux-2.6.17.11/arch/sparc64/kernel/binfmt_aout32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/kernel/binfmt_aout32.c 2006-08-28 14:56:36.000000000 +0200 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/sparc64/kernel/ptrace.c linux-2.6.17.11-g-v/arch/sparc64/kernel/ptrace.c --- linux-2.6.17.11/arch/sparc64/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/kernel/ptrace.c 2006-08-28 14:56:36.000000000 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -213,6 +214,16 @@ asmlinkage void do_ptrace(struct pt_regs goto out; } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) { + pt_error_return(regs, ESRCH); + goto out_tsk; + } + + if (gr_handle_ptrace(child, (long)request)) { + pt_error_return(regs, EPERM); + goto out_tsk; + } + if ((current->personality == PER_SUNOS && request == PTRACE_SUNATTACH) || (current->personality != PER_SUNOS && request == PTRACE_ATTACH)) { if (ptrace_attach(child)) { diff -NurpP --minimal linux-2.6.17.11/arch/sparc64/kernel/sys_sparc.c linux-2.6.17.11-g-v/arch/sparc64/kernel/sys_sparc.c --- linux-2.6.17.11/arch/sparc64/kernel/sys_sparc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/kernel/sys_sparc.c 2006-08-28 14:56:36.000000000 +0200 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -140,6 +141,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); @@ -153,9 +158,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; } @@ -175,8 +180,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; } @@ -379,6 +384,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 { @@ -393,6 +404,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; } @@ -711,13 +728,13 @@ asmlinkage long sys_getdomainname(char _ down_read(&uts_sem); - nlen = strlen(system_utsname.domainname) + 1; + nlen = strlen(vx_new_uts(domainname)) + 1; if (nlen < len) len = nlen; if (len > __NEW_UTS_LEN) goto done; - if (copy_to_user(name, system_utsname.domainname, len)) + if (copy_to_user(name, vx_new_uts(domainname), len)) goto done; err = 0; done: diff -NurpP --minimal linux-2.6.17.11/arch/sparc64/kernel/sys_sunos32.c linux-2.6.17.11-g-v/arch/sparc64/kernel/sys_sunos32.c --- linux-2.6.17.11/arch/sparc64/kernel/sys_sunos32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/kernel/sys_sunos32.c 2006-08-28 14:56:36.000000000 +0200 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -437,18 +438,20 @@ struct sunos_utsname { asmlinkage int sunos_uname(struct sunos_utsname __user *name) { int ret; + struct new_utsname *ptr; down_read(&uts_sem); - ret = copy_to_user(&name->sname[0], &system_utsname.sysname[0], + ptr = vx_new_utsname(); + ret = copy_to_user(&name->sname[0], ptr->sysname, sizeof(name->sname) - 1); - ret |= copy_to_user(&name->nname[0], &system_utsname.nodename[0], + ret |= copy_to_user(&name->nname[0], ptr->nodename, sizeof(name->nname) - 1); ret |= put_user('\0', &name->nname[8]); - ret |= copy_to_user(&name->rel[0], &system_utsname.release[0], + ret |= copy_to_user(&name->rel[0], ptr->release, sizeof(name->rel) - 1); - ret |= copy_to_user(&name->ver[0], &system_utsname.version[0], + ret |= copy_to_user(&name->ver[0], ptr->version, sizeof(name->ver) - 1); - ret |= copy_to_user(&name->mach[0], &system_utsname.machine[0], + ret |= copy_to_user(&name->mach[0], ptr->machine, sizeof(name->mach) - 1); up_read(&uts_sem); return (ret ? -EFAULT : 0); diff -NurpP --minimal linux-2.6.17.11/arch/sparc64/kernel/systbls.S linux-2.6.17.11-g-v/arch/sparc64/kernel/systbls.S --- linux-2.6.17.11/arch/sparc64/kernel/systbls.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/kernel/systbls.S 2006-08-28 14:56:36.000000000 +0200 @@ -73,7 +73,7 @@ sys_call_table32: /*250*/ .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl .word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun - .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy + .word sys_timer_delete, compat_sys_timer_create, sys32_vserver, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid /*280*/ .word sys32_tee, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat @@ -143,7 +143,7 @@ sys_call_table: /*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun - .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy + .word sys_timer_delete, sys_timer_create, sys_vserver, sys_io_setup, sys_io_destroy /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .word sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat diff -NurpP --minimal linux-2.6.17.11/arch/sparc64/mm/fault.c linux-2.6.17.11-g-v/arch/sparc64/mm/fault.c --- linux-2.6.17.11/arch/sparc64/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/mm/fault.c 2006-08-28 14:44:49.000000000 +0200 @@ -19,6 +19,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -253,6 +257,369 @@ 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; + + memset(vma, 0, sizeof(*vma)); + 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 = protection_map[vma->vm_flags & 0x0f]; + 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_alloc(vm_area_cachep, SLAB_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; @@ -295,8 +662,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; } @@ -313,6 +682,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_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 -NurpP --minimal linux-2.6.17.11/arch/sparc64/solaris/fs.c linux-2.6.17.11-g-v/arch/sparc64/solaris/fs.c --- linux-2.6.17.11/arch/sparc64/solaris/fs.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/solaris/fs.c 2006-08-28 14:56:36.000000000 +0200 @@ -363,7 +363,7 @@ static int report_statvfs(struct vfsmoun int j = strlen (p); if (j > 15) j = 15; - if (IS_RDONLY(inode)) i = 1; + if (IS_RDONLY(inode) || MNT_IS_RDONLY(mnt)) i = 1; if (mnt->mnt_flags & MNT_NOSUID) i |= 2; if (!sysv_valid_dev(inode->i_sb->s_dev)) return -EOVERFLOW; @@ -399,7 +399,7 @@ static int report_statvfs64(struct vfsmo int j = strlen (p); if (j > 15) j = 15; - if (IS_RDONLY(inode)) i = 1; + if (IS_RDONLY(inode) || MNT_IS_RDONLY(mnt)) i = 1; if (mnt->mnt_flags & MNT_NOSUID) i |= 2; if (!sysv_valid_dev(inode->i_sb->s_dev)) return -EOVERFLOW; diff -NurpP --minimal linux-2.6.17.11/arch/sparc64/solaris/misc.c linux-2.6.17.11-g-v/arch/sparc64/solaris/misc.c --- linux-2.6.17.11/arch/sparc64/solaris/misc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/sparc64/solaris/misc.c 2006-08-28 14:56:36.000000000 +0200 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -239,7 +240,7 @@ asmlinkage int solaris_utssys(u32 buf, u /* Let's cheat */ err = set_utsfield(v->sysname, "SunOS", 1, 0); down_read(&uts_sem); - err |= set_utsfield(v->nodename, system_utsname.nodename, + err |= set_utsfield(v->nodename, vx_new_uts(nodename), 1, 1); up_read(&uts_sem); err |= set_utsfield(v->release, "2.6", 0, 0); @@ -263,7 +264,7 @@ asmlinkage int solaris_utsname(u32 buf) /* Why should we not lie a bit? */ down_read(&uts_sem); err = set_utsfield(v->sysname, "SunOS", 0, 0); - err |= set_utsfield(v->nodename, system_utsname.nodename, 1, 1); + err |= set_utsfield(v->nodename, vx_new_uts(nodename), 1, 1); err |= set_utsfield(v->release, "5.6", 0, 0); err |= set_utsfield(v->version, "Generic", 0, 0); err |= set_utsfield(v->machine, machine(), 0, 0); @@ -295,7 +296,7 @@ asmlinkage int solaris_sysinfo(int cmd, case SI_HOSTNAME: r = buffer + 256; down_read(&uts_sem); - for (p = system_utsname.nodename, q = buffer; + for (p = vx_new_uts(nodename), q = buffer; q < r && *p && *p != '.'; *q++ = *p++); up_read(&uts_sem); *q = 0; diff -NurpP --minimal linux-2.6.17.11/arch/um/Kconfig linux-2.6.17.11-g-v/arch/um/Kconfig --- linux-2.6.17.11/arch/um/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/um/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -279,6 +279,8 @@ source "drivers/connector/Kconfig" source "fs/Kconfig" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/um/drivers/mconsole_kern.c linux-2.6.17.11-g-v/arch/um/drivers/mconsole_kern.c --- linux-2.6.17.11/arch/um/drivers/mconsole_kern.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/um/drivers/mconsole_kern.c 2006-08-28 14:56:36.000000000 +0200 @@ -23,6 +23,7 @@ #include "linux/list.h" #include "linux/mm.h" #include "linux/console.h" +#include "linux/vs_cvirt.h" #include "asm/irq.h" #include "asm/uaccess.h" #include "user_util.h" diff -NurpP --minimal linux-2.6.17.11/arch/um/kernel/syscall_kern.c linux-2.6.17.11-g-v/arch/um/kernel/syscall_kern.c --- linux-2.6.17.11/arch/um/kernel/syscall_kern.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/um/kernel/syscall_kern.c 2006-08-28 14:56:36.000000000 +0200 @@ -15,6 +15,8 @@ #include "linux/unistd.h" #include "linux/slab.h" #include "linux/utime.h" +#include + #include "asm/mman.h" #include "asm/uaccess.h" #include "kern_util.h" @@ -110,7 +112,7 @@ long sys_uname(struct old_utsname __user if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); return err?-EFAULT:0; } @@ -118,6 +120,7 @@ long sys_uname(struct old_utsname __user long sys_olduname(struct oldold_utsname __user * name) { long error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -126,19 +129,20 @@ long sys_olduname(struct oldold_utsname down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname, + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname, __OLD_UTS_LEN); error |= __put_user(0,name->sysname+__OLD_UTS_LEN); - error |= __copy_to_user(&name->nodename,&system_utsname.nodename, + error |= __copy_to_user(&name->nodename,ptr->nodename, __OLD_UTS_LEN); error |= __put_user(0,name->nodename+__OLD_UTS_LEN); - error |= __copy_to_user(&name->release,&system_utsname.release, + error |= __copy_to_user(&name->release,ptr->release, __OLD_UTS_LEN); error |= __put_user(0,name->release+__OLD_UTS_LEN); - error |= __copy_to_user(&name->version,&system_utsname.version, + error |= __copy_to_user(&name->version,ptr->version, __OLD_UTS_LEN); error |= __put_user(0,name->version+__OLD_UTS_LEN); - error |= __copy_to_user(&name->machine,&system_utsname.machine, + error |= __copy_to_user(&name->machine,ptr->machine, __OLD_UTS_LEN); error |= __put_user(0,name->machine+__OLD_UTS_LEN); diff -NurpP --minimal linux-2.6.17.11/arch/um/sys-x86_64/syscalls.c linux-2.6.17.11-g-v/arch/um/sys-x86_64/syscalls.c --- linux-2.6.17.11/arch/um/sys-x86_64/syscalls.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/um/sys-x86_64/syscalls.c 2006-08-28 14:56:36.000000000 +0200 @@ -9,6 +9,7 @@ #include "linux/shm.h" #include "linux/utsname.h" #include "linux/personality.h" +#include "linux/vs_cvirt.h" #include "asm/uaccess.h" #define __FRAME_OFFSETS #include "asm/ptrace.h" @@ -21,7 +22,7 @@ asmlinkage long sys_uname64(struct new_u { int err; down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); if (personality(current->personality) == PER_LINUX32) err |= copy_to_user(&name->machine, "i686", 5); diff -NurpP --minimal linux-2.6.17.11/arch/v850/Kconfig linux-2.6.17.11-g-v/arch/v850/Kconfig --- linux-2.6.17.11/arch/v850/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/v850/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -326,6 +326,8 @@ source "drivers/usb/Kconfig" source "arch/v850/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/v850/kernel/module.c linux-2.6.17.11-g-v/arch/v850/kernel/module.c --- linux-2.6.17.11/arch/v850/kernel/module.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/v850/kernel/module.c 2006-08-28 14:44:49.000000000 +0200 @@ -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 -NurpP --minimal linux-2.6.17.11/arch/v850/kernel/ptrace.c linux-2.6.17.11-g-v/arch/v850/kernel/ptrace.c --- linux-2.6.17.11/arch/v850/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/v850/kernel/ptrace.c 2006-08-28 14:56:36.000000000 +0200 @@ -117,6 +117,9 @@ long arch_ptrace(struct task_struct *chi { int rval; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out; + switch (request) { unsigned long val, copied; diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/Kconfig linux-2.6.17.11-g-v/arch/x86_64/Kconfig --- linux-2.6.17.11/arch/x86_64/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -617,6 +617,8 @@ endmenu source "arch/x86_64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/boot/compressed/head.S linux-2.6.17.11-g-v/arch/x86_64/boot/compressed/head.S --- linux-2.6.17.11/arch/x86_64/boot/compressed/head.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/boot/compressed/head.S 2006-08-28 14:44:49.000000000 +0200 @@ -41,11 +41,13 @@ startup_32: movl %eax,%gs lss stack_start,%esp + movl 0x000000,%ecx xorl %eax,%eax 1: incl %eax # check that A20 really IS enabled movl %eax,0x000000 # loop forever if it isn't cmpl %eax,0x100000 je 1b + movl %ecx,0x000000 /* * Initialize eflags. Some BIOS's leave bits like NT set. This would diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/ia32/ia32_aout.c linux-2.6.17.11-g-v/arch/x86_64/ia32/ia32_aout.c --- linux-2.6.17.11/arch/x86_64/ia32/ia32_aout.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/ia32/ia32_aout.c 2006-08-28 14:56:36.000000000 +0200 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/ia32/ia32_binfmt.c linux-2.6.17.11-g-v/arch/x86_64/ia32/ia32_binfmt.c --- linux-2.6.17.11/arch/x86_64/ia32/ia32_binfmt.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/ia32/ia32_binfmt.c 2006-08-28 14:56:36.000000000 +0200 @@ -186,6 +186,17 @@ struct elf_prpsinfo //#include #include +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE(tsk) 0x08048000UL + +#define PAX_DELTA_MMAP_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_MMAP_LEN(tsk) 16 +#define PAX_DELTA_EXEC_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_EXEC_LEN(tsk) 16 +#define PAX_DELTA_STACK_LSB(tsk) PAGE_SHIFT +#define PAX_DELTA_STACK_LEN(tsk) 16 +#endif + typedef struct user_i387_ia32_struct elf_fpregset_t; typedef struct user32_fxsr_struct elf_fpxregset_t; @@ -371,7 +382,8 @@ int ia32_setup_arg_pages(struct linux_bi kmem_cache_free(vm_area_cachep, mpnt); return ret; } - mm->stack_vm = mm->total_vm = vma_pages(mpnt); + vx_vmpages_sub(mm, mm->total_vm - vma_pages(mpnt)); + mm->stack_vm = mm->total_vm; } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/ia32/ia32entry.S linux-2.6.17.11-g-v/arch/x86_64/ia32/ia32entry.S --- linux-2.6.17.11/arch/x86_64/ia32/ia32entry.S 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/ia32/ia32entry.S 2006-08-28 14:56:36.000000000 +0200 @@ -652,7 +652,7 @@ ia32_sys_call_table: .quad sys_tgkill /* 270 */ .quad compat_sys_utimes .quad sys32_fadvise64_64 - .quad quiet_ni_syscall /* sys_vserver */ + .quad sys32_vserver .quad sys_mbind .quad compat_sys_get_mempolicy /* 275 */ .quad sys_set_mempolicy diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/ia32/mmap32.c linux-2.6.17.11-g-v/arch/x86_64/ia32/mmap32.c --- linux-2.6.17.11/arch/x86_64/ia32/mmap32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/ia32/mmap32.c 2006-08-28 14:44:49.000000000 +0200 @@ -68,10 +68,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 -NurpP --minimal linux-2.6.17.11/arch/x86_64/ia32/sys_ia32.c linux-2.6.17.11-g-v/arch/x86_64/ia32/sys_ia32.c --- linux-2.6.17.11/arch/x86_64/ia32/sys_ia32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/ia32/sys_ia32.c 2006-08-28 14:56:36.000000000 +0200 @@ -61,6 +61,7 @@ #include #include #include +#include #include #include #include @@ -793,6 +794,7 @@ asmlinkage long sys32_mmap2(unsigned lon asmlinkage long sys32_olduname(struct oldold_utsname __user * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -801,13 +803,14 @@ asmlinkage long sys32_olduname(struct ol down_read(&uts_sem); - error = __copy_to_user(&name->sysname,&system_utsname.sysname,__OLD_UTS_LEN); + ptr = vx_new_utsname(); + error = __copy_to_user(&name->sysname,ptr->sysname,__OLD_UTS_LEN); __put_user(0,name->sysname+__OLD_UTS_LEN); - __copy_to_user(&name->nodename,&system_utsname.nodename,__OLD_UTS_LEN); + __copy_to_user(&name->nodename,ptr->nodename,__OLD_UTS_LEN); __put_user(0,name->nodename+__OLD_UTS_LEN); - __copy_to_user(&name->release,&system_utsname.release,__OLD_UTS_LEN); + __copy_to_user(&name->release,ptr->release,__OLD_UTS_LEN); __put_user(0,name->release+__OLD_UTS_LEN); - __copy_to_user(&name->version,&system_utsname.version,__OLD_UTS_LEN); + __copy_to_user(&name->version,ptr->version,__OLD_UTS_LEN); __put_user(0,name->version+__OLD_UTS_LEN); { char *arch = "x86_64"; @@ -830,7 +833,7 @@ long sys32_uname(struct old_utsname __us if (!name) return -EFAULT; down_read(&uts_sem); - err=copy_to_user(name, &system_utsname, sizeof (*name)); + err=copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); if (personality(current->personality) == PER_LINUX32) err |= copy_to_user(&name->machine, "i686", 5); diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/ia32/syscall32.c linux-2.6.17.11-g-v/arch/x86_64/ia32/syscall32.c --- linux-2.6.17.11/arch/x86_64/ia32/syscall32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/ia32/syscall32.c 2006-08-28 14:56:36.000000000 +0200 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include #include @@ -70,7 +71,7 @@ int syscall32_setup_pages(struct linux_b kmem_cache_free(vm_area_cachep, vma); return ret; } - mm->total_vm += npages; + vx_vmpages_add(mm, npages); up_write(&mm->mmap_sem); return 0; } diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/kernel/process.c linux-2.6.17.11-g-v/arch/x86_64/kernel/process.c --- linux-2.6.17.11/arch/x86_64/kernel/process.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/kernel/process.c 2006-08-28 14:44:49.000000000 +0200 @@ -830,9 +830,3 @@ int dump_task_regs(struct task_struct *t return 1; } -unsigned long arch_align_stack(unsigned long sp) -{ - if (randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/kernel/ptrace.c linux-2.6.17.11-g-v/arch/x86_64/kernel/ptrace.c --- linux-2.6.17.11/arch/x86_64/kernel/ptrace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/kernel/ptrace.c 2006-08-28 14:44:49.000000000 +0200 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/kernel/setup64.c linux-2.6.17.11-g-v/arch/x86_64/kernel/setup64.c --- linux-2.6.17.11/arch/x86_64/kernel/setup64.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/kernel/setup64.c 2006-08-28 14:44:49.000000000 +0200 @@ -38,7 +38,6 @@ struct desc_ptr idt_descr = { 256 * 16 - char boot_cpu_stack[IRQSTACKSIZE] __attribute__((section(".bss.page_aligned"))); unsigned long __supported_pte_mask __read_mostly = ~0UL; -static int do_not_nx __cpuinitdata = 0; /* noexec=on|off Control non executable mappings for 64bit processes. @@ -50,16 +49,14 @@ int __init nonx_setup(char *str) { if (!strncmp(str, "on", 2)) { __supported_pte_mask |= _PAGE_NX; - do_not_nx = 0; } else if (!strncmp(str, "off", 3)) { - do_not_nx = 1; __supported_pte_mask &= ~_PAGE_NX; } return 1; } __setup("noexec=", nonx_setup); /* parsed early actually */ -int force_personality32 = 0; +int force_personality32; /* noexec32=on|off Control non executable heap for 32bit processes. @@ -173,7 +170,7 @@ void __cpuinit check_efer(void) unsigned long efer; rdmsrl(MSR_EFER, efer); - if (!(efer & EFER_NX) || do_not_nx) { + if (!(efer & EFER_NX)) { __supported_pte_mask &= ~_PAGE_NX; } } diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/kernel/sys_x86_64.c linux-2.6.17.11-g-v/arch/x86_64/kernel/sys_x86_64.c --- linux-2.6.17.11/arch/x86_64/kernel/sys_x86_64.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/kernel/sys_x86_64.c 2006-08-28 14:56:36.000000000 +0200 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -65,8 +66,8 @@ out: return error; } -static void find_start_end(unsigned long flags, unsigned long *begin, - unsigned long *end) +static void find_start_end(struct mm_struct *mm, unsigned long flags, + unsigned long *begin, unsigned long *end) { if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) { /* This is usually used needed to map code in small @@ -79,7 +80,7 @@ static void find_start_end(unsigned long *begin = 0x40000000; *end = 0x80000000; } else { - *begin = TASK_UNMAPPED_BASE; + *begin = mm->mmap_base; *end = TASK_SIZE; } } @@ -93,11 +94,15 @@ arch_get_unmapped_area(struct file *filp unsigned long start_addr; unsigned long begin, end; - find_start_end(flags, &begin, &end); + find_start_end(mm, flags, &begin, &end); if (len > end) return -ENOMEM; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); @@ -148,7 +153,7 @@ asmlinkage long sys_uname(struct new_uts { int err; down_read(&uts_sem); - err = copy_to_user(name, &system_utsname, sizeof (*name)); + err = copy_to_user(name, vx_new_utsname(), sizeof (*name)); up_read(&uts_sem); if (personality(current->personality) == PER_LINUX32) err |= copy_to_user(&name->machine, "i686", 5); diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/kernel/traps.c linux-2.6.17.11-g-v/arch/x86_64/kernel/traps.c --- linux-2.6.17.11/arch/x86_64/kernel/traps.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/kernel/traps.c 2006-08-28 14:56:36.000000000 +0200 @@ -324,8 +324,9 @@ void show_registers(struct pt_regs *regs printk("CPU %d ", cpu); __show_regs(regs); - printk("Process %s (pid: %d, threadinfo %p, task %p)\n", - cur->comm, cur->pid, task_thread_info(cur), cur); + printk("Process %s (pid: %d[#%u], threadinfo %p, task %p)\n", + cur->comm, cur->pid, cur->xid, + task_thread_info(cur), cur); /* * When in-kernel, we also print out the stack and code at the diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/mm/fault.c linux-2.6.17.11-g-v/arch/x86_64/mm/fault.c --- linux-2.6.17.11/arch/x86_64/mm/fault.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/mm/fault.c 2006-08-28 14:44:49.000000000 +0200 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -294,6 +295,33 @@ static int vmalloc_fault(unsigned long a return 0; } +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(void *pc, void *sp) +{ + long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (get_user(c, (unsigned char __user *)pc+i)) + printk("?? "); + else + printk("%02x ", c); + } + printk("\n"); + + printk(KERN_ERR "PAX: bytes at SP-8: "); + for (i = -1; i < 10; i++) { + unsigned long c; + if (get_user(c, (unsigned long __user *)sp+i)) + printk("???????????????? "); + else + printk("%016lx ", c); + } + printk("\n"); +} +#endif + int page_fault_trace = 0; int exception_trace = 1; @@ -423,6 +451,8 @@ asmlinkage void __kprobes do_page_fault( good_area: info.si_code = SEGV_ACCERR; write = 0; + if ((error_code & PF_INSTR) && !(vma->vm_flags & VM_EXEC)) + goto bad_area; switch (error_code & (PF_PROT|PF_WRITE)) { default: /* 3: write, present */ /* fall through */ @@ -489,7 +519,14 @@ bad_area_nosemaphore: tsk->comm, tsk->pid, address, regs->rip, regs->rsp, error_code); } - + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm && (mm->pax_flags & MF_PAX_PAGEEXEC) && (error_code & 16)) { + pax_report_fault(regs, (void*)regs->rip, (void*)regs->rsp); + do_exit(SIGKILL); + } +#endif + tsk->thread.cr2 = address; /* Kernel addresses are always protection faults */ tsk->thread.error_code = error_code | (address >= TASK_SIZE); diff -NurpP --minimal linux-2.6.17.11/arch/x86_64/mm/mmap.c linux-2.6.17.11-g-v/arch/x86_64/mm/mmap.c --- linux-2.6.17.11/arch/x86_64/mm/mmap.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/x86_64/mm/mmap.c 2006-08-28 14:44:49.000000000 +0200 @@ -24,6 +24,12 @@ void arch_pick_mmap_layout(struct mm_str unsigned rnd = get_random_int() & 0xfffffff; mm->mmap_base += ((unsigned long)rnd) << PAGE_SHIFT; } + +#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; } diff -NurpP --minimal linux-2.6.17.11/arch/xtensa/kernel/syscalls.c linux-2.6.17.11-g-v/arch/xtensa/kernel/syscalls.c --- linux-2.6.17.11/arch/xtensa/kernel/syscalls.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/arch/xtensa/kernel/syscalls.c 2006-08-28 14:56:36.000000000 +0200 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include @@ -129,7 +130,7 @@ out: int sys_uname(struct old_utsname * name) { - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + if (name && !copy_to_user(name, vx_new_utsname(), sizeof (*name))) return 0; return -EFAULT; } diff -NurpP --minimal linux-2.6.17.11/drivers/block/Kconfig linux-2.6.17.11-g-v/drivers/block/Kconfig --- linux-2.6.17.11/drivers/block/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/block/Kconfig 2006-08-28 14:56:36.000000000 +0200 @@ -315,6 +315,13 @@ config BLK_DEV_CRYPTOLOOP instead, which can be configured to be on-disk compatible with the cryptoloop device. +config BLK_DEV_VROOT + tristate "Virtual Root device support" + depends on QUOTACTL + ---help--- + Saying Y here will allow you to use quota/fs ioctls on a shared + partition within a virtual server without compromising security. + config BLK_DEV_NBD tristate "Network block device support" depends on NET diff -NurpP --minimal linux-2.6.17.11/drivers/block/Makefile linux-2.6.17.11-g-v/drivers/block/Makefile --- linux-2.6.17.11/drivers/block/Makefile 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/block/Makefile 2006-08-28 14:56:36.000000000 +0200 @@ -29,4 +29,5 @@ obj-$(CONFIG_BLK_DEV_CRYPTOLOOP) += cryp obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o obj-$(CONFIG_BLK_DEV_UB) += ub.o +obj-$(CONFIG_BLK_DEV_VROOT) += vroot.o diff -NurpP --minimal linux-2.6.17.11/drivers/block/vroot.c linux-2.6.17.11-g-v/drivers/block/vroot.c --- linux-2.6.17.11/drivers/block/vroot.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.17.11-g-v/drivers/block/vroot.c 2006-08-28 14:56:36.000000000 +0200 @@ -0,0 +1,288 @@ +/* + * linux/drivers/block/vroot.c + * + * written by Herbert Pötzl, 9/11/2002 + * ported to 2.6.10 by Herbert Pötzl, 30/12/2004 + * + * based on the loop.c code by Theodore Ts'o. + * + * Copyright (C) 2002-2005 by Herbert Pötzl. + * Redistribution of this file is permitted under the + * GNU General Public License. + * + */ + +#include +#include +#include +#include +#include +#include + +#include +#include + + +static int max_vroot = 8; + +static struct vroot_device *vroot_dev; +static struct gendisk **disks; + + +static int vroot_set_dev( + struct vroot_device *vr, + struct file *vr_file, + struct block_device *bdev, + unsigned int arg) +{ + struct block_device *real_bdev; + struct file *file; + struct inode *inode; + int error; + + error = -EBUSY; + if (vr->vr_state != Vr_unbound) + goto out; + + error = -EBADF; + file = fget(arg); + if (!file) + goto out; + + error = -EINVAL; + inode = file->f_dentry->d_inode; + + + if (S_ISBLK(inode->i_mode)) { + real_bdev = inode->i_bdev; + vr->vr_device = real_bdev; + __iget(real_bdev->bd_inode); + } else + goto out_fput; + + vxdprintk(VXD_CBIT(misc, 0), + "vroot[%d]_set_dev: dev=" VXF_DEV, + vr->vr_number, VXD_DEV(real_bdev)); + + vr->vr_state = Vr_bound; + error = 0; + + out_fput: + fput(file); + out: + return error; +} + +static int vroot_clr_dev( + struct vroot_device *vr, + struct file *vr_file, + struct block_device *bdev) +{ + struct block_device *real_bdev; + + if (vr->vr_state != Vr_bound) + return -ENXIO; + if (vr->vr_refcnt > 1) /* we needed one fd for the ioctl */ + return -EBUSY; + + real_bdev = vr->vr_device; + + vxdprintk(VXD_CBIT(misc, 0), + "vroot[%d]_clr_dev: dev=" VXF_DEV, + vr->vr_number, VXD_DEV(real_bdev)); + + bdput(real_bdev); + vr->vr_state = Vr_unbound; + vr->vr_device = NULL; + return 0; +} + + +static int vr_ioctl(struct inode * inode, struct file * file, + unsigned int cmd, unsigned long arg) +{ + struct vroot_device *vr = inode->i_bdev->bd_disk->private_data; + int err; + + down(&vr->vr_ctl_mutex); + switch (cmd) { + case VROOT_SET_DEV: + err = vroot_set_dev(vr, file, inode->i_bdev, arg); + break; + case VROOT_CLR_DEV: + err = vroot_clr_dev(vr, file, inode->i_bdev); + break; + default: + err = -EINVAL; + break; + } + up(&vr->vr_ctl_mutex); + return err; +} + +static int vr_open(struct inode *inode, struct file *file) +{ + struct vroot_device *vr = inode->i_bdev->bd_disk->private_data; + + down(&vr->vr_ctl_mutex); + vr->vr_refcnt++; + up(&vr->vr_ctl_mutex); + return 0; +} + +static int vr_release(struct inode *inode, struct file *file) +{ + struct vroot_device *vr = inode->i_bdev->bd_disk->private_data; + + down(&vr->vr_ctl_mutex); + --vr->vr_refcnt; + up(&vr->vr_ctl_mutex); + return 0; +} + +static struct block_device_operations vr_fops = { + .owner = THIS_MODULE, + .open = vr_open, + .release = vr_release, + .ioctl = vr_ioctl, +}; + +struct block_device *__vroot_get_real_bdev(struct block_device *bdev) +{ + struct inode *inode = bdev->bd_inode; + struct vroot_device *vr; + struct block_device *real_bdev; + int minor = iminor(inode); + + vr = &vroot_dev[minor]; + real_bdev = vr->vr_device; + + vxdprintk(VXD_CBIT(misc, 0), + "vroot[%d]_get_real_bdev: dev=" VXF_DEV, + vr->vr_number, VXD_DEV(real_bdev)); + + if (vr->vr_state != Vr_bound) + return ERR_PTR(-ENXIO); + + __iget(real_bdev->bd_inode); + return real_bdev; +} + +/* + * And now the modules code and kernel interface. + */ + +module_param(max_vroot, int, 0); + +MODULE_PARM_DESC(max_vroot, "Maximum number of vroot devices (1-256)"); +MODULE_LICENSE("GPL"); +MODULE_ALIAS_BLOCKDEV_MAJOR(VROOT_MAJOR); + +MODULE_AUTHOR ("Herbert Pötzl"); +MODULE_DESCRIPTION ("Virtual Root Device Mapper"); + + +int __init vroot_init(void) +{ + int err, i; + + if (max_vroot < 1 || max_vroot > 256) { + max_vroot = MAX_VROOT_DEFAULT; + printk(KERN_WARNING "vroot: invalid max_vroot " + "(must be between 1 and 256), " + "using default (%d)\n", max_vroot); + } + + if (register_blkdev(VROOT_MAJOR, "vroot")) + return -EIO; + + err = -ENOMEM; + vroot_dev = kmalloc(max_vroot * sizeof(struct vroot_device), GFP_KERNEL); + if (!vroot_dev) + goto out_mem1; + memset(vroot_dev, 0, max_vroot * sizeof(struct vroot_device)); + + disks = kmalloc(max_vroot * sizeof(struct gendisk *), GFP_KERNEL); + if (!disks) + goto out_mem2; + + for (i = 0; i < max_vroot; i++) { + disks[i] = alloc_disk(1); + if (!disks[i]) + goto out_mem3; + } + + devfs_mk_dir("vroot"); + + for (i = 0; i < max_vroot; i++) { + struct vroot_device *vr = &vroot_dev[i]; + struct gendisk *disk = disks[i]; + + memset(vr, 0, sizeof(*vr)); + init_MUTEX(&vr->vr_ctl_mutex); + vr->vr_number = i; + disk->major = VROOT_MAJOR; + disk->first_minor = i; + disk->fops = &vr_fops; + sprintf(disk->disk_name, "vroot%d", i); + sprintf(disk->devfs_name, "vroot/%d", i); + disk->private_data = vr; + } + + err = register_vroot_grb(&__vroot_get_real_bdev); + if (err) + goto out_reg; + + for (i = 0; i < max_vroot; i++) + add_disk(disks[i]); + printk(KERN_INFO "vroot: loaded (max %d devices)\n", max_vroot); + return 0; + +out_reg: + devfs_remove("vroot"); +out_mem3: + while (i--) + put_disk(disks[i]); + kfree(disks); +out_mem2: + kfree(vroot_dev); +out_mem1: + unregister_blkdev(VROOT_MAJOR, "vroot"); + printk(KERN_ERR "vroot: ran out of memory\n"); + return err; +} + +void vroot_exit(void) +{ + int i; + + if (unregister_vroot_grb(&__vroot_get_real_bdev)) + printk(KERN_WARNING "vroot: cannot unregister grb\n"); + + for (i = 0; i < max_vroot; i++) { + del_gendisk(disks[i]); + put_disk(disks[i]); + } + devfs_remove("vroot"); + if (unregister_blkdev(VROOT_MAJOR, "vroot")) + printk(KERN_WARNING "vroot: cannot unregister blkdev\n"); + + kfree(disks); + kfree(vroot_dev); +} + +module_init(vroot_init); +module_exit(vroot_exit); + +#ifndef MODULE + +static int __init max_vroot_setup(char *str) +{ + max_vroot = simple_strtol(str, NULL, 0); + return 1; +} + +__setup("max_vroot=", max_vroot_setup); + +#endif + diff -NurpP --minimal linux-2.6.17.11/drivers/char/agp/frontend.c linux-2.6.17.11-g-v/drivers/char/agp/frontend.c --- linux-2.6.17.11/drivers/char/agp/frontend.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/char/agp/frontend.c 2006-08-28 14:44:49.000000000 +0200 @@ -841,7 +841,7 @@ static int agpioc_reserve_wrap(struct ag if (copy_from_user(&reserve, arg, sizeof(struct agp_region))) return -EFAULT; - if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment)) + if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment_priv)) return -EFAULT; client = agp_find_client_by_pid(reserve.pid); diff -NurpP --minimal linux-2.6.17.11/drivers/char/keyboard.c linux-2.6.17.11-g-v/drivers/char/keyboard.c --- linux-2.6.17.11/drivers/char/keyboard.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/char/keyboard.c 2006-08-28 14:44:49.000000000 +0200 @@ -618,6 +618,16 @@ static void k_spec(struct vc_data *vc, u kbd->kbdmode == VC_MEDIUMRAW) && value != KVAL(K_SAK)) return; /* SAK is allowed even in raw mode */ + +#if defined(CONFIG_GRKERNSEC_PROC) || defined(CONFIG_GRKERNSEC_PROC_MEMMAP) + { + void *func = fn_handler[value]; + if (func == fn_show_state || func == fn_show_ptregs || + func == fn_show_mem) + return; + } +#endif + fn_handler[value](vc, regs); } diff -NurpP --minimal linux-2.6.17.11/drivers/char/mem.c linux-2.6.17.11-g-v/drivers/char/mem.c --- linux-2.6.17.11/drivers/char/mem.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/char/mem.c 2006-08-28 14:44:49.000000000 +0200 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include @@ -36,6 +37,10 @@ # include #endif +#ifdef CONFIG_GRKERNSEC +extern struct file_operations grsec_fops; +#endif + /* * Architectures vary in how they handle caching for addresses * outside of main memory. @@ -175,6 +180,11 @@ static ssize_t write_mem(struct file * f if (!valid_phys_addr_range(p, count)) return -EFAULT; +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_mem_write(); + return -EPERM; +#endif + written = 0; #ifdef __ARCH_HAS_NO_PAGE_ZERO_MAPPED @@ -251,6 +261,11 @@ static int mmap_mem(struct file * file, size, vma->vm_page_prot); +#ifdef CONFIG_GRKERNSEC_KMEM + if (gr_handle_mem_mmap(vma->vm_pgoff << PAGE_SHIFT, vma)) + return -EPERM; +#endif + /* Remap-pfn-range will mark the range VM_IO and VM_RESERVED */ if (remap_pfn_range(vma, vma->vm_start, @@ -478,6 +493,11 @@ static ssize_t write_kmem(struct file * ssize_t written; char * kbuf; /* k-addr because vwrite() takes vmlist_lock rwlock */ +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_kmem_write(); + return -EPERM; +#endif + if (p < (unsigned long) high_memory) { wrote = count; @@ -618,7 +638,23 @@ static inline size_t read_zero_pagealign count = size; zap_page_range(vma, addr, count, NULL); - zeromap_page_range(vma, addr, count, PAGE_COPY); + zeromap_page_range(vma, addr, count, vma->vm_page_prot); + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma->vm_flags & VM_MIRROR) { + unsigned long addr_m; + struct vm_area_struct * vma_m; + + addr_m = vma->vm_start + vma->vm_mirror; + vma_m = find_vma(mm, addr_m); + if (vma_m && vma_m->vm_start == addr_m && (vma_m->vm_flags & VM_MIRROR)) { + addr_m = addr + vma->vm_mirror; + zap_page_range(vma_m, addr_m, count, NULL); + } else + printk(KERN_ERR "PAX: VMMIRROR: read_zero bug, %08lx, %08lx\n", + addr, vma->vm_start); + } +#endif size -= count; buf += count; @@ -767,6 +803,16 @@ static loff_t memory_lseek(struct file * static int open_port(struct inode * inode, struct file * filp) { +#ifdef CONFIG_GRKERNSEC_KMEM + gr_handle_open_port(); + return -EPERM; +#endif + + return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; +} + +static int open_mem(struct inode * inode, struct file * filp) +{ return capable(CAP_SYS_RAWIO) ? 0 : -EPERM; } @@ -774,7 +820,6 @@ static int open_port(struct inode * inod #define full_lseek null_lseek #define write_zero write_null #define read_full read_zero -#define open_mem open_port #define open_kmem open_mem #define open_oldmem open_mem @@ -897,6 +942,11 @@ static int memory_open(struct inode * in filp->f_op = &oldmem_fops; break; #endif +#ifdef CONFIG_GRKERNSEC + case 13: + filp->f_op = &grsec_fops; + break; +#endif default: return -ENXIO; } @@ -929,6 +979,9 @@ static const struct { #ifdef CONFIG_CRASH_DUMP {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops}, #endif +#ifdef CONFIG_GRKERNSEC + {13,"grsec", S_IRUSR | S_IWUGO, &grsec_fops}, +#endif }; static struct class *mem_class; diff -NurpP --minimal linux-2.6.17.11/drivers/char/random.c linux-2.6.17.11-g-v/drivers/char/random.c --- linux-2.6.17.11/drivers/char/random.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/char/random.c 2006-08-28 14:56:36.000000000 +0200 @@ -249,8 +249,13 @@ /* * Configuration information */ +#ifdef CONFIG_GRKERNSEC_RANDNET +#define INPUT_POOL_WORDS 512 +#define OUTPUT_POOL_WORDS 128 +#else #define INPUT_POOL_WORDS 128 #define OUTPUT_POOL_WORDS 32 +#endif #define SEC_XFER_SIZE 512 /* @@ -287,10 +292,17 @@ static struct poolinfo { int poolwords; int tap1, tap2, tap3, tap4, tap5; } poolinfo_table[] = { +#ifdef CONFIG_GRKERNSEC_RANDNET + /* x^512 + x^411 + x^308 + x^208 +x^104 + x + 1 -- 225 */ + { 512, 411, 308, 208, 104, 1 }, + /* x^128 + x^103 + x^76 + x^51 + x^25 + x + 1 -- 105 */ + { 128, 103, 76, 51, 25, 1 }, +#else /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ { 128, 103, 76, 51, 25, 1 }, /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ { 32, 26, 20, 14, 7, 1 }, +#endif #if 0 /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ { 2048, 1638, 1231, 819, 411, 1 }, @@ -1174,7 +1186,7 @@ static char sysctl_bootid[16]; static int proc_do_uuid(ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) { - ctl_table fake_table; + ctl_table fake_table = {0}; unsigned char buf[64], tmp_uuid[16], *uuid; uuid = table->data; @@ -1658,3 +1670,25 @@ randomize_range(unsigned long start, uns return 0; return PAGE_ALIGN(get_random_int() % range + start); } + +#if defined(CONFIG_PAX_ASLR) || defined(CONFIG_GRKERNSEC) +unsigned long pax_get_random_long(void) +{ + static time_t rekey_time; + static __u32 secret[12]; + time_t t; + + /* + * Pick a random secret every REKEY_INTERVAL seconds. + */ + t = get_seconds(); + if (!rekey_time || (t - rekey_time) > REKEY_INTERVAL) { + rekey_time = t; + get_random_bytes(secret, sizeof(secret)); + } + + secret[1] = half_md4_transform(secret+8, secret); + secret[0] = half_md4_transform(secret+8, secret); + return *(unsigned long *)secret; +} +#endif diff -NurpP --minimal linux-2.6.17.11/drivers/char/tty_io.c linux-2.6.17.11-g-v/drivers/char/tty_io.c --- linux-2.6.17.11/drivers/char/tty_io.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/char/tty_io.c 2006-08-28 14:56:36.000000000 +0200 @@ -103,6 +103,7 @@ #include #include #include +#include #include @@ -2388,13 +2389,16 @@ static int tiocsctty(struct tty_struct * static int tiocgpgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) { + pid_t pgrp; /* * (tty == real_tty) is a cheap way of * testing if the tty is NOT a master pty. */ if (tty == real_tty && current->signal->tty != real_tty) return -ENOTTY; - return put_user(real_tty->pgrp, p); + + pgrp = vx_map_pid(real_tty->pgrp); + return put_user(pgrp, p); } static int tiocspgrp(struct tty_struct *tty, struct tty_struct *real_tty, pid_t __user *p) @@ -2412,6 +2416,8 @@ static int tiocspgrp(struct tty_struct * return -ENOTTY; if (get_user(pgrp, p)) return -EFAULT; + + pgrp = vx_rmap_pid(pgrp); if (pgrp < 0) return -EINVAL; if (session_of_pgrp(pgrp) != current->signal->session) diff -NurpP --minimal linux-2.6.17.11/drivers/char/vt_ioctl.c linux-2.6.17.11-g-v/drivers/char/vt_ioctl.c --- linux-2.6.17.11/drivers/char/vt_ioctl.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/char/vt_ioctl.c 2006-08-28 14:44:49.000000000 +0200 @@ -96,6 +96,12 @@ do_kdsk_ioctl(int cmd, struct kbentry __ case KDSKBENT: if (!perm) return -EPERM; + +#ifdef CONFIG_GRKERNSEC + if (!capable(CAP_SYS_TTY_CONFIG)) + return -EPERM; +#endif + if (!i && v == K_NOSUCHMAP) { /* disallocate map */ key_map = key_maps[s]; @@ -236,6 +242,13 @@ do_kdgkb_ioctl(int cmd, struct kbsentry goto reterr; } +#ifdef CONFIG_GRKERNSEC + if (!capable(CAP_SYS_TTY_CONFIG)) { + ret = -EPERM; + goto reterr; + } +#endif + q = func_table[i]; first_free = funcbufptr + (funcbufsize - funcbufleft); for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) diff -NurpP --minimal linux-2.6.17.11/drivers/ieee1394/hosts.c linux-2.6.17.11-g-v/drivers/ieee1394/hosts.c --- linux-2.6.17.11/drivers/ieee1394/hosts.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/ieee1394/hosts.c 2006-08-28 14:44:49.000000000 +0200 @@ -75,6 +75,7 @@ static int dummy_isoctl(struct hpsb_iso } static struct hpsb_host_driver dummy_driver = { + .name = "dummy", .transmit_packet = dummy_transmit_packet, .devctl = dummy_devctl, .isoctl = dummy_isoctl diff -NurpP --minimal linux-2.6.17.11/drivers/ieee1394/ohci1394.c linux-2.6.17.11-g-v/drivers/ieee1394/ohci1394.c --- linux-2.6.17.11/drivers/ieee1394/ohci1394.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/ieee1394/ohci1394.c 2006-08-28 14:44:49.000000000 +0200 @@ -162,9 +162,9 @@ printk(level "%s: " fmt "\n" , OHCI1394_ printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) /* Module Parameters */ -static int phys_dma = 1; +static int phys_dma = 0; module_param(phys_dma, int, 0644); -MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 1)."); +MODULE_PARM_DESC(phys_dma, "Enable physical dma (default = 0)."); static void dma_trm_tasklet(unsigned long data); static void dma_trm_reset(struct dma_trm_ctx *d); diff -NurpP --minimal linux-2.6.17.11/drivers/infiniband/core/uverbs_mem.c linux-2.6.17.11-g-v/drivers/infiniband/core/uverbs_mem.c --- linux-2.6.17.11/drivers/infiniband/core/uverbs_mem.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/infiniband/core/uverbs_mem.c 2006-08-28 14:56:36.000000000 +0200 @@ -36,6 +36,7 @@ #include #include +#include #include "uverbs.h" @@ -161,7 +162,7 @@ out: if (ret < 0) __ib_umem_release(dev, mem, 0); else - current->mm->locked_vm = locked; + vx_vmlocked_sub(current->mm, current->mm->locked_vm - locked); up_write(¤t->mm->mmap_sem); free_page((unsigned long) page_list); @@ -174,8 +175,8 @@ void ib_umem_release(struct ib_device *d __ib_umem_release(dev, umem, 1); down_write(¤t->mm->mmap_sem); - current->mm->locked_vm -= - PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT; + vx_vmlocked_sub(current->mm, + PAGE_ALIGN(umem->length + umem->offset) >> PAGE_SHIFT); up_write(¤t->mm->mmap_sem); } @@ -184,7 +185,7 @@ static void ib_umem_account(void *work_p struct ib_umem_account_work *work = work_ptr; down_write(&work->mm->mmap_sem); - work->mm->locked_vm -= work->diff; + vx_vmlocked_sub(work->mm, work->diff); up_write(&work->mm->mmap_sem); mmput(work->mm); kfree(work); diff -NurpP --minimal linux-2.6.17.11/drivers/infiniband/hw/ipath/ipath_user_pages.c linux-2.6.17.11-g-v/drivers/infiniband/hw/ipath/ipath_user_pages.c --- linux-2.6.17.11/drivers/infiniband/hw/ipath/ipath_user_pages.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/infiniband/hw/ipath/ipath_user_pages.c 2006-08-28 14:56:36.000000000 +0200 @@ -32,6 +32,7 @@ #include #include +#include #include "ipath_kernel.h" @@ -71,7 +72,8 @@ static int __get_user_pages(unsigned lon lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; - if (num_pages > lock_limit) { + if (num_pages > lock_limit || + !vx_vmlocked_avail(current->mm, num_pages)) { ret = -ENOMEM; goto bail; } @@ -88,7 +90,7 @@ static int __get_user_pages(unsigned lon goto bail_release; } - current->mm->locked_vm += num_pages; + vx_vmlocked_add(current->mm, num_pages); ret = 0; goto bail; @@ -157,7 +159,7 @@ void ipath_release_user_pages(struct pag __ipath_release_user_pages(p, num_pages, 1); - current->mm->locked_vm -= num_pages; + vx_vmlocked_sub(current->mm, num_pages); up_write(¤t->mm->mmap_sem); } @@ -173,7 +175,7 @@ static void user_pages_account(void *ptr struct ipath_user_pages_work *work = ptr; down_write(&work->mm->mmap_sem); - work->mm->locked_vm -= work->num_pages; + vx_vmlocked_sub(work->mm, work->num_pages); up_write(&work->mm->mmap_sem); mmput(work->mm); kfree(work); diff -NurpP --minimal linux-2.6.17.11/drivers/mtd/devices/doc2001.c linux-2.6.17.11-g-v/drivers/mtd/devices/doc2001.c --- linux-2.6.17.11/drivers/mtd/devices/doc2001.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/mtd/devices/doc2001.c 2006-08-28 14:44:49.000000000 +0200 @@ -423,6 +423,8 @@ static int doc_read_ecc (struct mtd_info /* Don't allow read past end of device */ if (from >= this->totlen) return -EINVAL; + if (!len) + return -EINVAL; /* Don't allow a single read to cross a 512-byte block boundary */ if (from + len > ((from | 0x1ff) + 1)) diff -NurpP --minimal linux-2.6.17.11/drivers/net/pcnet32.c linux-2.6.17.11-g-v/drivers/net/pcnet32.c --- linux-2.6.17.11/drivers/net/pcnet32.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/net/pcnet32.c 2006-08-28 14:44:49.000000000 +0200 @@ -81,7 +81,7 @@ static int cards_found; /* * VLB I/O addresses */ -static unsigned int pcnet32_portlist[] __initdata = +static unsigned int pcnet32_portlist[] __devinitdata = { 0x300, 0x320, 0x340, 0x360, 0 }; static int pcnet32_debug = 0; diff -NurpP --minimal linux-2.6.17.11/drivers/pci/proc.c linux-2.6.17.11-g-v/drivers/pci/proc.c --- linux-2.6.17.11/drivers/pci/proc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/pci/proc.c 2006-08-28 14:44:49.000000000 +0200 @@ -473,7 +473,15 @@ static int __init pci_proc_init(void) { struct proc_dir_entry *entry; struct pci_dev *dev = NULL; +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + proc_bus_pci_dir = proc_mkdir_mode("pci", S_IRUSR | S_IXUSR, proc_bus); +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + proc_bus_pci_dir = proc_mkdir_mode("pci", S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP, proc_bus); +#endif +#else proc_bus_pci_dir = proc_mkdir("pci", proc_bus); +#endif entry = create_proc_entry("devices", 0, proc_bus_pci_dir); if (entry) entry->proc_fops = &proc_bus_pci_dev_operations; diff -NurpP --minimal linux-2.6.17.11/drivers/pnp/pnpbios/bioscalls.c linux-2.6.17.11-g-v/drivers/pnp/pnpbios/bioscalls.c --- linux-2.6.17.11/drivers/pnp/pnpbios/bioscalls.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/pnp/pnpbios/bioscalls.c 2006-08-28 14:44:49.000000000 +0200 @@ -65,7 +65,7 @@ set_base(gdt[(selname) >> 3], (u32)(addr set_limit(gdt[(selname) >> 3], size); \ } while(0) -static struct desc_struct bad_bios_desc = { 0, 0x00409200 }; +static struct desc_struct bad_bios_desc = { 0, 0x00409300 }; /* * At some point we want to use this stack frame pointer to unwind @@ -93,6 +93,10 @@ static inline u16 call_pnp_bios(u16 func struct desc_struct save_desc_40; int cpu; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + /* * PnP BIOSes are generally not terribly re-entrant. * Also, don't rely on them to save everything correctly. @@ -107,6 +111,10 @@ static inline u16 call_pnp_bios(u16 func /* On some boxes IRQ's during PnP BIOS calls are deadly. */ spin_lock_irqsave(&pnp_bios_lock, flags); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + /* The lock prevents us bouncing CPU here */ if (ts1_size) Q2_SET_SEL(smp_processor_id(), PNP_TS1, ts1_base, ts1_size); @@ -142,9 +150,14 @@ static inline u16 call_pnp_bios(u16 func "i" (0) : "memory" ); - spin_unlock_irqrestore(&pnp_bios_lock, flags); get_cpu_gdt_table(cpu)[0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + spin_unlock_irqrestore(&pnp_bios_lock, flags); put_cpu(); /* If we get here and this is set then the PnP BIOS faulted on us. */ diff -NurpP --minimal linux-2.6.17.11/drivers/video/i810/i810_main.c linux-2.6.17.11-g-v/drivers/video/i810/i810_main.c --- linux-2.6.17.11/drivers/video/i810/i810_main.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/video/i810/i810_main.c 2006-08-28 14:44:49.000000000 +0200 @@ -1508,7 +1508,7 @@ static int i810fb_cursor(struct fb_info int size = ((cursor->image.width + 7) >> 3) * cursor->image.height; int i; - u8 *data = kmalloc(64 * 8, GFP_ATOMIC); + u8 *data = kmalloc(64 * 8, GFP_KERNEL); if (data == NULL) return -ENOMEM; diff -NurpP --minimal linux-2.6.17.11/drivers/video/vesafb.c linux-2.6.17.11-g-v/drivers/video/vesafb.c --- linux-2.6.17.11/drivers/video/vesafb.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/drivers/video/vesafb.c 2006-08-28 14:44:49.000000000 +0200 @@ -259,7 +259,7 @@ static int __init vesafb_probe(struct pl size_remap = size_total; vesafb_fix.smem_len = size_remap; -#ifndef __i386__ +#if !defined(__i386__) || defined(CONFIG_PAX_KERNEXEC) screen_info.vesapm_seg = 0; #endif diff -NurpP --minimal linux-2.6.17.11/fs/Kconfig linux-2.6.17.11-g-v/fs/Kconfig --- linux-2.6.17.11/fs/Kconfig 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/Kconfig 2006-08-28 14:44:49.000000000 +0200 @@ -794,7 +794,7 @@ config PROC_FS config PROC_KCORE bool "/proc/kcore support" if !ARM - depends on PROC_FS && MMU + depends on PROC_FS && MMU && !GRKERNSEC_PROC_ADD config PROC_VMCORE bool "/proc/vmcore support (EXPERIMENTAL)" diff -NurpP --minimal linux-2.6.17.11/fs/attr.c linux-2.6.17.11-g-v/fs/attr.c --- linux-2.6.17.11/fs/attr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/attr.c 2006-08-28 14:56:36.000000000 +0200 @@ -15,6 +15,9 @@ #include #include #include +#include +#include +#include /* Taken over from the old code... */ @@ -56,6 +59,28 @@ int inode_change_ok(struct inode *inode, if (current->fsuid != inode->i_uid && !capable(CAP_FOWNER)) goto error; } + + /* Check for evil vserver activity */ + if (vx_check(0, VX_ADMIN)) + goto fine; + + if (IS_BARRIER(inode)) { + vxwprintk(1, "xid=%d messing with the barrier.", + vx_current_xid()); + goto error; + } + switch (inode->i_sb->s_magic) { + case PROC_SUPER_MAGIC: + vxwprintk(1, "xid=%d messing with the procfs.", + vx_current_xid()); + goto error; + case DEVPTS_SUPER_MAGIC: + if (vx_check(inode->i_xid, VX_IDENT)) + goto fine; + vxwprintk(1, "xid=%d messing with the devpts.", + vx_current_xid()); + goto error; + } fine: retval = 0; error: @@ -79,6 +104,8 @@ int inode_setattr(struct inode * inode, inode->i_uid = attr->ia_uid; if (ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; + if ((ia_valid & ATTR_XID) && IS_TAGXID(inode)) + inode->i_xid = attr->ia_xid; if (ia_valid & ATTR_ATIME) inode->i_atime = timespec_trunc(attr->ia_atime, inode->i_sb->s_time_gran); @@ -153,7 +180,8 @@ int notify_change(struct dentry * dentry error = security_inode_setattr(dentry, attr); if (!error) { if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || - (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) + (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) || + (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid)) error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; if (!error) error = inode_setattr(inode, attr); diff -NurpP --minimal linux-2.6.17.11/fs/binfmt_aout.c linux-2.6.17.11-g-v/fs/binfmt_aout.c --- linux-2.6.17.11/fs/binfmt_aout.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/binfmt_aout.c 2006-08-28 14:56:36.000000000 +0200 @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -123,10 +125,12 @@ static int aout_core_dump(long signr, st /* If the size of the dump file exceeds the rlimit, then see what would happen if we wrote the stack, but not the data area. */ #ifdef __sparc__ + gr_learn_resource(current, RLIMIT_CORE, dump.u_dsize+dump.u_ssize, 1); if ((dump.u_dsize+dump.u_ssize) > current->signal->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; #else + gr_learn_resource(current, RLIMIT_CORE, (dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE, 1); if ((dump.u_dsize+dump.u_ssize+1) * PAGE_SIZE > current->signal->rlim[RLIMIT_CORE].rlim_cur) dump.u_dsize = 0; @@ -134,10 +138,12 @@ static int aout_core_dump(long signr, st /* Make sure we have enough room to write the stack and data areas. */ #ifdef __sparc__ + gr_learn_resource(current, RLIMIT_CORE, dump.u_ssize, 1); if ((dump.u_ssize) > current->signal->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; #else + gr_learn_resource(current, RLIMIT_CORE, (dump.u_ssize+1) * PAGE_SIZE, 1); if ((dump.u_ssize+1) * PAGE_SIZE > current->signal->rlim[RLIMIT_CORE].rlim_cur) dump.u_ssize = 0; @@ -287,6 +293,8 @@ static int load_aout_binary(struct linux rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; if (rlim >= RLIM_INFINITY) rlim = ~0; + + gr_learn_resource(current, RLIMIT_DATA, ex.a_data + ex.a_bss, 1); if (ex.a_data + ex.a_bss > rlim) return -ENOMEM; @@ -319,6 +327,28 @@ static int load_aout_binary(struct linux current->mm->mmap = NULL; compute_creds(bprm); current->flags &= ~PF_FORKNOEXEC; + +#if defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) + current->mm->pax_flags = 0UL; +#endif + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(N_FLAGS(ex) & F_PAX_PAGEEXEC)) { + current->mm->pax_flags |= MF_PAX_PAGEEXEC; + +#ifdef CONFIG_PAX_EMUTRAMP + if (N_FLAGS(ex) & F_PAX_EMUTRAMP) + current->mm->pax_flags |= MF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_PAX_MPROTECT + if (!(N_FLAGS(ex) & F_PAX_MPROTECT)) + current->mm->pax_flags |= MF_PAX_MPROTECT; +#endif + + } +#endif + #ifdef __sparc__ if (N_MAGIC(ex) == NMAGIC) { loff_t pos = fd_offset; @@ -414,7 +444,7 @@ static int load_aout_binary(struct linux down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); up_write(¤t->mm->mmap_sem); diff -NurpP --minimal linux-2.6.17.11/fs/binfmt_elf.c linux-2.6.17.11-g-v/fs/binfmt_elf.c --- linux-2.6.17.11/fs/binfmt_elf.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/binfmt_elf.c 2006-08-28 14:56:36.000000000 +0200 @@ -38,11 +38,18 @@ #include #include #include +#include +#include +#include #include #include #include +#ifdef CONFIG_PAX_SEGMEXEC +#include +#endif + #include static int load_elf_binary(struct linux_binprm * bprm, struct pt_regs * regs); @@ -90,6 +97,8 @@ static struct linux_binfmt elf_format = static int set_brk(unsigned long start, unsigned long end) { + unsigned long e = end; + start = ELF_PAGEALIGN(start); end = ELF_PAGEALIGN(end); if (end > start) { @@ -100,7 +109,7 @@ static int set_brk(unsigned long start, if (BAD_ADDR(addr)) return addr; } - current->mm->start_brk = current->mm->brk = end; + current->mm->start_brk = current->mm->brk = e; return 0; } @@ -316,10 +325,9 @@ static unsigned long load_elf_interp(str { struct elf_phdr *elf_phdata; struct elf_phdr *eppnt; - unsigned long load_addr = 0; - int load_addr_set = 0; + unsigned long load_addr = 0, min_addr, max_addr, task_size = TASK_SIZE; unsigned long last_bss = 0, elf_bss = 0; - unsigned long error = ~0UL; + unsigned long error = -EINVAL; int retval, i, size; /* First of all, some simple consistency checks */ @@ -358,59 +366,80 @@ static unsigned long load_elf_interp(str goto out_close; } +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) + task_size = SEGMEXEC_TASK_SIZE; +#endif + eppnt = elf_phdata; + min_addr = task_size; + max_addr = 0; + error = -ENOMEM; + for (i=0; ie_phnum; i++, eppnt++) { - if (eppnt->p_type == PT_LOAD) { - int elf_type = MAP_PRIVATE | MAP_DENYWRITE; - int elf_prot = 0; - unsigned long vaddr = 0; - unsigned long k, map_addr; + if (eppnt->p_type != PT_LOAD) + continue; - if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; - if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; - if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; - vaddr = eppnt->p_vaddr; - if (interp_elf_ex->e_type == ET_EXEC || load_addr_set) - elf_type |= MAP_FIXED; + /* + * Check to see if the section's size will overflow the + * allowed task size. Note that p_filesz must always be + * <= p_memsize so it is only necessary to check p_memsz. + */ + if (eppnt->p_filesz > eppnt->p_memsz || eppnt->p_vaddr >= eppnt->p_vaddr + eppnt->p_memsz) + goto out_close; - map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); - error = map_addr; - if (BAD_ADDR(map_addr)) - goto out_close; + if (min_addr > ELF_PAGESTART(eppnt->p_vaddr)) + min_addr = ELF_PAGESTART(eppnt->p_vaddr); + if (max_addr < ELF_PAGEALIGN(eppnt->p_vaddr + eppnt->p_memsz)) + max_addr = ELF_PAGEALIGN(eppnt->p_vaddr + eppnt->p_memsz); + } + if (min_addr >= max_addr) + goto out_close; - if (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = map_addr - ELF_PAGESTART(vaddr); - load_addr_set = 1; - } + eppnt = elf_phdata; + for (i=0; ie_phnum; i++, eppnt++) { + int elf_type = MAP_PRIVATE | MAP_DENYWRITE | MAP_FIXED; + int elf_prot = 0; + unsigned long vaddr; + unsigned long k, map_addr; - /* - * Check to see if the section's size will overflow the - * allowed task size. Note that p_filesz must always be - * <= p_memsize so it is only necessary to check p_memsz. - */ - k = load_addr + eppnt->p_vaddr; - if (k > TASK_SIZE || eppnt->p_filesz > eppnt->p_memsz || - eppnt->p_memsz > TASK_SIZE || TASK_SIZE - eppnt->p_memsz < k) { - error = -ENOMEM; - goto out_close; - } + if (eppnt->p_type != PT_LOAD) + continue; - /* - * Find the end of the file mapping for this phdr, and keep - * track of the largest address we see for this. - */ - k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; - if (k > elf_bss) - elf_bss = k; + if (eppnt->p_flags & PF_R) elf_prot = PROT_READ; + if (eppnt->p_flags & PF_W) elf_prot |= PROT_WRITE; + if (eppnt->p_flags & PF_X) elf_prot |= PROT_EXEC; + vaddr = eppnt->p_vaddr; - /* - * Do the same thing for the memory mapping - between - * elf_bss and last_bss is the bss section. - */ - k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; - if (k > last_bss) - last_bss = k; - } + if (!load_addr && interp_elf_ex->e_type == ET_DYN) { + load_addr = get_unmapped_area(interpreter, 0, max_addr - min_addr, 0, MAP_PRIVATE | MAP_EXECUTABLE); + + if (load_addr > task_size) + goto out_close; + + load_addr -= min_addr; + } + + map_addr = elf_map(interpreter, load_addr + vaddr, eppnt, elf_prot, elf_type); + error = map_addr; + if (BAD_ADDR(map_addr)) + goto out_close; + + /* + * Find the end of the file mapping for this phdr, and keep + * track of the largest address we see for this. + */ + k = load_addr + eppnt->p_vaddr + eppnt->p_filesz; + if (k > elf_bss) + elf_bss = k; + + /* + * Do the same thing for the memory mapping - between + * elf_bss and last_bss is the bss section. + */ + k = load_addr + eppnt->p_memsz + eppnt->p_vaddr; + if (k > last_bss) + last_bss = k; } /* @@ -447,7 +476,7 @@ out: static unsigned long load_aout_interp(struct exec * interp_ex, struct file * interpreter) { - unsigned long text_data, elf_entry = ~0UL; + unsigned long text_data, elf_entry = -EINVAL; char __user * addr; loff_t offset; @@ -491,6 +520,180 @@ out: return elf_entry; } +#if (defined(CONFIG_PAX_EI_PAX) || defined(CONFIG_PAX_PT_PAX_FLAGS)) && defined(CONFIG_PAX_SOFTMODE) +static unsigned long pax_parse_softmode(const struct elf_phdr * const elf_phdata) +{ + unsigned long pax_flags = 0UL; + +#ifdef CONFIG_PAX_PAGEEXEC + if (elf_phdata->p_flags & PF_PAGEEXEC) + pax_flags |= MF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_PAX_SEGMEXEC + if (elf_phdata->p_flags & PF_SEGMEXEC) + pax_flags |= MF_PAX_SEGMEXEC; +#endif + +#ifdef CONFIG_PAX_DEFAULT_PAGEEXEC + if (pax_flags & MF_PAX_PAGEEXEC) + pax_flags &= ~MF_PAX_SEGMEXEC; +#endif + +#ifdef CONFIG_PAX_DEFAULT_SEGMEXEC + if (pax_flags & MF_PAX_SEGMEXEC) + pax_flags &= ~MF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_PAX_EMUTRAMP + if (elf_phdata->p_flags & PF_EMUTRAMP) + pax_flags |= MF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_PAX_MPROTECT + if (elf_phdata->p_flags & PF_MPROTECT) + pax_flags |= MF_PAX_MPROTECT; +#endif + +#if defined(CONFIG_PAX_RANDMMAP) || defined(CONFIG_PAX_RANDUSTACK) + if (randomize_va_space && (elf_phdata->p_flags & PF_RANDMMAP)) + pax_flags |= MF_PAX_RANDMMAP; +#endif + + return pax_flags; +} +#endif + +#ifdef CONFIG_PAX_PT_PAX_FLAGS +static unsigned long pax_parse_hardmode(const struct elf_phdr * const elf_phdata) +{ + unsigned long pax_flags = 0UL; + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(elf_phdata->p_flags & PF_NOPAGEEXEC)) + pax_flags |= MF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_PAX_SEGMEXEC + if (!(elf_phdata->p_flags & PF_NOSEGMEXEC)) + pax_flags |= MF_PAX_SEGMEXEC; +#endif + +#ifdef CONFIG_PAX_DEFAULT_PAGEEXEC + if (pax_flags & MF_PAX_PAGEEXEC) + pax_flags &= ~MF_PAX_SEGMEXEC; +#endif + +#ifdef CONFIG_PAX_DEFAULT_SEGMEXEC + if (pax_flags & MF_PAX_SEGMEXEC) + pax_flags &= ~MF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_PAX_EMUTRAMP + if (!(elf_phdata->p_flags & PF_NOEMUTRAMP)) + pax_flags |= MF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_PAX_MPROTECT + if (!(elf_phdata->p_flags & PF_NOMPROTECT)) + pax_flags |= MF_PAX_MPROTECT; +#endif + +#if defined(CONFIG_PAX_RANDMMAP) || defined(CONFIG_PAX_RANDUSTACK) + if (randomize_va_space && !(elf_phdata->p_flags & PF_NORANDMMAP)) + pax_flags |= MF_PAX_RANDMMAP; +#endif + + return pax_flags; +} +#endif + +#ifdef CONFIG_PAX_EI_PAX +static unsigned long pax_parse_ei_pax(const struct elfhdr * const elf_ex) +{ + unsigned long pax_flags = 0UL; + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(elf_ex->e_ident[EI_PAX] & EF_PAX_PAGEEXEC)) + pax_flags |= MF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_PAX_SEGMEXEC + if (!(elf_ex->e_ident[EI_PAX] & EF_PAX_SEGMEXEC)) + pax_flags |= MF_PAX_SEGMEXEC; +#endif + +#ifdef CONFIG_PAX_DEFAULT_PAGEEXEC + if (pax_flags & MF_PAX_PAGEEXEC) + pax_flags &= ~MF_PAX_SEGMEXEC; +#endif + +#ifdef CONFIG_PAX_DEFAULT_SEGMEXEC + if (pax_flags & MF_PAX_SEGMEXEC) + pax_flags &= ~MF_PAX_PAGEEXEC; +#endif + +#ifdef CONFIG_PAX_EMUTRAMP + if ((pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) && (elf_ex->e_ident[EI_PAX] & EF_PAX_EMUTRAMP)) + pax_flags |= MF_PAX_EMUTRAMP; +#endif + +#ifdef CONFIG_PAX_MPROTECT + if ((pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) && !(elf_ex->e_ident[EI_PAX] & EF_PAX_MPROTECT)) + pax_flags |= MF_PAX_MPROTECT; +#endif + +#ifdef CONFIG_PAX_ASLR + if (randomize_va_space && !(elf_ex->e_ident[EI_PAX] & EF_PAX_RANDMMAP)) + pax_flags |= MF_PAX_RANDMMAP; +#endif + + return pax_flags; +} +#endif + +#if defined(CONFIG_PAX_EI_PAX) || defined(CONFIG_PAX_PT_PAX_FLAGS) +static long pax_parse_elf_flags(const struct elfhdr * const elf_ex, const struct elf_phdr * const elf_phdata) +{ + unsigned long pax_flags = 0UL; + +#ifdef CONFIG_PAX_PT_PAX_FLAGS + unsigned long i; +#endif + +#ifdef CONFIG_PAX_EI_PAX + pax_flags = pax_parse_ei_pax(elf_ex); +#endif + +#ifdef CONFIG_PAX_PT_PAX_FLAGS + for (i = 0UL; i < elf_ex->e_phnum; i++) + if (elf_phdata[i].p_type == PT_PAX_FLAGS) { + if (((elf_phdata[i].p_flags & PF_PAGEEXEC) && (elf_phdata[i].p_flags & PF_NOPAGEEXEC)) || + ((elf_phdata[i].p_flags & PF_SEGMEXEC) && (elf_phdata[i].p_flags & PF_NOSEGMEXEC)) || + ((elf_phdata[i].p_flags & PF_EMUTRAMP) && (elf_phdata[i].p_flags & PF_NOEMUTRAMP)) || + ((elf_phdata[i].p_flags & PF_MPROTECT) && (elf_phdata[i].p_flags & PF_NOMPROTECT)) || + ((elf_phdata[i].p_flags & PF_RANDMMAP) && (elf_phdata[i].p_flags & PF_NORANDMMAP))) + return -EINVAL; + +#ifdef CONFIG_PAX_SOFTMODE + if (pax_softmode) + pax_flags = pax_parse_softmode(&elf_phdata[i]); + else +#endif + + pax_flags = pax_parse_hardmode(&elf_phdata[i]); + break; + } +#endif + + if (0 > pax_check_flags(&pax_flags)) + return -EINVAL; + + current->mm->pax_flags = pax_flags; + return 0; +} +#endif + /* * These are the functions used to load ELF style executables and shared * libraries. There is no binary dependent code anywhere else. @@ -527,7 +730,7 @@ static int load_elf_binary(struct linux_ char * elf_interpreter = NULL; unsigned int interpreter_type = INTERPRETER_NONE; unsigned char ibcs2_interpreter = 0; - unsigned long error; + unsigned long error = 0; struct elf_phdr * elf_ppnt, *elf_phdata; unsigned long elf_bss, elf_brk; int elf_exec_fileno; @@ -545,6 +748,7 @@ static int load_elf_binary(struct linux_ struct elfhdr interp_elf_ex; struct exec interp_ex; } *loc; + unsigned long task_size = TASK_SIZE; loc = kmalloc(sizeof(*loc), GFP_KERNEL); if (!loc) { @@ -770,14 +974,88 @@ static int load_elf_binary(struct linux_ current->mm->end_code = 0; current->mm->mmap = NULL; current->flags &= ~PF_FORKNOEXEC; + +#if defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) + current->mm->pax_flags = 0UL; +#endif + +#ifdef CONFIG_PAX_DLRESOLVE + current->mm->call_dl_resolve = 0UL; +#endif + +#if defined(CONFIG_PPC32) && defined(CONFIG_PAX_EMUSIGRT) + current->mm->call_syscall = 0UL; +#endif + +#ifdef CONFIG_PAX_ASLR + current->mm->delta_mmap = 0UL; + current->mm->delta_exec = 0UL; + current->mm->delta_stack = 0UL; +#endif + current->mm->def_flags = def_flags; +#if defined(CONFIG_PAX_EI_PAX) || defined(CONFIG_PAX_PT_PAX_FLAGS) + if (0 > pax_parse_elf_flags(&loc->elf_ex, elf_phdata)) { + send_sig(SIGKILL, current, 0); + goto out_free_dentry; + } +#endif + +#ifdef CONFIG_PAX_HAVE_ACL_FLAGS + pax_set_initial_flags(bprm); +#elif defined(CONFIG_PAX_HOOK_ACL_FLAGS) + if (pax_set_initial_flags_func) + (pax_set_initial_flags_func)(bprm); +#endif + +#ifdef CONFIG_ARCH_TRACK_EXEC_LIMIT + if (current->mm->pax_flags & MF_PAX_PAGEEXEC) + current->mm->context.user_cs_limit = PAGE_SIZE; +#endif + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) { + int cpu = get_cpu(); + + current->mm->context.user_cs_base = SEGMEXEC_TASK_SIZE; + current->mm->context.user_cs_limit = -SEGMEXEC_TASK_SIZE; + set_user_cs(current->mm, cpu); + put_cpu(); + task_size = SEGMEXEC_TASK_SIZE; + } +#endif + +#ifdef CONFIG_PAX_ASLR + if (current->mm->pax_flags & MF_PAX_RANDMMAP) { +#define pax_delta_mask(delta, lsb, len) (((delta) & ((1UL << (len)) - 1)) << (lsb)) + + current->mm->delta_mmap = pax_delta_mask(pax_get_random_long(), PAX_DELTA_MMAP_LSB(current), PAX_DELTA_MMAP_LEN(current)); + current->mm->delta_exec = pax_delta_mask(pax_get_random_long(), PAX_DELTA_EXEC_LSB(current), PAX_DELTA_EXEC_LEN(current)); + current->mm->delta_stack = pax_delta_mask(pax_get_random_long(), PAX_DELTA_STACK_LSB(current), PAX_DELTA_STACK_LEN(current)); + } +#endif + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (current->mm->pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) + executable_stack = EXSTACK_DEFAULT; +#endif + /* Do this immediately, since STACK_TOP as used in setup_arg_pages may depend on the personality. */ SET_PERSONALITY(loc->elf_ex, ibcs2_interpreter); + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (!(current->mm->pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC))) +#endif + if (elf_read_implies_exec(loc->elf_ex, executable_stack)) current->personality |= READ_IMPLIES_EXEC; +#ifdef CONFIG_PAX_ASLR + if (!(current->mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if ( !(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) current->flags |= PF_RANDOMIZE; arch_pick_mmap_layout(current->mm); @@ -849,6 +1127,15 @@ static int load_elf_binary(struct linux_ base, as well as whatever program they might try to exec. This is because the brk will follow the loader, and is not movable. */ load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); + +#ifdef CONFIG_PAX_RANDMMAP + /* PaX: randomize base address at the default exe base if requested */ + if (current->mm->pax_flags & MF_PAX_RANDMMAP) { + load_bias = ELF_PAGESTART(PAX_ELF_ET_DYN_BASE(current) - vaddr + current->mm->delta_exec); + elf_flags |= MAP_FIXED; + } +#endif + } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, elf_prot, elf_flags); @@ -876,9 +1163,9 @@ static int load_elf_binary(struct linux_ * allowed task size. Note that p_filesz must always be * <= p_memsz so it is only necessary to check p_memsz. */ - if (k > TASK_SIZE || elf_ppnt->p_filesz > elf_ppnt->p_memsz || - elf_ppnt->p_memsz > TASK_SIZE || - TASK_SIZE - elf_ppnt->p_memsz < k) { + if (k > task_size || elf_ppnt->p_filesz > elf_ppnt->p_memsz || + elf_ppnt->p_memsz > task_size || + task_size - elf_ppnt->p_memsz < k) { /* set_brk can never work. Avoid overflows. */ send_sig(SIGKILL, current, 0); goto out_free_dentry; @@ -905,6 +1192,12 @@ static int load_elf_binary(struct linux_ start_data += load_bias; end_data += load_bias; +#ifdef CONFIG_PAX_RANDMMAP + if (current->mm->pax_flags & MF_PAX_RANDMMAP) + elf_brk += PAGE_SIZE + pax_delta_mask(pax_get_random_long(), 4, PAGE_SHIFT); +#undef pax_delta_mask +#endif + /* Calling set_brk effectively mmaps the pages that we need * for the bss and break sections. We must do this before * mapping in the interpreter, to make sure it doesn't wind @@ -933,7 +1226,7 @@ static int load_elf_binary(struct linux_ printk(KERN_ERR "Unable to load interpreter %.128s\n", elf_interpreter); force_sig(SIGSEGV, current); - retval = -ENOEXEC; /* Nobody gets to see this, but.. */ + retval = elf_entry; /* Nobody gets to see this, but.. */ goto out_free_dentry; } reloc_func_desc = interp_load_addr; @@ -1157,7 +1450,7 @@ static int dump_seek(struct file *file, * * I think we should skip something. But I am not sure how. H.J. */ -static int maydump(struct vm_area_struct *vma) +static int maydump(struct vm_area_struct *vma, long signr) { /* Do not dump I/O mapped devices or special mappings */ if (vma->vm_flags & (VM_IO | VM_RESERVED)) @@ -1168,7 +1461,7 @@ static int maydump(struct vm_area_struct return vma->vm_file->f_dentry->d_inode->i_nlink == 0; /* If it hasn't been written to, don't write it out */ - if (!vma->anon_vma) + if (signr != SIGKILL && !vma->anon_vma) return 0; return 1; @@ -1222,8 +1515,11 @@ static int writenote(struct memelfnote * #undef DUMP_SEEK #define DUMP_WRITE(addr, nr) \ + do { \ + gr_learn_resource(current, RLIMIT_CORE, size + (nr), 1); \ if ((size += (nr)) > limit || !dump_write(file, (addr), (nr))) \ - goto end_coredump; + goto end_coredump; \ + } while (0); #define DUMP_SEEK(off) \ if (!dump_seek(file, (off))) \ goto end_coredump; @@ -1573,7 +1869,7 @@ static int elf_core_dump(long signr, str phdr.p_offset = offset; phdr.p_vaddr = vma->vm_start; phdr.p_paddr = 0; - phdr.p_filesz = maydump(vma) ? sz : 0; + phdr.p_filesz = maydump(vma, signr) ? sz : 0; phdr.p_memsz = sz; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; @@ -1606,7 +1902,7 @@ static int elf_core_dump(long signr, str for (vma = current->mm->mmap; vma != NULL; vma = vma->vm_next) { unsigned long addr; - if (!maydump(vma)) + if (!maydump(vma, signr)) continue; for (addr = vma->vm_start; @@ -1625,6 +1921,7 @@ static int elf_core_dump(long signr, str void *kaddr; flush_cache_page(vma, addr, page_to_pfn(page)); kaddr = kmap(page); + gr_learn_resource(current, RLIMIT_CORE, size + PAGE_SIZE, 1); if ((size += PAGE_SIZE) > limit || !dump_write(file, kaddr, PAGE_SIZE)) { diff -NurpP --minimal linux-2.6.17.11/fs/binfmt_elf_fdpic.c linux-2.6.17.11-g-v/fs/binfmt_elf_fdpic.c --- linux-2.6.17.11/fs/binfmt_elf_fdpic.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/binfmt_elf_fdpic.c 2006-08-28 14:56:36.000000000 +0200 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.17.11/fs/binfmt_flat.c linux-2.6.17.11-g-v/fs/binfmt_flat.c --- linux-2.6.17.11/fs/binfmt_flat.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/binfmt_flat.c 2006-08-28 14:56:36.000000000 +0200 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -552,7 +553,9 @@ static int load_flat_file(struct linux_b realdatastart = (unsigned long) -ENOMEM; printk("Unable to allocate RAM for process data, errno %d\n", (int)-datapos); + down_write(¤t->mm->mmap_sem); do_munmap(current->mm, textpos, text_len); + up_write(¤t->mm->mmap_sem); ret = realdatastart; goto err; } @@ -574,8 +577,10 @@ static int load_flat_file(struct linux_b } if (result >= (unsigned long)-4096) { printk("Unable to read data+bss, errno %d\n", (int)-result); + down_write(¤t->mm->mmap_sem); do_munmap(current->mm, textpos, text_len); do_munmap(current->mm, realdatastart, data_len + extra); + up_write(¤t->mm->mmap_sem); ret = result; goto err; } @@ -639,8 +644,10 @@ static int load_flat_file(struct linux_b } if (result >= (unsigned long)-4096) { printk("Unable to read code+data+bss, errno %d\n",(int)-result); + down_write(¤t->mm->mmap_sem); do_munmap(current->mm, textpos, text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long)); + up_write(¤t->mm->mmap_sem); ret = result; goto err; } diff -NurpP --minimal linux-2.6.17.11/fs/binfmt_misc.c linux-2.6.17.11-g-v/fs/binfmt_misc.c --- linux-2.6.17.11/fs/binfmt_misc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/binfmt_misc.c 2006-08-28 14:44:49.000000000 +0200 @@ -112,9 +112,11 @@ static int load_misc_binary(struct linux struct files_struct *files = NULL; retval = -ENOEXEC; - if (!enabled) + if (!enabled || bprm->misc) goto _ret; + bprm->misc++; + /* to keep locking time low, we copy the interpreter string */ read_lock(&entries_lock); fmt = check_file(bprm); diff -NurpP --minimal linux-2.6.17.11/fs/binfmt_som.c linux-2.6.17.11-g-v/fs/binfmt_som.c --- linux-2.6.17.11/fs/binfmt_som.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/binfmt_som.c 2006-08-28 14:56:36.000000000 +0200 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.17.11/fs/buffer.c linux-2.6.17.11-g-v/fs/buffer.c --- linux-2.6.17.11/fs/buffer.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/buffer.c 2006-08-28 14:44:49.000000000 +0200 @@ -42,6 +42,7 @@ #include #include #include +#include static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); static void invalidate_bh_lrus(void); @@ -2167,6 +2168,7 @@ static int __generic_cont_expand(struct err = -EFBIG; limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; + gr_learn_resource(current, RLIMIT_FSIZE, (unsigned long) size, 1); if (limit != RLIM_INFINITY && size > (loff_t)limit) { send_sig(SIGXFSZ, current, 0); goto out; diff -NurpP --minimal linux-2.6.17.11/fs/compat.c linux-2.6.17.11-g-v/fs/compat.c --- linux-2.6.17.11/fs/compat.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/compat.c 2006-08-28 14:44:49.000000000 +0200 @@ -46,6 +46,7 @@ #include #include #include +#include #include /* siocdevprivate_ioctl */ @@ -1498,6 +1499,11 @@ int compat_do_execve(char * filename, struct file *file; int retval; int i; +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif retval = -ENOMEM; bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); @@ -1515,6 +1521,15 @@ int compat_do_execve(char * filename, bprm->file = file; bprm->filename = filename; bprm->interp = filename; + + gr_learn_resource(current, RLIMIT_NPROC, atomic_read(¤t->user->processes), 1); + retval = -EAGAIN; + if (gr_handle_nproc()) + goto out_file; + retval = -EACCES; + if (!gr_acl_handle_execve(file->f_dentry, file->f_vfsmnt)) + goto out_file; + bprm->mm = mm_alloc(); retval = -ENOMEM; if (!bprm->mm) @@ -1553,10 +1568,39 @@ int compat_do_execve(char * filename, if (retval < 0) goto out; + if (!gr_tpe_allow(file)) { + retval = -EACCES; + goto out; + } + + if (gr_check_crash_exec(file)) { + retval = -EACCES; + goto out; + } + + gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); + + gr_handle_exec_args(bprm, (char __user * __user *)argv); + +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->signal->rlim, sizeof(old_rlim)); + old_exec_file = current->exec_file; + get_file(file); + current->exec_file = file; +#endif + + gr_set_proc_label(file->f_dentry, file->f_vfsmnt); + retval = search_binary_handler(bprm, regs); if (retval >= 0) { free_arg_pages(bprm); +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif + /* execve success */ security_bprm_free(bprm); acct_update_integrals(current); @@ -1564,6 +1608,13 @@ int compat_do_execve(char * filename, return retval; } +#ifdef CONFIG_GRKERNSEC + current->acl = old_acl; + memcpy(current->signal->rlim, old_rlim, sizeof(old_rlim)); + fput(current->exec_file); + current->exec_file = old_exec_file; +#endif + out: /* Something went wrong, return the inode and free the argument pages*/ for (i = 0 ; i < MAX_ARG_PAGES ; i++) { diff -NurpP --minimal linux-2.6.17.11/fs/dcache.c linux-2.6.17.11-g-v/fs/dcache.c --- linux-2.6.17.11/fs/dcache.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/dcache.c 2006-08-28 14:44:49.000000000 +0200 @@ -1389,7 +1389,7 @@ already_unhashed: * * "buflen" should be positive. Caller holds the dcache_lock. */ -static char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, +char * __d_path( struct dentry *dentry, struct vfsmount *vfsmnt, struct dentry *root, struct vfsmount *rootmnt, char *buffer, int buflen) { diff -NurpP --minimal linux-2.6.17.11/fs/devpts/inode.c linux-2.6.17.11-g-v/fs/devpts/inode.c --- linux-2.6.17.11/fs/devpts/inode.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/devpts/inode.c 2006-08-28 14:56:36.000000000 +0200 @@ -20,7 +20,19 @@ #include #include -#define DEVPTS_SUPER_MAGIC 0x1cd1 + +static int devpts_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + int ret = -EACCES; + + if (vx_check(inode->i_xid, VX_IDENT)) + ret = generic_permission(inode, mask, NULL); + return ret; +} + +static struct inode_operations devpts_file_inode_operations = { + .permission = devpts_permission, +}; static struct vfsmount *devpts_mnt; static struct dentry *devpts_root; @@ -91,6 +103,24 @@ static int devpts_remount(struct super_b return 0; } +static int devpts_filter(struct dentry *de) +{ + return vx_check(de->d_inode->i_xid, VX_IDENT); +} + +static int devpts_readdir(struct file * filp, void * dirent, filldir_t filldir) +{ + return dcache_readdir_filter(filp, dirent, filldir, devpts_filter); +} + +static struct file_operations devpts_dir_operations = { + .open = dcache_dir_open, + .release = dcache_dir_close, + .llseek = dcache_dir_lseek, + .read = generic_read_dir, + .readdir = devpts_readdir, +}; + static struct super_operations devpts_sops = { .statfs = simple_statfs, .remount_fs = devpts_remount, @@ -117,8 +147,9 @@ devpts_fill_super(struct super_block *s, inode->i_uid = inode->i_gid = 0; inode->i_mode = S_IFDIR | S_IRUGO | S_IXUGO | S_IWUSR; inode->i_op = &simple_dir_inode_operations; - inode->i_fop = &simple_dir_operations; + inode->i_fop = &devpts_dir_operations; inode->i_nlink = 2; + inode->i_xid = vx_current_xid(); devpts_root = s->s_root = d_alloc_root(inode); if (s->s_root) @@ -177,6 +208,8 @@ int devpts_pty_new(struct tty_struct *tt inode->i_gid = config.setgid ? config.gid : current->fsgid; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; init_special_inode(inode, S_IFCHR|config.mode, device); + inode->i_xid = vx_current_xid(); + inode->i_op = &devpts_file_inode_operations; inode->u.generic_ip = tty; dentry = get_node(number); diff -NurpP --minimal linux-2.6.17.11/fs/exec.c linux-2.6.17.11-g-v/fs/exec.c --- linux-2.6.17.11/fs/exec.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/exec.c 2006-08-28 14:56:36.000000000 +0200 @@ -49,6 +49,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -67,6 +71,15 @@ EXPORT_SYMBOL(suid_dumpable); static struct linux_binfmt *formats; static DEFINE_RWLOCK(binfmt_lock); +#ifdef CONFIG_PAX_SOFTMODE +unsigned int pax_softmode; +#endif + +#ifdef CONFIG_PAX_HOOK_ACL_FLAGS +void (*pax_set_initial_flags_func)(struct linux_binprm * bprm); +EXPORT_SYMBOL(pax_set_initial_flags_func); +#endif + int register_binfmt(struct linux_binfmt * fmt) { struct linux_binfmt ** tmp = &formats; @@ -312,6 +325,10 @@ void install_arg_page(struct vm_area_str if (unlikely(anon_vma_prepare(vma))) goto out; +#ifdef CONFIG_PAX_SEGMEXEC + if (page_count(page) == 1) +#endif + flush_dcache_page(page); pte = get_locked_pte(mm, address, &ptl); if (!pte) @@ -321,9 +338,21 @@ void install_arg_page(struct vm_area_str goto out; } inc_mm_counter(mm, anon_rss); + +#ifdef CONFIG_PAX_SEGMEXEC + if (page_count(page) == 1) +#endif + lru_cache_add_active(page); set_pte_at(mm, address, pte, pte_mkdirty(pte_mkwrite(mk_pte( page, vma->vm_page_prot)))); + +#ifdef CONFIG_PAX_SEGMEXEC + if (page_count(page) != 1) + page_add_anon_rmap(page, vma, address); + else +#endif + page_add_new_anon_rmap(page, vma, address); pte_unmap_unlock(pte, ptl); @@ -346,6 +375,10 @@ int setup_arg_pages(struct linux_binprm int i, ret; long arg_size; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *mpnt_m = NULL; +#endif + #ifdef CONFIG_STACK_GROWSUP /* Move the argument and environment strings to the bottom of the * stack space. @@ -404,11 +437,19 @@ int setup_arg_pages(struct linux_binprm bprm->loader += stack_base; bprm->exec += stack_base; - mpnt = kmem_cache_alloc(vm_area_cachep, SLAB_KERNEL); + mpnt = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); if (!mpnt) return -ENOMEM; - memset(mpnt, 0, sizeof(*mpnt)); +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && (VM_STACK_FLAGS & VM_MAYEXEC)) { + mpnt_m = kmem_cache_zalloc(vm_area_cachep, SLAB_KERNEL); + if (!mpnt_m) { + kmem_cache_free(vm_area_cachep, mpnt); + return -ENOMEM; + } + } +#endif down_write(&mm->mmap_sem); { @@ -430,13 +471,51 @@ int setup_arg_pages(struct linux_binprm else mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_flags |= mm->def_flags; - mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7]; + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_X86_32) + if (!(mm->pax_flags & MF_PAX_PAGEEXEC)) + mpnt->vm_page_prot = protection_map[(mpnt->vm_flags | VM_EXEC) & (VM_READ|VM_WRITE|VM_EXEC)]; + else +#endif + + mpnt->vm_page_prot = protection_map[mpnt->vm_flags & (VM_READ|VM_WRITE|VM_EXEC)]; if ((ret = insert_vm_struct(mm, mpnt))) { up_write(&mm->mmap_sem); kmem_cache_free(vm_area_cachep, mpnt); + +#ifdef CONFIG_PAX_SEGMEXEC + if (mpnt_m) + kmem_cache_free(vm_area_cachep, mpnt_m); +#endif + return ret; } - mm->stack_vm = mm->total_vm = vma_pages(mpnt); + vx_vmpages_sub(mm, mm->total_vm - vma_pages(mpnt)); + mm->stack_vm = mm->total_vm; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mpnt_m) { + *mpnt_m = *mpnt; + if (!(mpnt->vm_flags & VM_EXEC)) { + mpnt_m->vm_flags &= ~(VM_READ | VM_WRITE | VM_EXEC); + mpnt_m->vm_page_prot = PAGE_NONE; + } + mpnt_m->vm_start += SEGMEXEC_TASK_SIZE; + mpnt_m->vm_end += SEGMEXEC_TASK_SIZE; + if ((ret = insert_vm_struct(mm, mpnt_m))) { + up_write(&mm->mmap_sem); + kmem_cache_free(vm_area_cachep, mpnt_m); + return ret; + } + mpnt_m->vm_flags |= VM_MIRROR; + mpnt->vm_flags |= VM_MIRROR; + mpnt_m->vm_mirror = mpnt->vm_start - mpnt_m->vm_start; + mpnt->vm_mirror = mpnt_m->vm_start - mpnt->vm_start; + mpnt_m->vm_pgoff = mpnt->vm_pgoff; + mm->total_vm += vma_pages(mpnt_m); + } +#endif + } for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -444,6 +523,14 @@ int setup_arg_pages(struct linux_binprm if (page) { bprm->page[i] = NULL; install_arg_page(mpnt, page, stack_base); + +#ifdef CONFIG_PAX_SEGMEXEC + if (mpnt_m) { + page_cache_get(page); + install_arg_page(mpnt_m, page, stack_base + SEGMEXEC_TASK_SIZE); + } +#endif + } stack_base += PAGE_SIZE; } @@ -1147,6 +1234,11 @@ int do_execve(char * filename, struct file *file; int retval; int i; +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif retval = -ENOMEM; bprm = kzalloc(sizeof(*bprm), GFP_KERNEL); @@ -1158,10 +1250,29 @@ int do_execve(char * filename, if (IS_ERR(file)) goto out_kfree; + gr_learn_resource(current, RLIMIT_NPROC, atomic_read(¤t->user->processes), 1); + + if (gr_handle_nproc()) { + allow_write_access(file); + fput(file); + return -EAGAIN; + } + + if (!gr_acl_handle_execve(file->f_dentry, file->f_vfsmnt)) { + allow_write_access(file); + fput(file); + return -EACCES; + } + sched_exec(); bprm->p = PAGE_SIZE*MAX_ARG_PAGES-sizeof(void *); +#ifdef CONFIG_PAX_RANDUSTACK + if (randomize_va_space) + bprm->p -= (pax_get_random_long() & ~(sizeof(void *)-1)) & ~PAGE_MASK; +#endif + bprm->file = file; bprm->filename = filename; bprm->interp = filename; @@ -1203,8 +1314,38 @@ int do_execve(char * filename, if (retval < 0) goto out; + if (!gr_tpe_allow(file)) { + retval = -EACCES; + goto out; + } + + if (gr_check_crash_exec(file)) { + retval = -EACCES; + goto out; + } + + gr_log_chroot_exec(file->f_dentry, file->f_vfsmnt); + + gr_handle_exec_args(bprm, argv); + +#ifdef CONFIG_GRKERNSEC + old_acl = current->acl; + memcpy(old_rlim, current->signal->rlim, sizeof(old_rlim)); + old_exec_file = current->exec_file; + get_file(file); + current->exec_file = file; +#endif + + retval = gr_set_proc_label(file->f_dentry, file->f_vfsmnt); + if (retval < 0) + goto out_fail; + retval = search_binary_handler(bprm,regs); if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif free_arg_pages(bprm); /* execve success */ @@ -1214,6 +1355,14 @@ int do_execve(char * filename, return retval; } +out_fail: +#ifdef CONFIG_GRKERNSEC + current->acl = old_acl; + memcpy(current->signal->rlim, old_rlim, sizeof(old_rlim)); + fput(current->exec_file); + current->exec_file = old_exec_file; +#endif + out: /* Something went wrong, return the inode and free the argument pages*/ for (i = 0 ; i < MAX_ARG_PAGES ; i++) { @@ -1337,7 +1486,7 @@ static void format_corename(char *corena case 'h': down_read(&uts_sem); rc = snprintf(out_ptr, out_end - out_ptr, - "%s", system_utsname.nodename); + "%s", vx_new_uts(nodename)); up_read(&uts_sem); if (rc > out_end - out_ptr) goto out; @@ -1374,6 +1523,114 @@ static void format_corename(char *corena *out_ptr = 0; } +int pax_check_flags(unsigned long * flags) +{ + int retval = 0; + +#if !defined(__i386__) || !defined(CONFIG_PAX_SEGMEXEC) + if (*flags & MF_PAX_SEGMEXEC) + { + *flags &= ~MF_PAX_SEGMEXEC; + retval = -EINVAL; + } +#endif + + if ((*flags & MF_PAX_PAGEEXEC) + +#ifdef CONFIG_PAX_PAGEEXEC + && (*flags & MF_PAX_SEGMEXEC) +#endif + + ) + { + *flags &= ~MF_PAX_PAGEEXEC; + retval = -EINVAL; + } + + if ((*flags & MF_PAX_MPROTECT) + +#ifdef CONFIG_PAX_MPROTECT + && !(*flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) +#endif + + ) + { + *flags &= ~MF_PAX_MPROTECT; + retval = -EINVAL; + } + + if ((*flags & MF_PAX_EMUTRAMP) + +#ifdef CONFIG_PAX_EMUTRAMP + && !(*flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) +#endif + + ) + { + *flags &= ~MF_PAX_EMUTRAMP; + retval = -EINVAL; + } + + return retval; +} + +EXPORT_SYMBOL(pax_check_flags); + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) +void pax_report_fault(struct pt_regs *regs, void *pc, void *sp) +{ + struct task_struct *tsk = current; + struct mm_struct *mm = current->mm; + char* buffer_exec = (char*)__get_free_page(GFP_ATOMIC); + char* buffer_fault = (char*)__get_free_page(GFP_ATOMIC); + char* path_exec=NULL; + char* path_fault=NULL; + unsigned long start=0UL, end=0UL, offset=0UL; + + if (buffer_exec && buffer_fault) { + struct vm_area_struct* vma, * vma_exec=NULL, * vma_fault=NULL; + + down_read(&mm->mmap_sem); + vma = mm->mmap; + while (vma && (!vma_exec || !vma_fault)) { + if ((vma->vm_flags & VM_EXECUTABLE) && vma->vm_file) + vma_exec = vma; + if (vma->vm_start <= (unsigned long)pc && (unsigned long)pc < vma->vm_end) + vma_fault = vma; + vma = vma->vm_next; + } + if (vma_exec) { + path_exec = d_path(vma_exec->vm_file->f_dentry, vma_exec->vm_file->f_vfsmnt, buffer_exec, PAGE_SIZE); + if (IS_ERR(path_exec)) + path_exec = ""; + } + if (vma_fault) { + start = vma_fault->vm_start; + end = vma_fault->vm_end; + offset = vma_fault->vm_pgoff << PAGE_SHIFT; + if (vma_fault->vm_file) { + path_fault = d_path(vma_fault->vm_file->f_dentry, vma_fault->vm_file->f_vfsmnt, buffer_fault, PAGE_SIZE); + if (IS_ERR(path_fault)) + path_fault = ""; + } else + path_fault = ""; + } + up_read(&mm->mmap_sem); + } + if (tsk->signal->curr_ip) + printk(KERN_ERR "PAX: From %u.%u.%u.%u: execution attempt in: %s, %08lx-%08lx %08lx\n", NIPQUAD(tsk->signal->curr_ip), path_fault, start, end, offset); + else + printk(KERN_ERR "PAX: execution attempt in: %s, %08lx-%08lx %08lx\n", path_fault, start, end, offset); + printk(KERN_ERR "PAX: terminating task: %s(%s):%d, uid/euid: %u/%u, " + "PC: %p, SP: %p\n", path_exec, tsk->comm, tsk->pid, + tsk->uid, tsk->euid, pc, sp); + free_page((unsigned long)buffer_exec); + free_page((unsigned long)buffer_fault); + pax_report_insns(pc, sp); + do_coredump(SIGKILL, SIGKILL, regs); +} +#endif + static void zap_threads (struct mm_struct *mm) { struct task_struct *g, *p; @@ -1491,6 +1748,10 @@ int do_coredump(long signr, int exit_cod */ clear_thread_flag(TIF_SIGPENDING); + if (signr == SIGKILL || signr == SIGILL) + gr_handle_brute_attach(current); + + gr_learn_resource(current, RLIMIT_CORE, binfmt->min_coredump, 1); if (current->signal->rlim[RLIMIT_CORE].rlim_cur < binfmt->min_coredump) goto fail_unlock; diff -NurpP --minimal linux-2.6.17.11/fs/ext2/balloc.c linux-2.6.17.11-g-v/fs/ext2/balloc.c --- linux-2.6.17.11/fs/ext2/balloc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/balloc.c 2006-08-28 14:56:36.000000000 +0200 @@ -17,6 +17,7 @@ #include #include #include +#include /* * balloc.c contains the blocks allocation and deallocation routines @@ -109,6 +110,8 @@ static int reserve_blocks(struct super_b free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); root_blocks = le32_to_cpu(es->s_r_blocks_count); + DLIMIT_ADJUST_BLOCK(sb, vx_current_xid(), &free_blocks, &root_blocks); + if (free_blocks < count) count = free_blocks; @@ -259,6 +262,7 @@ do_more: } error_return: brelse(bitmap_bh); + DLIMIT_FREE_BLOCK(inode, freed); release_blocks(sb, freed); DQUOT_FREE_BLOCK(inode, freed); } @@ -362,6 +366,10 @@ int ext2_new_block(struct inode *inode, *err = -ENOSPC; goto out_dquot; } + if (DLIMIT_ALLOC_BLOCK(inode, es_alloc)) { + *err = -ENOSPC; + goto out_dlimit; + } ext2_debug ("goal=%lu.\n", goal); @@ -509,6 +517,8 @@ got_block: *err = 0; out_release: group_release_blocks(sb, group_no, desc, gdp_bh, group_alloc); + DLIMIT_FREE_BLOCK(inode, es_alloc); +out_dlimit: release_blocks(sb, es_alloc); out_dquot: DQUOT_FREE_BLOCK(inode, dq_alloc); diff -NurpP --minimal linux-2.6.17.11/fs/ext2/ext2.h linux-2.6.17.11-g-v/fs/ext2/ext2.h --- linux-2.6.17.11/fs/ext2/ext2.h 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/ext2.h 2006-08-28 14:56:36.000000000 +0200 @@ -165,6 +165,7 @@ extern const struct file_operations ext2 extern struct address_space_operations ext2_aops; extern struct address_space_operations ext2_aops_xip; extern struct address_space_operations ext2_nobh_aops; +extern int ext2_sync_flags(struct inode *inode); /* namei.c */ extern struct inode_operations ext2_dir_inode_operations; diff -NurpP --minimal linux-2.6.17.11/fs/ext2/file.c linux-2.6.17.11-g-v/fs/ext2/file.c --- linux-2.6.17.11/fs/ext2/file.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/file.c 2006-08-28 14:56:36.000000000 +0200 @@ -81,4 +81,5 @@ struct inode_operations ext2_file_inode_ #endif .setattr = ext2_setattr, .permission = ext2_permission, + .sync_flags = ext2_sync_flags, }; diff -NurpP --minimal linux-2.6.17.11/fs/ext2/ialloc.c linux-2.6.17.11-g-v/fs/ext2/ialloc.c --- linux-2.6.17.11/fs/ext2/ialloc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/ialloc.c 2006-08-28 14:56:36.000000000 +0200 @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -126,6 +128,7 @@ void ext2_free_inode (struct inode * ino ext2_xattr_delete_inode(inode); DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); } es = EXT2_SB(sb)->s_es; @@ -465,6 +468,11 @@ struct inode *ext2_new_inode(struct inod if (!inode) return ERR_PTR(-ENOMEM); + inode->i_xid = vx_current_fsxid(sb); + if (DLIMIT_ALLOC_INODE(inode)) { + err = -ENOSPC; + goto fail_dlim; + } ei = EXT2_I(inode); sbi = EXT2_SB(sb); es = sbi->s_es; @@ -579,7 +587,8 @@ got: inode->i_blocks = 0; inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME_SEC; memset(ei->i_data, 0, sizeof(ei->i_data)); - ei->i_flags = EXT2_I(dir)->i_flags & ~EXT2_BTREE_FL; + ei->i_flags = EXT2_I(dir)->i_flags & + ~(EXT2_BTREE_FL|EXT2_IUNLINK_FL|EXT2_BARRIER_FL); if (S_ISLNK(mode)) ei->i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL); /* dirsync is only applied to directories */ @@ -627,12 +636,15 @@ fail_free_drop: fail_drop: DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; iput(inode); return ERR_PTR(err); fail: + DLIMIT_FREE_INODE(inode); +fail_dlim: make_bad_inode(inode); iput(inode); return ERR_PTR(err); diff -NurpP --minimal linux-2.6.17.11/fs/ext2/inode.c linux-2.6.17.11-g-v/fs/ext2/inode.c --- linux-2.6.17.11/fs/ext2/inode.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/inode.c 2006-08-28 16:03:19.000000000 +0200 @@ -31,6 +31,7 @@ #include #include #include +#include #include "ext2.h" #include "acl.h" #include "xip.h" @@ -1042,25 +1043,70 @@ void ext2_set_inode_flags(struct inode * { unsigned int flags = EXT2_I(inode)->i_flags; - inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + inode->i_flags &= ~(S_IMMUTABLE | S_IUNLINK | S_BARRIER | + S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); + + if (flags & EXT2_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & EXT2_IUNLINK_FL) + inode->i_flags |= S_IUNLINK; + if (flags & EXT2_BARRIER_FL) + inode->i_flags |= S_BARRIER; + if (flags & EXT2_SYNC_FL) inode->i_flags |= S_SYNC; if (flags & EXT2_APPEND_FL) inode->i_flags |= S_APPEND; - if (flags & EXT2_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; if (flags & EXT2_NOATIME_FL) inode->i_flags |= S_NOATIME; if (flags & EXT2_DIRSYNC_FL) inode->i_flags |= S_DIRSYNC; } +int ext2_sync_flags(struct inode *inode) +{ + unsigned int oldflags, newflags; + + oldflags = EXT2_I(inode)->i_flags; + newflags = oldflags & ~(EXT2_APPEND_FL | + EXT2_IMMUTABLE_FL | EXT2_IUNLINK_FL | + EXT2_BARRIER_FL | EXT2_NOATIME_FL | + EXT2_SYNC_FL | EXT2_DIRSYNC_FL); + + if (IS_APPEND(inode)) + newflags |= EXT2_APPEND_FL; + if (IS_IMMUTABLE(inode)) + newflags |= EXT2_IMMUTABLE_FL; + if (IS_IUNLINK(inode)) + newflags |= EXT2_IUNLINK_FL; + if (IS_BARRIER(inode)) + newflags |= EXT2_BARRIER_FL; + + /* we do not want to copy superblock flags */ + if (inode->i_flags & S_NOATIME) + newflags |= EXT2_NOATIME_FL; + if (inode->i_flags & S_SYNC) + newflags |= EXT2_SYNC_FL; + if (inode->i_flags & S_DIRSYNC) + newflags |= EXT2_DIRSYNC_FL; + + if (oldflags ^ newflags) { + EXT2_I(inode)->i_flags = newflags; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + } + + return 0; +} + void ext2_read_inode (struct inode * inode) { struct ext2_inode_info *ei = EXT2_I(inode); ino_t ino = inode->i_ino; struct buffer_head * bh; struct ext2_inode * raw_inode = ext2_get_inode(inode->i_sb, ino, &bh); + uid_t uid; + gid_t gid; int n; #ifdef CONFIG_EXT2_FS_POSIX_ACL @@ -1071,12 +1117,17 @@ void ext2_read_inode (struct inode * ino goto bad_inode; inode->i_mode = le16_to_cpu(raw_inode->i_mode); - inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); - inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); + uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); + gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); if (!(test_opt (inode->i_sb, NO_UID32))) { - inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; - inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; + uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; + gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; } + inode->i_uid = INOXID_UID(XID_TAG(inode), uid, gid); + inode->i_gid = INOXID_GID(XID_TAG(inode), uid, gid); + inode->i_xid = INOXID_XID(XID_TAG(inode), uid, gid, + le16_to_cpu(raw_inode->i_raw_xid)); + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); inode->i_size = le32_to_cpu(raw_inode->i_size); inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime); @@ -1174,8 +1225,8 @@ static int ext2_update_inode(struct inod struct ext2_inode_info *ei = EXT2_I(inode); struct super_block *sb = inode->i_sb; ino_t ino = inode->i_ino; - uid_t uid = inode->i_uid; - gid_t gid = inode->i_gid; + uid_t uid = XIDINO_UID(XID_TAG(inode), inode->i_uid, inode->i_xid); + gid_t gid = XIDINO_GID(XID_TAG(inode), inode->i_gid, inode->i_xid); struct buffer_head * bh; struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); int n; @@ -1210,6 +1261,9 @@ static int ext2_update_inode(struct inod raw_inode->i_uid_high = 0; raw_inode->i_gid_high = 0; } +#ifdef CONFIG_INOXID_INTERN + raw_inode->i_raw_xid = cpu_to_le16(inode->i_xid); +#endif raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); raw_inode->i_size = cpu_to_le32(inode->i_size); raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); @@ -1296,7 +1350,8 @@ int ext2_setattr(struct dentry *dentry, if (error) return error; if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || - (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { + (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) || + (iattr->ia_valid & ATTR_XID && iattr->ia_xid != inode->i_xid)) { error = DQUOT_TRANSFER(inode, iattr) ? -EDQUOT : 0; if (error) return error; diff -NurpP --minimal linux-2.6.17.11/fs/ext2/ioctl.c linux-2.6.17.11-g-v/fs/ext2/ioctl.c --- linux-2.6.17.11/fs/ext2/ioctl.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/ioctl.c 2006-08-28 14:56:36.000000000 +0200 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -30,7 +31,8 @@ int ext2_ioctl (struct inode * inode, st case EXT2_IOC_SETFLAGS: { unsigned int oldflags; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) @@ -50,7 +52,9 @@ int ext2_ioctl (struct inode * inode, st * * This test looks nicer. Thanks to Pauline Middelink */ - if ((flags ^ oldflags) & (EXT2_APPEND_FL | EXT2_IMMUTABLE_FL)) { + if ((oldflags & EXT2_IMMUTABLE_FL) || + ((flags ^ oldflags) & (EXT2_APPEND_FL | + EXT2_IMMUTABLE_FL | EXT2_IUNLINK_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; } @@ -69,7 +73,8 @@ int ext2_ioctl (struct inode * inode, st case EXT2_IOC_SETVERSION: if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (get_user(inode->i_generation, (int __user *) arg)) return -EFAULT; diff -NurpP --minimal linux-2.6.17.11/fs/ext2/namei.c linux-2.6.17.11-g-v/fs/ext2/namei.c --- linux-2.6.17.11/fs/ext2/namei.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/namei.c 2006-08-28 14:56:36.000000000 +0200 @@ -31,6 +31,7 @@ */ #include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -66,6 +67,7 @@ static struct dentry *ext2_lookup(struct inode = iget(dir->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); + vx_propagate_xid(nd, inode); } return d_splice_alias(inode, dentry); } @@ -391,6 +393,7 @@ struct inode_operations ext2_dir_inode_o #endif .setattr = ext2_setattr, .permission = ext2_permission, + .sync_flags = ext2_sync_flags, }; struct inode_operations ext2_special_inode_operations = { @@ -402,4 +405,5 @@ struct inode_operations ext2_special_ino #endif .setattr = ext2_setattr, .permission = ext2_permission, + .sync_flags = ext2_sync_flags, }; diff -NurpP --minimal linux-2.6.17.11/fs/ext2/super.c linux-2.6.17.11-g-v/fs/ext2/super.c --- linux-2.6.17.11/fs/ext2/super.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/super.c 2006-08-28 14:56:36.000000000 +0200 @@ -287,7 +287,7 @@ enum { Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota + Opt_usrquota, Opt_grpquota, Opt_tagxid }; static match_table_t tokens = { @@ -315,6 +315,7 @@ static match_table_t tokens = { {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, {Opt_xip, "xip"}, + {Opt_tagxid, "tagxid"}, {Opt_grpquota, "grpquota"}, {Opt_ignore, "noquota"}, {Opt_quota, "quota"}, @@ -378,6 +379,11 @@ static int parse_options (char * options case Opt_nouid32: set_opt (sbi->s_mount_opt, NO_UID32); break; +#ifndef CONFIG_INOXID_NONE + case Opt_tagxid: + set_opt (sbi->s_mount_opt, TAGXID); + break; +#endif case Opt_nocheck: clear_opt (sbi->s_mount_opt, CHECK); break; @@ -679,6 +685,8 @@ static int ext2_fill_super(struct super_ if (!parse_options ((char *) data, sbi)) goto failed_mount; + if (EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_TAGXID) + sb->s_flags |= MS_TAGXID; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); @@ -988,6 +996,13 @@ static int ext2_remount (struct super_bl goto restore_opts; } + if ((sbi->s_mount_opt & EXT2_MOUNT_TAGXID) && + !(sb->s_flags & MS_TAGXID)) { + printk("EXT2-fs: %s: tagxid not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); diff -NurpP --minimal linux-2.6.17.11/fs/ext2/symlink.c linux-2.6.17.11-g-v/fs/ext2/symlink.c --- linux-2.6.17.11/fs/ext2/symlink.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/symlink.c 2006-08-28 14:56:36.000000000 +0200 @@ -38,6 +38,7 @@ struct inode_operations ext2_symlink_ino .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext2_sync_flags, }; struct inode_operations ext2_fast_symlink_inode_operations = { @@ -49,4 +50,5 @@ struct inode_operations ext2_fast_symlin .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext2_sync_flags, }; diff -NurpP --minimal linux-2.6.17.11/fs/ext2/xattr.c linux-2.6.17.11-g-v/fs/ext2/xattr.c --- linux-2.6.17.11/fs/ext2/xattr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext2/xattr.c 2006-08-28 14:56:36.000000000 +0200 @@ -60,6 +60,7 @@ #include #include #include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -645,8 +646,12 @@ ext2_xattr_set2(struct inode *inode, str the inode. */ ea_bdebug(new_bh, "reusing block"); + error = -ENOSPC; + if (DLIMIT_ALLOC_BLOCK(inode, 1)) + goto cleanup; error = -EDQUOT; if (DQUOT_ALLOC_BLOCK(inode, 1)) { + DLIMIT_FREE_BLOCK(inode, 1); unlock_buffer(new_bh); goto cleanup; } @@ -740,6 +745,7 @@ ext2_xattr_set2(struct inode *inode, str le32_to_cpu(HDR(old_bh)->h_refcount) - 1); if (ce) mb_cache_entry_release(ce); + DLIMIT_FREE_BLOCK(inode, 1); DQUOT_FREE_BLOCK(inode, 1); mark_buffer_dirty(old_bh); ea_bdebug(old_bh, "refcount now=%d", @@ -804,6 +810,7 @@ ext2_xattr_delete_inode(struct inode *in mark_buffer_dirty(bh); if (IS_SYNC(inode)) sync_dirty_buffer(bh); + DLIMIT_FREE_BLOCK(inode, 1); DQUOT_FREE_BLOCK(inode, 1); } EXT2_I(inode)->i_file_acl = 0; diff -NurpP --minimal linux-2.6.17.11/fs/ext3/balloc.c linux-2.6.17.11-g-v/fs/ext3/balloc.c --- linux-2.6.17.11/fs/ext3/balloc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/balloc.c 2006-08-28 14:56:36.000000000 +0200 @@ -20,6 +20,7 @@ #include #include #include +#include /* * balloc.c contains the blocks allocation and deallocation routines @@ -504,8 +505,10 @@ void ext3_free_blocks(handle_t *handle, return; } ext3_free_blocks_sb(handle, sb, block, count, &dquot_freed_blocks); - if (dquot_freed_blocks) + if (dquot_freed_blocks) { + DLIMIT_FREE_BLOCK(inode, dquot_freed_blocks); DQUOT_FREE_BLOCK(inode, dquot_freed_blocks); + } return; } @@ -1162,18 +1165,32 @@ out: return ret; } -static int ext3_has_free_blocks(struct ext3_sb_info *sbi) +static int ext3_has_free_blocks(struct super_block *sb) { - int free_blocks, root_blocks; + struct ext3_sb_info *sbi = EXT3_SB(sb); + int free_blocks, root_blocks, cond; free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); root_blocks = le32_to_cpu(sbi->s_es->s_r_blocks_count); - if (free_blocks < root_blocks + 1 && !capable(CAP_SYS_RESOURCE) && + + vxdprintk(VXD_CBIT(dlim, 3), + "ext3_has_free_blocks(%p): free=%u, root=%u", + sb, free_blocks, root_blocks); + + DLIMIT_ADJUST_BLOCK(sb, vx_current_xid(), &free_blocks, &root_blocks); + + cond = (free_blocks < root_blocks + 1 && + !capable(CAP_SYS_RESOURCE) && sbi->s_resuid != current->fsuid && - (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { - return 0; - } - return 1; + (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))); + + vxdprintk(VXD_CBIT(dlim, 3), + "ext3_has_free_blocks(%p): %u<%u+1, %c, %u!=%u r=%d", + sb, free_blocks, root_blocks, + !capable(CAP_SYS_RESOURCE)?'1':'0', + sbi->s_resuid, current->fsuid, cond?0:1); + + return (cond ? 0 : 1); } /* @@ -1184,7 +1201,7 @@ static int ext3_has_free_blocks(struct e */ int ext3_should_retry_alloc(struct super_block *sb, int *retries) { - if (!ext3_has_free_blocks(EXT3_SB(sb)) || (*retries)++ > 3) + if (!ext3_has_free_blocks(sb) || (*retries)++ > 3) return 0; jbd_debug(1, "%s: retrying operation after ENOSPC\n", sb->s_id); @@ -1240,6 +1257,8 @@ int ext3_new_blocks(handle_t *handle, st *errp = -EDQUOT; return 0; } + if (DLIMIT_ALLOC_BLOCK(inode, 1)) + goto out_dlimit; sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; @@ -1256,7 +1275,7 @@ int ext3_new_blocks(handle_t *handle, st if (block_i && ((windowsz = block_i->rsv_window_node.rsv_goal_size) > 0)) my_rsv = &block_i->rsv_window_node; - if (!ext3_has_free_blocks(sbi)) { + if (!ext3_has_free_blocks(sb)) { *errp = -ENOSPC; goto out; } @@ -1448,6 +1467,9 @@ allocated: io_error: *errp = -EIO; out: + if (!performed_allocation) + DLIMIT_FREE_BLOCK(inode, 1); +out_dlimit: if (fatal) { *errp = fatal; ext3_std_error(sb, fatal); diff -NurpP --minimal linux-2.6.17.11/fs/ext3/file.c linux-2.6.17.11-g-v/fs/ext3/file.c --- linux-2.6.17.11/fs/ext3/file.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/file.c 2006-08-28 14:56:36.000000000 +0200 @@ -133,5 +133,6 @@ struct inode_operations ext3_file_inode_ .removexattr = generic_removexattr, #endif .permission = ext3_permission, + .sync_flags = ext3_sync_flags, }; diff -NurpP --minimal linux-2.6.17.11/fs/ext3/ialloc.c linux-2.6.17.11-g-v/fs/ext3/ialloc.c --- linux-2.6.17.11/fs/ext3/ialloc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/ialloc.c 2006-08-28 14:56:36.000000000 +0200 @@ -23,6 +23,8 @@ #include #include #include +#include +#include #include @@ -127,6 +129,7 @@ void ext3_free_inode (handle_t *handle, ext3_xattr_delete_inode(handle, inode); DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); is_directory = S_ISDIR(inode->i_mode); @@ -443,6 +446,12 @@ struct inode *ext3_new_inode(handle_t *h inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); + + inode->i_xid = vx_current_fsxid(sb); + if (DLIMIT_ALLOC_INODE(inode)) { + err = -ENOSPC; + goto out_dlimit; + } ei = EXT3_I(inode); sbi = EXT3_SB(sb); @@ -565,7 +574,8 @@ got: ei->i_dir_start_lookup = 0; ei->i_disksize = 0; - ei->i_flags = EXT3_I(dir)->i_flags & ~EXT3_INDEX_FL; + ei->i_flags = EXT3_I(dir)->i_flags & + ~(EXT3_INDEX_FL|EXT3_IUNLINK_FL|EXT3_BARRIER_FL); if (S_ISLNK(mode)) ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL); /* dirsync only applies to directories */ @@ -620,6 +630,8 @@ got: fail: ext3_std_error(sb, err); out: + DLIMIT_FREE_INODE(inode); +out_dlimit: iput(inode); ret = ERR_PTR(err); really_out: @@ -631,6 +643,7 @@ fail_free_drop: fail_drop: DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; iput(inode); diff -NurpP --minimal linux-2.6.17.11/fs/ext3/inode.c linux-2.6.17.11-g-v/fs/ext3/inode.c --- linux-2.6.17.11/fs/ext3/inode.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/inode.c 2006-08-28 14:56:36.000000000 +0200 @@ -36,6 +36,7 @@ #include #include #include +#include #include "xattr.h" #include "acl.h" @@ -2563,19 +2564,77 @@ void ext3_set_inode_flags(struct inode * { unsigned int flags = EXT3_I(inode)->i_flags; - inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + inode->i_flags &= ~(S_IMMUTABLE | S_IUNLINK | S_BARRIER | + S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); + + if (flags & EXT3_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & EXT3_IUNLINK_FL) + inode->i_flags |= S_IUNLINK; + if (flags & EXT3_BARRIER_FL) + inode->i_flags |= S_BARRIER; + if (flags & EXT3_SYNC_FL) inode->i_flags |= S_SYNC; if (flags & EXT3_APPEND_FL) inode->i_flags |= S_APPEND; - if (flags & EXT3_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; if (flags & EXT3_NOATIME_FL) inode->i_flags |= S_NOATIME; if (flags & EXT3_DIRSYNC_FL) inode->i_flags |= S_DIRSYNC; } +int ext3_sync_flags(struct inode *inode) +{ + unsigned int oldflags, newflags; + int err = 0; + + oldflags = EXT3_I(inode)->i_flags; + newflags = oldflags & ~(EXT3_APPEND_FL | + EXT3_IMMUTABLE_FL | EXT3_IUNLINK_FL | + EXT3_BARRIER_FL | EXT3_NOATIME_FL | + EXT3_SYNC_FL | EXT3_DIRSYNC_FL); + + if (IS_APPEND(inode)) + newflags |= EXT3_APPEND_FL; + if (IS_IMMUTABLE(inode)) + newflags |= EXT3_IMMUTABLE_FL; + if (IS_IUNLINK(inode)) + newflags |= EXT3_IUNLINK_FL; + if (IS_BARRIER(inode)) + newflags |= EXT3_BARRIER_FL; + + /* we do not want to copy superblock flags */ + if (inode->i_flags & S_NOATIME) + newflags |= EXT3_NOATIME_FL; + if (inode->i_flags & S_SYNC) + newflags |= EXT3_SYNC_FL; + if (inode->i_flags & S_DIRSYNC) + newflags |= EXT3_DIRSYNC_FL; + + if (oldflags ^ newflags) { + handle_t *handle; + struct ext3_iloc iloc; + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (IS_SYNC(inode)) + handle->h_sync = 1; + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + goto flags_err; + + EXT3_I(inode)->i_flags = newflags; + inode->i_ctime = CURRENT_TIME; + + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + flags_err: + ext3_journal_stop(handle); + } + return err; +} + void ext3_read_inode(struct inode * inode) { struct ext3_iloc iloc; @@ -2583,6 +2642,8 @@ void ext3_read_inode(struct inode * inod struct ext3_inode_info *ei = EXT3_I(inode); struct buffer_head *bh; int block; + uid_t uid; + gid_t gid; #ifdef CONFIG_EXT3_FS_POSIX_ACL ei->i_acl = EXT3_ACL_NOT_CACHED; @@ -2595,12 +2656,17 @@ void ext3_read_inode(struct inode * inod bh = iloc.bh; raw_inode = ext3_raw_inode(&iloc); inode->i_mode = le16_to_cpu(raw_inode->i_mode); - inode->i_uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); - inode->i_gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); + uid = (uid_t)le16_to_cpu(raw_inode->i_uid_low); + gid = (gid_t)le16_to_cpu(raw_inode->i_gid_low); if(!(test_opt (inode->i_sb, NO_UID32))) { - inode->i_uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; - inode->i_gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; + uid |= le16_to_cpu(raw_inode->i_uid_high) << 16; + gid |= le16_to_cpu(raw_inode->i_gid_high) << 16; } + inode->i_uid = INOXID_UID(XID_TAG(inode), uid, gid); + inode->i_gid = INOXID_GID(XID_TAG(inode), uid, gid); + inode->i_xid = INOXID_XID(XID_TAG(inode), uid, gid, + le16_to_cpu(raw_inode->i_raw_xid)); + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); inode->i_size = le32_to_cpu(raw_inode->i_size); inode->i_atime.tv_sec = le32_to_cpu(raw_inode->i_atime); @@ -2727,6 +2793,8 @@ static int ext3_do_update_inode(handle_t struct ext3_inode *raw_inode = ext3_raw_inode(iloc); struct ext3_inode_info *ei = EXT3_I(inode); struct buffer_head *bh = iloc->bh; + uid_t uid = XIDINO_UID(XID_TAG(inode), inode->i_uid, inode->i_xid); + gid_t gid = XIDINO_GID(XID_TAG(inode), inode->i_gid, inode->i_xid); int err = 0, rc, block; /* For fields not not tracking in the in-memory inode, @@ -2736,29 +2804,32 @@ static int ext3_do_update_inode(handle_t raw_inode->i_mode = cpu_to_le16(inode->i_mode); if(!(test_opt(inode->i_sb, NO_UID32))) { - raw_inode->i_uid_low = cpu_to_le16(low_16_bits(inode->i_uid)); - raw_inode->i_gid_low = cpu_to_le16(low_16_bits(inode->i_gid)); + raw_inode->i_uid_low = cpu_to_le16(low_16_bits(uid)); + raw_inode->i_gid_low = cpu_to_le16(low_16_bits(gid)); /* * Fix up interoperability with old kernels. Otherwise, old inodes get * re-used with the upper 16 bits of the uid/gid intact */ if(!ei->i_dtime) { raw_inode->i_uid_high = - cpu_to_le16(high_16_bits(inode->i_uid)); + cpu_to_le16(high_16_bits(uid)); raw_inode->i_gid_high = - cpu_to_le16(high_16_bits(inode->i_gid)); + cpu_to_le16(high_16_bits(gid)); } else { raw_inode->i_uid_high = 0; raw_inode->i_gid_high = 0; } } else { raw_inode->i_uid_low = - cpu_to_le16(fs_high2lowuid(inode->i_uid)); + cpu_to_le16(fs_high2lowuid(uid)); raw_inode->i_gid_low = - cpu_to_le16(fs_high2lowgid(inode->i_gid)); + cpu_to_le16(fs_high2lowgid(gid)); raw_inode->i_uid_high = 0; raw_inode->i_gid_high = 0; } +#ifdef CONFIG_INOXID_INTERN + raw_inode->i_raw_xid = cpu_to_le16(inode->i_xid); +#endif raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); raw_inode->i_size = cpu_to_le32(ei->i_disksize); raw_inode->i_atime = cpu_to_le32(inode->i_atime.tv_sec); @@ -2911,7 +2982,8 @@ int ext3_setattr(struct dentry *dentry, return error; if ((ia_valid & ATTR_UID && attr->ia_uid != inode->i_uid) || - (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid)) { + (ia_valid & ATTR_GID && attr->ia_gid != inode->i_gid) || + (ia_valid & ATTR_XID && attr->ia_xid != inode->i_xid)) { handle_t *handle; /* (user+group)*(old+new) structure, inode write (sb, @@ -2933,6 +3005,8 @@ int ext3_setattr(struct dentry *dentry, inode->i_uid = attr->ia_uid; if (attr->ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; + if ((attr->ia_valid & ATTR_XID) && IS_TAGXID(inode)) + inode->i_xid = attr->ia_xid; error = ext3_mark_inode_dirty(handle, inode); ext3_journal_stop(handle); } diff -NurpP --minimal linux-2.6.17.11/fs/ext3/ioctl.c linux-2.6.17.11-g-v/fs/ext3/ioctl.c --- linux-2.6.17.11/fs/ext3/ioctl.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/ioctl.c 2006-08-28 14:56:36.000000000 +0200 @@ -8,11 +8,13 @@ */ #include +#include #include #include #include #include #include +#include #include @@ -36,7 +38,8 @@ int ext3_ioctl (struct inode * inode, st unsigned int oldflags; unsigned int jflag; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) @@ -60,7 +63,9 @@ int ext3_ioctl (struct inode * inode, st * * This test looks nicer. Thanks to Pauline Middelink */ - if ((flags ^ oldflags) & (EXT3_APPEND_FL | EXT3_IMMUTABLE_FL)) { + if ((oldflags & EXT3_IMMUTABLE_FL) || + ((flags ^ oldflags) & (EXT3_APPEND_FL | + EXT3_IMMUTABLE_FL | EXT3_IUNLINK_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) { mutex_unlock(&inode->i_mutex); return -EPERM; @@ -122,7 +127,8 @@ flags_err: if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (get_user(generation, (int __user *) arg)) return -EFAULT; @@ -176,7 +182,8 @@ flags_err: if (!test_opt(inode->i_sb, RESERVATION) ||!S_ISREG(inode->i_mode)) return -ENOTTY; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) @@ -211,7 +218,8 @@ flags_err: if (!capable(CAP_SYS_RESOURCE)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (get_user(n_blocks_count, (__u32 __user *)arg)) @@ -232,7 +240,8 @@ flags_err: if (!capable(CAP_SYS_RESOURCE)) return -EPERM; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if (copy_from_user(&input, (struct ext3_new_group_input __user *)arg, @@ -247,6 +256,38 @@ flags_err: return err; } +#if defined(CONFIG_VSERVER_LEGACY) && !defined(CONFIG_INOXID_NONE) + case EXT3_IOC_SETXID: { + handle_t *handle; + struct ext3_iloc iloc; + int xid; + int err; + + /* fixme: if stealth, return -ENOTTY */ + if (!capable(CAP_CONTEXT)) + return -EPERM; + if (IS_RDONLY(inode)) + return -EROFS; + if (!(inode->i_sb->s_flags & MS_TAGXID)) + return -ENOSYS; + if (get_user(xid, (int __user *) arg)) + return -EFAULT; + + handle = ext3_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + err = ext3_reserve_inode_write(handle, inode, &iloc); + if (err) + return err; + + inode->i_xid = (xid & 0xFFFF); + inode->i_ctime = CURRENT_TIME; + + err = ext3_mark_iloc_dirty(handle, inode, &iloc); + ext3_journal_stop(handle); + return err; + } +#endif default: return -ENOTTY; diff -NurpP --minimal linux-2.6.17.11/fs/ext3/namei.c linux-2.6.17.11-g-v/fs/ext3/namei.c --- linux-2.6.17.11/fs/ext3/namei.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/namei.c 2006-08-28 14:56:36.000000000 +0200 @@ -36,6 +36,7 @@ #include #include #include +#include #include "namei.h" #include "xattr.h" @@ -1009,6 +1010,7 @@ static struct dentry *ext3_lookup(struct if (!inode) return ERR_PTR(-EACCES); + vx_propagate_xid(nd, inode); } return d_splice_alias(inode, dentry); } @@ -2384,6 +2386,7 @@ struct inode_operations ext3_dir_inode_o .removexattr = generic_removexattr, #endif .permission = ext3_permission, + .sync_flags = ext3_sync_flags, }; struct inode_operations ext3_special_inode_operations = { @@ -2395,4 +2398,5 @@ struct inode_operations ext3_special_ino .removexattr = generic_removexattr, #endif .permission = ext3_permission, + .sync_flags = ext3_sync_flags, }; diff -NurpP --minimal linux-2.6.17.11/fs/ext3/super.c linux-2.6.17.11-g-v/fs/ext3/super.c --- linux-2.6.17.11/fs/ext3/super.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/super.c 2006-08-28 14:56:36.000000000 +0200 @@ -675,7 +675,7 @@ enum { Opt_usrjquota, Opt_grpjquota, Opt_offusrjquota, Opt_offgrpjquota, Opt_jqfmt_vfsold, Opt_jqfmt_vfsv0, Opt_quota, Opt_noquota, Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, - Opt_grpquota + Opt_grpquota, Opt_tagxid }; static match_table_t tokens = { @@ -724,6 +724,7 @@ static match_table_t tokens = { {Opt_quota, "quota"}, {Opt_usrquota, "usrquota"}, {Opt_barrier, "barrier=%u"}, + {Opt_tagxid, "tagxid"}, {Opt_err, NULL}, {Opt_resize, "resize"}, }; @@ -816,6 +817,11 @@ static int parse_options (char *options, case Opt_nouid32: set_opt (sbi->s_mount_opt, NO_UID32); break; +#ifndef CONFIG_INOXID_NONE + case Opt_tagxid: + set_opt (sbi->s_mount_opt, TAGXID); + break; +#endif case Opt_nocheck: clear_opt (sbi->s_mount_opt, CHECK); break; @@ -1470,6 +1476,9 @@ static int ext3_fill_super (struct super NULL, 0)) goto failed_mount; + if (EXT3_SB(sb)->s_mount_opt & EXT3_MOUNT_TAGXID) + sb->s_flags |= MS_TAGXID; + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); @@ -2273,6 +2282,12 @@ static int ext3_remount (struct super_bl if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) ext3_abort(sb, __FUNCTION__, "Abort forced by user"); + if ((sbi->s_mount_opt & EXT3_MOUNT_TAGXID) && + !(sb->s_flags & MS_TAGXID)) { + printk("EXT3-fs: %s: tagxid not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); diff -NurpP --minimal linux-2.6.17.11/fs/ext3/symlink.c linux-2.6.17.11-g-v/fs/ext3/symlink.c --- linux-2.6.17.11/fs/ext3/symlink.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/symlink.c 2006-08-28 14:56:36.000000000 +0200 @@ -40,6 +40,7 @@ struct inode_operations ext3_symlink_ino .listxattr = ext3_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext3_sync_flags, }; struct inode_operations ext3_fast_symlink_inode_operations = { @@ -51,4 +52,5 @@ struct inode_operations ext3_fast_symlin .listxattr = ext3_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext3_sync_flags, }; diff -NurpP --minimal linux-2.6.17.11/fs/ext3/xattr.c linux-2.6.17.11-g-v/fs/ext3/xattr.c --- linux-2.6.17.11/fs/ext3/xattr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ext3/xattr.c 2006-08-28 14:56:36.000000000 +0200 @@ -58,6 +58,7 @@ #include #include #include +#include #include "xattr.h" #include "acl.h" @@ -495,6 +496,7 @@ ext3_xattr_release_block(handle_t *handl ext3_journal_dirty_metadata(handle, bh); if (IS_SYNC(inode)) handle->h_sync = 1; + DLIMIT_FREE_BLOCK(inode, 1); DQUOT_FREE_BLOCK(inode, 1); unlock_buffer(bh); ea_bdebug(bh, "refcount now=%d; releasing", @@ -763,11 +765,14 @@ inserted: if (new_bh == bs->bh) ea_bdebug(new_bh, "keeping"); else { + error = -ENOSPC; + if (DLIMIT_ALLOC_BLOCK(inode, 1)) + goto cleanup; /* The old block is released after updating the inode. */ error = -EDQUOT; if (DQUOT_ALLOC_BLOCK(inode, 1)) - goto cleanup; + goto cleanup_dlimit; error = ext3_journal_get_write_access(handle, new_bh); if (error) @@ -843,6 +848,8 @@ cleanup: cleanup_dquot: DQUOT_FREE_BLOCK(inode, 1); +cleanup_dlimit: + DLIMIT_FREE_BLOCK(inode, 1); goto cleanup; bad_block: diff -NurpP --minimal linux-2.6.17.11/fs/fcntl.c linux-2.6.17.11-g-v/fs/fcntl.c --- linux-2.6.17.11/fs/fcntl.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/fcntl.c 2006-08-28 14:56:36.000000000 +0200 @@ -18,6 +18,8 @@ #include #include #include +#include +#include #include #include @@ -63,6 +65,7 @@ static int locate_fd(struct files_struct struct fdtable *fdt; error = -EINVAL; + gr_learn_resource(current, RLIMIT_NOFILE, orig_start, 0); if (orig_start >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) goto out; @@ -83,8 +86,11 @@ repeat: } error = -EMFILE; + gr_learn_resource(current, RLIMIT_NOFILE, newfd, 0); if (newfd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) goto out; + if (!vx_files_avail(1)) + goto out; error = expand_files(files, newfd); if (error < 0) @@ -125,6 +131,7 @@ static int dupfd(struct file *file, unsi FD_SET(fd, fdt->open_fds); FD_CLR(fd, fdt->close_on_exec); spin_unlock(&files->file_lock); + vx_openfd_inc(fd); fd_install(fd, file); } else { spin_unlock(&files->file_lock); @@ -141,6 +148,8 @@ asmlinkage long sys_dup2(unsigned int ol struct files_struct * files = current->files; struct fdtable *fdt; + gr_learn_resource(current, RLIMIT_NOFILE, newfd, 0); + spin_lock(&files->file_lock); if (!(file = fcheck(oldfd))) goto out_unlock; @@ -177,6 +186,9 @@ asmlinkage long sys_dup2(unsigned int ol if (tofree) filp_close(tofree, files); + else + vx_openfd_inc(newfd); /* fd was unused */ + err = newfd; out: return err; @@ -427,7 +439,8 @@ static inline int sigio_perm(struct task return (((fown->euid == 0) || (fown->euid == p->suid) || (fown->euid == p->uid) || (fown->uid == p->suid) || (fown->uid == p->uid)) && - !security_file_send_sigiotask(p, fown, sig)); + !security_file_send_sigiotask(p, fown, sig) && + !gr_check_protected_task(p) && !gr_pid_is_chrooted(p)); } static void send_sigio_to_task(struct task_struct *p, @@ -479,7 +492,7 @@ void send_sigio(struct fown_struct *fown read_lock(&tasklist_lock); if (pid > 0) { - p = find_task_by_pid(pid); + p = find_task_by_real_pid(pid); if (p) { send_sigio_to_task(p, fown, fd, band); } @@ -514,7 +527,7 @@ int send_sigurg(struct fown_struct *fown read_lock(&tasklist_lock); if (pid > 0) { - p = find_task_by_pid(pid); + p = find_task_by_real_pid(pid); if (p) { send_sigurg_to_task(p, fown); } diff -NurpP --minimal linux-2.6.17.11/fs/file_table.c linux-2.6.17.11-g-v/fs/file_table.c --- linux-2.6.17.11/fs/file_table.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/file_table.c 2006-08-28 14:56:36.000000000 +0200 @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include @@ -121,6 +123,8 @@ struct file *get_empty_filp(void) f->f_gid = tsk->fsgid; eventpoll_init_file(f); /* f->f_version: 0 */ + f->f_xid = vx_current_xid(); + vx_files_inc(f); return f; over: @@ -175,6 +179,8 @@ void fastcall __fput(struct file *file) fops_put(file->f_op); if (file->f_mode & FMODE_WRITE) put_write_access(inode); + vx_files_dec(file); + file->f_xid = 0; file_kill(file); file->f_dentry = NULL; file->f_vfsmnt = NULL; @@ -240,6 +246,8 @@ void put_filp(struct file *file) { if (atomic_dec_and_test(&file->f_count)) { security_file_free(file); + vx_files_dec(file); + file->f_xid = 0; file_kill(file); file_free(file); } diff -NurpP --minimal linux-2.6.17.11/fs/hfsplus/ioctl.c linux-2.6.17.11-g-v/fs/hfsplus/ioctl.c --- linux-2.6.17.11/fs/hfsplus/ioctl.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/hfsplus/ioctl.c 2006-08-28 14:56:36.000000000 +0200 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include "hfsplus_fs.h" @@ -35,7 +36,8 @@ int hfsplus_ioctl(struct inode *inode, s flags |= EXT2_FLAG_NODUMP; /* EXT2_NODUMP_FL */ return put_user(flags, (int __user *)arg); case HFSPLUS_IOC_EXT2_SETFLAGS: { - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) diff -NurpP --minimal linux-2.6.17.11/fs/inode.c linux-2.6.17.11-g-v/fs/inode.c --- linux-2.6.17.11/fs/inode.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/inode.c 2006-08-28 14:56:36.000000000 +0200 @@ -116,6 +116,9 @@ static struct inode *alloc_inode(struct struct address_space * const mapping = &inode->i_data; inode->i_sb = sb; + + /* essential because of inode slab reuse */ + inode->i_xid = 0; inode->i_blkbits = sb->s_blocksize_bits; inode->i_flags = 0; atomic_set(&inode->i_count, 1); @@ -235,6 +238,8 @@ void __iget(struct inode * inode) inodes_stat.nr_unused--; } +EXPORT_SYMBOL_GPL(__iget); + /** * clear_inode - clear an inode * @inode: inode to clear diff -NurpP --minimal linux-2.6.17.11/fs/ioctl.c linux-2.6.17.11-g-v/fs/ioctl.c --- linux-2.6.17.11/fs/ioctl.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ioctl.c 2006-08-28 14:56:36.000000000 +0200 @@ -13,10 +13,19 @@ #include #include #include +#include +#include +#include #include #include + +#ifdef CONFIG_VSERVER_LEGACY +extern int vx_proc_ioctl(struct inode *, struct file *, + unsigned int, unsigned long); +#endif + static long do_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { @@ -147,6 +156,48 @@ int vfs_ioctl(struct file *filp, unsigne else error = -ENOTTY; break; +#ifdef CONFIG_VSERVER_LEGACY +#ifndef CONFIG_INOXID_NONE + case FIOC_GETXID: { + struct inode *inode = filp->f_dentry->d_inode; + + /* fixme: if stealth, return -ENOTTY */ + error = -EPERM; + if (capable(CAP_CONTEXT)) + error = put_user(inode->i_xid, (int __user *) arg); + break; + } + case FIOC_SETXID: { + struct inode *inode = filp->f_dentry->d_inode; + int xid; + + /* fixme: if stealth, return -ENOTTY */ + error = -EPERM; + if (!capable(CAP_CONTEXT)) + break; + error = -EROFS; + if (IS_RDONLY(inode)) + break; + error = -ENOSYS; + if (!(inode->i_sb->s_flags & MS_TAGXID)) + break; + error = -EFAULT; + if (get_user(xid, (int __user *) arg)) + break; + error = 0; + inode->i_xid = (xid & 0xFFFF); + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + break; + } +#endif + case FIOC_GETXFLG: + case FIOC_SETXFLG: + error = -ENOTTY; + if (filp->f_dentry->d_inode->i_sb->s_magic == PROC_SUPER_MAGIC) + error = vx_proc_ioctl(filp->f_dentry->d_inode, filp, cmd, arg); + break; +#endif default: if (S_ISREG(filp->f_dentry->d_inode->i_mode)) error = file_ioctl(filp, cmd, arg); diff -NurpP --minimal linux-2.6.17.11/fs/ioprio.c linux-2.6.17.11-g-v/fs/ioprio.c --- linux-2.6.17.11/fs/ioprio.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/ioprio.c 2006-08-28 14:56:36.000000000 +0200 @@ -24,6 +24,7 @@ #include #include #include +#include static int set_task_ioprio(struct task_struct *task, int ioprio) { @@ -95,7 +96,7 @@ asmlinkage long sys_ioprio_set(int which if (!who) user = current->user; else - user = find_user(who); + user = find_user(vx_current_xid(), who); if (!user) break; @@ -149,7 +150,7 @@ asmlinkage long sys_ioprio_get(int which if (!who) user = current->user; else - user = find_user(who); + user = find_user(vx_current_xid(), who); if (!user) break; diff -NurpP --minimal linux-2.6.17.11/fs/jfs/acl.c linux-2.6.17.11-g-v/fs/jfs/acl.c --- linux-2.6.17.11/fs/jfs/acl.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/acl.c 2006-08-28 14:56:36.000000000 +0200 @@ -232,7 +232,8 @@ int jfs_setattr(struct dentry *dentry, s return rc; if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || - (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { + (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) || + (iattr->ia_valid & ATTR_XID && iattr->ia_xid != inode->i_xid)) { if (DQUOT_TRANSFER(inode, iattr)) return -EDQUOT; } diff -NurpP --minimal linux-2.6.17.11/fs/jfs/file.c linux-2.6.17.11-g-v/fs/jfs/file.c --- linux-2.6.17.11/fs/jfs/file.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/file.c 2006-08-28 14:56:36.000000000 +0200 @@ -98,6 +98,7 @@ struct inode_operations jfs_file_inode_o .setattr = jfs_setattr, .permission = jfs_permission, #endif + .sync_flags = jfs_sync_flags, }; const struct file_operations jfs_file_operations = { diff -NurpP --minimal linux-2.6.17.11/fs/jfs/inode.c linux-2.6.17.11-g-v/fs/jfs/inode.c --- linux-2.6.17.11/fs/jfs/inode.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/inode.c 2006-08-28 14:56:36.000000000 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_filsys.h" @@ -144,6 +145,7 @@ void jfs_delete_inode(struct inode *inod DQUOT_INIT(inode); DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); } clear_inode(inode); diff -NurpP --minimal linux-2.6.17.11/fs/jfs/ioctl.c linux-2.6.17.11-g-v/fs/jfs/ioctl.c --- linux-2.6.17.11/fs/jfs/ioctl.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/ioctl.c 2006-08-28 14:56:36.000000000 +0200 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -65,7 +66,8 @@ int jfs_ioctl(struct inode * inode, stru case JFS_IOC_SETFLAGS: { unsigned int oldflags; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || + (filp && MNT_IS_RDONLY(filp->f_vfsmnt))) return -EROFS; if ((current->fsuid != inode->i_uid) && !capable(CAP_FOWNER)) @@ -85,8 +87,8 @@ int jfs_ioctl(struct inode * inode, stru * the relevant capability. */ if ((oldflags & JFS_IMMUTABLE_FL) || - ((flags ^ oldflags) & - (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) { + ((flags ^ oldflags) & (JFS_APPEND_FL | + JFS_IMMUTABLE_FL | JFS_IUNLINK_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) return -EPERM; } diff -NurpP --minimal linux-2.6.17.11/fs/jfs/jfs_dinode.h linux-2.6.17.11-g-v/fs/jfs/jfs_dinode.h --- linux-2.6.17.11/fs/jfs/jfs_dinode.h 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/jfs_dinode.h 2006-08-28 16:03:19.000000000 +0200 @@ -162,9 +162,12 @@ struct dinode { #define JFS_APPEND_FL 0x01000000 /* writes to file may only append */ #define JFS_IMMUTABLE_FL 0x02000000 /* Immutable file */ -#define JFS_FL_USER_VISIBLE 0x03F80000 +#define JFS_BARRIER_FL 0x04000000 /* Barrier for chroot() */ +#define JFS_IUNLINK_FL 0x08000000 /* Immutable unlink */ + +#define JFS_FL_USER_VISIBLE 0x0FF80000 #define JFS_FL_USER_MODIFIABLE 0x03F80000 -#define JFS_FL_INHERIT 0x03C80000 +#define JFS_FL_INHERIT 0x0BC80000 /* These are identical to EXT[23]_IOC_GETFLAGS/SETFLAGS */ #define JFS_IOC_GETFLAGS _IOR('f', 1, long) diff -NurpP --minimal linux-2.6.17.11/fs/jfs/jfs_dtree.c linux-2.6.17.11-g-v/fs/jfs/jfs_dtree.c --- linux-2.6.17.11/fs/jfs/jfs_dtree.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/jfs_dtree.c 2006-08-28 16:03:19.000000000 +0200 @@ -102,6 +102,7 @@ #include #include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_filsys.h" @@ -383,10 +384,10 @@ static u32 add_index(tid_t tid, struct i */ if (DQUOT_ALLOC_BLOCK(ip, sbi->nbperpage)) goto clean_up; - if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr)) { - DQUOT_FREE_BLOCK(ip, sbi->nbperpage); - goto clean_up; - } + if (DLIMIT_ALLOC_BLOCK(ip, sbi->nbperpage)) + goto clean_up_quota; + if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr)) + goto clean_up_dlim; /* * Save the table, we're going to overwrite it with the @@ -479,6 +480,10 @@ static u32 add_index(tid_t tid, struct i return index; + clean_up_dlim: + DLIMIT_FREE_BLOCK(ip, sbi->nbperpage); + clean_up_quota: + DQUOT_FREE_BLOCK(ip, sbi->nbperpage); clean_up: jfs_ip->next_index--; @@ -952,6 +957,7 @@ static int dtSplitUp(tid_t tid, struct tlock *tlck; struct lv *lv; int quota_allocation = 0; + int dlimit_allocation = 0; /* get split page */ smp = split->mp; @@ -1036,6 +1042,12 @@ static int dtSplitUp(tid_t tid, } quota_allocation += n; + if (DLIMIT_ALLOC_BLOCK(ip, n)) { + rc = -ENOSPC; + goto extendOut; + } + dlimit_allocation += n; + if ((rc = dbReAlloc(sbi->ipbmap, xaddr, (s64) xlen, (s64) n, &nxaddr))) goto extendOut; @@ -1309,6 +1321,9 @@ static int dtSplitUp(tid_t tid, freeKeyName: kfree(key.name); + /* Rollback dlimit allocation */ + if (rc && dlimit_allocation) + DLIMIT_FREE_BLOCK(ip, dlimit_allocation); /* Rollback quota allocation */ if (rc && quota_allocation) DQUOT_FREE_BLOCK(ip, quota_allocation); @@ -1376,6 +1391,12 @@ static int dtSplitPage(tid_t tid, struct release_metapage(rmp); return -EDQUOT; } + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + DQUOT_FREE_BLOCK(ip, lengthPXD(pxd)); + release_metapage(rmp); + return -ENOSPC; + } jfs_info("dtSplitPage: ip:0x%p smp:0x%p rmp:0x%p", ip, smp, rmp); @@ -1926,6 +1947,12 @@ static int dtSplitRoot(tid_t tid, release_metapage(rmp); return -EDQUOT; } + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + DQUOT_FREE_BLOCK(ip, lengthPXD(pxd)); + release_metapage(rmp); + return -ENOSPC; + } BT_MARK_DIRTY(rmp, ip); /* @@ -2292,6 +2319,8 @@ static int dtDeleteUp(tid_t tid, struct xlen = lengthPXD(&fp->header.self); + /* Free dlimit allocation. */ + DLIMIT_FREE_BLOCK(ip, xlen); /* Free quota allocation. */ DQUOT_FREE_BLOCK(ip, xlen); @@ -2368,6 +2397,8 @@ static int dtDeleteUp(tid_t tid, struct xlen = lengthPXD(&p->header.self); + /* Free dlimit allocation */ + DLIMIT_FREE_BLOCK(ip, xlen); /* Free quota allocation */ DQUOT_FREE_BLOCK(ip, xlen); diff -NurpP --minimal linux-2.6.17.11/fs/jfs/jfs_extent.c linux-2.6.17.11-g-v/fs/jfs/jfs_extent.c --- linux-2.6.17.11/fs/jfs/jfs_extent.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/jfs_extent.c 2006-08-28 14:56:36.000000000 +0200 @@ -18,6 +18,7 @@ #include #include +#include #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_superblock.h" @@ -146,6 +147,13 @@ extAlloc(struct inode *ip, s64 xlen, s64 mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; } + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, nxlen)) { + DQUOT_FREE_BLOCK(ip, nxlen); + dbFree(ip, nxaddr, (s64) nxlen); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + return -ENOSPC; + } /* determine the value of the extent flag */ xflag = (abnr == TRUE) ? XAD_NOTRECORDED : 0; @@ -164,6 +172,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 */ if (rc) { dbFree(ip, nxaddr, nxlen); + DLIMIT_FREE_BLOCK(ip, nxlen); DQUOT_FREE_BLOCK(ip, nxlen); mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); @@ -261,6 +270,13 @@ int extRealloc(struct inode *ip, s64 nxl mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; } + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, nxlen)) { + DQUOT_FREE_BLOCK(ip, nxlen); + dbFree(ip, nxaddr, (s64) nxlen); + up(&JFS_IP(ip)->commit_sem); + return -ENOSPC; + } delta = nxlen - xlen; @@ -297,6 +313,7 @@ int extRealloc(struct inode *ip, s64 nxl /* extend the extent */ if ((rc = xtExtend(0, ip, xoff + xlen, (int) nextend, 0))) { dbFree(ip, xaddr + xlen, delta); + DLIMIT_FREE_BLOCK(ip, nxlen); DQUOT_FREE_BLOCK(ip, nxlen); goto exit; } @@ -308,6 +325,7 @@ int extRealloc(struct inode *ip, s64 nxl */ if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) { dbFree(ip, nxaddr, nxlen); + DLIMIT_FREE_BLOCK(ip, nxlen); DQUOT_FREE_BLOCK(ip, nxlen); goto exit; } diff -NurpP --minimal linux-2.6.17.11/fs/jfs/jfs_filsys.h linux-2.6.17.11-g-v/fs/jfs/jfs_filsys.h --- linux-2.6.17.11/fs/jfs/jfs_filsys.h 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/jfs_filsys.h 2006-08-28 14:56:36.000000000 +0200 @@ -84,6 +84,7 @@ #define JFS_DIR_INDEX 0x00200000 /* Persistant index for */ /* directory entries */ +#define JFS_TAGXID 0x00800000 /* xid tagging */ /* * buffer cache configuration diff -NurpP --minimal linux-2.6.17.11/fs/jfs/jfs_imap.c linux-2.6.17.11-g-v/fs/jfs/jfs_imap.c --- linux-2.6.17.11/fs/jfs/jfs_imap.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/jfs_imap.c 2006-08-28 14:56:36.000000000 +0200 @@ -45,6 +45,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_inode.h" @@ -3075,6 +3076,8 @@ static int copy_from_dinode(struct dinod { struct jfs_inode_info *jfs_ip = JFS_IP(ip); struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + uid_t uid; + gid_t gid; jfs_ip->fileset = le32_to_cpu(dip->di_fileset); jfs_ip->mode2 = le32_to_cpu(dip->di_mode); @@ -3094,14 +3097,18 @@ static int copy_from_dinode(struct dinod } ip->i_nlink = le32_to_cpu(dip->di_nlink); - jfs_ip->saved_uid = le32_to_cpu(dip->di_uid); + uid = le32_to_cpu(dip->di_uid); + gid = le32_to_cpu(dip->di_gid); + ip->i_xid = INOXID_XID(XID_TAG(ip), uid, gid, 0); + + jfs_ip->saved_uid = INOXID_UID(XID_TAG(ip), uid, gid); if (sbi->uid == -1) ip->i_uid = jfs_ip->saved_uid; else { ip->i_uid = sbi->uid; } - jfs_ip->saved_gid = le32_to_cpu(dip->di_gid); + jfs_ip->saved_gid = INOXID_GID(XID_TAG(ip), uid, gid); if (sbi->gid == -1) ip->i_gid = jfs_ip->saved_gid; else { @@ -3167,14 +3174,12 @@ static void copy_to_dinode(struct dinode dip->di_size = cpu_to_le64(ip->i_size); dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks)); dip->di_nlink = cpu_to_le32(ip->i_nlink); - if (sbi->uid == -1) - dip->di_uid = cpu_to_le32(ip->i_uid); - else - dip->di_uid = cpu_to_le32(jfs_ip->saved_uid); - if (sbi->gid == -1) - dip->di_gid = cpu_to_le32(ip->i_gid); - else - dip->di_gid = cpu_to_le32(jfs_ip->saved_gid); + + dip->di_uid = cpu_to_le32(XIDINO_UID(XID_TAG(ip), + (sbi->uid == -1) ? ip->i_uid : jfs_ip->saved_uid, ip->i_xid)); + dip->di_gid = cpu_to_le32(XIDINO_GID(XID_TAG(ip), + (sbi->gid == -1) ? ip->i_gid : jfs_ip->saved_gid, ip->i_xid)); + /* * mode2 is only needed for storing the higher order bits. * Trust i_mode for the lower order ones diff -NurpP --minimal linux-2.6.17.11/fs/jfs/jfs_inode.c linux-2.6.17.11-g-v/fs/jfs/jfs_inode.c --- linux-2.6.17.11/fs/jfs/jfs_inode.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/jfs_inode.c 2006-08-28 14:56:36.000000000 +0200 @@ -18,6 +18,8 @@ #include #include +#include +#include #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_filsys.h" @@ -30,19 +32,59 @@ void jfs_set_inode_flags(struct inode *i { unsigned int flags = JFS_IP(inode)->mode2; - inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | - S_NOATIME | S_DIRSYNC | S_SYNC); + inode->i_flags &= ~(S_IMMUTABLE | S_IUNLINK | S_BARRIER | + S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); if (flags & JFS_IMMUTABLE_FL) inode->i_flags |= S_IMMUTABLE; + if (flags & JFS_IUNLINK_FL) + inode->i_flags |= S_IUNLINK; + if (flags & JFS_BARRIER_FL) + inode->i_flags |= S_BARRIER; + + if (flags & JFS_SYNC_FL) + inode->i_flags |= S_SYNC; if (flags & JFS_APPEND_FL) inode->i_flags |= S_APPEND; if (flags & JFS_NOATIME_FL) inode->i_flags |= S_NOATIME; if (flags & JFS_DIRSYNC_FL) inode->i_flags |= S_DIRSYNC; - if (flags & JFS_SYNC_FL) - inode->i_flags |= S_SYNC; +} + +int jfs_sync_flags(struct inode *inode) +{ + unsigned int oldflags, newflags; + + oldflags = JFS_IP(inode)->mode2; + newflags = oldflags & ~(JFS_APPEND_FL | + JFS_IMMUTABLE_FL | JFS_IUNLINK_FL | + JFS_BARRIER_FL | JFS_NOATIME_FL | + JFS_SYNC_FL | JFS_DIRSYNC_FL); + + if (IS_APPEND(inode)) + newflags |= JFS_APPEND_FL; + if (IS_IMMUTABLE(inode)) + newflags |= JFS_IMMUTABLE_FL; + if (IS_IUNLINK(inode)) + newflags |= JFS_IUNLINK_FL; + if (IS_BARRIER(inode)) + newflags |= JFS_BARRIER_FL; + + /* we do not want to copy superblock flags */ + if (inode->i_flags & S_NOATIME) + newflags |= JFS_NOATIME_FL; + if (inode->i_flags & S_SYNC) + newflags |= JFS_SYNC_FL; + if (inode->i_flags & S_DIRSYNC) + newflags |= JFS_DIRSYNC_FL; + + if (oldflags ^ newflags) { + JFS_IP(inode)->mode2 = newflags; + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + } + return 0; } /* @@ -89,10 +131,17 @@ struct inode *ialloc(struct inode *paren jfs_inode->saved_uid = inode->i_uid; jfs_inode->saved_gid = inode->i_gid; + inode->i_xid = vx_current_fsxid(sb); + if (DLIMIT_ALLOC_INODE(inode)) { + iput(inode); + return NULL; + } + /* * Allocate inode to quota. */ if (DQUOT_ALLOC_INODE(inode)) { + DLIMIT_FREE_INODE(inode); DQUOT_DROP(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; diff -NurpP --minimal linux-2.6.17.11/fs/jfs/jfs_inode.h linux-2.6.17.11-g-v/fs/jfs/jfs_inode.h --- linux-2.6.17.11/fs/jfs/jfs_inode.h 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/jfs_inode.h 2006-08-28 14:56:36.000000000 +0200 @@ -31,6 +31,7 @@ extern void jfs_truncate(struct inode *) extern void jfs_truncate_nolock(struct inode *, loff_t); extern void jfs_free_zero_link(struct inode *); extern struct dentry *jfs_get_parent(struct dentry *dentry); +extern int jfs_sync_flags(struct inode *); extern void jfs_set_inode_flags(struct inode *); extern struct address_space_operations jfs_aops; diff -NurpP --minimal linux-2.6.17.11/fs/jfs/jfs_xtree.c linux-2.6.17.11-g-v/fs/jfs/jfs_xtree.c --- linux-2.6.17.11/fs/jfs/jfs_xtree.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/jfs_xtree.c 2006-08-28 16:03:19.000000000 +0200 @@ -21,6 +21,7 @@ #include #include +#include #include "jfs_incore.h" #include "jfs_filsys.h" #include "jfs_metapage.h" @@ -841,7 +842,12 @@ int xtInsert(tid_t tid, /* transaction hint = 0; if ((rc = DQUOT_ALLOC_BLOCK(ip, xlen))) goto out; + if ((rc = DLIMIT_ALLOC_BLOCK(ip, xlen))) { + DQUOT_FREE_BLOCK(ip, xlen); + goto out; + } if ((rc = dbAlloc(ip, hint, (s64) xlen, &xaddr))) { + DLIMIT_FREE_BLOCK(ip, xlen); DQUOT_FREE_BLOCK(ip, xlen); goto out; } @@ -871,6 +877,7 @@ int xtInsert(tid_t tid, /* transaction /* undo data extent allocation */ if (*xaddrp == 0) { dbFree(ip, xaddr, (s64) xlen); + DLIMIT_FREE_BLOCK(ip, xlen); DQUOT_FREE_BLOCK(ip, xlen); } return rc; @@ -1231,6 +1238,7 @@ xtSplitPage(tid_t tid, struct inode *ip, struct tlock *tlck; struct xtlock *sxtlck = NULL, *rxtlck = NULL; int quota_allocation = 0; + int dlimit_allocation = 0; smp = split->mp; sp = XT_PAGE(ip, smp); @@ -1250,6 +1258,13 @@ xtSplitPage(tid_t tid, struct inode *ip, quota_allocation += lengthPXD(pxd); + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + rc = -ENOSPC; + goto clean_up; + } + dlimit_allocation += lengthPXD(pxd); + /* * allocate the new right page for the split */ @@ -1451,6 +1466,9 @@ xtSplitPage(tid_t tid, struct inode *ip, clean_up: + /* Rollback dlimit allocation. */ + if (dlimit_allocation) + DLIMIT_FREE_BLOCK(ip, dlimit_allocation); /* Rollback quota allocation. */ if (quota_allocation) DQUOT_FREE_BLOCK(ip, quota_allocation); @@ -1515,6 +1533,12 @@ xtSplitRoot(tid_t tid, release_metapage(rmp); return -EDQUOT; } + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + DQUOT_FREE_BLOCK(ip, lengthPXD(pxd)); + release_metapage(rmp); + return -ENOSPC; + } jfs_info("xtSplitRoot: ip:0x%p rmp:0x%p", ip, rmp); @@ -3941,6 +3965,8 @@ s64 xtTruncate(tid_t tid, struct inode * else ip->i_size = newsize; + /* update dlimit allocation to reflect freed blocks */ + DLIMIT_FREE_BLOCK(ip, nfreed); /* update quota allocation to reflect freed blocks */ DQUOT_FREE_BLOCK(ip, nfreed); diff -NurpP --minimal linux-2.6.17.11/fs/jfs/namei.c linux-2.6.17.11-g-v/fs/jfs/namei.c --- linux-2.6.17.11/fs/jfs/namei.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/namei.c 2006-08-28 14:56:36.000000000 +0200 @@ -20,6 +20,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_inode.h" @@ -1465,6 +1466,7 @@ static struct dentry *jfs_lookup(struct return ERR_PTR(-EACCES); } + vx_propagate_xid(nd, ip); dentry = d_splice_alias(ip, dentry); if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)) @@ -1517,6 +1519,7 @@ struct inode_operations jfs_dir_inode_op .setattr = jfs_setattr, .permission = jfs_permission, #endif + .sync_flags = jfs_sync_flags, }; const struct file_operations jfs_dir_operations = { diff -NurpP --minimal linux-2.6.17.11/fs/jfs/super.c linux-2.6.17.11-g-v/fs/jfs/super.c --- linux-2.6.17.11/fs/jfs/super.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/super.c 2006-08-28 14:56:36.000000000 +0200 @@ -194,7 +194,8 @@ static void jfs_put_super(struct super_b enum { Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask + Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask, + Opt_tagxid }; static match_table_t tokens = { @@ -204,6 +205,7 @@ static match_table_t tokens = { {Opt_resize, "resize=%u"}, {Opt_resize_nosize, "resize"}, {Opt_errors, "errors=%s"}, + {Opt_tagxid, "tagxid"}, {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, {Opt_usrquota, "usrquota"}, @@ -338,6 +340,11 @@ static int parse_options(char *options, } break; } +#ifndef CONFIG_TAGGING_NONE + case Opt_tagxid: + *flag |= JFS_TAGXID; + break; +#endif default: printk("jfs: Unrecognized mount option \"%s\" " " or missing value\n", p); @@ -368,6 +375,13 @@ static int jfs_remount(struct super_bloc if (!parse_options(data, sb, &newLVSize, &flag)) { return -EINVAL; } + + if ((flag & JFS_TAGXID) && !(sb->s_flags & MS_TAGXID)) { + printk(KERN_ERR "JFS: %s: tagxid not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } + if (newLVSize) { if (sb->s_flags & MS_RDONLY) { printk(KERN_ERR @@ -439,6 +453,9 @@ static int jfs_fill_super(struct super_b #ifdef CONFIG_JFS_POSIX_ACL sb->s_flags |= MS_POSIXACL; #endif + /* map mount option tagxid */ + if (sbi->flag & JFS_TAGXID) + sb->s_flags |= MS_TAGXID; if (newLVSize) { printk(KERN_ERR "resize option for remount only\n"); diff -NurpP --minimal linux-2.6.17.11/fs/jfs/xattr.c linux-2.6.17.11-g-v/fs/jfs/xattr.c --- linux-2.6.17.11/fs/jfs/xattr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/jfs/xattr.c 2006-08-28 14:56:36.000000000 +0200 @@ -23,6 +23,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_dmap.h" @@ -263,9 +264,16 @@ static int ea_write(struct inode *ip, st if (DQUOT_ALLOC_BLOCK(ip, nblocks)) { return -EDQUOT; } + /* Allocate new blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, nblocks)) { + DQUOT_FREE_BLOCK(ip, nblocks); + return -ENOSPC; + } rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno); if (rc) { + /*Rollback dlimit allocation. */ + DLIMIT_FREE_BLOCK(ip, nblocks); /*Rollback quota allocation. */ DQUOT_FREE_BLOCK(ip, nblocks); return rc; @@ -332,6 +340,8 @@ static int ea_write(struct inode *ip, st failed: /* Rollback quota allocation. */ + DLIMIT_FREE_BLOCK(ip, nblocks); + /* Rollback quota allocation. */ DQUOT_FREE_BLOCK(ip, nblocks); dbFree(ip, blkno, nblocks); @@ -468,6 +478,7 @@ static int ea_get(struct inode *inode, s s64 blkno; int rc; int quota_allocation = 0; + int dlimit_allocation = 0; /* When fsck.jfs clears a bad ea, it doesn't clear the size */ if (ji->ea.flag == 0) @@ -543,6 +554,12 @@ static int ea_get(struct inode *inode, s quota_allocation = blocks_needed; + /* Allocate new blocks to dlimit. */ + rc = -ENOSPC; + if (DLIMIT_ALLOC_BLOCK(inode, blocks_needed)) + goto clean_up; + dlimit_allocation = blocks_needed; + rc = dbAlloc(inode, INOHINT(inode), (s64) blocks_needed, &blkno); if (rc) @@ -599,6 +616,9 @@ static int ea_get(struct inode *inode, s return ea_size; clean_up: + /* Rollback dlimit allocation */ + if (dlimit_allocation) + DLIMIT_FREE_BLOCK(inode, dlimit_allocation); /* Rollback quota allocation */ if (quota_allocation) DQUOT_FREE_BLOCK(inode, quota_allocation); @@ -675,8 +695,10 @@ static int ea_put(tid_t tid, struct inod } /* If old blocks exist, they must be removed from quota allocation. */ - if (old_blocks) + if (old_blocks) { + DLIMIT_FREE_BLOCK(inode, old_blocks); DQUOT_FREE_BLOCK(inode, old_blocks); + } inode->i_ctime = CURRENT_TIME; diff -NurpP --minimal linux-2.6.17.11/fs/libfs.c linux-2.6.17.11-g-v/fs/libfs.c --- linux-2.6.17.11/fs/libfs.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/libfs.c 2006-08-28 14:56:36.000000000 +0200 @@ -124,7 +124,8 @@ static inline unsigned char dt_type(stru * both impossible due to the lock on directory. */ -int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) +static inline int do_dcache_readdir_filter(struct file * filp, + void * dirent, filldir_t filldir, int (*filter)(struct dentry *dentry)) { struct dentry *dentry = filp->f_dentry; struct dentry *cursor = filp->private_data; @@ -158,6 +159,8 @@ int dcache_readdir(struct file * filp, v next = list_entry(p, struct dentry, d_u.d_child); if (d_unhashed(next) || !next->d_inode) continue; + if (filter && !filter(next)) + continue; spin_unlock(&dcache_lock); if (filldir(dirent, next->d_name.name, next->d_name.len, filp->f_pos, next->d_inode->i_ino, dt_type(next->d_inode)) < 0) @@ -174,6 +177,18 @@ int dcache_readdir(struct file * filp, v return 0; } +int dcache_readdir(struct file * filp, void * dirent, filldir_t filldir) +{ + return do_dcache_readdir_filter(filp, dirent, filldir, NULL); +} + +int dcache_readdir_filter(struct file * filp, void * dirent, filldir_t filldir, + int (*filter)(struct dentry *)) +{ + return do_dcache_readdir_filter(filp, dirent, filldir, filter); +} + + ssize_t generic_read_dir(struct file *filp, char __user *buf, size_t siz, loff_t *ppos) { return -EISDIR; @@ -623,6 +638,7 @@ EXPORT_SYMBOL(dcache_dir_close); EXPORT_SYMBOL(dcache_dir_lseek); EXPORT_SYMBOL(dcache_dir_open); EXPORT_SYMBOL(dcache_readdir); +EXPORT_SYMBOL(dcache_readdir_filter); EXPORT_SYMBOL(generic_read_dir); EXPORT_SYMBOL(get_sb_pseudo); EXPORT_SYMBOL(simple_commit_write); diff -NurpP --minimal linux-2.6.17.11/fs/lockd/clntproc.c linux-2.6.17.11-g-v/fs/lockd/clntproc.c --- linux-2.6.17.11/fs/lockd/clntproc.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/lockd/clntproc.c 2006-08-28 14:56:36.000000000 +0200 @@ -18,6 +18,7 @@ #include #include #include +#include #define NLMDBG_FACILITY NLMDBG_CLIENT #define NLMCLNT_GRACE_WAIT (5*HZ) @@ -130,11 +131,11 @@ static void nlmclnt_setlockargs(struct n nlmclnt_next_cookie(&argp->cookie); argp->state = nsm_local_state; memcpy(&lock->fh, NFS_FH(fl->fl_file->f_dentry->d_inode), sizeof(struct nfs_fh)); - lock->caller = system_utsname.nodename; + lock->caller = vx_new_uts(nodename); lock->oh.data = req->a_owner; lock->oh.len = snprintf(req->a_owner, sizeof(req->a_owner), "%u@%s", (unsigned int)fl->fl_u.nfs_fl.owner->pid, - system_utsname.nodename); + vx_new_uts(nodename)); lock->svid = fl->fl_u.nfs_fl.owner->pid; lock->fl.fl_start = fl->fl_start; lock->fl.fl_end = fl->fl_end; diff -NurpP --minimal linux-2.6.17.11/fs/locks.c linux-2.6.17.11-g-v/fs/locks.c --- linux-2.6.17.11/fs/locks.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/locks.c 2006-08-28 16:03:19.000000000 +0200 @@ -125,6 +125,7 @@ #include #include #include +#include #include #include @@ -147,6 +148,8 @@ static kmem_cache_t *filelock_cache __re /* Allocate an empty lock structure. */ static struct file_lock *locks_alloc_lock(void) { + if (!vx_locks_avail(1)) + return NULL; return kmem_cache_alloc(filelock_cache, SLAB_KERNEL); } @@ -172,6 +175,7 @@ static void locks_free_lock(struct file_ BUG_ON(!list_empty(&fl->fl_block)); BUG_ON(!list_empty(&fl->fl_link)); + vx_locks_dec(fl); locks_release_private(fl); kmem_cache_free(filelock_cache, fl); } @@ -191,6 +195,7 @@ void locks_init_lock(struct file_lock *f fl->fl_start = fl->fl_end = 0; fl->fl_ops = NULL; fl->fl_lmops = NULL; + fl->fl_xid = -1; } EXPORT_SYMBOL(locks_init_lock); @@ -248,6 +253,7 @@ void locks_copy_lock(struct file_lock *n new->fl_file = fl->fl_file; new->fl_ops = fl->fl_ops; new->fl_lmops = fl->fl_lmops; + new->fl_xid = fl->fl_xid; locks_copy_private(new, fl); } @@ -286,6 +292,9 @@ static int flock_make_lock(struct file * fl->fl_flags = FL_FLOCK; fl->fl_type = type; fl->fl_end = OFFSET_MAX; + + fl->fl_xid = filp->f_xid; + vx_locks_inc(fl); *lock = fl; return 0; @@ -451,6 +460,7 @@ static int lease_init(struct file *filp, fl->fl_owner = current->files; fl->fl_pid = current->tgid; + fl->fl_xid = vx_current_xid(); fl->fl_file = filp; fl->fl_flags = FL_LEASE; @@ -470,6 +480,8 @@ static int lease_alloc(struct file *filp if (fl == NULL) goto out; + fl->fl_xid = vx_current_xid(); + vx_locks_inc(fl); error = lease_init(filp, type, fl); if (error) { locks_free_lock(fl); @@ -780,6 +792,7 @@ static int flock_lock_file(struct file * goto out; } locks_copy_lock(new_fl, request); + vx_locks_inc(new_fl); locks_insert_lock(&inode->i_flock, new_fl); new_fl = NULL; error = 0; @@ -791,7 +804,8 @@ out: return error; } -static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, struct file_lock *conflock) +static int __posix_lock_file_conf(struct inode *inode, struct file_lock *request, + struct file_lock *conflock, xid_t xid) { struct file_lock *fl; struct file_lock *new_fl, *new_fl2; @@ -805,7 +819,11 @@ static int __posix_lock_file_conf(struct * so we get them in advance to avoid races. */ new_fl = locks_alloc_lock(); + new_fl->fl_xid = xid; + vx_locks_inc(new_fl); new_fl2 = locks_alloc_lock(); + new_fl2->fl_xid = xid; + vx_locks_inc(new_fl2); lock_kernel(); if (request->fl_type != F_UNLCK) { @@ -986,7 +1004,8 @@ static int __posix_lock_file_conf(struct */ int posix_lock_file(struct file *filp, struct file_lock *fl) { - return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, NULL); + return __posix_lock_file_conf(filp->f_dentry->d_inode, + fl, NULL, filp->f_xid); } EXPORT_SYMBOL(posix_lock_file); @@ -1001,7 +1020,8 @@ EXPORT_SYMBOL(posix_lock_file); int posix_lock_file_conf(struct file *filp, struct file_lock *fl, struct file_lock *conflock) { - return __posix_lock_file_conf(filp->f_dentry->d_inode, fl, conflock); + return __posix_lock_file_conf(filp->f_dentry->d_inode, + fl, conflock, filp->f_xid); } EXPORT_SYMBOL(posix_lock_file_conf); @@ -1091,7 +1111,7 @@ int locks_mandatory_area(int read_write, fl.fl_end = offset + count - 1; for (;;) { - error = __posix_lock_file_conf(inode, &fl, NULL); + error = __posix_lock_file_conf(inode, &fl, NULL, filp->f_xid); if (error != -EAGAIN) break; if (!(fl.fl_flags & FL_SLEEP)) @@ -1651,6 +1671,9 @@ int fcntl_setlk(unsigned int fd, struct if (file_lock == NULL) return -ENOLCK; + file_lock->fl_xid = filp->f_xid; + vx_locks_inc(file_lock); + /* * This might block, so we do it before checking the inode. */ @@ -1794,6 +1817,9 @@ int fcntl_setlk64(unsigned int fd, struc if (file_lock == NULL) return -ENOLCK; + file_lock->fl_xid = filp->f_xid; + vx_locks_inc(file_lock); + /* * This might block, so we do it before checking the inode. */ @@ -2104,6 +2130,10 @@ int get_locks_status(char *buffer, char list_for_each(tmp, &file_lock_list) { struct list_head *btmp; struct file_lock *fl = list_entry(tmp, struct file_lock, fl_link); + + if (!vx_check(fl->fl_xid, VX_IDENT|VX_WATCH)) + continue; + lock_get_status(q, fl, ++i, ""); move_lock_status(&q, &pos, offset); diff -NurpP --minimal linux-2.6.17.11/fs/namei.c linux-2.6.17.11-g-v/fs/namei.c --- linux-2.6.17.11/fs/namei.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/namei.c 2006-08-28 16:03:19.000000000 +0200 @@ -32,6 +32,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -225,6 +229,24 @@ int generic_permission(struct inode *ino return -EACCES; } +static inline int xid_permission(struct inode *inode, int mask, struct nameidata *nd) +{ + if (IS_BARRIER(inode) && !vx_check(0, VX_ADMIN)) { + vxwprintk(1, "xid=%d did hit the barrier.", + vx_current_xid()); + return -EACCES; + } + if (inode->i_xid == 0) + return 0; + if (vx_check(inode->i_xid, VX_ADMIN|VX_WATCH|VX_IDENT)) + return 0; + + vxwprintk(1, "xid=%d denied access to %p[#%d,%lu] »%s«.", + vx_current_xid(), inode, inode->i_xid, inode->i_ino, + vxd_cond_path(nd)); + return -EACCES; +} + int permission(struct inode *inode, int mask, struct nameidata *nd) { int retval, submask; @@ -235,7 +257,7 @@ int permission(struct inode *inode, int /* * Nobody gets write access to a read-only fs. */ - if (IS_RDONLY(inode) && + if ((IS_RDONLY(inode) || (nd && MNT_IS_RDONLY(nd->mnt))) && (S_ISREG(mode) || S_ISDIR(mode) || S_ISLNK(mode))) return -EROFS; @@ -249,6 +271,8 @@ int permission(struct inode *inode, int /* Ordinary permission routines do not understand MAY_APPEND. */ submask = mask & ~MAY_APPEND; + if ((retval = xid_permission(inode, mask, nd))) + return retval; if (inode->i_op && inode->i_op->permission) retval = inode->i_op->permission(inode, submask, nd); else @@ -611,6 +635,13 @@ static inline int do_follow_link(struct err = security_inode_follow_link(path->dentry, nd); if (err) goto loop; + + if (gr_handle_follow_link(path->dentry->d_parent->d_inode, + path->dentry->d_inode, path->dentry, nd->mnt)) { + err = -EACCES; + goto loop; + } + current->link_count++; current->total_link_count++; nd->depth++; @@ -705,7 +736,8 @@ static __always_inline void follow_dotdo if (nd->dentry == current->fs->root && nd->mnt == current->fs->rootmnt) { read_unlock(¤t->fs->lock); - break; + /* for sane '/' avoid follow_mount() */ + return; } read_unlock(¤t->fs->lock); spin_lock(&dcache_lock); @@ -742,16 +774,34 @@ static int do_lookup(struct nameidata *n { struct vfsmount *mnt = nd->mnt; struct dentry *dentry = __d_lookup(nd->dentry, name); + struct inode *inode; if (!dentry) goto need_lookup; if (dentry->d_op && dentry->d_op->d_revalidate) goto need_revalidate; + inode = dentry->d_inode; + if (!inode) + goto done; + if (!vx_check(inode->i_xid, VX_WATCH|VX_ADMIN|VX_HOSTID|VX_IDENT)) + goto hidden; + if (inode->i_sb->s_magic == PROC_SUPER_MAGIC) { + struct proc_dir_entry *de = PDE(inode); + + if (de && !vx_hide_check(0, de->vx_flags)) + goto hidden; + } done: path->mnt = mnt; path->dentry = dentry; __follow_mount(path); return 0; +hidden: + vxwprintk(1, "xid=%d did lookup hidden %p[#%d,%lu] »%s«.", + vx_current_xid(), inode, inode->i_xid, inode->i_ino, + vxd_path(dentry, mnt)); + dput(dentry); + return -ENOENT; need_lookup: dentry = real_lookup(nd->dentry, name, nd); @@ -954,11 +1004,18 @@ return_reval: break; } return_base: + if (!gr_acl_handle_hidden_file(nd->dentry, nd->mnt)) { + path_release(nd); + return -ENOENT; + } return 0; out_dput: dput_path(&next, nd); break; } + if (!gr_acl_handle_hidden_file(nd->dentry, nd->mnt)) + err = -ENOENT; + path_release(nd); return_err: return err; @@ -1349,7 +1406,8 @@ static inline int check_sticky(struct in * 10. We don't allow removal of NFS sillyrenamed files; it's handled by * nfs_async_unlink(). */ -static int may_delete(struct inode *dir,struct dentry *victim,int isdir) +static int may_delete(struct inode *dir, struct dentry *victim, + int isdir, struct nameidata *nd) { int error; @@ -1359,13 +1417,13 @@ static int may_delete(struct inode *dir, BUG_ON(victim->d_parent->d_inode != dir); audit_inode_child(victim->d_name.name, victim->d_inode, dir->i_ino); - error = permission(dir,MAY_WRITE | MAY_EXEC, NULL); + error = permission(dir,MAY_WRITE | MAY_EXEC, nd); if (error) return error; if (IS_APPEND(dir)) return -EPERM; if (check_sticky(dir, victim->d_inode)||IS_APPEND(victim->d_inode)|| - IS_IMMUTABLE(victim->d_inode)) + IS_IXORUNLINK(victim->d_inode)) return -EPERM; if (isdir) { if (!S_ISDIR(victim->d_inode->i_mode)) @@ -1512,7 +1570,8 @@ int may_open(struct nameidata *nd, int a return -EACCES; flag &= ~O_TRUNC; - } else if (IS_RDONLY(inode) && (flag & FMODE_WRITE)) + } else if ((IS_RDONLY(inode) || MNT_IS_RDONLY(nd->mnt)) + && (flag & FMODE_WRITE)) return -EROFS; /* * An append-only file must be opened in append mode for writing. @@ -1601,6 +1660,17 @@ int open_namei(int dfd, const char *path nd, flag); if (error) return error; + + if (gr_handle_rawio(nd->dentry->d_inode)) { + error = -EPERM; + goto exit; + } + + if (!gr_acl_handle_open(nd->dentry, nd->mnt, flag)) { + error = -EACCES; + goto exit; + } + goto ok; } @@ -1641,9 +1711,16 @@ do_last: /* Negative dentry, just create the file */ if (!path.dentry->d_inode) { + if (!gr_acl_handle_creat(path.dentry, nd->dentry, nd->mnt, flag, mode)) { + error = -EACCES; + mutex_unlock(&dir->d_inode->i_mutex); + goto exit_dput; + } if (!IS_POSIXACL(dir->d_inode)) mode &= ~current->fs->umask; error = vfs_create(dir->d_inode, path.dentry, mode, nd); + if (!error) + gr_handle_create(path.dentry, nd->mnt); mutex_unlock(&dir->d_inode->i_mutex); dput(nd->dentry); nd->dentry = path.dentry; @@ -1658,6 +1735,23 @@ do_last: /* * It already exists. */ + + if (gr_handle_rawio(path.dentry->d_inode)) { + mutex_unlock(&dir->d_inode->i_mutex); + error = -EPERM; + goto exit_dput; + } + if (!gr_acl_handle_open(path.dentry, nd->mnt, flag)) { + mutex_unlock(&dir->d_inode->i_mutex); + error = -EACCES; + goto exit_dput; + } + if (gr_handle_fifo(path.dentry, nd->mnt, dir, flag, acc_mode)) { + mutex_unlock(&dir->d_inode->i_mutex); + error = -EACCES; + goto exit_dput; + } + mutex_unlock(&dir->d_inode->i_mutex); error = -EEXIST; @@ -1711,6 +1805,13 @@ do_link: error = security_inode_follow_link(path.dentry, nd); if (error) goto exit_dput; + + if (gr_handle_follow_link(path.dentry->d_parent->d_inode, path.dentry->d_inode, + path.dentry, nd->mnt)) { + error = -EACCES; + goto exit_dput; + } + error = __do_follow_link(&path, nd); if (error) { /* Does someone understand code flow here? Or it is only @@ -1790,9 +1891,10 @@ fail: } EXPORT_SYMBOL_GPL(lookup_create); -int vfs_mknod(struct inode *dir, struct dentry *dentry, int mode, dev_t dev) +int vfs_mknod(struct inode *dir, struct dentry *dentry, + int mode, dev_t dev, struct nameidata *nd) { - int error = may_create(dir, dentry, NULL); + int error = may_create(dir, dentry, nd); if (error) return error; @@ -1837,16 +1939,33 @@ asmlinkage long sys_mknodat(int dfd, con if (!IS_POSIXACL(nd.dentry->d_inode)) mode &= ~current->fs->umask; if (!IS_ERR(dentry)) { + if (gr_handle_chroot_mknod(dentry, nd.mnt, mode)) { + error = -EPERM; + dput(dentry); + mutex_unlock(&nd.dentry->d_inode->i_mutex); + path_release(&nd); + goto out; + } + + if (!gr_acl_handle_mknod(dentry, nd.dentry, nd.mnt, mode)) { + error = -EACCES; + dput(dentry); + mutex_unlock(&nd.dentry->d_inode->i_mutex); + path_release(&nd); + goto out; + } + switch (mode & S_IFMT) { case 0: case S_IFREG: error = vfs_create(nd.dentry->d_inode,dentry,mode,&nd); break; case S_IFCHR: case S_IFBLK: - error = vfs_mknod(nd.dentry->d_inode,dentry,mode, - new_decode_dev(dev)); + error = vfs_mknod(nd.dentry->d_inode, dentry, mode, + new_decode_dev(dev), &nd); break; case S_IFIFO: case S_IFSOCK: - error = vfs_mknod(nd.dentry->d_inode,dentry,mode,0); + error = vfs_mknod(nd.dentry->d_inode, dentry, mode, + 0, &nd); break; case S_IFDIR: error = -EPERM; @@ -1854,6 +1973,10 @@ asmlinkage long sys_mknodat(int dfd, con default: error = -EINVAL; } + + if (!error) + gr_handle_create(dentry, nd.mnt); + dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -1869,9 +1992,10 @@ asmlinkage long sys_mknod(const char __u return sys_mknodat(AT_FDCWD, filename, mode, dev); } -int vfs_mkdir(struct inode *dir, struct dentry *dentry, int mode) +int vfs_mkdir(struct inode *dir, struct dentry *dentry, + int mode, struct nameidata *nd) { - int error = may_create(dir, dentry, NULL); + int error = may_create(dir, dentry, nd); if (error) return error; @@ -1908,9 +2032,19 @@ asmlinkage long sys_mkdirat(int dfd, con dentry = lookup_create(&nd, 1); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { + error = 0; if (!IS_POSIXACL(nd.dentry->d_inode)) mode &= ~current->fs->umask; - error = vfs_mkdir(nd.dentry->d_inode, dentry, mode); + + if (!gr_acl_handle_mkdir(dentry, nd.dentry, nd.mnt)) + error = -EACCES; + + if (!error) + error = vfs_mkdir(nd.dentry->d_inode, dentry, mode, &nd); + + if (!error) + gr_handle_create(dentry, nd.mnt); + dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -1955,9 +2089,10 @@ void dentry_unhash(struct dentry *dentry spin_unlock(&dcache_lock); } -int vfs_rmdir(struct inode *dir, struct dentry *dentry) +int vfs_rmdir(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) { - int error = may_delete(dir, dentry, 1); + int error = may_delete(dir, dentry, 1, nd); if (error) return error; @@ -1994,6 +2129,8 @@ static long do_rmdir(int dfd, const char char * name; struct dentry *dentry; struct nameidata nd; + ino_t saved_ino = 0; + dev_t saved_dev = 0; name = getname(pathname); if(IS_ERR(name)) @@ -2018,7 +2155,21 @@ static long do_rmdir(int dfd, const char dentry = lookup_hash(&nd); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_rmdir(nd.dentry->d_inode, dentry); + error = 0; + if (dentry->d_inode) { + if (dentry->d_inode->i_nlink <= 1) { + saved_ino = dentry->d_inode->i_ino; + saved_dev = dentry->d_inode->i_sb->s_dev; + } + + if (!gr_acl_handle_rmdir(dentry, nd.mnt)) + error = -EACCES; + } + + if (!error) + error = vfs_rmdir(nd.dentry->d_inode, dentry, &nd); + if (!error && (saved_dev || saved_ino)) + gr_handle_delete(saved_ino, saved_dev); dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -2034,9 +2185,10 @@ asmlinkage long sys_rmdir(const char __u return do_rmdir(AT_FDCWD, pathname); } -int vfs_unlink(struct inode *dir, struct dentry *dentry) +int vfs_unlink(struct inode *dir, struct dentry *dentry, + struct nameidata *nd) { - int error = may_delete(dir, dentry, 0); + int error = may_delete(dir, dentry, 0, nd); if (error) return error; @@ -2077,6 +2229,8 @@ static long do_unlinkat(int dfd, const c struct dentry *dentry; struct nameidata nd; struct inode *inode = NULL; + ino_t saved_ino = 0; + dev_t saved_dev = 0; name = getname(pathname); if(IS_ERR(name)) @@ -2092,13 +2246,26 @@ static long do_unlinkat(int dfd, const c dentry = lookup_hash(&nd); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { + error = 0; /* Why not before? Because we want correct error value */ if (nd.last.name[nd.last.len]) goto slashes; inode = dentry->d_inode; - if (inode) + if (inode) { + if (inode->i_nlink <= 1) { + saved_ino = inode->i_ino; + saved_dev = inode->i_sb->s_dev; + } + + if (!gr_acl_handle_unlink(dentry, nd.mnt)) + error = -EACCES; + atomic_inc(&inode->i_count); - error = vfs_unlink(nd.dentry->d_inode, dentry); + } + if (!error) + error = vfs_unlink(nd.dentry->d_inode, dentry, &nd); + if (!error && (saved_ino || saved_dev)) + gr_handle_delete(saved_ino, saved_dev); exit2: dput(dentry); } @@ -2133,9 +2300,10 @@ asmlinkage long sys_unlink(const char __ return do_unlinkat(AT_FDCWD, pathname); } -int vfs_symlink(struct inode *dir, struct dentry *dentry, const char *oldname, int mode) +int vfs_symlink(struct inode *dir, struct dentry *dentry, + const char *oldname, int mode, struct nameidata *nd) { - int error = may_create(dir, dentry, NULL); + int error = may_create(dir, dentry, nd); if (error) return error; @@ -2176,7 +2344,15 @@ asmlinkage long sys_symlinkat(const char dentry = lookup_create(&nd, 0); error = PTR_ERR(dentry); if (!IS_ERR(dentry)) { - error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO); + error = 0; + if (!gr_acl_handle_symlink(dentry, nd.dentry, nd.mnt, from)) + error = -EACCES; + + if (!error) + error = vfs_symlink(nd.dentry->d_inode, dentry, from, S_IALLUGO, &nd); + + if (!error) + gr_handle_create(dentry, nd.mnt); dput(dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -2193,7 +2369,8 @@ asmlinkage long sys_symlink(const char _ return sys_symlinkat(oldname, AT_FDCWD, newname); } -int vfs_link(struct dentry *old_dentry, struct inode *dir, struct dentry *new_dentry) +int vfs_link(struct dentry *old_dentry, struct inode *dir, + struct dentry *new_dentry, struct nameidata *nd) { struct inode *inode = old_dentry->d_inode; int error; @@ -2201,7 +2378,7 @@ int vfs_link(struct dentry *old_dentry, if (!inode) return -ENOENT; - error = may_create(dir, new_dentry, NULL); + error = may_create(dir, new_dentry, nd); if (error) return error; @@ -2211,7 +2388,7 @@ int vfs_link(struct dentry *old_dentry, /* * A link to an append-only or immutable file cannot be created. */ - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) return -EPERM; if (!dir->i_op || !dir->i_op->link) return -EPERM; @@ -2268,7 +2445,20 @@ asmlinkage long sys_linkat(int olddfd, c new_dentry = lookup_create(&nd, 0); error = PTR_ERR(new_dentry); if (!IS_ERR(new_dentry)) { - error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry); + error = 0; + if (gr_handle_hardlink(old_nd.dentry, old_nd.mnt, + old_nd.dentry->d_inode, + old_nd.dentry->d_inode->i_mode, to)) + error = -EPERM; + if (!gr_acl_handle_link(new_dentry, nd.dentry, nd.mnt, + old_nd.dentry, old_nd.mnt, to)) + error = -EACCES; + if (!error) + error = vfs_link(old_nd.dentry, nd.dentry->d_inode, new_dentry, &nd); + + if (!error) + gr_handle_create(new_dentry, nd.mnt); + dput(new_dentry); } mutex_unlock(&nd.dentry->d_inode->i_mutex); @@ -2400,14 +2590,14 @@ int vfs_rename(struct inode *old_dir, st if (old_dentry->d_inode == new_dentry->d_inode) return 0; - error = may_delete(old_dir, old_dentry, is_dir); + error = may_delete(old_dir, old_dentry, is_dir, NULL); if (error) return error; if (!new_dentry->d_inode) error = may_create(new_dir, new_dentry, NULL); else - error = may_delete(new_dir, new_dentry, is_dir); + error = may_delete(new_dir, new_dentry, is_dir, NULL); if (error) return error; @@ -2485,6 +2675,9 @@ static int do_rename(int olddfd, const c error = -EINVAL; if (old_dentry == trap) goto exit4; + error = -EROFS; + if (MNT_IS_RDONLY(newnd.mnt)) + goto exit4; new_dentry = lookup_hash(&newnd); error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) @@ -2494,8 +2687,16 @@ static int do_rename(int olddfd, const c if (new_dentry == trap) goto exit5; - error = vfs_rename(old_dir->d_inode, old_dentry, + error = gr_acl_handle_rename(new_dentry, newnd.dentry, newnd.mnt, + old_dentry, old_dir->d_inode, oldnd.mnt, + newname); + + if (!error) + error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); + if (!error) + gr_handle_rename(old_dir->d_inode, newnd.dentry->d_inode, old_dentry, + new_dentry, oldnd.mnt, new_dentry->d_inode ? 1 : 0); exit5: dput(new_dentry); exit4: diff -NurpP --minimal linux-2.6.17.11/fs/namespace.c linux-2.6.17.11-g-v/fs/namespace.c --- linux-2.6.17.11/fs/namespace.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/namespace.c 2006-09-04 14:26:43.000000000 +0200 @@ -23,6 +23,10 @@ #include #include #include +#include +#include +#include +#include #include #include #include "pnode.h" @@ -241,6 +245,7 @@ static struct vfsmount *clone_mnt(struct mnt->mnt_root = dget(root); mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; + mnt->mnt_xid = old->mnt_xid; if (flag & CL_SLAVE) { list_add(&mnt->mnt_slave, &old->mnt_slave_list); @@ -349,43 +354,85 @@ static inline void mangle(struct seq_fil seq_escape(m, s, " \t\n\\"); } +static int mnt_is_reachable(struct vfsmount *mnt) +{ + struct vfsmount *root_mnt; + struct dentry *root, *point; + int ret; + + if (mnt == mnt->mnt_namespace->root) + return 1; + + spin_lock(&dcache_lock); + root_mnt = current->fs->rootmnt; + root = current->fs->root; + point = root; + + while ((mnt != mnt->mnt_parent) && (mnt != root_mnt)) { + point = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + } + + ret = (mnt == root_mnt) && is_subdir(point, root); + + spin_unlock(&dcache_lock); + + return ret; +} + static int show_vfsmnt(struct seq_file *m, void *v) { struct vfsmount *mnt = v; int err = 0; static struct proc_fs_info { - int flag; - char *str; + int s_flag; + int mnt_flag; + char *set_str; + char *unset_str; } fs_info[] = { - { MS_SYNCHRONOUS, ",sync" }, - { MS_DIRSYNC, ",dirsync" }, - { MS_MANDLOCK, ",mand" }, - { 0, NULL } - }; - static struct proc_fs_info mnt_info[] = { - { MNT_NOSUID, ",nosuid" }, - { MNT_NODEV, ",nodev" }, - { MNT_NOEXEC, ",noexec" }, - { MNT_NOATIME, ",noatime" }, - { MNT_NODIRATIME, ",nodiratime" }, - { 0, NULL } + { MS_RDONLY, MNT_RDONLY, "ro", "rw" }, + { MS_SYNCHRONOUS, 0, ",sync", NULL }, + { MS_DIRSYNC, 0, ",dirsync", NULL }, + { MS_MANDLOCK, 0, ",mand", NULL }, + { MS_TAGXID, 0, ",tagxid", NULL }, + { MS_NOATIME, MNT_NOATIME, ",noatime", NULL }, + { MS_NODIRATIME, MNT_NODIRATIME, ",nodiratime", NULL }, + { 0, MNT_NOSUID, ",nosuid", NULL }, + { 0, MNT_NODEV, ",nodev", NULL }, + { 0, MNT_NOEXEC, ",noexec", NULL }, + { 0, 0, NULL, NULL } }; - struct proc_fs_info *fs_infop; + struct proc_fs_info *p; + unsigned long s_flags = mnt->mnt_sb->s_flags; + int mnt_flags = mnt->mnt_flags; - mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); - seq_putc(m, ' '); - seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); - seq_putc(m, ' '); - mangle(m, mnt->mnt_sb->s_type->name); - seq_puts(m, mnt->mnt_sb->s_flags & MS_RDONLY ? " ro" : " rw"); - for (fs_infop = fs_info; fs_infop->flag; fs_infop++) { - if (mnt->mnt_sb->s_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); + if (vx_flags(VXF_HIDE_MOUNT, 0)) + return 0; + if (!mnt_is_reachable(mnt)) + return 0; + + if (!vx_check(0, VX_ADMIN|VX_WATCH) && + mnt == current->fs->rootmnt) { + seq_puts(m, "/dev/root / "); + } else { + mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); + seq_putc(m, ' '); + seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); + seq_putc(m, ' '); } - for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { - if (mnt->mnt_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); + mangle(m, mnt->mnt_sb->s_type->name); + seq_putc(m, ' '); + for (p = fs_info; (p->s_flag | p->mnt_flag) ; p++) { + if ((s_flags & p->s_flag) || (mnt_flags & p->mnt_flag)) { + if (p->set_str) + seq_puts(m, p->set_str); + } else { + if (p->unset_str) + seq_puts(m, p->unset_str); + } } + if (mnt->mnt_flags & MNT_XID) + seq_printf(m, ",xid=%d", mnt->mnt_xid); if (mnt->mnt_sb->s_op->show_options) err = mnt->mnt_sb->s_op->show_options(m, mnt); seq_puts(m, " 0 0\n"); @@ -404,17 +451,27 @@ static int show_vfsstat(struct seq_file struct vfsmount *mnt = v; int err = 0; - /* device */ - if (mnt->mnt_devname) { - seq_puts(m, "device "); - mangle(m, mnt->mnt_devname); - } else - seq_puts(m, "no device"); + if (vx_flags(VXF_HIDE_MOUNT, 0)) + return 0; + if (!mnt_is_reachable(mnt) && !vx_check(0, VX_WATCH)) + return 0; - /* mount point */ - seq_puts(m, " mounted on "); - seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); - seq_putc(m, ' '); + if (!vx_check(0, VX_ADMIN|VX_WATCH) && + mnt == current->fs->rootmnt) { + seq_puts(m, "device /dev/root mounted on / "); + } else { + /* device */ + if (mnt->mnt_devname) { + seq_puts(m, "device "); + mangle(m, mnt->mnt_devname); + } else + seq_puts(m, "no device"); + + /* mount point */ + seq_puts(m, " mounted on "); + seq_path(m, mnt, mnt->mnt_root, " \t\n\\"); + seq_putc(m, ' '); + } /* file system type */ seq_puts(m, "with fstype "); @@ -600,6 +657,8 @@ static int do_umount(struct vfsmount *mn DQUOT_OFF(sb); retval = do_remount_sb(sb, MS_RDONLY, NULL, 0); unlock_kernel(); + + gr_log_remount(mnt->mnt_devname, retval); } up_write(&sb->s_umount); return retval; @@ -620,6 +679,9 @@ static int do_umount(struct vfsmount *mn security_sb_umount_busy(mnt); up_write(&namespace_sem); release_mounts(&umount_list); + + gr_log_unmount(mnt->mnt_devname, retval); + return retval; } @@ -646,7 +708,7 @@ asmlinkage long sys_umount(char __user * goto dput_and_out; retval = -EPERM; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) goto dput_and_out; retval = do_umount(nd.mnt, flags); @@ -670,7 +732,7 @@ asmlinkage long sys_oldumount(char __use static int mount_is_safe(struct nameidata *nd) { - if (capable(CAP_SYS_ADMIN)) + if (vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) return 0; return -EPERM; #ifdef notyet @@ -899,11 +961,13 @@ static int do_change_type(struct nameida /* * do loopback mount. */ -static int do_loopback(struct nameidata *nd, char *old_name, int recurse) +static int do_loopback(struct nameidata *nd, char *old_name, xid_t xid, + unsigned long flags, int mnt_flags) { struct nameidata old_nd; struct vfsmount *mnt = NULL; int err = mount_is_safe(nd); + int recurse = flags & MS_REC; if (err) return err; if (!old_name || !*old_name) @@ -929,6 +993,12 @@ static int do_loopback(struct nameidata if (!mnt) goto out; + mnt->mnt_flags = mnt_flags; + if (flags & MS_XID) { + mnt->mnt_xid = xid; + mnt->mnt_flags |= MNT_XID; + } + err = graft_tree(mnt, nd); if (err) { LIST_HEAD(umount_list); @@ -937,6 +1007,7 @@ static int do_loopback(struct nameidata spin_unlock(&vfsmount_lock); release_mounts(&umount_list); } + mnt->mnt_flags = mnt_flags; out: up_write(&namespace_sem); @@ -950,12 +1021,12 @@ out: * on it - tough luck. */ static int do_remount(struct nameidata *nd, int flags, int mnt_flags, - void *data) + void *data, xid_t xid) { int err; struct super_block *sb = nd->mnt->mnt_sb; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_REMOUNT)) return -EPERM; if (!check_mnt(nd->mnt)) @@ -989,7 +1060,7 @@ static int do_move_mount(struct nameidat struct nameidata old_nd, parent_nd; struct vfsmount *p; int err = 0; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) return -EPERM; if (!old_name || !*old_name) return -EINVAL; @@ -1069,7 +1140,7 @@ static int do_new_mount(struct nameidata return -EINVAL; /* we need capabilities... */ - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) return -EPERM; mnt = do_kern_mount(type, flags, name, data); @@ -1307,6 +1378,7 @@ long do_mount(char *dev_name, char *dir_ struct nameidata nd; int retval = 0; int mnt_flags = 0; + xid_t xid = 0; /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) @@ -1322,7 +1394,17 @@ long do_mount(char *dev_name, char *dir_ if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; + retval = vx_parse_xid(data_page, &xid, 1); + if (retval) { + mnt_flags |= MNT_XID; + /* bind and re-mounts get xid flag */ + if (flags & (MS_BIND|MS_REMOUNT)) + flags |= MS_XID; + } + /* Separate the per-mountpoint flags */ + if (flags & MS_RDONLY) + mnt_flags |= MNT_RDONLY; if (flags & MS_NOSUID) mnt_flags |= MNT_NOSUID; if (flags & MS_NODEV) @@ -1334,6 +1416,8 @@ long do_mount(char *dev_name, char *dir_ if (flags & MS_NODIRATIME) mnt_flags |= MNT_NODIRATIME; + if (!capable(CAP_SYS_ADMIN)) + mnt_flags |= MNT_NODEV; flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_NOATIME | MS_NODIRATIME); @@ -1346,11 +1430,16 @@ long do_mount(char *dev_name, char *dir_ if (retval) goto dput_out; + if (gr_handle_chroot_mount(nd.dentry, nd.mnt, dev_name)) { + retval = -EPERM; + goto dput_out; + } + if (flags & MS_REMOUNT) retval = do_remount(&nd, flags & ~MS_REMOUNT, mnt_flags, - data_page); + data_page, xid); else if (flags & MS_BIND) - retval = do_loopback(&nd, dev_name, flags & MS_REC); + retval = do_loopback(&nd, dev_name, xid, flags, mnt_flags); else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) retval = do_change_type(&nd, flags); else if (flags & MS_MOVE) @@ -1360,6 +1449,9 @@ long do_mount(char *dev_name, char *dir_ dev_name, data_page); dput_out: path_release(&nd); + + gr_log_mount(dev_name, dir_name, retval); + return retval; } @@ -1448,7 +1540,7 @@ int copy_namespace(int flags, struct tas if (!(flags & CLONE_NEWNS)) return 0; - if (!capable(CAP_SYS_ADMIN)) { + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) { err = -EPERM; goto out; } @@ -1612,6 +1704,9 @@ asmlinkage long sys_pivot_root(const cha if (!capable(CAP_SYS_ADMIN)) return -EPERM; + if (gr_handle_chroot_pivot()) + return -EPERM; + lock_kernel(); error = __user_walk(new_root, LOOKUP_FOLLOW | LOOKUP_DIRECTORY, diff -NurpP --minimal linux-2.6.17.11/fs/nfs/dir.c linux-2.6.17.11-g-v/fs/nfs/dir.c --- linux-2.6.17.11/fs/nfs/dir.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfs/dir.c 2006-08-28 14:56:36.000000000 +0200 @@ -28,9 +28,11 @@ #include #include #include +#include #include #include #include +#include #include "nfs4_fs.h" #include "delegation.h" @@ -904,6 +906,7 @@ static struct dentry *nfs_lookup(struct res = (struct dentry *)inode; if (IS_ERR(res)) goto out_unlock; + vx_propagate_xid(nd, inode); no_entry: res = d_add_unique(dentry, inode); if (res != NULL) @@ -937,7 +940,8 @@ static int is_atomic_open(struct inode * if (nd->flags & LOOKUP_DIRECTORY) return 0; /* Are we trying to write to a read only partition? */ - if (IS_RDONLY(dir) && (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE))) + if ((IS_RDONLY(dir) || MNT_IS_RDONLY(nd->mnt)) && + (nd->intent.open.flags & (O_CREAT|O_TRUNC|FMODE_WRITE))) return 0; return 1; } diff -NurpP --minimal linux-2.6.17.11/fs/nfs/inode.c linux-2.6.17.11-g-v/fs/nfs/inode.c --- linux-2.6.17.11/fs/nfs/inode.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfs/inode.c 2006-08-28 14:56:36.000000000 +0200 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -343,12 +344,16 @@ nfs_sb_init(struct super_block *sb, rpc_ } server->backing_dev_info.ra_pages = server->rpages * NFS_MAX_READAHEAD; + if (server->flags & NFS_MOUNT_TAGXID) + sb->s_flags |= MS_TAGXID; + sb->s_maxbytes = fsinfo.maxfilesize; if (sb->s_maxbytes > MAX_LFS_FILESIZE) sb->s_maxbytes = MAX_LFS_FILESIZE; server->client->cl_intr = (server->flags & NFS_MOUNT_INTR) ? 1 : 0; server->client->cl_softrtry = (server->flags & NFS_MOUNT_SOFT) ? 1 : 0; + server->client->cl_tagxid = (server->flags & NFS_MOUNT_TAGXID) ? 1 : 0; /* We're airborne Set socket buffersize */ rpc_setbufsize(server->client, server->wsize + 100, server->rsize + 100); @@ -423,6 +428,7 @@ nfs_create_client(struct nfs_server *ser clnt->cl_intr = 1; clnt->cl_softrtry = 1; + clnt->cl_tagxid = 1; return clnt; @@ -602,6 +608,7 @@ static void nfs_show_mount_options(struc { NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NONLM, ",nolock", "" }, { NFS_MOUNT_NOACL, ",noacl", "" }, + { NFS_MOUNT_TAGXID, ",tagxid", "" }, { 0, NULL, NULL } }; struct proc_nfs_info *nfs_infop; @@ -903,8 +910,10 @@ nfs_fhget(struct super_block *sb, struct nfsi->change_attr = fattr->change_attr; inode->i_size = nfs_size_to_loff_t(fattr->size); inode->i_nlink = fattr->nlink; - inode->i_uid = fattr->uid; - inode->i_gid = fattr->gid; + inode->i_uid = INOXID_UID(XID_TAG(inode), fattr->uid, fattr->gid); + inode->i_gid = INOXID_GID(XID_TAG(inode), fattr->uid, fattr->gid); + inode->i_xid = INOXID_XID(XID_TAG(inode), fattr->uid, fattr->gid, 0); + /* maybe fattr->xid someday */ if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) { /* * report the blocks in 512byte units @@ -995,6 +1004,8 @@ void nfs_setattr_update_inode(struct ino inode->i_uid = attr->ia_uid; if ((attr->ia_valid & ATTR_GID) != 0) inode->i_gid = attr->ia_gid; + if ((attr->ia_valid & ATTR_XID) && IS_TAGXID(inode)) + inode->i_xid = attr->ia_xid; spin_lock(&inode->i_lock); NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; spin_unlock(&inode->i_lock); @@ -1397,6 +1408,9 @@ static int nfs_check_inode_attributes(st struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_size, new_isize; int data_unstable; + uid_t uid; + gid_t gid; + xid_t xid; if ((fattr->valid & NFS_ATTR_FATTR) == 0) @@ -1434,10 +1448,15 @@ static int nfs_check_inode_attributes(st if (cur_size != new_isize && nfsi->npages == 0) nfsi->cache_validity |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; + uid = INOXID_UID(XID_TAG(inode), fattr->uid, fattr->gid); + gid = INOXID_GID(XID_TAG(inode), fattr->uid, fattr->gid); + xid = INOXID_XID(XID_TAG(inode), fattr->uid, fattr->gid, 0); + /* Have any file permissions changed? */ if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) - || inode->i_uid != fattr->uid - || inode->i_gid != fattr->gid) + || inode->i_uid != uid + || inode->i_gid != gid + || inode->i_xid != xid) nfsi->cache_validity |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; /* Has the link count changed? */ @@ -1522,6 +1541,9 @@ static int nfs_update_inode(struct inode loff_t cur_isize, new_isize; unsigned int invalid = 0; int data_stable; + uid_t uid; + gid_t gid; + xid_t xid; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", __FUNCTION__, inode->i_sb->s_id, inode->i_ino, @@ -1591,15 +1613,21 @@ static int nfs_update_inode(struct inode } memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); + uid = INOXID_UID(XID_TAG(inode), fattr->uid, fattr->gid); + gid = INOXID_GID(XID_TAG(inode), fattr->uid, fattr->gid); + xid = INOXID_XID(XID_TAG(inode), fattr->uid, fattr->gid, 0); + if ((inode->i_mode & S_IALLUGO) != (fattr->mode & S_IALLUGO) || - inode->i_uid != fattr->uid || - inode->i_gid != fattr->gid) + inode->i_uid != uid || + inode->i_gid != gid || + inode->i_xid != xid) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; inode->i_mode = fattr->mode; inode->i_nlink = fattr->nlink; - inode->i_uid = fattr->uid; - inode->i_gid = fattr->gid; + inode->i_uid = uid; + inode->i_gid = gid; + inode->i_xid = xid; if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) { /* diff -NurpP --minimal linux-2.6.17.11/fs/nfs/nfs3xdr.c linux-2.6.17.11-g-v/fs/nfs/nfs3xdr.c --- linux-2.6.17.11/fs/nfs/nfs3xdr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfs/nfs3xdr.c 2006-08-28 14:56:36.000000000 +0200 @@ -22,6 +22,7 @@ #include #include #include +#include #define NFSDBG_FACILITY NFSDBG_XDR @@ -178,7 +179,7 @@ xdr_decode_fattr(u32 *p, struct nfs_fatt } static inline u32 * -xdr_encode_sattr(u32 *p, struct iattr *attr) +xdr_encode_sattr(u32 *p, struct iattr *attr, int tagxid) { if (attr->ia_valid & ATTR_MODE) { *p++ = xdr_one; @@ -186,15 +187,17 @@ xdr_encode_sattr(u32 *p, struct iattr *a } else { *p++ = xdr_zero; } - if (attr->ia_valid & ATTR_UID) { + if (attr->ia_valid & ATTR_UID || + (tagxid && (attr->ia_valid & ATTR_XID))) { *p++ = xdr_one; - *p++ = htonl(attr->ia_uid); + *p++ = htonl(XIDINO_UID(tagxid, attr->ia_uid, attr->ia_xid)); } else { *p++ = xdr_zero; } - if (attr->ia_valid & ATTR_GID) { + if (attr->ia_valid & ATTR_GID || + (tagxid && (attr->ia_valid & ATTR_XID))) { *p++ = xdr_one; - *p++ = htonl(attr->ia_gid); + *p++ = htonl(XIDINO_GID(tagxid, attr->ia_gid, attr->ia_xid)); } else { *p++ = xdr_zero; } @@ -279,7 +282,8 @@ static int nfs3_xdr_sattrargs(struct rpc_rqst *req, u32 *p, struct nfs3_sattrargs *args) { p = xdr_encode_fhandle(p, args->fh); - p = xdr_encode_sattr(p, args->sattr); + p = xdr_encode_sattr(p, args->sattr, + req->rq_task->tk_client->cl_tagxid); *p++ = htonl(args->guard); if (args->guard) p = xdr_encode_time3(p, &args->guardtime); @@ -370,7 +374,8 @@ nfs3_xdr_createargs(struct rpc_rqst *req *p++ = args->verifier[0]; *p++ = args->verifier[1]; } else - p = xdr_encode_sattr(p, args->sattr); + p = xdr_encode_sattr(p, args->sattr, + req->rq_task->tk_client->cl_tagxid); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; @@ -384,7 +389,8 @@ nfs3_xdr_mkdirargs(struct rpc_rqst *req, { p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_array(p, args->name, args->len); - p = xdr_encode_sattr(p, args->sattr); + p = xdr_encode_sattr(p, args->sattr, + req->rq_task->tk_client->cl_tagxid); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; } @@ -397,7 +403,8 @@ nfs3_xdr_symlinkargs(struct rpc_rqst *re { p = xdr_encode_fhandle(p, args->fromfh); p = xdr_encode_array(p, args->fromname, args->fromlen); - p = xdr_encode_sattr(p, args->sattr); + p = xdr_encode_sattr(p, args->sattr, + req->rq_task->tk_client->cl_tagxid); p = xdr_encode_array(p, args->topath, args->tolen); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; @@ -412,7 +419,8 @@ nfs3_xdr_mknodargs(struct rpc_rqst *req, p = xdr_encode_fhandle(p, args->fh); p = xdr_encode_array(p, args->name, args->len); *p++ = htonl(args->type); - p = xdr_encode_sattr(p, args->sattr); + p = xdr_encode_sattr(p, args->sattr, + req->rq_task->tk_client->cl_tagxid); if (args->type == NF3CHR || args->type == NF3BLK) { *p++ = htonl(MAJOR(args->rdev)); *p++ = htonl(MINOR(args->rdev)); diff -NurpP --minimal linux-2.6.17.11/fs/nfs/nfsroot.c linux-2.6.17.11-g-v/fs/nfs/nfsroot.c --- linux-2.6.17.11/fs/nfs/nfsroot.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfs/nfsroot.c 2006-08-28 14:56:36.000000000 +0200 @@ -87,6 +87,7 @@ #include #include #include +#include /* Define this to allow debugging output */ #undef NFSROOT_DEBUG @@ -124,7 +125,7 @@ enum { Opt_soft, Opt_hard, Opt_intr, Opt_nointr, Opt_posix, Opt_noposix, Opt_cto, Opt_nocto, Opt_ac, Opt_noac, Opt_lock, Opt_nolock, Opt_v2, Opt_v3, Opt_udp, Opt_tcp, - Opt_acl, Opt_noacl, + Opt_acl, Opt_noacl, Opt_tagxid, /* Error token */ Opt_err }; @@ -161,6 +162,7 @@ static match_table_t __initdata tokens = {Opt_tcp, "tcp"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, + {Opt_tagxid, "tagxid"}, {Opt_err, NULL} }; @@ -275,6 +277,11 @@ static int __init root_nfs_parse(char *n case Opt_noacl: nfs_data.flags |= NFS_MOUNT_NOACL; break; +#ifndef CONFIG_INOXID_NONE + case Opt_tagxid: + nfs_data.flags |= NFS_MOUNT_TAGXID; + break; +#endif default: printk(KERN_WARNING "Root-NFS: unknown " "option: %s\n", p); @@ -312,7 +319,7 @@ static int __init root_nfs_name(char *na /* Override them by options set on kernel command-line */ root_nfs_parse(name, buf); - cp = system_utsname.nodename; + cp = vx_new_uts(nodename); if (strlen(buf) + strlen(cp) > NFS_MAXPATHLEN) { printk(KERN_ERR "Root-NFS: Pathname for remote directory too long.\n"); return -1; diff -NurpP --minimal linux-2.6.17.11/fs/nfsd/auth.c linux-2.6.17.11-g-v/fs/nfsd/auth.c --- linux-2.6.17.11/fs/nfsd/auth.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfsd/auth.c 2006-08-28 14:56:36.000000000 +0200 @@ -9,6 +9,7 @@ #include #include #include +#include #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) @@ -41,19 +42,22 @@ int nfsd_setuser(struct svc_rqst *rqstp, get_group_info(cred.cr_group_info); if (cred.cr_uid != (uid_t) -1) - current->fsuid = cred.cr_uid; + current->fsuid = INOXID_UID(XID_TAG_NFSD, cred.cr_uid, cred.cr_gid); else current->fsuid = exp->ex_anon_uid; if (cred.cr_gid != (gid_t) -1) - current->fsgid = cred.cr_gid; + current->fsgid = INOXID_GID(XID_TAG_NFSD, cred.cr_uid, cred.cr_gid); else current->fsgid = exp->ex_anon_gid; + /* this desperately needs a tag :) */ + current->xid = INOXID_XID(XID_TAG_NFSD, cred.cr_uid, cred.cr_gid, 0); + if (!cred.cr_group_info) return -ENOMEM; ret = set_current_groups(cred.cr_group_info); put_group_info(cred.cr_group_info); - if ((cred.cr_uid)) { + if (INOXID_UID(XID_TAG_NFSD, cred.cr_uid, cred.cr_gid)) { cap_t(current->cap_effective) &= ~CAP_NFSD_MASK; } else { cap_t(current->cap_effective) |= (CAP_NFSD_MASK & diff -NurpP --minimal linux-2.6.17.11/fs/nfsd/nfs3xdr.c linux-2.6.17.11-g-v/fs/nfsd/nfs3xdr.c --- linux-2.6.17.11/fs/nfsd/nfs3xdr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfsd/nfs3xdr.c 2006-08-28 14:56:36.000000000 +0200 @@ -21,6 +21,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -111,6 +112,8 @@ static inline u32 * decode_sattr3(u32 *p, struct iattr *iap) { u32 tmp; + uid_t uid = 0; + gid_t gid = 0; iap->ia_valid = 0; @@ -120,12 +123,15 @@ decode_sattr3(u32 *p, struct iattr *iap) } if (*p++) { iap->ia_valid |= ATTR_UID; - iap->ia_uid = ntohl(*p++); + uid = ntohl(*p++); } if (*p++) { iap->ia_valid |= ATTR_GID; - iap->ia_gid = ntohl(*p++); + gid = ntohl(*p++); } + iap->ia_uid = INOXID_UID(XID_TAG_NFSD, uid, gid); + iap->ia_gid = INOXID_GID(XID_TAG_NFSD, uid, gid); + iap->ia_xid = INOXID_XID(XID_TAG_NFSD, uid, gid, 0); if (*p++) { u64 newsize; @@ -163,8 +169,10 @@ encode_fattr3(struct svc_rqst *rqstp, u3 *p++ = htonl(nfs3_ftypes[(stat->mode & S_IFMT) >> 12]); *p++ = htonl((u32) stat->mode); *p++ = htonl((u32) stat->nlink); - *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid)); - *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid)); + *p++ = htonl((u32) nfsd_ruid(rqstp, + XIDINO_UID(XID_TAG(dentry->d_inode), stat->uid, stat->xid))); + *p++ = htonl((u32) nfsd_rgid(rqstp, + XIDINO_GID(XID_TAG(dentry->d_inode), stat->gid, stat->xid))); if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) { p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { diff -NurpP --minimal linux-2.6.17.11/fs/nfsd/nfs4recover.c linux-2.6.17.11-g-v/fs/nfsd/nfs4recover.c --- linux-2.6.17.11/fs/nfsd/nfs4recover.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfsd/nfs4recover.c 2006-08-28 14:56:36.000000000 +0200 @@ -155,7 +155,7 @@ nfsd4_create_clid_dir(struct nfs4_client dprintk("NFSD: nfsd4_create_clid_dir: DIRECTORY EXISTS\n"); goto out_put; } - status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU); + status = vfs_mkdir(rec_dir.dentry->d_inode, dentry, S_IRWXU, NULL); out_put: dput(dentry); out_unlock: @@ -259,7 +259,7 @@ nfsd4_remove_clid_file(struct dentry *di return -EINVAL; } mutex_lock(&dir->d_inode->i_mutex); - status = vfs_unlink(dir->d_inode, dentry); + status = vfs_unlink(dir->d_inode, dentry, NULL); mutex_unlock(&dir->d_inode->i_mutex); return status; } @@ -274,7 +274,7 @@ nfsd4_clear_clid_dir(struct dentry *dir, * a kernel from the future.... */ nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file); mutex_lock(&dir->d_inode->i_mutex); - status = vfs_rmdir(dir->d_inode, dentry); + status = vfs_rmdir(dir->d_inode, dentry, NULL); mutex_unlock(&dir->d_inode->i_mutex); return status; } diff -NurpP --minimal linux-2.6.17.11/fs/nfsd/nfs4xdr.c linux-2.6.17.11-g-v/fs/nfsd/nfs4xdr.c --- linux-2.6.17.11/fs/nfsd/nfs4xdr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfsd/nfs4xdr.c 2006-08-28 14:56:36.000000000 +0200 @@ -57,6 +57,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -1560,14 +1561,18 @@ out_acl: WRITE32(stat.nlink); } if (bmval1 & FATTR4_WORD1_OWNER) { - status = nfsd4_encode_user(rqstp, stat.uid, &p, &buflen); + status = nfsd4_encode_user(rqstp, + XIDINO_UID(XID_TAG(dentry->d_inode), + stat.uid, stat.xid), &p, &buflen); if (status == nfserr_resource) goto out_resource; if (status) goto out; } if (bmval1 & FATTR4_WORD1_OWNER_GROUP) { - status = nfsd4_encode_group(rqstp, stat.gid, &p, &buflen); + status = nfsd4_encode_group(rqstp, + XIDINO_GID(XID_TAG(dentry->d_inode), + stat.gid, stat.xid), &p, &buflen); if (status == nfserr_resource) goto out_resource; if (status) diff -NurpP --minimal linux-2.6.17.11/fs/nfsd/nfsxdr.c linux-2.6.17.11-g-v/fs/nfsd/nfsxdr.c --- linux-2.6.17.11/fs/nfsd/nfsxdr.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfsd/nfsxdr.c 2006-08-28 14:56:36.000000000 +0200 @@ -15,6 +15,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -102,6 +103,8 @@ static inline u32 * decode_sattr(u32 *p, struct iattr *iap) { u32 tmp, tmp1; + uid_t uid = 0; + gid_t gid = 0; iap->ia_valid = 0; @@ -115,12 +118,15 @@ decode_sattr(u32 *p, struct iattr *iap) } if ((tmp = ntohl(*p++)) != (u32)-1) { iap->ia_valid |= ATTR_UID; - iap->ia_uid = tmp; + uid = tmp; } if ((tmp = ntohl(*p++)) != (u32)-1) { iap->ia_valid |= ATTR_GID; - iap->ia_gid = tmp; + gid = tmp; } + iap->ia_uid = INOXID_UID(XID_TAG_NFSD, uid, gid); + iap->ia_gid = INOXID_GID(XID_TAG_NFSD, uid, gid); + iap->ia_xid = INOXID_XID(XID_TAG_NFSD, uid, gid, 0); if ((tmp = ntohl(*p++)) != (u32)-1) { iap->ia_valid |= ATTR_SIZE; iap->ia_size = tmp; @@ -164,8 +170,10 @@ encode_fattr(struct svc_rqst *rqstp, u32 *p++ = htonl(nfs_ftypes[type >> 12]); *p++ = htonl((u32) stat->mode); *p++ = htonl((u32) stat->nlink); - *p++ = htonl((u32) nfsd_ruid(rqstp, stat->uid)); - *p++ = htonl((u32) nfsd_rgid(rqstp, stat->gid)); + *p++ = htonl((u32) nfsd_ruid(rqstp, + XIDINO_UID(XID_TAG(dentry->d_inode), stat->uid, stat->xid))); + *p++ = htonl((u32) nfsd_rgid(rqstp, + XIDINO_GID(XID_TAG(dentry->d_inode), stat->gid, stat->xid))); if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) { *p++ = htonl(NFS_MAXPATHLEN); diff -NurpP --minimal linux-2.6.17.11/fs/nfsd/vfs.c linux-2.6.17.11-g-v/fs/nfsd/vfs.c --- linux-2.6.17.11/fs/nfsd/vfs.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/nfsd/vfs.c 2006-08-28 14:56:36.000000000 +0200 @@ -1156,13 +1156,13 @@ nfsd_create(struct svc_rqst *rqstp, stru err = vfs_create(dirp, dchild, iap->ia_mode, NULL); break; case S_IFDIR: - err = vfs_mkdir(dirp, dchild, iap->ia_mode); + err = vfs_mkdir(dirp, dchild, iap->ia_mode, NULL); break; case S_IFCHR: case S_IFBLK: case S_IFIFO: case S_IFSOCK: - err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev); + err = vfs_mknod(dirp, dchild, iap->ia_mode, rdev, NULL); break; default: printk("nfsd: bad file type %o in nfsd_create\n", type); @@ -1442,11 +1442,13 @@ nfsd_symlink(struct svc_rqst *rqstp, str else { strncpy(path_alloced, path, plen); path_alloced[plen] = 0; - err = vfs_symlink(dentry->d_inode, dnew, path_alloced, mode); + err = vfs_symlink(dentry->d_inode, dnew, + path_alloced, mode, NULL); kfree(path_alloced); } } else - err = vfs_symlink(dentry->d_inode, dnew, path, mode); + err = vfs_symlink(dentry->d_inode, dnew, + path, mode, NULL); if (!err) if (EX_ISSYNC(fhp->fh_export)) @@ -1504,7 +1506,7 @@ nfsd_link(struct svc_rqst *rqstp, struct dold = tfhp->fh_dentry; dest = dold->d_inode; - err = vfs_link(dold, dirp, dnew); + err = vfs_link(dold, dirp, dnew, NULL); if (!err) { if (EX_ISSYNC(ffhp->fh_export)) { err = nfserrno(nfsd_sync_dir(ddir)); @@ -1666,9 +1668,9 @@ nfsd_unlink(struct svc_rqst *rqstp, stru err = -EPERM; } else #endif - err = vfs_unlink(dirp, rdentry); + err = vfs_unlink(dirp, rdentry, NULL); } else { /* It's RMDIR */ - err = vfs_rmdir(dirp, rdentry); + err = vfs_rmdir(dirp, rdentry, NULL); } dput(rdentry); @@ -1777,7 +1779,8 @@ nfsd_permission(struct svc_export *exp, */ if (!(acc & MAY_LOCAL_ACCESS)) if (acc & (MAY_WRITE | MAY_SATTR | MAY_TRUNC)) { - if (EX_RDONLY(exp) || IS_RDONLY(inode)) + if (EX_RDONLY(exp) || IS_RDONLY(inode) + || MNT_IS_RDONLY(exp->ex_mnt)) return nfserr_rofs; if (/* (acc & MAY_WRITE) && */ IS_IMMUTABLE(inode)) return nfserr_perm; diff -NurpP --minimal linux-2.6.17.11/fs/open.c linux-2.6.17.11-g-v/fs/open.c --- linux-2.6.17.11/fs/open.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/open.c 2006-08-28 14:56:36.000000000 +0200 @@ -28,6 +28,10 @@ #include #include #include +#include +#include +#include +#include #include @@ -46,6 +50,8 @@ int vfs_statfs(struct super_block *sb, s if (retval == 0 && buf->f_frsize == 0) buf->f_frsize = buf->f_bsize; } + if (!vx_check(0, VX_ADMIN|VX_WATCH)) + vx_vsi_statfs(sb, buf); } return retval; } @@ -207,6 +213,9 @@ int do_truncate(struct dentry *dentry, l if (length < 0) return -EINVAL; + if (filp && !gr_acl_handle_truncate(dentry, filp->f_vfsmnt)) + return -EACCES; + newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | time_attrs; if (filp) { @@ -249,7 +258,7 @@ static long do_sys_truncate(const char _ goto dput_and_out; error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt)) goto dput_and_out; error = -EPERM; @@ -379,7 +388,7 @@ asmlinkage long sys_utime(char __user * inode = nd.dentry->d_inode; error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt)) goto dput_and_out; /* Don't worry, the checks are done in inode_change_ok() */ @@ -407,6 +416,12 @@ asmlinkage long sys_utime(char __user * (error = vfs_permission(&nd, MAY_WRITE)) != 0) goto dput_and_out; } + + if (!gr_acl_handle_utime(nd.dentry, nd.mnt)) { + error = -EACCES; + goto dput_and_out; + } + mutex_lock(&inode->i_mutex); error = notify_change(nd.dentry, &newattrs); mutex_unlock(&inode->i_mutex); @@ -436,7 +451,7 @@ long do_utimes(int dfd, char __user *fil inode = nd.dentry->d_inode; error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt)) goto dput_and_out; /* Don't worry, the checks are done in inode_change_ok() */ @@ -460,6 +475,12 @@ long do_utimes(int dfd, char __user *fil (error = vfs_permission(&nd, MAY_WRITE)) != 0) goto dput_and_out; } + + if (!gr_acl_handle_utime(nd.dentry, nd.mnt)) { + error = -EACCES; + goto dput_and_out; + } + mutex_lock(&inode->i_mutex); error = notify_change(nd.dentry, &newattrs); mutex_unlock(&inode->i_mutex); @@ -523,9 +544,14 @@ asmlinkage long sys_faccessat(int dfd, c if (!res) { res = vfs_permission(&nd, mode); /* SuS v2 requires we report a read only fs too */ - if(!res && (mode & S_IWOTH) && IS_RDONLY(nd.dentry->d_inode) + if(!res && (mode & S_IWOTH) + && (IS_RDONLY(nd.dentry->d_inode) || MNT_IS_RDONLY(nd.mnt)) && !special_file(nd.dentry->d_inode->i_mode)) res = -EROFS; + + if (!res && !gr_acl_handle_access(nd.dentry, nd.mnt, mode)) + res = -EACCES; + path_release(&nd); } @@ -554,6 +580,8 @@ asmlinkage long sys_chdir(const char __u if (error) goto dput_and_out; + gr_log_chdir(nd.dentry, nd.mnt); + set_fs_pwd(current->fs, nd.mnt, nd.dentry); dput_and_out: @@ -584,6 +612,13 @@ asmlinkage long sys_fchdir(unsigned int goto out_putf; error = file_permission(file, MAY_EXEC); + + if (!error && !gr_chroot_fchdir(dentry, mnt)) + error = -EPERM; + + if (!error) + gr_log_chdir(dentry, mnt); + if (!error) set_fs_pwd(current->fs, mnt, dentry); out_putf: @@ -609,8 +644,16 @@ asmlinkage long sys_chroot(const char __ if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; + if (gr_handle_chroot_chroot(nd.dentry, nd.mnt)) + goto dput_and_out; + set_fs_root(current->fs, nd.mnt, nd.dentry); set_fs_altroot(); + + gr_handle_chroot_caps(current); + + gr_handle_chroot_chdir(nd.dentry, nd.mnt); + error = 0; dput_and_out: path_release(&nd); @@ -636,14 +679,27 @@ asmlinkage long sys_fchmod(unsigned int audit_inode(NULL, inode, 0); err = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(file->f_vfsmnt)) goto out_putf; err = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out_putf; + + if (!gr_acl_handle_fchmod(dentry, file->f_vfsmnt, mode)) { + err = -EACCES; + goto out_putf; + } + mutex_lock(&inode->i_mutex); if (mode == (mode_t) -1) mode = inode->i_mode; + + if (gr_handle_chroot_chmod(dentry, file->f_vfsmnt, mode)) { + err = -EPERM; + mutex_unlock(&inode->i_mutex); + goto out_putf; + } + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); @@ -669,16 +725,28 @@ asmlinkage long sys_fchmodat(int dfd, co inode = nd.dentry->d_inode; error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(nd.mnt)) goto dput_and_out; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto dput_and_out; + if (!gr_acl_handle_chmod(nd.dentry, nd.mnt, mode)) { + error = -EACCES; + goto dput_and_out; + }; + mutex_lock(&inode->i_mutex); if (mode == (mode_t) -1) mode = inode->i_mode; + + if (gr_handle_chroot_chmod(nd.dentry, nd.mnt, mode)) { + error = -EACCES; + mutex_unlock(&inode->i_mutex); + goto dput_and_out; + } + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(nd.dentry, &newattrs); @@ -695,7 +763,7 @@ asmlinkage long sys_chmod(const char __u return sys_fchmodat(AT_FDCWD, filename, mode); } -static int chown_common(struct dentry * dentry, uid_t user, gid_t group) +static int chown_common(struct dentry * dentry, uid_t user, gid_t group, struct vfsmount *mnt) { struct inode * inode; int error; @@ -707,19 +775,25 @@ static int chown_common(struct dentry * goto out; } error = -EROFS; - if (IS_RDONLY(inode)) + if (IS_RDONLY(inode) || MNT_IS_RDONLY(mnt)) goto out; error = -EPERM; if (IS_IMMUTABLE(inode) || IS_APPEND(inode)) goto out; + + if (!gr_acl_handle_chown(dentry, mnt)) { + error = -EACCES; + goto out; + } + newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) -1) { newattrs.ia_valid |= ATTR_UID; - newattrs.ia_uid = user; + newattrs.ia_uid = vx_map_uid(user); } if (group != (gid_t) -1) { newattrs.ia_valid |= ATTR_GID; - newattrs.ia_gid = group; + newattrs.ia_gid = vx_map_gid(group); } if (!S_ISDIR(inode->i_mode)) newattrs.ia_valid |= ATTR_KILL_SUID|ATTR_KILL_SGID; @@ -737,7 +811,7 @@ asmlinkage long sys_chown(const char __u error = user_path_walk(filename, &nd); if (!error) { - error = chown_common(nd.dentry, user, group); + error = chown_common(nd.dentry, user, group, nd.mnt); path_release(&nd); } return error; @@ -756,7 +830,7 @@ asmlinkage long sys_fchownat(int dfd, co follow = (flag & AT_SYMLINK_NOFOLLOW) ? 0 : LOOKUP_FOLLOW; error = __user_walk_fd(dfd, filename, follow, &nd); if (!error) { - error = chown_common(nd.dentry, user, group); + error = chown_common(nd.dentry, user, group, nd.mnt); path_release(&nd); } out: @@ -770,7 +844,7 @@ asmlinkage long sys_lchown(const char __ error = user_path_walk_link(filename, &nd); if (!error) { - error = chown_common(nd.dentry, user, group); + error = chown_common(nd.dentry, user, group, nd.mnt); path_release(&nd); } return error; @@ -787,7 +861,7 @@ asmlinkage long sys_fchown(unsigned int struct dentry * dentry; dentry = file->f_dentry; audit_inode(NULL, dentry->d_inode, 0); - error = chown_common(dentry, user, group); + error = chown_common(dentry, user, group, file->f_vfsmnt); fput(file); } return error; @@ -995,6 +1069,7 @@ repeat: * N.B. For clone tasks sharing a files structure, this test * will limit the total number of files that can be opened. */ + gr_learn_resource(current, RLIMIT_NOFILE, fd, 0); if (fd >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) goto out; @@ -1015,6 +1090,7 @@ repeat: FD_SET(fd, fdt->open_fds); FD_CLR(fd, fdt->close_on_exec); files->next_fd = fd + 1; + vx_openfd_inc(fd); #if 1 /* Sanity check */ if (fdt->fd[fd] != NULL) { @@ -1037,6 +1113,7 @@ static void __put_unused_fd(struct files __FD_CLR(fd, fdt->open_fds); if (fd < files->next_fd) files->next_fd = fd; + vx_openfd_dec(fd); } void fastcall put_unused_fd(unsigned int fd) diff -NurpP --minimal linux-2.6.17.11/fs/pipe.c linux-2.6.17.11-g-v/fs/pipe.c --- linux-2.6.17.11/fs/pipe.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/pipe.c 2006-08-28 14:44:49.000000000 +0200 @@ -842,7 +842,7 @@ void free_pipe_info(struct inode *inode) inode->i_pipe = NULL; } -static struct vfsmount *pipe_mnt __read_mostly; +struct vfsmount *pipe_mnt __read_mostly; static int pipefs_delete_dentry(struct dentry *dentry) { return 1; diff -NurpP --minimal linux-2.6.17.11/fs/proc/array.c linux-2.6.17.11-g-v/fs/proc/array.c --- linux-2.6.17.11/fs/proc/array.c 2006-08-23 23:16:33.000000000 +0200 +++ linux-2.6.17.11-g-v/fs/proc/array.c 2006-08-28 14:56:36.000000000 +0200 @@ -75,6 +75,9 @@ #include #include #include +#include +#include +#include #include #include @@ -135,7 +138,9 @@ static const char *task_state_array[] = "T (stopped)", /* 4 */ "T (tracing stop)", /* 8 */ "Z (zombie)", /* 16 */ - "X (dead)" /* 32 */ + "X (dead)", /* 32 */ + "N (noninteractive)", /* 64 */ + "H (on hold)" /* 128 */ }; static inline const char * get_task_state(struct task_struct *tsk) @@ -144,7 +149,8 @@ static inline const char * get_task_stat TASK_INTERRUPTIBLE | TASK_UNINTERRUPTIBLE | TASK_STOPPED | - TASK_TRACED)) | + TASK_TRACED | + TASK_ONHOLD)) | (tsk->exit_state & (EXIT_ZOMBIE | EXIT_DEAD)); const char **p = &task_state_array[0]; @@ -161,8 +167,13 @@ static inline char * task_state(struct t struct group_info *group_info; int g; struct fdtable *fdt = NULL; + pid_t pid, ptgid, tppid, tgid; read_lock(&tasklist_lock); + tgid = vx_map_tgid(p->tgid); + pid = vx_map_pid(p->pid); + ptgid = vx_map_pid(p->group_leader->real_parent->tgid); + tppid = vx_map_pid(p->parent->pid); buffer += sprintf(buffer, "State:\t%s\n" "SleepAVG:\t%lu%%\n" @@ -174,9 +185,8 @@ static inline char * task_state(struct t "Gid:\t%d\t%d\t%d\t%d\n", get_task_state(p), (p->sleep_avg/1024)*100/(1020000000/1024), - p->tgid, - p->pid, pid_alive(p) ? p->group_leader->real_parent->tgid : 0, - pid_alive(p) && p->ptrace ? p->parent->pid : 0, + tgid, pid, (pid > 1) ? ptgid : 0, + pid_alive(p) && p->ptrace ? tppid : 0, p->uid, p->euid, p->suid, p->fsuid, p->gid, p->egid, p->sgid, p->fsgid); read_unlock(&tasklist_lock); @@ -293,9 +303,30 @@ static inline char *task_cap(struct task cap_t(p->cap_effective)); } +#if defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) +static inline char *task_pax(struct task_struct *p, char *buffer) +{ + if (p->mm) + return buffer + sprintf(buffer, "PaX:\t%c%c%c%c%c\n", + p->mm->pax_flags & MF_PAX_PAGEEXEC ? 'P' : 'p', + p->mm->pax_flags & MF_PAX_EMUTRAMP ? 'E' : 'e', + p->mm->pax_flags & MF_PAX_MPROTECT ? 'M' : 'm', + p->mm->pax_flags & MF_PAX_RANDMMAP ? 'R' : 'r', + p->mm->pax_flags & MF_PAX_SEGMEXEC ? 'S' : 's'); + else + return buffer + sprintf(buffer, "PaX:\t-----\n"); +} +#endif + int proc_pid_status(struct task_struct *task, char * buffer) { char * orig = buffer; +#ifdef CONFIG_VSERVER_LEGACY + struct vx_info *vxi; +#endif +#ifdef CONFIG_VSERVER_LEGACYNET + struct nx_info *nxi; +#endif struct mm_struct *mm = get_task_mm(task); buffer = task_name(task, buffer); @@ -308,12 +339,63 @@ int proc_pid_status(struct task_struct * buffer = task_sig(task, buffer); buffer = task_cap(task, buffer); buffer = cpuset_task_status_allowed(task, buffer); + + if (task_vx_flags(task, VXF_INFO_HIDE, 0)) + goto skip; +#ifdef CONFIG_VSERVER_LEGACY + buffer += sprintf (buffer,"s_context: %d\n", vx_task_xid(task)); + vxi = task_get_vx_info(task); + if (vxi) { + buffer += sprintf (buffer,"ctxflags: %08llx\n" + ,(unsigned long long)vxi->vx_flags); + buffer += sprintf (buffer,"initpid: %d\n" + ,vxi->vx_initpid); + } else { + buffer += sprintf (buffer,"ctxflags: none\n"); + buffer += sprintf (buffer,"initpid: none\n"); + } + put_vx_info(vxi); +#else + buffer += sprintf (buffer,"VxID: %d\n", vx_task_xid(task)); +#endif +#ifdef CONFIG_VSERVER_LEGACYNET + nxi = task_get_nx_info(task); + if (nxi) { + int i; + + buffer += sprintf (buffer,"ipv4root:"); + for (i=0; inbipv4; i++){ + buffer += sprintf (buffer," %08x/%08x" + ,nxi->ipv4[i] + ,nxi->mask[i]); + } + *buffer++ = '\n'; + buffer += sprintf (buffer,"ipv4root_bcast: %08x\n" + ,nxi->v4_bcast); + } else { + buffer += sprintf (buffer,"ipv4root: 0\n"); + buffer += sprintf (buffer,"ipv4root_bcast: 0\n"); + } + put_nx_info(nxi); +#endif +skip: #if defined(CONFIG_S390) buffer = task_show_regs(task, buffer); #endif + +#if defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) + buffer = task_pax(task, buffer); +#endif + return buffer - orig; } +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP +#define PAX_RAND_FLAGS(_mm) (_mm != NULL && _mm != current->mm && \ + (_mm->pax_flags & MF_PAX_RANDMMAP || \ + _mm->pax_flags & MF_PAX_SEGMEXEC)) +#endif + static int do_task_stat(struct task_struct *task, char * buffer, int whole) { unsigned long vsize, eip, esp, wchan = ~0UL; @@ -322,7 +404,7 @@ static int do_task_stat(struct task_stru sigset_t sigign, sigcatch; char state; int res; - pid_t ppid, pgid = -1, sid = -1; + pid_t pid, ppid, pgid = -1, sid = -1; int num_threads = 0; struct mm_struct *mm; unsigned long long start_time; @@ -386,7 +468,11 @@ static int do_task_stat(struct task_stru stime = cputime_add(stime, task->signal->stime); } } - ppid = pid_alive(task) ? task->group_leader->real_parent->tgid : 0; + pid = vx_info_map_pid(task->vx_info, pid_alive(task) ? task->pid : 0); + ppid = (!(pid > 1)) ? 0 : vx_info_map_tgid(task->vx_info, + task->group_leader->real_parent->tgid); + pgid = vx_info_map_pid(task->vx_info, pgid); + read_unlock(&tasklist_lock); if (!whole || num_threads<2) @@ -398,6 +484,19 @@ static int do_task_stat(struct task_stru stime = task->stime; } +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + if (PAX_RAND_FLAGS(mm)) { + eip = 0; + esp = 0; + wchan = 0; + } +#endif +#ifdef CONFIG_GRKERNSEC_HIDESYM + wchan = 0; + eip =0; + esp =0; +#endif + /* scale priority and nice values from timeslices to -20..20 */ /* to make it look like a "normal" Unix priority/nice value */ priority = task_prio(task); @@ -410,10 +509,21 @@ static int do_task_stat(struct task_stru /* convert nsec -> ticks */ start_time = nsec_to_clock_t(start_time); + /* fixup start time for virt uptime */ + if (vx_flags(VXF_VIRT_UPTIME, 0)) { + unsigned long long bias = + current->vx_info->cvirt.bias_clock; + + if (start_time > bias) + start_time -= bias; + else + start_time = 0; + } + res = sprintf(buffer,"%d (%s) %c %d %d %d %d