diff -NurpP linux-2.6.14.7/Documentation/vserver/debug.txt linux-2.6.14.7-vs2.1.0-grsec-2.1.9/Documentation/vserver/debug.txt --- linux-2.6.14.7/Documentation/vserver/debug.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/Documentation/vserver/debug.txt 2006-02-27 17:33:28.000000000 +0100 @@ -0,0 +1,106 @@ + +debug_cvirt: + + 2 4 "vx_map_tgid: %p/%llx: %d -> %d" + "vx_rmap_tgid: %p/%llx: %d -> %d" + +debug_dlim: + + 0 1 "ALLOC (%p,#%d)%c inode (%d)" + "FREE (%p,#%d)%c inode" + 1 2 "ALLOC (%p,#%d)%c %lld bytes (%d)" + "FREE (%p,#%d)%c %lld bytes" + 2 4 "ADJUST: %lld,%lld on %d,%d [mult=%d]" + 3 8 "ext3_has_free_blocks(%p): %u<%u+1, %c, %u!=%u r=%d" + "ext3_has_free_blocks(%p): free=%u, root=%u" + "rcu_free_dl_info(%p)" + 4 10 "alloc_dl_info(%p,%d) = %p" + "dealloc_dl_info(%p)" + "get_dl_info(%p[#%d.%d])" + "put_dl_info(%p[#%d.%d])" + 5 20 "alloc_dl_info(%p,%d)*" + 6 40 "__hash_dl_info: %p[#%d]" + "__unhash_dl_info: %p[#%d]" + 7 80 "locate_dl_info(%p,#%d) = %p" + +debug_net: + + 2 4 "nx_addr_conflict(%p,%p) %d.%d,%d.%d" + 3 8 "inet_bind(%p) %d.%d.%d.%d, %d.%d.%d.%d, %d.%d.%d.%d" + "inet_bind(%p)* %p,%p;%lx %d.%d.%d.%d" + 4 10 "ip_route_connect(%p) %p,%p;%lx" + 5 20 "__addr_in_socket(%p,%d.%d.%d.%d) %p:%d.%d.%d.%d %p;%lx" + 6 40 "sk,egf: %p [#%d] (from %d)" + "sk,egn: %p [#%d] (from %d)" + "sk,req: %p [#%d] (from %d)" + "sk: %p [#%d] (from %d)" + "tw: %p [#%d] (from %d)" + 7 80 "__sock_recvmsg: %p[%p,%p,%p;%d]:%d/%d" + "__sock_sendmsg: %p[%p,%p,%p;%d]:%d/%d" + +debug_nid: + + 0 1 "__lookup_nx_info(#%u): %p[#%u]" + "alloc_nx_info(%d) = %p" + "create_nx_info(%d) (dynamic rejected)" + "create_nx_info(%d) = %p (already there)" + "create_nx_info(%d) = %p (new)" + "dealloc_nx_info(%p)" + 1 2 "alloc_nx_info(%d)*" + "create_nx_info(%d)*" + 2 4 "get_nx_info(%p[#%d.%d])" + "put_nx_info(%p[#%d.%d])" + 3 8 "claim_nx_info(%p[#%d.%d.%d]) %p" + "clr_nx_info(%p[#%d.%d])" + "init_nx_info(%p[#%d.%d])" + "release_nx_info(%p[#%d.%d.%d]) %p" + "set_nx_info(%p[#%d.%d])" + 4 10 "__hash_nx_info: %p[#%d]" + "__nx_dynamic_id: [#%d]" + "__unhash_nx_info: %p[#%d]" + 5 20 "moved task %p into nxi:%p[#%d]" + "nx_migrate_task(%p,%p[#%d.%d.%d])" + "task_get_nx_info(%p)" + +debug_switch: + + 0 1 "vc: VCMD_%02d_%d[%d], %d,%p,%d" + 1 2 "vc: VCMD_%02d_%d[%d] = %08lx(%ld)" + 4 10 "%s: (%s %s) returned %s with %d" + +debug_xid: + + 0 1 "__lookup_vx_info(#%u): %p[#%u]" + "alloc_vx_info(%d) = %p" + "alloc_vx_info(%d)*" + "create_vx_info(%d) (dynamic rejected)" + "create_vx_info(%d) = %p (already there)" + "create_vx_info(%d) = %p (new)" + "dealloc_vx_info(%p)" + 1 2 "create_vx_info(%d)*" + 2 4 "get_vx_info(%p[#%d.%d])" + "put_vx_info(%p[#%d.%d])" + 3 8 "claim_vx_info(%p[#%d.%d.%d]) %p" + "clr_vx_info(%p[#%d.%d])" + "init_vx_info(%p[#%d.%d])" + "release_vx_info(%p[#%d.%d.%d]) %p" + "set_vx_info(%p[#%d.%d])" + 4 10 "__hash_vx_info: %p[#%d]" + "__unhash_vx_info: %p[#%d]" + "__vx_dynamic_id: [#%d]" + 5 20 "moved task %p into vxi:%p[#%d]" + "task_get_vx_info(%p)" + "vx_migrate_task(%p,%p[#%d.%d])" + 6 40 "vx_set_init(%p[#%d],%p[#%d,%d,%d])" + 7 80 "vx_parse_xid(»%s«): %d:#%d" + "vx_propagate_xid(%p[#%lu.%d]): %d,%d" + + +debug_limit: + + n 2^n "vx_acc_cres[%5d,%s,%2d]: %5d%s" + "vx_cres_avail[%5d,%s,%2d]: %5ld > %5d + %5d" + + m 2^m "vx_acc_page[%5d,%s,%2d]: %5d%s" + "vx_acc_pages[%5d,%s,%2d]: %5d += %5d" + "vx_pages_avail[%5d,%s,%2d]: %5ld > %5d + %5d" diff -NurpP linux-2.6.14.7/Makefile linux-2.6.14.7-vs2.1.0-grsec-2.1.9/Makefile --- linux-2.6.14.7/Makefile 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/Makefile 2006-02-27 17:45:24.000000000 +0100 @@ -582,7 +582,7 @@ export MODLIB ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ +core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ grsecurity/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ diff -NurpP linux-2.6.14.7/arch/alpha/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/Kconfig --- linux-2.6.14.7/arch/alpha/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -609,6 +609,8 @@ source "arch/alpha/oprofile/Kconfig" source "arch/alpha/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/alpha/kernel/asm-offsets.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/asm-offsets.c --- linux-2.6.14.7/arch/alpha/kernel/asm-offsets.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/asm-offsets.c 2006-02-27 17:33:28.000000000 +0100 @@ -35,6 +35,7 @@ void foo(void) DEFINE(PT_PTRACED, PT_PTRACED); DEFINE(CLONE_VM, CLONE_VM); DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); + DEFINE(CLONE_KTHREAD, CLONE_KTHREAD); DEFINE(SIGCHLD, SIGCHLD); BLANK(); diff -NurpP linux-2.6.14.7/arch/alpha/kernel/entry.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/entry.S --- linux-2.6.14.7/arch/alpha/kernel/entry.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/entry.S 2006-02-27 17:33:28.000000000 +0100 @@ -645,7 +645,7 @@ kernel_thread: stq $2, 152($sp) /* HAE */ /* Shuffle FLAGS to the front; add CLONE_VM. */ - ldi $1, CLONE_VM|CLONE_UNTRACED + ldi $1, CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD; or $18, $1, $16 bsr $26, sys_clone @@ -874,22 +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_REAL_PARENT($2) -1: ldl $1, TASK_TGID($3) -#ifdef CONFIG_SMP - mov $3, $4 - mb - ldq $3, TASK_REAL_PARENT($2) - cmpeq $3, $4, $4 - beq $4, 1b -#endif - stq $1, 80($sp) - ldl $0, TASK_TGID($2) + lda $16, 96($sp) + jsr $26, do_getxpid + ldq $26, 0($sp) + + lda $sp, 16($sp) ret .end sys_getxpid diff -NurpP linux-2.6.14.7/arch/alpha/kernel/module.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/module.c --- linux-2.6.14.7/arch/alpha/kernel/module.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/module.c 2006-02-27 17:28:34.000000000 +0100 @@ -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 linux-2.6.14.7/arch/alpha/kernel/osf_sys.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/osf_sys.c --- linux-2.6.14.7/arch/alpha/kernel/osf_sys.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/osf_sys.c 2006-02-27 17:28:34.000000000 +0100 @@ -1274,6 +1274,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) @@ -1281,8 +1285,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 linux-2.6.14.7/arch/alpha/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/ptrace.c --- linux-2.6.14.7/arch/alpha/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -15,6 +15,7 @@ #include #include #include +#include #include #include @@ -289,6 +290,11 @@ do_sys_ptrace(long request, long pid, lo read_unlock(&tasklist_lock); if (!child) goto out_notsk; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out; + + if (gr_handle_ptrace(child, request)) + goto out; if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); diff -NurpP linux-2.6.14.7/arch/alpha/kernel/systbls.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/systbls.S --- linux-2.6.14.7/arch/alpha/kernel/systbls.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/kernel/systbls.S 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/arch/alpha/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/mm/fault.c --- linux-2.6.14.7/arch/alpha/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/mm/fault.c 2006-02-27 17:28:34.000000000 +0100 @@ -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 linux-2.6.14.7/arch/alpha/mm/init.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/mm/init.c --- linux-2.6.14.7/arch/alpha/mm/init.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/alpha/mm/init.c 2006-02-27 17:33:28.000000000 +0100 @@ -20,6 +20,7 @@ #include #include /* max_low_pfn */ #include +#include #include #include diff -NurpP linux-2.6.14.7/arch/arm/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/Kconfig --- linux-2.6.14.7/arch/arm/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -739,6 +739,8 @@ source "arch/arm/oprofile/Kconfig" source "arch/arm/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/arm/kernel/calls.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/kernel/calls.S --- linux-2.6.14.7/arch/arm/kernel/calls.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/kernel/calls.S 2006-02-27 17:33:28.000000000 +0100 @@ -327,7 +327,7 @@ __syscall_start: /* 310 */ .long sys_request_key .long sys_keyctl .long sys_semtimedop -/* vserver */ .long sys_ni_syscall + .long sys_vserver .long sys_ioprio_set /* 315 */ .long sys_ioprio_get .long sys_inotify_init diff -NurpP linux-2.6.14.7/arch/arm/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/kernel/process.c --- linux-2.6.14.7/arch/arm/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -436,7 +436,8 @@ pid_t kernel_thread(int (*fn)(void *), v regs.ARM_pc = (unsigned long)kernel_thread_helper; regs.ARM_cpsr = SVC_MODE; - return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); diff -NurpP linux-2.6.14.7/arch/arm/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/kernel/ptrace.c --- linux-2.6.14.7/arch/arm/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -809,6 +809,8 @@ asmlinkage int sys_ptrace(long request, 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) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/arm/mm/mmap.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/mm/mmap.c --- linux-2.6.14.7/arch/arm/mm/mmap.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm/mm/mmap.c 2006-02-27 17:28:34.000000000 +0100 @@ -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 linux-2.6.14.7/arch/arm26/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm26/Kconfig --- linux-2.6.14.7/arch/arm26/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm26/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -232,6 +232,8 @@ source "drivers/usb/Kconfig" source "arch/arm26/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/arm26/kernel/calls.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm26/kernel/calls.S --- linux-2.6.14.7/arch/arm26/kernel/calls.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm26/kernel/calls.S 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/arch/arm26/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm26/kernel/process.c --- linux-2.6.14.7/arch/arm26/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm26/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -369,7 +369,8 @@ pid_t kernel_thread(int (*fn)(void *), v regs.ARM_r3 = (unsigned long)do_exit; regs.ARM_pc = (unsigned long)kernel_thread_helper | MODE_SVC26; - return do_fork(flags|CLONE_VM|CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); diff -NurpP linux-2.6.14.7/arch/arm26/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm26/kernel/ptrace.c --- linux-2.6.14.7/arch/arm26/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/arm26/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -692,6 +692,8 @@ asmlinkage int sys_ptrace(long request, 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) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/cris/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/cris/Kconfig --- linux-2.6.14.7/arch/cris/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/cris/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -177,6 +177,8 @@ source "drivers/usb/Kconfig" source "arch/cris/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/cris/arch-v10/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/cris/arch-v10/kernel/process.c --- linux-2.6.14.7/arch/cris/arch-v10/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/cris/arch-v10/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -104,7 +104,8 @@ int kernel_thread(int (*fn)(void *), voi regs.dccr = 1 << I_DCCR_BITNR; /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } /* setup the child's kernel stack with a pt_regs and switch_stack on it. diff -NurpP linux-2.6.14.7/arch/cris/arch-v32/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/cris/arch-v32/kernel/process.c --- linux-2.6.14.7/arch/cris/arch-v32/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/cris/arch-v32/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -121,7 +121,8 @@ kernel_thread(int (*fn)(void *), void * regs.ccs = 1 << (I_CCS_BITNR + CCS_SHIFT); /* Create the new process. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } /* diff -NurpP linux-2.6.14.7/arch/frv/kernel/kernel_thread.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/frv/kernel/kernel_thread.S --- linux-2.6.14.7/arch/frv/kernel/kernel_thread.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/frv/kernel/kernel_thread.S 2006-02-27 17:33:28.000000000 +0100 @@ -13,6 +13,8 @@ #include #define CLONE_VM 0x00000100 /* set if VM shared between processes */ +#define CLONE_KTHREAD 0x10000000 /* kernel thread */ +#define CLONE_KT (CLONE_VM | CLONE_KTHREAD) /* kernel thread flags */ #define KERN_ERR "<3>" .section .rodata @@ -37,7 +39,7 @@ kernel_thread: # start by forking the current process, but with shared VM setlos.p #__NR_clone,gr7 ; syscall number - ori gr10,#CLONE_VM,gr8 ; first syscall arg [clone_flags] + ori gr10,#CLONE_KT,gr8 ; first syscall arg [clone_flags] sethi.p #0xe4e4,gr9 ; second syscall arg [newsp] setlo #0xe4e4,gr9 setlos.p #0,gr10 ; third syscall arg [parent_tidptr] diff -NurpP linux-2.6.14.7/arch/h8300/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/h8300/Kconfig --- linux-2.6.14.7/arch/h8300/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/h8300/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -191,6 +191,8 @@ source "fs/Kconfig" source "arch/h8300/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/h8300/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/h8300/kernel/process.c --- linux-2.6.14.7/arch/h8300/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/h8300/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -130,7 +130,7 @@ int kernel_thread(int (*fn)(void *), voi fs = get_fs(); set_fs (KERNEL_DS); - clone_arg = flags | CLONE_VM; + clone_arg = flags | CLONE_VM | CLONE_KTHREAD; __asm__("mov.l sp,er3\n\t" "sub.l er2,er2\n\t" "mov.l %2,er1\n\t" diff -NurpP linux-2.6.14.7/arch/h8300/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/h8300/kernel/ptrace.c --- linux-2.6.14.7/arch/h8300/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/h8300/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -81,6 +81,8 @@ asmlinkage int sys_ptrace(long request, 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) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/i386/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/Kconfig --- linux-2.6.14.7/arch/i386/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -397,7 +397,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 @@ -422,7 +422,7 @@ config X86_POPAD_OK config X86_ALIGNMENT_16 bool - depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 + depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK8 || MK7 || MK6 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 default y config X86_GOOD_APIC @@ -746,6 +746,46 @@ config HIGHMEM64G endchoice +choice + prompt "Memory Split User Space" + default SPLIT_3GB + help + A different Userspace/Kernel split allows you to + utilize up to alsmost 3GB of RAM without the requirement + for HIGHMEM. It also increases the available lowmem. + +config SPLIT_3GB + bool "3.0GB/1.0GB Kernel (Default)" + help + This is the default split of 3GB userspace to 1GB kernel + space, which will result in about 860MB of lowmem. + +config SPLIT_25GB + bool "2.5GB/1.5GB Kernel" + help + This split provides 2.5GB userspace and 1.5GB kernel + space, which will result in about 1370MB of lowmem. + +config SPLIT_2GB + bool "2.0GB/2.0GB Kernel" + help + This split provides 2GB userspace and 2GB kernel + space, which will result in about 1880MB of lowmem. + +config SPLIT_15GB + bool "1.5GB/2.5GB Kernel" + help + This split provides 1.5GB userspace and 2.5GB kernel + space, which will result in about 2390MB of lowmem. + +config SPLIT_1GB + bool "1.0GB/3.0GB Kernel" + help + This split provides 1GB userspace and 3GB kernel + space, which will result in about 2900MB of lowmem. + +endchoice + config HIGHMEM bool depends on HIGHMEM64G || HIGHMEM4G @@ -1196,7 +1236,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 @@ -1299,6 +1339,8 @@ source "arch/i386/oprofile/Kconfig" source "arch/i386/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/i386/boot/compressed/head.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/boot/compressed/head.S --- linux-2.6.14.7/arch/i386/boot/compressed/head.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/boot/compressed/head.S 2006-02-27 17:28:34.000000000 +0100 @@ -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 linux-2.6.14.7/arch/i386/boot/compressed/misc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/boot/compressed/misc.c --- linux-2.6.14.7/arch/i386/boot/compressed/misc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/boot/compressed/misc.c 2006-02-27 17:33:28.000000000 +0100 @@ -309,7 +309,7 @@ static void setup_normal_output_buffer(v #else if ((RM_ALT_MEM_K > RM_EXT_MEM_K ? RM_ALT_MEM_K : RM_EXT_MEM_K) < 1024) error("Less than 2MB of memory"); #endif - output_data = (char *)__PHYSICAL_START; /* Normally Points to 1M */ + output_data = (char *)PHYSICAL_START; /* Normally Points to 1M */ free_mem_end_ptr = (long)real_mode; } @@ -334,8 +334,8 @@ static void setup_output_buffer_if_we_ru low_buffer_size = low_buffer_end - LOW_BUFFER_START; high_loaded = 1; free_mem_end_ptr = (long)high_buffer_start; - if ( (__PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) { - high_buffer_start = (uch *)(__PHYSICAL_START + low_buffer_size); + if ((PHYSICAL_START + low_buffer_size) > ((ulg)high_buffer_start)) { + high_buffer_start = (uch *)(PHYSICAL_START + low_buffer_size); mv->hcount = 0; /* say: we need not to move high_buffer */ } else mv->hcount = -1; diff -NurpP linux-2.6.14.7/arch/i386/kernel/acpi/sleep.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/acpi/sleep.c --- linux-2.6.14.7/arch/i386/kernel/acpi/sleep.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/acpi/sleep.c 2006-02-27 17:28:35.000000000 +0100 @@ -10,6 +10,7 @@ #include #include #include +#include /* address in low memory of the wakeup routine. */ unsigned long acpi_wakeup_address = 0; diff -NurpP linux-2.6.14.7/arch/i386/kernel/apic.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/apic.c --- linux-2.6.14.7/arch/i386/kernel/apic.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/apic.c 2006-02-27 17:28:35.000000000 +0100 @@ -1150,7 +1150,7 @@ inline void smp_local_timer_interrupt(st } #ifdef CONFIG_SMP - update_process_times(user_mode_vm(regs)); + update_process_times(user_mode(regs)); #endif } diff -NurpP linux-2.6.14.7/arch/i386/kernel/apm.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/apm.c --- linux-2.6.14.7/arch/i386/kernel/apm.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/apm.c 2006-02-27 17:28:35.000000000 +0100 @@ -598,19 +598,39 @@ static u8 apm_bios_call(u32 func, u32 eb int cpu; struct desc_struct save_desc_40; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + cpus = apm_save_cpus(); - cpu = get_cpu(); - save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8]; - per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc; +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(flags, cr0); +#endif + + save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; + cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + +#ifndef CONFIG_PAX_KERNEXEC local_save_flags(flags); APM_DO_CLI; +#endif + APM_DO_SAVE_SEGS; apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi); APM_DO_RESTORE_SEGS; + +#ifndef CONFIG_PAX_KERNEXEC local_irq_restore(flags); - per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = save_desc_40; +#endif + + cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(flags, cr0); +#endif + put_cpu(); apm_restore_cpus(cpus); @@ -640,20 +660,39 @@ static u8 apm_bios_call_simple(u32 func, int cpu; struct desc_struct save_desc_40; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif cpus = apm_save_cpus(); - cpu = get_cpu(); - save_desc_40 = per_cpu(cpu_gdt_table, cpu)[0x40 / 8]; - per_cpu(cpu_gdt_table, cpu)[0x40 / 8] = bad_bios_desc; +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(flags, cr0); +#endif + + save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; + cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + +#ifndef CONFIG_PAX_KERNEXEC local_save_flags(flags); APM_DO_CLI; +#endif + APM_DO_SAVE_SEGS; error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax); APM_DO_RESTORE_SEGS; + +#ifndef CONFIG_PAX_KERNEXEC local_irq_restore(flags); - __get_cpu_var(cpu_gdt_table)[0x40 / 8] = save_desc_40; +#endif + + cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(flags, cr0); +#endif + put_cpu(); apm_restore_cpus(cpus); return error; @@ -2295,35 +2334,35 @@ static int __init apm_init(void) apm_bios_entry.segment = APM_CS; for (i = 0; i < NR_CPUS; i++) { - set_base(per_cpu(cpu_gdt_table, i)[APM_CS >> 3], + set_base(cpu_gdt_table[i][APM_CS >> 3], __va((unsigned long)apm_info.bios.cseg << 4)); - set_base(per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], + set_base(cpu_gdt_table[i][APM_CS_16 >> 3], __va((unsigned long)apm_info.bios.cseg_16 << 4)); - set_base(per_cpu(cpu_gdt_table, i)[APM_DS >> 3], + set_base(cpu_gdt_table[i][APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); #ifndef APM_RELAX_SEGMENTS if (apm_info.bios.version == 0x100) { #endif /* For ASUS motherboard, Award BIOS rev 110 (and others?) */ - _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 - 1); + _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 - 1); /* For some unknown machine. */ - _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], 64 * 1024 - 1); + _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], 64 * 1024 - 1); /* For the DEC Hinote Ultra CT475 (and others?) */ - _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], 64 * 1024 - 1); + _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], 64 * 1024 - 1); #ifndef APM_RELAX_SEGMENTS } else { - _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], + _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], (apm_info.bios.cseg_len - 1) & 0xffff); - _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS_16 >> 3], + _set_limit((char *)&cpu_gdt_table[i][APM_CS_16 >> 3], (apm_info.bios.cseg_16_len - 1) & 0xffff); - _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_DS >> 3], + _set_limit((char *)&cpu_gdt_table[i][APM_DS >> 3], (apm_info.bios.dseg_len - 1) & 0xffff); /* workaround for broken BIOSes */ if (apm_info.bios.cseg_len <= apm_info.bios.offset) - _set_limit((char *)&per_cpu(cpu_gdt_table, i)[APM_CS >> 3], 64 * 1024 -1); + _set_limit((char *)&cpu_gdt_table[i][APM_CS >> 3], 64 * 1024 -1); if (apm_info.bios.dseg_len <= 0x40) { /* 0x40 * 4kB == 64kB */ /* for the BIOS that assumes granularity = 1 */ - per_cpu(cpu_gdt_table, i)[APM_DS >> 3].b |= 0x800000; + cpu_gdt_table[i][APM_DS >> 3].b |= 0x800000; printk(KERN_NOTICE "apm: we set the granularity of dseg.\n"); } } diff -NurpP linux-2.6.14.7/arch/i386/kernel/cpu/common.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/cpu/common.c --- linux-2.6.14.7/arch/i386/kernel/cpu/common.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/cpu/common.c 2006-02-27 17:28:35.000000000 +0100 @@ -18,8 +18,7 @@ #include "cpu.h" -DEFINE_PER_CPU(struct desc_struct, cpu_gdt_table[GDT_ENTRIES]); -EXPORT_PER_CPU_SYMBOL(cpu_gdt_table); +EXPORT_SYMBOL_GPL(cpu_gdt_table); DEFINE_PER_CPU(unsigned char, cpu_16bit_stack[CPU_16BIT_STACK_SIZE]); EXPORT_PER_CPU_SYMBOL(cpu_16bit_stack); @@ -376,6 +375,10 @@ void __devinit identify_cpu(struct cpuin if (this_cpu->c_init) this_cpu->c_init(c); +#if defined(CONFIG_PAX_SEGMEXEC) || defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_NOVSYSCALL) + clear_bit(X86_FEATURE_SEP, c->x86_capability); +#endif + /* Disable the PN if appropriate */ squash_the_stupid_serial_number(c); @@ -571,7 +574,7 @@ void __init early_cpu_init(void) void __devinit 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; __u32 stk16_off = (__u32)&per_cpu(cpu_16bit_stack, cpu); @@ -594,24 +597,22 @@ void __devinit cpu_init(void) * Initialize the per-CPU GDT with the boot GDT, * and set up the GDT descriptor: */ - memcpy(&per_cpu(cpu_gdt_table, cpu), cpu_gdt_table, - GDT_SIZE); + if (cpu) + memcpy(cpu_gdt_table[cpu], cpu_gdt_table[0], GDT_SIZE); /* Set up GDT entry for 16bit stack */ - *(__u64 *)&(per_cpu(cpu_gdt_table, cpu)[GDT_ENTRY_ESPFIX_SS]) |= + *(__u64 *)&(cpu_gdt_table[cpu][GDT_ENTRY_ESPFIX_SS]) |= ((((__u64)stk16_off) << 16) & 0x000000ffffff0000ULL) | ((((__u64)stk16_off) << 32) & 0xff00000000000000ULL) | (CPU_16BIT_STACK_SIZE - 1); cpu_gdt_descr[cpu].size = GDT_SIZE - 1; - cpu_gdt_descr[cpu].address = - (unsigned long)&per_cpu(cpu_gdt_table, cpu); + cpu_gdt_descr[cpu].address = (unsigned long)cpu_gdt_table[cpu]; /* * Set up the per-thread TLS descriptor cache: */ - memcpy(thread->tls_array, &per_cpu(cpu_gdt_table, cpu), - GDT_ENTRY_TLS_ENTRIES * 8); + memcpy(thread->tls_array, cpu_gdt_table[cpu], GDT_ENTRY_TLS_ENTRIES * 8); load_gdt(&cpu_gdt_descr[cpu]); load_idt(&idt_descr); @@ -633,7 +634,7 @@ void __devinit 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); /* Set up doublefault TSS pointer in the GDT */ __set_tss_desc(cpu, GDT_ENTRY_DOUBLEFAULT_TSS, &doublefault_tss); diff -NurpP linux-2.6.14.7/arch/i386/kernel/cpu/mtrr/if.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/cpu/mtrr/if.c --- linux-2.6.14.7/arch/i386/kernel/cpu/mtrr/if.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/cpu/mtrr/if.c 2006-02-27 17:28:35.000000000 +0100 @@ -105,7 +105,7 @@ mtrr_write(struct file *file, const char if (!len) return -EINVAL; memset(line, 0, LINE_SIZE); - if (len > LINE_SIZE) + if (!len || len > LINE_SIZE) len = LINE_SIZE; if (copy_from_user(line, buf, len - 1)) return -EFAULT; diff -NurpP linux-2.6.14.7/arch/i386/kernel/doublefault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/doublefault.c --- linux-2.6.14.7/arch/i386/kernel/doublefault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/doublefault.c 2006-02-27 17:28:35.000000000 +0100 @@ -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) diff -NurpP linux-2.6.14.7/arch/i386/kernel/efi.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/efi.c --- linux-2.6.14.7/arch/i386/kernel/efi.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/efi.c 2006-02-27 17:28:35.000000000 +0100 @@ -64,78 +64,59 @@ 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[4]; -static void efi_call_phys_prelog(void) +static void __init efi_call_phys_prelog(void) { - unsigned long cr4; - unsigned long temp; - spin_lock(&efi_rt_lock); local_irq_save(efi_rt_eflags); - /* - * 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(); + efi_bak_pg_dir_pointer[0] = swapper_pg_dir[0]; + swapper_pg_dir[0] = swapper_pg_dir[USER_PTRS_PER_PGD]; + +#ifndef CONFIG_X86_PAE + efi_bak_pg_dir_pointer[1] = swapper_pg_dir[1]; + swapper_pg_dir[1] = swapper_pg_dir[USER_PTRS_PER_PGD+1]; + efi_bak_pg_dir_pointer[2] = swapper_pg_dir[2]; + swapper_pg_dir[2] = swapper_pg_dir[USER_PTRS_PER_PGD+2]; + efi_bak_pg_dir_pointer[3] = swapper_pg_dir[3]; + swapper_pg_dir[3] = swapper_pg_dir[USER_PTRS_PER_PGD+3]; +#endif - 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; - } /* * After the lock is released, the original page table is restored. */ - local_flush_tlb(); + __flush_tlb_all(); 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; - cpu_gdt_descr[0].address = (unsigned long) __va(cpu_gdt_descr[0].address); load_gdt(&cpu_gdt_descr[0]); - cr4 = read_cr4(); - 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; - } + swapper_pg_dir[0] = efi_bak_pg_dir_pointer[0]; + +#ifndef CONFIG_X86_PAE + swapper_pg_dir[1] = efi_bak_pg_dir_pointer[1]; + swapper_pg_dir[2] = efi_bak_pg_dir_pointer[2]; + swapper_pg_dir[3] = efi_bak_pg_dir_pointer[3]; +#endif /* * 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, @@ -151,7 +132,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 linux-2.6.14.7/arch/i386/kernel/efi_stub.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/efi_stub.S --- linux-2.6.14.7/arch/i386/kernel/efi_stub.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/efi_stub.S 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/i386/kernel/entry.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/entry.S --- linux-2.6.14.7/arch/i386/kernel/entry.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/entry.S 2006-02-27 17:28:35.000000000 +0100 @@ -213,6 +213,13 @@ 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 @@ -243,6 +250,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 @@ -561,9 +572,9 @@ nmi_debug_stack_check: cmpw $__KERNEL_CS,16(%esp) jne nmi_stack_correct cmpl $debug - 1,(%esp) - jle nmi_stack_correct + jbe nmi_stack_correct cmpl $debug_esp_fix_insn,(%esp) - jle nmi_debug_stack_fixup + jbe nmi_debug_stack_fixup nmi_debug_stack_fixup: FIX_STACK(24,nmi_stack_correct, 1) jmp nmi_stack_correct diff -NurpP linux-2.6.14.7/arch/i386/kernel/head.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/head.S --- linux-2.6.14.7/arch/i386/kernel/head.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/head.S 2006-02-27 17:28:35.000000000 +0100 @@ -48,6 +48,12 @@ /* + * Real beginning of normal "text" segment + */ +ENTRY(stext) +ENTRY(_stext) + +/* * 32-bit kernel entrypoint; only used by the boot CPU. On entry, * %esi points to the real-mode code as a 32-bit pointer. * CS and DS must be 4 GB flat segments, but we don't depend on @@ -67,6 +73,19 @@ ENTRY(startup_32) movl %eax,%fs movl %eax,%gs +#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 +133,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)); +#else +page_pde_offset = ((__PAGE_OFFSET >> 22) * (4096 / PTRS_PER_PTE)); +#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 +191,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 +211,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 +240,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 +270,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 */ /* @@ -408,32 +447,50 @@ ignore_int: #endif iret -/* - * Real beginning of normal "text" segment - */ -ENTRY(stext) -ENTRY(_stext) - -/* - * BSS section - */ -.section ".bss.page_aligned","w" +.section .data.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 .data.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 .rodata.empty_zero_page,"a",@progbits ENTRY(empty_zero_page) .fill 4096,1,0 /* - * This starts the data section. - */ -.data + * The IDT has to be page-aligned to simplify the Pentium + * F0 0F bug workaround.. We have a special link segment + * for this. + */ +.section .rodata.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" @@ -475,8 +532,8 @@ 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. @@ -495,28 +552,27 @@ ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* 0x4b reserved */ .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 */ /* Segments used for calling PnP BIOS */ - .quad 0x00c09a0000000000 /* 0x90 32-bit code */ - .quad 0x00809a0000000000 /* 0x98 16-bit code */ - .quad 0x0080920000000000 /* 0xa0 16-bit data */ - .quad 0x0080920000000000 /* 0xa8 16-bit data */ - .quad 0x0080920000000000 /* 0xb0 16-bit data */ + .quad 0x00c09b0000000000 /* 0x90 32-bit code */ + .quad 0x00809b0000000000 /* 0x98 16-bit code */ + .quad 0x0080930000000000 /* 0xa0 16-bit data */ + .quad 0x0080930000000000 /* 0xa8 16-bit data */ + .quad 0x0080930000000000 /* 0xb0 16-bit data */ /* * The APM segments have byte granularity and their bases * and limits are set at run time. */ - .quad 0x00409a0000000000 /* 0xb8 APM CS code */ - .quad 0x00009a0000000000 /* 0xc0 APM CS 16 code (16 bit) */ - .quad 0x0040920000000000 /* 0xc8 APM DS data */ + .quad 0x00409b0000000000 /* 0xb8 APM CS code */ + .quad 0x00009b0000000000 /* 0xc0 APM CS 16 code (16 bit) */ + .quad 0x0040930000000000 /* 0xc8 APM DS data */ .quad 0x0000920000000000 /* 0xd0 - ESPFIX 16-bit SS */ .quad 0x0000000000000000 /* 0xd8 - unused */ @@ -525,3 +581,6 @@ ENTRY(cpu_gdt_table) .quad 0x0000000000000000 /* 0xf0 - unused */ .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ +#ifdef CONFIG_SMP + .fill (NR_CPUS-1)*GDT_ENTRIES,8,0 /* other CPU's GDT */ +#endif diff -NurpP linux-2.6.14.7/arch/i386/kernel/init_task.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/init_task.c --- linux-2.6.14.7/arch/i386/kernel/init_task.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/init_task.c 2006-02-27 17:28:35.000000000 +0100 @@ -42,5 +42,4 @@ 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_maxaligned_in_smp = INIT_TSS; - +struct tss_struct init_tss[NR_CPUS] ____cacheline_maxaligned_in_smp = { [0 ... NR_CPUS-1] = INIT_TSS }; diff -NurpP linux-2.6.14.7/arch/i386/kernel/ioport.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/ioport.c --- linux-2.6.14.7/arch/i386/kernel/ioport.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/ioport.c 2006-02-27 17:28:35.000000000 +0100 @@ -15,6 +15,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) @@ -63,9 +64,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(), @@ -87,7 +95,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); @@ -138,8 +146,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 linux-2.6.14.7/arch/i386/kernel/irq.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/irq.c --- linux-2.6.14.7/arch/i386/kernel/irq.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/irq.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/i386/kernel/ldt.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/ldt.c --- linux-2.6.14.7/arch/i386/kernel/ldt.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/ldt.c 2006-02-27 17:28:35.000000000 +0100 @@ -102,6 +102,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; } @@ -159,7 +172,7 @@ static int read_default_ldt(void __user { int err; unsigned long size; - void *address; + const void *address; err = 0; address = &default_ldt[0]; @@ -214,6 +227,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 linux-2.6.14.7/arch/i386/kernel/module.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/module.c --- linux-2.6.14.7/arch/i386/kernel/module.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/module.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 flags, cr0; + + pax_open_kernel(flags, cr0); + memset(tmp->addr, 0xCC, tmp->size); + pax_close_kernel(flags, 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 linux-2.6.14.7/arch/i386/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/process.c --- linux-2.6.14.7/arch/i386/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -357,7 +357,8 @@ int kernel_thread(int (*fn)(void *), voi regs.eflags = X86_EFLAGS_IF | X86_EFLAGS_SF | X86_EFLAGS_PF | 0x2; /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); @@ -379,7 +380,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; @@ -406,6 +407,9 @@ void flush_thread(void) */ kprobe_flush_task(tsk); + __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)); /* @@ -502,6 +506,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); @@ -565,9 +574,8 @@ EXPORT_SYMBOL(dump_thread); int dump_task_regs(struct task_struct *tsk, elf_gregset_t *regs) { struct pt_regs ptregs; - - ptregs = *(struct pt_regs *) - ((unsigned long)tsk->thread_info+THREAD_SIZE - sizeof(ptregs)); + + ptregs = *(struct pt_regs *)(tsk->thread.esp0 - sizeof(ptregs)); ptregs.xcs &= 0xffff; ptregs.xds &= 0xffff; ptregs.xes &= 0xffff; @@ -669,7 +677,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 */ @@ -692,11 +704,19 @@ struct task_struct fastcall * __switch_t savesegment(fs, prev->fs); savesegment(gs, prev->gs); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel_noirq(cr0); +#endif + /* * Load the per-thread Thread-Local Storage descriptor. */ load_TLS(next, cpu); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel_noirq(cr0); +#endif + /* * Restore %fs and %gs if needed. * @@ -851,8 +871,18 @@ asmlinkage int sys_set_thread_area(struc struct desc_struct *desc; int cpu, idx; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long flags, 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; /* @@ -884,8 +914,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(flags, cr0); +#endif + load_TLS(t, cpu); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(flags, cr0); +#endif + put_cpu(); return 0; @@ -941,9 +980,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 linux-2.6.14.7/arch/i386/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/ptrace.c --- linux-2.6.14.7/arch/i386/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -339,6 +340,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; @@ -383,11 +389,16 @@ asmlinkage int sys_ptrace(long request, 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) /* you may not mess 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; @@ -466,6 +477,17 @@ asmlinkage int sys_ptrace(long request, 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 @@ -682,7 +704,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 linux-2.6.14.7/arch/i386/kernel/reboot.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/reboot.c --- linux-2.6.14.7/arch/i386/kernel/reboot.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/reboot.c 2006-02-27 17:28:35.000000000 +0100 @@ -129,18 +129,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 }, diff -NurpP linux-2.6.14.7/arch/i386/kernel/setup.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/setup.c --- linux-2.6.14.7/arch/i386/kernel/setup.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/setup.c 2006-02-27 17:33:28.000000000 +0100 @@ -59,6 +59,7 @@ #include #include "setup_arch_pre.h" #include +#include /* Forward Declaration. */ void __init find_max_pfn(void); @@ -85,7 +86,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; @@ -1176,8 +1181,8 @@ void __init setup_bootmem_allocator(void * the (very unlikely) case of us accidentally initializing the * bootmem allocator with an invalid RAM area. */ - reserve_bootmem(__PHYSICAL_START, (PFN_PHYS(min_low_pfn) + - bootmap_size + PAGE_SIZE-1) - (__PHYSICAL_START)); + reserve_bootmem(PHYSICAL_START, (PFN_PHYS(min_low_pfn) + + bootmap_size + PAGE_SIZE-1) - (PHYSICAL_START)); /* * reserve physical page 0 - it's a special BIOS page on many boxes, @@ -1428,12 +1433,22 @@ void apply_alternatives(void *start, voi struct alt_instr *a; int diff, i, k; unsigned char **noptable = intel_nops; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long flags, cr0; +#endif + for (i = 0; noptypes[i].cpuid >= 0; i++) { if (boot_cpu_has(noptypes[i].cpuid)) { noptable = noptypes[i].noptable; break; } } + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(flags, cr0); +#endif + for (a = start; (void *)a < end; a++) { if (!boot_cpu_has(a->cpuid)) continue; @@ -1448,6 +1463,11 @@ void apply_alternatives(void *start, voi memcpy(a->instr + i, noptable[k], k); } } + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(flags, cr0); +#endif + } void __init alternative_instructions(void) @@ -1526,14 +1546,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 linux-2.6.14.7/arch/i386/kernel/signal.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/signal.c --- linux-2.6.14.7/arch/i386/kernel/signal.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/signal.c 2006-02-27 17:28:35.000000000 +0100 @@ -384,7 +384,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; @@ -480,7 +490,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); @@ -612,7 +633,7 @@ int fastcall do_signal(struct pt_regs *r * before reaching here, so testing against kernel * CS suffices. */ - if (!user_mode(regs)) + if (!user_mode_novm(regs)) return 1; if (try_to_freeze()) diff -NurpP linux-2.6.14.7/arch/i386/kernel/sys_i386.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/sys_i386.c --- linux-2.6.14.7/arch/i386/kernel/sys_i386.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/sys_i386.c 2006-02-27 17:33:28.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -106,6 +107,109 @@ out: return err; } +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; @@ -217,7 +321,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; } @@ -225,6 +329,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; @@ -233,15 +338,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); @@ -250,3 +356,84 @@ asmlinkage int sys_olduname(struct oldol return error; } +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 & 0x03FFFFFFUL; +#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; + } + } +} diff -NurpP linux-2.6.14.7/arch/i386/kernel/syscall_table.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/syscall_table.S --- linux-2.6.14.7/arch/i386/kernel/syscall_table.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/syscall_table.S 2006-02-27 17:33:28.000000000 +0100 @@ -1,4 +1,4 @@ -.data +.section .rodata,"a",@progbits ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit @@ -273,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 linux-2.6.14.7/arch/i386/kernel/sysenter.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/sysenter.c --- linux-2.6.14.7/arch/i386/kernel/sysenter.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/sysenter.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/i386/kernel/traps.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/traps.c --- linux-2.6.14.7/arch/i386/kernel/traps.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/traps.c 2006-02-27 17:33:28.000000000 +0100 @@ -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); @@ -116,6 +113,7 @@ static inline unsigned long print_contex unsigned long *stack, unsigned long ebp) { unsigned long addr; + int i = kstack_depth_to_print; #ifdef CONFIG_FRAME_POINTER while (valid_stack_ptr(tinfo, (void *)ebp)) { @@ -124,6 +122,7 @@ static inline unsigned long print_contex print_symbol("%s", addr); printk("\n"); ebp = *(unsigned long *)ebp; + --i; } #else while (valid_stack_ptr(tinfo, stack)) { @@ -132,6 +131,7 @@ static inline unsigned long print_contex printk(" [<%08lx>]", addr); print_symbol(" %s", addr); printk("\n"); + --i; } } #endif @@ -241,7 +241,7 @@ void show_registers(struct pt_regs *regs printk("Code: "); - eip = (u8 __user *)regs->eip - 43; + eip = (u8 __user *)regs->eip - 43 + __KERNEL_TEXT_OFFSET; for (i = 0; i < 64; i++, eip++) { unsigned char c; @@ -249,7 +249,7 @@ 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); @@ -266,7 +266,7 @@ static void handle_BUG(struct pt_regs *r char c; unsigned long eip; - eip = regs->eip; + eip = regs->eip + __KERNEL_TEXT_OFFSET; if (eip < PAGE_OFFSET) goto no_bug; @@ -307,6 +307,8 @@ void die(const char * str, struct pt_reg }; static int die_counter; + vxh_throw_oops(); + if (die.lock_owner != raw_smp_processor_id()) { console_verbose(); spin_lock_irq(&die.lock); @@ -333,8 +335,9 @@ void die(const char * str, struct pt_reg #endif if (nl) printk("\n"); - notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); + notify_die(DIE_OOPS, (char *)str, regs, err, 255, SIGSEGV); show_registers(regs); + vxh_dump_history(); } else printk(KERN_ERR "Recursive die() failure, output suppressed\n"); @@ -358,7 +361,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); } @@ -376,7 +379,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: { @@ -464,7 +467,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; /* @@ -499,9 +502,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); @@ -517,6 +536,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); } } @@ -747,7 +773,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; } @@ -1037,7 +1063,18 @@ do { \ */ void set_intr_gate(unsigned int n, void *addr) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long flags, cr0; + pax_open_kernel(flags, cr0); +#endif + _set_gate(idt_table+n,14,0,addr,__KERNEL_CS); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(flags, cr0); +#endif + } /* diff -NurpP linux-2.6.14.7/arch/i386/kernel/vm86.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/vm86.c --- linux-2.6.14.7/arch/i386/kernel/vm86.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/vm86.c 2006-02-27 17:28:35.000000000 +0100 @@ -121,7 +121,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 linux-2.6.14.7/arch/i386/kernel/vmlinux.lds.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/vmlinux.lds.S --- linux-2.6.14.7/arch/i386/kernel/vmlinux.lds.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/kernel/vmlinux.lds.S 2006-02-27 17:28:35.000000000 +0100 @@ -4,9 +4,18 @@ #define LOAD_OFFSET __PAGE_OFFSET +#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) @@ -15,67 +24,17 @@ 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 */ + phys_startup_32 = startup_32 - LOAD_OFFSET + __KERNEL_TEXT_OFFSET; - . = ALIGN(16); /* Exception table */ - __start___ex_table = .; - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { *(__ex_table) } - __stop___ex_table = .; - - RODATA - - /* 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) - } - /* 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 = .; @@ -107,9 +66,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 = .; @@ -119,10 +76,112 @@ SECTIONS __per_cpu_start = .; .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { *(.data.percpu) } __per_cpu_end = .; + + /* read-only */ + + . = ALIGN(4096); + .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); - __init_end = .; +#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) { + *(.rodata.empty_zero_page) + *(.rodata.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) + } + + . = ALIGN(4096); + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + +#ifdef CONFIG_X86_PAE + *(.data.swapper_pm_dir) +#endif + + *(.data.swapper_pg_dir) + } + + _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 linux-2.6.14.7/arch/i386/mach-voyager/voyager_smp.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mach-voyager/voyager_smp.c --- linux-2.6.14.7/arch/i386/mach-voyager/voyager_smp.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mach-voyager/voyager_smp.c 2006-02-27 17:28:35.000000000 +0100 @@ -1294,7 +1294,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 linux-2.6.14.7/arch/i386/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/fault.c --- linux-2.6.14.7/arch/i386/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/fault.c 2006-02-27 17:28:35.000000000 +0100 @@ -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, @@ -108,7 +113,7 @@ static inline unsigned long get_segment_ desc = (void *)desc + (seg & ~7); } else { /* Must disable preemption while reading the GDT. */ - desc = (u32 *)&per_cpu(cpu_gdt_table, get_cpu()); + desc = (u32 *)&cpu_gdt_table[get_cpu()]; desc = (void *)desc + (seg & ~7); } @@ -214,6 +219,31 @@ 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 +/* PaX: called with the page_table_lock spinlock held */ +static inline pte_t * pax_get_pte(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 pte_offset_map(pmd, address); +} +#endif + /* * This routine handles page faults. It determines the address, * and the problem, and then passes it off to one of the appropriate @@ -231,9 +261,13 @@ 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 + pte_t *pte; + unsigned char pte_mask; +#endif + /* get the address */ address = read_cr2(); @@ -245,6 +279,7 @@ fastcall void __kprobes do_page_fault(st local_irq_enable(); tsk = current; + mm = tsk->mm; si_code = SEGV_MAPERR; @@ -271,14 +306,98 @@ fastcall void __kprobes do_page_fault(st goto bad_area_nosemaphore; } - 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; + +#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 */ + 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); + } + + spin_lock(&mm->page_table_lock); + pte = pax_get_pte(mm, address); + if (unlikely(!pte || !(pte_val(*pte) & _PAGE_PRESENT) || pte_user(*pte))) { + pte_unmap(pte); + spin_unlock(&mm->page_table_lock); + goto not_pax_fault; + } + + if (unlikely((error_code & 2) && !pte_write(*pte))) { + /* write attempt to a protected page in user mode */ + pte_unmap(pte); + spin_unlock(&mm->page_table_lock); + 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(pte); + spin_unlock(&mm->page_table_lock); + return; + } + + pte_mask = _PAGE_ACCESSED | _PAGE_USER | ((error_code & 2) << (_PAGE_BIT_DIRTY-1)); + + /* + * PaX: fill DTLB with user rights and retry + */ + __asm__ __volatile__ ( + "orb %2,%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,%1\n" + : + : "m" (*(char*)address), "m" (*(char*)pte), "q" (pte_mask), "i" (_PAGE_USER) + : "memory", "cc"); + pte_unmap(pte); + spin_unlock(&mm->page_table_lock); + return; + +not_pax_fault: +#endif /* When running in the kernel we expect faults to occur only to * addresses in user space. All other faults represent errors in the @@ -298,7 +417,7 @@ 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); } @@ -387,6 +506,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) { /* @@ -450,28 +600,55 @@ no_context: #endif if (address < PAGE_SIZE) printk(KERN_ALERT "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 "Unable to handle kernel paging request"); printk(" at virtual address %08lx\n",address); printk(KERN_ALERT " printing eip:\n"); printk("%08lx\n", regs->eip); - page = read_cr3(); - page = ((unsigned long *) __va(page))[address >> 22]; - 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. - */ + { + 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) { - 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; @@ -521,7 +698,7 @@ vmalloc_fault: * Do _not_ use "tsk" here. We might be inside * an interrupt in the middle of a task switch.. */ - int index = pgd_index(address); + unsigned long index = pgd_index(address); unsigned long pgd_paddr; pgd_t *pgd, *pgd_k; pud_t *pud, *pud_k; @@ -558,3 +735,105 @@ vmalloc_fault: return; } } + +#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 linux-2.6.14.7/arch/i386/mm/hugetlbpage.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/hugetlbpage.c --- linux-2.6.14.7/arch/i386/mm/hugetlbpage.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/hugetlbpage.c 2006-02-27 17:28:35.000000000 +0100 @@ -133,7 +133,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; @@ -147,7 +152,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. @@ -175,9 +180,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) @@ -187,7 +191,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; @@ -229,16 +233,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() @@ -264,16 +258,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 linux-2.6.14.7/arch/i386/mm/init.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/init.c --- linux-2.6.14.7/arch/i386/mm/init.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/init.c 2006-02-27 17:28:35.000000000 +0100 @@ -39,6 +39,7 @@ #include #include #include +#include unsigned int __VMALLOC_RESERVE = 128 << 20; @@ -48,30 +49,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. */ @@ -79,7 +56,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(); @@ -114,8 +95,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++) { @@ -128,11 +107,12 @@ 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; + if (start > (unsigned long)_etext + __KERNEL_TEXT_OFFSET || + end <= (unsigned long)_sinittext + __KERNEL_TEXT_OFFSET) + return 0; + return 1; } /* @@ -144,26 +124,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)); @@ -172,7 +150,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)); @@ -310,13 +288,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); @@ -340,17 +311,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 @@ -392,7 +352,6 @@ void zap_low_mappings (void) flush_tlb_all(); } -static int disable_nx __initdata = 0; u64 __supported_pte_mask __read_mostly = ~_PAGE_NX; /* @@ -406,11 +365,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; } } @@ -419,17 +376,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); } } @@ -481,14 +434,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(); @@ -580,7 +525,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); @@ -597,10 +542,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(); @@ -671,6 +612,36 @@ void free_initmem(void) { unsigned long addr; +#ifdef CONFIG_PAX_KERNEXEC + /* PaX: limit KERNEL_CS to actual size */ + unsigned long 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++) { + cpu_gdt_table[cpu][GDT_ENTRY_KERNEL_CS].a = (cpu_gdt_table[cpu][GDT_ENTRY_KERNEL_CS].a & 0xFFFF0000UL) | (limit & 0x0FFFFUL); + cpu_gdt_table[cpu][GDT_ENTRY_KERNEL_CS].b = (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 + addr = (unsigned long)(&__init_begin); for (; addr < (unsigned long)(&__init_end); addr += PAGE_SIZE) { ClearPageReserved(virt_to_page(addr)); diff -NurpP linux-2.6.14.7/arch/i386/mm/mmap.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/mmap.c --- linux-2.6.14.7/arch/i386/mm/mmap.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/mmap.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/i386/mm/pageattr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/pageattr.c --- linux-2.6.14.7/arch/i386/mm/pageattr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/mm/pageattr.c 2006-02-27 17:28:35.000000000 +0100 @@ -13,6 +13,7 @@ #include #include #include +#include static DEFINE_SPINLOCK(cpa_lock); static struct list_head df_list = LIST_HEAD_INIT(df_list); diff -NurpP linux-2.6.14.7/arch/i386/oprofile/backtrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/oprofile/backtrace.c --- linux-2.6.14.7/arch/i386/oprofile/backtrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/oprofile/backtrace.c 2006-02-27 17:28:35.000000000 +0100 @@ -91,7 +91,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_backtrace(head); return; diff -NurpP linux-2.6.14.7/arch/i386/pci/pcbios.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/pci/pcbios.c --- linux-2.6.14.7/arch/i386/pci/pcbios.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/pci/pcbios.c 2006-02-27 17:28:35.000000000 +0100 @@ -8,7 +8,6 @@ #include "pci.h" #include "pci-functions.h" - /* BIOS32 signature: "_32_" */ #define BIOS32_SIGNATURE (('_' << 0) + ('3' << 8) + ('2' << 16) + ('_' << 24)) diff -NurpP linux-2.6.14.7/arch/i386/power/cpu.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/power/cpu.c --- linux-2.6.14.7/arch/i386/power/cpu.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/i386/power/cpu.c 2006-02-27 17:28:35.000000000 +0100 @@ -64,7 +64,7 @@ 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. */ @@ -94,7 +94,7 @@ void __restore_processor_state(struct sa write_cr4(ctxt->cr4); write_cr3(ctxt->cr3); write_cr2(ctxt->cr2); - write_cr2(ctxt->cr0); + write_cr0(ctxt->cr0); /* * now restore the descriptor tables to their proper values diff -NurpP linux-2.6.14.7/arch/ia64/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/Kconfig --- linux-2.6.14.7/arch/ia64/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -408,6 +408,8 @@ source "arch/ia64/oprofile/Kconfig" source "arch/ia64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/ia64/ia32/binfmt_elf32.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/ia32/binfmt_elf32.c --- linux-2.6.14.7/arch/ia64/ia32/binfmt_elf32.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/ia32/binfmt_elf32.c 2006-02-27 17:33:28.000000000 +0100 @@ -43,6 +43,17 @@ static void elf32_set_personality (void) #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" @@ -199,7 +210,7 @@ ia64_elf32_init (struct pt_regs *regs) int ia32_setup_arg_pages (struct linux_binprm *bprm, int executable_stack) { - unsigned long stack_base; + unsigned long stack_base, grow; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; int i, ret; @@ -236,7 +247,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 linux-2.6.14.7/arch/ia64/ia32/ia32_entry.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/ia32/ia32_entry.S --- linux-2.6.14.7/arch/ia64/ia32/ia32_entry.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/ia32/ia32_entry.S 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/arch/ia64/ia32/ia32priv.h linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/ia32/ia32priv.h --- linux-2.6.14.7/arch/ia64/ia32/ia32priv.h 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/ia32/ia32priv.h 2006-02-27 17:28:35.000000000 +0100 @@ -306,10 +306,17 @@ struct old_linux32_dirent { #define ELF_ARCH EM_386 #define IA32_PAGE_OFFSET 0xc0000000 -#define IA32_STACK_TOP IA32_PAGE_OFFSET #define IA32_GATE_OFFSET IA32_PAGE_OFFSET #define IA32_GATE_END IA32_PAGE_OFFSET + PAGE_SIZE +#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) + /* * The system segments (GDT, TSS, LDT) have to be mapped below 4GB so the IA-32 engine can * access them. diff -NurpP linux-2.6.14.7/arch/ia64/kernel/asm-offsets.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/asm-offsets.c --- linux-2.6.14.7/arch/ia64/kernel/asm-offsets.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/asm-offsets.c 2006-02-27 17:33:28.000000000 +0100 @@ -192,6 +192,7 @@ void foo(void) /* for assembly files which can't include sched.h: */ DEFINE(IA64_CLONE_VFORK, CLONE_VFORK); DEFINE(IA64_CLONE_VM, CLONE_VM); + DEFINE(IA64_CLONE_KTHREAD, CLONE_KTHREAD); BLANK(); DEFINE(IA64_CPUINFO_NSEC_PER_CYC_OFFSET, diff -NurpP linux-2.6.14.7/arch/ia64/kernel/entry.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/entry.S --- linux-2.6.14.7/arch/ia64/kernel/entry.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/entry.S 2006-02-27 17:33:28.000000000 +0100 @@ -1589,7 +1589,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 linux-2.6.14.7/arch/ia64/kernel/module.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/module.c --- linux-2.6.14.7/arch/ia64/kernel/module.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/module.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/ia64/kernel/perfmon.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/perfmon.c --- linux-2.6.14.7/arch/ia64/kernel/perfmon.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/perfmon.c 2006-02-27 17:33:28.000000000 +0100 @@ -39,6 +39,8 @@ #include #include #include +#include +#include #include #include @@ -2351,7 +2353,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); up_write(&task->mm->mmap_sem); diff -NurpP linux-2.6.14.7/arch/ia64/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/process.c --- linux-2.6.14.7/arch/ia64/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -683,7 +683,8 @@ kernel_thread (int (*fn)(void *), void * regs.sw.ar_fpsr = regs.pt.ar_fpsr = ia64_getreg(_IA64_REG_AR_FPSR); regs.sw.ar_bspstore = (unsigned long) current + IA64_RBS_OFFSET; regs.sw.pr = (1 << PRED_KERNEL_STACK); - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s.pt, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s.pt, 0, NULL, NULL); } EXPORT_SYMBOL(kernel_thread); diff -NurpP linux-2.6.14.7/arch/ia64/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/ptrace.c --- linux-2.6.14.7/arch/ia64/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -1456,10 +1457,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 linux-2.6.14.7/arch/ia64/kernel/sys_ia64.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/sys_ia64.c --- linux-2.6.14.7/arch/ia64/kernel/sys_ia64.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/kernel/sys_ia64.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/ia64/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/mm/fault.c --- linux-2.6.14.7/arch/ia64/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/mm/fault.c 2006-02-27 17:50:20.000000000 +0100 @@ -10,6 +10,8 @@ #include #include #include +#include +#include #include #include @@ -35,12 +37,21 @@ expand_backing_store (struct vm_area_str grow = PAGE_SIZE >> PAGE_SHIFT; if (address - vma->vm_start > current->signal->rlim[RLIMIT_STACK].rlim_cur - || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > current->signal->rlim[RLIMIT_AS].rlim_cur)) + || (((vma->vm_mm->total_vm + grow) << PAGE_SHIFT) > + current->signal->rlim[RLIMIT_AS].rlim_cur)) + return -ENOMEM; + if (!vx_vmpages_avail(vma->vm_mm, grow) || + ((vma->vm_flags & VM_LOCKED) && + !vx_vmlocked_avail(vma->vm_mm, grow))) + return -ENOMEM; + if ((vma->vm_flags & VM_LOCKED) && + ((vma->vm_mm->locked_vm + grow) << PAGE_SHIFT) > current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur && + !capable(CAP_IPC_LOCK)) return -ENOMEM; vma->vm_end += PAGE_SIZE; - vma->vm_mm->total_vm += grow; + vx_vmpages_add(vma->vm_mm, grow); if (vma->vm_flags & VM_LOCKED) - vma->vm_mm->locked_vm += grow; + vx_vmlocked_add(vma->vm_mm, grow); __vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, grow); return 0; } @@ -77,6 +88,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) { @@ -139,9 +167,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 linux-2.6.14.7/arch/ia64/mm/init.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/mm/init.c --- linux-2.6.14.7/arch/ia64/mm/init.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ia64/mm/init.c 2006-02-27 17:28:35.000000000 +0100 @@ -20,8 +20,8 @@ #include #include #include +#include -#include #include #include #include diff -NurpP linux-2.6.14.7/arch/m32r/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m32r/kernel/process.c --- linux-2.6.14.7/arch/m32r/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m32r/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -202,8 +202,8 @@ int kernel_thread(int (*fn)(void *), voi regs.psw = M32R_PSW_BIE; /* Ok, create the new process. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, - NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } /* diff -NurpP linux-2.6.14.7/arch/m68k/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68k/Kconfig --- linux-2.6.14.7/arch/m68k/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68k/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -672,6 +672,8 @@ source "fs/Kconfig" source "arch/m68k/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/m68k/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68k/kernel/process.c --- linux-2.6.14.7/arch/m68k/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68k/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -155,7 +155,8 @@ int kernel_thread(int (*fn)(void *), voi { register long retval __asm__ ("d0"); - register long clone_arg __asm__ ("d1") = flags | CLONE_VM | CLONE_UNTRACED; + register long clone_arg __asm__ ("d1") = + flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD; retval = __NR_clone; __asm__ __volatile__ diff -NurpP linux-2.6.14.7/arch/m68k/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68k/kernel/ptrace.c --- linux-2.6.14.7/arch/m68k/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68k/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -147,6 +147,8 @@ asmlinkage int sys_ptrace(long request, ret = -ESRCH; goto out; } + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; /* you may not mess with init */ if (unlikely(pid == 1)) { diff -NurpP linux-2.6.14.7/arch/m68knommu/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68knommu/Kconfig --- linux-2.6.14.7/arch/m68knommu/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68knommu/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -635,6 +635,8 @@ source "fs/Kconfig" source "arch/m68knommu/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/m68knommu/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68knommu/kernel/process.c --- linux-2.6.14.7/arch/m68knommu/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68knommu/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -115,7 +115,7 @@ void show_regs(struct pt_regs * regs) int kernel_thread(int (*fn)(void *), void * arg, unsigned long flags) { int retval; - long clone_arg = flags | CLONE_VM; + long clone_arg = flags | CLONE_VM | CLONE_KTHREAD; mm_segment_t fs; fs = get_fs(); diff -NurpP linux-2.6.14.7/arch/m68knommu/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68knommu/kernel/ptrace.c --- linux-2.6.14.7/arch/m68knommu/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/m68knommu/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -125,6 +125,8 @@ asmlinkage int sys_ptrace(long request, 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) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/mips/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/Kconfig --- linux-2.6.14.7/arch/mips/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -1732,6 +1732,8 @@ source "fs/Kconfig" source "arch/mips/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/mips/kernel/binfmt_elfn32.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/binfmt_elfn32.c --- linux-2.6.14.7/arch/mips/kernel/binfmt_elfn32.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/binfmt_elfn32.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/mips/kernel/binfmt_elfo32.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/binfmt_elfo32.c --- linux-2.6.14.7/arch/mips/kernel/binfmt_elfo32.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/binfmt_elfo32.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/mips/kernel/linux32.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/linux32.c --- linux-2.6.14.7/arch/mips/kernel/linux32.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/linux32.c 2006-02-27 17:33:28.000000000 +0100 @@ -1199,7 +1199,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 linux-2.6.14.7/arch/mips/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/process.c --- linux-2.6.14.7/arch/mips/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -208,7 +208,8 @@ long kernel_thread(int (*fn)(void *), vo #endif /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } struct mips_frame_info { diff -NurpP linux-2.6.14.7/arch/mips/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/ptrace.c --- linux-2.6.14.7/arch/mips/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -78,6 +78,8 @@ asmlinkage int sys_ptrace(long request, 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) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/mips/kernel/scall32-o32.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/scall32-o32.S --- linux-2.6.14.7/arch/mips/kernel/scall32-o32.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/scall32-o32.S 2006-02-27 17:33:28.000000000 +0100 @@ -617,7 +617,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 4 sys sys_ni_syscall 0 /* available, was setaltroot */ sys sys_add_key 5 diff -NurpP linux-2.6.14.7/arch/mips/kernel/scall64-64.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/scall64-64.S --- linux-2.6.14.7/arch/mips/kernel/scall64-64.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/scall64-64.S 2006-02-27 17:33:28.000000000 +0100 @@ -443,7 +443,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 linux-2.6.14.7/arch/mips/kernel/scall64-n32.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/scall64-n32.S --- linux-2.6.14.7/arch/mips/kernel/scall64-n32.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/scall64-n32.S 2006-02-27 17:33:28.000000000 +0100 @@ -357,7 +357,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 sys_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key diff -NurpP linux-2.6.14.7/arch/mips/kernel/scall64-o32.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/scall64-o32.S --- linux-2.6.14.7/arch/mips/kernel/scall64-o32.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/scall64-o32.S 2006-02-27 17:33:28.000000000 +0100 @@ -479,7 +479,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 sys_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key /* 4280 */ diff -NurpP linux-2.6.14.7/arch/mips/kernel/syscall.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/syscall.c --- linux-2.6.14.7/arch/mips/kernel/syscall.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/syscall.c 2006-02-27 17:33:28.000000000 +0100 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include @@ -84,6 +85,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); @@ -94,7 +100,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 @@ -210,7 +216,7 @@ out: */ asmlinkage 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; } @@ -221,21 +227,23 @@ asmlinkage int sys_uname(struct old_utsn asmlinkage int sys_olduname(struct oldold_utsname * 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; @@ -261,10 +269,10 @@ asmlinkage int _sys_sysmips(int cmd, lon return -EFAULT; down_write(&uts_sem); - strncpy(system_utsname.nodename, nodename, len); + strncpy(vx_new_uts(nodename), nodename, len); nodename[__NEW_UTS_LEN] = '\0'; - strlcpy(system_utsname.nodename, nodename, - sizeof(system_utsname.nodename)); + strlcpy(vx_new_uts(nodename), nodename, + sizeof(vx_new_uts(nodename))); up_write(&uts_sem); return 0; } diff -NurpP linux-2.6.14.7/arch/mips/kernel/sysirix.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/sysirix.c --- linux-2.6.14.7/arch/mips/kernel/sysirix.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/kernel/sysirix.c 2006-02-27 17:33:28.000000000 +0100 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include diff -NurpP linux-2.6.14.7/arch/mips/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/mm/fault.c --- linux-2.6.14.7/arch/mips/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/mips/mm/fault.c 2006-02-27 17:28:35.000000000 +0100 @@ -26,6 +26,23 @@ #include #include +#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 linux-2.6.14.7/arch/parisc/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/Kconfig --- linux-2.6.14.7/arch/parisc/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -204,6 +204,8 @@ source "arch/parisc/oprofile/Kconfig" source "arch/parisc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/parisc/kernel/entry.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/entry.S --- linux-2.6.14.7/arch/parisc/kernel/entry.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/entry.S 2006-02-27 17:33:28.000000000 +0100 @@ -753,6 +753,7 @@ fault_vector_11: #define CLONE_VM 0x100 /* Must agree with */ #define CLONE_UNTRACED 0x00800000 +#define CLONE_KTHREAD 0x10000000 .export __kernel_thread, code .import do_fork diff -NurpP linux-2.6.14.7/arch/parisc/kernel/module.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/module.c --- linux-2.6.14.7/arch/parisc/kernel/module.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/module.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 = ALIGN(me->core_size, 16); - me->arch.fdesc_offset = me->core_size; - me->core_size += fdescs * sizeof(Elf_Fdesc); - - me->core_size = ALIGN(me->core_size, 16); - me->arch.stub_offset = me->core_size; - me->core_size += stubs * sizeof(struct stub_entry); - - me->init_size = ALIGN(me->init_size, 16); - me->arch.init_stub_offset = me->init_size; - me->init_size += init_stubs * sizeof(struct stub_entry); + me->core_size_rw = ALIGN(me->core_size_rw, 16); + me->arch.got_offset = me->core_size_rw; + me->core_size_rw += gots * sizeof(struct got_entry); + + me->core_size_rw = ALIGN(me->core_size_rw, 16); + me->arch.fdesc_offset = me->core_size_rw; + me->core_size_rw += fdescs * sizeof(Elf_Fdesc); + + me->core_size_rx = ALIGN(me->core_size_rx, 16); + me->arch.stub_offset = me->core_size_rx; + me->core_size_rx += stubs * sizeof(struct stub_entry); + + me->init_size_rx = ALIGN(me->init_size_rx, 16); + me->arch.init_stub_offset = me->init_size_rx; + me->init_size_rx += init_stubs * sizeof(struct stub_entry); me->arch.got_max = gots; me->arch.fdesc_max = fdescs; @@ -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 linux-2.6.14.7/arch/parisc/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/process.c --- linux-2.6.14.7/arch/parisc/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -197,7 +197,7 @@ pid_t kernel_thread(int (*fn)(void *), v * kernel_thread can become a #define. */ - return __kernel_thread(fn, arg, flags); + return __kernel_thread(fn, arg, flags | CLONE_KTHREAD); } EXPORT_SYMBOL(kernel_thread); diff -NurpP linux-2.6.14.7/arch/parisc/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/ptrace.c --- linux-2.6.14.7/arch/parisc/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -111,10 +112,16 @@ long sys_ptrace(long request, pid_t pid, 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 linux-2.6.14.7/arch/parisc/kernel/sys_parisc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/sys_parisc.c --- linux-2.6.14.7/arch/parisc/kernel/sys_parisc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/sys_parisc.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/parisc/kernel/sys_parisc32.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/sys_parisc32.c --- linux-2.6.14.7/arch/parisc/kernel/sys_parisc32.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/sys_parisc32.c 2006-02-27 17:33:28.000000000 +0100 @@ -657,6 +657,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 linux-2.6.14.7/arch/parisc/kernel/syscall_table.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/syscall_table.S --- linux-2.6.14.7/arch/parisc/kernel/syscall_table.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/syscall_table.S 2006-02-27 17:33:28.000000000 +0100 @@ -368,5 +368,6 @@ ENTRY_COMP(mbind) /* 260 */ ENTRY_COMP(get_mempolicy) ENTRY_COMP(set_mempolicy) + ENTRY_DIFF(vserver) /* Nothing yet */ diff -NurpP linux-2.6.14.7/arch/parisc/kernel/traps.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/traps.c --- linux-2.6.14.7/arch/parisc/kernel/traps.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/kernel/traps.c 2006-02-27 17:28:35.000000000 +0100 @@ -687,9 +687,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 linux-2.6.14.7/arch/parisc/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/mm/fault.c --- linux-2.6.14.7/arch/parisc/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/parisc/mm/fault.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/ppc/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/Kconfig --- linux-2.6.14.7/arch/ppc/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -1372,6 +1372,8 @@ source "arch/ppc/oprofile/Kconfig" source "arch/ppc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/ppc/kernel/asm-offsets.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/asm-offsets.c --- linux-2.6.14.7/arch/ppc/kernel/asm-offsets.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/asm-offsets.c 2006-02-27 17:33:28.000000000 +0100 @@ -121,6 +121,7 @@ main(void) DEFINE(TRAP, STACK_FRAME_OVERHEAD+offsetof(struct pt_regs, trap)); DEFINE(CLONE_VM, CLONE_VM); DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); + DEFINE(CLONE_KTHREAD, CLONE_KTHREAD); DEFINE(MM_PGD, offsetof(struct mm_struct, pgd)); /* About the CPU features table */ diff -NurpP linux-2.6.14.7/arch/ppc/kernel/misc.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/misc.S --- linux-2.6.14.7/arch/ppc/kernel/misc.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/misc.S 2006-02-27 17:33:28.000000000 +0100 @@ -1135,7 +1135,7 @@ _GLOBAL(kernel_thread) mr r30,r3 /* function */ mr r31,r4 /* argument */ ori r3,r5,CLONE_VM /* flags */ - oris r3,r3,CLONE_UNTRACED>>16 + oris r3,r3,(CLONE_UNTRACED|CLONE_KTHREAD)>>16 li r4,0 /* new sp (unused) */ li r0,__NR_clone sc @@ -1434,7 +1434,7 @@ _GLOBAL(sys_call_table) .long ppc_fadvise64_64 .long sys_ni_syscall /* 255 - rtas (used on ppc64) */ .long sys_debug_setcontext - .long sys_ni_syscall /* 257 reserved for vserver */ + .long sys_vserver .long sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ .long sys_ni_syscall /* 259 reserved for new sys_mbind */ .long sys_ni_syscall /* 260 reserved for new sys_get_mempolicy */ diff -NurpP linux-2.6.14.7/arch/ppc/kernel/module.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/module.c --- linux-2.6.14.7/arch/ppc/kernel/module.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/module.c 2006-02-27 17:28:35.000000000 +0100 @@ -164,8 +164,8 @@ 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) entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; else entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; diff -NurpP linux-2.6.14.7/arch/ppc/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/ptrace.c --- linux-2.6.14.7/arch/ppc/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -266,11 +267,16 @@ int sys_ptrace(long request, long pid, l 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) /* you may not mess 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 linux-2.6.14.7/arch/ppc/kernel/syscalls.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/syscalls.c --- linux-2.6.14.7/arch/ppc/kernel/syscalls.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/kernel/syscalls.c 2006-02-27 17:33:28.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -225,7 +226,7 @@ int sys_uname(struct old_utsname __user int err = -EFAULT; down_read(&uts_sem); - if (name && !copy_to_user(name, &system_utsname, sizeof (*name))) + if (name && !copy_to_user(name, vx_new_utsname(), sizeof (*name))) err = 0; up_read(&uts_sem); return err; @@ -234,6 +235,7 @@ int sys_uname(struct old_utsname __user int sys_olduname(struct oldold_utsname __user * name) { int error; + struct new_utsname *ptr; if (!name) return -EFAULT; @@ -241,15 +243,16 @@ int sys_olduname(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 = __put_user(0,name->machine+__OLD_UTS_LEN); up_read(&uts_sem); diff -NurpP linux-2.6.14.7/arch/ppc/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/mm/fault.c --- linux-2.6.14.7/arch/ppc/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc/mm/fault.c 2006-02-27 17:28:35.000000000 +0100 @@ -28,6 +28,11 @@ #include #include #include +#include +#include +#include +#include +#include #include #include @@ -51,6 +56,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. @@ -111,7 +474,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 */ @@ -205,15 +568,14 @@ good_area: } else if (TRAP(regs) == 0x400) { pte_t *ptep; -#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; @@ -233,6 +595,7 @@ good_area: if (ptep != NULL) pte_unmap(ptep); #endif +#endif /* a read */ } else { /* protection fault */ @@ -278,6 +641,32 @@ 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 linux-2.6.14.7/arch/ppc64/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/Kconfig --- linux-2.6.14.7/arch/ppc64/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -462,6 +462,8 @@ source "arch/ppc64/oprofile/Kconfig" source "arch/ppc64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" config KEYS_COMPAT diff -NurpP linux-2.6.14.7/arch/ppc64/kernel/asm-offsets.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/kernel/asm-offsets.c --- linux-2.6.14.7/arch/ppc64/kernel/asm-offsets.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/kernel/asm-offsets.c 2006-02-27 17:33:28.000000000 +0100 @@ -163,6 +163,7 @@ int main(void) DEFINE(CLONE_VM, CLONE_VM); DEFINE(CLONE_UNTRACED, CLONE_UNTRACED); + DEFINE(CLONE_KTHREAD, CLONE_KTHREAD); /* About the CPU features table */ DEFINE(CPU_SPEC_ENTRY_SIZE, sizeof(struct cpu_spec)); diff -NurpP linux-2.6.14.7/arch/ppc64/kernel/misc.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/kernel/misc.S --- linux-2.6.14.7/arch/ppc64/kernel/misc.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/kernel/misc.S 2006-02-27 17:33:28.000000000 +0100 @@ -659,7 +659,7 @@ _GLOBAL(kernel_thread) mr r29,r3 mr r30,r4 ori r3,r5,CLONE_VM /* flags */ - oris r3,r3,(CLONE_UNTRACED>>16) + oris r3,r3,(CLONE_UNTRACED|CLONE_KTHREAD)>>16 li r4,0 /* new sp (unused) */ li r0,__NR_clone sc @@ -1209,7 +1209,7 @@ _GLOBAL(sys_call_table32) .llong .ppc32_fadvise64_64 /* 32bit only fadvise64_64 */ .llong .ppc_rtas /* 255 */ .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ - .llong .sys_ni_syscall /* 257 reserved for vserver */ + .llong .sys32_vserver .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ .llong .compat_sys_mbind .llong .compat_sys_get_mempolicy /* 260 */ @@ -1490,7 +1490,7 @@ _GLOBAL(sys_call_table) .llong .sys_ni_syscall /* 32bit only fadvise64_64 */ .llong .ppc_rtas /* 255 */ .llong .sys_ni_syscall /* 256 reserved for sys_debug_setcontext */ - .llong .sys_ni_syscall /* 257 reserved for vserver */ + .llong .sys_vserver .llong .sys_ni_syscall /* 258 reserved for new sys_remap_file_pages */ .llong .sys_mbind .llong .sys_get_mempolicy /* 260 */ diff -NurpP linux-2.6.14.7/arch/ppc64/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/kernel/ptrace.c --- linux-2.6.14.7/arch/ppc64/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -79,6 +79,8 @@ int sys_ptrace(long request, long pid, l 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) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/ppc64/kernel/sys_ppc32.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/kernel/sys_ppc32.c --- linux-2.6.14.7/arch/ppc64/kernel/sys_ppc32.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/kernel/sys_ppc32.c 2006-02-27 17:33:28.000000000 +0100 @@ -1037,7 +1037,7 @@ asmlinkage int sys32_uname(struct old_ut 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 && personality(current->personality) == PER_LINUX32) { @@ -1052,20 +1052,22 @@ asmlinkage int sys32_uname(struct old_ut asmlinkage int sys32_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 |= __put_user(0,name->machine+__OLD_UTS_LEN); if (personality(current->personality) == PER_LINUX32) { /* change "ppc64" to "ppc" */ diff -NurpP linux-2.6.14.7/arch/ppc64/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/mm/fault.c --- linux-2.6.14.7/arch/ppc64/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/mm/fault.c 2006-02-27 17:28:35.000000000 +0100 @@ -30,6 +30,7 @@ #include #include #include +#include #include #include @@ -100,6 +101,38 @@ static void do_dabr(struct pt_regs *regs force_sig_info(SIGTRAP, &info, current); } +#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 + /* * The error_code parameter is * - DSISR for a non-SLB data access fault, @@ -268,6 +301,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 ((trap == 0x400) && (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 + info.si_signo = SIGSEGV; info.si_errno = 0; info.si_code = code; diff -NurpP linux-2.6.14.7/arch/ppc64/mm/mmap.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/mm/mmap.c --- linux-2.6.14.7/arch/ppc64/mm/mmap.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/ppc64/mm/mmap.c 2006-02-27 17:28:35.000000000 +0100 @@ -76,10 +76,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 linux-2.6.14.7/arch/s390/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/Kconfig --- linux-2.6.14.7/arch/s390/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -485,6 +485,8 @@ source "arch/s390/oprofile/Kconfig" source "arch/s390/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/s390/kernel/module.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/kernel/module.c --- linux-2.6.14.7/arch/s390/kernel/module.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/kernel/module.c 2006-02-27 17:28:35.000000000 +0100 @@ -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_ARCH_S390X 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 linux-2.6.14.7/arch/s390/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/kernel/process.c --- linux-2.6.14.7/arch/s390/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -180,7 +180,7 @@ int kernel_thread(int (*fn)(void *), voi regs.orig_gpr2 = -1; /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, 0, ®s, 0, NULL, NULL); } diff -NurpP linux-2.6.14.7/arch/s390/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/kernel/ptrace.c --- linux-2.6.14.7/arch/s390/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -738,9 +738,11 @@ sys_ptrace(long request, long pid, long read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; ret = do_ptrace(child, request, addr, data); - +out_tsk: put_task_struct(child); out: unlock_kernel(); diff -NurpP linux-2.6.14.7/arch/s390/kernel/syscalls.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/kernel/syscalls.S --- linux-2.6.14.7/arch/s390/kernel/syscalls.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/s390/kernel/syscalls.S 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/arch/sh/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh/Kconfig --- linux-2.6.14.7/arch/sh/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -798,6 +798,8 @@ source "arch/sh/oprofile/Kconfig" source "arch/sh/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/sh/kernel/kgdb_stub.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh/kernel/kgdb_stub.c --- linux-2.6.14.7/arch/sh/kernel/kgdb_stub.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh/kernel/kgdb_stub.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/arch/sh/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh/kernel/process.c --- linux-2.6.14.7/arch/sh/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -177,7 +177,8 @@ int kernel_thread(int (*fn)(void *), voi regs.sr = (1 << 30); /* Ok, create the new process.. */ - return do_fork(flags | CLONE_VM | CLONE_UNTRACED, 0, ®s, 0, NULL, NULL); + return do_fork(flags | CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD, + 0, ®s, 0, NULL, NULL); } /* diff -NurpP linux-2.6.14.7/arch/sh/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh/kernel/ptrace.c --- linux-2.6.14.7/arch/sh/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -108,6 +108,8 @@ asmlinkage int sys_ptrace(long request, 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) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/sh64/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh64/kernel/process.c --- linux-2.6.14.7/arch/sh64/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sh64/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -643,7 +643,7 @@ int kernel_thread(int (*fn)(void *), voi static __inline__ _syscall2(int,clone,unsigned long,flags,unsigned long,newsp) static __inline__ _syscall1(int,exit,int,ret) - reply = clone(flags | CLONE_VM, 0); + reply = clone(flags | CLONE_VM | CLONE_KTHREAD, 0); if (!reply) { /* Child */ reply = exit(fn(arg)); diff -NurpP linux-2.6.14.7/arch/sparc/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/Kconfig --- linux-2.6.14.7/arch/sparc/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -276,6 +276,8 @@ source "fs/Kconfig" source "arch/sparc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/sparc/Makefile linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/Makefile --- linux-2.6.14.7/arch/sparc/Makefile 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/Makefile 2006-02-27 17:28:35.000000000 +0100 @@ -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/ +CORE_Y += kernel/ mm/ fs/ ipc/ security/ crypto/ 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 linux-2.6.14.7/arch/sparc/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/kernel/process.c --- linux-2.6.14.7/arch/sparc/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -707,7 +707,8 @@ pid_t kernel_thread(int (*fn)(void *), v /* Notreached by child. */ "1: mov %%o0, %0\n\t" : "=r" (retval) : - "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), + "i" (__NR_clone), "r" (flags | + CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD), "i" (__NR_exit), "r" (fn), "r" (arg) : "g1", "g2", "g3", "o0", "o1", "memory", "cc"); return retval; diff -NurpP linux-2.6.14.7/arch/sparc/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/kernel/ptrace.c --- linux-2.6.14.7/arch/sparc/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -322,6 +323,15 @@ asmlinkage void do_ptrace(struct pt_regs pt_error_return(regs, ESRCH); 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)) { diff -NurpP linux-2.6.14.7/arch/sparc/kernel/sys_sparc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/kernel/sys_sparc.c --- linux-2.6.14.7/arch/sparc/kernel/sys_sparc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/kernel/sys_sparc.c 2006-02-27 17:33:28.000000000 +0100 @@ -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); @@ -470,13 +471,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 linux-2.6.14.7/arch/sparc/kernel/systbls.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/kernel/systbls.S --- linux-2.6.14.7/arch/sparc/kernel/systbls.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/kernel/systbls.S 2006-02-27 17:33:28.000000000 +0100 @@ -72,7 +72,7 @@ sys_call_table: /*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl /*255*/ .long sys_nis_syscall, 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_ni_syscall, sys_add_key, sys_request_key, sys_keyctl diff -NurpP linux-2.6.14.7/arch/sparc/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/mm/fault.c --- linux-2.6.14.7/arch/sparc/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/mm/fault.c 2006-02-27 17:28:35.000000000 +0100 @@ -21,6 +21,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -219,6 +223,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) { @@ -282,6 +532,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 linux-2.6.14.7/arch/sparc/mm/init.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/mm/init.c --- linux-2.6.14.7/arch/sparc/mm/init.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/mm/init.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/sparc/mm/srmmu.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/mm/srmmu.c --- linux-2.6.14.7/arch/sparc/mm/srmmu.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc/mm/srmmu.c 2006-02-27 17:28:35.000000000 +0100 @@ -2148,6 +2148,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); pg_iobits = SRMMU_VALID | SRMMU_WRITE | SRMMU_REF; diff -NurpP linux-2.6.14.7/arch/sparc64/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/Kconfig --- linux-2.6.14.7/arch/sparc64/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -381,6 +381,8 @@ source "arch/sparc64/oprofile/Kconfig" source "arch/sparc64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/sparc64/kernel/binfmt_aout32.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/binfmt_aout32.c --- linux-2.6.14.7/arch/sparc64/kernel/binfmt_aout32.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/binfmt_aout32.c 2006-02-27 17:33:28.000000000 +0100 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include diff -NurpP linux-2.6.14.7/arch/sparc64/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/process.c --- linux-2.6.14.7/arch/sparc64/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -701,7 +701,8 @@ pid_t kernel_thread(int (*fn)(void *), v /* Notreached by child. */ "1:" : "=r" (retval) : - "i" (__NR_clone), "r" (flags | CLONE_VM | CLONE_UNTRACED), + "i" (__NR_clone), "r" (flags | + CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD), "i" (__NR_exit), "r" (fn), "r" (arg) : "g1", "g2", "g3", "o0", "o1", "memory", "cc"); return retval; diff -NurpP linux-2.6.14.7/arch/sparc64/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/ptrace.c --- linux-2.6.14.7/arch/sparc64/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -233,6 +234,15 @@ asmlinkage void do_ptrace(struct pt_regs pt_error_return(regs, ESRCH); 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)) { diff -NurpP linux-2.6.14.7/arch/sparc64/kernel/sys_sparc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/sys_sparc.c --- linux-2.6.14.7/arch/sparc64/kernel/sys_sparc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/sys_sparc.c 2006-02-27 17:33:28.000000000 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,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); @@ -86,7 +91,7 @@ unsigned long arch_get_unmapped_area(str if (len <= mm->cached_hole_size) { mm->cached_hole_size = 0; - mm->free_area_cache = TASK_UNMAPPED_BASE; + mm->free_area_cache = mm->mmap_base; } start_addr = addr = mm->free_area_cache; @@ -105,8 +110,8 @@ full_search: vma = find_vma(mm, PAGE_OFFSET); } if (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; } @@ -476,13 +481,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 linux-2.6.14.7/arch/sparc64/kernel/systbls.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/systbls.S --- linux-2.6.14.7/arch/sparc64/kernel/systbls.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/kernel/systbls.S 2006-02-27 17:33:28.000000000 +0100 @@ -73,7 +73,7 @@ sys_call_table32: /*250*/ .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl .word sys_ni_syscall, sys32_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, sys32_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy + .word sys_timer_delete, sys32_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 sys_ni_syscall, sys_add_key, sys_request_key, sys_keyctl @@ -139,7 +139,7 @@ sys_call_table: /*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_ni_syscall, 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_nis_syscall, sys_add_key, sys_request_key, sys_keyctl diff -NurpP linux-2.6.14.7/arch/sparc64/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/mm/fault.c --- linux-2.6.14.7/arch/sparc64/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/mm/fault.c 2006-02-27 17:28:35.000000000 +0100 @@ -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: + goto fault_done; +#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 linux-2.6.14.7/arch/sparc64/solaris/fs.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/solaris/fs.c --- linux-2.6.14.7/arch/sparc64/solaris/fs.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/sparc64/solaris/fs.c 2006-02-27 17:33:28.000000000 +0100 @@ -362,7 +362,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; @@ -398,7 +398,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 linux-2.6.14.7/arch/um/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/um/Kconfig --- linux-2.6.14.7/arch/um/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/um/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -293,6 +293,8 @@ source "drivers/net/Kconfig" source "fs/Kconfig" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/um/kernel/process_kern.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/um/kernel/process_kern.c --- linux-2.6.14.7/arch/um/kernel/process_kern.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/um/kernel/process_kern.c 2006-02-27 17:33:28.000000000 +0100 @@ -23,6 +23,8 @@ #include "linux/proc_fs.h" #include "linux/ptrace.h" #include "linux/random.h" +#include "linux/vs_cvirt.h" + #include "asm/unistd.h" #include "asm/mman.h" #include "asm/segment.h" @@ -97,7 +99,7 @@ int kernel_thread(int (*fn)(void *), voi current->thread.request.u.thread.proc = fn; current->thread.request.u.thread.arg = arg; - pid = do_fork(CLONE_VM | CLONE_UNTRACED | flags, 0, + pid = do_fork(CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD | flags, 0, ¤t->thread.regs, 0, NULL, NULL); if(pid < 0) panic("do_fork failed in kernel_thread, errno = %d", pid); diff -NurpP linux-2.6.14.7/arch/um/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/um/kernel/ptrace.c --- linux-2.6.14.7/arch/um/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/um/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -72,6 +72,8 @@ long sys_ptrace(long request, long pid, 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) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/um/kernel/syscall_kern.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/um/kernel/syscall_kern.c --- linux-2.6.14.7/arch/um/kernel/syscall_kern.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/um/kernel/syscall_kern.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 * name 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 * name long sys_olduname(struct oldold_utsname * 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 linux-2.6.14.7/arch/v850/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/v850/Kconfig --- linux-2.6.14.7/arch/v850/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/v850/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -311,6 +311,8 @@ source "drivers/usb/Kconfig" source "arch/v850/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/v850/kernel/module.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/v850/kernel/module.c --- linux-2.6.14.7/arch/v850/kernel/module.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/v850/kernel/module.c 2006-02-27 17:28:35.000000000 +0100 @@ -150,8 +150,8 @@ static uint32_t do_plt_call (void *locat tramp[1] = ((val >> 16) & 0xffff) + 0x610000; /* ...; jmp r1 */ /* Init, or core PLT? */ - if (location >= mod->module_core - && location < mod->module_core + mod->core_size) + if (location >= mod->module_core_rx + && location < mod->module_core_rx + mod->core_size_rx) entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; else entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; diff -NurpP linux-2.6.14.7/arch/v850/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/v850/kernel/process.c --- linux-2.6.14.7/arch/v850/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/v850/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -77,7 +77,7 @@ int kernel_thread (int (*fn)(void *), vo /* Clone this thread. Note that we don't pass the clone syscall's second argument -- it's ignored for calls from kernel mode (the child's SP is always set to the top of the kernel stack). */ - arg0 = flags | CLONE_VM; + arg0 = flags | CLONE_VM | CLONE_KTHREAD; syscall = __NR_clone; asm volatile ("trap " SYSCALL_SHORT_TRAP : "=r" (ret), "=r" (syscall) diff -NurpP linux-2.6.14.7/arch/v850/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/v850/kernel/ptrace.c --- linux-2.6.14.7/arch/v850/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/v850/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -139,6 +139,8 @@ int sys_ptrace(long request, long pid, l read_unlock(&tasklist_lock); if (!child) goto out; + if (!vx_check(vx_task_xid(child), VX_WATCH|VX_IDENT)) + goto out_tsk; rval = -EPERM; if (pid == 1) /* you may not mess with init */ diff -NurpP linux-2.6.14.7/arch/x86_64/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/Kconfig --- linux-2.6.14.7/arch/x86_64/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -536,6 +536,8 @@ source "arch/x86_64/oprofile/Kconfig" source "arch/x86_64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP linux-2.6.14.7/arch/x86_64/boot/compressed/head.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/boot/compressed/head.S --- linux-2.6.14.7/arch/x86_64/boot/compressed/head.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/boot/compressed/head.S 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/arch/x86_64/ia32/ia32_aout.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/ia32/ia32_aout.c --- linux-2.6.14.7/arch/x86_64/ia32/ia32_aout.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/ia32/ia32_aout.c 2006-02-27 17:33:28.000000000 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include diff -NurpP linux-2.6.14.7/arch/x86_64/ia32/ia32_binfmt.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/ia32/ia32_binfmt.c --- linux-2.6.14.7/arch/x86_64/ia32/ia32_binfmt.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/ia32/ia32_binfmt.c 2006-02-27 17:33:28.000000000 +0100 @@ -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; @@ -337,7 +348,7 @@ static void elf32_init(struct pt_regs *r int setup_arg_pages(struct linux_binprm *bprm, unsigned long stack_top, int executable_stack) { - unsigned long stack_base; + unsigned long stack_base, grow; struct vm_area_struct *mpnt; struct mm_struct *mm = current->mm; int i, ret; @@ -374,7 +385,8 @@ int setup_arg_pages(struct linux_binprm 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 linux-2.6.14.7/arch/x86_64/ia32/ia32entry.S linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/ia32/ia32entry.S --- linux-2.6.14.7/arch/x86_64/ia32/ia32entry.S 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/ia32/ia32entry.S 2006-02-27 17:33:28.000000000 +0100 @@ -622,7 +622,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 linux-2.6.14.7/arch/x86_64/ia32/sys_ia32.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/ia32/sys_ia32.c --- linux-2.6.14.7/arch/x86_64/ia32/sys_ia32.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/ia32/sys_ia32.c 2006-02-27 17:33:28.000000000 +0100 @@ -860,6 +860,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; @@ -868,13 +869,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"; @@ -897,7 +899,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 linux-2.6.14.7/arch/x86_64/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/kernel/process.c --- linux-2.6.14.7/arch/x86_64/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -53,7 +53,8 @@ asmlinkage extern void ret_from_fork(void); -unsigned long kernel_thread_flags = CLONE_VM | CLONE_UNTRACED; +unsigned long kernel_thread_flags = + CLONE_VM | CLONE_UNTRACED | CLONE_KTHREAD; static atomic_t hlt_counter = ATOMIC_INIT(0); @@ -809,9 +810,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 linux-2.6.14.7/arch/x86_64/kernel/ptrace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/kernel/ptrace.c --- linux-2.6.14.7/arch/x86_64/kernel/ptrace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/kernel/ptrace.c 2006-02-27 17:33:28.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -342,11 +343,16 @@ asmlinkage long sys_ptrace(long request, 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) /* you may not mess 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 linux-2.6.14.7/arch/x86_64/kernel/setup64.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/kernel/setup64.c --- linux-2.6.14.7/arch/x86_64/kernel/setup64.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/kernel/setup64.c 2006-02-27 17:28:35.000000000 +0100 @@ -37,7 +37,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 __initdata = 0; /* noexec=on|off Control non executable mappings for 64bit processes. @@ -49,16 +48,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 0; } __setup("noexec=", nonx_setup); /* parsed early actually */ -int force_personality32 = READ_IMPLIES_EXEC; +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 linux-2.6.14.7/arch/x86_64/kernel/sys_x86_64.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/kernel/sys_x86_64.c --- linux-2.6.14.7/arch/x86_64/kernel/sys_x86_64.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/kernel/sys_x86_64.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 @@ -78,8 +79,14 @@ static void find_start_end(unsigned long of playground for now. -AK */ *begin = 0x40000000; *end = 0x80000000; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + *begin += mm->delta_mmap & 0x0FFFFFFFU; +#endif + } else { - *begin = TASK_UNMAPPED_BASE; + *begin = mm->mmap_base; *end = TASK_SIZE; } } @@ -93,11 +100,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 +159,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 linux-2.6.14.7/arch/x86_64/mm/fault.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/mm/fault.c --- linux-2.6.14.7/arch/x86_64/mm/fault.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/x86_64/mm/fault.c 2006-02-27 17:28:35.000000000 +0100 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include @@ -282,6 +283,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; @@ -420,6 +448,8 @@ asmlinkage void __kprobes do_page_fault( good_area: info.si_code = SEGV_ACCERR; write = 0; + if ((error_code & 16) && !(vma->vm_flags & VM_EXEC)) + goto bad_area; switch (error_code & 3) { default: /* 3: write, present */ /* fall through */ @@ -486,7 +516,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 linux-2.6.14.7/arch/xtensa/kernel/process.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/xtensa/kernel/process.c --- linux-2.6.14.7/arch/xtensa/kernel/process.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/arch/xtensa/kernel/process.c 2006-02-27 17:33:28.000000000 +0100 @@ -203,7 +203,7 @@ int kernel_thread(int (*fn)(void *), voi :"=r" (retval) :"i" (__NR_clone), "i" (__NR_exit), "r" (arg), "r" (fn), - "r" (flags | CLONE_VM) + "r" (flags | CLONE_VM | CLONE_KTHREAD) : "a2", "a3", "a4", "a5", "a6" ); return retval; } diff -NurpP linux-2.6.14.7/drivers/block/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/block/Kconfig --- linux-2.6.14.7/drivers/block/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/block/Kconfig 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/drivers/block/Makefile linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/block/Makefile --- linux-2.6.14.7/drivers/block/Makefile 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/block/Makefile 2006-02-27 17:33:28.000000000 +0100 @@ -44,4 +44,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 linux-2.6.14.7/drivers/block/cfq-iosched.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/block/cfq-iosched.c --- linux-2.6.14.7/drivers/block/cfq-iosched.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/block/cfq-iosched.c 2006-02-27 17:33:28.000000000 +0100 @@ -303,6 +303,16 @@ static void cfq_put_cfqd(struct cfq_data #define process_sync(tsk) ((tsk)->flags & PF_SYNCWRITE) +static inline pid_t cfq_queue_pid(struct task_struct *task, int rw) +{ + if (task->xid) + return task->xid; + if (rw == READ || process_sync(task)) + return task->pid; + + return CFQ_KEY_ASYNC; +} + /* * lots of deadline iosched dupes, can be abstracted later... */ @@ -654,7 +664,8 @@ cfq_reposition_crq_rb(struct cfq_queue * static struct request *cfq_find_rq_rb(struct cfq_data *cfqd, sector_t sector) { - struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, current->pid, CFQ_KEY_ANY); + struct cfq_queue *cfqq = cfq_find_cfq_hash(cfqd, + cfq_queue_pid(current, READ), CFQ_KEY_ANY); struct rb_node *n; if (!cfqq) @@ -1949,14 +1960,6 @@ static void cfq_prio_boost(struct cfq_qu cfq_resort_rr_list(cfqq, 0); } -static inline pid_t cfq_queue_pid(struct task_struct *task, int rw) -{ - if (rw == READ || process_sync(task)) - return task->pid; - - return CFQ_KEY_ASYNC; -} - static inline int __cfq_may_queue(struct cfq_data *cfqd, struct cfq_queue *cfqq, struct task_struct *task, int rw) diff -NurpP linux-2.6.14.7/drivers/block/vroot.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/block/vroot.c --- linux-2.6.14.7/drivers/block/vroot.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/block/vroot.c 2006-02-27 17:33:28.000000000 +0100 @@ -0,0 +1,289 @@ +/* + * 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 +#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 linux-2.6.14.7/drivers/char/agp/frontend.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/agp/frontend.c --- linux-2.6.14.7/drivers/char/agp/frontend.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/agp/frontend.c 2006-02-27 17:28:35.000000000 +0100 @@ -848,7 +848,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 linux-2.6.14.7/drivers/char/keyboard.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/keyboard.c --- linux-2.6.14.7/drivers/char/keyboard.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/keyboard.c 2006-02-27 17:28:35.000000000 +0100 @@ -607,6 +607,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 linux-2.6.14.7/drivers/char/mem.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/mem.c --- linux-2.6.14.7/drivers/char/mem.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/mem.c 2006-02-27 17:28:35.000000000 +0100 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -35,6 +36,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 @@ -245,6 +255,11 @@ static int mmap_mem(struct file * file, vma->vm_page_prot = pgprot_noncached(vma->vm_page_prot); #endif +#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, @@ -474,6 +489,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; @@ -600,7 +620,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; @@ -749,6 +785,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; } @@ -756,7 +802,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 @@ -875,6 +920,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; } @@ -907,6 +957,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 linux-2.6.14.7/drivers/char/random.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/random.c --- linux-2.6.14.7/drivers/char/random.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/random.c 2006-02-27 17:33:28.000000000 +0100 @@ -249,8 +249,13 @@ /* * Configuration information */ +#ifdef CONFIG_GRKERNSEC_RANDNET +#define INPUT_POOL_WORDS 256 +#define OUTPUT_POOL_WORDS 64 +#else #define INPUT_POOL_WORDS 128 #define OUTPUT_POOL_WORDS 32 +#endif #define SEC_XFER_SIZE 512 /* @@ -1174,7 +1179,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; @@ -1661,3 +1666,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 linux-2.6.14.7/drivers/char/sysrq.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/sysrq.c --- linux-2.6.14.7/drivers/char/sysrq.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/sysrq.c 2006-02-27 17:33:28.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include @@ -271,6 +272,21 @@ static struct sysrq_key_op sysrq_unrt_op .enable_mask = SYSRQ_ENABLE_RTNICE, }; + +#ifdef CONFIG_VSERVER_DEBUG +static void sysrq_handle_vxinfo(int key, struct pt_regs *pt_regs, + struct tty_struct *tty) +{ + dump_vx_info_inactive((key == 'x')?0:1); +} +static struct sysrq_key_op sysrq_showvxinfo_op = { + .handler = sysrq_handle_vxinfo, + .help_msg = "conteXt", + .action_msg = "Show Context Info", + .enable_mask = SYSRQ_ENABLE_DUMP, +}; +#endif + /* Key Operations table and lock */ static DEFINE_SPINLOCK(sysrq_key_table_lock); #define SYSRQ_KEY_TABLE_LENGTH 36 @@ -323,7 +339,11 @@ static struct sysrq_key_op *sysrq_key_ta /* u */ &sysrq_mountro_op, /* v */ NULL, /* May be assigned at init time by SMP VOYAGER */ /* w */ NULL, +#ifdef CONFIG_VSERVER_DEBUG +/* x */ &sysrq_showvxinfo_op, +#else /* x */ NULL, +#endif /* y */ NULL, /* z */ NULL }; @@ -335,6 +355,8 @@ static int sysrq_key_table_key2index(int retval = key - '0'; } else if ((key >= 'a') && (key <= 'z')) { retval = key + 10 - 'a'; + } else if ((key >= 'A') && (key <= 'Z')) { + retval = key + 10 - 'A'; } else { retval = -1; } diff -NurpP linux-2.6.14.7/drivers/char/tty_io.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/tty_io.c --- linux-2.6.14.7/drivers/char/tty_io.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/tty_io.c 2006-02-27 17:33:28.000000000 +0100 @@ -103,6 +103,7 @@ #include #include #include +#include #include @@ -2155,13 +2156,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) @@ -2179,6 +2183,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 linux-2.6.14.7/drivers/char/vt_ioctl.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/vt_ioctl.c --- linux-2.6.14.7/drivers/char/vt_ioctl.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/char/vt_ioctl.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/drivers/mtd/devices/blkmtd.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/mtd/devices/blkmtd.c --- linux-2.6.14.7/drivers/mtd/devices/blkmtd.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/mtd/devices/blkmtd.c 2006-02-27 17:33:28.000000000 +0100 @@ -617,7 +617,7 @@ static struct mtd_erase_region_info *cal } -extern dev_t __init name_to_dev_t(const char *line); +extern dev_t __init name_to_dev_t(char *line); static struct blkmtd_dev *add_device(char *devname, int readonly, int erase_size) { diff -NurpP linux-2.6.14.7/drivers/mtd/devices/doc2001.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/mtd/devices/doc2001.c --- linux-2.6.14.7/drivers/mtd/devices/doc2001.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/mtd/devices/doc2001.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/drivers/net/wan/sdla_ppp.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/net/wan/sdla_ppp.c --- linux-2.6.14.7/drivers/net/wan/sdla_ppp.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/net/wan/sdla_ppp.c 2006-02-27 17:28:35.000000000 +0100 @@ -451,7 +451,7 @@ static int update(struct wan_device *wan sdla_t* card = wandev->private; struct net_device* dev; volatile ppp_private_area_t *ppp_priv_area; - ppp_flags_t *flags = card->flags; + ppp_flags_t *flags; unsigned long timeout; /* sanity checks */ @@ -475,6 +475,7 @@ static int update(struct wan_device *wan ppp_priv_area->update_comms_stats = 2; ppp_priv_area->timer_int_enabled |= TMR_INT_ENABLED_UPDATE; + flags = card->flags; flags->imask |= PPP_INTR_TIMER; /* wait a maximum of 1 second for the statistics to be updated */ diff -NurpP linux-2.6.14.7/drivers/pci/proc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/pci/proc.c --- linux-2.6.14.7/drivers/pci/proc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/pci/proc.c 2006-02-27 17:28:35.000000000 +0100 @@ -567,7 +567,15 @@ static struct file_operations proc_pci_o static void legacy_proc_init(void) { +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + struct proc_dir_entry * entry = create_proc_entry("pci", S_IRUSR, NULL); +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + struct proc_dir_entry * entry = create_proc_entry("pci", S_IRUSR | S_IRGRP, NULL); +#endif +#else struct proc_dir_entry * entry = create_proc_entry("pci", 0, NULL); +#endif if (entry) entry->proc_fops = &proc_pci_operations; } @@ -596,7 +604,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 linux-2.6.14.7/drivers/pnp/pnpbios/bioscalls.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/pnp/pnpbios/bioscalls.c --- linux-2.6.14.7/drivers/pnp/pnpbios/bioscalls.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/pnp/pnpbios/bioscalls.c 2006-02-27 17:28:35.000000000 +0100 @@ -69,17 +69,17 @@ __asm__( #define Q_SET_SEL(cpu, selname, address, size) \ do { \ -set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], __va((u32)(address))); \ -set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ +set_base(cpu_gdt_table[cpu][(selname) >> 3], __va((u32)(address))); \ +set_limit(cpu_gdt_table[cpu][(selname) >> 3], size); \ } while(0) #define Q2_SET_SEL(cpu, selname, address, size) \ do { \ -set_base(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], (u32)(address)); \ -set_limit(per_cpu(cpu_gdt_table,cpu)[(selname) >> 3], size); \ +set_base(cpu_gdt_table[cpu][(selname) >> 3], (u32)(address)); \ +set_limit(cpu_gdt_table[cpu][(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 @@ -107,6 +107,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. @@ -115,12 +119,17 @@ static inline u16 call_pnp_bios(u16 func return PNP_FUNCTION_NOT_SUPPORTED; cpu = get_cpu(); - save_desc_40 = per_cpu(cpu_gdt_table,cpu)[0x40 / 8]; - per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = bad_bios_desc; /* 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_noirq(cr0); +#endif + + save_desc_40 = cpu_gdt_table[cpu][0x40 / 8]; + cpu_gdt_table[cpu][0x40 / 8] = bad_bios_desc; + /* The lock prevents us bouncing CPU here */ if (ts1_size) Q2_SET_SEL(smp_processor_id(), PNP_TS1, ts1_base, ts1_size); @@ -156,9 +165,14 @@ static inline u16 call_pnp_bios(u16 func "i" (0) : "memory" ); - spin_unlock_irqrestore(&pnp_bios_lock, flags); - per_cpu(cpu_gdt_table,cpu)[0x40 / 8] = save_desc_40; + cpu_gdt_table[cpu][0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel_noirq(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 linux-2.6.14.7/drivers/scsi/libata-scsi.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/scsi/libata-scsi.c --- linux-2.6.14.7/drivers/scsi/libata-scsi.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/scsi/libata-scsi.c 2006-02-27 17:28:35.000000000 +0100 @@ -992,7 +992,7 @@ unsigned int ata_scsiop_inq_80(struct at return 0; } -static const char *inq_83_str = "Linux ATA-SCSI simulator"; +static const char inq_83_str[] = "Linux ATA-SCSI simulator"; /** * ata_scsiop_inq_83 - Simulate INQUIRY EVPD page 83, device identity @@ -1011,13 +1011,13 @@ unsigned int ata_scsiop_inq_83(struct at unsigned int buflen) { rbuf[1] = 0x83; /* this page code */ - rbuf[3] = 4 + strlen(inq_83_str); /* page len */ + rbuf[3] = 3 + sizeof(inq_83_str); /* page len */ /* our one and only identification descriptor (vendor-specific) */ - if (buflen > (strlen(inq_83_str) + 4 + 4 - 1)) { + if (buflen >= (sizeof(inq_83_str) + 4 + 4 - 1)) { rbuf[4 + 0] = 2; /* code set: ASCII */ - rbuf[4 + 3] = strlen(inq_83_str); - memcpy(rbuf + 4 + 4, inq_83_str, strlen(inq_83_str)); + rbuf[4 + 3] = sizeof(inq_83_str)-1; + memcpy(rbuf + 4 + 4, inq_83_str, sizeof(inq_83_str)-1); } return 0; diff -NurpP linux-2.6.14.7/drivers/video/i810/i810_main.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/video/i810/i810_main.c --- linux-2.6.14.7/drivers/video/i810/i810_main.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/video/i810/i810_main.c 2006-02-27 17:28:35.000000000 +0100 @@ -1465,7 +1465,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_KERNEL); + u8 *data = kmalloc(64 * 8, GFP_ATOMIC); if (data == NULL) return -ENOMEM; diff -NurpP linux-2.6.14.7/drivers/video/vesafb.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/video/vesafb.c --- linux-2.6.14.7/drivers/video/vesafb.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/drivers/video/vesafb.c 2006-02-27 17:28:35.000000000 +0100 @@ -299,7 +299,7 @@ static int __init vesafb_probe(struct de 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 linux-2.6.14.7/fs/Kconfig linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/Kconfig --- linux-2.6.14.7/fs/Kconfig 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/Kconfig 2006-02-27 17:28:35.000000000 +0100 @@ -764,7 +764,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 linux-2.6.14.7/fs/attr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/attr.c --- linux-2.6.14.7/fs/attr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/attr.c 2006-02-27 17:33:28.000000000 +0100 @@ -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: @@ -87,6 +112,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); @@ -164,7 +191,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 linux-2.6.14.7/fs/binfmt_aout.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_aout.c --- linux-2.6.14.7/fs/binfmt_aout.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_aout.c 2006-02-27 18:16:11.000000000 +0100 @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -125,10 +127,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; @@ -136,10 +140,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; @@ -289,6 +295,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; @@ -322,6 +330,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; @@ -417,7 +447,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 linux-2.6.14.7/fs/binfmt_elf.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_elf.c --- linux-2.6.14.7/fs/binfmt_elf.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_elf.c 2006-02-27 18:16:31.000000000 +0100 @@ -38,11 +38,17 @@ #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 +96,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) { @@ -99,8 +107,9 @@ static int set_brk(unsigned long start, up_write(¤t->mm->mmap_sem); if (BAD_ADDR(addr)) return addr; + } - current->mm->start_brk = current->mm->brk = end; + current->mm->start_brk = current->mm->brk = e; return 0; } @@ -310,10 +319,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 */ @@ -352,59 +360,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_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; - - 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 (!load_addr_set && interp_elf_ex->e_type == ET_DYN) { - load_addr = map_addr - ELF_PAGESTART(vaddr); - load_addr_set = 1; - } - - /* - * 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; + if (eppnt->p_type != PT_LOAD) + continue; + + /* + * 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; + + 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; - } - /* - * 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; - } + 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; + + 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 (!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; } /* @@ -441,7 +470,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; @@ -485,6 +514,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. @@ -516,7 +719,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; @@ -534,6 +737,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) { @@ -759,14 +963,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); @@ -839,6 +1117,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); @@ -866,9 +1153,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; @@ -895,6 +1182,12 @@ static int load_elf_binary(struct linux_ start_data += load_bias; end_data += load_bias; +#ifdef CONFIG_PAX_RANDMMAP + if (randomize_va_space) + 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 @@ -923,7 +1216,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; @@ -1143,7 +1436,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)) @@ -1154,7 +1447,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; @@ -1208,8 +1501,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; @@ -1562,7 +1858,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; @@ -1595,7 +1891,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; @@ -1614,6 +1910,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 linux-2.6.14.7/fs/binfmt_flat.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_flat.c --- linux-2.6.14.7/fs/binfmt_flat.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_flat.c 2006-02-27 17:33:28.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include #include @@ -540,7 +541,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); return realdatastart; } datapos = realdatastart + MAX_SHARED_LIBS * sizeof(unsigned long); @@ -561,8 +564,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); return result; } @@ -624,8 +629,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); return result; } } diff -NurpP linux-2.6.14.7/fs/binfmt_misc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_misc.c --- linux-2.6.14.7/fs/binfmt_misc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_misc.c 2006-02-27 17:28:35.000000000 +0100 @@ -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 linux-2.6.14.7/fs/binfmt_som.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_som.c --- linux-2.6.14.7/fs/binfmt_som.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/binfmt_som.c 2006-02-27 17:33:28.000000000 +0100 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff -NurpP linux-2.6.14.7/fs/buffer.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/buffer.c --- linux-2.6.14.7/fs/buffer.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/buffer.c 2006-02-27 17:33:28.000000000 +0100 @@ -41,6 +41,7 @@ #include #include #include +#include static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); static void invalidate_bh_lrus(void); @@ -173,7 +174,7 @@ EXPORT_SYMBOL(sync_blockdev); int fsync_super(struct super_block *sb) { sync_inodes_sb(sb, 0); - DQUOT_SYNC(sb); + DQUOT_SYNC(sb->s_dqh); lock_super(sb); if (sb->s_dirt && sb->s_op->write_super) sb->s_op->write_super(sb); @@ -222,7 +223,7 @@ struct super_block *freeze_bdev(struct b smp_wmb(); sync_inodes_sb(sb, 0); - DQUOT_SYNC(sb); + DQUOT_SYNC(sb->s_dqh); lock_super(sb); if (sb->s_dirt && sb->s_op->write_super) @@ -2158,6 +2159,7 @@ int generic_cont_expand(struct inode *in 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 linux-2.6.14.7/fs/compat.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/compat.c --- linux-2.6.14.7/fs/compat.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/compat.c 2006-02-27 17:28:35.000000000 +0100 @@ -46,6 +46,7 @@ #include #include #include +#include #include /* siocdevprivate_ioctl */ @@ -1427,6 +1428,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 = kmalloc(sizeof(*bprm), GFP_KERNEL); @@ -1445,6 +1451,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) @@ -1483,10 +1498,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); @@ -1495,6 +1539,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 linux-2.6.14.7/fs/dcache.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/dcache.c --- linux-2.6.14.7/fs/dcache.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/dcache.c 2006-02-27 17:28:35.000000000 +0100 @@ -1355,7 +1355,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 linux-2.6.14.7/fs/devpts/inode.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/devpts/inode.c --- linux-2.6.14.7/fs/devpts/inode.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/devpts/inode.c 2006-02-27 17:33:28.000000000 +0100 @@ -19,7 +19,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; @@ -69,6 +81,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, @@ -95,8 +125,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) @@ -155,6 +186,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 linux-2.6.14.7/fs/dquot.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/dquot.c --- linux-2.6.14.7/fs/dquot.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/dquot.c 2006-02-27 17:33:28.000000000 +0100 @@ -73,10 +73,12 @@ #include #include #include +#include #include #include #include #include +#include #include @@ -183,7 +185,7 @@ static void put_quota_format(struct quot /* * Dquot List Management: * The quota code uses three lists for dquot management: the inuse_list, - * free_dquots, and dquot_hash[] array. A single dquot structure may be + * free_dquots, and hash->dqh_hash[] array. A single dquot structure may be * on all three lists, depending on its current state. * * All dquots are placed to the end of inuse_list when first created, and this @@ -196,7 +198,7 @@ static void put_quota_format(struct quot * dquot is invalidated it's completely released from memory. * * Dquots with a specific identity (device, type and id) are placed on - * one of the dquot_hash[] hash chains. The provides an efficient search + * one of the hash->dqh_hash[] hash chains. The provides an efficient search * mechanism to locate a specific dquot. */ @@ -210,36 +212,44 @@ struct dqstats dqstats; static void dqput(struct dquot *dquot); static inline unsigned int -hashfn(const struct super_block *sb, unsigned int id, int type) +hashfn(struct dqhash *hash, unsigned int id, int type) { unsigned long tmp; - tmp = (((unsigned long)sb>>L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type); + tmp = (((unsigned long)hash >> L1_CACHE_SHIFT) ^ id) * (MAXQUOTAS - type); return (tmp + (tmp >> dq_hash_bits)) & dq_hash_mask; } /* * Following list functions expect dq_list_lock to be held */ -static inline void insert_dquot_hash(struct dquot *dquot) +static inline void insert_dquot_hash(struct dqhash *hash, struct dquot *dquot) { - struct hlist_head *head = dquot_hash + hashfn(dquot->dq_sb, dquot->dq_id, dquot->dq_type); + struct hlist_head *head = dquot_hash + + hashfn(hash, dquot->dq_id, dquot->dq_type); + /* struct hlist_head *head = hash->dqh_hash + + hashfn(dquot->dq_dqh, dquot->dq_id, dquot->dq_type); */ hlist_add_head(&dquot->dq_hash, head); + dquot->dq_dqh = dqhget(hash); } static inline void remove_dquot_hash(struct dquot *dquot) { hlist_del_init(&dquot->dq_hash); + dqhput(dquot->dq_dqh); + dquot->dq_dqh = NULL; } -static inline struct dquot *find_dquot(unsigned int hashent, struct super_block *sb, unsigned int id, int type) +static inline struct dquot *find_dquot(struct dqhash *hash, + unsigned int hashent, unsigned int id, int type) { struct hlist_node *node; struct dquot *dquot; - hlist_for_each (node, dquot_hash+hashent) { + /* hlist_for_each (node, hash->dqh_hash + hashent) { */ + hlist_for_each (node, dquot_hash + hashent) { dquot = hlist_entry(node, struct dquot, dq_hash); - if (dquot->dq_sb == sb && dquot->dq_id == id && dquot->dq_type == type) + if (dquot->dq_dqh == hash && dquot->dq_id == id && dquot->dq_type == type) return dquot; } return NODQUOT; @@ -283,13 +293,13 @@ static void wait_on_dquot(struct dquot * up(&dquot->dq_lock); } -#define mark_dquot_dirty(dquot) ((dquot)->dq_sb->dq_op->mark_dirty(dquot)) +#define mark_dquot_dirty(dquot) ((dquot)->dq_dqh->dqh_qop->mark_dirty(dquot)) int dquot_mark_dquot_dirty(struct dquot *dquot) { spin_lock(&dq_list_lock); if (!test_and_set_bit(DQ_MOD_B, &dquot->dq_flags)) - list_add(&dquot->dq_dirty, &sb_dqopt(dquot->dq_sb)-> + list_add(&dquot->dq_dirty, &dqh_dqopt(dquot->dq_dqh)-> info[dquot->dq_type].dqi_dirty_list); spin_unlock(&dq_list_lock); return 0; @@ -304,9 +314,9 @@ static inline int clear_dquot_dirty(stru return 1; } -void mark_info_dirty(struct super_block *sb, int type) +void mark_info_dirty(struct dqhash *hash, int type) { - set_bit(DQF_INFO_DIRTY_B, &sb_dqopt(sb)->info[type].dqi_flags); + set_bit(DQF_INFO_DIRTY_B, &dqh_dqopt(hash)->info[type].dqi_flags); } EXPORT_SYMBOL(mark_info_dirty); @@ -317,7 +327,7 @@ EXPORT_SYMBOL(mark_info_dirty); int dquot_acquire(struct dquot *dquot) { int ret = 0, ret2 = 0; - struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + struct quota_info *dqopt = dqh_dqopt(dquot->dq_dqh); down(&dquot->dq_lock); down(&dqopt->dqio_sem); @@ -331,7 +341,7 @@ int dquot_acquire(struct dquot *dquot) ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); /* Write the info if needed */ if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); + ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_dqh, dquot->dq_type); if (ret < 0) goto out_iolock; if (ret2 < 0) { @@ -352,7 +362,7 @@ out_iolock: int dquot_commit(struct dquot *dquot) { int ret = 0, ret2 = 0; - struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + struct quota_info *dqopt = dqh_dqopt(dquot->dq_dqh); down(&dqopt->dqio_sem); spin_lock(&dq_list_lock); @@ -366,7 +376,7 @@ int dquot_commit(struct dquot *dquot) if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { ret = dqopt->ops[dquot->dq_type]->commit_dqblk(dquot); if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); + ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_dqh, dquot->dq_type); if (ret >= 0) ret = ret2; } @@ -381,7 +391,7 @@ out_sem: int dquot_release(struct dquot *dquot) { int ret = 0, ret2 = 0; - struct quota_info *dqopt = sb_dqopt(dquot->dq_sb); + struct quota_info *dqopt = dqh_dqopt(dquot->dq_dqh); down(&dquot->dq_lock); /* Check whether we are not racing with some other dqget() */ @@ -392,7 +402,7 @@ int dquot_release(struct dquot *dquot) ret = dqopt->ops[dquot->dq_type]->release_dqblk(dquot); /* Write the info */ if (info_dirty(&dqopt->info[dquot->dq_type])) - ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_sb, dquot->dq_type); + ret2 = dqopt->ops[dquot->dq_type]->write_file_info(dquot->dq_dqh, dquot->dq_type); if (ret >= 0) ret = ret2; } @@ -407,13 +417,13 @@ out_dqlock: * quota is disabled and pointers from inodes removed so there cannot be new * quota users. Also because we hold dqonoff_sem there can be no quota users * for this sb+type at all. */ -static void invalidate_dquots(struct super_block *sb, int type) +static void invalidate_dquots(struct dqhash *hash, int type) { struct dquot *dquot, *tmp; spin_lock(&dq_list_lock); list_for_each_entry_safe(dquot, tmp, &inuse_list, dq_inuse) { - if (dquot->dq_sb != sb) + if (dquot->dq_dqh != hash) continue; if (dquot->dq_type != type) continue; @@ -430,18 +440,94 @@ static void invalidate_dquots(struct sup spin_unlock(&dq_list_lock); } -int vfs_quota_sync(struct super_block *sb, int type) + +/* Dquota Hash Management Functions */ + +static LIST_HEAD(dqhash_list); + +struct dqhash *new_dqhash(struct super_block *sb, unsigned int id) +{ + struct dqhash *hash; + int err; + + err = -ENOMEM; + hash = kmalloc(sizeof(struct dqhash), GFP_USER); + if (!hash) + goto out; + + memset(hash, 0, sizeof(struct dqhash)); + hash->dqh_id = id; + atomic_set(&hash->dqh_count, 1); + + INIT_LIST_HEAD(&hash->dqh_list); + + sema_init(&hash->dqh_dqopt.dqio_sem, 1); + sema_init(&hash->dqh_dqopt.dqonoff_sem, 1); + init_rwsem(&hash->dqh_dqopt.dqptr_sem); + hash->dqh_qop = sb->s_qop; + hash->dqh_qcop = sb->s_qcop; + hash->dqh_sb = sb; + + lock_kernel(); + list_add(&hash->dqh_list, &dqhash_list); + unlock_kernel(); + vxdprintk(VXD_CBIT(misc, 0), + "new_dqhash: %p [#0x%08x]", hash, hash->dqh_id); + return hash; + + // kfree(hash); +out: + return ERR_PTR(err); +} + +void destroy_dqhash(struct dqhash *hash) +{ + int cnt; + + vxdprintk(VXD_CBIT(misc, 0), + "destroy_dqhash: %p [#0x%08x] c=%d", + hash, hash->dqh_id, atomic_read(&hash->dqh_count)); + lock_kernel(); + list_del_init(&hash->dqh_list); + unlock_kernel(); + for (cnt = 0; cnt < MAXQUOTAS; cnt++) /* should not be required anymore! */ + invalidate_dquots(hash, cnt); + kfree(hash); +} + + +struct dqhash *find_dqhash(unsigned int id) +{ + struct list_head *head; + struct dqhash *hash; + + lock_kernel(); + list_for_each(head, &dqhash_list) { + hash = list_entry(head, struct dqhash, dqh_list); + if (hash->dqh_id == id) + goto dqh_found; + } + unlock_kernel(); + return NULL; + +dqh_found: + unlock_kernel(); + return dqhget(hash); +} + + +int vfs_quota_sync(struct dqhash *hash, int type) { struct list_head *dirty; struct dquot *dquot; - struct quota_info *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = dqh_dqopt(hash); int cnt; down(&dqopt->dqonoff_sem); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (type != -1 && cnt != type) continue; - if (!sb_has_quota_enabled(sb, cnt)) + if (!dqh_has_quota_enabled(hash, cnt)) continue; spin_lock(&dq_list_lock); dirty = &dqopt->info[cnt].dqi_dirty_list; @@ -458,7 +544,7 @@ int vfs_quota_sync(struct super_block *s atomic_inc(&dquot->dq_count); dqstats.lookups++; spin_unlock(&dq_list_lock); - sb->dq_op->write_dquot(dquot); + hash->dqh_qop->write_dquot(dquot); dqput(dquot); spin_lock(&dq_list_lock); } @@ -466,9 +552,10 @@ int vfs_quota_sync(struct super_block *s } for (cnt = 0; cnt < MAXQUOTAS; cnt++) - if ((cnt == type || type == -1) && sb_has_quota_enabled(sb, cnt) + if ((cnt == type || type == -1) + && dqh_has_quota_enabled(hash, cnt) && info_dirty(&dqopt->info[cnt])) - sb->dq_op->write_info(sb, cnt); + hash->dqh_qop->write_info(hash, cnt); spin_lock(&dq_list_lock); dqstats.syncs++; spin_unlock(&dq_list_lock); @@ -523,7 +610,7 @@ static void dqput(struct dquot *dquot) if (!atomic_read(&dquot->dq_count)) { printk("VFS: dqput: trying to free free dquot\n"); printk("VFS: device %s, dquot of %s %d\n", - dquot->dq_sb->s_id, + dquot->dq_dqh->dqh_sb->s_id, quotatypes[dquot->dq_type], dquot->dq_id); BUG(); @@ -545,14 +632,14 @@ we_slept: if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && dquot_dirty(dquot)) { spin_unlock(&dq_list_lock); /* Commit dquot before releasing */ - dquot->dq_sb->dq_op->write_dquot(dquot); + dquot->dq_dqh->dqh_qop->write_dquot(dquot); goto we_slept; } /* Clear flag in case dquot was inactive (something bad happened) */ clear_dquot_dirty(dquot); if (test_bit(DQ_ACTIVE_B, &dquot->dq_flags)) { spin_unlock(&dq_list_lock); - dquot->dq_sb->dq_op->release_dquot(dquot); + dquot->dq_dqh->dqh_qop->release_dquot(dquot); goto we_slept; } atomic_dec(&dquot->dq_count); @@ -565,7 +652,7 @@ we_slept: spin_unlock(&dq_list_lock); } -static struct dquot *get_empty_dquot(struct super_block *sb, int type) +static struct dquot *get_empty_dquot(int type) { struct dquot *dquot; @@ -579,7 +666,7 @@ static struct dquot *get_empty_dquot(str INIT_LIST_HEAD(&dquot->dq_inuse); INIT_HLIST_NODE(&dquot->dq_hash); INIT_LIST_HEAD(&dquot->dq_dirty); - dquot->dq_sb = sb; + dquot->dq_dqh = NULL; dquot->dq_type = type; atomic_set(&dquot->dq_count, 1); @@ -590,19 +677,19 @@ static struct dquot *get_empty_dquot(str * Get reference to dquot * MUST be called with either dqptr_sem or dqonoff_sem held */ -static struct dquot *dqget(struct super_block *sb, unsigned int id, int type) +static struct dquot *dqget(struct dqhash *hash, unsigned int id, int type) { - unsigned int hashent = hashfn(sb, id, type); + unsigned int hashent = hashfn(hash, id, type); struct dquot *dquot, *empty = NODQUOT; - if (!sb_has_quota_enabled(sb, type)) + if (!dqh_has_quota_enabled(hash, type)) return NODQUOT; we_slept: spin_lock(&dq_list_lock); - if ((dquot = find_dquot(hashent, sb, id, type)) == NODQUOT) { + if ((dquot = find_dquot(hash, hashent, id, type)) == NODQUOT) { if (empty == NODQUOT) { spin_unlock(&dq_list_lock); - if ((empty = get_empty_dquot(sb, type)) == NODQUOT) + if ((empty = get_empty_dquot(type)) == NODQUOT) schedule(); /* Try to wait for a moment... */ goto we_slept; } @@ -611,7 +698,7 @@ we_slept: /* all dquots go on the inuse_list */ put_inuse(dquot); /* hash it first so it can be found */ - insert_dquot_hash(dquot); + insert_dquot_hash(hash, dquot); dqstats.lookups++; spin_unlock(&dq_list_lock); } else { @@ -628,12 +715,13 @@ we_slept: * finished or it will be canceled due to dq_count > 1 test */ wait_on_dquot(dquot); /* Read the dquot and instantiate it (everything done only if needed) */ - if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && sb->dq_op->acquire_dquot(dquot) < 0) { + if (!test_bit(DQ_ACTIVE_B, &dquot->dq_flags) && + hash->dqh_qop->acquire_dquot(dquot) < 0) { dqput(dquot); return NODQUOT; } #ifdef __DQUOT_PARANOIA - if (!dquot->dq_sb) /* Has somebody invalidated entry under us? */ + if (!dquot->dq_dqh) /* Has somebody invalidated entry under us? */ BUG(); #endif @@ -655,9 +743,10 @@ static int dqinit_needed(struct inode *i } /* This routine is guarded by dqonoff_sem semaphore */ -static void add_dquot_ref(struct super_block *sb, int type) +static void add_dquot_ref(struct dqhash *hash, int type) { struct list_head *p; + struct super_block *sb = hash->dqh_sb; restart: file_list_lock(); @@ -667,7 +756,7 @@ restart: if (filp->f_mode & FMODE_WRITE && dqinit_needed(inode, type)) { struct dentry *dentry = dget(filp->f_dentry); file_list_unlock(); - sb->dq_op->initialize(inode, type); + hash->dqh_qop->initialize(inode, type); dput(dentry); /* As we may have blocked we had better restart... */ goto restart; @@ -726,16 +815,16 @@ static void put_dquot_list(struct list_h } /* Gather all references from inodes and drop them */ -static void drop_dquot_ref(struct super_block *sb, int type) +static void drop_dquot_ref(struct dqhash *hash, int type) { LIST_HEAD(tofree_head); /* We need to be guarded against prune_icache to reach all the * inodes - otherwise some can be on the local list of prune_icache */ down(&iprune_sem); - down_write(&sb_dqopt(sb)->dqptr_sem); - remove_dquot_ref(sb, type, &tofree_head); - up_write(&sb_dqopt(sb)->dqptr_sem); + down_write(&dqh_dqopt(hash)->dqptr_sem); + remove_dquot_ref(hash, type, &tofree_head); + up_write(&dqh_dqopt(hash)->dqptr_sem); up(&iprune_sem); put_dquot_list(&tofree_head); } @@ -807,7 +896,7 @@ static void print_warning(struct dquot * if (!need_print_warning(dquot) || (flag && test_and_set_bit(flag, &dquot->dq_flags))) return; - tty_write_message(current->signal->tty, dquot->dq_sb->s_id); + tty_write_message(current->signal->tty, dquot->dq_dqh->dqh_sb->s_id); if (warntype == ISOFTWARN || warntype == BSOFTWARN) tty_write_message(current->signal->tty, ": warning, "); else @@ -847,7 +936,7 @@ static inline void flush_warnings(struct static inline char ignore_hardlimit(struct dquot *dquot) { - struct mem_dqinfo *info = &sb_dqopt(dquot->dq_sb)->info[dquot->dq_type]; + struct mem_dqinfo *info = &dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type]; return capable(CAP_SYS_RESOURCE) && (info->dqi_format->qf_fmt_id != QFMT_VFS_OLD || !(info->dqi_flags & V1_DQF_RSQUASH)); @@ -879,7 +968,7 @@ static int check_idq(struct dquot *dquot (dquot->dq_dqb.dqb_curinodes + inodes) > dquot->dq_dqb.dqb_isoftlimit && dquot->dq_dqb.dqb_itime == 0) { *warntype = ISOFTWARN; - dquot->dq_dqb.dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; + dquot->dq_dqb.dqb_itime = get_seconds() + dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type].dqi_igrace; } return QUOTA_OK; @@ -914,7 +1003,7 @@ static int check_bdq(struct dquot *dquot dquot->dq_dqb.dqb_btime == 0) { if (!prealloc) { *warntype = BSOFTWARN; - dquot->dq_dqb.dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; + dquot->dq_dqb.dqb_btime = get_seconds() + dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type].dqi_bgrace; } else /* @@ -940,7 +1029,7 @@ int dquot_initialize(struct inode *inode * re-enter the quota code and are already holding the semaphore */ if (IS_NOQUOTA(inode)) return 0; - down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); /* Having dqptr_sem we know NOQUOTA flags can't be altered... */ if (IS_NOQUOTA(inode)) goto out_err; @@ -956,11 +1045,11 @@ int dquot_initialize(struct inode *inode id = inode->i_gid; break; } - inode->i_dquot[cnt] = dqget(inode->i_sb, id, cnt); + inode->i_dquot[cnt] = dqget(inode->i_dqh, id, cnt); } } out_err: - up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return ret; } @@ -972,14 +1061,14 @@ int dquot_drop(struct inode *inode) { int cnt; - down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); for (cnt = 0; cnt < MAXQUOTAS; cnt++) { if (inode->i_dquot[cnt] != NODQUOT) { dqput(inode->i_dquot[cnt]); inode->i_dquot[cnt] = NODQUOT; } } - up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return 0; } @@ -1010,9 +1099,9 @@ out_add: for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = NOWARN; - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); if (IS_NOQUOTA(inode)) { /* Now we can do reliable test... */ - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); goto out_add; } spin_lock(&dq_data_lock); @@ -1037,7 +1126,7 @@ warn_put_all: if (inode->i_dquot[cnt]) mark_dquot_dirty(inode->i_dquot[cnt]); flush_warnings(inode->i_dquot, warntype); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return ret; } @@ -1055,9 +1144,9 @@ int dquot_alloc_inode(const struct inode return QUOTA_OK; for (cnt = 0; cnt < MAXQUOTAS; cnt++) warntype[cnt] = NOWARN; - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); if (IS_NOQUOTA(inode)) { - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return QUOTA_OK; } spin_lock(&dq_data_lock); @@ -1082,7 +1171,7 @@ warn_put_all: if (inode->i_dquot[cnt]) mark_dquot_dirty(inode->i_dquot[cnt]); flush_warnings((struct dquot **)inode->i_dquot, warntype); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return ret; } @@ -1100,10 +1189,10 @@ out_sub: inode_sub_bytes(inode, number); return QUOTA_OK; } - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); /* Now recheck reliably when holding dqptr_sem */ if (IS_NOQUOTA(inode)) { - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); goto out_sub; } spin_lock(&dq_data_lock); @@ -1118,7 +1207,7 @@ out_sub: for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (inode->i_dquot[cnt]) mark_dquot_dirty(inode->i_dquot[cnt]); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return QUOTA_OK; } @@ -1133,10 +1222,10 @@ int dquot_free_inode(const struct inode * re-enter the quota code and are already holding the semaphore */ if (IS_NOQUOTA(inode)) return QUOTA_OK; - down_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); /* Now recheck reliably when holding dqptr_sem */ if (IS_NOQUOTA(inode)) { - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return QUOTA_OK; } spin_lock(&dq_data_lock); @@ -1150,7 +1239,7 @@ int dquot_free_inode(const struct inode for (cnt = 0; cnt < MAXQUOTAS; cnt++) if (inode->i_dquot[cnt]) mark_dquot_dirty(inode->i_dquot[cnt]); - up_read(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_read(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return QUOTA_OK; } @@ -1165,6 +1254,7 @@ int dquot_transfer(struct inode *inode, qsize_t space; struct dquot *transfer_from[MAXQUOTAS]; struct dquot *transfer_to[MAXQUOTAS]; + struct dqhash *dqh = inode->i_sb->s_dqh; int cnt, ret = NO_QUOTA, chuid = (iattr->ia_valid & ATTR_UID) && inode->i_uid != iattr->ia_uid, chgid = (iattr->ia_valid & ATTR_GID) && inode->i_gid != iattr->ia_gid; char warntype[MAXQUOTAS]; @@ -1178,10 +1268,10 @@ int dquot_transfer(struct inode *inode, transfer_to[cnt] = transfer_from[cnt] = NODQUOT; warntype[cnt] = NOWARN; } - down_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + down_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); /* Now recheck reliably when holding dqptr_sem */ if (IS_NOQUOTA(inode)) { /* File without quota accounting? */ - up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return QUOTA_OK; } /* First build the transfer_to list - here we can block on @@ -1192,12 +1282,12 @@ int dquot_transfer(struct inode *inode, case USRQUOTA: if (!chuid) continue; - transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_uid, cnt); + transfer_to[cnt] = dqget(dqh, iattr->ia_uid, cnt); break; case GRPQUOTA: if (!chgid) continue; - transfer_to[cnt] = dqget(inode->i_sb, iattr->ia_gid, cnt); + transfer_to[cnt] = dqget(dqh, iattr->ia_gid, cnt); break; } } @@ -1252,20 +1342,20 @@ warn_put_all: if (ret == NO_QUOTA && transfer_to[cnt] != NODQUOT) dqput(transfer_to[cnt]); } - up_write(&sb_dqopt(inode->i_sb)->dqptr_sem); + up_write(&dqh_dqopt(inode->i_dqh)->dqptr_sem); return ret; } /* * Write info of quota file to disk */ -int dquot_commit_info(struct super_block *sb, int type) +int dquot_commit_info(struct dqhash *hash, int type) { int ret; - struct quota_info *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = dqh_dqopt(hash); down(&dqopt->dqio_sem); - ret = dqopt->ops[type]->write_file_info(sb, type); + ret = dqopt->ops[type]->write_file_info(hash, type); up(&dqopt->dqio_sem); return ret; } @@ -1315,10 +1405,10 @@ static inline void reset_enable_flags(st /* * Turn quota off on a device. type == -1 ==> quotaoff for all types (umount) */ -int vfs_quota_off(struct super_block *sb, int type) +int vfs_quota_off(struct dqhash *hash, int type) { int cnt; - struct quota_info *dqopt = sb_dqopt(sb); + struct quota_info *dqopt = dqh_dqopt(hash); struct inode *toputinode[MAXQUOTAS]; struct vfsmount *toputmnt[MAXQUOTAS]; @@ -1329,21 +1419,21 @@ int vfs_quota_off(struct super_block *sb toputmnt[cnt] = NULL; if (type != -1 && cnt != type) continue; - if (!sb_has_quota_enabled(sb, cnt)) + if (!dqh_has_quota_enabled(hash, cnt)) continue; reset_enable_flags(dqopt, cnt); /* Note: these are blocking operations */ - drop_dquot_ref(sb, cnt); - invalidate_dquots(sb, cnt); + drop_dquot_ref(hash, cnt); + invalidate_dquots(hash, cnt); /* * Now all dquots should be invalidated, all writes done so we should be only * users of the info. No locks needed. */ if (info_dirty(&dqopt->info[cnt])) - sb->dq_op->write_info(sb, cnt); + hash->dqh_qop->write_info(hash, cnt); if (dqopt->ops[cnt]->free_file_info) - dqopt->ops[cnt]->free_file_info(sb, cnt); + dqopt->ops[cnt]->free_file_info(hash, cnt); put_quota_format(dqopt->info[cnt].dqi_format); toputinode[cnt] = dqopt->files[cnt]; @@ -1361,9 +1451,9 @@ int vfs_quota_off(struct super_block *sb * The reference to vfsmnt we are still holding protects us from * umount (we don't have it only when quotas are turned on/off for * journal replay but in that case we are guarded by the fs anyway). */ - if (sb->s_op->sync_fs) - sb->s_op->sync_fs(sb, 1); - sync_blockdev(sb->s_bdev); + if (hash->dqh_sb->s_op->sync_fs) + hash->dqh_sb->s_op->sync_fs(hash->dqh_sb, 1); + sync_blockdev(hash->dqh_sb->s_bdev); /* Now the quota files are just ordinary files and we can set the * inode flags back. Moreover we discard the pagecache so that * userspace sees the writes we did bypassing the pagecache. We @@ -1374,7 +1464,7 @@ int vfs_quota_off(struct super_block *sb down(&dqopt->dqonoff_sem); /* If quota was reenabled in the meantime, we have * nothing to do */ - if (!sb_has_quota_enabled(sb, cnt)) { + if (!dqh_has_quota_enabled(hash, cnt)) { down(&toputinode[cnt]->i_sem); toputinode[cnt]->i_flags &= ~(S_IMMUTABLE | S_NOATIME | S_NOQUOTA); @@ -1389,8 +1479,8 @@ int vfs_quota_off(struct super_block *sb if (toputmnt[cnt]) mntput(toputmnt[cnt]); } - if (sb->s_bdev) - invalidate_bdev(sb->s_bdev, 0); + if (hash->dqh_sb->s_bdev) + invalidate_bdev(hash->dqh_sb->s_bdev, 0); return 0; } @@ -1403,7 +1493,8 @@ static int vfs_quota_on_inode(struct ino { struct quota_format_type *fmt = find_quota_format(format_id); struct super_block *sb = inode->i_sb; - struct quota_info *dqopt = sb_dqopt(sb); + struct dqhash *hash = inode->i_dqh; + struct quota_info *dqopt = dqh_dqopt(hash); int error; int oldflags = -1; @@ -1429,7 +1520,7 @@ static int vfs_quota_on_inode(struct ino invalidate_bdev(sb->s_bdev, 0); down(&inode->i_sem); down(&dqopt->dqonoff_sem); - if (sb_has_quota_enabled(sb, type)) { + if (dqh_has_quota_enabled(hash, type)) { error = -EBUSY; goto out_lock; } @@ -1440,21 +1531,21 @@ static int vfs_quota_on_inode(struct ino oldflags = inode->i_flags & (S_NOATIME | S_IMMUTABLE | S_NOQUOTA); inode->i_flags |= S_NOQUOTA | S_NOATIME | S_IMMUTABLE; up_write(&dqopt->dqptr_sem); - sb->dq_op->drop(inode); + hash->dqh_qop->drop(inode); error = -EIO; dqopt->files[type] = igrab(inode); if (!dqopt->files[type]) goto out_lock; error = -EINVAL; - if (!fmt->qf_ops->check_quota_file(sb, type)) + if (!fmt->qf_ops->check_quota_file(hash, type)) goto out_file_init; dqopt->ops[type] = fmt->qf_ops; dqopt->info[type].dqi_format = fmt; INIT_LIST_HEAD(&dqopt->info[type].dqi_dirty_list); down(&dqopt->dqio_sem); - if ((error = dqopt->ops[type]->read_file_info(sb, type)) < 0) { + if ((error = dqopt->ops[type]->read_file_info(hash, type)) < 0) { up(&dqopt->dqio_sem); goto out_file_init; } @@ -1462,7 +1553,7 @@ static int vfs_quota_on_inode(struct ino up(&inode->i_sem); set_enable_flags(dqopt, type); - add_dquot_ref(sb, type); + add_dquot_ref(hash, type); up(&dqopt->dqonoff_sem); return 0; @@ -1488,7 +1579,7 @@ out_fmt: } /* Actual function called from quotactl() */ -int vfs_quota_on(struct super_block *sb, int type, int format_id, char *path) +int vfs_quota_on(struct dqhash *hash, int type, int format_id, char *path) { struct nameidata nd; int error; @@ -1500,12 +1591,12 @@ int vfs_quota_on(struct super_block *sb, if (error) goto out_path; /* Quota file not on the same filesystem? */ - if (nd.mnt->mnt_sb != sb) + if (nd.mnt->mnt_sb != hash->dqh_sb) error = -EXDEV; else { error = vfs_quota_on_inode(nd.dentry->d_inode, type, format_id); if (!error) - sb_dqopt(sb)->mnt[type] = mntget(nd.mnt); + dqh_dqopt(hash)->mnt[type] = mntget(nd.mnt); } out_path: path_release(&nd); @@ -1516,13 +1607,13 @@ out_path: * This function is used when filesystem needs to initialize quotas * during mount time. */ -int vfs_quota_on_mount(struct super_block *sb, char *qf_name, +int vfs_quota_on_mount(struct dqhash *hash, char *qf_name, int format_id, int type) { struct dentry *dentry; int error; - dentry = lookup_one_len(qf_name, sb->s_root, strlen(qf_name)); + dentry = lookup_one_len(qf_name, hash->dqh_sb->s_root, strlen(qf_name)); if (IS_ERR(dentry)) return PTR_ERR(dentry); @@ -1552,18 +1643,18 @@ static void do_get_dqblk(struct dquot *d spin_unlock(&dq_data_lock); } -int vfs_get_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +int vfs_get_dqblk(struct dqhash *hash, int type, qid_t id, struct if_dqblk *di) { struct dquot *dquot; - down(&sb_dqopt(sb)->dqonoff_sem); - if (!(dquot = dqget(sb, id, type))) { - up(&sb_dqopt(sb)->dqonoff_sem); + down(&dqh_dqopt(hash)->dqonoff_sem); + if (!(dquot = dqget(hash, id, type))) { + up(&dqh_dqopt(hash)->dqonoff_sem); return -ESRCH; } do_get_dqblk(dquot, di); dqput(dquot); - up(&sb_dqopt(sb)->dqonoff_sem); + up(&dqh_dqopt(hash)->dqonoff_sem); return 0; } @@ -1603,7 +1694,7 @@ static void do_set_dqblk(struct dquot *d clear_bit(DQ_BLKS_B, &dquot->dq_flags); } else if (!(di->dqb_valid & QIF_BTIME)) /* Set grace only if user hasn't provided his own... */ - dm->dqb_btime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_bgrace; + dm->dqb_btime = get_seconds() + dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type].dqi_bgrace; } if (check_ilim) { if (!dm->dqb_isoftlimit || dm->dqb_curinodes < dm->dqb_isoftlimit) { @@ -1611,7 +1702,7 @@ static void do_set_dqblk(struct dquot *d clear_bit(DQ_INODES_B, &dquot->dq_flags); } else if (!(di->dqb_valid & QIF_ITIME)) /* Set grace only if user hasn't provided his own... */ - dm->dqb_itime = get_seconds() + sb_dqopt(dquot->dq_sb)->info[dquot->dq_type].dqi_igrace; + dm->dqb_itime = get_seconds() + dqh_dqopt(dquot->dq_dqh)->info[dquot->dq_type].dqi_igrace; } if (dm->dqb_bhardlimit || dm->dqb_bsoftlimit || dm->dqb_ihardlimit || dm->dqb_isoftlimit) clear_bit(DQ_FAKE_B, &dquot->dq_flags); @@ -1621,53 +1712,53 @@ static void do_set_dqblk(struct dquot *d mark_dquot_dirty(dquot); } -int vfs_set_dqblk(struct super_block *sb, int type, qid_t id, struct if_dqblk *di) +int vfs_set_dqblk(struct dqhash *hash, int type, qid_t id, struct if_dqblk *di) { struct dquot *dquot; - down(&sb_dqopt(sb)->dqonoff_sem); - if (!(dquot = dqget(sb, id, type))) { - up(&sb_dqopt(sb)->dqonoff_sem); + down(&dqh_dqopt(hash)->dqonoff_sem); + if (!(dquot = dqget(hash, id, type))) { + up(&dqh_dqopt(hash)->dqonoff_sem); return -ESRCH; } do_set_dqblk(dquot, di); dqput(dquot); - up(&sb_dqopt(sb)->dqonoff_sem); + up(&dqh_dqopt(hash)->dqonoff_sem); return 0; } /* Generic routine for getting common part of quota file information */ -int vfs_get_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +int vfs_get_dqinfo(struct dqhash *hash, int type, struct if_dqinfo *ii) { struct mem_dqinfo *mi; - down(&sb_dqopt(sb)->dqonoff_sem); - if (!sb_has_quota_enabled(sb, type)) { - up(&sb_dqopt(sb)->dqonoff_sem); + down(&dqh_dqopt(hash)->dqonoff_sem); + if (!dqh_has_quota_enabled(hash, type)) { + up(&dqh_dqopt(hash)->dqonoff_sem); return -ESRCH; } - mi = sb_dqopt(sb)->info + type; + mi = dqh_dqopt(hash)->info + type; spin_lock(&dq_data_lock); ii->dqi_bgrace = mi->dqi_bgrace; ii->dqi_igrace = mi->dqi_igrace; ii->dqi_flags = mi->dqi_flags & DQF_MASK; ii->dqi_valid = IIF_ALL; spin_unlock(&dq_data_lock); - up(&sb_dqopt(sb)->dqonoff_sem); + up(&dqh_dqopt(hash)->dqonoff_sem); return 0; } /* Generic routine for setting common part of quota file information */ -int vfs_set_dqinfo(struct super_block *sb, int type, struct if_dqinfo *ii) +int vfs_set_dqinfo(struct dqhash *hash, int type, struct if_dqinfo *ii) { struct mem_dqinfo *mi; - down(&sb_dqopt(sb)->dqonoff_sem); - if (!sb_has_quota_enabled(sb, type)) { - up(&sb_dqopt(sb)->dqonoff_sem); + down(&dqh_dqopt(hash)->dqonoff_sem); + if (!dqh_has_quota_enabled(hash, type)) { + up(&dqh_dqopt(hash)->dqonoff_sem); return -ESRCH; } - mi = sb_dqopt(sb)->info + type; + mi = dqh_dqopt(hash)->info + type; spin_lock(&dq_data_lock); if (ii->dqi_valid & IIF_BGRACE) mi->dqi_bgrace = ii->dqi_bgrace; @@ -1676,10 +1767,10 @@ int vfs_set_dqinfo(struct super_block *s if (ii->dqi_valid & IIF_FLAGS) mi->dqi_flags = (mi->dqi_flags & ~DQF_MASK) | (ii->dqi_flags & DQF_MASK); spin_unlock(&dq_data_lock); - mark_info_dirty(sb, type); + mark_info_dirty(hash, type); /* Force write to disk */ - sb->dq_op->write_info(sb, type); - up(&sb_dqopt(sb)->dqonoff_sem); + hash->dqh_qop->write_info(hash, type); + up(&dqh_dqopt(hash)->dqonoff_sem); return 0; } diff -NurpP linux-2.6.14.7/fs/exec.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/exec.c --- linux-2.6.14.7/fs/exec.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/exec.c 2006-02-27 18:15:28.000000000 +0100 @@ -48,6 +48,9 @@ #include #include #include +#include +#include +#include #include #include @@ -66,6 +69,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; @@ -313,6 +325,10 @@ void install_arg_page(struct vm_area_str if (unlikely(anon_vma_prepare(vma))) goto out_sig; +#ifdef CONFIG_PAX_SEGMEXEC + if (page_count(page) == 1) +#endif + flush_dcache_page(page); pgd = pgd_offset(mm, address); @@ -331,6 +347,11 @@ void install_arg_page(struct vm_area_str goto out; } inc_mm_counter(mm, 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)))); @@ -359,6 +380,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. @@ -423,6 +448,18 @@ int setup_arg_pages(struct linux_binprm 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_alloc(vm_area_cachep, SLAB_KERNEL); + if (!mpnt_m) { + kmem_cache_free(vm_area_cachep, mpnt); + return -ENOMEM; + } + + memset(mpnt_m, 0, sizeof(*mpnt_m)); + } +#endif + down_write(&mm->mmap_sem); { mpnt->vm_mm = mm; @@ -443,13 +480,51 @@ int setup_arg_pages(struct linux_binprm else mpnt->vm_flags = VM_STACK_FLAGS; mpnt->vm_flags |= mm->def_flags; + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(mm->pax_flags & MF_PAX_PAGEEXEC)) + mpnt->vm_page_prot = protection_map[(mpnt->vm_flags | VM_EXEC) & 0x7]; + else +#endif + mpnt->vm_page_prot = protection_map[mpnt->vm_flags & 0x7]; 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++) { @@ -457,6 +532,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 +1230,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 = kmalloc(sizeof(*bprm), GFP_KERNEL); @@ -1159,10 +1247,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; @@ -1204,8 +1311,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 */ @@ -1216,6 +1353,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++) { @@ -1376,6 +1521,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; @@ -1486,6 +1739,10 @@ int do_coredump(long signr, int exit_cod current->signal->group_stop_count = 0; 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; @@ -1511,7 +1768,7 @@ int do_coredump(long signr, int exit_cod goto close_fail; if (!file->f_op->write) goto close_fail; - if (do_truncate(file->f_dentry, 0) != 0) + if (do_truncate(file->f_dentry, 0, file->f_vfsmnt) != 0) goto close_fail; retval = binfmt->core_dump(signr, regs, file); diff -NurpP linux-2.6.14.7/fs/ext2/balloc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/balloc.c --- linux-2.6.14.7/fs/ext2/balloc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/balloc.c 2006-02-27 17:33:28.000000000 +0100 @@ -16,6 +16,7 @@ #include #include #include +#include /* * balloc.c contains the blocks allocation and deallocation routines @@ -108,6 +109,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; @@ -258,6 +261,7 @@ do_more: } error_return: brelse(bitmap_bh); + DLIMIT_FREE_BLOCK(inode, freed); release_blocks(sb, freed); DQUOT_FREE_BLOCK(inode, freed); } @@ -361,6 +365,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); @@ -508,6 +516,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 linux-2.6.14.7/fs/ext2/ext2.h linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/ext2.h --- linux-2.6.14.7/fs/ext2/ext2.h 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/ext2.h 2006-02-27 17:33:28.000000000 +0100 @@ -162,6 +162,7 @@ extern struct file_operations ext2_xip_f 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 linux-2.6.14.7/fs/ext2/file.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/file.c --- linux-2.6.14.7/fs/ext2/file.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/file.c 2006-02-27 17:33:28.000000000 +0100 @@ -53,6 +53,7 @@ struct file_operations ext2_file_operati .readv = generic_file_readv, .writev = generic_file_writev, .sendfile = generic_file_sendfile, + .sendpage = generic_file_sendpage, }; #ifdef CONFIG_EXT2_FS_XIP @@ -79,4 +80,5 @@ struct inode_operations ext2_file_inode_ #endif .setattr = ext2_setattr, .permission = ext2_permission, + .sync_flags = ext2_sync_flags, }; diff -NurpP linux-2.6.14.7/fs/ext2/ialloc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/ialloc.c --- linux-2.6.14.7/fs/ext2/ialloc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/ialloc.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 */ @@ -605,7 +614,7 @@ got: insert_inode_hash(inode); if (DQUOT_ALLOC_INODE(inode)) { - err = -ENOSPC; + err = -EDQUOT; goto fail_drop; } @@ -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 linux-2.6.14.7/fs/ext2/inode.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/inode.c --- linux-2.6.14.7/fs/ext2/inode.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/inode.c 2006-02-27 17:33:28.000000000 +0100 @@ -31,6 +31,7 @@ #include #include #include +#include #include "ext2.h" #include "acl.h" #include "xip.h" @@ -66,6 +67,8 @@ void ext2_put_inode(struct inode *inode) ext2_discard_prealloc(inode); } +static void ext2_truncate_nocheck (struct inode * inode); + /* * Called at the last iput() if i_nlink is zero. */ @@ -81,7 +84,7 @@ void ext2_delete_inode (struct inode * i inode->i_size = 0; if (inode->i_blocks) - ext2_truncate (inode); + ext2_truncate_nocheck(inode); ext2_free_inode (inode); return; @@ -902,7 +905,7 @@ static void ext2_free_branches(struct in ext2_free_data(inode, p, q); } -void ext2_truncate (struct inode * inode) +static void ext2_truncate_nocheck(struct inode * inode) { __le32 *i_data = EXT2_I(inode)->i_data; int addr_per_block = EXT2_ADDR_PER_BLOCK(inode->i_sb); @@ -919,8 +922,6 @@ void ext2_truncate (struct inode * inode return; if (ext2_inode_is_fast_symlink(inode)) return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; ext2_discard_prealloc(inode); @@ -1044,29 +1045,81 @@ Egdp: return ERR_PTR(-EIO); } +void ext2_truncate (struct inode * inode) +{ + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + ext2_truncate_nocheck(inode); +} + void ext2_set_inode_flags(struct inode *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 @@ -1077,12 +1130,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); @@ -1180,8 +1238,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; @@ -1216,6 +1274,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); @@ -1302,7 +1363,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 linux-2.6.14.7/fs/ext2/ioctl.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/ioctl.c --- linux-2.6.14.7/fs/ext2/ioctl.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/ioctl.c 2006-02-27 17:33:28.000000000 +0100 @@ -29,7 +29,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)) @@ -49,7 +50,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; } @@ -68,7 +71,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 linux-2.6.14.7/fs/ext2/namei.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/namei.c --- linux-2.6.14.7/fs/ext2/namei.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/namei.c 2006-02-27 17:33:28.000000000 +0100 @@ -31,6 +31,7 @@ */ #include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -82,6 +83,7 @@ static struct dentry *ext2_lookup(struct inode = iget(dir->i_sb, ino); if (!inode) return ERR_PTR(-EACCES); + vx_propagate_xid(nd, inode); } if (inode) return d_splice_alias(inode, dentry); @@ -410,6 +412,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 = { @@ -421,4 +424,5 @@ struct inode_operations ext2_special_ino #endif .setattr = ext2_setattr, .permission = ext2_permission, + .sync_flags = ext2_sync_flags, }; diff -NurpP linux-2.6.14.7/fs/ext2/super.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/super.c --- linux-2.6.14.7/fs/ext2/super.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/super.c 2006-02-27 17:33:28.000000000 +0100 @@ -225,8 +225,8 @@ static int ext2_show_options(struct seq_ } #ifdef CONFIG_QUOTA -static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, size_t len, loff_t off); -static ssize_t ext2_quota_write(struct super_block *sb, int type, const char *data, size_t len, loff_t off); +static ssize_t ext2_quota_read(struct dqhash *hash, int type, char *data, size_t len, loff_t off); +static ssize_t ext2_quota_write(struct dqhash *hash, int type, const char *data, size_t len, loff_t off); #endif static struct super_operations ext2_sops = { @@ -284,7 +284,7 @@ enum { Opt_err_ro, Opt_nouid32, Opt_check, 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 = { @@ -313,6 +313,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"}, @@ -376,6 +377,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_check: #ifdef CONFIG_EXT2_CHECK set_opt (sbi->s_mount_opt, CHECK); @@ -690,6 +696,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); @@ -999,6 +1007,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); @@ -1110,10 +1125,11 @@ static struct super_block *ext2_get_sb(s * acquiring the locks... As quota files are never truncated and quota code * itself serializes the operations (and noone else should touch the files) * we don't have to be afraid of races */ -static ssize_t ext2_quota_read(struct super_block *sb, int type, char *data, +static ssize_t ext2_quota_read(struct dqhash *hash, int type, char *data, size_t len, loff_t off) { - struct inode *inode = sb_dqopt(sb)->files[type]; + struct inode *inode = dqh_dqopt(hash)->files[type]; + struct super_block *sb = hash->dqh_sb; sector_t blk = off >> EXT2_BLOCK_SIZE_BITS(sb); int err = 0; int offset = off & (sb->s_blocksize - 1); @@ -1154,10 +1170,11 @@ static ssize_t ext2_quota_read(struct su } /* Write to quotafile */ -static ssize_t ext2_quota_write(struct super_block *sb, int type, +static ssize_t ext2_quota_write(struct dqhash *hash, int type, const char *data, size_t len, loff_t off) { - struct inode *inode = sb_dqopt(sb)->files[type]; + struct inode *inode = dqh_dqopt(hash)->files[type]; + struct super_block *sb = hash->dqh_sb; sector_t blk = off >> EXT2_BLOCK_SIZE_BITS(sb); int err = 0; int offset = off & (sb->s_blocksize - 1); diff -NurpP linux-2.6.14.7/fs/ext2/symlink.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/symlink.c --- linux-2.6.14.7/fs/ext2/symlink.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/symlink.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/fs/ext2/xattr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/xattr.c --- linux-2.6.14.7/fs/ext2/xattr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext2/xattr.c 2006-02-27 17:33:28.000000000 +0100 @@ -60,6 +60,7 @@ #include #include #include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -649,8 +650,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; } @@ -744,6 +749,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); } ea_bdebug(bh, "refcount now=%d", le32_to_cpu(HDR(bh)->h_refcount) - 1); diff -NurpP linux-2.6.14.7/fs/ext3/balloc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/balloc.c --- linux-2.6.14.7/fs/ext3/balloc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/balloc.c 2006-02-27 17:33:28.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include /* * balloc.c contains the blocks allocation and deallocation routines @@ -503,8 +504,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; } @@ -1115,18 +1118,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); } /* @@ -1137,7 +1154,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); @@ -1192,6 +1209,8 @@ int ext3_new_block(handle_t *handle, str *errp = -EDQUOT; return 0; } + if (DLIMIT_ALLOC_BLOCK(inode, 1)) + goto out_dlimit; sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; @@ -1208,7 +1227,7 @@ int ext3_new_block(handle_t *handle, str 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; } @@ -1392,6 +1411,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 linux-2.6.14.7/fs/ext3/file.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/file.c --- linux-2.6.14.7/fs/ext3/file.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/file.c 2006-02-27 17:33:28.000000000 +0100 @@ -119,6 +119,7 @@ struct file_operations ext3_file_operati .release = ext3_release_file, .fsync = ext3_sync_file, .sendfile = generic_file_sendfile, + .sendpage = generic_file_sendpage, }; struct inode_operations ext3_file_inode_operations = { @@ -131,5 +132,6 @@ struct inode_operations ext3_file_inode_ .removexattr = generic_removexattr, #endif .permission = ext3_permission, + .sync_flags = ext3_sync_flags, }; diff -NurpP linux-2.6.14.7/fs/ext3/ialloc.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/ialloc.c --- linux-2.6.14.7/fs/ext3/ialloc.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/ialloc.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/fs/ext3/inode.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/inode.c --- linux-2.6.14.7/fs/ext3/inode.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/inode.c 2006-02-27 17:33:28.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include "xattr.h" #include "acl.h" @@ -180,6 +181,8 @@ static int ext3_journal_test_restart(han return ext3_journal_restart(handle, blocks_for_truncate(inode)); } +static void ext3_truncate_nocheck (struct inode *inode); + /* * Called at the last iput() if i_nlink is zero. */ @@ -205,7 +208,7 @@ void ext3_delete_inode (struct inode * i handle->h_sync = 1; inode->i_size = 0; if (inode->i_blocks) - ext3_truncate(inode); + ext3_truncate_nocheck(inode); /* * Kill off the orphan record which ext3_truncate created. * AKPM: I think this can be inside the above `if'. @@ -2067,7 +2070,7 @@ static void ext3_free_branches(handle_t * ext3_truncate() run will find them and release them. */ -void ext3_truncate(struct inode * inode) +void ext3_truncate_nocheck(struct inode * inode) { handle_t *handle; struct ext3_inode_info *ei = EXT3_I(inode); @@ -2088,8 +2091,6 @@ void ext3_truncate(struct inode * inode) return; if (ext3_inode_is_fast_symlink(inode)) return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) - return; /* * We have to lock the EOF page here, because lock_page() nests @@ -2408,23 +2409,88 @@ int ext3_get_inode_loc(struct inode *ino !(EXT3_I(inode)->i_state & EXT3_STATE_XATTR)); } +void ext3_truncate(struct inode * inode) +{ + if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + return; + ext3_truncate_nocheck(inode); +} + void ext3_set_inode_flags(struct inode *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; @@ -2432,6 +2498,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; @@ -2444,12 +2512,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); @@ -2576,6 +2649,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, @@ -2585,29 +2660,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); @@ -2760,7 +2838,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, @@ -2782,6 +2861,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 linux-2.6.14.7/fs/ext3/ioctl.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/ioctl.c --- linux-2.6.14.7/fs/ext3/ioctl.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/ioctl.c 2006-02-27 17:33:28.000000000 +0100 @@ -12,6 +12,7 @@ #include #include #include +#include #include @@ -35,7 +36,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)) @@ -58,7 +60,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)) return -EPERM; } @@ -111,7 +115,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; @@ -165,7 +170,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)) @@ -200,7 +206,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)) @@ -221,7 +228,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, @@ -236,6 +244,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 *) 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 linux-2.6.14.7/fs/ext3/namei.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/namei.c --- linux-2.6.14.7/fs/ext3/namei.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/namei.c 2006-02-27 17:33:28.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include "xattr.h" #include "acl.h" @@ -1002,6 +1003,7 @@ static struct dentry *ext3_lookup(struct if (!inode) return ERR_PTR(-EACCES); + vx_propagate_xid(nd, inode); } if (inode) return d_splice_alias(inode, dentry); @@ -2373,6 +2375,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 = { @@ -2384,4 +2387,5 @@ struct inode_operations ext3_special_ino .removexattr = generic_removexattr, #endif .permission = ext3_permission, + .sync_flags = ext3_sync_flags, }; diff -NurpP linux-2.6.14.7/fs/ext3/super.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/super.c --- linux-2.6.14.7/fs/ext3/super.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/super.c 2006-02-27 17:33:28.000000000 +0100 @@ -553,12 +553,12 @@ static int ext3_write_dquot(struct dquot static int ext3_acquire_dquot(struct dquot *dquot); static int ext3_release_dquot(struct dquot *dquot); static int ext3_mark_dquot_dirty(struct dquot *dquot); -static int ext3_write_info(struct super_block *sb, int type); -static int ext3_quota_on(struct super_block *sb, int type, int format_id, char *path); -static int ext3_quota_on_mount(struct super_block *sb, int type); -static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, +static int ext3_write_info(struct dqhash *hash, int type); +static int ext3_quota_on(struct dqhash *hash, int type, int format_id, char *path); +static int ext3_quota_on_mount(struct dqhash *hash, int type); +static ssize_t ext3_quota_read(struct dqhash *hash, int type, char *data, size_t len, loff_t off); -static ssize_t ext3_quota_write(struct super_block *sb, int type, +static ssize_t ext3_quota_write(struct dqhash *hash, int type, const char *data, size_t len, loff_t off); static struct dquot_operations ext3_quota_operations = { @@ -625,7 +625,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 = { @@ -674,6 +674,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"}, }; @@ -765,6 +766,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_check: #ifdef CONFIG_EXT3_CHECK set_opt (sbi->s_mount_opt, CHECK); @@ -881,7 +887,7 @@ static int parse_options (char * options case Opt_grpjquota: qtype = GRPQUOTA; set_qf_name: - if (sb_any_quota_enabled(sb)) { + if (dqh_any_quota_enabled(sb->s_dqh)) { printk(KERN_ERR "EXT3-fs: Cannot change journalled " "quota options when quota turned on.\n"); @@ -919,7 +925,7 @@ set_qf_name: case Opt_offgrpjquota: qtype = GRPQUOTA; clear_qf_name: - if (sb_any_quota_enabled(sb)) { + if (dqh_any_quota_enabled(sb->s_dqh)) { printk(KERN_ERR "EXT3-fs: Cannot change " "journalled quota options when " "quota turned on.\n"); @@ -947,7 +953,7 @@ clear_qf_name: set_opt(sbi->s_mount_opt, GRPQUOTA); break; case Opt_noquota: - if (sb_any_quota_enabled(sb)) { + if (dqh_any_quota_enabled(sb->s_dqh)) { printk(KERN_ERR "EXT3-fs: Cannot change quota " "options when quota turned on.\n"); return 0; @@ -1225,7 +1231,7 @@ static void ext3_orphan_cleanup (struct /* Turn on quotas so that they are updated correctly */ for (i = 0; i < MAXQUOTAS; i++) { if (EXT3_SB(sb)->s_qf_names[i]) { - int ret = ext3_quota_on_mount(sb, i); + int ret = ext3_quota_on_mount(sb->s_dqh, i); if (ret < 0) printk(KERN_ERR "EXT3-fs: Cannot turn on journalled " @@ -1275,8 +1281,8 @@ static void ext3_orphan_cleanup (struct #ifdef CONFIG_QUOTA /* Turn quotas off */ for (i = 0; i < MAXQUOTAS; i++) { - if (sb_dqopt(sb)->files[i]) - vfs_quota_off(sb, i); + if (dqh_dqopt(sb->s_dqh)->files[i]) + vfs_quota_off(sb->s_dqh, i); } #endif sb->s_flags = s_flags; /* Restore MS_RDONLY status */ @@ -1421,6 +1427,9 @@ static int ext3_fill_super (struct super if (!parse_options ((char *) data, sb, &journal_inum, 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); @@ -1612,8 +1621,8 @@ static int ext3_fill_super (struct super sb->s_export_op = &ext3_export_ops; sb->s_xattr = ext3_xattr_handlers; #ifdef CONFIG_QUOTA - sb->s_qcop = &ext3_qctl_operations; - sb->dq_op = &ext3_quota_operations; + sb->s_dqh->dqh_qop = &ext3_quota_operations; + sb->s_dqh->dqh_qcop = &ext3_qctl_operations; #endif INIT_LIST_HEAD(&sbi->s_orphan); /* unlinked but open files */ @@ -2211,6 +2220,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); @@ -2364,7 +2379,7 @@ static int ext3_statfs (struct super_blo static inline struct inode *dquot_to_inode(struct dquot *dquot) { - return sb_dqopt(dquot->dq_sb)->files[dquot->dq_type]; + return dqh_dqopt(dquot->dq_dqh)->files[dquot->dq_type]; } static int ext3_dquot_initialize(struct inode *inode, int type) @@ -2407,7 +2422,7 @@ static int ext3_write_dquot(struct dquot inode = dquot_to_inode(dquot); handle = ext3_journal_start(inode, - EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_sb)); + EXT3_QUOTA_TRANS_BLOCKS(dquot->dq_dqh->dqh_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_commit(dquot); @@ -2423,7 +2438,7 @@ static int ext3_acquire_dquot(struct dqu handle_t *handle; handle = ext3_journal_start(dquot_to_inode(dquot), - EXT3_QUOTA_INIT_BLOCKS(dquot->dq_sb)); + EXT3_QUOTA_INIT_BLOCKS(dquot->dq_dqh->dqh_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_acquire(dquot); @@ -2439,7 +2454,7 @@ static int ext3_release_dquot(struct dqu handle_t *handle; handle = ext3_journal_start(dquot_to_inode(dquot), - EXT3_QUOTA_DEL_BLOCKS(dquot->dq_sb)); + EXT3_QUOTA_DEL_BLOCKS(dquot->dq_dqh->dqh_sb)); if (IS_ERR(handle)) return PTR_ERR(handle); ret = dquot_release(dquot); @@ -2452,8 +2467,8 @@ static int ext3_release_dquot(struct dqu static int ext3_mark_dquot_dirty(struct dquot *dquot) { /* Are we journalling quotas? */ - if (EXT3_SB(dquot->dq_sb)->s_qf_names[USRQUOTA] || - EXT3_SB(dquot->dq_sb)->s_qf_names[GRPQUOTA]) { + if (EXT3_SB(dquot->dq_dqh->dqh_sb)->s_qf_names[USRQUOTA] || + EXT3_SB(dquot->dq_dqh->dqh_sb)->s_qf_names[GRPQUOTA]) { dquot_mark_dquot_dirty(dquot); return ext3_write_dquot(dquot); } else { @@ -2461,8 +2476,9 @@ static int ext3_mark_dquot_dirty(struct } } -static int ext3_write_info(struct super_block *sb, int type) +static int ext3_write_info(struct dqhash *hash, int type) { + struct super_block *sb = hash->dqh_sb; int ret, err; handle_t *handle; @@ -2470,7 +2486,7 @@ static int ext3_write_info(struct super_ handle = ext3_journal_start(sb->s_root->d_inode, 2); if (IS_ERR(handle)) return PTR_ERR(handle); - ret = dquot_commit_info(sb, type); + ret = dquot_commit_info(hash, type); err = ext3_journal_stop(handle); if (!ret) ret = err; @@ -2481,18 +2497,20 @@ static int ext3_write_info(struct super_ * Turn on quotas during mount time - we need to find * the quota file and such... */ -static int ext3_quota_on_mount(struct super_block *sb, int type) +static int ext3_quota_on_mount(struct dqhash *hash, int type) { - return vfs_quota_on_mount(sb, EXT3_SB(sb)->s_qf_names[type], - EXT3_SB(sb)->s_jquota_fmt, type); + return vfs_quota_on_mount(hash, + EXT3_SB(hash->dqh_sb)->s_qf_names[type], + EXT3_SB(hash->dqh_sb)->s_jquota_fmt, type); } /* * Standard function to be called on quota_on */ -static int ext3_quota_on(struct super_block *sb, int type, int format_id, +static int ext3_quota_on(struct dqhash *hash, int type, int format_id, char *path) { + struct super_block *sb = hash->dqh_sb; int err; struct nameidata nd; @@ -2501,7 +2519,7 @@ static int ext3_quota_on(struct super_bl /* Not journalling quota? */ if (!EXT3_SB(sb)->s_qf_names[USRQUOTA] && !EXT3_SB(sb)->s_qf_names[GRPQUOTA]) - return vfs_quota_on(sb, type, format_id, path); + return vfs_quota_on(hash, type, format_id, path); err = path_lookup(path, LOOKUP_FOLLOW, &nd); if (err) return err; @@ -2516,17 +2534,18 @@ static int ext3_quota_on(struct super_bl "EXT3-fs: Quota file not on filesystem root. " "Journalled quota will not work.\n"); path_release(&nd); - return vfs_quota_on(sb, type, format_id, path); + return vfs_quota_on(hash, type, format_id, path); } /* Read data from quotafile - avoid pagecache and such because we cannot afford * acquiring the locks... As quota files are never truncated and quota code * itself serializes the operations (and noone else should touch the files) * we don't have to be afraid of races */ -static ssize_t ext3_quota_read(struct super_block *sb, int type, char *data, +static ssize_t ext3_quota_read(struct dqhash *hash, int type, char *data, size_t len, loff_t off) { - struct inode *inode = sb_dqopt(sb)->files[type]; + struct inode *inode = dqh_dqopt(hash)->files[type]; + struct super_block *sb = hash->dqh_sb; sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); int err = 0; int offset = off & (sb->s_blocksize - 1); @@ -2561,10 +2580,11 @@ static ssize_t ext3_quota_read(struct su /* Write to quotafile (we know the transaction is already started and has * enough credits) */ -static ssize_t ext3_quota_write(struct super_block *sb, int type, +static ssize_t ext3_quota_write(struct dqhash *hash, int type, const char *data, size_t len, loff_t off) { - struct inode *inode = sb_dqopt(sb)->files[type]; + struct inode *inode = dqh_dqopt(hash)->files[type]; + struct super_block *sb = hash->dqh_sb; sector_t blk = off >> EXT3_BLOCK_SIZE_BITS(sb); int err = 0; int offset = off & (sb->s_blocksize - 1); diff -NurpP linux-2.6.14.7/fs/ext3/symlink.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/symlink.c --- linux-2.6.14.7/fs/ext3/symlink.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/symlink.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/fs/ext3/xattr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/xattr.c --- linux-2.6.14.7/fs/ext3/xattr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ext3/xattr.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/fs/fcntl.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/fcntl.c --- linux-2.6.14.7/fs/fcntl.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/fcntl.c 2006-02-27 18:03:16.000000000 +0100 @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include #include @@ -62,6 +64,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; @@ -82,8 +85,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; @@ -424,7 +436,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, @@ -477,7 +490,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); } @@ -512,7 +525,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 linux-2.6.14.7/fs/file_table.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/file_table.c --- linux-2.6.14.7/fs/file_table.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/file_table.c 2006-02-27 17:33:28.000000000 +0100 @@ -18,6 +18,8 @@ #include #include #include +#include +#include /* sysctl tunables... */ struct files_stat_struct files_stat = { @@ -96,6 +98,8 @@ struct file *get_empty_filp(void) rwlock_init(&f->f_owner.lock); /* f->f_version: 0 */ INIT_LIST_HEAD(&f->f_list); + f->f_xid = vx_current_xid(); + vx_files_inc(f); return f; over: @@ -150,6 +154,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; @@ -215,6 +221,8 @@ void put_filp(struct file *file) { if (rcuref_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 linux-2.6.14.7/fs/hfsplus/ioctl.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/hfsplus/ioctl.c --- linux-2.6.14.7/fs/hfsplus/ioctl.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/hfsplus/ioctl.c 2006-02-27 17:33:28.000000000 +0100 @@ -34,7 +34,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 linux-2.6.14.7/fs/inode.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/inode.c --- linux-2.6.14.7/fs/inode.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/inode.c 2006-02-27 17:33:28.000000000 +0100 @@ -115,6 +115,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); @@ -127,6 +130,7 @@ static struct inode *alloc_inode(struct inode->i_bytes = 0; inode->i_generation = 0; #ifdef CONFIG_QUOTA + inode->i_dqh = dqhget(sb->s_dqh); memset(&inode->i_dquot, 0, sizeof(inode->i_dquot)); #endif inode->i_pipe = NULL; @@ -174,6 +178,8 @@ void destroy_inode(struct inode *inode) if (inode_has_buffers(inode)) BUG(); security_inode_free(inode); + if (dqhash_valid(inode->i_dqh)) + dqhput(inode->i_dqh); if (inode->i_sb->s_op->destroy_inode) inode->i_sb->s_op->destroy_inode(inode); else @@ -235,6 +241,8 @@ void __iget(struct inode * inode) inodes_stat.nr_unused--; } +EXPORT_SYMBOL_GPL(__iget); + /** * clear_inode - clear an inode * @inode: inode to clear @@ -1256,12 +1264,13 @@ EXPORT_SYMBOL(inode_needs_sync); /* Function back in dquot.c */ int remove_inode_dquot_ref(struct inode *, int, struct list_head *); -void remove_dquot_ref(struct super_block *sb, int type, +void remove_dquot_ref(struct dqhash *hash, int type, struct list_head *tofree_head) { struct inode *inode; + struct super_block *sb = hash->dqh_sb; - if (!sb->dq_op) + if (!hash->dqh_qop) return; /* nothing to do */ spin_lock(&inode_lock); /* This lock is for inodes code */ diff -NurpP linux-2.6.14.7/fs/ioctl.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ioctl.c --- linux-2.6.14.7/fs/ioctl.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ioctl.c 2006-02-27 17:33:28.000000000 +0100 @@ -12,10 +12,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) { @@ -146,6 +155,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 *) 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 *) 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 linux-2.6.14.7/fs/ioprio.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ioprio.c --- linux-2.6.14.7/fs/ioprio.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/ioprio.c 2006-02-27 17:33:28.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include static int set_task_ioprio(struct task_struct *task, int ioprio) { @@ -93,7 +94,7 @@ asmlinkage long sys_ioprio_set(int which if (!who) user = current->user; else - user = find_user(who); + user = find_user(who, vx_current_xid()); if (!user) break; @@ -147,7 +148,7 @@ asmlinkage long sys_ioprio_get(int which if (!who) user = current->user; else - user = find_user(who); + user = find_user(who, vx_current_xid()); if (!user) break; diff -NurpP linux-2.6.14.7/fs/jfs/acl.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/acl.c --- linux-2.6.14.7/fs/jfs/acl.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/acl.c 2006-02-27 17:33:28.000000000 +0100 @@ -229,7 +229,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 linux-2.6.14.7/fs/jfs/file.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/file.c --- linux-2.6.14.7/fs/jfs/file.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/file.c 2006-02-27 17:33:28.000000000 +0100 @@ -111,6 +111,7 @@ struct file_operations jfs_file_operatio .readv = generic_file_readv, .writev = generic_file_writev, .sendfile = generic_file_sendfile, + .sendpage = generic_file_sendpage, .fsync = jfs_fsync, .release = jfs_release, }; diff -NurpP linux-2.6.14.7/fs/jfs/inode.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/inode.c --- linux-2.6.14.7/fs/jfs/inode.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/inode.c 2006-02-27 17:33:28.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_filsys.h" @@ -143,6 +144,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 linux-2.6.14.7/fs/jfs/jfs_dtree.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_dtree.c --- linux-2.6.14.7/fs/jfs/jfs_dtree.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_dtree.c 2006-02-27 17:33:28.000000000 +0100 @@ -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_dquot; + if (dbAlloc(ip, 0, sbi->nbperpage, &xaddr)) + goto clean_up_dlimit; /* * Save the table, we're going to overwrite it with the @@ -479,6 +480,12 @@ static u32 add_index(tid_t tid, struct i return index; + clean_up_dlimit: + DLIMIT_FREE_BLOCK(ip, sbi->nbperpage); + + clean_up_dquot: + DQUOT_FREE_BLOCK(ip, sbi->nbperpage); + clean_up: jfs_ip->next_index--; @@ -930,7 +937,8 @@ int dtInsert(tid_t tid, struct inode *ip static int dtSplitUp(tid_t tid, struct inode *ip, struct dtsplit * split, struct btstack * btstack) { - struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + struct super_block *sb = ip->i_sb; + struct jfs_sb_info *sbi = JFS_SBI(sb); int rc = 0; struct metapage *smp; dtpage_t *sp; /* split page */ @@ -952,6 +960,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; @@ -1033,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; @@ -1301,6 +1316,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); @@ -1368,6 +1386,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); @@ -1918,6 +1942,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); /* @@ -2284,6 +2314,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); @@ -2360,6 +2392,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 linux-2.6.14.7/fs/jfs/jfs_extent.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_extent.c --- linux-2.6.14.7/fs/jfs/jfs_extent.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_extent.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 up(&JFS_IP(ip)->commit_sem); 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; + } /* 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); up(&JFS_IP(ip)->commit_sem); return (rc); @@ -261,6 +270,13 @@ int extRealloc(struct inode *ip, s64 nxl up(&JFS_IP(ip)->commit_sem); 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 linux-2.6.14.7/fs/jfs/jfs_filsys.h linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_filsys.h --- linux-2.6.14.7/fs/jfs/jfs_filsys.h 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_filsys.h 2006-02-27 17:33:28.000000000 +0100 @@ -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 linux-2.6.14.7/fs/jfs/jfs_imap.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_imap.c --- linux-2.6.14.7/fs/jfs/jfs_imap.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_imap.c 2006-02-27 17:33:28.000000000 +0100 @@ -45,6 +45,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_inode.h" @@ -3072,14 +3073,21 @@ static void duplicateIXtree(struct super static int copy_from_dinode(struct dinode * dip, struct inode *ip) { struct jfs_inode_info *jfs_ip = JFS_IP(ip); + uid_t uid; + gid_t gid; jfs_ip->fileset = le32_to_cpu(dip->di_fileset); jfs_ip->mode2 = le32_to_cpu(dip->di_mode); ip->i_mode = le32_to_cpu(dip->di_mode) & 0xffff; ip->i_nlink = le32_to_cpu(dip->di_nlink); - ip->i_uid = le32_to_cpu(dip->di_uid); - ip->i_gid = le32_to_cpu(dip->di_gid); + + uid = le32_to_cpu(dip->di_uid); + gid = le32_to_cpu(dip->di_gid); + ip->i_uid = INOXID_UID(XID_TAG(ip), uid, gid); + ip->i_gid = INOXID_GID(XID_TAG(ip), uid, gid); + ip->i_xid = INOXID_XID(XID_TAG(ip), uid, gid, 0); + ip->i_size = le64_to_cpu(dip->di_size); ip->i_atime.tv_sec = le32_to_cpu(dip->di_atime.tv_sec); ip->i_atime.tv_nsec = le32_to_cpu(dip->di_atime.tv_nsec); @@ -3130,6 +3138,8 @@ static int copy_from_dinode(struct dinod static void copy_to_dinode(struct dinode * dip, struct inode *ip) { struct jfs_inode_info *jfs_ip = JFS_IP(ip); + uid_t uid; + gid_t gid; dip->di_fileset = cpu_to_le32(jfs_ip->fileset); dip->di_inostamp = cpu_to_le32(JFS_SBI(ip->i_sb)->inostamp); @@ -3138,8 +3148,11 @@ 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); - dip->di_uid = cpu_to_le32(ip->i_uid); - dip->di_gid = cpu_to_le32(ip->i_gid); + + uid = XIDINO_UID(XID_TAG(ip), ip->i_uid, ip->i_xid); + gid = XIDINO_GID(XID_TAG(ip), ip->i_gid, ip->i_xid); + dip->di_uid = cpu_to_le32(uid); + dip->di_gid = cpu_to_le32(gid); /* * mode2 is only needed for storing the higher order bits. * Trust i_mode for the lower order ones diff -NurpP linux-2.6.14.7/fs/jfs/jfs_inode.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_inode.c --- linux-2.6.14.7/fs/jfs/jfs_inode.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_inode.c 2006-02-27 17:33:28.000000000 +0100 @@ -18,6 +18,8 @@ #include #include +#include +#include #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_filsys.h" @@ -62,10 +64,17 @@ struct inode *ialloc(struct inode *paren } else inode->i_gid = current->fsgid; + 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 linux-2.6.14.7/fs/jfs/jfs_xtree.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_xtree.c --- linux-2.6.14.7/fs/jfs/jfs_xtree.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/jfs_xtree.c 2006-02-27 17:33:28.000000000 +0100 @@ -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); @@ -1243,13 +1251,20 @@ xtSplitPage(tid_t tid, struct inode *ip, rbn = addressPXD(pxd); /* Allocate blocks to quota. */ - if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + if (DQUOT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { rc = -EDQUOT; goto clean_up; } 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 linux-2.6.14.7/fs/jfs/namei.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/namei.c --- linux-2.6.14.7/fs/jfs/namei.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/namei.c 2006-02-27 17:33:28.000000000 +0100 @@ -20,6 +20,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_inode.h" @@ -1462,6 +1463,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)) diff -NurpP linux-2.6.14.7/fs/jfs/super.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/super.c --- linux-2.6.14.7/fs/jfs/super.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/super.c 2006-02-27 17:33:28.000000000 +0100 @@ -195,7 +195,7 @@ 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_usrquota, Opt_grpquota, Opt_tagxid }; static match_table_t tokens = { @@ -205,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"}, @@ -313,7 +314,11 @@ static int parse_options(char *options, "JFS: quota operations not supported\n"); break; #endif - +#ifndef CONFIG_INOXID_NONE + case Opt_tagxid: + *flag |= JFS_TAGXID; + break; +#endif default: printk("jfs: Unrecognized mount option \"%s\" " " or missing value\n", p); @@ -344,6 +349,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 @@ -415,6 +427,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 linux-2.6.14.7/fs/jfs/xattr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/xattr.c --- linux-2.6.14.7/fs/jfs/xattr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/jfs/xattr.c 2006-02-27 17:33:28.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_dmap.h" @@ -277,9 +278,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; @@ -346,6 +354,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); @@ -482,6 +492,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) @@ -557,6 +568,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) @@ -613,6 +630,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); @@ -689,8 +709,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 linux-2.6.14.7/fs/libfs.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/libfs.c --- linux-2.6.14.7/fs/libfs.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/libfs.c 2006-02-27 17:33:28.000000000 +0100 @@ -122,7 +122,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; @@ -156,6 +157,8 @@ int dcache_readdir(struct file * filp, v next = list_entry(p, struct dentry, 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) @@ -172,6 +175,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; @@ -620,6 +635,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 linux-2.6.14.7/fs/locks.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/locks.c --- linux-2.6.14.7/fs/locks.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/locks.c 2006-02-27 17:33:28.000000000 +0100 @@ -125,6 +125,7 @@ #include #include #include +#include #include #include @@ -150,12 +151,16 @@ static kmem_cache_t *filelock_cache; /* 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); } /* Free a lock which is not in use. */ static inline void locks_free_lock(struct file_lock *fl) { + vx_locks_dec(fl); + if (fl == NULL) { BUG(); return; @@ -199,6 +204,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); @@ -236,6 +242,8 @@ void locks_copy_lock(struct file_lock *n fl->fl_ops->fl_copy_lock(new, fl); if (fl->fl_lmops && fl->fl_lmops->fl_copy_lock) fl->fl_lmops->fl_copy_lock(new, fl); + + new->fl_xid = fl->fl_xid; } EXPORT_SYMBOL(locks_copy_lock); @@ -272,6 +280,11 @@ static int flock_make_lock(struct file * fl->fl_flags = FL_FLOCK; fl->fl_type = type; fl->fl_end = OFFSET_MAX; + + vxd_assert(filp->f_xid == vx_current_xid(), + "f_xid(%d) == current(%d)", filp->f_xid, vx_current_xid()); + fl->fl_xid = filp->f_xid; + vx_locks_inc(fl); *lock = fl; return 0; @@ -449,6 +462,11 @@ static int lease_alloc(struct file *filp if (fl == NULL) return -ENOMEM; + fl->fl_xid = vx_current_xid(); + if (filp) + vxd_assert(filp->f_xid == fl->fl_xid, + "f_xid(%d) == fl_xid(%d)", filp->f_xid, fl->fl_xid); + vx_locks_inc(fl); error = lease_init(filp, type, fl); if (error) return error; @@ -764,7 +782,7 @@ out: EXPORT_SYMBOL(posix_lock_file); -static int __posix_lock_file(struct inode *inode, struct file_lock *request) +static int __posix_lock_file(struct inode *inode, struct file_lock *request, xid_t xid) { struct file_lock *fl; struct file_lock *new_fl, *new_fl2; @@ -773,12 +791,18 @@ static int __posix_lock_file(struct inod struct file_lock **before; int error, added = 0; + vxd_assert(xid == vx_current_xid(), + "xid(%d) == current(%d)", xid, vx_current_xid()); /* * We may need two file_lock structures for this operation, * 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) { @@ -952,7 +976,7 @@ static int __posix_lock_file(struct inod */ int posix_lock_file(struct file *filp, struct file_lock *fl) { - return __posix_lock_file(filp->f_dentry->d_inode, fl); + return __posix_lock_file(filp->f_dentry->d_inode, fl, filp->f_xid); } /** @@ -969,7 +993,8 @@ int posix_lock_file_wait(struct file *fi int error; might_sleep (); for (;;) { - error = __posix_lock_file(filp->f_dentry->d_inode, fl); + error = __posix_lock_file(filp->f_dentry->d_inode, + fl, filp->f_xid); if ((error != -EAGAIN) || !(fl->fl_flags & FL_SLEEP)) break; error = wait_event_interruptible(fl->fl_wait, !fl->fl_next); @@ -1041,7 +1066,7 @@ int locks_mandatory_area(int read_write, fl.fl_end = offset + count - 1; for (;;) { - error = __posix_lock_file(inode, &fl); + error = __posix_lock_file(inode, &fl, filp->f_xid); if (error != -EAGAIN) break; if (!(fl.fl_flags & FL_SLEEP)) @@ -1603,6 +1628,11 @@ int fcntl_setlk(unsigned int fd, struct if (file_lock == NULL) return -ENOLCK; + vxd_assert(filp->f_xid == vx_current_xid(), + "f_xid(%d) == current(%d)", filp->f_xid, vx_current_xid()); + file_lock->fl_xid = filp->f_xid; + vx_locks_inc(file_lock); + /* * This might block, so we do it before checking the inode. */ @@ -1655,7 +1685,8 @@ again: error = filp->f_op->lock(filp, cmd, file_lock); else { for (;;) { - error = __posix_lock_file(inode, file_lock); + error = __posix_lock_file(inode, file_lock, + filp->f_xid); if ((error != -EAGAIN) || (cmd == F_SETLK)) break; error = wait_event_interruptible(file_lock->fl_wait, @@ -1746,6 +1777,11 @@ int fcntl_setlk64(unsigned int fd, struc if (file_lock == NULL) return -ENOLCK; + vxd_assert(filp->f_xid == vx_current_xid(), + "f_xid(%d) == current(%d)", filp->f_xid, vx_current_xid()); + file_lock->fl_xid = filp->f_xid; + vx_locks_inc(file_lock); + /* * This might block, so we do it before checking the inode. */ @@ -1798,7 +1834,8 @@ again: error = filp->f_op->lock(filp, cmd, file_lock); else { for (;;) { - error = __posix_lock_file(inode, file_lock); + error = __posix_lock_file(inode, file_lock, + filp->f_xid); if ((error != -EAGAIN) || (cmd == F_SETLK64)) break; error = wait_event_interruptible(file_lock->fl_wait, @@ -2075,6 +2112,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 linux-2.6.14.7/fs/namei.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/namei.c --- linux-2.6.14.7/fs/namei.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/namei.c 2006-02-27 18:14:33.000000000 +0100 @@ -28,6 +28,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -221,6 +225,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_path(nd->dentry, nd->mnt)); + return -EACCES; +} + int permission(struct inode *inode, int mask, struct nameidata *nd) { int retval, submask; @@ -231,7 +253,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; @@ -245,6 +267,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 @@ -560,6 +584,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++; @@ -654,7 +685,8 @@ static inline void follow_dotdot(struct 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); @@ -691,16 +723,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); @@ -903,11 +953,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; @@ -1184,7 +1241,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 inline int may_delete(struct inode *dir,struct dentry *victim,int isdir) +static inline int may_delete(struct inode *dir, struct dentry *victim, + int isdir, struct nameidata *nd) { int error; @@ -1193,13 +1251,13 @@ static inline int may_delete(struct inod BUG_ON(victim->d_parent->d_inode != dir); - 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)) @@ -1336,6 +1394,11 @@ int may_open(struct nameidata *nd, int a if (S_ISDIR(inode->i_mode) && (flag & FMODE_WRITE)) return -EISDIR; +#ifdef CONFIG_VSERVER_COWBL + if (IS_COW_LINK(inode) && (flag & FMODE_WRITE)) + return -EMLINK; +#endif + error = permission(inode, acc_mode, nd); if (error) return error; @@ -1352,7 +1415,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. @@ -1388,7 +1452,7 @@ int may_open(struct nameidata *nd, int a if (!error) { DQUOT_INIT(inode); - error = do_truncate(dentry, 0); + error = do_truncate(dentry, 0, nd->mnt); } put_write_access(inode); if (error) @@ -1400,6 +1464,8 @@ int may_open(struct nameidata *nd, int a return 0; } +int cow_break_link(struct dentry *dentry, const char *pathname); + /* * open_namei() * @@ -1421,6 +1487,11 @@ int open_namei(const char * pathname, in struct dentry *dir; int count = 0; +#ifdef CONFIG_VSERVER_COWBL + int rflag = flag; + int rmode = mode; +restart: +#endif acc_mode = ACC_MODE(flag); /* Allow the LSM permission hook to distinguish append @@ -1439,6 +1510,17 @@ int open_namei(const char * pathname, in error = path_lookup(pathname, lookup_flags(flag)|LOOKUP_OPEN, nd); 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; } @@ -1473,9 +1555,18 @@ 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; + up(&dir->d_inode->i_sem); + 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); + up(&dir->d_inode->i_sem); dput(nd->dentry); nd->dentry = path.dentry; @@ -1490,6 +1581,25 @@ do_last: /* * It already exists. */ + + if (gr_handle_rawio(path.dentry->d_inode)) { + error = -EPERM; + up(&dir->d_inode->i_sem); + goto exit_dput; + } + + if (!gr_acl_handle_open(path.dentry, nd->mnt, flag)) { + up(&dir->d_inode->i_sem); + error = -EACCES; + goto exit_dput; + } + + if (gr_handle_fifo(path.dentry, nd->mnt, dir, flag, acc_mode)) { + up(&dir->d_inode->i_sem); + error = -EACCES; + goto exit_dput; + } + up(&dir->d_inode->i_sem); error = -EEXIST; @@ -1513,6 +1623,18 @@ do_last: goto exit; ok: error = may_open(nd, acc_mode, flag); +#ifdef CONFIG_VSERVER_COWBL + if (error == -EMLINK) { + error = cow_break_link(path.dentry, pathname); + if (error) + goto exit; + path_release(nd); + vxdprintk(VXD_CBIT(misc, 2), "restarting open_namei() ..."); + flag = rflag; + mode = rmode; + goto restart; + } +#endif if (error) goto exit; return 0; @@ -1541,6 +1663,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) return error; @@ -1614,9 +1743,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; @@ -1660,16 +1790,33 @@ asmlinkage long sys_mknod(const char __u 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); + up(&nd.dentry->d_inode->i_sem); + path_release(&nd); + goto out; + } + + if (!gr_acl_handle_mknod(dentry, nd.dentry, nd.mnt, mode)) { + error = -EACCES; + dput(dentry); + up(&nd.dentry->d_inode->i_sem); + 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; @@ -1677,6 +1824,10 @@ asmlinkage long sys_mknod(const char __u default: error = -EINVAL; } + + if (!error) + gr_handle_create(dentry, nd.mnt); + dput(dentry); } up(&nd.dentry->d_inode->i_sem); @@ -1687,9 +1838,10 @@ out: return error; } -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; @@ -1726,9 +1878,20 @@ asmlinkage long sys_mkdir(const char __u 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); } up(&nd.dentry->d_inode->i_sem); @@ -1768,9 +1931,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; @@ -1807,6 +1971,8 @@ asmlinkage long sys_rmdir(const char __u 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)) @@ -1831,7 +1997,21 @@ asmlinkage long sys_rmdir(const char __u dentry = lookup_hash(&nd.last, nd.dentry); 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); } up(&nd.dentry->d_inode->i_sem); @@ -1842,9 +2022,10 @@ exit: return error; } -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; @@ -1885,6 +2066,8 @@ asmlinkage long sys_unlink(const char __ 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)) @@ -1900,13 +2083,26 @@ asmlinkage long sys_unlink(const char __ dentry = lookup_hash(&nd.last, nd.dentry); 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); } @@ -1925,9 +2121,10 @@ slashes: goto exit2; } -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; @@ -1967,7 +2164,16 @@ asmlinkage long sys_symlink(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); } up(&nd.dentry->d_inode->i_sem); @@ -1979,7 +2185,8 @@ out: return error; } -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; @@ -1987,7 +2194,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; @@ -1997,7 +2204,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; @@ -2049,7 +2256,21 @@ asmlinkage long sys_link(const char __us 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); } up(&nd.dentry->d_inode->i_sem); @@ -2176,14 +2397,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; @@ -2260,6 +2481,9 @@ static inline int do_rename(const char * error = -EINVAL; if (old_dentry == trap) goto exit4; + error = -EROFS; + if (MNT_IS_RDONLY(newnd.mnt)) + goto exit4; new_dentry = lookup_hash(&newnd.last, new_dir); error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) @@ -2269,8 +2493,16 @@ static inline int do_rename(const char * 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: @@ -2347,6 +2579,128 @@ int vfs_follow_link(struct nameidata *nd return __vfs_follow_link(nd, link); } + +#ifdef CONFIG_VSERVER_COWBL + +#include + +int cow_break_link(struct dentry *dentry, const char *pathname) +{ + int err = -EMLINK; + int ret, mode, pathlen; + struct nameidata old_nd, dir_nd; + struct dentry *old_dentry, *new_dentry; + struct vfsmount *old_mnt, *new_mnt; + struct file *old_file; + struct file *new_file; + char *to, *path, pad='\251'; + loff_t size; + + vxdprintk(VXD_CBIT(misc, 2), + "cow_break_link(%p,»%s«)", dentry, pathname); + path = kmalloc(PATH_MAX, GFP_KERNEL); + + ret = path_lookup(pathname, LOOKUP_FOLLOW, &old_nd); + vxdprintk(VXD_CBIT(misc, 2), "path_lookup(old): %d", ret); + old_dentry = old_nd.dentry; + old_mnt = old_nd.mnt; + mode = old_dentry->d_inode->i_mode; + + to = d_path(old_dentry, old_mnt, path, PATH_MAX-2); + pathlen = strlen(to); + vxdprintk(VXD_CBIT(misc, 2), "old path »%s«", to); + + to[pathlen+1] = 0; +retry: + to[pathlen] = pad--; + if (pad <= '\240') + goto out_rel_old; + + vxdprintk(VXD_CBIT(misc, 2), "temp copy »%s«", to); + ret = path_lookup(to, + LOOKUP_PARENT|LOOKUP_OPEN|LOOKUP_CREATE, &dir_nd); + + /* this puppy downs the inode sem */ + new_dentry = lookup_create(&dir_nd, 0); + vxdprintk(VXD_CBIT(misc, 2), + "lookup_create(new): %p", new_dentry); + if (!new_dentry) { + path_release(&dir_nd); + goto retry; + } + + ret = vfs_create(dir_nd.dentry->d_inode, new_dentry, mode, &dir_nd); + vxdprintk(VXD_CBIT(misc, 2), + "vfs_create(new): %d", ret); + if (ret == -EEXIST) { + up(&dir_nd.dentry->d_inode->i_sem); + dput(new_dentry); + path_release(&dir_nd); + goto retry; + } + + new_mnt = dir_nd.mnt; + + dget(old_dentry); + mntget(old_mnt); + /* this one cleans up the dentry in case of failure */ + old_file = dentry_open(old_dentry, old_mnt, O_RDONLY); + vxdprintk(VXD_CBIT(misc, 2), + "dentry_open(old): %p", old_file); + if (!old_file) + goto out_rel_both; + + dget(new_dentry); + mntget(new_mnt); + /* this one cleans up the dentry in case of failure */ + new_file = dentry_open(new_dentry, new_mnt, O_WRONLY); + vxdprintk(VXD_CBIT(misc, 2), + "dentry_open(new): %p", new_file); + if (!new_file) + goto out_fput_old; + + vxdprintk(VXD_CBIT(misc, 3), + "file@b %p,%p", new_file, new_file->f_list.next); + size = i_size_read(old_file->f_dentry->d_inode); + ret = vfs_sendfile(new_file, old_file, NULL, size, 0); + vxdprintk(VXD_CBIT(misc, 2), "vfs_sendfile: %d", ret); + vxdprintk(VXD_CBIT(misc, 3), + "file@a %p,%p", new_file, new_file->f_list.next); + + if (ret < 0) + goto out_fput_both; + + ret = vfs_rename(dir_nd.dentry->d_inode, new_dentry, + old_nd.dentry->d_parent->d_inode, old_dentry); + vxdprintk(VXD_CBIT(misc, 2), "vfs_rename: %d", ret); + if (!ret) + err = 0; + +out_fput_both: + vxdprintk(VXD_CBIT(misc, 3), + "fput(new_file=%p[#%d])", new_file, + atomic_read(&new_file->f_count)); + fput(new_file); + +out_fput_old: + vxdprintk(VXD_CBIT(misc, 3), + "fput(old_file=%p[#%d])", old_file, + atomic_read(&old_file->f_count)); + fput(old_file); + +out_rel_both: + up(&dir_nd.dentry->d_inode->i_sem); + dput(new_dentry); + + path_release(&dir_nd); +out_rel_old: + path_release(&old_nd); + kfree(path); + return err; +} + +#endif + /* get the link contents into pagecache */ static char *page_getlink(struct dentry * dentry, struct page **ppage) { diff -NurpP linux-2.6.14.7/fs/namespace.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/namespace.c --- linux-2.6.14.7/fs/namespace.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/namespace.c 2006-02-27 18:15:50.000000000 +0100 @@ -22,6 +22,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -161,6 +165,7 @@ clone_mnt(struct vfsmount *old, struct d mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; mnt->mnt_namespace = current->namespace; + mnt->mnt_xid = old->mnt_xid; /* stick the duplicate mount on the same expiry list * as the original if that was on one */ @@ -215,43 +220,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" }, - { MS_NOATIME, ",noatime" }, - { MS_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 } }; - static struct proc_fs_info mnt_info[] = { - { MNT_NOSUID, ",nosuid" }, - { MNT_NODEV, ",nodev" }, - { MNT_NOEXEC, ",noexec" }, - { 0, 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, ' '); + 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, ' '); + } 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); - } - for (fs_infop = mnt_info; fs_infop->flag; fs_infop++) { - if (mnt->mnt_flags & fs_infop->flag) - seq_puts(m, fs_infop->str); + 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"); @@ -337,19 +384,12 @@ int may_umount(struct vfsmount *mnt) EXPORT_SYMBOL(may_umount); -static void umount_tree(struct vfsmount *mnt) +static inline void __umount_list(struct list_head *kill) { - struct vfsmount *p; - LIST_HEAD(kill); - - for (p = mnt; p; p = next_mnt(p, mnt)) { - list_del(&p->mnt_list); - list_add(&p->mnt_list, &kill); - p->mnt_namespace = NULL; - } + struct vfsmount *mnt; - while (!list_empty(&kill)) { - mnt = list_entry(kill.next, struct vfsmount, mnt_list); + while (!list_empty(kill)) { + mnt = list_entry(kill->next, struct vfsmount, mnt_list); list_del_init(&mnt->mnt_list); list_del_init(&mnt->mnt_expire); if (mnt->mnt_parent == mnt) { @@ -365,6 +405,34 @@ static void umount_tree(struct vfsmount } } +void umount_tree(struct vfsmount *mnt) +{ + struct vfsmount *p; + LIST_HEAD(kill); + + for (p = mnt; p; p = next_mnt(p, mnt)) { + list_del(&p->mnt_list); + list_add(&p->mnt_list, &kill); + p->mnt_namespace = NULL; + } + __umount_list(&kill); +} + +void umount_unused(struct vfsmount *mnt, struct fs_struct *fs) +{ + struct vfsmount *p; + LIST_HEAD(kill); + + for (p = mnt; p; p = next_mnt(p, mnt)) { + if (p == fs->rootmnt || p == fs->pwdmnt) + continue; + list_del(&p->mnt_list); + list_add(&p->mnt_list, &kill); + p->mnt_namespace = NULL; + } + __umount_list(&kill); +} + static int do_umount(struct vfsmount *mnt, int flags) { struct super_block * sb = mnt->mnt_sb; @@ -424,9 +492,11 @@ static int do_umount(struct vfsmount *mn down_write(&sb->s_umount); if (!(sb->s_flags & MS_RDONLY)) { lock_kernel(); - DQUOT_OFF(sb); + DQUOT_OFF(sb->s_dqh); 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; @@ -439,7 +509,7 @@ static int do_umount(struct vfsmount *mn /* last instance - try to be smart */ spin_unlock(&vfsmount_lock); lock_kernel(); - DQUOT_OFF(sb); + DQUOT_OFF(sb->s_dqh); acct_auto_close(sb); unlock_kernel(); security_sb_umount_close(mnt); @@ -455,6 +525,9 @@ static int do_umount(struct vfsmount *mn if (retval) security_sb_umount_busy(mnt); up_write(¤t->namespace->sem); + + gr_log_unmount(mnt->mnt_devname, retval); + return retval; } @@ -481,7 +554,7 @@ asmlinkage long sys_umount(char __user * goto dput_and_out; retval = -EPERM; - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) goto dput_and_out; retval = do_umount(nd.mnt, flags); @@ -508,6 +581,8 @@ static int mount_is_safe(struct nameidat { if (capable(CAP_SYS_ADMIN)) return 0; + if (vx_ccaps(VXC_SECURE_MOUNT)) + return 0; return -EPERM; #ifdef notyet if (S_ISLNK(nd->dentry->d_inode->i_mode)) @@ -617,11 +692,13 @@ out_unlock: /* * 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) @@ -646,6 +723,10 @@ static int do_loopback(struct nameidata list_del_init(&mnt->mnt_expire); spin_unlock(&vfsmount_lock); + if (flags & MS_XID) { + mnt->mnt_xid = xid; + mnt->mnt_flags |= MNT_XID; + } err = graft_tree(mnt, nd); if (err) { spin_lock(&vfsmount_lock); @@ -653,6 +734,7 @@ static int do_loopback(struct nameidata spin_unlock(&vfsmount_lock); } else mntput(mnt); + mnt->mnt_flags = mnt_flags; } up_write(¤t->namespace->sem); @@ -667,12 +749,12 @@ static int do_loopback(struct nameidata */ 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 (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_REMOUNT)) return -EPERM; if (!check_mnt(nd->mnt)) @@ -681,10 +763,15 @@ static int do_remount(struct nameidata * if (nd->dentry != nd->mnt->mnt_root) return -EINVAL; + if (vx_ccaps(VXC_SECURE_REMOUNT)) + mnt_flags |= MNT_NODEV; down_write(&sb->s_umount); err = do_remount_sb(sb, flags, data, 0); - if (!err) + if (!err) { nd->mnt->mnt_flags=mnt_flags; + if (flags & MS_XID) + nd->mnt->mnt_xid = xid; + } up_write(&sb->s_umount); if (!err) security_sb_post_remount(nd->mnt, flags, data); @@ -696,7 +783,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 (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) return -EPERM; if (!old_name || !*old_name) return -EINVAL; @@ -768,7 +855,7 @@ static int do_new_mount(struct nameidata return -EINVAL; /* we need capabilities... */ - if (!capable(CAP_SYS_ADMIN)) + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) return -EPERM; mnt = do_kern_mount(type, flags, name, data); @@ -857,7 +944,7 @@ static void expire_mount(struct vfsmount if (atomic_read(&mnt->mnt_sb->s_active) == 1) { /* last instance - try to be smart */ lock_kernel(); - DQUOT_OFF(mnt->mnt_sb); + DQUOT_OFF(mnt->mnt_sb->s_dqh); acct_auto_close(mnt->mnt_sb); unlock_kernel(); } @@ -1017,6 +1104,7 @@ long do_mount(char * dev_name, char * di struct nameidata nd; int retval = 0; int mnt_flags = 0; + xid_t xid = 0; /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) @@ -1032,15 +1120,34 @@ long do_mount(char * dev_name, char * di if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; +#ifdef CONFIG_XID_PROPAGATE + 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; + } +#endif + /* 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) mnt_flags |= MNT_NODEV; if (flags & MS_NOEXEC) mnt_flags |= MNT_NOEXEC; + if (flags & MS_NOATIME) + mnt_flags |= MNT_NOATIME; + if (flags & MS_NODIRATIME) + mnt_flags |= MNT_NODIRATIME; flags &= ~(MS_NOSUID|MS_NOEXEC|MS_NODEV|MS_ACTIVE); + if (vx_ccaps(VXC_SECURE_MOUNT)) + mnt_flags |= MNT_NODEV; + /* ... and get the mountpoint */ retval = path_lookup(dir_name, LOOKUP_FOLLOW, &nd); if (retval) @@ -1050,11 +1157,16 @@ long do_mount(char * dev_name, char * di 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_MOVE) retval = do_move_mount(&nd, dev_name); else @@ -1062,6 +1174,9 @@ long do_mount(char * dev_name, char * di dev_name, data_page); dput_out: path_release(&nd); + + gr_log_mount(dev_name, dir_name, retval); + return retval; } @@ -1081,7 +1196,7 @@ int copy_namespace(int flags, struct tas if (!(flags & CLONE_NEWNS)) return 0; - if (!capable(CAP_SYS_ADMIN)) { + if (!capable(CAP_SYS_ADMIN) && !vx_ccaps(VXC_SECURE_MOUNT)) { put_namespace(namespace); return -EPERM; } @@ -1291,6 +1406,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, &new_nd); diff -NurpP linux-2.6.14.7/fs/nfs/dir.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfs/dir.c --- linux-2.6.14.7/fs/nfs/dir.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfs/dir.c 2006-02-27 17:33:28.000000000 +0100 @@ -31,6 +31,7 @@ #include #include #include +#include #include "nfs4_fs.h" #include "delegation.h" @@ -875,6 +876,7 @@ static struct dentry *nfs_lookup(struct inode = nfs_fhget(dentry->d_sb, &fhandle, &fattr); if (!inode) goto out_unlock; + vx_propagate_xid(nd, inode); no_entry: res = d_add_unique(dentry, inode); if (res != NULL) @@ -908,7 +910,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 linux-2.6.14.7/fs/nfs/inode.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfs/inode.c --- linux-2.6.14.7/fs/nfs/inode.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfs/inode.c 2006-02-27 17:33:28.000000000 +0100 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -340,12 +341,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); @@ -398,6 +403,7 @@ nfs_create_client(struct nfs_server *ser clnt->cl_intr = 1; clnt->cl_softrtry = 1; + clnt->cl_tagxid = 1; clnt->cl_chatty = 1; return clnt; @@ -581,6 +587,7 @@ static int nfs_show_options(struct seq_f { NFS_MOUNT_NOAC, ",noac", "" }, { NFS_MOUNT_NONLM, ",nolock", ",lock" }, { NFS_MOUNT_NOACL, ",noacl", "" }, + { NFS_MOUNT_TAGXID, ",tagxid", "" }, { 0, NULL, NULL } }; struct proc_nfs_info *nfs_infop; @@ -761,8 +768,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 @@ -849,6 +858,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); @@ -1223,6 +1234,9 @@ int nfs_refresh_inode(struct inode *inod 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; spin_lock(&inode->i_lock); @@ -1275,10 +1289,15 @@ int nfs_refresh_inode(struct inode *inod nfsi->cache_validity |= 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? */ @@ -1311,6 +1330,9 @@ static int nfs_update_inode(struct inode loff_t cur_isize, new_isize; unsigned int invalid = 0; int data_unstable; + 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, @@ -1393,15 +1415,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 linux-2.6.14.7/fs/nfs/nfs3xdr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfs/nfs3xdr.c --- linux-2.6.14.7/fs/nfs/nfs3xdr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfs/nfs3xdr.c 2006-02-27 17:33:28.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #define NFSDBG_FACILITY NFSDBG_XDR @@ -179,7 +180,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; @@ -187,15 +188,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; } @@ -280,7 +283,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); @@ -371,7 +375,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; @@ -385,7 +390,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; } @@ -398,7 +404,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; @@ -413,7 +420,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 linux-2.6.14.7/fs/nfs/nfsroot.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfs/nfsroot.c --- linux-2.6.14.7/fs/nfs/nfsroot.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfs/nfsroot.c 2006-02-27 17:33:28.000000000 +0100 @@ -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 : return 0; } @@ -310,7 +317,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 linux-2.6.14.7/fs/nfsd/auth.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/auth.c --- linux-2.6.14.7/fs/nfsd/auth.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/auth.c 2006-02-27 17:33:28.000000000 +0100 @@ -9,6 +9,7 @@ #include #include #include +#include #define CAP_NFSD_MASK (CAP_FS_MASK|CAP_TO_MASK(CAP_SYS_RESOURCE)) @@ -42,18 +43,20 @@ int nfsd_setuser(struct svc_rqst *rqstp, } 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; + 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); - 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 linux-2.6.14.7/fs/nfsd/nfs3xdr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/nfs3xdr.c --- linux-2.6.14.7/fs/nfsd/nfs3xdr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/nfs3xdr.c 2006-02-27 17:33:28.000000000 +0100 @@ -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; @@ -166,8 +172,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 linux-2.6.14.7/fs/nfsd/nfs4recover.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/nfs4recover.c --- linux-2.6.14.7/fs/nfsd/nfs4recover.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/nfs4recover.c 2006-02-27 17:33:28.000000000 +0100 @@ -155,7 +155,8 @@ 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, &rec_dir); out_put: dput(dentry); out_unlock: @@ -260,7 +261,7 @@ nfsd4_remove_clid_file(struct dentry *di return -EINVAL; } down(&dir->d_inode->i_sem); - status = vfs_unlink(dir->d_inode, dentry); + status = vfs_unlink(dir->d_inode, dentry, NULL); up(&dir->d_inode->i_sem); return status; } @@ -275,7 +276,7 @@ nfsd4_clear_clid_dir(struct dentry *dir, * a kernel from the future.... */ nfsd4_list_rec_dir(dentry, nfsd4_remove_clid_file); down(&dir->d_inode->i_sem); - status = vfs_rmdir(dir->d_inode, dentry); + status = vfs_rmdir(dir->d_inode, dentry, NULL); up(&dir->d_inode->i_sem); return status; } diff -NurpP linux-2.6.14.7/fs/nfsd/nfs4xdr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/nfs4xdr.c --- linux-2.6.14.7/fs/nfsd/nfs4xdr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/nfs4xdr.c 2006-02-27 17:33:28.000000000 +0100 @@ -57,6 +57,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -1562,14 +1563,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 linux-2.6.14.7/fs/nfsd/nfsxdr.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/nfsxdr.c --- linux-2.6.14.7/fs/nfsd/nfsxdr.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/nfsxdr.c 2006-02-27 17:33:28.000000000 +0100 @@ -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; @@ -166,8 +172,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 linux-2.6.14.7/fs/nfsd/vfs.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/vfs.c --- linux-2.6.14.7/fs/nfsd/vfs.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/nfsd/vfs.c 2006-02-27 17:33:28.000000000 +0100 @@ -1154,13 +1154,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); @@ -1436,11 +1436,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)) @@ -1498,7 +1500,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)) { nfsd_sync_dir(ddir); @@ -1659,9 +1661,9 @@ nfsd_unlink(struct svc_rqst *rqstp, stru err = nfserr_perm; } 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); @@ -1773,7 +1775,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 linux-2.6.14.7/fs/open.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/open.c --- linux-2.6.14.7/fs/open.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/open.c 2006-02-27 18:09:20.000000000 +0100 @@ -25,6 +25,10 @@ #include #include #include +#include +#include +#include +#include #include @@ -43,6 +47,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; } @@ -194,7 +200,7 @@ out: return error; } -int do_truncate(struct dentry *dentry, loff_t length) +int do_truncate(struct dentry *dentry, loff_t length, struct vfsmount *mnt) { int err; struct iattr newattrs; @@ -203,6 +209,9 @@ int do_truncate(struct dentry *dentry, l if (length < 0) return -EINVAL; + if (!gr_acl_handle_truncate(dentry, mnt)) + return -EACCES; + newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | ATTR_CTIME; @@ -241,7 +250,7 @@ static inline long do_sys_truncate(const 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; @@ -262,7 +271,7 @@ static inline long do_sys_truncate(const error = locks_verify_truncate(inode, NULL, length); if (!error) { DQUOT_INIT(inode); - error = do_truncate(nd.dentry, length); + error = do_truncate(nd.dentry, length, nd.mnt); } put_write_access(inode); @@ -314,7 +323,7 @@ static inline long do_sys_ftruncate(unsi error = locks_verify_truncate(inode, file, length); if (!error) - error = do_truncate(dentry, length); + error = do_truncate(dentry, length, file->f_vfsmnt); out_putf: fput(file); out: @@ -365,7 +374,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() */ @@ -393,6 +402,11 @@ asmlinkage long sys_utime(char __user * (error = permission(inode,MAY_WRITE,&nd)) != 0) goto dput_and_out; } + if (!gr_acl_handle_utime(nd.dentry, nd.mnt)) { + error = -EACCES; + goto dput_and_out; + } + down(&inode->i_sem); error = notify_change(nd.dentry, &newattrs); up(&inode->i_sem); @@ -422,7 +436,7 @@ long do_utimes(char __user * filename, s 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() */ @@ -446,6 +460,12 @@ long do_utimes(char __user * filename, s (error = permission(inode,MAY_WRITE,&nd)) != 0) goto dput_and_out; } + + if (!gr_acl_handle_utime(nd.dentry, nd.mnt)) { + error = -EACCES; + goto dput_and_out; + } + down(&inode->i_sem); error = notify_change(nd.dentry, &newattrs); up(&inode->i_sem); @@ -504,9 +524,14 @@ asmlinkage long sys_access(const char __ if (!res) { res = permission(nd.dentry->d_inode, mode, &nd); /* 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); } @@ -530,6 +555,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: @@ -560,6 +587,13 @@ asmlinkage long sys_fchdir(unsigned int goto out_putf; error = permission(inode, MAY_EXEC, NULL); + + 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: @@ -585,8 +619,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); @@ -610,14 +652,27 @@ asmlinkage long sys_fchmod(unsigned int inode = dentry->d_inode; 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; + } + down(&inode->i_sem); if (mode == (mode_t) -1) mode = inode->i_mode; + + if (gr_handle_chroot_chmod(dentry, file->f_vfsmnt, mode)) { + err = -EPERM; + up(&inode->i_sem); + 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); @@ -642,16 +697,28 @@ asmlinkage long sys_chmod(const char __u 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; + } + down(&inode->i_sem); if (mode == (mode_t) -1) mode = inode->i_mode; + + if (gr_handle_chroot_chmod(nd.dentry, nd.mnt, mode)) { + error = -EACCES; + up(&inode->i_sem); + 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); @@ -663,7 +730,7 @@ out: return error; } -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; @@ -675,19 +742,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; @@ -705,7 +778,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; @@ -718,7 +791,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; @@ -732,7 +805,8 @@ asmlinkage long sys_fchown(unsigned int file = fget(fd); if (file) { - error = chown_common(file->f_dentry, user, group); + error = chown_common(file->f_dentry, user, + group, file->f_vfsmnt); fput(file); } return error; @@ -820,7 +894,7 @@ struct file *filp_open(const char * file if ((namei_flags+1) & O_ACCMODE) namei_flags++; if (namei_flags & O_TRUNC) - namei_flags |= 2; + namei_flags |= FMODE_WRITE; error = -ENFILE; f = get_empty_filp(); @@ -872,6 +946,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; @@ -892,6 +967,7 @@ repeat: FD_SET(fd, fdt->open_fds); FD_CLR(fd, fdt->close_on_exec); fdt->next_fd = fd + 1; + vx_openfd_inc(fd); #if 1 /* Sanity check */ if (fdt->fd[fd] != NULL) { @@ -914,6 +990,7 @@ static inline void __put_unused_fd(struc __FD_CLR(fd, fdt->open_fds); if (fd < fdt->next_fd) fdt->next_fd = fd; + vx_openfd_dec(fd); } void fastcall put_unused_fd(unsigned int fd) diff -NurpP linux-2.6.14.7/fs/proc/array.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/proc/array.c --- linux-2.6.14.7/fs/proc/array.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/proc/array.c 2006-02-27 17:33:28.000000000 +0100 @@ -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_ARCH_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; @@ -388,7 +470,11 @@ static int do_task_stat(struct task_stru } it_real_value = task->signal->it_real_value; } - 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) @@ -400,6 +486,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); @@ -412,10 +511,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 %d %lu %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d %ld %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %lu %lu\n", - task->pid, + pid, tcomm, state, ppid, @@ -440,9 +550,15 @@ static int do_task_stat(struct task_stru vsize, mm ? get_mm_counter(mm, rss) : 0, /* you might want to shift this left 3 */ rsslim, +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + PAX_RAND_FLAGS(mm) ? 1 : (mm ? mm->start_code : 0), + PAX_RAND_FLAGS(mm) ? 1 : (mm ? mm->end_code : 0), + PAX_RAND_FLAGS(mm) ? 0 : (mm ? mm->start_stack : 0), +#else mm ? mm->start_code : 0, mm ? mm->end_code : 0, mm ? mm->start_stack : 0, +#endif esp, eip, /* The signal information here is obsolete. @@ -488,3 +604,14 @@ int proc_pid_statm(struct task_struct *t return sprintf(buffer,"%d %d %d %d %d %d %d\n", size, resident, shared, text, lib, data, 0); } + +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR +int proc_pid_ipaddr(struct task_struct *task, char * buffer) +{ + int len; + + len = sprintf(buffer, "%u.%u.%u.%u\n", NIPQUAD(task->signal->curr_ip)); + return len; +} +#endif + diff -NurpP linux-2.6.14.7/fs/proc/base.c linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/proc/base.c --- linux-2.6.14.7/fs/proc/base.c 2006-01-31 07:52:07.000000000 +0100 +++ linux-2.6.14.7-vs2.1.0-grsec-2.1.9/fs/proc/base.c 2006-02-27 18:08:52.000000000 +0100 @@ -70,6 +70,8 @@ #include #include #include +#include +#include #include "internal.h" /* @@ -119,9 +121,14 @@ enum pid_directory_inos { PROC_TGID_ATTR_EXEC, PROC_TGID_ATTR_FSCREATE, #endif + PROC_TGID_VX_INFO, + PROC_TGID_IP_INFO, #ifdef CONFIG_AUDITSYSCALL PROC_TGID_LOGINUID, #endif +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR + PROC_TGID_IPADDR, +#endif PROC_TGID_OOM_SCORE, PROC_TGID_OOM_ADJUST, PROC_TID_INO, @@ -159,6 +166,8 @@ enum pid_directory_inos { PROC_TID_ATTR_EXEC, PROC_TID_ATTR_FSCREATE, #endif + PROC_TID_VX_INFO, + PROC_TID_IP_INFO, #ifdef CONFIG_AUDITSYSCALL PROC_TID_LOGINUID, #endif @@ -199,6 +208,9 @@ static struct pid_entry tgid_base_stuff[ E(PROC_TGID_ROOT, "root", S_IFLNK|S_IRWXUGO), E(PROC_TGID_EXE, "exe", S_IFLNK|S_IRWXUGO), E(PROC_TGID_MOUNTS, "mounts", S_IFREG|S_IRUGO), +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR + E(PROC_TGID_IPADDR, "ipaddr", S_IFREG|S_IRUSR), +#endif #ifdef CONFIG_MMU E(PROC_TGID_SMAPS, "smaps", S_IFREG|S_IRUGO), #endif @@ -214,6 +226,8 @@ static struct pid_entry tgid_base_stuff[ #ifdef CONFIG_CPUSETS E(PROC_TGID_CPUSET, "cpuset", S_IFREG|S_IRUGO), #endif + E(PROC_TGID_VX_INFO, "vinfo", S_IFREG|S_IRUGO), + E(PROC_TGID_IP_INFO, "ninfo", S_IFREG|S_IRUGO), E(PROC_TGID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO), E(PROC_TGID_OOM_ADJUST,"oom_adj", S_IFREG|S_IRUGO|S_IWUSR), #ifdef CONFIG_AUDITSYSCALL @@ -256,6 +270,8 @@ static struct pid_entry tid_base_stuff[] #ifdef CONFIG_CPUSETS E(PROC_TID_CPUSET, "cpuset", S_IFREG|S_IRUGO), #endif + E(PROC_TID_VX_INFO, "vinfo", S_IFREG|S_IRUGO), + E(PROC_TID_IP_INFO, "ninfo", S_IFREG|S_IRUGO), E(PROC_TID_OOM_SCORE, "oom_score",S_IFREG|S_IRUGO), E(PROC_TID_OOM_ADJUST, "oom_adj", S_IFREG|S_IRUGO|S_IWUSR), #ifdef CONFIG_AUDITSYSCALL @@ -401,7 +417,7 @@ static int proc_task_root_link(struct in (task->parent == current && \ (task->ptrace & PT_PTRACED) && \ (task->state == TASK_STOPPED || task->state == TASK_TRACED) && \ - security_ptrace(current,task) == 0)) + security_ptrace(current,task) == 0 && !gr_handle_proc_ptrace(task))) static int proc_pid_environ(struct task_struct *task, char * buffer) { @@ -579,9 +595,25 @@ static int proc_check_root(struct inode static int proc_permission(struct inode *inode, int mask, struct nameidata *nd) { + int ret = -EACCES; + struct task_struct *task; + if (generic_permission(inode, mask, NULL) != 0) - return -EACCES; - return proc_check_root(inode); + goto out; + + ret = proc_check_root(inode); + if (ret) + goto out; + + task = proc_task(inode); + + if (!task) + goto out; + + ret = gr_acl_handle_procpidmem(task); + +out: + return ret; } static int proc_task_permission(struct inode *inode, int mask, struct nameidata *nd) @@ -1188,7 +1220,7 @@ static int proc_pident_readdir(struct fi struct inode *inode = dentry->d_inode; struct pid_entry *p; ino_t ino; - int ret; + int ret, hide; ret = -ENOENT; if (!pid_alive(proc_task(inode))) @@ -1219,11 +1251,20 @@ static int proc_pident_readdir(struct fi goto out; } p = ents + i; + hide = vx_flags(VXF_INFO_HIDE, 0); while (p->name) { + if (hide) { + switch (p->type) { + case PROC_TGID_VX_INFO: + case PROC_TGID_IP_INFO: + goto skip; + } + } if (filldir(dirent, p->name, p->len, filp->f_pos, fake_ino(pid, p->type), p->mode >> 12) < 0) goto out; filp->f_pos++; + skip: p++; } } @@ -1297,6 +1338,10 @@ static struct inode *proc_pid_make_inode inode->i_uid = task->euid; inode->i_gid = task->egid; } +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#endif + inode->i_xid = vx_task_xid(task); security_task_to_inode(task, inode); out: @@ -1322,10 +1367,17 @@ static int pid_revalidate(struct dentry { struct inode *inode = dentry->d_inode; struct task_struct *task = proc_task(inode); + + if (!vx_check(vx_task_xid(task), VX_IDENT)) + goto out_drop; + /* discard wrong fakeinit */ + if (pid_alive(task)) { if (proc_type(inode) == PROC_TGID_INO || proc_type(inode) == PROC_TID_INO || task_dumpable(task)) { inode->i_uid = task->euid; +#ifndef CONFIG_GRKERNSEC_PROC_USERGROUP inode->i_gid = task->egid; +#endif } else { inode->i_uid = 0; inode->i_gid = 0; @@ -1333,6 +1385,7 @@ static int pid_revalidate(struct dentry security_task_to_inode(task, inode); return 1; } +out_drop: d_drop(dentry); return 0; } @@ -1567,6 +1620,9 @@ static struct file_operations proc_tgid_ static struct inode_operations proc_tgid_attr_inode_operations; #endif +extern int proc_pid_vx_info(struct task_struct *, char *); +extern int proc_pid_nx_info(struct task_struct *, char *); + static int get_tid_list(int index, unsigned int *tids, struct inode *dir); /* SMP-safe */ @@ -1648,6 +1704,12 @@ static struct dentry *proc_pident_lookup inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_pid_status; break; +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR + case PROC_TGID_IPADDR: + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pid_ipaddr; + break; +#endif case PROC_TID_STAT: inode->i_fop = &proc_info_file_operations; ei->op.proc_read = proc_tid_stat; @@ -1754,15 +1816,33 @@ static struct dentry *proc_pident_lookup inode->i_fop = &proc_loginuid_operations; break; #endif + case PROC_TID_VX_INFO: + case PROC_TGID_VX_INFO: + if (task_vx_flags(task, VXF_INFO_HIDE, 0)) + goto out_noent; + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pid_vx_info; + break; + case PROC_TID_IP_INFO: + case PROC_TGID_IP_INFO: + if (task_vx_flags(task, VXF_INFO_HIDE, 0)) + goto out_noent; + inode->i_fop = &proc_info_file_operations; + ei->op.proc_read = proc_pid_nx_info; + break; default: printk("procfs: impossible type (%d)",p->type); - iput(inode); - return ERR_PTR(-EINVAL); + error = -EINVAL; + goto out_put; } dentry->d_op = &pid_dentry_operations; d_add(dentry, inode); return NULL; +out_noent: + error=-ENOENT; +out_put: + iput(inode); out: return ERR_PTR(error); } @@ -1846,14 +1926,14 @@ static int proc_self_readlink(struct den int buflen) { char tmp[30]; - sprintf(tmp, "%d", current->tgid); + sprintf(tmp, "%d", vx_map_tgid(current->tgid)); return vfs_readlink(dentry,buffer,buflen,tmp); } static void *proc_self_follow_link(struct dentry *dentry, struct nameidata *nd) { char tmp[30]; - sprintf(tmp, "%d", current->tgid); + sprintf(tmp, "%d", vx_map_tgid(current->tgid)); return ERR_PTR(vfs_follow_link(nd,tmp)); } @@ -1916,6 +1996,20 @@ void proc_pid_flush(struct dentry *proc_ } } +#define VXF_FAKE_INIT (VXF_INFO_INIT|VXF_STATE_INIT) + +static inline int proc_pid_visible(struct task_struct *task, int pid) +{ + if ((pid == 1) && + !vx_flags(VXF_FAKE_INIT, VXF_FAKE_INIT)) + goto visible; + if (vx_check(vx_task_xid(task), VX_WATCH|VX_IDENT)) + goto visible; + return 0; +visible: + return 1; +} + /* SMP-safe */ struct dentry *proc_pid_lookup(struct inode *dir, struct dentry * dentry, struct nameidata *nd) { @@ -1952,14 +2046,38 @@ struct dentry *proc_pid_lookup(struct in if (!task) goto out; - inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); - + if (gr_check_hidden_task(task)) { + put_task_struct(task); + goto out; + } - if (!inode) { +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + if (current->uid && (task->uid != current->uid) +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + && !in_group_p(CONFIG_GRKERNSEC_PROC_GID) +#endif + ) { put_task_struct(task); goto out; } +#endif + + /* check for context visibility */ + if (!proc_pid_visible(task, tgid)) + goto out_drop_task; + + inode = proc_pid_make_inode(dir->i_sb, task, PROC_TGID_INO); + if (!inode) + goto out_drop_task; + +#ifdef CONFIG_GRKERNSEC_PROC_USER + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR; +#elif CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR|S_IRGRP|S_IXGRP; + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#else inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; +#endif inode->i_op = &proc_tgid_base_inode_operations; inode->i_fop = &proc_tgid_base_operations; inode->i_flags|=S_IMMUTABLE; @@ -1987,6 +2105,8 @@ struct dentry *proc_pid_lookup(struct in goto out; } return NULL; +out_drop_task: + put_task_struct(task); out: return ERR_PTR(-ENOENT); } @@ -2002,6 +2122,8 @@ static struct dentry *proc_task_lookup(s tid = name_to_int(dentry); if (tid == ~0U) goto out; + if (vx_current_initpid(tid)) + goto out; read_lock(&tasklist_lock); task = find_task_by_pid(tid); @@ -2013,11 +2135,14 @@ static struct dentry *proc_task_lookup(s if (leader->tgid != task->tgid) goto out_drop_task; - inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO); - + /* check for context visibility */ + if (!proc_pid_visible(task, tid)) + goto out_drop_task; + inode = proc_pid_make_inode(dir->i_sb, task, PROC_TID_INO); if (!inode) goto out_drop_task; + inode->i_mode = S_IFDIR|S_IRUGO|S_IXUGO; inode->i_op = &proc_tid_base_inode_operations; inode->i_fop = &proc_tid_base_operations; @@ -2051,13 +2176,16 @@ out: static int get_tgid_list(int index, unsigned long version, unsigned int *tgids) { struct task_struct *p; +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + struct task_struct *tmp = current; +#endif int nr_tgids = 0; index--; read_lock(&tasklist_lock); p = NULL; if (version) { - p = find_task_by_pid(version); + p = find_task_by_real_pid(version); if (p && !thread_group_leader(p)) p = NULL; } @@ -2069,11 +2197,27 @@ static int get_tgid_list(int index, unsi for ( ; p != &init_task; p = next_task(p)) { int tgid = p->pid; + if (!pid_alive(p)) continue; + if (gr_pid_is_chrooted(p)) + continue; + if (gr_check_hidden_task(p)) + continue; +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + if (tmp->uid && (p->uid != tmp->uid) +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + && !in_group_p(CONFIG_GRKERNSEC_PROC_GID) +#endif + ) + continue; +#endif + /* check for context visibility */ + if (!proc_pid_visible(p, tgid)) + continue; if (--index >= 0) continue; - tgids[nr_tgids] = tgid; + tgids[nr_tgids] = vx_map_tgid(tgid); nr_tgids++; if (nr_tgids >= PROC_MAXPIDS) break; @@ -2103,10 +2247,13 @@ static int get_tid_list(int index, unsig if (pid_alive(task)) do { int tid = task->pid; + /* check for context visibility */ + if (!proc_pid_visible(task, tid)) + continue; if (--index >= 0) continue; if (tids != NULL) - tids[nr_tids] = tid; + tids[nr_tids] = vx_map_pid(tid); nr_tids++; if (nr_tids >= PROC_MAXPIDS) break; @@ -2182,11 +2329,14 @@ static int proc_task_readdir(struct file unsigned int nr_tids, i; struct dentry *dentry = filp->f_dentry; struct inode *inode = dentry->d_inode; + struct task_struct *task = proc_task(inode); int retval = -ENOENT; ino_t ino; unsigned long pos = filp->f_pos; /* avoiding "long long" filp->f_pos */ - if (!pid_alive(proc_task(inode))) + if (!vx_check(vx_task_xid(task), VX_WATCH|V