Patch-2.6.27.15-vs2.3.0.36.4-grsec2.1.12-20090210.diff
diff -NurpP --minimal linux-2.6.27.15/arch/alpha/include/asm/elf.h linux-2.6.27.15-g-v/arch/alpha/include/asm/elf.h --- linux-2.6.27.15/arch/alpha/include/asm/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/include/asm/elf.h 2009-02-10 20:32:09.000000000 +0100 @@ -91,6 +91,13 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_N #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x1000000) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (current->personality & ADDR_LIMIT_32BIT ? 0x10000 : 0x120000000UL) + +#define PAX_DELTA_MMAP_LEN (current->personality & ADDR_LIMIT_32BIT ? 14 : 28) +#define PAX_DELTA_STACK_LEN (current->personality & ADDR_LIMIT_32BIT ? 14 : 19) +#endif + /* $0 is set by ld.so to a pointer to a function which might be registered using atexit. This provides a mean for the dynamic linker to call DT_FINI functions for shared libraries that have diff -NurpP --minimal linux-2.6.27.15/arch/alpha/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/alpha/include/asm/kmap_types.h --- linux-2.6.27.15/arch/alpha/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/include/asm/kmap_types.h 2009-02-10 20:32:09.000000000 +0100 @@ -24,7 +24,8 @@ D(9) KM_IRQ0, D(10) KM_IRQ1, D(11) KM_SOFTIRQ0, D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR +D(13) KM_CLEARPAGE, +D(14) KM_TYPE_NR }; #undef D diff -NurpP --minimal linux-2.6.27.15/arch/alpha/include/asm/pgtable.h linux-2.6.27.15-g-v/arch/alpha/include/asm/pgtable.h --- linux-2.6.27.15/arch/alpha/include/asm/pgtable.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/include/asm/pgtable.h 2009-02-10 20:32:09.000000000 +0100 @@ -101,6 +101,17 @@ struct vm_area_struct; #define PAGE_SHARED __pgprot(_PAGE_VALID | __ACCESS_BITS) #define PAGE_COPY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) #define PAGE_READONLY __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW) + +#ifdef CONFIG_PAX_PAGEEXEC +# define PAGE_SHARED_NOEXEC __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOE) +# define PAGE_COPY_NOEXEC __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_FOE) +# define PAGE_READONLY_NOEXEC __pgprot(_PAGE_VALID | __ACCESS_BITS | _PAGE_FOW | _PAGE_FOE) +#else +# define PAGE_SHARED_NOEXEC PAGE_SHARED +# define PAGE_COPY_NOEXEC PAGE_COPY +# define PAGE_READONLY_NOEXEC PAGE_READONLY +#endif + #define PAGE_KERNEL __pgprot(_PAGE_VALID | _PAGE_ASM | _PAGE_KRE | _PAGE_KWE) #define _PAGE_NORMAL(x) __pgprot(_PAGE_VALID | __ACCESS_BITS | (x)) diff -NurpP --minimal linux-2.6.27.15/arch/alpha/Kconfig linux-2.6.27.15-g-v/arch/alpha/Kconfig --- linux-2.6.27.15/arch/alpha/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/Kconfig 2009-02-10 20:32:09.000000000 +0100 @@ -667,6 +667,8 @@ config DUMMY_CONSOLE depends on VGA_HOSE default y +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/alpha/kernel/entry.S linux-2.6.27.15-g-v/arch/alpha/kernel/entry.S --- linux-2.6.27.15/arch/alpha/kernel/entry.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/kernel/entry.S 2009-02-10 20:32:09.000000000 +0100 @@ -872,24 +872,15 @@ sys_getxgid: .globl sys_getxpid .ent sys_getxpid sys_getxpid: + lda $sp, -16($sp) + stq $26, 0($sp) .prologue 0 - ldq $2, TI_TASK($8) - /* See linux/kernel/timer.c sys_getppid for discussion - about this loop. */ - ldq $3, TASK_GROUP_LEADER($2) - ldq $4, TASK_REAL_PARENT($3) - ldl $0, TASK_TGID($2) -1: ldl $1, TASK_TGID($4) -#ifdef CONFIG_SMP - mov $4, $5 - mb - ldq $3, TASK_GROUP_LEADER($2) - ldq $4, TASK_REAL_PARENT($3) - cmpeq $4, $5, $5 - beq $5, 1b -#endif - stq $1, 80($sp) + lda $16, 96($sp) + jsr $26, do_getxpid + ldq $26, 0($sp) + + lda $sp, 16($sp) ret .end sys_getxpid diff -NurpP --minimal linux-2.6.27.15/arch/alpha/kernel/module.c linux-2.6.27.15-g-v/arch/alpha/kernel/module.c --- linux-2.6.27.15/arch/alpha/kernel/module.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/kernel/module.c 2009-02-10 20:32:09.000000000 +0100 @@ -182,7 +182,7 @@ apply_relocate_add(Elf64_Shdr *sechdrs, /* The small sections were sorted to the end of the segment. The following should definitely cover them. */ - gp = (u64)me->module_core + me->core_size - 0x8000; + gp = (u64)me->module_core_rw + me->core_size_rw - 0x8000; got = sechdrs[me->arch.gotsecindex].sh_addr; for (i = 0; i < n; i++) { diff -NurpP --minimal linux-2.6.27.15/arch/alpha/kernel/osf_sys.c linux-2.6.27.15-g-v/arch/alpha/kernel/osf_sys.c --- linux-2.6.27.15/arch/alpha/kernel/osf_sys.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/kernel/osf_sys.c 2009-02-10 20:32:09.000000000 +0100 @@ -888,7 +888,7 @@ osf_gettimeofday(struct timeval32 __user { if (tv) { struct timeval ktv; - do_gettimeofday(&ktv); + vx_gettimeofday(&ktv); if (put_tv32(tv, &ktv)) return -EFAULT; } @@ -1232,6 +1232,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) @@ -1239,8 +1243,8 @@ arch_get_unmapped_area(struct file *filp } /* Next, try allocating at TASK_UNMAPPED_BASE. */ - addr = arch_get_unmapped_area_1 (PAGE_ALIGN(TASK_UNMAPPED_BASE), - len, limit); + addr = arch_get_unmapped_area_1 (PAGE_ALIGN(current->mm->mmap_base), len, limit); + if (addr != (unsigned long) -ENOMEM) return addr; diff -NurpP --minimal linux-2.6.27.15/arch/alpha/kernel/ptrace.c linux-2.6.27.15-g-v/arch/alpha/kernel/ptrace.c --- linux-2.6.27.15/arch/alpha/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/kernel/ptrace.c 2009-02-10 20:32:09.000000000 +0100 @@ -15,6 +15,8 @@ #include #include #include +#include +#include #include #include @@ -266,6 +268,9 @@ long arch_ptrace(struct task_struct *chi size_t copied; long ret; + if (gr_handle_ptrace(child, request)) + return -EPERM; + switch (request) { /* When I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ diff -NurpP --minimal linux-2.6.27.15/arch/alpha/kernel/systbls.S linux-2.6.27.15-g-v/arch/alpha/kernel/systbls.S --- linux-2.6.27.15/arch/alpha/kernel/systbls.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/kernel/systbls.S 2009-02-10 20:32:09.000000000 +0100 @@ -446,7 +446,7 @@ sys_call_table: .quad sys_stat64 /* 425 */ .quad sys_lstat64 .quad sys_fstat64 - .quad sys_ni_syscall /* sys_vserver */ + .quad sys_vserver /* sys_vserver */ .quad sys_ni_syscall /* sys_mbind */ .quad sys_ni_syscall /* sys_get_mempolicy */ .quad sys_ni_syscall /* sys_set_mempolicy */ diff -NurpP --minimal linux-2.6.27.15/arch/alpha/kernel/traps.c linux-2.6.27.15-g-v/arch/alpha/kernel/traps.c --- linux-2.6.27.15/arch/alpha/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/kernel/traps.c 2009-02-10 20:32:09.000000000 +0100 @@ -183,7 +183,8 @@ die_if_kernel(char * str, struct pt_regs #ifdef CONFIG_SMP printk("CPU %d ", hard_smp_processor_id()); #endif - printk("%s(%d): %s %ld\n", current->comm, task_pid_nr(current), str, err); + printk("%s(%d[#%u]): %s %ld\n", current->comm, + task_pid_nr(current), current->xid, str, err); dik_show_regs(regs, r9_15); add_taint(TAINT_DIE); dik_show_trace((unsigned long *)(regs+1)); diff -NurpP --minimal linux-2.6.27.15/arch/alpha/mm/fault.c linux-2.6.27.15-g-v/arch/alpha/mm/fault.c --- linux-2.6.27.15/arch/alpha/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/alpha/mm/fault.c 2009-02-10 20:32:09.000000000 +0100 @@ -54,6 +54,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(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif /* * This routine handles page faults. It determines the address, @@ -131,8 +249,29 @@ do_page_fault(unsigned long address, uns good_area: si_code = SEGV_ACCERR; if (cause < 0) { - if (!(vma->vm_flags & VM_EXEC)) + if (!(vma->vm_flags & VM_EXEC)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(mm->pax_flags & MF_PAX_PAGEEXEC) || address != regs->pc) + goto bad_area; + + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void *)regs->pc, (void *)rdusp()); + do_group_exit(SIGKILL); +#else goto bad_area; +#endif + + } } else if (!cause) { /* Allow reads even for write-only mappings */ if (!(vma->vm_flags & (VM_READ | VM_WRITE))) @@ -193,8 +332,8 @@ do_page_fault(unsigned long address, uns down_read(&mm->mmap_sem); goto survive; } - printk(KERN_ALERT "VM: killing process %s(%d)\n", - current->comm, task_pid_nr(current)); + printk(KERN_ALERT "VM: killing process %s(%d:#%u)\n", + current->comm, task_pid_nr(current), current->xid); if (!user_mode(regs)) goto no_context; do_group_exit(SIGKILL); diff -NurpP --minimal linux-2.6.27.15/arch/arm/include/asm/elf.h linux-2.6.27.15-g-v/arch/arm/include/asm/elf.h --- linux-2.6.27.15/arch/arm/include/asm/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/arm/include/asm/elf.h 2009-02-10 20:32:09.000000000 +0100 @@ -87,7 +87,14 @@ extern char elf_platform[]; the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) + +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE 0x00008000UL + +#define PAX_DELTA_MMAP_LEN ((current->personality == PER_LINUX_32BIT) ? 16 : 10) +#define PAX_DELTA_STACK_LEN ((current->personality == PER_LINUX_32BIT) ? 16 : 10) +#endif /* When the program starts, a1 contains a pointer to a function to be registered with atexit, as per the SVR4 ABI. A value of 0 means we diff -NurpP --minimal linux-2.6.27.15/arch/arm/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/arm/include/asm/kmap_types.h --- linux-2.6.27.15/arch/arm/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/arm/include/asm/kmap_types.h 2009-02-10 20:32:09.000000000 +0100 @@ -18,6 +18,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/arch/arm/Kconfig linux-2.6.27.15-g-v/arch/arm/Kconfig --- linux-2.6.27.15/arch/arm/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/arm/Kconfig 2009-02-10 20:32:09.000000000 +0100 @@ -1240,6 +1240,8 @@ source "fs/Kconfig" source "arch/arm/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/arm/kernel/calls.S linux-2.6.27.15-g-v/arch/arm/kernel/calls.S --- linux-2.6.27.15/arch/arm/kernel/calls.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/arm/kernel/calls.S 2009-02-10 20:32:09.000000000 +0100 @@ -322,7 +322,7 @@ /* 310 */ CALL(sys_request_key) CALL(sys_keyctl) CALL(ABI(sys_semtimedop, sys_oabi_semtimedop)) -/* vserver */ CALL(sys_ni_syscall) + CALL(sys_vserver) CALL(sys_ioprio_set) /* 315 */ CALL(sys_ioprio_get) CALL(sys_inotify_init) diff -NurpP --minimal linux-2.6.27.15/arch/arm/kernel/process.c linux-2.6.27.15-g-v/arch/arm/kernel/process.c --- linux-2.6.27.15/arch/arm/kernel/process.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/arm/kernel/process.c 2009-02-10 20:32:09.000000000 +0100 @@ -262,7 +262,8 @@ void __show_regs(struct pt_regs *regs) void show_regs(struct pt_regs * regs) { printk("\n"); - printk("Pid: %d, comm: %20s\n", task_pid_nr(current), current->comm); + printk("Pid: %d[#%u], comm: %20s\n", + task_pid_nr(current), current->xid, current->comm); __show_regs(regs); __backtrace(); } diff -NurpP --minimal linux-2.6.27.15/arch/arm/kernel/traps.c linux-2.6.27.15-g-v/arch/arm/kernel/traps.c --- linux-2.6.27.15/arch/arm/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/arm/kernel/traps.c 2009-02-10 20:32:09.000000000 +0100 @@ -214,8 +214,8 @@ static void __die(const char *str, int e str, err, ++die_counter); print_modules(); __show_regs(regs); - printk("Process %s (pid: %d, stack limit = 0x%p)\n", - tsk->comm, task_pid_nr(tsk), thread + 1); + printk("Process %s (pid: %d:#%u, stack limit = 0x%p)\n", + tsk->comm, task_pid_nr(tsk), tsk->xid, thread + 1); if (!user_mode(regs) || in_interrupt()) { dump_mem("Stack: ", regs->ARM_sp, diff -NurpP --minimal linux-2.6.27.15/arch/arm/mm/fault.c linux-2.6.27.15-g-v/arch/arm/mm/fault.c --- linux-2.6.27.15/arch/arm/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/arm/mm/fault.c 2009-02-10 20:32:09.000000000 +0100 @@ -292,7 +292,8 @@ do_page_fault(unsigned long addr, unsign * happened to us that made us unable to handle * the page fault gracefully. */ - printk("VM: killing process %s\n", tsk->comm); + printk("VM: killing process %s(%d:#%u)\n", + tsk->comm, task_pid_nr(tsk), tsk->xid); do_group_exit(SIGKILL); return 0; } diff -NurpP --minimal linux-2.6.27.15/arch/arm/mm/mmap.c linux-2.6.27.15-g-v/arch/arm/mm/mmap.c --- linux-2.6.27.15/arch/arm/mm/mmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/arm/mm/mmap.c 2009-02-10 20:32:09.000000000 +0100 @@ -60,6 +60,10 @@ arch_get_unmapped_area(struct file *filp if (len > TASK_SIZE) return -ENOMEM; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP) || !filp) +#endif + if (addr) { if (do_align) addr = COLOUR_ALIGN(addr, pgoff); @@ -72,10 +76,10 @@ arch_get_unmapped_area(struct file *filp return addr; } if (len > mm->cached_hole_size) { - start_addr = addr = mm->free_area_cache; + start_addr = addr = mm->free_area_cache; } else { - start_addr = addr = TASK_UNMAPPED_BASE; - mm->cached_hole_size = 0; + start_addr = addr = mm->mmap_base; + mm->cached_hole_size = 0; } full_search: @@ -91,8 +95,8 @@ full_search: * Start a new search - just in case we missed * some holes. */ - if (start_addr != TASK_UNMAPPED_BASE) { - start_addr = addr = TASK_UNMAPPED_BASE; + if (start_addr != mm->mmap_base) { + start_addr = addr = mm->mmap_base; mm->cached_hole_size = 0; goto full_search; } diff -NurpP --minimal linux-2.6.27.15/arch/avr32/include/asm/elf.h linux-2.6.27.15-g-v/arch/avr32/include/asm/elf.h --- linux-2.6.27.15/arch/avr32/include/asm/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/avr32/include/asm/elf.h 2009-02-10 20:32:09.000000000 +0100 @@ -85,8 +85,14 @@ typedef struct user_fpu_struct elf_fpreg the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ -#define ELF_ET_DYN_BASE (2 * TASK_SIZE / 3) +#define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) + +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE 0x00001000UL +#define PAX_DELTA_MMAP_LEN 15 +#define PAX_DELTA_STACK_LEN 15 +#endif /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, diff -NurpP --minimal linux-2.6.27.15/arch/avr32/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/avr32/include/asm/kmap_types.h --- linux-2.6.27.15/arch/avr32/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/avr32/include/asm/kmap_types.h 2009-02-10 20:32:09.000000000 +0100 @@ -22,7 +22,8 @@ D(10) KM_IRQ0, D(11) KM_IRQ1, D(12) KM_SOFTIRQ0, D(13) KM_SOFTIRQ1, -D(14) KM_TYPE_NR +D(14) KM_CLEARPAGE, +D(15) KM_TYPE_NR }; #undef D diff -NurpP --minimal linux-2.6.27.15/arch/avr32/mm/fault.c linux-2.6.27.15-g-v/arch/avr32/mm/fault.c --- linux-2.6.27.15/arch/avr32/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/avr32/mm/fault.c 2009-02-10 20:32:09.000000000 +0100 @@ -41,6 +41,23 @@ static inline int notify_page_fault(stru int exception_trace = 1; +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 20; i++) { + unsigned char c; + if (get_user(c, (unsigned char *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%02x ", c); + } + printk("\n"); +} +#endif + /* * This routine handles page faults. It determines the address and the * problem, and then passes it off to one of the appropriate routines. @@ -157,6 +174,16 @@ bad_area: up_read(&mm->mmap_sem); if (user_mode(regs)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm->pax_flags & MF_PAX_PAGEEXEC) { + if (ecr == ECR_PROTECTION_X || ecr == ECR_TLB_MISS_X) { + pax_report_fault(regs, (void *)regs->pc, (void *)regs->sp); + do_group_exit(SIGKILL); + } + } +#endif + if (exception_trace && printk_ratelimit()) printk("%s%s[%d]: segfault at %08lx pc %08lx " "sp %08lx ecr %lu\n", diff -NurpP --minimal linux-2.6.27.15/arch/blackfin/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/blackfin/include/asm/kmap_types.h --- linux-2.6.27.15/arch/blackfin/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/blackfin/include/asm/kmap_types.h 2009-02-10 20:32:09.000000000 +0100 @@ -15,6 +15,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/arch/cris/Kconfig linux-2.6.27.15-g-v/arch/cris/Kconfig --- linux-2.6.27.15/arch/cris/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/cris/Kconfig 2009-02-10 20:32:09.000000000 +0100 @@ -679,6 +679,8 @@ source "drivers/usb/Kconfig" source "arch/cris/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/frv/kernel/kernel_thread.S linux-2.6.27.15-g-v/arch/frv/kernel/kernel_thread.S --- linux-2.6.27.15/arch/frv/kernel/kernel_thread.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/frv/kernel/kernel_thread.S 2009-02-10 20:32:09.000000000 +0100 @@ -37,7 +37,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 --minimal linux-2.6.27.15/arch/h8300/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/h8300/include/asm/kmap_types.h --- linux-2.6.27.15/arch/h8300/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/h8300/include/asm/kmap_types.h 2009-02-10 20:32:09.000000000 +0100 @@ -15,6 +15,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/arch/h8300/Kconfig linux-2.6.27.15-g-v/arch/h8300/Kconfig --- linux-2.6.27.15/arch/h8300/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/h8300/Kconfig 2009-02-10 20:32:09.000000000 +0100 @@ -219,6 +219,8 @@ source "fs/Kconfig" source "arch/h8300/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/ia64/ia32/binfmt_elf32.c linux-2.6.27.15-g-v/arch/ia64/ia32/binfmt_elf32.c --- linux-2.6.27.15/arch/ia64/ia32/binfmt_elf32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/ia32/binfmt_elf32.c 2009-02-10 20:32:09.000000000 +0100 @@ -45,6 +45,13 @@ randomize_stack_top(unsigned long stack_ #define elf_read_implies_exec(ex, have_pt_gnu_stack) (!(have_pt_gnu_stack)) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (current->personality == PER_LINUX32 ? 0x08048000UL : 0x4000000000000000UL) + +#define PAX_DELTA_MMAP_LEN (current->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - 13) +#define PAX_DELTA_STACK_LEN (current->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - 13) +#endif + /* Ugly but avoids duplication */ #include "../../../fs/binfmt_elf.c" diff -NurpP --minimal linux-2.6.27.15/arch/ia64/ia32/ia32_entry.S linux-2.6.27.15-g-v/arch/ia64/ia32/ia32_entry.S --- linux-2.6.27.15/arch/ia64/ia32/ia32_entry.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/ia32/ia32_entry.S 2009-02-10 20:32:09.000000000 +0100 @@ -446,7 +446,7 @@ ia32_syscall_table: data8 sys_tgkill /* 270 */ data8 compat_sys_utimes data8 sys32_fadvise64_64 - data8 sys_ni_syscall + data8 sys32_vserver data8 sys_ni_syscall data8 sys_ni_syscall /* 275 */ data8 sys_ni_syscall diff -NurpP --minimal linux-2.6.27.15/arch/ia64/ia32/ia32priv.h linux-2.6.27.15-g-v/arch/ia64/ia32/ia32priv.h --- linux-2.6.27.15/arch/ia64/ia32/ia32priv.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/ia32/ia32priv.h 2009-02-10 20:32:09.000000000 +0100 @@ -296,7 +296,14 @@ typedef struct compat_siginfo { #define ELF_DATA ELFDATA2LSB #define ELF_ARCH EM_386 -#define IA32_STACK_TOP IA32_PAGE_OFFSET +#ifdef CONFIG_PAX_RANDUSTACK +#define __IA32_DELTA_STACK (current->mm->delta_stack) +#else +#define __IA32_DELTA_STACK 0UL +#endif + +#define IA32_STACK_TOP (IA32_PAGE_OFFSET - __IA32_DELTA_STACK) + #define IA32_GATE_OFFSET IA32_PAGE_OFFSET #define IA32_GATE_END IA32_PAGE_OFFSET + PAGE_SIZE diff -NurpP --minimal linux-2.6.27.15/arch/ia64/ia32/sys_ia32.c linux-2.6.27.15-g-v/arch/ia64/ia32/sys_ia32.c --- linux-2.6.27.15/arch/ia64/ia32/sys_ia32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/ia32/sys_ia32.c 2009-02-10 20:32:09.000000000 +0100 @@ -1178,7 +1178,7 @@ sys32_gettimeofday (struct compat_timeva { if (tv) { struct timeval ktv; - do_gettimeofday(&ktv); + vx_gettimeofday(&ktv); if (put_tv32(tv, &ktv)) return -EFAULT; } diff -NurpP --minimal linux-2.6.27.15/arch/ia64/include/asm/elf.h linux-2.6.27.15-g-v/arch/ia64/include/asm/elf.h --- linux-2.6.27.15/arch/ia64/include/asm/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/include/asm/elf.h 2009-02-10 20:32:09.000000000 +0100 @@ -43,6 +43,13 @@ */ #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x800000000UL) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (current->personality == PER_LINUX32 ? 0x08048000UL : 0x4000000000000000UL) + +#define PAX_DELTA_MMAP_LEN (current->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - 13) +#define PAX_DELTA_STACK_LEN (current->personality == PER_LINUX32 ? 16 : 3*PAGE_SHIFT - 13) +#endif + #define PT_IA_64_UNWIND 0x70000001 /* IA-64 relocations: */ diff -NurpP --minimal linux-2.6.27.15/arch/ia64/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/ia64/include/asm/kmap_types.h --- linux-2.6.27.15/arch/ia64/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/include/asm/kmap_types.h 2009-02-10 20:32:09.000000000 +0100 @@ -22,7 +22,8 @@ D(9) KM_IRQ0, D(10) KM_IRQ1, D(11) KM_SOFTIRQ0, D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR +D(13) KM_CLEARPAGE, +D(14) KM_TYPE_NR }; #undef D diff -NurpP --minimal linux-2.6.27.15/arch/ia64/include/asm/pgtable.h linux-2.6.27.15-g-v/arch/ia64/include/asm/pgtable.h --- linux-2.6.27.15/arch/ia64/include/asm/pgtable.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/include/asm/pgtable.h 2009-02-10 20:32:09.000000000 +0100 @@ -143,6 +143,17 @@ #define PAGE_READONLY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) #define PAGE_COPY __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) #define PAGE_COPY_EXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RX) + +#ifdef CONFIG_PAX_PAGEEXEC +# define PAGE_SHARED_NOEXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_RW) +# define PAGE_READONLY_NOEXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) +# define PAGE_COPY_NOEXEC __pgprot(__ACCESS_BITS | _PAGE_PL_3 | _PAGE_AR_R) +#else +# define PAGE_SHARED_NOEXEC PAGE_SHARED +# define PAGE_READONLY_NOEXEC PAGE_READONLY +# define PAGE_COPY_NOEXEC PAGE_COPY +#endif + #define PAGE_GATE __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_X_RX) #define PAGE_KERNEL __pgprot(__DIRTY_BITS | _PAGE_PL_0 | _PAGE_AR_RWX) #define PAGE_KERNELRX __pgprot(__ACCESS_BITS | _PAGE_PL_0 | _PAGE_AR_RX) diff -NurpP --minimal linux-2.6.27.15/arch/ia64/Kconfig linux-2.6.27.15-g-v/arch/ia64/Kconfig --- linux-2.6.27.15/arch/ia64/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/Kconfig 2009-02-10 20:32:09.000000000 +0100 @@ -640,6 +640,8 @@ source "arch/ia64/hp/sim/Kconfig" source "arch/ia64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/ia64/kernel/entry.S linux-2.6.27.15-g-v/arch/ia64/kernel/entry.S --- linux-2.6.27.15/arch/ia64/kernel/entry.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/kernel/entry.S 2009-02-10 20:32:09.000000000 +0100 @@ -1647,7 +1647,7 @@ sys_call_table: data8 sys_mq_notify data8 sys_mq_getsetattr data8 sys_kexec_load - data8 sys_ni_syscall // reserved for vserver + data8 sys_vserver data8 sys_waitid // 1270 data8 sys_add_key data8 sys_request_key diff -NurpP --minimal linux-2.6.27.15/arch/ia64/kernel/module.c linux-2.6.27.15-g-v/arch/ia64/kernel/module.c --- linux-2.6.27.15/arch/ia64/kernel/module.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/kernel/module.c 2009-02-10 20:32:09.000000000 +0100 @@ -312,8 +312,7 @@ module_alloc (unsigned long size) void module_free (struct module *mod, void *module_region) { - if (mod && mod->arch.init_unw_table && - module_region == mod->module_init) { + if (mod && 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; } @@ -491,15 +490,39 @@ module_frob_arch_sections (Elf_Ehdr *ehd } static inline int +in_init_rx (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_init_rx < mod->init_size_rx; +} + +static inline int +in_init_rw (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_init_rw < mod->init_size_rw; +} + +static inline int in_init (const struct module *mod, uint64_t addr) { - return addr - (uint64_t) mod->module_init < mod->init_size; + return in_init_rx(mod, addr) || in_init_rw(mod, addr); +} + +static inline int +in_core_rx (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_core_rx < mod->core_size_rx; +} + +static inline int +in_core_rw (const struct module *mod, uint64_t addr) +{ + return addr - (uint64_t) mod->module_core_rw < mod->core_size_rw; } static inline int in_core (const struct module *mod, uint64_t addr) { - return addr - (uint64_t) mod->module_core < mod->core_size; + return in_core_rx(mod, addr) || in_core_rw(mod, addr); } static inline int @@ -683,7 +706,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: @@ -817,15 +847,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", __func__, gp); } diff -NurpP --minimal linux-2.6.27.15/arch/ia64/kernel/perfmon.c linux-2.6.27.15-g-v/arch/ia64/kernel/perfmon.c --- linux-2.6.27.15/arch/ia64/kernel/perfmon.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/kernel/perfmon.c 2009-02-10 20:32:09.000000000 +0100 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include @@ -2376,7 +2377,7 @@ pfm_smpl_buffer_alloc(struct task_struct */ insert_vm_struct(mm, vma); - mm->total_vm += size >> PAGE_SHIFT; + vx_vmpages_add(mm, size >> PAGE_SHIFT); vm_stat_account(vma->vm_mm, vma->vm_flags, vma->vm_file, vma_pages(vma)); up_write(&task->mm->mmap_sem); diff -NurpP --minimal linux-2.6.27.15/arch/ia64/kernel/process.c linux-2.6.27.15-g-v/arch/ia64/kernel/process.c --- linux-2.6.27.15/arch/ia64/kernel/process.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/kernel/process.c 2009-02-10 20:32:09.000000000 +0100 @@ -109,8 +109,8 @@ show_regs (struct pt_regs *regs) unsigned long ip = regs->cr_iip + ia64_psr(regs)->ri; print_modules(); - printk("\nPid: %d, CPU %d, comm: %20s\n", task_pid_nr(current), - smp_processor_id(), current->comm); + printk("\nPid: %d[#%u], CPU %d, comm: %20s\n", task_pid_nr(current), + current->xid, smp_processor_id(), current->comm); printk("psr : %016lx ifs : %016lx ip : [<%016lx>] %s (%s)\n", regs->cr_ipsr, regs->cr_ifs, ip, print_tainted(), init_utsname()->release); diff -NurpP --minimal linux-2.6.27.15/arch/ia64/kernel/ptrace.c linux-2.6.27.15-g-v/arch/ia64/kernel/ptrace.c --- linux-2.6.27.15/arch/ia64/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/kernel/ptrace.c 2009-02-10 20:32:09.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/arch/ia64/kernel/sys_ia64.c linux-2.6.27.15-g-v/arch/ia64/kernel/sys_ia64.c --- linux-2.6.27.15/arch/ia64/kernel/sys_ia64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/kernel/sys_ia64.c 2009-02-10 20:32:09.000000000 +0100 @@ -43,6 +43,13 @@ arch_get_unmapped_area (struct file *fil if (REGION_NUMBER(addr) == RGN_HPAGE) addr = 0; #endif + +#ifdef CONFIG_PAX_RANDMMAP + if ((mm->pax_flags & MF_PAX_RANDMMAP) && addr && filp) + addr = mm->free_area_cache; + else +#endif + if (!addr) addr = mm->free_area_cache; @@ -61,9 +68,9 @@ arch_get_unmapped_area (struct file *fil for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { /* At this point: (!vma || addr < vma->vm_end). */ if (TASK_SIZE - len < addr || RGN_MAP_LIMIT - len < REGION_OFFSET(addr)) { - if (start_addr != TASK_UNMAPPED_BASE) { + if (start_addr != mm->mmap_base) { /* Start a new search --- just in case we missed some holes. */ - addr = TASK_UNMAPPED_BASE; + addr = mm->mmap_base; goto full_search; } return -ENOMEM; diff -NurpP --minimal linux-2.6.27.15/arch/ia64/kernel/traps.c linux-2.6.27.15-g-v/arch/ia64/kernel/traps.c --- linux-2.6.27.15/arch/ia64/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/kernel/traps.c 2009-02-10 20:32:09.000000000 +0100 @@ -60,8 +60,9 @@ die (const char *str, struct pt_regs *re put_cpu(); if (++die.lock_owner_depth < 3) { - printk("%s[%d]: %s %ld [%d]\n", - current->comm, task_pid_nr(current), str, err, ++die_counter); + printk("%s[%d[#%u]]: %s %ld [%d]\n", + current->comm, task_pid_nr(current), current->xid, + str, err, ++die_counter); if (notify_die(DIE_OOPS, str, regs, err, 255, SIGSEGV) != NOTIFY_STOP) show_regs(regs); @@ -324,8 +325,9 @@ handle_fpu_swa (int fp_fault, struct pt_ if ((last.count & 15) < 5 && (ia64_fetchadd(1, &last.count, acq) & 15) < 5) { last.time = current_jiffies + 5 * HZ; printk(KERN_WARNING - "%s(%d): floating-point assist fault at ip %016lx, isr %016lx\n", - current->comm, task_pid_nr(current), regs->cr_iip + ia64_psr(regs)->ri, isr); + "%s(%d[#%u]): floating-point assist fault at ip %016lx, isr %016lx\n", + current->comm, task_pid_nr(current), current->xid, + regs->cr_iip + ia64_psr(regs)->ri, isr); } } } diff -NurpP --minimal linux-2.6.27.15/arch/ia64/mm/fault.c linux-2.6.27.15-g-v/arch/ia64/mm/fault.c --- linux-2.6.27.15/arch/ia64/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/mm/fault.c 2009-02-10 20:32:09.000000000 +0100 @@ -10,6 +10,7 @@ #include #include #include +#include #include #include @@ -72,6 +73,23 @@ mapped_kernel_page_is_present (unsigned return pte_present(pte); } +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 8; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + void __kprobes ia64_do_page_fault (unsigned long address, unsigned long isr, struct pt_regs *regs) { @@ -145,9 +163,23 @@ ia64_do_page_fault (unsigned long addres mask = ( (((isr >> IA64_ISR_X_BIT) & 1UL) << VM_EXEC_BIT) | (((isr >> IA64_ISR_W_BIT) & 1UL) << VM_WRITE_BIT)); - if ((vma->vm_flags & mask) != mask) + if ((vma->vm_flags & mask) != mask) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (!(vma->vm_flags & VM_EXEC) && (mask & VM_EXEC)) { + if (!(mm->pax_flags & MF_PAX_PAGEEXEC) || address != regs->cr_iip) + goto bad_area; + + up_read(&mm->mmap_sem); + pax_report_fault(regs, (void *)regs->cr_iip, (void *)regs->r12); + do_group_exit(SIGKILL); + } +#endif + goto bad_area; + } + survive: /* * If for any reason at all we couldn't handle the fault, make diff -NurpP --minimal linux-2.6.27.15/arch/ia64/mm/init.c linux-2.6.27.15-g-v/arch/ia64/mm/init.c --- linux-2.6.27.15/arch/ia64/mm/init.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/ia64/mm/init.c 2009-02-10 20:32:09.000000000 +0100 @@ -122,6 +122,19 @@ ia64_init_addr_space (void) vma->vm_start = current->thread.rbs_bot & PAGE_MASK; vma->vm_end = vma->vm_start + PAGE_SIZE; vma->vm_flags = VM_DATA_DEFAULT_FLAGS|VM_GROWSUP|VM_ACCOUNT; + +#ifdef CONFIG_PAX_PAGEEXEC + if (current->mm->pax_flags & MF_PAX_PAGEEXEC) { + vma->vm_flags &= ~VM_EXEC; + +#ifdef CONFIG_PAX_MPROTECT + if (current->mm->pax_flags & MF_PAX_MPROTECT) + vma->vm_flags &= ~VM_MAYEXEC; +#endif + + } +#endif + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); down_write(¤t->mm->mmap_sem); if (insert_vm_struct(current->mm, vma)) { diff -NurpP --minimal linux-2.6.27.15/arch/m32r/kernel/traps.c linux-2.6.27.15-g-v/arch/m32r/kernel/traps.c --- linux-2.6.27.15/arch/m32r/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/m32r/kernel/traps.c 2009-02-10 20:32:09.000000000 +0100 @@ -196,8 +196,9 @@ static void show_registers(struct pt_reg } else { printk("SPI: %08lx\n", sp); } - printk("Process %s (pid: %d, process nr: %d, stackpage=%08lx)", - current->comm, task_pid_nr(current), 0xffff & i, 4096+(unsigned long)current); + printk("Process %s (pid: %d[#%u], process nr: %d, stackpage=%08lx)", + current->comm, task_pid_nr(current), current->xid, + 0xffff & i, 4096+(unsigned long)current); /* * When in-kernel, we also print out the stack and code at the diff -NurpP --minimal linux-2.6.27.15/arch/m68k/Kconfig linux-2.6.27.15-g-v/arch/m68k/Kconfig --- linux-2.6.27.15/arch/m68k/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/m68k/Kconfig 2009-02-10 20:32:09.000000000 +0100 @@ -633,6 +633,8 @@ source "fs/Kconfig" source "arch/m68k/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/m68k/kernel/ptrace.c linux-2.6.27.15-g-v/arch/m68k/kernel/ptrace.c --- linux-2.6.27.15/arch/m68k/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/m68k/kernel/ptrace.c 2009-02-10 20:32:09.000000000 +0100 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include @@ -269,6 +270,8 @@ long arch_ptrace(struct task_struct *chi ret = ptrace_request(child, request, addr, data); break; } + if (!vx_check(vx_task_xid(child), VS_WATCH_P | VS_IDENT)) + goto out_tsk; return ret; out_eio: diff -NurpP --minimal linux-2.6.27.15/arch/m68k/kernel/traps.c linux-2.6.27.15-g-v/arch/m68k/kernel/traps.c --- linux-2.6.27.15/arch/m68k/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/m68k/kernel/traps.c 2009-02-10 20:32:09.000000000 +0100 @@ -909,8 +909,8 @@ void show_registers(struct pt_regs *regs printk("d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", regs->d4, regs->d5, regs->a0, regs->a1); - printk("Process %s (pid: %d, task=%p)\n", - current->comm, task_pid_nr(current), current); + printk("Process %s (pid: %d[#%u], task=%p)\n", + current->comm, task_pid_nr(current), current->xid, current); addr = (unsigned long)&fp->un; printk("Frame format=%X ", regs->format); switch (regs->format) { diff -NurpP --minimal linux-2.6.27.15/arch/m68knommu/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/m68knommu/include/asm/kmap_types.h --- linux-2.6.27.15/arch/m68knommu/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/m68knommu/include/asm/kmap_types.h 2009-02-10 20:32:09.000000000 +0100 @@ -15,6 +15,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/arch/m68knommu/Kconfig linux-2.6.27.15-g-v/arch/m68knommu/Kconfig --- linux-2.6.27.15/arch/m68knommu/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/m68knommu/Kconfig 2009-02-10 20:32:09.000000000 +0100 @@ -744,6 +744,8 @@ source "fs/Kconfig" source "arch/m68knommu/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/m68knommu/kernel/traps.c linux-2.6.27.15-g-v/arch/m68knommu/kernel/traps.c --- linux-2.6.27.15/arch/m68knommu/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/m68knommu/kernel/traps.c 2009-02-10 20:32:10.000000000 +0100 @@ -79,8 +79,9 @@ void die_if_kernel(char *str, struct pt_ printk(KERN_EMERG "d4: %08lx d5: %08lx a0: %08lx a1: %08lx\n", fp->d4, fp->d5, fp->a0, fp->a1); - printk(KERN_EMERG "Process %s (pid: %d, stackpage=%08lx)\n", - current->comm, current->pid, PAGE_SIZE+(unsigned long)current); + printk(KERN_EMERG "Process %s (pid: %d[#%u], stackpage=%08lx)\n", + current->comm, task_pid_nr(current), current->xid, + PAGE_SIZE+(unsigned long)current); show_stack(NULL, (unsigned long *)(fp + 1)); add_taint(TAINT_DIE); do_exit(SIGSEGV); diff -NurpP --minimal linux-2.6.27.15/arch/mips/Kconfig linux-2.6.27.15-g-v/arch/mips/Kconfig --- linux-2.6.27.15/arch/mips/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -2031,6 +2031,8 @@ source "fs/Kconfig" source "arch/mips/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/binfmt_elfn32.c linux-2.6.27.15-g-v/arch/mips/kernel/binfmt_elfn32.c --- linux-2.6.27.15/arch/mips/kernel/binfmt_elfn32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/binfmt_elfn32.c 2009-02-10 20:32:10.000000000 +0100 @@ -50,6 +50,13 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_N #undef ELF_ET_DYN_BASE #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (test_thread_flag(TIF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LEN (test_thread_flag(TIF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LEN (test_thread_flag(TIF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include #include diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/binfmt_elfo32.c linux-2.6.27.15-g-v/arch/mips/kernel/binfmt_elfo32.c --- linux-2.6.27.15/arch/mips/kernel/binfmt_elfo32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/binfmt_elfo32.c 2009-02-10 20:32:10.000000000 +0100 @@ -52,6 +52,13 @@ typedef elf_fpreg_t elf_fpregset_t[ELF_N #undef ELF_ET_DYN_BASE #define ELF_ET_DYN_BASE (TASK32_SIZE / 3 * 2) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (test_thread_flag(TIF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LEN (test_thread_flag(TIF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LEN (test_thread_flag(TIF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #include #include #include diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/linux32.c linux-2.6.27.15-g-v/arch/mips/kernel/linux32.c --- linux-2.6.27.15/arch/mips/kernel/linux32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/linux32.c 2009-02-10 20:32:10.000000000 +0100 @@ -191,7 +191,7 @@ sys32_gettimeofday(struct compat_timeval { if (tv) { struct timeval ktv; - do_gettimeofday(&ktv); + vx_gettimeofday(&ktv); if (put_tv32(tv, &ktv)) return -EFAULT; } diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/process.c linux-2.6.27.15-g-v/arch/mips/kernel/process.c --- linux-2.6.27.15/arch/mips/kernel/process.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/process.c 2009-02-10 20:32:10.000000000 +0100 @@ -458,15 +458,3 @@ unsigned long get_wchan(struct task_stru out: return pc; } - -/* - * Don't forget that the stack pointer must be aligned on a 8 bytes - * boundary for 32-bits ABI and 16 bytes for 64-bits ABI. - */ -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() & ~PAGE_MASK; - - return sp & ALMASK; -} diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/ptrace.c linux-2.6.27.15-g-v/arch/mips/kernel/ptrace.c --- linux-2.6.27.15/arch/mips/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/ptrace.c 2009-02-10 20:32:10.000000000 +0100 @@ -25,6 +25,7 @@ #include #include #include +#include #include #include @@ -171,6 +172,9 @@ long arch_ptrace(struct task_struct *chi { int ret; + if (!vx_check(vx_task_xid(child), VS_WATCH_P | VS_IDENT)) + goto out; + switch (request) { /* when I and D space are separate, these will need to be fixed. */ case PTRACE_PEEKTEXT: /* read word at location addr. */ diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/scall32-o32.S linux-2.6.27.15-g-v/arch/mips/kernel/scall32-o32.S --- linux-2.6.27.15/arch/mips/kernel/scall32-o32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/scall32-o32.S 2009-02-10 20:32:10.000000000 +0100 @@ -600,7 +600,7 @@ einval: li v0, -EINVAL sys sys_mq_timedreceive 5 sys sys_mq_notify 2 /* 4275 */ sys sys_mq_getsetattr 3 - sys sys_ni_syscall 0 /* sys_vserver */ + sys sys_vserver 3 sys sys_waitid 5 sys sys_ni_syscall 0 /* available, was setaltroot */ sys sys_add_key 5 /* 4280 */ diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/scall64-64.S linux-2.6.27.15-g-v/arch/mips/kernel/scall64-64.S --- linux-2.6.27.15/arch/mips/kernel/scall64-64.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/scall64-64.S 2009-02-10 20:32:10.000000000 +0100 @@ -434,7 +434,7 @@ sys_call_table: PTR sys_mq_timedreceive PTR sys_mq_notify PTR sys_mq_getsetattr /* 5235 */ - PTR sys_ni_syscall /* sys_vserver */ + PTR sys_vserver PTR sys_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/scall64-n32.S linux-2.6.27.15-g-v/arch/mips/kernel/scall64-n32.S --- linux-2.6.27.15/arch/mips/kernel/scall64-n32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/scall64-n32.S 2009-02-10 20:32:10.000000000 +0100 @@ -360,7 +360,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 compat_sys_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/scall64-o32.S linux-2.6.27.15-g-v/arch/mips/kernel/scall64-o32.S --- linux-2.6.27.15/arch/mips/kernel/scall64-o32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/scall64-o32.S 2009-02-10 20:32:10.000000000 +0100 @@ -482,7 +482,7 @@ sys_call_table: PTR compat_sys_mq_timedreceive PTR compat_sys_mq_notify /* 4275 */ PTR compat_sys_mq_getsetattr - PTR sys_ni_syscall /* sys_vserver */ + PTR sys32_vserver PTR sys32_waitid PTR sys_ni_syscall /* available, was setaltroot */ PTR sys_add_key /* 4280 */ diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/syscall.c linux-2.6.27.15-g-v/arch/mips/kernel/syscall.c --- linux-2.6.27.15/arch/mips/kernel/syscall.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/syscall.c 2009-02-10 20:32:10.000000000 +0100 @@ -100,6 +100,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); @@ -110,7 +115,7 @@ unsigned long arch_get_unmapped_area(str (!vmm || addr + len <= vmm->vm_start)) return addr; } - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; if (do_color_align) addr = COLOUR_ALIGN(addr, pgoff); else diff -NurpP --minimal linux-2.6.27.15/arch/mips/kernel/traps.c linux-2.6.27.15-g-v/arch/mips/kernel/traps.c --- linux-2.6.27.15/arch/mips/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/kernel/traps.c 2009-02-10 20:32:10.000000000 +0100 @@ -328,9 +328,10 @@ void show_registers(const struct pt_regs __show_regs(regs); print_modules(); - printk("Process %s (pid: %d, threadinfo=%p, task=%p, tls=%0*lx)\n", - current->comm, current->pid, current_thread_info(), current, - field, current_thread_info()->tp_value); + printk("Process %s (pid: %d:#%u, threadinfo=%p, task=%p, tls=%0*lx)\n", + current->comm, task_pid_nr(current), current->xid, + current_thread_info(), current, + field, current_thread_info()->tp_value); if (cpu_has_userlocal) { unsigned long tls; diff -NurpP --minimal linux-2.6.27.15/arch/mips/mm/fault.c linux-2.6.27.15-g-v/arch/mips/mm/fault.c --- linux-2.6.27.15/arch/mips/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/mips/mm/fault.c 2009-02-10 20:32:10.000000000 +0100 @@ -26,6 +26,23 @@ #include #include /* For VMALLOC_END */ +#ifdef CONFIG_PAX_PAGEEXEC +void pax_report_insns(void *pc) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%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 @@ -178,7 +195,8 @@ out_of_memory: down_read(&mm->mmap_sem); goto survive; } - printk("VM: killing process %s\n", tsk->comm); + printk("VM: killing process %s(%d:#%u)\n", + tsk->comm, tsk->pid, tsk->xid); if (user_mode(regs)) do_group_exit(SIGKILL); goto no_context; diff -NurpP --minimal linux-2.6.27.15/arch/parisc/Kconfig linux-2.6.27.15-g-v/arch/parisc/Kconfig --- linux-2.6.27.15/arch/parisc/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/parisc/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -279,6 +279,8 @@ source "fs/Kconfig" source "arch/parisc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/parisc/kernel/module.c linux-2.6.27.15-g-v/arch/parisc/kernel/module.c --- linux-2.6.27.15/arch/parisc/kernel/module.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/parisc/kernel/module.c 2009-02-10 20:32:10.000000000 +0100 @@ -75,16 +75,38 @@ /* three functions to determine where in the module core * or init pieces the location is */ +static inline int in_init_rx(struct module *me, void *loc) +{ + return (loc >= me->module_init_rx && + loc < (me->module_init_rx + me->init_size_rx)); +} + +static inline int in_init_rw(struct module *me, void *loc) +{ + return (loc >= me->module_init_rw && + loc < (me->module_init_rw + me->init_size_rw)); +} + static inline int in_init(struct module *me, void *loc) { - return (loc >= me->module_init && - loc <= (me->module_init + me->init_size)); + return in_init_rx(me, loc) || in_init_rw(me, loc); +} + +static inline int in_core_rx(struct module *me, void *loc) +{ + return (loc >= me->module_core_rx && + loc < (me->module_core_rx + me->core_size_rx)); +} + +static inline int in_core_rw(struct module *me, void *loc) +{ + return (loc >= me->module_core_rw && + loc < (me->module_core_rw + me->core_size_rw)); } static inline int in_core(struct module *me, void *loc) { - return (loc >= me->module_core && - loc <= (me->module_core + me->core_size)); + return in_core_rx(me, loc) || in_core_rw(me, loc); } static inline int in_local(struct module *me, void *loc) @@ -298,21 +320,21 @@ int module_frob_arch_sections(CONST Elf_ } /* align things a bit */ - me->core_size = ALIGN(me->core_size, 16); - me->arch.got_offset = me->core_size; - me->core_size += gots * sizeof(struct got_entry); + me->core_size_rw = ALIGN(me->core_size_rw, 16); + me->arch.got_offset = me->core_size_rw; + me->core_size_rw += gots * sizeof(struct got_entry); - me->core_size = ALIGN(me->core_size, 16); - me->arch.fdesc_offset = me->core_size; - me->core_size += fdescs * sizeof(Elf_Fdesc); + me->core_size_rw = ALIGN(me->core_size_rw, 16); + me->arch.fdesc_offset = me->core_size_rw; + me->core_size_rw += fdescs * sizeof(Elf_Fdesc); - me->core_size = ALIGN(me->core_size, 16); - me->arch.stub_offset = me->core_size; - me->core_size += stubs * sizeof(struct stub_entry); + me->core_size_rx = ALIGN(me->core_size_rx, 16); + me->arch.stub_offset = me->core_size_rx; + me->core_size_rx += stubs * sizeof(struct stub_entry); - me->init_size = ALIGN(me->init_size, 16); - me->arch.init_stub_offset = me->init_size; - me->init_size += init_stubs * sizeof(struct stub_entry); + me->init_size_rx = ALIGN(me->init_size_rx, 16); + me->arch.init_stub_offset = me->init_size_rx; + me->init_size_rx += init_stubs * sizeof(struct stub_entry); me->arch.got_max = gots; me->arch.fdesc_max = fdescs; @@ -332,7 +354,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; @@ -350,7 +372,7 @@ static Elf64_Word get_got(struct module #ifdef CONFIG_64BIT static Elf_Addr get_fdesc(struct module *me, unsigned long value) { - Elf_Fdesc *fdesc = me->module_core + me->arch.fdesc_offset; + Elf_Fdesc *fdesc = me->module_core_rw + me->arch.fdesc_offset; if (!value) { printk(KERN_ERR "%s: zero OPD requested!\n", me->name); @@ -368,7 +390,7 @@ static Elf_Addr get_fdesc(struct module /* Create new one */ fdesc->addr = value; - fdesc->gp = (Elf_Addr)me->module_core + me->arch.got_offset; + fdesc->gp = (Elf_Addr)me->module_core_rw + me->arch.got_offset; return (Elf_Addr)fdesc; } #endif /* CONFIG_64BIT */ @@ -388,12 +410,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); } @@ -761,7 +783,7 @@ register_unwind_table(struct module *me, table = (unsigned char *)sechdrs[me->arch.unwind_section].sh_addr; end = table + sechdrs[me->arch.unwind_section].sh_size; - gp = (Elf_Addr)me->module_core + me->arch.got_offset; + gp = (Elf_Addr)me->module_core_rw + me->arch.got_offset; DEBUGP("register_unwind_table(), sect = %d at 0x%p - 0x%p (gp=0x%lx)\n", me->arch.unwind_section, table, end, gp); diff -NurpP --minimal linux-2.6.27.15/arch/parisc/kernel/syscall_table.S linux-2.6.27.15-g-v/arch/parisc/kernel/syscall_table.S --- linux-2.6.27.15/arch/parisc/kernel/syscall_table.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/parisc/kernel/syscall_table.S 2009-02-10 20:32:10.000000000 +0100 @@ -361,7 +361,7 @@ ENTRY_COMP(mbind) /* 260 */ ENTRY_COMP(get_mempolicy) ENTRY_COMP(set_mempolicy) - ENTRY_SAME(ni_syscall) /* 263: reserved for vserver */ + ENTRY_DIFF(vserver) ENTRY_SAME(add_key) ENTRY_SAME(request_key) /* 265 */ ENTRY_SAME(keyctl) diff -NurpP --minimal linux-2.6.27.15/arch/parisc/kernel/sys_parisc32.c linux-2.6.27.15-g-v/arch/parisc/kernel/sys_parisc32.c --- linux-2.6.27.15/arch/parisc/kernel/sys_parisc32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/parisc/kernel/sys_parisc32.c 2009-02-10 20:32:10.000000000 +0100 @@ -203,11 +203,11 @@ static inline long get_ts32(struct times asmlinkage int sys32_gettimeofday(struct compat_timeval __user *tv, struct timezone __user *tz) { - extern void do_gettimeofday(struct timeval *tv); + extern void vx_gettimeofday(struct timeval *tv); if (tv) { struct timeval ktv; - do_gettimeofday(&ktv); + vx_gettimeofday(&ktv); if (put_compat_timeval(tv, &ktv)) return -EFAULT; } diff -NurpP --minimal linux-2.6.27.15/arch/parisc/kernel/sys_parisc.c linux-2.6.27.15-g-v/arch/parisc/kernel/sys_parisc.c --- linux-2.6.27.15/arch/parisc/kernel/sys_parisc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/parisc/kernel/sys_parisc.c 2009-02-10 20:32:10.000000000 +0100 @@ -98,7 +98,7 @@ unsigned long arch_get_unmapped_area(str if (flags & MAP_FIXED) return addr; if (!addr) - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; if (filp) { addr = get_shared_area(filp->f_mapping, addr, len, pgoff); diff -NurpP --minimal linux-2.6.27.15/arch/parisc/kernel/traps.c linux-2.6.27.15-g-v/arch/parisc/kernel/traps.c --- linux-2.6.27.15/arch/parisc/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/parisc/kernel/traps.c 2009-02-10 20:32:10.000000000 +0100 @@ -236,8 +236,9 @@ void die_if_kernel(char *str, struct pt_ if (err == 0) return; /* STFU */ - printk(KERN_CRIT "%s (pid %d): %s (code %ld) at " RFMT "\n", - current->comm, task_pid_nr(current), str, err, regs->iaoq[0]); + printk(KERN_CRIT "%s (pid %d:#%u): %s (code %ld) at " RFMT "\n", + current->comm, task_pid_nr(current), current->xid, + str, err, regs->iaoq[0]); #ifdef PRINT_USER_FAULTS /* XXX for debugging only */ show_regs(regs); @@ -269,8 +270,8 @@ KERN_CRIT " || | pdc_console_restart(); if (err) - printk(KERN_CRIT "%s (pid %d): %s (code %ld)\n", - current->comm, task_pid_nr(current), str, err); + printk(KERN_CRIT "%s (pid %d:#%u): %s (code %ld)\n", + current->comm, task_pid_nr(current), current->xid, str, err); /* Wot's wrong wif bein' racy? */ if (current->thread.flags & PARISC_KERNEL_DEATH) { @@ -731,9 +732,7 @@ void handle_interruption(int code, struc down_read(¤t->mm->mmap_sem); vma = find_vma(current->mm,regs->iaoq[0]); - if (vma && (regs->iaoq[0] >= vma->vm_start) - && (vma->vm_flags & VM_EXEC)) { - + if (vma && (regs->iaoq[0] >= vma->vm_start)) { fault_address = regs->iaoq[0]; fault_space = regs->iasq[0]; diff -NurpP --minimal linux-2.6.27.15/arch/parisc/mm/fault.c linux-2.6.27.15-g-v/arch/parisc/mm/fault.c --- linux-2.6.27.15/arch/parisc/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/parisc/mm/fault.c 2009-02-10 20:32:10.000000000 +0100 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -53,7 +54,7 @@ DEFINE_PER_CPU(struct exception_data, ex static unsigned long parisc_acctyp(unsigned long code, unsigned int inst) { - if (code == 6 || code == 16) + if (code == 6 || code == 7 || code == 16) return VM_EXEC; switch (inst & 0xf0000000) { @@ -139,6 +140,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(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + void do_page_fault(struct pt_regs *regs, unsigned long code, unsigned long address) { @@ -165,8 +276,33 @@ good_area: acc_type = parisc_acctyp(code,regs->iir); - if ((vma->vm_flags & acc_type) != acc_type) + if ((vma->vm_flags & acc_type) != acc_type) { + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && (acc_type & VM_EXEC) && + (address & ~3UL) == instruction_pointer(regs)) + { + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 3: + return; +#endif + +#ifdef CONFIG_PAX_EMUTRAMP + case 2: + return; +#endif + + } + pax_report_fault(regs, (void *)instruction_pointer(regs), (void *)regs->gr[30]); + do_group_exit(SIGKILL); + } +#endif + goto bad_area; + } /* * If for any reason at all we couldn't handle the fault, make @@ -210,8 +346,9 @@ bad_area: #ifdef PRINT_USER_FAULTS printk(KERN_DEBUG "\n"); - printk(KERN_DEBUG "do_page_fault() pid=%d command='%s' type=%lu address=0x%08lx\n", - task_pid_nr(tsk), tsk->comm, code, address); + printk(KERN_DEBUG "do_page_fault() pid=%d:#%u " + "command='%s' type=%lu address=0x%08lx\n", + task_pid_nr(tsk), tsk->xid, tsk->comm, code, address); if (vma) { printk(KERN_DEBUG "vm_start = 0x%08lx, vm_end = 0x%08lx\n", vma->vm_start, vma->vm_end); @@ -261,7 +398,8 @@ no_context: out_of_memory: up_read(&mm->mmap_sem); - printk(KERN_CRIT "VM: killing process %s\n", current->comm); + printk(KERN_CRIT "VM: killing process %s(%d:#%u)\n", + current->comm, current->pid, current->xid); if (user_mode(regs)) do_group_exit(SIGKILL); goto no_context; diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/include/asm/elf.h linux-2.6.27.15-g-v/arch/powerpc/include/asm/elf.h --- linux-2.6.27.15/arch/powerpc/include/asm/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/include/asm/elf.h 2009-02-10 20:32:10.000000000 +0100 @@ -180,6 +180,18 @@ typedef elf_fpreg_t elf_vsrreghalf_t32[E #define ELF_ET_DYN_BASE (0x20000000) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (0x10000000UL) + +#ifdef __powerpc64__ +#define PAX_DELTA_MMAP_LEN (test_thread_flag(TIF_32BIT) ? 16 : 28) +#define PAX_DELTA_STACK_LEN (test_thread_flag(TIF_32BIT) ? 16 : 28) +#else +#define PAX_DELTA_MMAP_LEN 15 +#define PAX_DELTA_STACK_LEN 15 +#endif +#endif + /* * Our registers are always unsigned longs, whether we're a 32 bit * process or 64 bit, on either a 64 bit or 32 bit kernel. diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/powerpc/include/asm/kmap_types.h --- linux-2.6.27.15/arch/powerpc/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/include/asm/kmap_types.h 2009-02-10 20:32:10.000000000 +0100 @@ -26,6 +26,7 @@ enum km_type { KM_SOFTIRQ1, KM_PPC_SYNC_PAGE, KM_PPC_SYNC_ICACHE, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/include/asm/page_64.h linux-2.6.27.15-g-v/arch/powerpc/include/asm/page_64.h --- linux-2.6.27.15/arch/powerpc/include/asm/page_64.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/include/asm/page_64.h 2009-02-10 20:32:10.000000000 +0100 @@ -170,15 +170,18 @@ do { \ * stack by default, so in the absense of a PT_GNU_STACK program header * we turn execute permission off. */ -#define VM_STACK_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_STACK_DEFAULT_FLAGS32 \ + (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define VM_STACK_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#ifndef CONFIG_PAX_PAGEEXEC #define VM_STACK_DEFAULT_FLAGS \ (test_thread_flag(TIF_32BIT) ? \ VM_STACK_DEFAULT_FLAGS32 : VM_STACK_DEFAULT_FLAGS64) +#endif #include diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/include/asm/page.h linux-2.6.27.15-g-v/arch/powerpc/include/asm/page.h --- linux-2.6.27.15/arch/powerpc/include/asm/page.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/include/asm/page.h 2009-02-10 20:32:10.000000000 +0100 @@ -100,8 +100,9 @@ extern phys_addr_t kernstart_addr; * and needs to be executable. This means the whole heap ends * up being executable. */ -#define VM_DATA_DEFAULT_FLAGS32 (VM_READ | VM_WRITE | VM_EXEC | \ - VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) +#define VM_DATA_DEFAULT_FLAGS32 \ + (((current->personality & READ_IMPLIES_EXEC) ? VM_EXEC : 0) | \ + VM_READ | VM_WRITE | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) #define VM_DATA_DEFAULT_FLAGS64 (VM_READ | VM_WRITE | \ VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC) diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/Kconfig linux-2.6.27.15-g-v/arch/powerpc/Kconfig --- linux-2.6.27.15/arch/powerpc/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -836,6 +836,8 @@ source "lib/Kconfig" source "arch/powerpc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" config KEYS_COMPAT diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/kernel/irq.c linux-2.6.27.15-g-v/arch/powerpc/kernel/irq.c --- linux-2.6.27.15/arch/powerpc/kernel/irq.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/kernel/irq.c 2009-02-10 20:32:10.000000000 +0100 @@ -53,6 +53,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/kernel/module_32.c linux-2.6.27.15-g-v/arch/powerpc/kernel/module_32.c --- linux-2.6.27.15/arch/powerpc/kernel/module_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/kernel/module_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -158,7 +158,7 @@ int module_frob_arch_sections(Elf32_Ehdr me->arch.core_plt_section = i; } if (!me->arch.core_plt_section || !me->arch.init_plt_section) { - printk("Module doesn't contain .plt or .init.plt sections.\n"); + printk("Module %s doesn't contain .plt or .init.plt sections.\n", me->name); return -ENOEXEC; } @@ -199,11 +199,16 @@ static uint32_t do_plt_call(void *locati DEBUGP("Doing plt for call to 0x%x at 0x%x\n", val, (unsigned int)location); /* Init, or core PLT? */ - if (location >= mod->module_core - && location < mod->module_core + mod->core_size) + if ((location >= mod->module_core_rx && location < mod->module_core_rx + mod->core_size_rx) || + (location >= mod->module_core_rw && location < mod->module_core_rw + mod->core_size_rw)) entry = (void *)sechdrs[mod->arch.core_plt_section].sh_addr; - else + else if ((location >= mod->module_init_rx && location < mod->module_init_rx + mod->init_size_rx) || + (location >= mod->module_init_rw && location < mod->module_init_rw + mod->init_size_rw)) entry = (void *)sechdrs[mod->arch.init_plt_section].sh_addr; + else { + printk(KERN_ERR "%s: invalid R_PPC_REL24 entry found\n", mod->name); + return ~0UL; + } /* Find this entry, or if that fails, the next avail. entry */ while (entry->jump[0]) { diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/kernel/process.c linux-2.6.27.15-g-v/arch/powerpc/kernel/process.c --- linux-2.6.27.15/arch/powerpc/kernel/process.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/kernel/process.c 2009-02-10 20:32:10.000000000 +0100 @@ -513,8 +513,9 @@ void show_regs(struct pt_regs * regs) #else printk("DAR: "REG", DSISR: "REG"\n", regs->dar, regs->dsisr); #endif - printk("TASK = %p[%d] '%s' THREAD: %p", - current, task_pid_nr(current), current->comm, task_thread_info(current)); + printk("TASK = %p[%d,#%u] '%s' THREAD: %p", + current, task_pid_nr(current), current->xid, + current->comm, task_thread_info(current)); #ifdef CONFIG_SMP printk(" CPU: %d", raw_smp_processor_id()); diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/kernel/signal_32.c linux-2.6.27.15-g-v/arch/powerpc/kernel/signal_32.c --- linux-2.6.27.15/arch/powerpc/kernel/signal_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/kernel/signal_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -857,7 +857,7 @@ int handle_rt_signal32(unsigned long sig /* Save user registers on the stack */ frame = &rt_sf->uc.uc_mcontext; addr = frame; - if (vdso32_rt_sigtramp && current->mm->context.vdso_base) { + if (vdso32_rt_sigtramp && current->mm->context.vdso_base != ~0UL) { if (save_user_regs(regs, frame, 0)) goto badframe; regs->link = current->mm->context.vdso_base + vdso32_rt_sigtramp; diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/kernel/signal_64.c linux-2.6.27.15-g-v/arch/powerpc/kernel/signal_64.c --- linux-2.6.27.15/arch/powerpc/kernel/signal_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/kernel/signal_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -434,7 +434,7 @@ int handle_rt_signal64(int signr, struct current->thread.fpscr.val = 0; /* Set up to return from userspace. */ - if (vdso64_rt_sigtramp && current->mm->context.vdso_base) { + if (vdso64_rt_sigtramp && current->mm->context.vdso_base != ~0UL) { regs->link = current->mm->context.vdso_base + vdso64_rt_sigtramp; } else { err |= setup_trampoline(__NR_rt_sigreturn, &frame->tramp[0]); diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/kernel/sys_ppc32.c linux-2.6.27.15-g-v/arch/powerpc/kernel/sys_ppc32.c --- linux-2.6.27.15/arch/powerpc/kernel/sys_ppc32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/kernel/sys_ppc32.c 2009-02-10 20:32:10.000000000 +0100 @@ -147,7 +147,7 @@ asmlinkage long compat_sys_gettimeofday( { if (tv) { struct timeval ktv; - do_gettimeofday(&ktv); + vx_gettimeofday(&ktv); if (put_tv32(tv, &ktv)) return -EFAULT; } diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/kernel/traps.c linux-2.6.27.15-g-v/arch/powerpc/kernel/traps.c --- linux-2.6.27.15/arch/powerpc/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/kernel/traps.c 2009-02-10 20:32:10.000000000 +0100 @@ -941,8 +941,9 @@ void nonrecoverable_exception(struct pt_ void trace_syscall(struct pt_regs *regs) { - printk("Task: %p(%d), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n", - current, task_pid_nr(current), regs->nip, regs->link, regs->gpr[0], + printk("Task: %p(%d[#%u]), PC: %08lX/%08lX, Syscall: %3ld, Result: %s%ld %s\n", + current, task_pid_nr(current), current->xid, + regs->nip, regs->link, regs->gpr[0], regs->ccr&0x10000000?"Error=":"", regs->gpr[3], print_tainted()); } diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/kernel/vdso.c linux-2.6.27.15-g-v/arch/powerpc/kernel/vdso.c --- linux-2.6.27.15/arch/powerpc/kernel/vdso.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/kernel/vdso.c 2009-02-10 20:32:10.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include @@ -212,7 +213,7 @@ int arch_setup_additional_pages(struct l vdso_base = VDSO32_MBASE; #endif - current->mm->context.vdso_base = 0; + current->mm->context.vdso_base = ~0UL; /* vDSO has a problem and was disabled, just don't "enable" it for the * process @@ -229,7 +230,7 @@ int arch_setup_additional_pages(struct l */ down_write(&mm->mmap_sem); vdso_base = get_unmapped_area(NULL, vdso_base, - vdso_pages << PAGE_SHIFT, 0, 0); + vdso_pages << PAGE_SHIFT, 0, MAP_PRIVATE | MAP_EXECUTABLE); if (IS_ERR_VALUE(vdso_base)) { rc = vdso_base; goto fail_mmapsem; diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/mm/fault.c linux-2.6.27.15-g-v/arch/powerpc/mm/fault.c --- linux-2.6.27.15/arch/powerpc/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/mm/fault.c 2009-02-10 20:32:10.000000000 +0100 @@ -29,6 +29,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -62,6 +66,363 @@ static inline int notify_page_fault(stru } #endif +#ifdef CONFIG_PAX_EMUSIGRT +void pax_syscall_close(struct vm_area_struct *vma) +{ + vma->vm_mm->call_syscall = 0UL; +} + +static int pax_syscall_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + unsigned int *kaddr; + + vmf->page = alloc_page(GFP_HIGHUSER); + if (!vmf->page) + return VM_FAULT_OOM; + + kaddr = kmap(vmf->page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x44000002U; /* sc */ + __flush_dcache_icache(kaddr); + kunmap(vmf->page); + return VM_FAULT_MAJOR; +} + +static struct vm_operations_struct pax_vm_ops = { + .close = pax_syscall_close, + .fault = pax_syscall_fault +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} +#endif + +#ifdef CONFIG_PAX_PAGEEXEC +/* + * PaX: decide what to do with offenders (regs->nip = fault address) + * + * returns 1 when task should be killed + * 2 when patched GOT trampoline was detected + * 3 when patched PLT trampoline was detected + * 4 when unpatched PLT trampoline was detected + * 5 when sigreturn trampoline was detected + * 6 when rt_sigreturn trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#if defined(CONFIG_PAX_EMUPLT) || defined(CONFIG_PAX_EMUSIGRT) + int err; +#endif + +#ifdef CONFIG_PAX_EMUPLT + do { /* PaX: patched GOT emulation */ + unsigned int blrl; + + err = get_user(blrl, (unsigned int *)regs->nip); + + if (!err && blrl == 0x4E800021U) { + unsigned long temp = regs->nip; + + regs->nip = regs->link & 0xFFFFFFFCUL; + regs->link = temp + 4UL; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #1 */ + unsigned int b; + + err = get_user(b, (unsigned int *)regs->nip); + + if (!err && (b & 0xFC000003U) == 0x48000000U) { + regs->nip += (((b | 0xFC000000UL) ^ 0x02000000UL) + 0x02000000UL); + return 3; + } + } while (0); + + do { /* PaX: unpatched PLT emulation #1 */ + unsigned int li, b; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(b, (unsigned int *)(regs->nip+4)); + + if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) { + unsigned int rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(rlwinm, (unsigned int *)addr); + err |= get_user(add, (unsigned int *)(addr+4)); + err |= get_user(li2, (unsigned int *)(addr+8)); + err |= get_user(addis2, (unsigned int *)(addr+12)); + err |= get_user(mtctr, (unsigned int *)(addr+16)); + err |= get_user(li3, (unsigned int *)(addr+20)); + err |= get_user(addis3, (unsigned int *)(addr+24)); + err |= get_user(bctr, (unsigned int *)(addr+28)); + + if (err) + break; + + if (rlwinm == 0x556C083CU && + add == 0x7D6C5A14U && + (li2 & 0xFFFF0000U) == 0x39800000U && + (addis2 & 0xFFFF0000U) == 0x3D8C0000U && + mtctr == 0x7D8903A6U && + (li3 & 0xFFFF0000U) == 0x39800000U && + (addis3 & 0xFFFF0000U) == 0x3D8C0000U && + bctr == 0x4E800420U) + { + regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16; + regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->ctr += (addis2 & 0xFFFFU) << 16; + regs->nip = regs->ctr; + return 4; + } + } + } while (0); + +#if 0 + do { /* PaX: unpatched PLT emulation #2 */ + unsigned int lis, lwzu, b, bctr; + + err = get_user(lis, (unsigned int *)regs->nip); + err |= get_user(lwzu, (unsigned int *)(regs->nip+4)); + err |= get_user(b, (unsigned int *)(regs->nip+8)); + err |= get_user(bctr, (unsigned int *)(regs->nip+12)); + + if (err) + break; + + if ((lis & 0xFFFF0000U) == 0x39600000U && + (lwzu & 0xU) == 0xU && + (b & 0xFC000003U) == 0x48000000U && + bctr == 0x4E800420U) + { + unsigned int addis, addi, rlwinm, add, li2, addis2, mtctr, li3, addis3, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 12 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(addis, (unsigned int *)addr); + err |= get_user(addi, (unsigned int *)(addr+4)); + err |= get_user(rlwinm, (unsigned int *)(addr+8)); + err |= get_user(add, (unsigned int *)(addr+12)); + err |= get_user(li2, (unsigned int *)(addr+16)); + err |= get_user(addis2, (unsigned int *)(addr+20)); + err |= get_user(mtctr, (unsigned int *)(addr+24)); + err |= get_user(li3, (unsigned int *)(addr+28)); + err |= get_user(addis3, (unsigned int *)(addr+32)); + err |= get_user(bctr, (unsigned int *)(addr+36)); + + if (err) + break; + + if ((addis & 0xFFFF0000U) == 0x3D6B0000U && + (addi & 0xFFFF0000U) == 0x396B0000U && + rlwinm == 0x556C083CU && + add == 0x7D6C5A14U && + (li2 & 0xFFFF0000U) == 0x39800000U && + (addis2 & 0xFFFF0000U) == 0x3D8C0000U && + mtctr == 0x7D8903A6U && + (li3 & 0xFFFF0000U) == 0x39800000U && + (addis3 & 0xFFFF0000U) == 0x3D8C0000U && + bctr == 0x4E800420U) + { + regs->gpr[PT_R11] = 3 * (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] = (((li3 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->gpr[PT_R12] += (addis3 & 0xFFFFU) << 16; + regs->ctr = (((li2 | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + regs->ctr += (addis2 & 0xFFFFU) << 16; + regs->nip = regs->ctr; + return 4; + } + } + } while (0); +#endif + + do { /* PaX: unpatched PLT emulation #3 */ + unsigned int li, b; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(b, (unsigned int *)(regs->nip+4)); + + if (!err && (li & 0xFFFF0000U) == 0x39600000U && (b & 0xFC000003U) == 0x48000000U) { + unsigned int addis, lwz, mtctr, bctr; + unsigned long addr = b | 0xFC000000UL; + + addr = regs->nip + 4 + ((addr ^ 0x02000000UL) + 0x02000000UL); + err = get_user(addis, (unsigned int *)addr); + err |= get_user(lwz, (unsigned int *)(addr+4)); + err |= get_user(mtctr, (unsigned int *)(addr+8)); + err |= get_user(bctr, (unsigned int *)(addr+12)); + + if (err) + break; + + if ((addis & 0xFFFF0000U) == 0x3D6B0000U && + (lwz & 0xFFFF0000U) == 0x816B0000U && + mtctr == 0x7D6903A6U && + bctr == 0x4E800420U) + { + unsigned int r11; + + addr = (addis << 16) + (((li | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + addr += (((lwz | 0xFFFF0000UL) ^ 0x00008000UL) + 0x00008000UL); + + err = get_user(r11, (unsigned int *)addr); + if (err) + break; + + regs->gpr[PT_R11] = r11; + regs->ctr = r11; + regs->nip = r11; + return 4; + } + } + } while (0); +#endif + +#ifdef CONFIG_PAX_EMUSIGRT + do { /* PaX: sigreturn emulation */ + unsigned int li, sc; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(sc, (unsigned int *)(regs->nip+4)); + + if (!err && li == 0x38000000U + __NR_sigreturn && sc == 0x44000002U) { + struct vm_area_struct *vma; + unsigned long call_syscall; + + down_read(¤t->mm->mmap_sem); + call_syscall = current->mm->call_syscall; + up_read(¤t->mm->mmap_sem); + if (likely(call_syscall)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_syscall) { + call_syscall = current->mm->call_syscall; + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_syscall & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_syscall)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_syscall = call_syscall; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->gpr[PT_R0] = __NR_sigreturn; + regs->nip = call_syscall; + return 5; + } + } while (0); + + do { /* PaX: rt_sigreturn emulation */ + unsigned int li, sc; + + err = get_user(li, (unsigned int *)regs->nip); + err |= get_user(sc, (unsigned int *)(regs->nip+4)); + + if (!err && li == 0x38000000U + __NR_rt_sigreturn && sc == 0x44000002U) { + struct vm_area_struct *vma; + unsigned int call_syscall; + + down_read(¤t->mm->mmap_sem); + call_syscall = current->mm->call_syscall; + up_read(¤t->mm->mmap_sem); + if (likely(call_syscall)) + goto rt_emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_syscall) { + call_syscall = current->mm->call_syscall; + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + goto rt_emulate; + } + + call_syscall = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_syscall & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_syscall)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_syscall = call_syscall; + up_write(¤t->mm->mmap_sem); + +rt_emulate: + regs->gpr[PT_R0] = __NR_rt_sigreturn; + regs->nip = call_syscall; + return 6; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + /* * Check whether the instruction at regs->nip is a store using * an update addressing form which will update r1. @@ -132,7 +493,7 @@ int __kprobes do_page_fault(struct pt_re * indicate errors in DSISR but can validly be set in SRR1. */ if (trap == 0x400) - error_code &= 0x48200000; + error_code &= 0x58200000; else is_write = error_code & DSISR_ISSTORE; #else @@ -331,6 +692,37 @@ bad_area: bad_area_nosemaphore: /* User mode accesses cause a SIGSEGV */ if (user_mode(regs)) { + +#ifdef CONFIG_PAX_PAGEEXEC + if (mm->pax_flags & MF_PAX_PAGEEXEC) { +#ifdef CONFIG_PPC64 + if (is_exec && (error_code & DSISR_PROTFAULT)) { +#else + if (is_exec && regs->nip == address) { +#endif + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + case 4: + return 0; +#endif + +#ifdef CONFIG_PAX_EMUSIGRT + case 5: + case 6: + return 0; +#endif + + } + + pax_report_fault(regs, (void *)regs->nip, (void *)regs->gpr[PT_R1]); + do_group_exit(SIGKILL); + } + } +#endif + _exception(SIGSEGV, regs, code, address); return 0; } @@ -354,7 +746,8 @@ out_of_memory: down_read(&mm->mmap_sem); goto survive; } - printk("VM: killing process %s\n", current->comm); + printk("VM: killing process %s(%d:#%u)\n", + current->comm, current->pid, current->xid); if (user_mode(regs)) do_group_exit(SIGKILL); return SIGKILL; diff -NurpP --minimal linux-2.6.27.15/arch/powerpc/mm/mmap.c linux-2.6.27.15-g-v/arch/powerpc/mm/mmap.c --- linux-2.6.27.15/arch/powerpc/mm/mmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/powerpc/mm/mmap.c 2009-02-10 20:32:10.000000000 +0100 @@ -75,10 +75,22 @@ void arch_pick_mmap_layout(struct mm_str */ if (mmap_is_legacy()) { mm->mmap_base = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; mm->unmap_area = arch_unmap_area; } else { mm->mmap_base = mmap_base(); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } diff -NurpP --minimal linux-2.6.27.15/arch/s390/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/s390/include/asm/kmap_types.h --- linux-2.6.27.15/arch/s390/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/s390/include/asm/kmap_types.h 2009-02-10 20:32:10.000000000 +0100 @@ -16,6 +16,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/arch/s390/Kconfig linux-2.6.27.15-g-v/arch/s390/Kconfig --- linux-2.6.27.15/arch/s390/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/s390/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -588,6 +588,8 @@ source "fs/Kconfig" source "arch/s390/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/s390/kernel/compat_linux.c linux-2.6.27.15-g-v/arch/s390/kernel/compat_linux.c --- linux-2.6.27.15/arch/s390/kernel/compat_linux.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/s390/kernel/compat_linux.c 2009-02-10 20:32:10.000000000 +0100 @@ -566,7 +566,7 @@ asmlinkage long sys32_gettimeofday(struc { if (tv) { struct timeval ktv; - do_gettimeofday(&ktv); + vx_gettimeofday(&ktv); if (put_tv32(tv, &ktv)) return -EFAULT; } diff -NurpP --minimal linux-2.6.27.15/arch/s390/kernel/module.c linux-2.6.27.15-g-v/arch/s390/kernel/module.c --- linux-2.6.27.15/arch/s390/kernel/module.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/s390/kernel/module.c 2009-02-10 20:32:10.000000000 +0100 @@ -166,11 +166,11 @@ module_frob_arch_sections(Elf_Ehdr *hdr, /* Increase core size by size of got & plt and set start offsets for got and plt. */ - me->core_size = ALIGN(me->core_size, 4); - me->arch.got_offset = me->core_size; - me->core_size += me->arch.got_size; - me->arch.plt_offset = me->core_size; - me->core_size += me->arch.plt_size; + me->core_size_rw = ALIGN(me->core_size_rw, 4); + me->arch.got_offset = me->core_size_rw; + me->core_size_rw += me->arch.got_size; + me->arch.plt_offset = me->core_size_rx; + me->core_size_rx += me->arch.plt_size; return 0; } @@ -256,7 +256,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base if (info->got_initialized == 0) { Elf_Addr *gotent; - gotent = me->module_core + me->arch.got_offset + + gotent = me->module_core_rw + me->arch.got_offset + info->got_offset; *gotent = val; info->got_initialized = 1; @@ -280,7 +280,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base else if (r_type == R_390_GOTENT || r_type == R_390_GOTPLTENT) *(unsigned int *) loc = - (val + (Elf_Addr) me->module_core - loc) >> 1; + (val + (Elf_Addr) me->module_core_rw - loc) >> 1; else if (r_type == R_390_GOT64 || r_type == R_390_GOTPLT64) *(unsigned long *) loc = val; @@ -294,7 +294,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base case R_390_PLTOFF64: /* 16 bit offset from GOT to PLT. */ if (info->plt_initialized == 0) { unsigned int *ip; - ip = me->module_core + me->arch.plt_offset + + ip = me->module_core_rx + me->arch.plt_offset + info->plt_offset; #ifndef CONFIG_64BIT ip[0] = 0x0d105810; /* basr 1,0; l 1,6(1); br 1 */ @@ -316,7 +316,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base val = me->arch.plt_offset - me->arch.got_offset + info->plt_offset + rela->r_addend; else - val = (Elf_Addr) me->module_core + + val = (Elf_Addr) me->module_core_rx + me->arch.plt_offset + info->plt_offset + rela->r_addend - loc; if (r_type == R_390_PLT16DBL) @@ -336,7 +336,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base case R_390_GOTOFF32: /* 32 bit offset to GOT. */ case R_390_GOTOFF64: /* 64 bit offset to GOT. */ val = val + rela->r_addend - - ((Elf_Addr) me->module_core + me->arch.got_offset); + ((Elf_Addr) me->module_core_rw + me->arch.got_offset); if (r_type == R_390_GOTOFF16) *(unsigned short *) loc = val; else if (r_type == R_390_GOTOFF32) @@ -346,7 +346,7 @@ apply_rela(Elf_Rela *rela, Elf_Addr base break; case R_390_GOTPC: /* 32 bit PC relative offset to GOT. */ case R_390_GOTPCDBL: /* 32 bit PC rel. off. to GOT shifted by 1. */ - val = (Elf_Addr) me->module_core + me->arch.got_offset + + val = (Elf_Addr) me->module_core_rw + me->arch.got_offset + rela->r_addend - loc; if (r_type == R_390_GOTPC) *(unsigned int *) loc = val; diff -NurpP --minimal linux-2.6.27.15/arch/s390/kernel/ptrace.c linux-2.6.27.15-g-v/arch/s390/kernel/ptrace.c --- linux-2.6.27.15/arch/s390/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/s390/kernel/ptrace.c 2009-02-10 20:32:10.000000000 +0100 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/arch/s390/kernel/syscalls.S linux-2.6.27.15-g-v/arch/s390/kernel/syscalls.S --- linux-2.6.27.15/arch/s390/kernel/syscalls.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/s390/kernel/syscalls.S 2009-02-10 20:32:10.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(sys_s390_fadvise64_64,sys_ni_syscall,sys32_fadvise64_64_wrapper) SYSCALL(sys_statfs64,sys_statfs64,compat_sys_statfs64_wrapper) SYSCALL(sys_fstatfs64,sys_fstatfs64,compat_sys_fstatfs64_wrapper) diff -NurpP --minimal linux-2.6.27.15/arch/s390/mm/fault.c linux-2.6.27.15-g-v/arch/s390/mm/fault.c --- linux-2.6.27.15/arch/s390/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/s390/mm/fault.c 2009-02-10 20:32:10.000000000 +0100 @@ -216,7 +216,8 @@ static int do_out_of_memory(struct pt_re down_read(&mm->mmap_sem); return 1; } - printk("VM: killing process %s\n", tsk->comm); + printk("VM: killing process %s(%d:#%u)\n", + tsk->comm, tsk->pid, tsk->xid); if (regs->psw.mask & PSW_MASK_PSTATE) do_group_exit(SIGKILL); do_no_context(regs, error_code, address); diff -NurpP --minimal linux-2.6.27.15/arch/sh/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/sh/include/asm/kmap_types.h --- linux-2.6.27.15/arch/sh/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sh/include/asm/kmap_types.h 2009-02-10 20:32:10.000000000 +0100 @@ -24,7 +24,8 @@ D(9) KM_IRQ0, D(10) KM_IRQ1, D(11) KM_SOFTIRQ0, D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR +D(13) KM_CLEARPAGE, +D(14) KM_TYPE_NR }; #undef D diff -NurpP --minimal linux-2.6.27.15/arch/sh/Kconfig linux-2.6.27.15-g-v/arch/sh/Kconfig --- linux-2.6.27.15/arch/sh/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sh/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -747,6 +747,8 @@ source "fs/Kconfig" source "arch/sh/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/sh/kernel/irq.c linux-2.6.27.15-g-v/arch/sh/kernel/irq.c --- linux-2.6.27.15/arch/sh/kernel/irq.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sh/kernel/irq.c 2009-02-10 20:32:10.000000000 +0100 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include #include diff -NurpP --minimal linux-2.6.27.15/arch/sh/kernel/vsyscall/vsyscall.c linux-2.6.27.15-g-v/arch/sh/kernel/vsyscall/vsyscall.c --- linux-2.6.27.15/arch/sh/kernel/vsyscall/vsyscall.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sh/kernel/vsyscall/vsyscall.c 2009-02-10 20:32:10.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include /* * Should the kernel map a VDSO page into processes and pass its diff -NurpP --minimal linux-2.6.27.15/arch/sparc/include/asm/elf_32.h linux-2.6.27.15-g-v/arch/sparc/include/asm/elf_32.h --- linux-2.6.27.15/arch/sparc/include/asm/elf_32.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/include/asm/elf_32.h 2009-02-10 20:32:10.000000000 +0100 @@ -119,6 +119,13 @@ typedef struct { #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE 0x10000UL + +#define PAX_DELTA_MMAP_LEN 16 +#define PAX_DELTA_STACK_LEN 16 +#endif + /* This yields a mask that user programs can use to figure out what instruction set this cpu supports. This can NOT be done in userspace on Sparc. */ diff -NurpP --minimal linux-2.6.27.15/arch/sparc/include/asm/elf_64.h linux-2.6.27.15-g-v/arch/sparc/include/asm/elf_64.h --- linux-2.6.27.15/arch/sparc/include/asm/elf_64.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/include/asm/elf_64.h 2009-02-10 20:32:10.000000000 +0100 @@ -163,6 +163,12 @@ typedef struct { #define ELF_ET_DYN_BASE 0x0000010000000000UL #define COMPAT_ELF_ET_DYN_BASE 0x0000000070000000UL +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (test_thread_flag(TIF_32BIT) ? 0x10000UL : 0x100000UL) + +#define PAX_DELTA_MMAP_LEN (test_thread_flag(TIF_32BIT) ? 14 : 28 ) +#define PAX_DELTA_STACK_LEN (test_thread_flag(TIF_32BIT) ? 15 : 29 ) +#endif /* This yields a mask that user programs can use to figure out what instruction set this cpu supports. */ diff -NurpP --minimal linux-2.6.27.15/arch/sparc/include/asm/kmap_types.h linux-2.6.27.15-g-v/arch/sparc/include/asm/kmap_types.h --- linux-2.6.27.15/arch/sparc/include/asm/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/include/asm/kmap_types.h 2009-02-10 20:32:10.000000000 +0100 @@ -19,6 +19,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/arch/sparc/include/asm/pgtable_32.h linux-2.6.27.15-g-v/arch/sparc/include/asm/pgtable_32.h --- linux-2.6.27.15/arch/sparc/include/asm/pgtable_32.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/include/asm/pgtable_32.h 2009-02-10 20:32:10.000000000 +0100 @@ -47,6 +47,13 @@ BTFIXUPDEF_SIMM13(user_ptrs_per_pgd) BTFIXUPDEF_INT(page_none) BTFIXUPDEF_INT(page_copy) BTFIXUPDEF_INT(page_readonly) + +#ifdef CONFIG_PAX_PAGEEXEC +BTFIXUPDEF_INT(page_shared_noexec) +BTFIXUPDEF_INT(page_copy_noexec) +BTFIXUPDEF_INT(page_readonly_noexec) +#endif + BTFIXUPDEF_INT(page_kernel) #define PMD_SHIFT SUN4C_PMD_SHIFT @@ -68,6 +75,16 @@ extern pgprot_t PAGE_SHARED; #define PAGE_COPY __pgprot(BTFIXUP_INT(page_copy)) #define PAGE_READONLY __pgprot(BTFIXUP_INT(page_readonly)) +#ifdef CONFIG_PAX_PAGEEXEC +extern pgprot_t PAGE_SHARED_NOEXEC; +# define PAGE_COPY_NOEXEC __pgprot(BTFIXUP_INT(page_copy_noexec)) +# define PAGE_READONLY_NOEXEC __pgprot(BTFIXUP_INT(page_readonly_noexec)) +#else +# define PAGE_SHARED_NOEXEC PAGE_SHARED +# define PAGE_COPY_NOEXEC PAGE_COPY +# define PAGE_READONLY_NOEXEC PAGE_READONLY +#endif + extern unsigned long page_kernel; #ifdef MODULE diff -NurpP --minimal linux-2.6.27.15/arch/sparc/include/asm/pgtsrmmu.h linux-2.6.27.15-g-v/arch/sparc/include/asm/pgtsrmmu.h --- linux-2.6.27.15/arch/sparc/include/asm/pgtsrmmu.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/include/asm/pgtsrmmu.h 2009-02-10 20:32:10.000000000 +0100 @@ -115,6 +115,13 @@ SRMMU_EXEC | SRMMU_REF) #define SRMMU_PAGE_RDONLY __pgprot(SRMMU_VALID | SRMMU_CACHE | \ SRMMU_EXEC | SRMMU_REF) + +#ifdef CONFIG_PAX_PAGEEXEC +#define SRMMU_PAGE_SHARED_NOEXEC __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_WRITE | SRMMU_REF) +#define SRMMU_PAGE_COPY_NOEXEC __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_REF) +#define SRMMU_PAGE_RDONLY_NOEXEC __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_REF) +#endif + #define SRMMU_PAGE_KERNEL __pgprot(SRMMU_VALID | SRMMU_CACHE | SRMMU_PRIV | \ SRMMU_DIRTY | SRMMU_REF) diff -NurpP --minimal linux-2.6.27.15/arch/sparc/Kconfig linux-2.6.27.15-g-v/arch/sparc/Kconfig --- linux-2.6.27.15/arch/sparc/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -305,6 +305,8 @@ source "fs/Kconfig" source "arch/sparc/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/sparc/kernel/ptrace.c linux-2.6.27.15-g-v/arch/sparc/kernel/ptrace.c --- linux-2.6.27.15/arch/sparc/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/kernel/ptrace.c 2009-02-10 20:32:10.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/arch/sparc/kernel/sys_sparc.c linux-2.6.27.15-g-v/arch/sparc/kernel/sys_sparc.c --- linux-2.6.27.15/arch/sparc/kernel/sys_sparc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/kernel/sys_sparc.c 2009-02-10 20:32:10.000000000 +0100 @@ -56,7 +56,7 @@ unsigned long arch_get_unmapped_area(str if (ARCH_SUN4C_SUN4 && len > 0x20000000) return -ENOMEM; if (!addr) - addr = TASK_UNMAPPED_BASE; + addr = current->mm->mmap_base; if (flags & MAP_SHARED) addr = COLOUR_ALIGN(addr); diff -NurpP --minimal linux-2.6.27.15/arch/sparc/kernel/systbls.S linux-2.6.27.15-g-v/arch/sparc/kernel/systbls.S --- linux-2.6.27.15/arch/sparc/kernel/systbls.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/kernel/systbls.S 2009-02-10 20:32:10.000000000 +0100 @@ -70,7 +70,7 @@ sys_call_table: /*250*/ .long sparc_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl /*255*/ .long sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .long sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun -/*265*/ .long sys_timer_delete, sys_timer_create, sys_nis_syscall, sys_io_setup, sys_io_destroy +/*265*/ .long sys_timer_delete, sys_timer_create, sys_vserver, sys_io_setup, sys_io_destroy /*270*/ .long sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink /*275*/ .long sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .long sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat diff -NurpP --minimal linux-2.6.27.15/arch/sparc/kernel/traps.c linux-2.6.27.15-g-v/arch/sparc/kernel/traps.c --- linux-2.6.27.15/arch/sparc/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/kernel/traps.c 2009-02-10 20:32:10.000000000 +0100 @@ -95,7 +95,8 @@ void die_if_kernel(char *str, struct pt_ " /_| \\__/ |_\\\n" " \\__U_/\n"); - printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter); + printk("%s(%d[#%u]): %s [#%d]\n", current->comm, + task_pid_nr(current), current->xid, str, ++die_counter); show_regs(regs); add_taint(TAINT_DIE); diff -NurpP --minimal linux-2.6.27.15/arch/sparc/Makefile linux-2.6.27.15-g-v/arch/sparc/Makefile --- linux-2.6.27.15/arch/sparc/Makefile 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/Makefile 2009-02-10 20:32:10.000000000 +0100 @@ -37,7 +37,7 @@ drivers-$(CONFIG_OPROFILE) += arch/sparc # Renaming is done to avoid confusing pattern matching rules in 2.5.45 (multy-) INIT_Y := $(patsubst %/, %/built-in.o, $(init-y)) CORE_Y := $(core-y) -CORE_Y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ +CORE_Y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ grsecurity/ CORE_Y := $(patsubst %/, %/built-in.o, $(CORE_Y)) DRIVERS_Y := $(patsubst %/, %/built-in.o, $(drivers-y)) NET_Y := $(patsubst %/, %/built-in.o, $(net-y)) diff -NurpP --minimal linux-2.6.27.15/arch/sparc/mm/fault.c linux-2.6.27.15-g-v/arch/sparc/mm/fault.c --- linux-2.6.27.15/arch/sparc/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/mm/fault.c 2009-02-10 20:32:10.000000000 +0100 @@ -21,6 +21,9 @@ #include #include #include +#include +#include +#include #include #include @@ -167,6 +170,249 @@ 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 int pax_emuplt_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + unsigned int *kaddr; + + vmf->page = alloc_page(GFP_HIGHUSER); + if (!vmf->page) + return VM_FAULT_OOM; + + kaddr = kmap(vmf->page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x9DE3BFA8U; /* save */ + flush_dcache_page(vmf->page); + kunmap(vmf->page); + return VM_FAULT_MAJOR; +} + +static struct vm_operations_struct pax_vm_ops = { + .close = pax_emuplt_close, + .fault = pax_emuplt_fault +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} + +/* + * PaX: decide what to do with offenders (regs->pc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: patched PLT emulation #1 */ + unsigned int sethi1, sethi2, jmpl; + + err = get_user(sethi1, (unsigned int *)regs->pc); + err |= get_user(sethi2, (unsigned int *)(regs->pc+4)); + err |= get_user(jmpl, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U) + { + unsigned int addr; + + regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10; + addr = regs->u_regs[UREG_G1]; + addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + { /* PaX: patched PLT emulation #2 */ + unsigned int ba; + + err = get_user(ba, (unsigned int *)regs->pc); + + if (!err && (ba & 0xFFC00000U) == 0x30800000U) { + unsigned int addr; + + addr = regs->pc + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } + + do { /* PaX: patched PLT emulation #3 */ + unsigned int sethi, jmpl, nop; + + err = get_user(sethi, (unsigned int *)regs->pc); + err |= get_user(jmpl, (unsigned int *)(regs->pc+4)); + err |= get_user(nop, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U && + nop == 0x01000000U) + { + unsigned int addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr += (((jmpl | 0xFFFFE000U) ^ 0x00001000U) + 0x00001000U); + regs->pc = addr; + regs->npc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 1 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->pc); + err |= get_user(ba, (unsigned int *)(regs->pc+4)); + err |= get_user(nop, (unsigned int *)(regs->pc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) && + nop == 0x01000000U) + { + unsigned int addr, save, call; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->pc + 4 + ((((ba | 0xFFC00000U) ^ 0x00200000U) + 0x00200000U) << 2); + else + addr = regs->pc + 4 + ((((ba | 0xFFF80000U) ^ 0x00040000U) + 0x00040000U) << 2); + + err = get_user(save, (unsigned int *)addr); + err |= get_user(call, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + struct vm_area_struct *vma; + unsigned long call_dl_resolve; + + down_read(¤t->mm->mmap_sem); + call_dl_resolve = current->mm->call_dl_resolve; + up_read(¤t->mm->mmap_sem); + if (likely(call_dl_resolve)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_dl_resolve) { + call_dl_resolve = current->mm->call_dl_resolve; + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_dl_resolve & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_dl_resolve)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_dl_resolve = call_dl_resolve; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->pc = call_dl_resolve; + regs->npc = addr+4; + return 3; + } + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 2 */ + unsigned int save, call, nop; + + err = get_user(save, (unsigned int *)(regs->pc-4)); + err |= get_user(call, (unsigned int *)regs->pc); + err |= get_user(nop, (unsigned int *)(regs->pc+4)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + unsigned int dl_resolve = regs->pc + ((((call | 0xC0000000U) ^ 0x20000000U) + 0x20000000U) << 2); + + regs->u_regs[UREG_RETPC] = regs->pc; + regs->pc = dl_resolve; + regs->npc = dl_resolve+4; + return 3; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + asmlinkage void do_sparc_fault(struct pt_regs *regs, int text_fault, int write, unsigned long address) { @@ -231,6 +477,24 @@ good_area: if(!(vma->vm_flags & VM_WRITE)) goto bad_area; } else { + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && text_fault && !(vma->vm_flags & VM_EXEC)) { + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void *)regs->pc, (void *)regs->u_regs[UREG_FP]); + do_group_exit(SIGKILL); + } +#endif + /* Allow reads even for write-only mappings */ if(!(vma->vm_flags & (VM_READ | VM_EXEC))) goto bad_area; @@ -318,7 +582,8 @@ no_context: */ out_of_memory: up_read(&mm->mmap_sem); - printk("VM: killing process %s\n", tsk->comm); + printk("VM: killing process %s(%d:#%u)\n", + tsk->comm, tsk->pid, tsk->xid); if (from_user) do_group_exit(SIGKILL); goto no_context; diff -NurpP --minimal linux-2.6.27.15/arch/sparc/mm/init.c linux-2.6.27.15-g-v/arch/sparc/mm/init.c --- linux-2.6.27.15/arch/sparc/mm/init.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/mm/init.c 2009-02-10 20:32:10.000000000 +0100 @@ -312,6 +312,9 @@ extern void device_scan(void); pgprot_t PAGE_SHARED __read_mostly; EXPORT_SYMBOL(PAGE_SHARED); +pgprot_t PAGE_SHARED_NOEXEC __read_mostly; +EXPORT_SYMBOL(PAGE_SHARED_NOEXEC); + void __init paging_init(void) { switch(sparc_cpu_model) { @@ -337,17 +340,17 @@ void __init paging_init(void) /* Initialize the protection map with non-constant, MMU dependent values. */ protection_map[0] = PAGE_NONE; - protection_map[1] = PAGE_READONLY; - protection_map[2] = PAGE_COPY; - protection_map[3] = PAGE_COPY; + protection_map[1] = PAGE_READONLY_NOEXEC; + protection_map[2] = PAGE_COPY_NOEXEC; + protection_map[3] = PAGE_COPY_NOEXEC; protection_map[4] = PAGE_READONLY; protection_map[5] = PAGE_READONLY; protection_map[6] = PAGE_COPY; protection_map[7] = PAGE_COPY; protection_map[8] = PAGE_NONE; - protection_map[9] = PAGE_READONLY; - protection_map[10] = PAGE_SHARED; - protection_map[11] = PAGE_SHARED; + protection_map[9] = PAGE_READONLY_NOEXEC; + protection_map[10] = PAGE_SHARED_NOEXEC; + protection_map[11] = PAGE_SHARED_NOEXEC; protection_map[12] = PAGE_READONLY; protection_map[13] = PAGE_READONLY; protection_map[14] = PAGE_SHARED; diff -NurpP --minimal linux-2.6.27.15/arch/sparc/mm/srmmu.c linux-2.6.27.15-g-v/arch/sparc/mm/srmmu.c --- linux-2.6.27.15/arch/sparc/mm/srmmu.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc/mm/srmmu.c 2009-02-10 20:32:10.000000000 +0100 @@ -2163,6 +2163,13 @@ void __init ld_mmu_srmmu(void) PAGE_SHARED = pgprot_val(SRMMU_PAGE_SHARED); BTFIXUPSET_INT(page_copy, pgprot_val(SRMMU_PAGE_COPY)); BTFIXUPSET_INT(page_readonly, pgprot_val(SRMMU_PAGE_RDONLY)); + +#ifdef CONFIG_PAX_PAGEEXEC + PAGE_SHARED_NOEXEC = pgprot_val(SRMMU_PAGE_SHARED_NOEXEC); + BTFIXUPSET_INT(page_copy_noexec, pgprot_val(SRMMU_PAGE_COPY_NOEXEC)); + BTFIXUPSET_INT(page_readonly_noexec, pgprot_val(SRMMU_PAGE_RDONLY_NOEXEC)); +#endif + BTFIXUPSET_INT(page_kernel, pgprot_val(SRMMU_PAGE_KERNEL)); page_kernel = pgprot_val(SRMMU_PAGE_KERNEL); diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/Kconfig linux-2.6.27.15-g-v/arch/sparc64/Kconfig --- linux-2.6.27.15/arch/sparc64/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -403,6 +403,8 @@ source "fs/Kconfig" source "arch/sparc64/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/kernel/Makefile linux-2.6.27.15-g-v/arch/sparc64/kernel/Makefile --- linux-2.6.27.15/arch/sparc64/kernel/Makefile 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/kernel/Makefile 2009-02-10 20:32:10.000000000 +0100 @@ -3,7 +3,7 @@ # EXTRA_AFLAGS := -ansi -EXTRA_CFLAGS := -Werror +#EXTRA_CFLAGS := -Werror extra-y := head.o init_task.o vmlinux.lds diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/kernel/ptrace.c linux-2.6.27.15-g-v/arch/sparc64/kernel/ptrace.c --- linux-2.6.27.15/arch/sparc64/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/kernel/ptrace.c 2009-02-10 20:32:10.000000000 +0100 @@ -26,6 +26,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/kernel/sys_sparc32.c linux-2.6.27.15-g-v/arch/sparc64/kernel/sys_sparc32.c --- linux-2.6.27.15/arch/sparc64/kernel/sys_sparc32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/kernel/sys_sparc32.c 2009-02-10 20:32:10.000000000 +0100 @@ -532,7 +532,7 @@ asmlinkage long sys32_gettimeofday(struc { if (tv) { struct timeval ktv; - do_gettimeofday(&ktv); + vx_gettimeofday(&ktv); if (put_tv32(tv, &ktv)) return -EFAULT; } diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/kernel/sys_sparc.c linux-2.6.27.15-g-v/arch/sparc64/kernel/sys_sparc.c --- linux-2.6.27.15/arch/sparc64/kernel/sys_sparc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/kernel/sys_sparc.c 2009-02-10 20:32:10.000000000 +0100 @@ -124,7 +124,7 @@ unsigned long arch_get_unmapped_area(str /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if ((filp || (flags & MAP_SHARED)) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -139,6 +139,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); @@ -152,9 +156,9 @@ unsigned long arch_get_unmapped_area(str } if (len > mm->cached_hole_size) { - start_addr = addr = mm->free_area_cache; + start_addr = addr = mm->free_area_cache; } else { - start_addr = addr = TASK_UNMAPPED_BASE; + start_addr = addr = mm->mmap_base; mm->cached_hole_size = 0; } @@ -174,8 +178,8 @@ full_search: vma = find_vma(mm, VA_EXCLUDE_END); } if (unlikely(task_size < addr)) { - if (start_addr != TASK_UNMAPPED_BASE) { - start_addr = addr = TASK_UNMAPPED_BASE; + if (start_addr != mm->mmap_base) { + start_addr = addr = mm->mmap_base; mm->cached_hole_size = 0; goto full_search; } @@ -215,7 +219,7 @@ arch_get_unmapped_area_topdown(struct fi /* We do not accept a shared mapping if it would violate * cache aliasing constraints. */ - if ((flags & MAP_SHARED) && + if ((filp || (flags & MAP_SHARED)) && ((addr - (pgoff << PAGE_SHIFT)) & (SHMLBA - 1))) return -EINVAL; return addr; @@ -378,6 +382,12 @@ void arch_pick_mmap_layout(struct mm_str current->signal->rlim[RLIMIT_STACK].rlim_cur == RLIM_INFINITY || sysctl_legacy_va_layout) { mm->mmap_base = TASK_UNMAPPED_BASE + random_factor; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base += mm->delta_mmap; +#endif + mm->get_unmapped_area = arch_get_unmapped_area; mm->unmap_area = arch_unmap_area; } else { @@ -392,6 +402,12 @@ void arch_pick_mmap_layout(struct mm_str gap = (task_size / 6 * 5); mm->mmap_base = PAGE_ALIGN(task_size - gap - random_factor); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/kernel/systbls.S linux-2.6.27.15-g-v/arch/sparc64/kernel/systbls.S --- linux-2.6.27.15/arch/sparc64/kernel/systbls.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/kernel/systbls.S 2009-02-10 20:32:10.000000000 +0100 @@ -71,7 +71,7 @@ sys_call_table32: /*250*/ .word sys32_mremap, sys32_sysctl, sys32_getsid, sys_fdatasync, sys32_nfsservctl .word sys32_sync_file_range, compat_sys_clock_settime, compat_sys_clock_gettime, compat_sys_clock_getres, sys32_clock_nanosleep /*260*/ .word compat_sys_sched_getaffinity, compat_sys_sched_setaffinity, sys32_timer_settime, compat_sys_timer_gettime, sys_timer_getoverrun - .word sys_timer_delete, compat_sys_timer_create, sys_ni_syscall, compat_sys_io_setup, sys_io_destroy + .word sys_timer_delete, compat_sys_timer_create, sys32_vserver, compat_sys_io_setup, sys_io_destroy /*270*/ .word sys32_io_submit, sys_io_cancel, compat_sys_io_getevents, sys32_mq_open, sys_mq_unlink .word compat_sys_mq_timedsend, compat_sys_mq_timedreceive, compat_sys_mq_notify, compat_sys_mq_getsetattr, compat_sys_waitid /*280*/ .word sys32_tee, sys_add_key, sys_request_key, sys_keyctl, compat_sys_openat @@ -145,7 +145,7 @@ sys_call_table: /*250*/ .word sys64_mremap, sys_sysctl, sys_getsid, sys_fdatasync, sys_nfsservctl .word sys_sync_file_range, sys_clock_settime, sys_clock_gettime, sys_clock_getres, sys_clock_nanosleep /*260*/ .word sys_sched_getaffinity, sys_sched_setaffinity, sys_timer_settime, sys_timer_gettime, sys_timer_getoverrun - .word sys_timer_delete, sys_timer_create, sys_ni_syscall, sys_io_setup, sys_io_destroy + .word sys_timer_delete, sys_timer_create, sys_vserver, sys_io_setup, sys_io_destroy /*270*/ .word sys_io_submit, sys_io_cancel, sys_io_getevents, sys_mq_open, sys_mq_unlink .word sys_mq_timedsend, sys_mq_timedreceive, sys_mq_notify, sys_mq_getsetattr, sys_waitid /*280*/ .word sys_tee, sys_add_key, sys_request_key, sys_keyctl, sys_openat diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/kernel/traps.c linux-2.6.27.15-g-v/arch/sparc64/kernel/traps.c --- linux-2.6.27.15/arch/sparc64/kernel/traps.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/kernel/traps.c 2009-02-10 20:32:10.000000000 +0100 @@ -2186,7 +2186,8 @@ void die_if_kernel(char *str, struct pt_ " /_| \\__/ |_\\\n" " \\__U_/\n"); - printk("%s(%d): %s [#%d]\n", current->comm, task_pid_nr(current), str, ++die_counter); + printk("%s(%d[#%u]): %s [#%d]\n", current->comm, + task_pid_nr(current), current->xid, str, ++die_counter); notify_die(DIE_OOPS, str, regs, 0, 255, SIGSEGV); __asm__ __volatile__("flushw"); show_regs(regs); diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/mm/fault.c linux-2.6.27.15-g-v/arch/sparc64/mm/fault.c --- linux-2.6.27.15/arch/sparc64/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/mm/fault.c 2009-02-10 20:32:10.000000000 +0100 @@ -19,6 +19,9 @@ #include #include #include +#include +#include +#include #include #include @@ -261,6 +264,367 @@ 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 int pax_emuplt_fault(struct vm_area_struct *vma, struct vm_fault *vmf) +{ + unsigned int *kaddr; + + vmf->page = alloc_page(GFP_HIGHUSER); + if (!vmf->page) + return VM_FAULT_OOM; + + kaddr = kmap(vmf->page); + memset(kaddr, 0, PAGE_SIZE); + kaddr[0] = 0x9DE3BFA8U; /* save */ + flush_dcache_page(vmf->page); + kunmap(vmf->page); + return VM_FAULT_MAJOR; +} + +static struct vm_operations_struct pax_vm_ops = { + .close = pax_emuplt_close, + .fault = pax_emuplt_fault +}; + +static int pax_insert_vma(struct vm_area_struct *vma, unsigned long addr) +{ + int ret; + + vma->vm_mm = current->mm; + vma->vm_start = addr; + vma->vm_end = addr + PAGE_SIZE; + vma->vm_flags = VM_READ | VM_EXEC | VM_MAYREAD | VM_MAYEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + vma->vm_ops = &pax_vm_ops; + + ret = insert_vm_struct(current->mm, vma); + if (ret) + return ret; + + ++current->mm->total_vm; + return 0; +} +#endif + +/* + * PaX: decide what to do with offenders (regs->tpc = fault address) + * + * returns 1 when task should be killed + * 2 when patched PLT trampoline was detected + * 3 when unpatched PLT trampoline was detected + */ +static int pax_handle_fetch_fault(struct pt_regs *regs) +{ + +#ifdef CONFIG_PAX_EMUPLT + int err; + + do { /* PaX: patched PLT emulation #1 */ + unsigned int sethi1, sethi2, jmpl; + + err = get_user(sethi1, (unsigned int *)regs->tpc); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+4)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = (sethi2 & 0x003FFFFFU) << 10; + addr = regs->u_regs[UREG_G1]; + addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + { /* PaX: patched PLT emulation #2 */ + unsigned int ba; + + err = get_user(ba, (unsigned int *)regs->tpc); + + if (!err && (ba & 0xFFC00000U) == 0x30800000U) { + unsigned long addr; + + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } + + do { /* PaX: patched PLT emulation #3 */ + unsigned int sethi, jmpl, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (jmpl & 0xFFFFE000U) == 0x81C06000U && + nop == 0x01000000U) + { + unsigned long addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr += (((jmpl | 0xFFFFFFFFFFFFE000UL) ^ 0x00001000UL) + 0x00001000UL); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #4 */ + unsigned int mov1, call, mov2; + + err = get_user(mov1, (unsigned int *)regs->tpc); + err |= get_user(call, (unsigned int *)(regs->tpc+4)); + err |= get_user(mov2, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if (mov1 == 0x8210000FU && + (call & 0xC0000000U) == 0x40000000U && + mov2 == 0x9E100001U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = regs->u_regs[UREG_RETPC]; + addr = regs->tpc + 4 + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #5 */ + unsigned int sethi1, sethi2, or1, or2, sllx, jmpl, nop; + + err = get_user(sethi1, (unsigned int *)regs->tpc); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+4)); + err |= get_user(or1, (unsigned int *)(regs->tpc+8)); + err |= get_user(or2, (unsigned int *)(regs->tpc+12)); + err |= get_user(sllx, (unsigned int *)(regs->tpc+16)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+20)); + err |= get_user(nop, (unsigned int *)(regs->tpc+24)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + (or1 & 0xFFFFE000U) == 0x82106000U && + (or2 & 0xFFFFE000U) == 0x8A116000U && + sllx == 0x83287020 && + jmpl == 0x81C04005U && + nop == 0x01000000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = ((sethi1 & 0x003FFFFFU) << 10) | (or1 & 0x000003FFU); + regs->u_regs[UREG_G1] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or2 & 0x000003FFU); + addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #6 */ + unsigned int sethi1, sethi2, sllx, or, jmpl, nop; + + err = get_user(sethi1, (unsigned int *)regs->tpc); + err |= get_user(sethi2, (unsigned int *)(regs->tpc+4)); + err |= get_user(sllx, (unsigned int *)(regs->tpc+8)); + err |= get_user(or, (unsigned int *)(regs->tpc+12)); + err |= get_user(jmpl, (unsigned int *)(regs->tpc+16)); + err |= get_user(nop, (unsigned int *)(regs->tpc+20)); + + if (err) + break; + + if ((sethi1 & 0xFFC00000U) == 0x03000000U && + (sethi2 & 0xFFC00000U) == 0x0B000000U && + sllx == 0x83287020 && + (or & 0xFFFFE000U) == 0x8A116000U && + jmpl == 0x81C04005U && + nop == 0x01000000U) + { + unsigned long addr; + + regs->u_regs[UREG_G1] = (sethi1 & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] <<= 32; + regs->u_regs[UREG_G5] = ((sethi2 & 0x003FFFFFU) << 10) | (or & 0x3FFU); + addr = regs->u_regs[UREG_G1] + regs->u_regs[UREG_G5]; + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: patched PLT emulation #7 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(ba, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + (ba & 0xFFF00000U) == 0x30600000U && + nop == 0x01000000U) + { + unsigned long addr; + + addr = (sethi & 0x003FFFFFU) << 10; + regs->u_regs[UREG_G1] = addr; + addr = regs->tpc + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + regs->tpc = addr; + regs->tnpc = addr+4; + return 2; + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 1 */ + unsigned int sethi, ba, nop; + + err = get_user(sethi, (unsigned int *)regs->tpc); + err |= get_user(ba, (unsigned int *)(regs->tpc+4)); + err |= get_user(nop, (unsigned int *)(regs->tpc+8)); + + if (err) + break; + + if ((sethi & 0xFFC00000U) == 0x03000000U && + ((ba & 0xFFC00000U) == 0x30800000U || (ba & 0xFFF80000U) == 0x30680000U) && + nop == 0x01000000U) + { + unsigned long addr; + unsigned int save, call; + + if ((ba & 0xFFC00000U) == 0x30800000U) + addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFC00000UL) ^ 0x00200000UL) + 0x00200000UL) << 2); + else + addr = regs->tpc + 4 + ((((ba | 0xFFFFFFFFFFF80000UL) ^ 0x00040000UL) + 0x00040000UL) << 2); + + err = get_user(save, (unsigned int *)addr); + err |= get_user(call, (unsigned int *)(addr+4)); + err |= get_user(nop, (unsigned int *)(addr+8)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + struct vm_area_struct *vma; + unsigned long call_dl_resolve; + + down_read(¤t->mm->mmap_sem); + call_dl_resolve = current->mm->call_dl_resolve; + up_read(¤t->mm->mmap_sem); + if (likely(call_dl_resolve)) + goto emulate; + + vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + + down_write(¤t->mm->mmap_sem); + if (current->mm->call_dl_resolve) { + call_dl_resolve = current->mm->call_dl_resolve; + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + goto emulate; + } + + call_dl_resolve = get_unmapped_area(NULL, 0UL, PAGE_SIZE, 0UL, MAP_PRIVATE); + if (!vma || (call_dl_resolve & ~PAGE_MASK)) { + up_write(¤t->mm->mmap_sem); + if (vma) + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + if (pax_insert_vma(vma, call_dl_resolve)) { + up_write(¤t->mm->mmap_sem); + kmem_cache_free(vm_area_cachep, vma); + return 1; + } + + current->mm->call_dl_resolve = call_dl_resolve; + up_write(¤t->mm->mmap_sem); + +emulate: + regs->u_regs[UREG_G1] = (sethi & 0x003FFFFFU) << 10; + regs->tpc = call_dl_resolve; + regs->tnpc = addr+4; + return 3; + } + } + } while (0); + + do { /* PaX: unpatched PLT emulation step 2 */ + unsigned int save, call, nop; + + err = get_user(save, (unsigned int *)(regs->tpc-4)); + err |= get_user(call, (unsigned int *)regs->tpc); + err |= get_user(nop, (unsigned int *)(regs->tpc+4)); + if (err) + break; + + if (save == 0x9DE3BFA8U && + (call & 0xC0000000U) == 0x40000000U && + nop == 0x01000000U) + { + unsigned long dl_resolve = regs->tpc + ((((call | 0xFFFFFFFFC0000000UL) ^ 0x20000000UL) + 0x20000000UL) << 2); + + regs->u_regs[UREG_RETPC] = regs->tpc; + regs->tpc = dl_resolve; + regs->tnpc = dl_resolve+4; + return 3; + } + } while (0); +#endif + + return 1; +} + +void pax_report_insns(void *pc, void *sp) +{ + unsigned long i; + + printk(KERN_ERR "PAX: bytes at PC: "); + for (i = 0; i < 5; i++) { + unsigned int c; + if (get_user(c, (unsigned int *)pc+i)) + printk(KERN_CONT "???????? "); + else + printk(KERN_CONT "%08x ", c); + } + printk("\n"); +} +#endif + asmlinkage void __kprobes do_sparc64_fault(struct pt_regs *regs) { struct mm_struct *mm = current->mm; @@ -302,8 +666,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; } @@ -320,6 +686,29 @@ asmlinkage void __kprobes do_sparc64_fau if (!vma) goto bad_area; +#ifdef CONFIG_PAX_PAGEEXEC + /* PaX: detect ITLB misses on non-exec pages */ + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && vma->vm_start <= address && + !(vma->vm_flags & VM_EXEC) && (fault_code & FAULT_CODE_ITLB)) + { + if (address != regs->tpc) + goto good_area; + + up_read(&mm->mmap_sem); + switch (pax_handle_fetch_fault(regs)) { + +#ifdef CONFIG_PAX_EMUPLT + case 2: + case 3: + return; +#endif + + } + pax_report_fault(regs, (void *)regs->tpc, (void *)(regs->u_regs[UREG_FP] + STACK_BIAS)); + do_group_exit(SIGKILL); + } +#endif + /* Pure DTLB misses do not tell us whether the fault causing * load/store/atomic was a write or not, it only says that there * was no match. So in such a case we (carefully) read the @@ -452,7 +841,8 @@ handle_kernel_fault: out_of_memory: insn = get_fault_insn(regs, insn); up_read(&mm->mmap_sem); - printk("VM: killing process %s\n", current->comm); + printk("VM: killing process %s(%d:#%u)\n", + current->comm, current->pid, current->xid); if (!(regs->tstate & TSTATE_PRIV)) do_group_exit(SIGKILL); goto handle_kernel_fault; diff -NurpP --minimal linux-2.6.27.15/arch/sparc64/mm/Makefile linux-2.6.27.15-g-v/arch/sparc64/mm/Makefile --- linux-2.6.27.15/arch/sparc64/mm/Makefile 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/sparc64/mm/Makefile 2009-02-10 20:32:10.000000000 +0100 @@ -2,7 +2,7 @@ # EXTRA_AFLAGS := -ansi -EXTRA_CFLAGS := -Werror +#EXTRA_CFLAGS := -Werror obj-y := ultra.o tlb.o tsb.o fault.o init.o generic.o diff -NurpP --minimal linux-2.6.27.15/arch/um/Kconfig linux-2.6.27.15-g-v/arch/um/Kconfig --- linux-2.6.27.15/arch/um/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/um/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -245,6 +245,8 @@ source "drivers/connector/Kconfig" source "fs/Kconfig" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/um/kernel/trap.c linux-2.6.27.15-g-v/arch/um/kernel/trap.c --- linux-2.6.27.15/arch/um/kernel/trap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/um/kernel/trap.c 2009-02-10 20:32:10.000000000 +0100 @@ -215,7 +215,8 @@ unsigned long segv(struct faultinfo fi, current->thread.arch.faultinfo = fi; force_sig_info(SIGBUS, &si, current); } else if (err == -ENOMEM) { - printk(KERN_INFO "VM: killing process %s\n", current->comm); + printk(KERN_INFO "VM: killing process %s(%d:#%u)\n", + current->comm, task_pid_nr(current), current->xid); do_exit(SIGKILL); } else { BUG_ON(err != -EFAULT); diff -NurpP --minimal linux-2.6.27.15/arch/um/sys-i386/syscalls.c linux-2.6.27.15-g-v/arch/um/sys-i386/syscalls.c --- linux-2.6.27.15/arch/um/sys-i386/syscalls.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/um/sys-i386/syscalls.c 2009-02-10 20:32:10.000000000 +0100 @@ -10,6 +10,21 @@ #include "asm/uaccess.h" #include "asm/unistd.h" +int i386_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) +{ + unsigned long pax_task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + if (len > pax_task_size || addr > pax_task_size - len) + return -EINVAL; + + return 0; +} + /* * Perform the select(nd, in, out, ex, tv) and mmap() system * calls. Linux/i386 didn't use to be able to handle more than diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/bitops.h linux-2.6.27.15-g-v/arch/x86/boot/bitops.h --- linux-2.6.27.15/arch/x86/boot/bitops.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/bitops.h 2009-02-10 20:32:10.000000000 +0100 @@ -26,7 +26,7 @@ static inline int variable_test_bit(int u8 v; const u32 *p = (const u32 *)addr; - asm("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); + asm volatile("btl %2,%1; setc %0" : "=qm" (v) : "m" (*p), "Ir" (nr)); return v; } @@ -37,7 +37,7 @@ static inline int variable_test_bit(int static inline void set_bit(int nr, void *addr) { - asm("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr)); + asm volatile("btsl %1,%0" : "+m" (*(u32 *)addr) : "Ir" (nr)); } #endif /* BOOT_BITOPS_H */ diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/boot.h linux-2.6.27.15-g-v/arch/x86/boot/boot.h --- linux-2.6.27.15/arch/x86/boot/boot.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/boot.h 2009-02-10 20:32:10.000000000 +0100 @@ -80,7 +80,7 @@ static inline void io_delay(void) static inline u16 ds(void) { u16 seg; - asm("movw %%ds,%0" : "=rm" (seg)); + asm volatile("movw %%ds,%0" : "=rm" (seg)); return seg; } @@ -176,7 +176,7 @@ static inline void wrgs32(u32 v, addr_t static inline int memcmp(const void *s1, const void *s2, size_t len) { u8 diff; - asm("repe; cmpsb; setnz %0" + asm volatile("repe; cmpsb; setnz %0" : "=qm" (diff), "+D" (s1), "+S" (s2), "+c" (len)); return diff; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/compressed/head_32.S linux-2.6.27.15-g-v/arch/x86/boot/compressed/head_32.S --- linux-2.6.27.15/arch/x86/boot/compressed/head_32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/compressed/head_32.S 2009-02-10 20:32:10.000000000 +0100 @@ -70,7 +70,7 @@ startup_32: addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebx andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebx #else - movl $LOAD_PHYSICAL_ADDR, %ebx + movl $____LOAD_PHYSICAL_ADDR, %ebx #endif /* Replace the compressed data size with the uncompressed size */ @@ -105,7 +105,7 @@ startup_32: addl $(CONFIG_PHYSICAL_ALIGN - 1), %ebp andl $(~(CONFIG_PHYSICAL_ALIGN - 1)), %ebp #else - movl $LOAD_PHYSICAL_ADDR, %ebp + movl $____LOAD_PHYSICAL_ADDR, %ebp #endif /* @@ -159,16 +159,15 @@ relocated: * and where it was actually loaded. */ movl %ebp, %ebx - subl $LOAD_PHYSICAL_ADDR, %ebx + subl $____LOAD_PHYSICAL_ADDR, %ebx jz 2f /* Nothing to be done if loaded at compiled addr. */ /* * Process relocations. */ 1: subl $4, %edi - movl 0(%edi), %ecx - testl %ecx, %ecx - jz 2f + movl (%edi), %ecx + jecxz 2f addl %ebx, -__PAGE_OFFSET(%ebx, %ecx) jmp 1b 2: diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/compressed/misc.c linux-2.6.27.15-g-v/arch/x86/boot/compressed/misc.c --- linux-2.6.27.15/arch/x86/boot/compressed/misc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/compressed/misc.c 2009-02-10 20:32:10.000000000 +0100 @@ -371,7 +371,7 @@ static void parse_elf(void *output) case PT_LOAD: #ifdef CONFIG_RELOCATABLE dest = output; - dest += (phdr->p_paddr - LOAD_PHYSICAL_ADDR); + dest += (phdr->p_paddr - ____LOAD_PHYSICAL_ADDR); #else dest = (void *)(phdr->p_paddr); #endif @@ -423,7 +423,7 @@ asmlinkage void decompress_kernel(void * if (heap > ((-__PAGE_OFFSET-(512<<20)-1) & 0x7fffffff)) error("Destination address too large"); #ifndef CONFIG_RELOCATABLE - if ((u32)output != LOAD_PHYSICAL_ADDR) + if ((u32)output != ____LOAD_PHYSICAL_ADDR) error("Wrong destination address"); #endif #endif diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/compressed/relocs.c linux-2.6.27.15-g-v/arch/x86/boot/compressed/relocs.c --- linux-2.6.27.15/arch/x86/boot/compressed/relocs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/compressed/relocs.c 2009-02-10 20:32:10.000000000 +0100 @@ -10,8 +10,11 @@ #define USE_BSD #include +#include "../../../../include/linux/autoconf.h" + #define ARRAY_SIZE(x) (sizeof(x) / sizeof((x)[0])) static Elf32_Ehdr ehdr; +static Elf32_Phdr *phdr; static unsigned long reloc_count, reloc_idx; static unsigned long *relocs; @@ -245,6 +248,36 @@ static void read_ehdr(FILE *fp) } } +static void read_phdrs(FILE *fp) +{ + int i; + + phdr = calloc(ehdr.e_phnum, sizeof(Elf32_Phdr)); + if (!phdr) { + die("Unable to allocate %d program headers\n", + ehdr.e_phnum); + } + if (fseek(fp, ehdr.e_phoff, SEEK_SET) < 0) { + die("Seek to %d failed: %s\n", + ehdr.e_phoff, strerror(errno)); + } + if (fread(phdr, sizeof(*phdr), ehdr.e_phnum, fp) != ehdr.e_phnum) { + die("Cannot read ELF program headers: %s\n", + strerror(errno)); + } + for(i = 0; i < ehdr.e_phnum; i++) { + phdr[i].p_type = elf32_to_cpu(phdr[i].p_type); + phdr[i].p_offset = elf32_to_cpu(phdr[i].p_offset); + phdr[i].p_vaddr = elf32_to_cpu(phdr[i].p_vaddr); + phdr[i].p_paddr = elf32_to_cpu(phdr[i].p_paddr); + phdr[i].p_filesz = elf32_to_cpu(phdr[i].p_filesz); + phdr[i].p_memsz = elf32_to_cpu(phdr[i].p_memsz); + phdr[i].p_flags = elf32_to_cpu(phdr[i].p_flags); + phdr[i].p_align = elf32_to_cpu(phdr[i].p_align); + } + +} + static void read_shdrs(FILE *fp) { int i; @@ -341,6 +374,8 @@ static void read_symtabs(FILE *fp) static void read_relocs(FILE *fp) { int i,j; + uint32_t base; + for (i = 0; i < ehdr.e_shnum; i++) { struct section *sec = &secs[i]; if (sec->shdr.sh_type != SHT_REL) { @@ -360,9 +395,18 @@ static void read_relocs(FILE *fp) die("Cannot read symbol table: %s\n", strerror(errno)); } + base = 0; + for (j = 0; j < ehdr.e_phnum; j++) { + if (phdr[j].p_type != PT_LOAD ) + continue; + if (secs[secs[i].shdr.sh_info].shdr.sh_offset < phdr[j].p_offset || secs[secs[i].shdr.sh_info].shdr.sh_offset > phdr[j].p_offset + phdr[j].p_filesz) + continue; + base = CONFIG_PAGE_OFFSET + phdr[j].p_paddr - phdr[j].p_vaddr; + break; + } for (j = 0; j < sec->shdr.sh_size/sizeof(Elf32_Rel); j++) { Elf32_Rel *rel = &sec->reltab[j]; - rel->r_offset = elf32_to_cpu(rel->r_offset); + rel->r_offset = elf32_to_cpu(rel->r_offset) + base; rel->r_info = elf32_to_cpu(rel->r_info); } } @@ -504,6 +548,23 @@ static void walk_relocs(void (*visit)(El if (sym->st_shndx == SHN_ABS) { continue; } + /* Don't relocate actual per-cpu variables, they are absolute indices, not addresses */ + if (!strcmp(sec_name(sym->st_shndx), ".data.percpu") && strncmp(sym_name(sym_strtab, sym), "__per_cpu_", 10)) + continue; +#if defined(CONFIG_PAX_KERNEXEC) && defined(CONFIG_X86_32) + /* Don't relocate actual code, they are relocated implicitly by the base address of KERNEL_CS */ + if (!strcmp(sec_name(sym->st_shndx), ".init.text")) + continue; + if (!strcmp(sec_name(sym->st_shndx), ".exit.text")) + continue; + if (!strcmp(sec_name(sym->st_shndx), ".text.head")) { + if (strcmp(sym_name(sym_strtab, sym), "__init_end") && + strcmp(sym_name(sym_strtab, sym), "KERNEL_TEXT_OFFSET")) + continue; + } + if (!strcmp(sec_name(sym->st_shndx), ".text")) + continue; +#endif if (r_type == R_386_PC32) { /* PC relative relocations don't need to be adjusted */ } @@ -631,6 +692,7 @@ int main(int argc, char **argv) fname, strerror(errno)); } read_ehdr(fp); + read_phdrs(fp); read_shdrs(fp); read_strtabs(fp); read_symtabs(fp); diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/cpucheck.c linux-2.6.27.15-g-v/arch/x86/boot/cpucheck.c --- linux-2.6.27.15/arch/x86/boot/cpucheck.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/cpucheck.c 2009-02-10 20:32:10.000000000 +0100 @@ -74,7 +74,7 @@ static int has_fpu(void) u16 fcw = -1, fsw = -1; u32 cr0; - asm("movl %%cr0,%0" : "=r" (cr0)); + asm volatile("movl %%cr0,%0" : "=r" (cr0)); if (cr0 & (X86_CR0_EM|X86_CR0_TS)) { cr0 &= ~(X86_CR0_EM|X86_CR0_TS); asm volatile("movl %0,%%cr0" : : "r" (cr0)); @@ -90,7 +90,7 @@ static int has_eflag(u32 mask) { u32 f0, f1; - asm("pushfl ; " + asm volatile("pushfl ; " "pushfl ; " "popl %0 ; " "movl %0,%1 ; " @@ -115,7 +115,7 @@ static void get_flags(void) set_bit(X86_FEATURE_FPU, cpu.flags); if (has_eflag(X86_EFLAGS_ID)) { - asm("cpuid" + asm volatile("cpuid" : "=a" (max_intel_level), "=b" (cpu_vendor[0]), "=d" (cpu_vendor[1]), @@ -124,7 +124,7 @@ static void get_flags(void) if (max_intel_level >= 0x00000001 && max_intel_level <= 0x0000ffff) { - asm("cpuid" + asm volatile("cpuid" : "=a" (tfms), "=c" (cpu.flags[4]), "=d" (cpu.flags[0]) @@ -136,7 +136,7 @@ static void get_flags(void) cpu.model += ((tfms >> 16) & 0xf) << 4; } - asm("cpuid" + asm volatile("cpuid" : "=a" (max_amd_level) : "a" (0x80000000) : "ebx", "ecx", "edx"); @@ -144,7 +144,7 @@ static void get_flags(void) if (max_amd_level >= 0x80000001 && max_amd_level <= 0x8000ffff) { u32 eax = 0x80000001; - asm("cpuid" + asm volatile("cpuid" : "+a" (eax), "=c" (cpu.flags[6]), "=d" (cpu.flags[1]) @@ -203,9 +203,9 @@ int check_cpu(int *cpu_level_ptr, int *r u32 ecx = MSR_K7_HWCR; u32 eax, edx; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); eax &= ~(1 << 15); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); get_flags(); /* Make sure it really did something */ err = check_flags(); @@ -218,9 +218,9 @@ int check_cpu(int *cpu_level_ptr, int *r u32 ecx = MSR_VIA_FCR; u32 eax, edx; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); eax |= (1<<1)|(1<<7); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); set_bit(X86_FEATURE_CX8, cpu.flags); err = check_flags(); @@ -231,12 +231,12 @@ int check_cpu(int *cpu_level_ptr, int *r u32 eax, edx; u32 level = 1; - asm("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); - asm("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx)); - asm("cpuid" + asm volatile("rdmsr" : "=a" (eax), "=d" (edx) : "c" (ecx)); + asm volatile("wrmsr" : : "a" (~0), "d" (edx), "c" (ecx)); + asm volatile("cpuid" : "+a" (level), "=d" (cpu.flags[0]) : : "ecx", "ebx"); - asm("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); + asm volatile("wrmsr" : : "a" (eax), "d" (edx), "c" (ecx)); err = check_flags(); } diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/edd.c linux-2.6.27.15-g-v/arch/x86/boot/edd.c --- linux-2.6.27.15/arch/x86/boot/edd.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/edd.c 2009-02-10 20:32:10.000000000 +0100 @@ -76,7 +76,7 @@ static int get_edd_info(u8 devno, struct ax = 0x4100; bx = EDDMAGIC1; dx = devno; - asm("pushfl; stc; int $0x13; setc %%al; popfl" + asm volatile("pushfl; stc; int $0x13; setc %%al; popfl" : "+a" (ax), "+b" (bx), "=c" (cx), "+d" (dx) : : "esi", "edi"); @@ -95,7 +95,7 @@ static int get_edd_info(u8 devno, struct ei->params.length = sizeof(ei->params); ax = 0x4800; dx = devno; - asm("pushfl; int $0x13; popfl" + asm volatile("pushfl; int $0x13; popfl" : "+a" (ax), "+d" (dx), "=m" (ei->params) : "S" (&ei->params) : "ebx", "ecx", "edi"); @@ -106,7 +106,7 @@ static int get_edd_info(u8 devno, struct ax = 0x0800; dx = devno; di = 0; - asm("pushw %%es; " + asm volatile("pushw %%es; " "movw %%di,%%es; " "pushfl; stc; int $0x13; setc %%al; popfl; " "popw %%es" diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/main.c linux-2.6.27.15-g-v/arch/x86/boot/main.c --- linux-2.6.27.15/arch/x86/boot/main.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/main.c 2009-02-10 20:32:10.000000000 +0100 @@ -78,7 +78,7 @@ static void query_ist(void) if (cpu.level < 6) return; - asm("int $0x15" + asm volatile("int $0x15" : "=a" (boot_params.ist_info.signature), "=b" (boot_params.ist_info.command), "=c" (boot_params.ist_info.event), diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/mca.c linux-2.6.27.15-g-v/arch/x86/boot/mca.c --- linux-2.6.27.15/arch/x86/boot/mca.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/mca.c 2009-02-10 20:32:10.000000000 +0100 @@ -19,7 +19,7 @@ int query_mca(void) u8 err; u16 es, bx, len; - asm("pushw %%es ; " + asm volatile("pushw %%es ; " "int $0x15 ; " "setc %0 ; " "movw %%es, %1 ; " diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/memory.c linux-2.6.27.15-g-v/arch/x86/boot/memory.c --- linux-2.6.27.15/arch/x86/boot/memory.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/memory.c 2009-02-10 20:32:10.000000000 +0100 @@ -30,7 +30,7 @@ static int detect_memory_e820(void) /* Important: %edx is clobbered by some BIOSes, so it must be either used for the error output or explicitly marked clobbered. */ - asm("int $0x15; setc %0" + asm volatile("int $0x15; setc %0" : "=d" (err), "+b" (next), "=a" (id), "+c" (size), "=m" (*desc) : "D" (desc), "d" (SMAP), "a" (0xe820)); @@ -65,7 +65,7 @@ static int detect_memory_e801(void) bx = cx = dx = 0; ax = 0xe801; - asm("stc; int $0x15; setc %0" + asm volatile("stc; int $0x15; setc %0" : "=m" (err), "+a" (ax), "+b" (bx), "+c" (cx), "+d" (dx)); if (err) @@ -95,7 +95,7 @@ static int detect_memory_88(void) u8 err; ax = 0x8800; - asm("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); + asm volatile("stc; int $0x15; setc %0" : "=bcdm" (err), "+a" (ax)); boot_params.screen_info.ext_mem_k = ax; diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/video.c linux-2.6.27.15-g-v/arch/x86/boot/video.c --- linux-2.6.27.15/arch/x86/boot/video.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/video.c 2009-02-10 20:32:10.000000000 +0100 @@ -23,7 +23,7 @@ static void store_cursor_position(void) ax = 0x0300; bx = 0; - asm(INT10 + asm volatile(INT10 : "=d" (curpos), "+a" (ax), "+b" (bx) : : "ecx", "esi", "edi"); @@ -38,7 +38,7 @@ static void store_video_mode(void) /* N.B.: the saving of the video page here is a bit silly, since we pretty much assume page 0 everywhere. */ ax = 0x0f00; - asm(INT10 + asm volatile(INT10 : "+a" (ax), "=b" (page) : : "ecx", "edx", "esi", "edi"); diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/video-vesa.c linux-2.6.27.15-g-v/arch/x86/boot/video-vesa.c --- linux-2.6.27.15/arch/x86/boot/video-vesa.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/video-vesa.c 2009-02-10 20:32:10.000000000 +0100 @@ -41,7 +41,7 @@ static int vesa_probe(void) ax = 0x4f00; di = (size_t)&vginfo; - asm(INT10 + asm volatile(INT10 : "+a" (ax), "+D" (di), "=m" (vginfo) : : "ebx", "ecx", "edx", "esi"); @@ -68,7 +68,7 @@ static int vesa_probe(void) ax = 0x4f01; cx = mode; di = (size_t)&vminfo; - asm(INT10 + asm volatile(INT10 : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo) : : "ebx", "edx", "esi"); @@ -123,7 +123,7 @@ static int vesa_set_mode(struct mode_inf ax = 0x4f01; cx = vesa_mode; di = (size_t)&vminfo; - asm(INT10 + asm volatile(INT10 : "+a" (ax), "+c" (cx), "+D" (di), "=m" (vminfo) : : "ebx", "edx", "esi"); @@ -203,19 +203,20 @@ static void vesa_dac_set_8bits(void) /* Save the VESA protected mode info */ static void vesa_store_pm_info(void) { - u16 ax, bx, di, es; + u16 ax, bx, cx, di, es; ax = 0x4f0a; - bx = di = 0; - asm("pushw %%es; "INT10"; movw %%es,%0; popw %%es" - : "=d" (es), "+a" (ax), "+b" (bx), "+D" (di) - : : "ecx", "esi"); + bx = cx = di = 0; + asm volatile("pushw %%es; "INT10"; movw %%es,%0; popw %%es" + : "=d" (es), "+a" (ax), "+b" (bx), "+c" (cx), "+D" (di) + : : "esi"); if (ax != 0x004f) return; boot_params.screen_info.vesapm_seg = es; boot_params.screen_info.vesapm_off = di; + boot_params.screen_info.vesapm_size = cx; } /* @@ -269,7 +270,7 @@ void vesa_store_edid(void) /* Note: The VBE DDC spec is different from the main VESA spec; we genuinely have to assume all registers are destroyed here. */ - asm("pushw %%es; movw %2,%%es; "INT10"; popw %%es" + asm volatile("pushw %%es; movw %2,%%es; "INT10"; popw %%es" : "+a" (ax), "+b" (bx) : "c" (cx), "D" (di) : "esi"); @@ -285,7 +286,7 @@ void vesa_store_edid(void) cx = 0; /* Controller 0 */ dx = 0; /* EDID block number */ di =(size_t) &boot_params.edid_info; /* (ES:)Pointer to block */ - asm(INT10 + asm volatile(INT10 : "+a" (ax), "+b" (bx), "+d" (dx), "=m" (boot_params.edid_info) : "c" (cx), "D" (di) : "esi"); diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/video-vga.c linux-2.6.27.15-g-v/arch/x86/boot/video-vga.c --- linux-2.6.27.15/arch/x86/boot/video-vga.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/video-vga.c 2009-02-10 20:32:10.000000000 +0100 @@ -225,7 +225,7 @@ static int vga_probe(void) }; u8 vga_flag; - asm(INT10 + asm volatile(INT10 : "=b" (ega_bx) : "a" (0x1200), "b" (0x10) /* Check EGA/VGA */ : "ecx", "edx", "esi", "edi"); @@ -237,7 +237,7 @@ static int vga_probe(void) /* If we have MDA/CGA/HGC then BL will be unchanged at 0x10 */ if ((u8)ega_bx != 0x10) { /* EGA/VGA */ - asm(INT10 + asm volatile(INT10 : "=a" (vga_flag) : "a" (0x1a00) : "ebx", "ecx", "edx", "esi", "edi"); diff -NurpP --minimal linux-2.6.27.15/arch/x86/boot/voyager.c linux-2.6.27.15-g-v/arch/x86/boot/voyager.c --- linux-2.6.27.15/arch/x86/boot/voyager.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/boot/voyager.c 2009-02-10 20:32:10.000000000 +0100 @@ -23,7 +23,7 @@ int query_voyager(void) data_ptr[0] = 0xff; /* Flag on config not found(?) */ - asm("pushw %%es ; " + asm volatile("pushw %%es ; " "int $0x15 ; " "setc %0 ; " "movw %%es, %1 ; " diff -NurpP --minimal linux-2.6.27.15/arch/x86/ia32/ia32entry.S linux-2.6.27.15-g-v/arch/x86/ia32/ia32entry.S --- linux-2.6.27.15/arch/x86/ia32/ia32entry.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/ia32/ia32entry.S 2009-02-10 20:32:10.000000000 +0100 @@ -772,7 +772,7 @@ ia32_sys_call_table: .quad sys_tgkill /* 270 */ .quad compat_sys_utimes .quad sys32_fadvise64_64 - .quad quiet_ni_syscall /* sys_vserver */ + .quad sys32_vserver .quad sys_mbind .quad compat_sys_get_mempolicy /* 275 */ .quad sys_set_mempolicy diff -NurpP --minimal linux-2.6.27.15/arch/x86/ia32/ia32_signal.c linux-2.6.27.15-g-v/arch/x86/ia32/ia32_signal.c --- linux-2.6.27.15/arch/x86/ia32/ia32_signal.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/ia32/ia32_signal.c 2009-02-10 20:32:10.000000000 +0100 @@ -535,6 +535,7 @@ int ia32_setup_rt_frame(int sig, struct __NR_ia32_rt_sigreturn, 0x80cd, 0, + 0 }; frame = get_sigframe(ka, regs, sizeof(*frame)); diff -NurpP --minimal linux-2.6.27.15/arch/x86/Kconfig linux-2.6.27.15-g-v/arch/x86/Kconfig --- linux-2.6.27.15/arch/x86/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/Kconfig 2009-02-10 20:32:10.000000000 +0100 @@ -915,7 +915,7 @@ config PAGE_OFFSET hex default 0xB0000000 if VMSPLIT_3G_OPT default 0x80000000 if VMSPLIT_2G - default 0x78000000 if VMSPLIT_2G_OPT + default 0x70000000 if VMSPLIT_2G_OPT default 0x40000000 if VMSPLIT_1G default 0xC0000000 depends on X86_32 @@ -1296,8 +1296,7 @@ config KEXEC_JUMP config PHYSICAL_START hex "Physical address where the kernel is loaded" if (EMBEDDED || CRASH_DUMP) default "0x1000000" if X86_NUMAQ - default "0x200000" if X86_64 - default "0x100000" + default "0x200000" help This gives the physical address where the kernel is loaded. @@ -1389,9 +1388,9 @@ config HOTPLUG_CPU suspend. config COMPAT_VDSO - def_bool y + def_bool n prompt "Compat VDSO support" - depends on X86_32 || IA32_EMULATION + depends on (X86_32 || IA32_EMULATION) && !PAX_NOEXEC help Map the 32-bit VDSO to the predictable old-style address too. ---help--- @@ -1811,6 +1810,8 @@ source "fs/Kconfig" source "arch/x86/Kconfig.debug" +source "kernel/vserver/Kconfig" + source "security/Kconfig" source "crypto/Kconfig" diff -NurpP --minimal linux-2.6.27.15/arch/x86/Kconfig.cpu linux-2.6.27.15-g-v/arch/x86/Kconfig.cpu --- linux-2.6.27.15/arch/x86/Kconfig.cpu 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/Kconfig.cpu 2009-02-10 20:32:10.000000000 +0100 @@ -340,7 +340,7 @@ config X86_PPRO_FENCE config X86_F00F_BUG def_bool y - depends on M586MMX || M586TSC || M586 || M486 || M386 + depends on (M586MMX || M586TSC || M586 || M486 || M386) && !PAX_KERNEXEC config X86_WP_WORKS_OK def_bool y @@ -360,7 +360,7 @@ config X86_POPAD_OK config X86_ALIGNMENT_16 def_bool y - depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK6 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 + depends on MWINCHIP3D || MWINCHIP2 || MWINCHIPC6 || MCYRIXIII || X86_ELAN || MK8 || MK7 || MK6 || MCORE2 || MPENTIUM4 || MPENTIUMIII || MPENTIUMII || M686 || M586MMX || M586TSC || M586 || M486 || MVIAC3_2 || MGEODEGX1 config X86_INTEL_USERCOPY def_bool y @@ -406,7 +406,7 @@ config X86_CMPXCHG64 # generates cmov. config X86_CMOV def_bool y - depends on (MK7 || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64) + depends on (MK8 || MK7 || MCORE2 || MPSC || MPENTIUM4 || MPENTIUMM || MPENTIUMIII || MPENTIUMII || M686 || MVIAC3_2 || MVIAC7 || X86_64) config X86_MINIMUM_CPU_FAMILY int diff -NurpP --minimal linux-2.6.27.15/arch/x86/Kconfig.debug linux-2.6.27.15-g-v/arch/x86/Kconfig.debug --- linux-2.6.27.15/arch/x86/Kconfig.debug 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/Kconfig.debug 2009-02-10 20:32:10.000000000 +0100 @@ -94,7 +94,7 @@ config X86_PTDUMP config DEBUG_RODATA bool "Write protect kernel read-only data structures" default y - depends on DEBUG_KERNEL + depends on DEBUG_KERNEL && BROKEN help Mark the kernel read-only data as write-protected in the pagetables, in order to catch accidental (and incorrect) writes to such const diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/acpi/boot.c linux-2.6.27.15-g-v/arch/x86/kernel/acpi/boot.c --- linux-2.6.27.15/arch/x86/kernel/acpi/boot.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/acpi/boot.c 2009-02-10 20:32:10.000000000 +0100 @@ -1640,7 +1640,7 @@ static struct dmi_system_id __initdata a DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq 6715b"), }, }, - {} + { NULL, NULL, Template:0, NULL, NULL} }; /* diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/acpi/realmode/wakeup.S linux-2.6.27.15-g-v/arch/x86/kernel/acpi/realmode/wakeup.S --- linux-2.6.27.15/arch/x86/kernel/acpi/realmode/wakeup.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/acpi/realmode/wakeup.S 2009-02-10 20:32:10.000000000 +0100 @@ -104,7 +104,7 @@ _start: movl %eax, %ecx orl %edx, %ecx jz 1f - movl $0xc0000080, %ecx + mov $MSR_EFER, %ecx wrmsr 1: diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/acpi/sleep.c linux-2.6.27.15-g-v/arch/x86/kernel/acpi/sleep.c --- linux-2.6.27.15/arch/x86/kernel/acpi/sleep.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/acpi/sleep.c 2009-02-10 20:32:10.000000000 +0100 @@ -37,6 +37,10 @@ int acpi_save_state_mem(void) { struct wakeup_header *header; +#if defined(CONFIG_64BIT) && defined(CONFIG_SMP) && defined(CONFIG_PAX_KERNEXEC) + unsigned long cr0; +#endif + if (!acpi_realmode) { printk(KERN_ERR "Could not allocate memory during boot, " "S3 disabled\n"); @@ -99,8 +103,18 @@ int acpi_save_state_mem(void) header->trampoline_segment = setup_trampoline() >> 4; #ifdef CONFIG_SMP stack_start.sp = temp_stack + 4096; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(smp_processor_id()); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + #endif initial_code = (unsigned long)wakeup_long64; saved_magic = 0x123456789abcdef0; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/acpi/wakeup_32.S linux-2.6.27.15-g-v/arch/x86/kernel/acpi/wakeup_32.S --- linux-2.6.27.15/arch/x86/kernel/acpi/wakeup_32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/acpi/wakeup_32.S 2009-02-10 20:32:10.000000000 +0100 @@ -30,13 +30,11 @@ wakeup_pmode_return: # and restore the stack ... but you need gdt for this to work movl saved_context_esp, %esp - movl %cs:saved_magic, %eax - cmpl $0x12345678, %eax + cmpl $0x12345678, saved_magic jne bogus_magic # jump to place where we left off - movl saved_eip, %eax - jmp *%eax + jmp *(saved_eip) bogus_magic: jmp bogus_magic diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/alternative.c linux-2.6.27.15-g-v/arch/x86/kernel/alternative.c --- linux-2.6.27.15/arch/x86/kernel/alternative.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/alternative.c 2009-02-10 20:32:10.000000000 +0100 @@ -393,7 +393,7 @@ void apply_paravirt(struct paravirt_patc BUG_ON(p->len > MAX_PATCH_LEN); /* prep the buffer with the original instructions */ - memcpy(insnbuf, p->instr, p->len); + memcpy(insnbuf, ktla_ktva(p->instr), p->len); used = pv_init_ops.patch(p->instrtype, p->clobbers, insnbuf, (unsigned long)p->instr, p->len); @@ -473,11 +473,26 @@ void __init alternative_instructions(voi * instructions. And on the local CPU you need to be protected again NMI or MCE * handlers seeing an inconsistent instruction while you patch. */ -void *text_poke_early(void *addr, const void *opcode, size_t len) +void *__kprobes text_poke_early(void *addr, const void *opcode, size_t len) { unsigned long flags; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + local_irq_save(flags); - memcpy(addr, opcode, len); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + memcpy(ktla_ktva(addr), opcode, len); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + local_irq_restore(flags); sync_core(); /* Could also do a CLFLUSH here to speed up CPU recovery; but @@ -498,33 +513,27 @@ void *text_poke_early(void *addr, const */ void *__kprobes text_poke(void *addr, const void *opcode, size_t len) { - unsigned long flags; - char *vaddr; - int nr_pages = 2; + unsigned char *vaddr = ktla_ktva(addr); struct page *pages[2]; - int i; + size_t i; - if (!core_kernel_text((unsigned long)addr)) { - pages[0] = vmalloc_to_page(addr); - pages[1] = vmalloc_to_page(addr + PAGE_SIZE); + if (!core_kernel_text((unsigned long)addr) + +#if defined(CONFIG_X86_32) && defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + && (vaddr < MODULES_VADDR || MODULES_END < vaddr) +#endif + + ) { + pages[0] = vmalloc_to_page(vaddr); + pages[1] = vmalloc_to_page(vaddr + PAGE_SIZE); } else { - pages[0] = virt_to_page(addr); + pages[0] = virt_to_page(vaddr); WARN_ON(!PageReserved(pages[0])); - pages[1] = virt_to_page(addr + PAGE_SIZE); + pages[1] = virt_to_page(vaddr + PAGE_SIZE); } BUG_ON(!pages[0]); - if (!pages[1]) - nr_pages = 1; - vaddr = vmap(pages, nr_pages, VM_MAP, PAGE_KERNEL); - BUG_ON(!vaddr); - local_irq_save(flags); - memcpy(&vaddr[(unsigned long)addr & ~PAGE_MASK], opcode, len); - local_irq_restore(flags); - vunmap(vaddr); - sync_core(); - /* Could also do a CLFLUSH here to speed up CPU recovery; but - that causes hangs on some VIA CPUs. */ + text_poke_early(addr, opcode, len); for (i = 0; i < len; i++) - BUG_ON(((char *)addr)[i] != ((char *)opcode)[i]); + BUG_ON((vaddr)[i] != ((unsigned char *)opcode)[i]); return addr; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/apm_32.c linux-2.6.27.15-g-v/arch/x86/kernel/apm_32.c --- linux-2.6.27.15/arch/x86/kernel/apm_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/apm_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -408,7 +408,7 @@ static DECLARE_WAIT_QUEUE_HEAD(apm_waitq static DECLARE_WAIT_QUEUE_HEAD(apm_suspend_waitqueue); static struct apm_user *user_list; static DEFINE_SPINLOCK(user_list_lock); -static const struct desc_struct bad_bios_desc = { { { 0, 0x00409200 } } }; +static const struct desc_struct bad_bios_desc = { { { 0, 0x00409300 } } }; static const char driver_version[] = "1.16ac"; /* no spaces */ @@ -603,19 +603,42 @@ static u8 apm_bios_call(u32 func, u32 eb struct desc_struct save_desc_40; struct desc_struct *gdt; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + cpus = apm_save_cpus(); cpu = get_cpu(); gdt = get_cpu_gdt_table(cpu); save_desc_40 = gdt[0x40 / 8]; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt[0x40 / 8] = bad_bios_desc; +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + apm_irq_save(flags); APM_DO_SAVE_SEGS; apm_bios_call_asm(func, ebx_in, ecx_in, eax, ebx, ecx, edx, esi); APM_DO_RESTORE_SEGS; apm_irq_restore(flags); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt[0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + put_cpu(); apm_restore_cpus(cpus); @@ -646,19 +669,42 @@ static u8 apm_bios_call_simple(u32 func, struct desc_struct save_desc_40; struct desc_struct *gdt; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + cpus = apm_save_cpus(); cpu = get_cpu(); gdt = get_cpu_gdt_table(cpu); save_desc_40 = gdt[0x40 / 8]; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt[0x40 / 8] = bad_bios_desc; +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + apm_irq_save(flags); APM_DO_SAVE_SEGS; error = apm_bios_call_simple_asm(func, ebx_in, ecx_in, eax); APM_DO_RESTORE_SEGS; apm_irq_restore(flags); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + gdt[0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + put_cpu(); apm_restore_cpus(cpus); return error; @@ -930,7 +976,7 @@ recalc: static void apm_power_off(void) { - unsigned char po_bios_call[] = { + const unsigned char po_bios_call[] = { 0xb8, 0x00, 0x10, /* movw $0x1000,ax */ 0x8e, 0xd0, /* movw ax,ss */ 0xbc, 0x00, 0xf0, /* movw $0xf000,sp */ @@ -1877,7 +1923,10 @@ static const struct file_operations apm_ static struct miscdevice apm_device = { APM_MINOR_DEV, "apm_bios", - &apm_bios_fops + &apm_bios_fops, + {NULL, NULL}, + NULL, + NULL }; @@ -2198,7 +2247,7 @@ static struct dmi_system_id __initdata a { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL} }; /* @@ -2216,6 +2265,10 @@ static int __init apm_init(void) struct desc_struct *gdt; int err; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + dmi_check_system(apm_dmi_table); if (apm_info.bios.version == 0 || paravirt_enabled() || machine_is_olpc()) { @@ -2289,9 +2342,18 @@ static int __init apm_init(void) * This is for buggy BIOS's that refer to (real mode) segment 0x40 * even though they are called in protected mode. */ + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* * Set up the long jump entry point to the APM BIOS, which is called * from inline assembly. @@ -2310,6 +2372,11 @@ static int __init apm_init(void) * code to that CPU. */ gdt = get_cpu_gdt_table(0); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + set_base(gdt[APM_CS >> 3], __va((unsigned long)apm_info.bios.cseg << 4)); set_base(gdt[APM_CS_16 >> 3], @@ -2317,6 +2384,10 @@ static int __init apm_init(void) set_base(gdt[APM_DS >> 3], __va((unsigned long)apm_info.bios.dseg << 4)); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + proc_create("apm", 0, NULL, &apm_file_ops); kapmd_task = kthread_create(apm, NULL, "kapmd"); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/asm-offsets_32.c linux-2.6.27.15-g-v/arch/x86/kernel/asm-offsets_32.c --- linux-2.6.27.15/arch/x86/kernel/asm-offsets_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/asm-offsets_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -100,6 +100,7 @@ void foo(void) DEFINE(PTRS_PER_PTE, PTRS_PER_PTE); DEFINE(PTRS_PER_PMD, PTRS_PER_PMD); DEFINE(PTRS_PER_PGD, PTRS_PER_PGD); + DEFINE(PERCPU_MODULE_RESERVE, PERCPU_MODULE_RESERVE); OFFSET(crypto_tfm_ctx_offset, crypto_tfm, __crt_ctx); @@ -113,6 +114,7 @@ void foo(void) OFFSET(PV_CPU_iret, pv_cpu_ops, iret); OFFSET(PV_CPU_irq_enable_sysexit, pv_cpu_ops, irq_enable_sysexit); OFFSET(PV_CPU_read_cr0, pv_cpu_ops, read_cr0); + OFFSET(PV_CPU_write_cr0, pv_cpu_ops, write_cr0); #endif #ifdef CONFIG_XEN diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/asm-offsets_64.c linux-2.6.27.15-g-v/arch/x86/kernel/asm-offsets_64.c --- linux-2.6.27.15/arch/x86/kernel/asm-offsets_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/asm-offsets_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -122,6 +122,7 @@ int main(void) ENTRY(cr8); BLANK(); #undef ENTRY + DEFINE(TSS_size, sizeof(struct tss_struct)); DEFINE(TSS_ist, offsetof(struct tss_struct, x86_tss.ist)); BLANK(); DEFINE(crypto_tfm_ctx_offset, offsetof(struct crypto_tfm, __crt_ctx)); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/cpu/common_64.c linux-2.6.27.15-g-v/arch/x86/kernel/cpu/common_64.c --- linux-2.6.27.15/arch/x86/kernel/cpu/common_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/cpu/common_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -37,22 +37,6 @@ #include "cpu.h" -/* We need valid kernel segments for data and code in long mode too - * IRET will check the segment types kkeil 2000/10/28 - * Also sysret mandates a special GDT layout - */ -/* The TLS descriptors are currently at a different place compared to i386. - Hopefully nobody expects them at a fixed place (Wine?) */ -DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { - [GDT_ENTRY_KERNEL32_CS] = { { { 0x0000ffff, 0x00cf9b00 } } }, - [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00af9b00 } } }, - [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9300 } } }, - [GDT_ENTRY_DEFAULT_USER32_CS] = { { { 0x0000ffff, 0x00cffb00 } } }, - [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff300 } } }, - [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00affb00 } } }, -} }; -EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); - __u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata; /* Current gdt points %fs at the "master" per-cpu area: after this, @@ -457,15 +441,13 @@ cpumask_t cpu_initialized __cpuinitdata struct x8664_pda **_cpu_pda __read_mostly; EXPORT_SYMBOL(_cpu_pda); -struct desc_ptr idt_descr = { 256 * 16 - 1, (unsigned long) idt_table }; +struct desc_ptr idt_descr __read_only = { 256 * 16 - 1, (unsigned long) idt_table }; char boot_cpu_stack[IRQSTACKSIZE] __page_aligned_bss; unsigned long __supported_pte_mask __read_mostly = ~0UL; EXPORT_SYMBOL_GPL(__supported_pte_mask); -static int do_not_nx __cpuinitdata; - /* noexec=on|off Control non executable mappings for 64bit processes. @@ -478,9 +460,7 @@ static int __init nonx_setup(char *str) return -EINVAL; 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; @@ -576,7 +556,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; } @@ -598,7 +578,7 @@ DEFINE_PER_CPU(struct orig_ist, orig_ist void __cpuinit cpu_init(void) { int cpu = stack_smp_processor_id(); - struct tss_struct *t = &per_cpu(init_tss, cpu); + struct tss_struct *t = init_tss + cpu; struct orig_ist *orig_ist = &per_cpu(orig_ist, cpu); unsigned long v; char *estacks = NULL; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/cpu/common.c linux-2.6.27.15-g-v/arch/x86/kernel/cpu/common.c --- linux-2.6.27.15/arch/x86/kernel/cpu/common.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/cpu/common.c 2009-02-10 20:32:10.000000000 +0100 @@ -4,7 +4,6 @@ #include #include #include -#include #include #include #include @@ -22,42 +21,6 @@ #include "cpu.h" -DEFINE_PER_CPU(struct gdt_page, gdt_page) = { .gdt = { - [GDT_ENTRY_KERNEL_CS] = { { { 0x0000ffff, 0x00cf9a00 } } }, - [GDT_ENTRY_KERNEL_DS] = { { { 0x0000ffff, 0x00cf9200 } } }, - [GDT_ENTRY_DEFAULT_USER_CS] = { { { 0x0000ffff, 0x00cffa00 } } }, - [GDT_ENTRY_DEFAULT_USER_DS] = { { { 0x0000ffff, 0x00cff200 } } }, - /* - * Segments used for calling PnP BIOS have byte granularity. - * They code segments and data segments have fixed 64k limits, - * the transfer segment sizes are set at run time. - */ - /* 32-bit code */ - [GDT_ENTRY_PNPBIOS_CS32] = { { { 0x0000ffff, 0x00409a00 } } }, - /* 16-bit code */ - [GDT_ENTRY_PNPBIOS_CS16] = { { { 0x0000ffff, 0x00009a00 } } }, - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_DS] = { { { 0x0000ffff, 0x00009200 } } }, - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS1] = { { { 0x00000000, 0x00009200 } } }, - /* 16-bit data */ - [GDT_ENTRY_PNPBIOS_TS2] = { { { 0x00000000, 0x00009200 } } }, - /* - * The APM segments have byte granularity and their bases - * are set at run time. All have 64k limits. - */ - /* 32-bit code */ - [GDT_ENTRY_APMBIOS_BASE] = { { { 0x0000ffff, 0x00409a00 } } }, - /* 16-bit code */ - [GDT_ENTRY_APMBIOS_BASE+1] = { { { 0x0000ffff, 0x00009a00 } } }, - /* data */ - [GDT_ENTRY_APMBIOS_BASE+2] = { { { 0x0000ffff, 0x00409200 } } }, - - [GDT_ENTRY_ESPFIX_SS] = { { { 0x00000000, 0x00c09200 } } }, - [GDT_ENTRY_PERCPU] = { { { 0x00000000, 0x00000000 } } }, -} }; -EXPORT_PER_CPU_SYMBOL_GPL(gdt_page); - __u32 cleared_cpu_caps[NCAPINTS] __cpuinitdata; static int cachesize_override __cpuinitdata = -1; @@ -493,6 +456,10 @@ static void __cpuinit identify_cpu(struc * we do "generic changes." */ +#if defined(CONFIG_PAX_SEGMEXEC) || defined(CONFIG_PAX_KERNEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) + setup_clear_cpu_cap(X86_FEATURE_SEP); +#endif + /* If the model name is still unset, do table lookup. */ if (!c->x86_model_id[0]) { char *p; @@ -629,7 +596,7 @@ static __init int setup_disablecpuid(cha } __setup("clearcpuid=", setup_disablecpuid); -cpumask_t cpu_initialized __cpuinitdata = CPU_MASK_NONE; +cpumask_t cpu_initialized = CPU_MASK_NONE; void __init early_cpu_init(void) { @@ -658,7 +625,7 @@ void switch_to_new_gdt(void) { struct desc_ptr gdt_descr; - gdt_descr.address = (long)get_cpu_gdt_table(smp_processor_id()); + gdt_descr.address = (unsigned long)get_cpu_gdt_table(smp_processor_id()); gdt_descr.size = GDT_SIZE - 1; load_gdt(&gdt_descr); asm("mov %0, %%fs" : : "r" (__KERNEL_PERCPU) : "memory"); @@ -674,7 +641,7 @@ void __cpuinit cpu_init(void) { int cpu = smp_processor_id(); struct task_struct *curr = current; - struct tss_struct *t = &per_cpu(init_tss, cpu); + struct tss_struct *t = init_tss + cpu; struct thread_struct *thread = &curr->thread; if (cpu_test_and_set(cpu, cpu_initialized)) { @@ -729,7 +696,7 @@ void __cpuinit cpu_init(void) } #ifdef CONFIG_HOTPLUG_CPU -void __cpuinit cpu_uninit(void) +void cpu_uninit(void) { int cpu = raw_smp_processor_id(); cpu_clear(cpu, cpu_initialized); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c linux-2.6.27.15-g-v/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c --- linux-2.6.27.15/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/cpu/cpufreq/acpi-cpufreq.c 2009-02-10 20:32:10.000000000 +0100 @@ -560,7 +560,7 @@ static const struct dmi_system_id sw_any DMI_MATCH(DMI_PRODUCT_NAME, "X6DLP"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; #endif diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c linux-2.6.27.15-g-v/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c --- linux-2.6.27.15/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/cpu/cpufreq/speedstep-centrino.c 2009-02-10 20:32:10.000000000 +0100 @@ -225,7 +225,7 @@ static struct cpu_model models[] = { &cpu_ids[CPU_MP4HT_D0], NULL, 0, NULL }, { &cpu_ids[CPU_MP4HT_E0], NULL, 0, NULL }, - { NULL, } + { NULL, NULL, 0, NULL} }; #undef _BANIAS #undef BANIAS diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/cpu/intel.c linux-2.6.27.15-g-v/arch/x86/kernel/cpu/intel.c --- linux-2.6.27.15/arch/x86/kernel/cpu/intel.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/cpu/intel.c 2009-02-10 20:32:10.000000000 +0100 @@ -107,7 +107,7 @@ static void __cpuinit trap_init_f00f_bug * Update the IDT descriptor and reload the IDT so that * it uses the read-only mapped virtual address. */ - idt_descr.address = fix_to_virt(FIX_F00F_IDT); + idt_descr.address = (struct desc_struct *)fix_to_virt(FIX_F00F_IDT); load_idt(&idt_descr); } #endif diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/cpu/mcheck/mce_64.c linux-2.6.27.15-g-v/arch/x86/kernel/cpu/mcheck/mce_64.c --- linux-2.6.27.15/arch/x86/kernel/cpu/mcheck/mce_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/cpu/mcheck/mce_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -681,6 +681,7 @@ static struct miscdevice mce_log_device MISC_MCELOG_MINOR, "mcelog", &mce_chrdev_ops, + {NULL, NULL}, NULL, NULL }; static unsigned long old_cr4 __initdata; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/cpu/mtrr/generic.c linux-2.6.27.15-g-v/arch/x86/kernel/cpu/mtrr/generic.c --- linux-2.6.27.15/arch/x86/kernel/cpu/mtrr/generic.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/cpu/mtrr/generic.c 2009-02-10 20:32:10.000000000 +0100 @@ -31,11 +31,11 @@ static struct fixed_range_block fixed_ra { MTRRfix64K_00000_MSR, 1 }, /* one 64k MTRR */ { MTRRfix16K_80000_MSR, 2 }, /* two 16k MTRRs */ { MTRRfix4K_C0000_MSR, 8 }, /* eight 4k MTRRs */ - {} + { 0, 0 } }; static unsigned long smp_changes_mask; -static struct mtrr_state mtrr_state = {}; +static struct mtrr_state mtrr_state; static int mtrr_state_set; u64 mtrr_tom2; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/crash.c linux-2.6.27.15-g-v/arch/x86/kernel/crash.c --- linux-2.6.27.15/arch/x86/kernel/crash.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/crash.c 2009-02-10 20:32:10.000000000 +0100 @@ -59,7 +59,7 @@ static int crash_nmi_callback(struct not local_irq_disable(); #ifdef CONFIG_X86_32 - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { crash_fixup_ss_esp(&fixed_regs, regs); regs = &fixed_regs; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/doublefault_32.c linux-2.6.27.15-g-v/arch/x86/kernel/doublefault_32.c --- linux-2.6.27.15/arch/x86/kernel/doublefault_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/doublefault_32.c 2009-02-10 20:32:10.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 + MAXMEM) @@ -21,7 +21,7 @@ static void doublefault_fn(void) unsigned long gdt, tss; store_gdt(&gdt_desc); - gdt = gdt_desc.address; + gdt = (unsigned long)gdt_desc.address; printk(KERN_EMERG "PANIC: double fault, gdt at %08lx [%d bytes]\n", gdt, gdt_desc.size); @@ -60,10 +60,10 @@ struct tss_struct doublefault_tss __cach /* 0x2 bit is always set */ .flags = X86_EFLAGS_SF | 0x2, .sp = STACK_START, - .es = __USER_DS, + .es = __KERNEL_DS, .cs = __KERNEL_CS, .ss = __KERNEL_DS, - .ds = __USER_DS, + .ds = __KERNEL_DS, .fs = __KERNEL_PERCPU, .__cr3 = __pa(swapper_pg_dir) diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/efi_32.c linux-2.6.27.15-g-v/arch/x86/kernel/efi_32.c --- linux-2.6.27.15/arch/x86/kernel/efi_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/efi_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -38,70 +38,38 @@ */ static unsigned long efi_rt_eflags; -static pgd_t efi_bak_pg_dir_pointer[2]; +static pgd_t __initdata efi_bak_pg_dir_pointer[KERNEL_PGD_PTRS]; -void efi_call_phys_prelog(void) +void __init efi_call_phys_prelog(void) { - unsigned long cr4; - unsigned long temp; struct desc_ptr gdt_descr; local_irq_save(efi_rt_eflags); - /* - * If I don't have PAE, I should just duplicate two entries in page - * directory. If I have PAE, I just need to duplicate one entry in - * page directory. - */ - cr4 = read_cr4_safe(); - if (cr4 & X86_CR4_PAE) { - efi_bak_pg_dir_pointer[0].pgd = - swapper_pg_dir[pgd_index(0)].pgd; - swapper_pg_dir[0].pgd = - swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd; - } else { - efi_bak_pg_dir_pointer[0].pgd = - swapper_pg_dir[pgd_index(0)].pgd; - efi_bak_pg_dir_pointer[1].pgd = - swapper_pg_dir[pgd_index(0x400000)].pgd; - swapper_pg_dir[pgd_index(0)].pgd = - swapper_pg_dir[pgd_index(PAGE_OFFSET)].pgd; - temp = PAGE_OFFSET + 0x400000; - swapper_pg_dir[pgd_index(0x400000)].pgd = - swapper_pg_dir[pgd_index(temp)].pgd; - } + clone_pgd_range(efi_bak_pg_dir_pointer, swapper_pg_dir, KERNEL_PGD_PTRS); + clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); /* * After the lock is released, the original page table is restored. */ __flush_tlb_all(); - gdt_descr.address = __pa(get_cpu_gdt_table(0)); + gdt_descr.address = (struct desc_struct *)__pa(get_cpu_gdt_table(0)); gdt_descr.size = GDT_SIZE - 1; load_gdt(&gdt_descr); } -void efi_call_phys_epilog(void) +void __init efi_call_phys_epilog(void) { - unsigned long cr4; struct desc_ptr gdt_descr; - gdt_descr.address = (unsigned long)get_cpu_gdt_table(0); + gdt_descr.address = get_cpu_gdt_table(0); gdt_descr.size = GDT_SIZE - 1; load_gdt(&gdt_descr); - cr4 = read_cr4_safe(); - - if (cr4 & X86_CR4_PAE) { - swapper_pg_dir[pgd_index(0)].pgd = - efi_bak_pg_dir_pointer[0].pgd; - } else { - swapper_pg_dir[pgd_index(0)].pgd = - efi_bak_pg_dir_pointer[0].pgd; - swapper_pg_dir[pgd_index(0x400000)].pgd = - efi_bak_pg_dir_pointer[1].pgd; - } + clone_pgd_range(swapper_pg_dir, efi_bak_pg_dir_pointer, KERNEL_PGD_PTRS); /* * After the lock is released, the original page table is restored. diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/efi_stub_32.S linux-2.6.27.15-g-v/arch/x86/kernel/efi_stub_32.S --- linux-2.6.27.15/arch/x86/kernel/efi_stub_32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/efi_stub_32.S 2009-02-10 20:32:10.000000000 +0100 @@ -6,6 +6,7 @@ */ #include +#include #include /* @@ -20,7 +21,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 @@ -36,9 +37,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: /* @@ -47,14 +46,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. @@ -73,9 +66,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. @@ -88,34 +80,27 @@ ENTRY(efi_call_phys) 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 + jmp 1f+__PAGE_OFFSET 1: /* * 9. Balance the stack. And because EAX contain the return value, * we'd better not clobber it. */ - leal efi_rt_function_ptr, %edx - movl (%edx), %ecx - pushl %ecx + pushl (efi_rt_function_ptr) /* - * 10. Push the saved return address onto the stack and return. + * 10. Return to the saved return address. */ - leal saved_return_addr, %edx - movl (%edx), %ecx - pushl %ecx - ret + jmpl *(saved_return_addr) .previous -.data +__INITDATA saved_return_addr: .long 0 efi_rt_function_ptr: diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/entry_32.S linux-2.6.27.15-g-v/arch/x86/kernel/entry_32.S --- linux-2.6.27.15/arch/x86/kernel/entry_32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/entry_32.S 2009-02-10 20:32:10.000000000 +0100 @@ -101,7 +101,7 @@ #define resume_userspace_sig resume_userspace #endif -#define SAVE_ALL \ +#define __SAVE_ALL(_DS) \ cld; \ pushl %fs; \ CFI_ADJUST_CFA_OFFSET 4;\ @@ -133,12 +133,26 @@ pushl %ebx; \ CFI_ADJUST_CFA_OFFSET 4;\ CFI_REL_OFFSET ebx, 0;\ - movl $(__USER_DS), %edx; \ + movl $(_DS), %edx; \ movl %edx, %ds; \ movl %edx, %es; \ movl $(__KERNEL_PERCPU), %edx; \ movl %edx, %fs +#ifdef CONFIG_PAX_KERNEXEC +#define SAVE_ALL \ + __SAVE_ALL(__KERNEL_DS); \ + GET_CR0_INTO_EDX; \ + movl %edx, %esi; \ + orl $X86_CR0_WP, %edx; \ + xorl %edx, %esi; \ + SET_CR0_FROM_EDX +#elif defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) || defined(CONFIG_PAX_MEMORY_UDEREF) +#define SAVE_ALL __SAVE_ALL(__KERNEL_DS) +#else +#define SAVE_ALL __SAVE_ALL(__USER_DS) +#endif + #define RESTORE_INT_REGS \ popl %ebx; \ CFI_ADJUST_CFA_OFFSET -4;\ @@ -229,6 +243,11 @@ ENTRY(ret_from_fork) CFI_ADJUST_CFA_OFFSET 4 popfl CFI_ADJUST_CFA_OFFSET -4 + +#ifdef CONFIG_PAX_KERNEXEC + xorl %esi, %esi +#endif + jmp syscall_exit CFI_ENDPROC END(ret_from_fork) @@ -252,7 +271,17 @@ check_userspace: movb PT_CS(%esp), %al andl $(X86_EFLAGS_VM | SEGMENT_RPL_MASK), %eax cmpl $USER_RPL, %eax + +#ifdef CONFIG_PAX_KERNEXEC + jae resume_userspace + + GET_CR0_INTO_EDX + xorl %esi, %edx + SET_CR0_FROM_EDX + jmp resume_kernel +#else jb resume_kernel # not returning to v8086 or userspace +#endif ENTRY(resume_userspace) LOCKDEP_SYS_EXIT @@ -314,10 +343,9 @@ sysenter_past_esp: /*CFI_REL_OFFSET cs, 0*/ /* * Push current_thread_info()->sysenter_return to the stack. - * A tiny bit of offset fixup is necessary - 4*4 means the 4 words - * pushed above; +8 corresponds to copy_thread's esp0 setting. */ - pushl (TI_sysenter_return-THREAD_SIZE+8+4*4)(%esp) + GET_THREAD_INFO(%ebp) + pushl TI_sysenter_return(%ebp) CFI_ADJUST_CFA_OFFSET 4 CFI_REL_OFFSET eip, 0 @@ -330,9 +358,17 @@ sysenter_past_esp: * Load the potential sixth argument from user stack. * Careful about security. */ + movl PT_OLDESP(%esp),%ebp + +#ifdef CONFIG_PAX_MEMORY_UDEREF + mov PT_OLDSS(%esp),%ds +1: movl %ds:(%ebp),%ebp +#else cmpl $__PAGE_OFFSET-3,%ebp jae syscall_fault 1: movl (%ebp),%ebp +#endif + movl %ebp,PT_EBP(%esp) .section __ex_table,"a" .align 4 @@ -356,12 +392,23 @@ sysenter_do_call: testw $_TIF_ALLWORK_MASK, %cx jne sysexit_audit sysenter_exit: + +#ifdef CONFIG_PAX_RANDKSTACK + pushl %eax + CFI_ADJUST_CFA_OFFSET 4 + call pax_randomize_kstack + popl %eax + CFI_ADJUST_CFA_OFFSET -4 +#endif + /* if something modifies registers it must also disable sysexit */ movl PT_EIP(%esp), %edx movl PT_OLDESP(%esp), %ecx xorl %ebp,%ebp TRACE_IRQS_ON 1: mov PT_FS(%esp), %fs +2: mov PT_DS(%esp), %ds +3: mov PT_ES(%esp), %es ENABLE_INTERRUPTS_SYSEXIT #ifdef CONFIG_AUDITSYSCALL @@ -404,11 +451,17 @@ sysexit_audit: CFI_ENDPROC .pushsection .fixup,"ax" -2: movl $0,PT_FS(%esp) +4: movl $0,PT_FS(%esp) + jmp 1b +5: movl $0,PT_DS(%esp) + jmp 1b +6: movl $0,PT_ES(%esp) jmp 1b .section __ex_table,"a" .align 4 - .long 1b,2b + .long 1b,4b + .long 2b,5b + .long 3b,6b .popsection ENDPROC(ia32_sysenter_target) @@ -438,6 +491,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 PT_EFLAGS(%esp), %eax # mix EFLAGS, SS and CS # Warning: PT_OLDSS(%esp) contains the wrong/random values if we @@ -531,25 +588,19 @@ work_resched: work_notifysig: # deal with pending signals and # notify-resume requests + movl %esp, %eax #ifdef CONFIG_VM86 testl $X86_EFLAGS_VM, PT_EFLAGS(%esp) - movl %esp, %eax - jne work_notifysig_v86 # returning to kernel-space or + jz 1f # returning to kernel-space or # vm86-space - xorl %edx, %edx - call do_notify_resume - jmp resume_userspace_sig - ALIGN -work_notifysig_v86: pushl %ecx # save ti_flags for do_notify_resume CFI_ADJUST_CFA_OFFSET 4 call save_v86_state # %eax contains pt_regs pointer popl %ecx CFI_ADJUST_CFA_OFFSET -4 movl %eax, %esp -#else - movl %esp, %eax +1: #endif xorl %edx, %edx call do_notify_resume @@ -595,17 +646,24 @@ syscall_badsys: END(syscall_badsys) CFI_ENDPROC -#define FIXUP_ESPFIX_STACK \ - /* since we are on a wrong stack, we cant make it a C code :( */ \ - PER_CPU(gdt_page, %ebx); \ - GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); \ - addl %esp, %eax; \ - pushl $__KERNEL_DS; \ - CFI_ADJUST_CFA_OFFSET 4; \ - pushl %eax; \ - CFI_ADJUST_CFA_OFFSET 4; \ - lss (%esp), %esp; \ +.macro FIXUP_ESPFIX_STACK + /* since we are on a wrong stack, we cant make it a C code :( */ +#ifdef CONFIG_SMP + movl PER_CPU_VAR(cpu_number), %ebx; + shll $PAGE_SHIFT_asm, %ebx; + addl $cpu_gdt_table, %ebx; +#else + movl $cpu_gdt_table, %ebx; +#endif + GET_DESC_BASE(GDT_ENTRY_ESPFIX_SS, %ebx, %eax, %ax, %al, %ah); + addl %esp, %eax; + pushl $__KERNEL_DS; + CFI_ADJUST_CFA_OFFSET 4; + pushl %eax; + CFI_ADJUST_CFA_OFFSET 4; + lss (%esp), %esp; CFI_ADJUST_CFA_OFFSET -8; +.endm #define UNWIND_ESPFIX_STACK \ movl %ss, %eax; \ /* see if on espfix stack */ \ @@ -622,7 +680,7 @@ END(syscall_badsys) * Build the entry stubs and pointer table with * some assembler magic. */ -.section .rodata,"a" +.section .rodata,"a",@progbits ENTRY(interrupt) .text @@ -722,12 +780,21 @@ error_code: popl %ecx CFI_ADJUST_CFA_OFFSET -4 /*CFI_REGISTER es, ecx*/ + +#ifdef CONFIG_PAX_KERNEXEC + GET_CR0_INTO_EDX + movl %edx, %esi + orl $X86_CR0_WP, %edx + xorl %edx, %esi + SET_CR0_FROM_EDX +#endif + movl PT_FS(%esp), %edi # get the function address movl PT_ORIG_EAX(%esp), %edx # get the error code movl $-1, PT_ORIG_EAX(%esp) # no syscall to restart mov %ecx, PT_FS(%esp) /*CFI_REL_OFFSET fs, ES*/ - movl $(__USER_DS), %ecx + movl $(__KERNEL_DS), %ecx movl %ecx, %ds movl %ecx, %es movl %esp,%eax # pt_regs pointer @@ -861,6 +928,13 @@ nmi_stack_correct: xorl %edx,%edx # zero error code movl %esp,%eax # pt_regs pointer call do_nmi + +#ifdef CONFIG_PAX_KERNEXEC + GET_CR0_INTO_EDX + xorl %esi, %edx + SET_CR0_FROM_EDX +#endif + jmp restore_nocheck_notrace CFI_ENDPROC @@ -901,6 +975,13 @@ nmi_espfix_stack: FIXUP_ESPFIX_STACK # %eax == %esp xorl %edx,%edx # zero error code call do_nmi + +#ifdef CONFIG_PAX_KERNEXEC + GET_CR0_INTO_EDX + xorl %esi, %edx + SET_CR0_FROM_EDX +#endif + RESTORE_REGS lss 12+4(%esp), %esp # back to espfix stack CFI_ADJUST_CFA_OFFSET -24 @@ -1226,7 +1307,6 @@ END(mcount) #endif /* CONFIG_DYNAMIC_FTRACE */ #endif /* CONFIG_FTRACE */ -.section .rodata,"a" #include "syscall_table_32.S" syscall_table_size=(.-sys_call_table) diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/entry_64.S linux-2.6.27.15-g-v/arch/x86/kernel/entry_64.S --- linux-2.6.27.15/arch/x86/kernel/entry_64.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/entry_64.S 2009-02-10 20:32:10.000000000 +0100 @@ -930,17 +930,18 @@ END(spurious_interrupt) xorl %ebx,%ebx 1: .if \ist - movq %gs:pda_data_offset, %rbp + imul $TSS_size, %gs:pda_cpunumber, %ebp + lea init_tss(%rbp), %rbp .endif movq %rsp,%rdi movq ORIG_RAX(%rsp),%rsi movq $-1,ORIG_RAX(%rsp) .if \ist - subq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) + subq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%rbp) .endif call \sym .if \ist - addq $EXCEPTION_STKSZ, per_cpu__init_tss + TSS_ist + (\ist - 1) * 8(%rbp) + addq $EXCEPTION_STKSZ, TSS_ist + (\ist - 1) * 8(%rbp) .endif DISABLE_INTERRUPTS(CLBR_NONE) .if \irqtrace diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/ftrace.c linux-2.6.27.15-g-v/arch/x86/kernel/ftrace.c --- linux-2.6.27.15/arch/x86/kernel/ftrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/ftrace.c 2009-02-10 20:32:10.000000000 +0100 @@ -103,9 +103,9 @@ notrace int ftrace_update_ftrace_func(ft unsigned char old[MCOUNT_INSN_SIZE], *new; int ret; - memcpy(old, &ftrace_call, MCOUNT_INSN_SIZE); + memcpy(old, (void *)ktla_ktva((unsigned long)ftrace_call), MCOUNT_INSN_SIZE); new = ftrace_call_replace(ip, (unsigned long)func); - ret = ftrace_modify_code(ip, old, new); + ret = ftrace_modify_code(ktla_ktva(ip), old, new); return ret; } @@ -120,9 +120,9 @@ notrace int ftrace_mcount_set(unsigned l * Replace the mcount stub with a pointer to the * ip recorder function. */ - memcpy(old, &mcount_call, MCOUNT_INSN_SIZE); + memcpy(old, ktla_ktva(mcount_call), MCOUNT_INSN_SIZE); new = ftrace_call_replace(ip, *addr); - *addr = ftrace_modify_code(ip, old, new); + *addr = ftrace_modify_code(ktla_ktva(ip), old, new); return 0; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/head32.c linux-2.6.27.15-g-v/arch/x86/kernel/head32.c --- linux-2.6.27.15/arch/x86/kernel/head32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/head32.c 2009-02-10 20:32:10.000000000 +0100 @@ -12,10 +12,11 @@ #include #include #include +#include void __init i386_start_kernel(void) { - reserve_early(__pa_symbol(&_text), __pa_symbol(&_end), "TEXT DATA BSS"); + reserve_early(LOAD_PHYSICAL_ADDR, __pa_symbol(&_end), "TEXT DATA BSS"); #ifdef CONFIG_BLK_DEV_INITRD /* Reserve INITRD */ diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/head_32.S linux-2.6.27.15-g-v/arch/x86/kernel/head_32.S --- linux-2.6.27.15/arch/x86/kernel/head_32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/head_32.S 2009-02-10 20:32:10.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include /* Physical address */ #define pa(X) ((X) - __PAGE_OFFSET) @@ -64,17 +65,22 @@ LOW_PAGES = 1<<(32-PAGE_SHIFT_asm) LOW_PAGES = LOW_PAGES + 0x1000000 #endif -#if PTRS_PER_PMD > 1 -PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PMD) + PTRS_PER_PGD -#else -PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PGD) -#endif +PAGE_TABLE_SIZE = (LOW_PAGES / PTRS_PER_PTE) BOOTBITMAP_SIZE = LOW_PAGES / 8 ALLOCATOR_SLOP = 4 INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + (PAGE_TABLE_SIZE + ALLOCATOR_SLOP)*PAGE_SIZE_asm /* + * Real beginning of normal "text" segment + */ +ENTRY(stext) +ENTRY(_stext) + +.section .text.startup,"ax",@progbits + ljmp $(__BOOT_CS),$phys_startup_32 + +/* * 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 @@ -82,6 +88,12 @@ INIT_MAP_BEYOND_END = BOOTBITMAP_SIZE + * can. */ .section .text.head,"ax",@progbits + +#ifdef CONFIG_PAX_KERNEXEC +/* PaX: fill first page in .text with int3 to catch NULL derefs in kernel mode */ +.fill 4096,1,0xcc +#endif + ENTRY(startup_32) /* test KEEP_SEGMENTS flag to see if the bootloader is asking us to not reload segments */ @@ -99,6 +111,56 @@ ENTRY(startup_32) movl %eax,%gs 2: + movl $pa(cpu_gdt_table),%edi + movl $__per_cpu_start,%eax + movw %ax,__KERNEL_PERCPU + 2(%edi) + rorl $16,%eax + movb %al,__KERNEL_PERCPU + 4(%edi) + movb %ah,__KERNEL_PERCPU + 7(%edi) + movl $__per_cpu_end + PERCPU_MODULE_RESERVE - 1,%eax + subl $__per_cpu_start,%eax + movw %ax,__KERNEL_PERCPU + 0(%edi) + +#ifdef CONFIG_PAX_MEMORY_UDEREF + /* check for VMware */ + movl $0x564d5868,%eax + xorl %ebx,%ebx + movl $0xa,%ecx + movl $0x5658,%edx + in (%dx),%eax + cmpl $0x564d5868,%ebx + jz 2f + + movl $NR_CPUS,%ecx + movl $pa(cpu_gdt_table),%edi +1: + movl $((((__PAGE_OFFSET-1) & 0xf0000000) >> 12) | 0x00c09700),GDT_ENTRY_KERNEL_DS * 8 + 4(%edi) + addl $PAGE_SIZE_asm,%edi + loop 1b +2: +#endif + +#ifdef CONFIG_PAX_KERNEXEC + movl $pa(boot_gdt),%edi + movl $KERNEL_TEXT_OFFSET,%eax + movw %ax,__BOOT_CS + 2(%edi) + rorl $16,%eax + movb %al,__BOOT_CS + 4(%edi) + movb %ah,__BOOT_CS + 7(%edi) + rorl $16,%eax + + movl $NR_CPUS,%ecx + movl $pa(cpu_gdt_table),%edi +1: + movw %ax,__KERNEL_CS + 2(%edi) + rorl $16,%eax + movb %al,__KERNEL_CS + 4(%edi) + movb %ah,__KERNEL_CS + 7(%edi) + rorl $16,%eax + addl $PAGE_SIZE_asm,%edi + loop 1b +#endif + /* * Clear BSS first so that there are no surprises... */ @@ -142,9 +204,7 @@ ENTRY(startup_32) cmpl $num_subarch_entries, %eax jae bad_subarch - movl pa(subarch_entries)(,%eax,4), %eax - subl $__PAGE_OFFSET, %eax - jmp *%eax + jmp *pa(subarch_entries)(,%eax,4) bad_subarch: WEAK(lguest_entry) @@ -156,9 +216,9 @@ WEAK(xen_entry) __INITDATA subarch_entries: - .long default_entry /* normal x86/PC */ - .long lguest_entry /* lguest hypervisor */ - .long xen_entry /* Xen hypervisor */ + .long pa(default_entry) /* normal x86/PC */ + .long pa(lguest_entry) /* lguest hypervisor */ + .long pa(xen_entry) /* Xen hypervisor */ num_subarch_entries = (. - subarch_entries) / 4 .previous #endif /* CONFIG_PARAVIRT */ @@ -172,7 +232,7 @@ num_subarch_entries = (. - subarch_entri * * Note that the stack is not yet set up! */ -#define PTE_ATTR 0x007 /* PRESENT+RW+USER */ +#define PTE_ATTR 0x067 /* PRESENT+RW+USER+DIRTY+ACCESSED */ #define PDE_ATTR 0x067 /* PRESENT+RW+USER+DIRTY+ACCESSED */ #define PGD_ATTR 0x001 /* PRESENT (no other attributes) */ @@ -224,8 +284,7 @@ default_entry: movl %eax, pa(max_pfn_mapped) /* Do early initialization of the fixmap area */ - movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax - movl %eax,pa(swapper_pg_pmd+0x1000*KPMDS-8) + movl $pa(swapper_pg_fixmap)+PDE_ATTR,pa(swapper_pg_pmd+0x1000*KPMDS-8) #else /* Not PAE */ page_pde_offset = (__PAGE_OFFSET >> 20); @@ -257,8 +316,7 @@ page_pde_offset = (__PAGE_OFFSET >> 20); movl %eax, pa(max_pfn_mapped) /* Do early initialization of the fixmap area */ - movl $pa(swapper_pg_fixmap)+PDE_ATTR,%eax - movl %eax,pa(swapper_pg_dir+0xffc) + movl $pa(swapper_pg_fixmap)+PDE_ATTR,pa(swapper_pg_dir+0xffc) #endif jmp 3f /* @@ -322,13 +380,16 @@ ENTRY(startup_32_smp) jnc 6f /* Setup EFER (Extended Feature Enable Register) */ - movl $0xc0000080, %ecx + movl $MSR_EFER, %ecx rdmsr btsl $11, %eax /* Make changes effective */ wrmsr + btsl $63-32,pa(__supported_pte_mask+4) + movl $1,pa(nx_enabled) + 6: /* @@ -354,9 +415,7 @@ ENTRY(startup_32_smp) #ifdef CONFIG_SMP cmpb $0, ready - jz 1f /* Initial CPU cleans BSS */ - jmp checkCPUtype -1: + jnz checkCPUtype /* Initial CPU cleans BSS */ #endif /* CONFIG_SMP */ /* @@ -433,12 +492,12 @@ is386: movl $2,%ecx # set MP ljmp $(__KERNEL_CS),$1f 1: movl $(__KERNEL_DS),%eax # reload all the segment registers movl %eax,%ss # after changing gdt. - movl %eax,%fs # gets reset once there's real percpu - - movl $(__USER_DS),%eax # DS/ES contains default USER segment movl %eax,%ds movl %eax,%es + movl $(__KERNEL_PERCPU), %eax + movl %eax,%fs # set this cpu's percpu + xorl %eax,%eax # Clear GS and LDT movl %eax,%gs lldt %ax @@ -448,12 +507,6 @@ is386: movl $2,%ecx # set MP #ifdef CONFIG_SMP movb ready, %cl movb $1, ready - cmpb $0,%cl # the first CPU calls start_kernel - je 1f - movl $(__KERNEL_PERCPU), %eax - movl %eax,%fs # set this cpu's percpu - movl (stack_start), %esp -1: #endif /* CONFIG_SMP */ jmp *(initial_code) @@ -539,15 +592,15 @@ early_page_fault: jmp early_fault early_fault: - cld #ifdef CONFIG_PRINTK + cmpl $2,%ss:early_recursion_flag + je hlt_loop + incl %ss:early_recursion_flag + cld pusha movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es - cmpl $2,early_recursion_flag - je hlt_loop - incl early_recursion_flag movl %cr2,%eax pushl %eax pushl %edx /* trapno */ @@ -557,8 +610,8 @@ early_fault: #else call printk #endif -#endif call dump_stack +#endif hlt_loop: hlt jmp hlt_loop @@ -566,8 +619,11 @@ hlt_loop: /* This is the default interrupt "handler" :-) */ ALIGN ignore_int: - cld #ifdef CONFIG_PRINTK + cmpl $2,%ss:early_recursion_flag + je hlt_loop + incl %ss:early_recursion_flag + cld pushl %eax pushl %ecx pushl %edx @@ -576,9 +632,6 @@ ignore_int: movl $(__KERNEL_DS),%eax movl %eax,%ds movl %eax,%es - cmpl $2,early_recursion_flag - je hlt_loop - incl early_recursion_flag pushl 16(%esp) pushl 24(%esp) pushl 32(%esp) @@ -603,36 +656,41 @@ ignore_int: ENTRY(initial_code) .long i386_start_kernel -.section .text -/* - * Real beginning of normal "text" segment - */ -ENTRY(stext) -ENTRY(_stext) - /* * BSS section */ -.section ".bss.page_aligned","wa" - .align PAGE_SIZE_asm #ifdef CONFIG_X86_PAE +.section .swapper_pg_pmd,"a",@progbits swapper_pg_pmd: .fill 1024*KPMDS,4,0 #else +.section .swapper_pg_dir,"a",@progbits ENTRY(swapper_pg_dir) .fill 1024,4,0 #endif swapper_pg_fixmap: .fill 1024,4,0 + +.section .empty_zero_page,"a",@progbits ENTRY(empty_zero_page) .fill 4096,1,0 + +/* + * The IDT has to be page-aligned to simplify the Pentium + * F0 0F bug workaround.. We have a special link segment + * for this. + */ +.section .idt,"a",@progbits +ENTRY(idt_table) + .fill 256,8,0 + /* * This starts the data section. */ +.data + #ifdef CONFIG_X86_PAE -.section ".data.page_aligned","wa" - /* Page-aligned for the benefit of paravirt? */ - .align PAGE_SIZE_asm +.section .swapper_pg_dir,"a",@progbits ENTRY(swapper_pg_dir) .long pa(swapper_pg_pmd+PGD_ATTR),0 /* low identity map */ # if KPMDS == 3 @@ -655,11 +713,12 @@ ENTRY(swapper_pg_dir) .data ENTRY(stack_start) - .long init_thread_union+THREAD_SIZE + .long init_thread_union+THREAD_SIZE-8 .long __BOOT_DS ready: .byte 0 +.section .rodata,"a",@progbits early_recursion_flag: .long 0 @@ -695,7 +754,7 @@ fault_msg: .word 0 # 32 bit align gdt_desc.address boot_gdt_descr: .word __BOOT_DS+7 - .long boot_gdt - __PAGE_OFFSET + .long pa(boot_gdt) .word 0 # 32-bit align idt_desc.address idt_descr: @@ -706,7 +765,7 @@ idt_descr: .word 0 # 32 bit align gdt_desc.address ENTRY(early_gdt_descr) .word GDT_ENTRIES*8-1 - .long per_cpu__gdt_page /* Overwritten for secondary CPUs */ + .long cpu_gdt_table /* Overwritten for secondary CPUs */ /* * The boot_gdt must mirror the equivalent in setup.S and is @@ -715,5 +774,59 @@ ENTRY(early_gdt_descr) .align L1_CACHE_BYTES ENTRY(boot_gdt) .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 */ + + .align PAGE_SIZE_asm +ENTRY(cpu_gdt_table) + .rept NR_CPUS + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x0000000000000000 /* 0x0b reserved */ + .quad 0x0000000000000000 /* 0x13 reserved */ + .quad 0x0000000000000000 /* 0x1b reserved */ + .quad 0x0000000000000000 /* 0x20 unused */ + .quad 0x0000000000000000 /* 0x28 unused */ + .quad 0x0000000000000000 /* 0x33 TLS entry 1 */ + .quad 0x0000000000000000 /* 0x3b TLS entry 2 */ + .quad 0x0000000000000000 /* 0x43 TLS entry 3 */ + .quad 0x0000000000000000 /* 0x4b reserved */ + .quad 0x0000000000000000 /* 0x53 reserved */ + .quad 0x0000000000000000 /* 0x5b reserved */ + + .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 have byte granularity. + * The code segments and data segments have fixed 64k limits, + * the transfer segment sizes are set at run time. + */ + .quad 0x00409b000000ffff /* 0x90 32-bit code */ + .quad 0x00009b000000ffff /* 0x98 16-bit code */ + .quad 0x000093000000ffff /* 0xa0 16-bit data */ + .quad 0x0000930000000000 /* 0xa8 16-bit data */ + .quad 0x0000930000000000 /* 0xb0 16-bit data */ + + /* + * The APM segments have byte granularity and their bases + * are set at run time. All have 64k limits. + */ + .quad 0x00409b000000ffff /* 0xb8 APM CS code */ + .quad 0x00009b000000ffff /* 0xc0 APM CS 16 code (16 bit) */ + .quad 0x004093000000ffff /* 0xc8 APM DS data */ + + .quad 0x00c0930000000000 /* 0xd0 - ESPFIX SS */ + .quad 0x0040930000000000 /* 0xd8 - PERCPU */ + .quad 0x0000000000000000 /* 0xe0 - PCIBIOS_CS */ + .quad 0x0000000000000000 /* 0xe8 - PCIBIOS_DS */ + .quad 0x0000000000000000 /* 0xf0 - unused */ + .quad 0x0000000000000000 /* 0xf8 - GDT entry 31: double-fault TSS */ + + /* Be sure this is zeroed to avoid false validations in Xen */ + .fill PAGE_SIZE_asm - GDT_SIZE,1,0 + .endr diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/head64.c linux-2.6.27.15-g-v/arch/x86/kernel/head64.c --- linux-2.6.27.15/arch/x86/kernel/head64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/head64.c 2009-02-10 20:32:10.000000000 +0100 @@ -93,6 +93,8 @@ void __init x86_64_start_kernel(char * r /* clear bss before set_intr_gate with early_idt_handler */ clear_bss(); + x86_64_init_pda(); + /* Make NULL pointers segfault */ zap_identity_mappings(); @@ -110,8 +112,6 @@ void __init x86_64_start_kernel(char * r early_printk("Kernel alive\n"); - x86_64_init_pda(); - early_printk("Kernel really alive\n"); x86_64_start_reservations(real_mode_data); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/head_64.S linux-2.6.27.15-g-v/arch/x86/kernel/head_64.S --- linux-2.6.27.15/arch/x86/kernel/head_64.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/head_64.S 2009-02-10 20:32:10.000000000 +0100 @@ -38,6 +38,10 @@ L4_PAGE_OFFSET = pgd_index(__PAGE_OFFSET L3_PAGE_OFFSET = pud_index(__PAGE_OFFSET) L4_START_KERNEL = pgd_index(__START_KERNEL_map) L3_START_KERNEL = pud_index(__START_KERNEL_map) +L4_VMALLOC_START = pgd_index(VMALLOC_START) +L3_VMALLOC_START = pud_index(VMALLOC_START) +L4_VMEMMAP_START = pgd_index(VMEMMAP_START) +L3_VMEMMAP_START = pud_index(VMEMMAP_START) .text .section .text.head @@ -85,14 +89,17 @@ startup_64: */ addq %rbp, init_level4_pgt + 0(%rip) addq %rbp, init_level4_pgt + (L4_PAGE_OFFSET*8)(%rip) + addq %rbp, init_level4_pgt + (L4_VMALLOC_START*8)(%rip) + addq %rbp, init_level4_pgt + (L4_VMEMMAP_START*8)(%rip) addq %rbp, init_level4_pgt + (L4_START_KERNEL*8)(%rip) addq %rbp, level3_ident_pgt + 0(%rip) - addq %rbp, level3_kernel_pgt + (510*8)(%rip) - addq %rbp, level3_kernel_pgt + (511*8)(%rip) + addq %rbp, level3_kernel_pgt + (L3_START_KERNEL*8)(%rip) + addq %rbp, level3_kernel_pgt + (L3_START_KERNEL*8+8)(%rip) addq %rbp, level2_fixmap_pgt + (506*8)(%rip) + addq %rbp, level2_fixmap_pgt + (507*8)(%rip) /* Add an Identity mapping if I am above 1G */ leaq _text(%rip), %rdi @@ -187,6 +194,10 @@ ENTRY(secondary_startup_64) btl $20,%edi /* No Execute supported? */ jnc 1f btsl $_EFER_NX, %eax + leaq init_level4_pgt(%rip), %rdi + btsq $_PAGE_BIT_NX, 8*L4_PAGE_OFFSET(%rdi) + btsq $_PAGE_BIT_NX, 8*L4_VMALLOC_START(%rdi) + btsq $_PAGE_BIT_NX, 8*L4_VMEMMAP_START(%rdi) 1: wrmsr /* Make changes effective */ /* Setup cr0 */ @@ -257,16 +268,16 @@ ENTRY(secondary_startup_64) .align 8 ENTRY(initial_code) .quad x86_64_start_kernel - __FINITDATA ENTRY(stack_start) .quad init_thread_union+THREAD_SIZE-8 .word 0 + __FINITDATA bad_address: jmp bad_address - .section ".init.text","ax" + __INIT #ifdef CONFIG_EARLY_PRINTK .globl early_idt_handlers early_idt_handlers: @@ -311,18 +322,23 @@ ENTRY(early_idt_handler) #endif /* EARLY_PRINTK */ 1: hlt jmp 1b + .previous #ifdef CONFIG_EARLY_PRINTK + __INITDATA early_recursion_flag: .long 0 + .previous + .section .rodata,"a",@progbits early_idt_msg: .asciz "PANIC: early exception %02lx rip %lx:%lx error %lx cr2 %lx\n" early_idt_ripmsg: .asciz "RIP %s\n" -#endif /* CONFIG_EARLY_PRINTK */ .previous +#endif /* CONFIG_EARLY_PRINTK */ + .section .rodata,"a",@progbits .balign PAGE_SIZE #define NEXT_PAGE(name) \ @@ -347,6 +363,10 @@ NEXT_PAGE(init_level4_pgt) .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE .org init_level4_pgt + L4_PAGE_OFFSET*8, 0 .quad level3_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE + .org init_level4_pgt + L4_VMALLOC_START*8, 0 + .quad level3_vmalloc_pgt - __START_KERNEL_map + _KERNPG_TABLE + .org init_level4_pgt + L4_VMEMMAP_START*8, 0 + .quad level3_vmemmap_pgt - __START_KERNEL_map + _KERNPG_TABLE .org init_level4_pgt + L4_START_KERNEL*8, 0 /* (2^48-(2*1024*1024*1024))/(2^39) = 511 */ .quad level3_kernel_pgt - __START_KERNEL_map + _PAGE_TABLE @@ -355,6 +375,12 @@ NEXT_PAGE(level3_ident_pgt) .quad level2_ident_pgt - __START_KERNEL_map + _KERNPG_TABLE .fill 511,8,0 +NEXT_PAGE(level3_vmalloc_pgt) + .fill 512,8,0 + +NEXT_PAGE(level3_vmemmap_pgt) + .fill 512,8,0 + NEXT_PAGE(level3_kernel_pgt) .fill L3_START_KERNEL,8,0 /* (2^48-(2*1024*1024*1024)-((2^39)*511))/(2^30) = 510 */ @@ -364,12 +390,16 @@ NEXT_PAGE(level3_kernel_pgt) NEXT_PAGE(level2_fixmap_pgt) .fill 506,8,0 .quad level1_fixmap_pgt - __START_KERNEL_map + _PAGE_TABLE - /* 8MB reserved for vsyscalls + a 2MB hole = 4 + 1 entries */ - .fill 5,8,0 + .quad level1_vsyscall_pgt - __START_KERNEL_map + _PAGE_TABLE + /* 6MB reserved for vsyscalls + a 2MB hole = 3 + 1 entries */ + .fill 4,8,0 NEXT_PAGE(level1_fixmap_pgt) .fill 512,8,0 +NEXT_PAGE(level1_vsyscall_pgt) + .fill 512,8,0 + NEXT_PAGE(level2_ident_pgt) /* Since I easily can, map the first 1G. * Don't set NX because code runs from these pages. @@ -396,19 +426,39 @@ NEXT_PAGE(level2_spare_pgt) #undef PMDS #undef NEXT_PAGE - .data + .align PAGE_SIZE +ENTRY(cpu_gdt_table) + .rept NR_CPUS + .quad 0x0000000000000000 /* NULL descriptor */ + .quad 0x00cf9b000000ffff /* __KERNEL32_CS */ + .quad 0x00af9b000000ffff /* __KERNEL_CS */ + .quad 0x00cf93000000ffff /* __KERNEL_DS */ + .quad 0x00cffb000000ffff /* __USER32_CS */ + .quad 0x00cff3000000ffff /* __USER_DS, __USER32_DS */ + .quad 0x00affb000000ffff /* __USER_CS */ + .quad 0x0 /* unused */ + .quad 0,0 /* TSS */ + .quad 0,0 /* LDT */ + .quad 0,0,0 /* three TLS descriptors */ + .quad 0x0000f40000000000 /* node/CPU stored in limit */ + /* asm/segment.h:GDT_ENTRIES must match this */ + + /* zero the remaining page */ + .fill PAGE_SIZE / 8 - GDT_ENTRIES,8,0 + .endr + .align 16 .globl early_gdt_descr early_gdt_descr: .word GDT_ENTRIES*8-1 - .quad per_cpu__gdt_page + .quad cpu_gdt_table ENTRY(phys_base) /* This must match the first entry in level2_kernel_pgt */ .quad 0x0000000000000000 #include "../../x86/xen/xen-head.S" - + .section .bss, "aw", @nobits .align L1_CACHE_BYTES ENTRY(idt_table) diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/i386_ksyms_32.c linux-2.6.27.15-g-v/arch/x86/kernel/i386_ksyms_32.c --- linux-2.6.27.15/arch/x86/kernel/i386_ksyms_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/i386_ksyms_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -10,8 +10,12 @@ EXPORT_SYMBOL(mcount); #endif +EXPORT_SYMBOL_GPL(cpu_gdt_table); + /* Networking helper routines. */ EXPORT_SYMBOL(csum_partial_copy_generic); +EXPORT_SYMBOL(csum_partial_copy_generic_to_user); +EXPORT_SYMBOL(csum_partial_copy_generic_from_user); EXPORT_SYMBOL(__get_user_1); EXPORT_SYMBOL(__get_user_2); @@ -26,3 +30,7 @@ EXPORT_SYMBOL(strstr); EXPORT_SYMBOL(csum_partial); EXPORT_SYMBOL(empty_zero_page); + +#ifdef CONFIG_PAX_KERNEXEC +EXPORT_SYMBOL(KERNEL_TEXT_OFFSET); +#endif diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/init_task.c linux-2.6.27.15-g-v/arch/x86/kernel/init_task.c --- linux-2.6.27.15/arch/x86/kernel/init_task.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/init_task.c 2009-02-10 20:32:10.000000000 +0100 @@ -42,5 +42,5 @@ EXPORT_SYMBOL(init_task); * section. Since TSS's are completely CPU-local, we want them * on exact cacheline boundaries, to eliminate cacheline ping-pong. */ -DEFINE_PER_CPU_SHARED_ALIGNED(struct tss_struct, init_tss) = INIT_TSS; - +struct tss_struct init_tss[NR_CPUS] ____cacheline_internodealigned_in_smp = { [0 ... NR_CPUS-1] = INIT_TSS }; +EXPORT_SYMBOL(init_tss); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/ioport.c linux-2.6.27.15-g-v/arch/x86/kernel/ioport.c --- linux-2.6.27.15/arch/x86/kernel/ioport.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/ioport.c 2009-02-10 20:32:10.000000000 +0100 @@ -14,6 +14,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, @@ -40,6 +41,12 @@ 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(); + return -EPERM; + } +#endif if (turn_on && !capable(CAP_SYS_RAWIO)) return -EPERM; @@ -66,7 +73,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); @@ -121,8 +128,13 @@ static int do_iopl(unsigned int level, s 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 } regs->flags = (regs->flags & ~X86_EFLAGS_IOPL) | (level << 12); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/irq_32.c linux-2.6.27.15-g-v/arch/x86/kernel/irq_32.c --- linux-2.6.27.15/arch/x86/kernel/irq_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/irq_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -116,7 +116,7 @@ execute_on_irq_stack(int overflow, struc return 0; /* build the stack frame on the IRQ stack */ - isp = (u32 *) ((char*)irqctx + sizeof(*irqctx)); + isp = (u32 *) ((char*)irqctx + sizeof(*irqctx) - 8); irqctx->tinfo.task = curctx->tinfo.task; irqctx->tinfo.previous_esp = current_stack_pointer; @@ -197,7 +197,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) - 8); call_on_stack(__do_softirq, isp); /* diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/kprobes.c linux-2.6.27.15-g-v/arch/x86/kernel/kprobes.c --- linux-2.6.27.15/arch/x86/kernel/kprobes.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/kprobes.c 2009-02-10 20:32:10.000000000 +0100 @@ -166,9 +166,24 @@ static void __kprobes set_jmp_op(void *f char op; s32 raddr; } __attribute__((packed)) * jop; - jop = (struct __arch_jmp_op *)from; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + + jop = (struct __arch_jmp_op *)(ktla_ktva(from)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + jop->raddr = (s32)((long)(to) - ((long)(from) + 5)); jop->op = RELATIVEJUMP_INSTRUCTION; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } /* @@ -342,16 +357,29 @@ static void __kprobes fix_riprel(struct static void __kprobes arch_copy_kprobe(struct kprobe *p) { - memcpy(p->ainsn.insn, p->addr, MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + memcpy(p->ainsn.insn, ktla_ktva(p->addr), MAX_INSN_SIZE * sizeof(kprobe_opcode_t)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif fix_riprel(p); - if (can_boost(p->addr)) + if (can_boost(ktla_ktva(p->addr))) p->ainsn.boostable = 0; else p->ainsn.boostable = -1; - p->opcode = *p->addr; + p->opcode = *(ktla_ktva(p->addr)); } int __kprobes arch_prepare_kprobe(struct kprobe *p) @@ -428,7 +456,7 @@ static void __kprobes prepare_singlestep if (p->opcode == BREAKPOINT_INSTRUCTION) regs->ip = (unsigned long)p->addr; else - regs->ip = (unsigned long)p->ainsn.insn; + regs->ip = ktva_ktla((unsigned long)p->ainsn.insn); } void __kprobes arch_prepare_kretprobe(struct kretprobe_instance *ri, @@ -449,7 +477,7 @@ static void __kprobes setup_singlestep(s if (p->ainsn.boostable == 1 && !p->post_handler) { /* Boost up -- we can execute copied instructions directly */ reset_current_kprobe(); - regs->ip = (unsigned long)p->ainsn.insn; + regs->ip = ktva_ktla((unsigned long)p->ainsn.insn); preempt_enable_no_resched(); return; } @@ -519,7 +547,7 @@ static int __kprobes kprobe_handler(stru struct kprobe_ctlblk *kcb; addr = (kprobe_opcode_t *)(regs->ip - sizeof(kprobe_opcode_t)); - if (*addr != BREAKPOINT_INSTRUCTION) { + if (*(kprobe_opcode_t *)ktla_ktva((unsigned long)addr) != BREAKPOINT_INSTRUCTION) { /* * The breakpoint instruction was removed right * after we hit it. Another cpu has removed @@ -770,7 +798,7 @@ static void __kprobes resume_execution(s struct pt_regs *regs, struct kprobe_ctlblk *kcb) { unsigned long *tos = stack_addr(regs); - unsigned long copy_ip = (unsigned long)p->ainsn.insn; + unsigned long copy_ip = ktva_ktla((unsigned long)p->ainsn.insn); unsigned long orig_ip = (unsigned long)p->addr; kprobe_opcode_t *insn = p->ainsn.insn; @@ -953,7 +981,7 @@ int __kprobes kprobe_exceptions_notify(s struct die_args *args = data; int ret = NOTIFY_DONE; - if (args->regs && user_mode_vm(args->regs)) + if (args->regs && user_mode(args->regs)) return ret; switch (val) { diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/ldt.c linux-2.6.27.15-g-v/arch/x86/kernel/ldt.c --- linux-2.6.27.15/arch/x86/kernel/ldt.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/ldt.c 2009-02-10 20:32:10.000000000 +0100 @@ -63,13 +63,13 @@ static int alloc_ldt(mm_context_t *pc, i if (reload) { #ifdef CONFIG_SMP preempt_disable(); - load_LDT(pc); + load_LDT_nolock(pc); if (!cpus_equal(current->mm->cpu_vm_mask, cpumask_of_cpu(smp_processor_id()))) smp_call_function(flush_ldt, current->mm, 1); preempt_enable(); #else - load_LDT(pc); + load_LDT_nolock(pc); #endif } if (oldsize) { @@ -108,6 +108,24 @@ int init_new_context(struct task_struct retval = copy_ldt(&mm->context, &old_mm->context); mutex_unlock(&old_mm->context.lock); } + + if (tsk == current) { + mm->context.vdso = ~0UL; + +#ifdef CONFIG_X86_32 +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + 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 +#endif + + } + return retval; } @@ -221,6 +239,13 @@ static int write_ldt(void __user *ptr, u } } +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && (ldt_info.contents & MODIFY_LDT_CONTENTS_CODE)) { + error = -EINVAL; + goto out_unlock; + } +#endif + fill_ldt(&ldt, &ldt_info); if (oldmode) ldt.avl = 0; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/machine_kexec_32.c linux-2.6.27.15-g-v/arch/x86/kernel/machine_kexec_32.c --- linux-2.6.27.15/arch/x86/kernel/machine_kexec_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/machine_kexec_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -34,7 +34,7 @@ static u32 kexec_pmd1[1024] PAGE_ALIGNED static u32 kexec_pte0[1024] PAGE_ALIGNED; static u32 kexec_pte1[1024] PAGE_ALIGNED; -static void set_idt(void *newidt, __u16 limit) +static void set_idt(struct desc_struct *newidt, __u16 limit) { struct desc_ptr curidt; @@ -46,7 +46,7 @@ static void set_idt(void *newidt, __u16 } -static void set_gdt(void *newgdt, __u16 limit) +static void set_gdt(struct desc_struct *newgdt, __u16 limit) { struct desc_ptr curgdt; @@ -145,7 +145,7 @@ void machine_kexec(struct kimage *image) } control_page = page_address(image->control_code_page); - memcpy(control_page, relocate_kernel, KEXEC_CONTROL_CODE_MAX_SIZE); + memcpy(control_page, (void *)ktla_ktva((unsigned long)relocate_kernel), KEXEC_CONTROL_CODE_MAX_SIZE); relocate_kernel_ptr = control_page; page_list[PA_CONTROL_PAGE] = __pa(control_page); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/module_32.c linux-2.6.27.15-g-v/arch/x86/kernel/module_32.c --- linux-2.6.27.15/arch/x86/kernel/module_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/module_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -23,6 +23,9 @@ #include #include +#include +#include + #if 0 #define DEBUGP printk #else @@ -33,9 +36,31 @@ void *module_alloc(unsigned long size) { if (size == 0) return NULL; + +#ifdef CONFIG_PAX_KERNEXEC + return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL); +#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, VM_ALLOC, (unsigned long)&MODULES_VADDR, (unsigned long)&MODULES_END); + if (area) + return area->addr; + + return NULL; +} +EXPORT_SYMBOL(module_alloc_exec); +#endif /* Free memory returned from module_alloc */ void module_free(struct module *mod, void *module_region) @@ -45,6 +70,45 @@ void module_free(struct module *mod, voi table entries. */ } +#ifdef CONFIG_PAX_KERNEXEC +void module_free_exec(struct module *mod, void *module_region) +{ + struct vm_struct **p, *tmp; + + if (!module_region) + return; + + if ((PAGE_SIZE-1) & (unsigned long)module_region) { + printk(KERN_ERR "Trying to module_free_exec() bad address (%p)\n", module_region); + WARN_ON(1); + return; + } + + write_lock(&vmlist_lock); + for (p = &vmlist; (tmp = *p) != NULL; p = &tmp->next) + if (tmp->addr == module_region) + break; + + if (tmp) { + unsigned long cr0; + + pax_open_kernel(cr0); + memset(tmp->addr, 0xCC, tmp->size); + pax_close_kernel(cr0); + + *p = tmp->next; + kfree(tmp); + } + write_unlock(&vmlist_lock); + + if (!tmp) { + printk(KERN_ERR "Trying to module_free_exec() nonexistent vm area (%p)\n", + module_region); + WARN_ON(1); + } +} +#endif + /* We don't need anything special. */ int module_frob_arch_sections(Elf_Ehdr *hdr, Elf_Shdr *sechdrs, @@ -63,14 +127,20 @@ 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; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif 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 = ktla_ktva((void *)plocation); /* This is the symbol it is referring to. Note that all undefined symbols have been resolved. */ sym = (Elf32_Sym *)sechdrs[symindex].sh_addr @@ -78,12 +148,32 @@ int apply_relocate(Elf32_Shdr *sechdrs, switch (ELF32_R_TYPE(rel[i].r_info)) { case R_386_32: + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + /* We add the value into the location given */ - *location += sym->st_value; + *plocation += sym->st_value; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + break; case R_386_PC32: + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + /* Add the value, subtract its postition */ - *location += sym->st_value - (uint32_t)location; + *plocation += sym->st_value - location; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + break; default: printk(KERN_ERR "module %s: Unknown relocation: %u\n", diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/module_64.c linux-2.6.27.15-g-v/arch/x86/kernel/module_64.c --- linux-2.6.27.15/arch/x86/kernel/module_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/module_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -40,7 +40,7 @@ void module_free(struct module *mod, voi table entries. */ } -void *module_alloc(unsigned long size) +static void *__module_alloc(unsigned long size, pgprot_t prot) { struct vm_struct *area; @@ -54,8 +54,31 @@ void *module_alloc(unsigned long size) if (!area) return NULL; - return __vmalloc_area(area, GFP_KERNEL, PAGE_KERNEL_EXEC); + return __vmalloc_area(area, GFP_KERNEL | __GFP_ZERO, prot); +} + +#ifdef CONFIG_PAX_KERNEXEC +void *module_alloc(unsigned long size) +{ + return __module_alloc(size, PAGE_KERNEL); } + +void module_free_exec(struct module *mod, void *module_region) +{ + module_free(mod, module_region); +} + +void *module_alloc_exec(unsigned long size) +{ + return __module_alloc(size, PAGE_KERNEL_RX); +} +#else +void *module_alloc(unsigned long size) +{ + return __module_alloc(size, PAGE_KERNEL_EXEC); +} +#endif + #endif /* We don't need anything special. */ @@ -77,7 +100,11 @@ int apply_relocate_add(Elf64_Shdr *sechd Elf64_Rela *rel = (void *)sechdrs[relsec].sh_addr; Elf64_Sym *sym; void *loc; - u64 val; + u64 val; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif DEBUGP("Applying relocate section %u to %u\n", relsec, sechdrs[relsec].sh_info); @@ -101,21 +128,61 @@ int apply_relocate_add(Elf64_Shdr *sechd case R_X86_64_NONE: break; case R_X86_64_64: + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + *(u64 *)loc = val; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + break; case R_X86_64_32: + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + *(u32 *)loc = val; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + if (val != *(u32 *)loc) goto overflow; break; case R_X86_64_32S: + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + *(s32 *)loc = val; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + if ((s64)val != *(s32 *)loc) goto overflow; break; case R_X86_64_PC32: val -= (u64)loc; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + *(u32 *)loc = val; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + #if 0 if ((s64)val != *(s32 *)loc) goto overflow; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/paravirt.c linux-2.6.27.15-g-v/arch/x86/kernel/paravirt.c --- linux-2.6.27.15/arch/x86/kernel/paravirt.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/paravirt.c 2009-02-10 20:32:10.000000000 +0100 @@ -44,7 +44,7 @@ void _paravirt_nop(void) { } -static void __init default_banner(void) +static void default_banner(void) { printk(KERN_INFO "Booting paravirtualized kernel on %s\n", pv_info.name); @@ -164,7 +164,7 @@ unsigned paravirt_patch_insns(void *insn if (insn_len > len || start == NULL) insn_len = len; else - memcpy(insnbuf, start, insn_len); + memcpy(insnbuf, ktla_ktva(start), insn_len); return insn_len; } @@ -279,21 +279,21 @@ void __init paravirt_use_bytelocks(void) #endif } -struct pv_info pv_info = { +struct pv_info pv_info __read_only = { .name = "bare hardware", .paravirt_enabled = 0, .kernel_rpl = 0, .shared_kernel_pmd = 1, /* Only used when CONFIG_X86_PAE is set */ }; -struct pv_init_ops pv_init_ops = { +struct pv_init_ops pv_init_ops __read_only = { .patch = native_patch, .banner = default_banner, .arch_setup = paravirt_nop, .memory_setup = machine_specific_memory_setup, }; -struct pv_time_ops pv_time_ops = { +struct pv_time_ops pv_time_ops __read_only = { .time_init = hpet_time_init, .get_wallclock = native_get_wallclock, .set_wallclock = native_set_wallclock, @@ -301,7 +301,7 @@ struct pv_time_ops pv_time_ops = { .get_tsc_khz = native_calibrate_tsc, }; -struct pv_irq_ops pv_irq_ops = { +struct pv_irq_ops pv_irq_ops __read_only = { .init_IRQ = native_init_IRQ, .save_fl = native_save_fl, .restore_fl = native_restore_fl, @@ -314,7 +314,7 @@ struct pv_irq_ops pv_irq_ops = { #endif }; -struct pv_cpu_ops pv_cpu_ops = { +struct pv_cpu_ops pv_cpu_ops __read_only = { .cpuid = native_cpuid, .get_debugreg = native_get_debugreg, .set_debugreg = native_set_debugreg, @@ -371,7 +371,7 @@ struct pv_cpu_ops pv_cpu_ops = { }, }; -struct pv_apic_ops pv_apic_ops = { +struct pv_apic_ops pv_apic_ops __read_only = { #ifdef CONFIG_X86_LOCAL_APIC .apic_write = native_apic_write, .apic_read = native_apic_read, @@ -381,7 +381,7 @@ struct pv_apic_ops pv_apic_ops = { #endif }; -struct pv_mmu_ops pv_mmu_ops = { +struct pv_mmu_ops pv_mmu_ops __read_only = { #ifndef CONFIG_X86_64 .pagetable_setup_start = native_pagetable_setup_start, .pagetable_setup_done = native_pagetable_setup_done, @@ -461,7 +461,7 @@ struct pv_mmu_ops pv_mmu_ops = { .set_fixmap = native_set_fixmap, }; -struct pv_lock_ops pv_lock_ops = { +struct pv_lock_ops pv_lock_ops __read_only = { #ifdef CONFIG_SMP .spin_is_locked = __ticket_spin_is_locked, .spin_is_contended = __ticket_spin_is_contended, diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/process_32.c linux-2.6.27.15-g-v/arch/x86/kernel/process_32.c --- linux-2.6.27.15/arch/x86/kernel/process_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/process_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -62,8 +62,10 @@ asmlinkage void ret_from_fork(void) __as DEFINE_PER_CPU(struct task_struct *, current_task) = &init_task; EXPORT_PER_CPU_SYMBOL(current_task); +#ifdef CONFIG_SMP DEFINE_PER_CPU(int, cpu_number); EXPORT_PER_CPU_SYMBOL(cpu_number); +#endif /* * Return saved PC of a blocked thread. @@ -71,6 +73,7 @@ EXPORT_PER_CPU_SYMBOL(cpu_number); unsigned long thread_saved_pc(struct task_struct *tsk) { return ((unsigned long *)tsk->thread.sp)[3]; +//XXX return tsk->thread.eip; } #ifdef CONFIG_HOTPLUG_CPU @@ -162,7 +165,7 @@ void __show_registers(struct pt_regs *re unsigned long sp; unsigned short ss, gs; - if (user_mode_vm(regs)) { + if (user_mode(regs)) { sp = regs->sp; ss = regs->ss & 0xffff; savesegment(gs, gs); @@ -239,8 +242,8 @@ int kernel_thread(int (*fn)(void *), voi regs.bx = (unsigned long) fn; regs.dx = (unsigned long) arg; - regs.ds = __USER_DS; - regs.es = __USER_DS; + regs.ds = __KERNEL_DS; + regs.es = __KERNEL_DS; regs.fs = __KERNEL_PERCPU; regs.orig_ax = -1; regs.ip = (unsigned long) kernel_thread_helper; @@ -262,7 +265,7 @@ void exit_thread(void) struct task_struct *tsk = current; struct thread_struct *t = &tsk->thread; 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; @@ -283,6 +286,7 @@ void flush_thread(void) { struct task_struct *tsk = current; + loadsegment(gs, 0); tsk->thread.debugreg0 = 0; tsk->thread.debugreg1 = 0; tsk->thread.debugreg2 = 0; @@ -322,7 +326,7 @@ int copy_thread(int nr, unsigned long cl struct task_struct *tsk; int err; - childregs = task_pt_regs(p); + childregs = task_stack_page(p) + THREAD_SIZE - sizeof(struct pt_regs) - 8; *childregs = *regs; childregs->ax = 0; childregs->sp = sp; @@ -351,6 +355,7 @@ int copy_thread(int nr, unsigned long cl * Set a new TLS for the child thread? */ if (clone_flags & CLONE_SETTLS) +//XXX needs set_fs()? err = do_set_thread_area(p, -1, (struct user_desc __user *)childregs->si, 0); @@ -550,7 +555,7 @@ struct task_struct * __switch_to(struct 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; /* never put a printk in __switch_to... printk() calls wake_up*() indirectly */ @@ -578,6 +583,11 @@ struct task_struct * __switch_to(struct */ savesegment(gs, prev->gs); +#ifdef CONFIG_PAX_MEMORY_UDEREF + if (!segment_eq(task_thread_info(prev_p)->addr_limit, task_thread_info(next_p)->addr_limit)) + __set_fs(task_thread_info(next_p)->addr_limit, cpu); +#endif + /* * Load the per-thread Thread-Local Storage descriptor. */ @@ -716,15 +726,27 @@ unsigned long get_wchan(struct task_stru return 0; } -unsigned long arch_align_stack(unsigned long sp) +#ifdef CONFIG_PAX_RANDKSTACK +asmlinkage void pax_randomize_kstack(void) { - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} + struct thread_struct *thread = ¤t->thread; + unsigned long time; -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long range_end = mm->brk + 0x02000000; - return randomize_range(mm->brk, range_end, 0) ? : mm->brk; + 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 + + thread->sp0 ^= time; + load_sp0(init_tss + smp_processor_id(), thread); } +#endif diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/process_64.c linux-2.6.27.15-g-v/arch/x86/kernel/process_64.c --- linux-2.6.27.15/arch/x86/kernel/process_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/process_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -119,6 +119,8 @@ static inline void play_dead(void) void cpu_idle(void) { current_thread_info()->status |= TS_POLLING; + current->stack_canary = pax_get_random_long(); + write_pda(stack_canary, current->stack_canary); /* endless idle loop with no priority at all */ while (1) { tick_nohz_stop_sched_tick(1); @@ -228,7 +230,7 @@ void exit_thread(void) struct thread_struct *t = &me->thread; if (me->thread.io_bitmap_ptr) { - struct tss_struct *tss = &per_cpu(init_tss, get_cpu()); + struct tss_struct *tss = init_tss + get_cpu(); kfree(t->io_bitmap_ptr); t->io_bitmap_ptr = NULL; @@ -541,7 +543,7 @@ __switch_to(struct task_struct *prev_p, struct thread_struct *prev = &prev_p->thread; struct thread_struct *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; unsigned fsindex, gsindex; /* we're going to use this soon, after a few expensive things */ @@ -630,7 +632,6 @@ __switch_to(struct task_struct *prev_p, (unsigned long)task_stack_page(next_p) + THREAD_SIZE - PDA_STACKOFFSET); #ifdef CONFIG_CC_STACKPROTECTOR - write_pda(stack_canary, next_p->stack_canary); /* * Build time only check to make sure the stack_canary is at * offset 40 in the pda; this is a gcc ABI requirement @@ -729,12 +730,11 @@ unsigned long get_wchan(struct task_stru if (!p || p == current || p->state==TASK_RUNNING) return 0; stack = (unsigned long)task_stack_page(p); - if (p->thread.sp < stack || p->thread.sp >= stack+THREAD_SIZE) + if (p->thread.sp < stack || p->thread.sp > stack+THREAD_SIZE-8-sizeof(u64)) return 0; fp = *(u64 *)(p->thread.sp); do { - if (fp < (unsigned long)stack || - fp >= (unsigned long)stack+THREAD_SIZE) + if (fp < stack || fp > stack+THREAD_SIZE-8-sizeof(u64)) return 0; ip = *(u64 *)(fp+8); if (!in_sched_functions(ip)) @@ -844,16 +844,3 @@ long sys_arch_prctl(int code, unsigned l { return do_arch_prctl(current, code, addr); } - -unsigned long arch_align_stack(unsigned long sp) -{ - if (!(current->personality & ADDR_NO_RANDOMIZE) && randomize_va_space) - sp -= get_random_int() % 8192; - return sp & ~0xf; -} - -unsigned long arch_randomize_brk(struct mm_struct *mm) -{ - unsigned long range_end = mm->brk + 0x02000000; - return randomize_range(mm->brk, range_end, 0) ? : mm->brk; -} diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/ptrace.c linux-2.6.27.15-g-v/arch/x86/kernel/ptrace.c --- linux-2.6.27.15/arch/x86/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/ptrace.c 2009-02-10 20:32:10.000000000 +0100 @@ -1369,7 +1369,7 @@ void send_sigtrap(struct task_struct *ts info.si_code = TRAP_BRKPT; /* User-mode ip? */ - info.si_addr = user_mode_vm(regs) ? (void __user *) regs->ip : NULL; + info.si_addr = user_mode(regs) ? (void __user *) regs->ip : NULL; /* Send us the fake SIGTRAP */ force_sig_info(SIGTRAP, &info, tsk); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/reboot.c linux-2.6.27.15-g-v/arch/x86/kernel/reboot.c --- linux-2.6.27.15/arch/x86/kernel/reboot.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/reboot.c 2009-02-10 20:32:10.000000000 +0100 @@ -28,7 +28,7 @@ void (*pm_power_off)(void); EXPORT_SYMBOL(pm_power_off); static const struct desc_ptr no_idt = {}; -static int reboot_mode; +static unsigned short reboot_mode; enum reboot_type reboot_type = BOOT_KBD; int reboot_force; @@ -193,7 +193,7 @@ static struct dmi_system_id __initdata r DMI_MATCH(DMI_PRODUCT_NAME, "HP Compaq"), }, }, - { } + { NULL, NULL, Template:0, NULL, NULL} }; static int __init reboot_init(void) @@ -209,12 +209,12 @@ core_initcall(reboot_init); controller to pulse the CPU reset line, which is more thorough, but doesn't work with at least one type of 486 motherboard. It is easy to stop this code working; hence the copious comments. */ -static const unsigned long long -real_mode_gdt_entries [3] = +static struct desc_struct +real_mode_gdt_entries [3] __read_only = { - 0x0000000000000000ULL, /* Null descriptor */ - 0x00009b000000ffffULL, /* 16-bit real-mode 64k code at 0x00000000 */ - 0x000093000100ffffULL /* 16-bit real-mode 64k data at 0x00000100 */ + {{{0x00000000, 0x00000000}}}, /* Null descriptor */ + {{{0x0000ffff, 0x00009b00}}}, /* 16-bit real-mode 64k code at 0x00000000 */ + {{{0x0100ffff, 0x00009300}}} /* 16-bit real-mode 64k data at 0x00000100 */ }; static const struct desc_ptr @@ -263,7 +263,7 @@ static const unsigned char jump_to_bios * specified by the code and length parameters. * We assume that length will aways be less that 100! */ -void machine_real_restart(const unsigned char *code, int length) +void machine_real_restart(const unsigned char *code, unsigned int length) { local_irq_disable(); @@ -283,8 +283,8 @@ void machine_real_restart(const unsigned /* Remap the kernel at virtual address zero, as well as offset zero from the kernel segment. This assumes the kernel segment starts at virtual address PAGE_OFFSET. */ - memcpy(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, - sizeof(swapper_pg_dir [0]) * KERNEL_PGD_PTRS); + clone_pgd_range(swapper_pg_dir, swapper_pg_dir + KERNEL_PGD_BOUNDARY, + min_t(unsigned long, KERNEL_PGD_PTRS, KERNEL_PGD_BOUNDARY)); /* * Use `swapper_pg_dir' as our page directory. @@ -296,16 +296,15 @@ void machine_real_restart(const unsigned boot)". This seems like a fairly standard thing that gets set by REBOOT.COM programs, and the previous reset routine did this too. */ - *((unsigned short *)0x472) = reboot_mode; + *(unsigned short *)(__va(0x472)) = reboot_mode; /* For the switch to real mode, copy some code to low memory. It has to be in the first 64k because it is running in 16-bit mode, and it has to have the same physical and virtual address, because it turns off paging. Copy it near the end of the first page, out of the way of BIOS variables. */ - memcpy((void *)(0x1000 - sizeof(real_mode_switch) - 100), - real_mode_switch, sizeof (real_mode_switch)); - memcpy((void *)(0x1000 - 100), code, length); + memcpy(__va(0x1000 - sizeof (real_mode_switch) - 100), real_mode_switch, sizeof (real_mode_switch)); + memcpy(__va(0x1000 - 100), code, length); /* Set up the IDT for real mode. */ load_idt(&real_mode_idt); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/setup.c linux-2.6.27.15-g-v/arch/x86/kernel/setup.c --- linux-2.6.27.15/arch/x86/kernel/setup.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/setup.c 2009-02-10 20:32:10.000000000 +0100 @@ -578,6 +578,7 @@ static struct x86_quirks default_x86_qui struct x86_quirks *x86_quirks __initdata = &default_x86_quirks; +#ifdef CONFIG_X86_RESERVE_LOW_64K static int __init dmi_low_memory_corruption(const struct dmi_system_id *d) { printk(KERN_NOTICE @@ -589,6 +590,7 @@ static int __init dmi_low_memory_corrupt return 0; } +#endif /* List of systems that have known low memory corruption BIOS problems */ static struct dmi_system_id __initdata bad_bios_dmi_table[] = { @@ -685,8 +687,8 @@ void __init setup_arch(char **cmdline_p) if (!boot_params.hdr.root_flags) root_mountflags &= ~MS_RDONLY; - init_mm.start_code = (unsigned long) _text; - init_mm.end_code = (unsigned long) _etext; + init_mm.start_code = ktla_ktva((unsigned long) _text); + init_mm.end_code = ktla_ktva((unsigned long) _etext); init_mm.end_data = (unsigned long) _edata; #ifdef CONFIG_X86_32 init_mm.brk = init_pg_tables_end + PAGE_OFFSET; @@ -694,9 +696,9 @@ void __init setup_arch(char **cmdline_p) init_mm.brk = (unsigned long) &_end; #endif - 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(ktla_ktva(_text)); + code_resource.end = virt_to_phys(ktla_ktva(_etext))-1; + data_resource.start = virt_to_phys(_data); data_resource.end = virt_to_phys(_edata)-1; bss_resource.start = virt_to_phys(&__bss_start); bss_resource.end = virt_to_phys(&__bss_stop)-1; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/setup_percpu.c linux-2.6.27.15-g-v/arch/x86/kernel/setup_percpu.c --- linux-2.6.27.15/arch/x86/kernel/setup_percpu.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/setup_percpu.c 2009-02-10 20:32:10.000000000 +0100 @@ -166,7 +166,11 @@ void __init setup_per_cpu_areas(void) else ptr = alloc_bootmem_pages_node(NODE_DATA(node), size); #endif +#ifdef CONFIG_X86_32 + __per_cpu_offset[cpu] = ptr - __per_cpu_start; +#else per_cpu_offset(cpu) = ptr - __per_cpu_start; +#endif memcpy(ptr, __per_cpu_start, __per_cpu_end - __per_cpu_start); } diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/signal_32.c linux-2.6.27.15-g-v/arch/x86/kernel/signal_32.c --- linux-2.6.27.15/arch/x86/kernel/signal_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/signal_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -378,9 +378,9 @@ setup_frame(int sig, struct k_sigaction } if (current->mm->context.vdso) - restorer = VDSO32_SYMBOL(current->mm->context.vdso, sigreturn); + restorer = (void __user *)VDSO32_SYMBOL(current->mm->context.vdso, sigreturn); else - restorer = &frame->retcode; + restorer = (void __user *)&frame->retcode; if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; @@ -460,7 +460,7 @@ static int setup_rt_frame(int sig, struc goto give_sigsegv; /* Set up to return from userspace. */ - restorer = VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); + restorer = (void __user *)VDSO32_SYMBOL(current->mm->context.vdso, rt_sigreturn); if (ka->sa.sa_flags & SA_RESTORER) restorer = ka->sa.sa_restorer; err |= __put_user(restorer, &frame->pretcode); @@ -590,7 +590,7 @@ static void do_signal(struct pt_regs *re * X86_32: vm86 regs switched out by assembly code before reaching * here, so testing against kernel CS suffices. */ - if (!user_mode(regs)) + if (!user_mode_novm(regs)) return; if (current_thread_info()->status & TS_RESTORE_SIGMASK) diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/signal_64.c linux-2.6.27.15-g-v/arch/x86/kernel/signal_64.c --- linux-2.6.27.15/arch/x86/kernel/signal_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/signal_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -312,8 +312,8 @@ static int setup_rt_frame(int sig, struc err |= setup_sigcontext(&frame->uc.uc_mcontext, regs, set->sig[0], me); err |= __put_user(fp, &frame->uc.uc_mcontext.fpstate); if (sizeof(*set) == 16) { - __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); - __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); + err |= __put_user(set->sig[0], &frame->uc.uc_sigmask.sig[0]); + err |= __put_user(set->sig[1], &frame->uc.uc_sigmask.sig[1]); } else err |= __copy_to_user(&frame->uc.uc_sigmask, set, sizeof(*set)); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/smpboot.c linux-2.6.27.15-g-v/arch/x86/kernel/smpboot.c --- linux-2.6.27.15/arch/x86/kernel/smpboot.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/smpboot.c 2009-02-10 20:32:10.000000000 +0100 @@ -814,6 +814,11 @@ static int __cpuinit do_boot_cpu(int api .cpu = cpu, .done = COMPLETION_INITIALIZER_ONSTACK(c_idle.done), }; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + INIT_WORK(&c_idle.work, do_fork_idle); #ifdef CONFIG_X86_64 @@ -864,7 +869,17 @@ do_rest: cpu_pda(cpu)->pcurrent = c_idle.idle; clear_tsk_thread_flag(c_idle.idle, TIF_FORK); #endif + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + initial_code = (unsigned long)start_secondary; stack_start.sp = (void *) c_idle.idle->thread.sp; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/smpcommon.c linux-2.6.27.15-g-v/arch/x86/kernel/smpcommon.c --- linux-2.6.27.15/arch/x86/kernel/smpcommon.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/smpcommon.c 2009-02-10 20:32:10.000000000 +0100 @@ -3,9 +3,10 @@ */ #include #include +#include #ifdef CONFIG_X86_32 -DEFINE_PER_CPU(unsigned long, this_cpu_off); +DEFINE_PER_CPU(unsigned long, this_cpu_off) = (unsigned long)__per_cpu_start; EXPORT_PER_CPU_SYMBOL(this_cpu_off); /* @@ -15,16 +16,19 @@ EXPORT_PER_CPU_SYMBOL(this_cpu_off); */ __cpuinit void init_gdt(int cpu) { - struct desc_struct gdt; + struct desc_struct d, *gdt = get_cpu_gdt_table(cpu); + unsigned long base, limit; - pack_descriptor(&gdt, __per_cpu_offset[cpu], 0xFFFFF, - 0x2 | DESCTYPE_S, 0x8); - gdt.s = 1; + base = per_cpu_offset(cpu); + limit = PERCPU_ENOUGH_ROOM - 1; + if (limit < 64*1024) + pack_descriptor(&d, base, limit, 0x80 | DESCTYPE_S | 0x3, 0x4); + else + pack_descriptor(&d, base, limit >> PAGE_SHIFT, 0x80 | DESCTYPE_S | 0x3, 0xC); - write_gdt_entry(get_cpu_gdt_table(cpu), - GDT_ENTRY_PERCPU, &gdt, DESCTYPE_S); + write_gdt_entry(gdt, GDT_ENTRY_PERCPU, &d, DESCTYPE_S); - per_cpu(this_cpu_off, cpu) = __per_cpu_offset[cpu]; + per_cpu(this_cpu_off, cpu) = base; per_cpu(cpu_number, cpu) = cpu; } #endif diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/step.c linux-2.6.27.15-g-v/arch/x86/kernel/step.c --- linux-2.6.27.15/arch/x86/kernel/step.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/step.c 2009-02-10 20:32:10.000000000 +0100 @@ -23,22 +23,20 @@ unsigned long convert_ip_to_linear(struc * and APM bios ones we just ignore here. */ if ((seg & SEGMENT_TI_MASK) == SEGMENT_LDT) { - u32 *desc; + struct desc_struct *desc; unsigned long base; - seg &= ~7UL; + seg >>= 3; mutex_lock(&child->mm->context.lock); - if (unlikely((seg >> 3) >= child->mm->context.size)) - addr = -1L; /* bogus selector, access would fault */ + if (unlikely(seg >= child->mm->context.size)) + addr = -EINVAL; else { - desc = child->mm->context.ldt + seg; - base = ((desc[0] >> 16) | - ((desc[1] & 0xff) << 16) | - (desc[1] & 0xff000000)); + desc = &child->mm->context.ldt[seg]; + base = (desc->a >> 16) | ((desc->b & 0xff) << 16) | (desc->b & 0xff000000); /* 16-bit code segment? */ - if (!((desc[1] >> 22) & 1)) + if (!((desc->b >> 22) & 1)) addr &= 0xffff; addr += base; } @@ -54,6 +52,9 @@ static int is_setting_trap_flag(struct t unsigned char opcode[15]; unsigned long addr = convert_ip_to_linear(child, regs); + if (addr == -EINVAL) + return 0; + copied = access_process_vm(child, addr, opcode, sizeof(opcode), 0); for (i = 0; i < copied; i++) { switch (opcode[i]) { @@ -75,7 +76,7 @@ static int is_setting_trap_flag(struct t #ifdef CONFIG_X86_64 case 0x40 ... 0x4f: - if (regs->cs != __USER_CS) + if ((regs->cs & 0xffff) != __USER_CS) /* 32-bit mode: register increment */ return 0; /* 64-bit mode: REX prefix */ diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/syscall_table_32.S linux-2.6.27.15-g-v/arch/x86/kernel/syscall_table_32.S --- linux-2.6.27.15/arch/x86/kernel/syscall_table_32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/syscall_table_32.S 2009-02-10 20:32:10.000000000 +0100 @@ -1,3 +1,4 @@ +.section .rodata,"a",@progbits ENTRY(sys_call_table) .long sys_restart_syscall /* 0 - old "setup()" system call, used for restarting */ .long sys_exit @@ -272,7 +273,7 @@ ENTRY(sys_call_table) .long sys_tgkill /* 270 */ .long sys_utimes .long sys_fadvise64_64 - .long sys_ni_syscall /* sys_vserver */ + .long sys_vserver .long sys_mbind .long sys_get_mempolicy .long sys_set_mempolicy diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/sys_i386_32.c linux-2.6.27.15-g-v/arch/x86/kernel/sys_i386_32.c --- linux-2.6.27.15/arch/x86/kernel/sys_i386_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/sys_i386_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -22,6 +22,21 @@ #include #include +int i386_mmap_check(unsigned long addr, unsigned long len, unsigned long flags) +{ + unsigned long pax_task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + if (len > pax_task_size || addr > pax_task_size - len) + return -EINVAL; + + return 0; +} + asmlinkage long sys_mmap2(unsigned long addr, unsigned long len, unsigned long prot, unsigned long flags, unsigned long fd, unsigned long pgoff) @@ -81,6 +96,205 @@ out: return err; } +unsigned long +arch_get_unmapped_area(struct file *filp, unsigned long addr, + unsigned long len, unsigned long pgoff, unsigned long flags) +{ + struct mm_struct *mm = current->mm; + struct vm_area_struct *vma; + unsigned long start_addr, pax_task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + if (len > pax_task_size) + return -ENOMEM; + + if (flags & MAP_FIXED) + return addr; + +#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 (pax_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 (!nx_enabled && (mm->pax_flags & MF_PAX_PAGEEXEC) && (flags & MAP_EXECUTABLE) && start_addr >= mm->mmap_base) { + start_addr = 0x00110000UL; + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + start_addr += mm->delta_mmap & 0x03FFF000UL; +#endif + + if (mm->start_brk <= start_addr && start_addr < mm->mmap_base) + start_addr = addr = mm->mmap_base; + else + addr = start_addr; + } +#endif + +full_search: + for (vma = find_vma(mm, addr); ; vma = vma->vm_next) { + /* At this point: (!vma || addr < vma->vm_end). */ + if (pax_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; + mm->cached_hole_size = 0; + goto full_search; + } + } +} + +unsigned long +arch_get_unmapped_area_topdown(struct file *filp, const unsigned long addr0, + const unsigned long len, const unsigned long pgoff, + const unsigned long flags) +{ + struct vm_area_struct *vma; + struct mm_struct *mm = current->mm; + unsigned long base = mm->mmap_base, addr = addr0, pax_task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + /* requested length too big for entire address space */ + if (len > pax_task_size) + return -ENOMEM; + + if (flags & MAP_FIXED) + return addr; + +#ifdef CONFIG_PAX_PAGEEXEC + if (!nx_enabled && (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 (pax_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. + */ + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + mm->mmap_base = SEGMEXEC_TASK_UNMAPPED_BASE; + else +#endif + + 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; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/sys_x86_64.c linux-2.6.27.15-g-v/arch/x86/kernel/sys_x86_64.c --- linux-2.6.27.15/arch/x86/kernel/sys_x86_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/sys_x86_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -45,8 +45,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)) { unsigned long new_begin; @@ -65,7 +65,7 @@ static void find_start_end(unsigned long *begin = new_begin; } } else { - *begin = TASK_UNMAPPED_BASE; + *begin = mm->mmap_base; *end = TASK_SIZE; } } @@ -82,11 +82,15 @@ arch_get_unmapped_area(struct file *filp if (flags & MAP_FIXED) return addr; - 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); @@ -141,7 +145,7 @@ arch_get_unmapped_area_topdown(struct fi { struct vm_area_struct *vma; struct mm_struct *mm = current->mm; - unsigned long addr = addr0; + unsigned long base = mm->mmap_base, addr = addr0; /* requested length too big for entire address space */ if (len > TASK_SIZE) @@ -154,6 +158,10 @@ arch_get_unmapped_area_topdown(struct fi if (!test_thread_flag(TIF_IA32) && (flags & MAP_32BIT)) goto bottomup; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + /* requesting a specific address */ if (addr) { addr = PAGE_ALIGN(addr); @@ -211,13 +219,21 @@ bottomup: * 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; - mm->free_area_cache = TASK_UNMAPPED_BASE; addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); /* * Restore the topdown base: */ - mm->free_area_cache = mm->mmap_base; + mm->mmap_base = base; + mm->free_area_cache = base; mm->cached_hole_size = ~0UL; return addr; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/time_32.c linux-2.6.27.15-g-v/arch/x86/kernel/time_32.c --- linux-2.6.27.15/arch/x86/kernel/time_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/time_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -49,20 +49,30 @@ unsigned long profile_pc(struct pt_regs if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->cs) && in_lock_functions(pc)) { #ifdef CONFIG_FRAME_POINTER - return *(unsigned long *)(regs->bp + 4); + return ktla_ktva(*(unsigned long *)(regs->bp + 4)); #else unsigned long *sp = (unsigned long *)®s->sp; /* Return address is either directly at stack pointer or above a saved flags. Eflags has bits 22-31 zero, kernel addresses don't. */ + +#ifdef CONFIG_PAX_KERNEXEC + return ktla_ktva(sp[0]); +#else if (sp[0] >> 22) return sp[0]; if (sp[1] >> 22) return sp[1]; #endif + +#endif } #endif + + if (!v8086_mode(regs) && SEGMENT_IS_KERNEL_CODE(regs->cs)) + pc = ktla_ktva(pc); + return pc; } EXPORT_SYMBOL(profile_pc); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/tlb_32.c linux-2.6.27.15-g-v/arch/x86/kernel/tlb_32.c --- linux-2.6.27.15/arch/x86/kernel/tlb_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/tlb_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -5,7 +5,7 @@ #include DEFINE_PER_CPU(struct tlb_state, cpu_tlbstate) - ____cacheline_aligned = { &init_mm, 0, }; + ____cacheline_aligned = { &init_mm, 0, {0} }; /* must come after the send_IPI functions above for inlining */ #include diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/tls.c linux-2.6.27.15-g-v/arch/x86/kernel/tls.c --- linux-2.6.27.15/arch/x86/kernel/tls.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/tls.c 2009-02-10 20:32:10.000000000 +0100 @@ -84,6 +84,11 @@ int do_set_thread_area(struct task_struc if (idx < GDT_ENTRY_TLS_MIN || idx > GDT_ENTRY_TLS_MAX) return -EINVAL; +#ifdef CONFIG_PAX_SEGMEXEC + if ((p->mm->pax_flags & MF_PAX_SEGMEXEC) && (info.contents & MODIFY_LDT_CONTENTS_CODE)) + return -EINVAL; +#endif + set_tls_desc(p, idx, &info, 1); return 0; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/traps_32.c linux-2.6.27.15-g-v/arch/x86/kernel/traps_32.c --- linux-2.6.27.15/arch/x86/kernel/traps_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/traps_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -70,14 +70,6 @@ asmlinkage int system_call(void); /* Do we ignore FPU interrupts ? */ char ignore_fpu_irq; -/* - * The IDT has to be page-aligned to simplify the Pentium - * F0 0F bug workaround.. We have a special link segment - * for this. - */ -gate_desc idt_table[256] - __attribute__((__section__(".data.idt"))) = { { { { 0, 0 } } }, }; - int panic_on_unrecovered_nmi; int kstack_depth_to_print = 24; static unsigned int code_bytes = 64; @@ -320,21 +312,22 @@ void show_registers(struct pt_regs *regs * When in-kernel, we also print out the stack and code at the * time of the fault.. */ - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { unsigned int code_prologue = code_bytes * 43 / 64; unsigned int code_len = code_bytes; unsigned char c; u8 *ip; + unsigned long cs_base = get_desc_base(&get_cpu_gdt_table(smp_processor_id())[(0xffff & regs->cs) >> 3]); printk("\n" KERN_EMERG "Stack: "); show_stack_log_lvl(NULL, regs, ®s->sp, 0, KERN_EMERG); printk(KERN_EMERG "Code: "); - ip = (u8 *)regs->ip - code_prologue; + ip = (u8 *)regs->ip - code_prologue + cs_base; if (ip < (u8 *)PAGE_OFFSET || probe_kernel_address(ip, c)) { /* try starting at EIP */ - ip = (u8 *)regs->ip; + ip = (u8 *)regs->ip + cs_base; code_len = code_len - code_prologue + 1; } for (i = 0; i < code_len; i++, ip++) { @@ -343,7 +336,7 @@ void show_registers(struct pt_regs *regs printk(" Bad EIP value."); break; } - if (ip == (u8 *)regs->ip) + if (ip == (u8 *)regs->ip + cs_base) printk("<%02x> ", c); else printk("%02x ", c); @@ -356,6 +349,7 @@ int is_valid_bugaddr(unsigned long ip) { unsigned short ud2; + ip = ktla_ktva(ip); if (ip < PAGE_OFFSET) return 0; if (probe_kernel_address((unsigned short *)ip, ud2)) @@ -469,7 +463,7 @@ void die(const char *str, struct pt_regs 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); } @@ -479,13 +473,13 @@ do_trap(int trapnr, int signr, char *str { struct task_struct *tsk = current; - if (regs->flags & X86_VM_MASK) { + if (v8086_mode(regs)) { if (vm86) goto vm86_trap; goto trap_signal; } - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto kernel_trap; trap_signal: @@ -513,6 +507,12 @@ kernel_trap: tsk->thread.trap_no = trapnr; die(str, regs, error_code); } + +#ifdef CONFIG_PAX_REFCOUNT + if (trapnr == 4) + pax_report_refcount_overflow(regs); +#endif + return; vm86_trap: @@ -595,7 +595,7 @@ do_general_protection(struct pt_regs *re int cpu; cpu = get_cpu(); - tss = &per_cpu(init_tss, cpu); + tss = init_tss + cpu; thread = ¤t->thread; /* @@ -627,13 +627,29 @@ do_general_protection(struct pt_regs *re } put_cpu(); - if (regs->flags & X86_VM_MASK) + if (v8086_mode(regs)) goto gp_in_vm86; tsk = current; - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto gp_in_kernel; +#ifdef CONFIG_PAX_PAGEEXEC + if (!nx_enabled && tsk->mm && (tsk->mm->pax_flags & MF_PAX_PAGEEXEC)) { + struct mm_struct *mm = tsk->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, VM_EXEC); + up_write(&mm->mmap_sem); + return; + } + up_write(&mm->mmap_sem); + } +#endif + tsk->thread.error_code = error_code; tsk->thread.trap_no = 13; @@ -664,6 +680,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->cs & 0xFFFF) == __KERNEL_CS) + die("PAX: suspicious general protection fault", regs, error_code); + else +#endif + die("general protection fault", regs, error_code); } @@ -766,7 +789,7 @@ void notrace __kprobes die_nmi(char *str * If we are in kernel we are probably nested up pretty bad * and might aswell get out now while we still can: */ - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { current->thread.trap_no = 2; crash_kexec(regs); } @@ -915,7 +938,7 @@ void __kprobes do_debug(struct pt_regs * goto clear_dr7; } - if (regs->flags & X86_VM_MASK) + if (v8086_mode(regs)) goto debug_vm86; /* Save debug status register where ptrace can see it */ @@ -931,7 +954,7 @@ void __kprobes do_debug(struct pt_regs * * check for kernel mode by just checking the CPL * of CS. */ - if (!user_mode(regs)) + if (!user_mode_novm(regs)) goto clear_TF_reenable; } @@ -1086,7 +1109,7 @@ void do_simd_coprocessor_error(struct pt * Handle strange cache flush from user space exception * in all other cases. This is undocumented behaviour. */ - if (regs->flags & X86_VM_MASK) { + if (v8086_mode(regs)) { handle_vm86_fault((struct kernel_vm86_regs *)regs, error_code); return; } @@ -1106,19 +1129,14 @@ void do_spurious_interrupt_bug(struct pt unsigned long patch_espfix_desc(unsigned long uesp, unsigned long kesp) { - struct desc_struct *gdt = get_cpu_gdt_table(smp_processor_id()); unsigned long base = (kesp - uesp) & -THREAD_SIZE; unsigned long new_kesp = kesp - base; unsigned long lim_pages = (new_kesp | (THREAD_SIZE - 1)) >> PAGE_SHIFT; - __u64 desc = *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS]; + struct desc_struct ss; /* Set up base for espfix segment */ - desc &= 0x00f0ff0000000000ULL; - desc |= ((((__u64)base) << 16) & 0x000000ffffff0000ULL) | - ((((__u64)base) << 32) & 0xff00000000000000ULL) | - ((((__u64)lim_pages) << 32) & 0x000f000000000000ULL) | - (lim_pages & 0xffff); - *(__u64 *)&gdt[GDT_ENTRY_ESPFIX_SS] = desc; + pack_descriptor(&ss, base, lim_pages, 0x93, 0xC); + write_gdt_entry(get_cpu_gdt_table(smp_processor_id()), GDT_ENTRY_ESPFIX_SS, &ss, DESCTYPE_S); return new_kesp; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/traps_64.c linux-2.6.27.15-g-v/arch/x86/kernel/traps_64.c --- linux-2.6.27.15/arch/x86/kernel/traps_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/traps_64.c 2009-02-10 20:32:10.000000000 +0100 @@ -634,6 +634,12 @@ kernel_trap: tsk->thread.trap_no = trapnr; die(str, regs, error_code); } + +#ifdef CONFIG_PAX_REFCOUNT + if (trapnr == 4) + pax_report_refcount_overflow(regs); +#endif + return; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/tsc.c linux-2.6.27.15-g-v/arch/x86/kernel/tsc.c --- linux-2.6.27.15/arch/x86/kernel/tsc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/tsc.c 2009-02-10 20:32:10.000000000 +0100 @@ -554,7 +554,7 @@ static struct dmi_system_id __initdata b DMI_MATCH(DMI_BOARD_NAME, "2635FA0"), }, }, - {} + { NULL, NULL, Template:0, NULL, NULL} }; /* diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/vm86_32.c linux-2.6.27.15-g-v/arch/x86/kernel/vm86_32.c --- linux-2.6.27.15/arch/x86/kernel/vm86_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/vm86_32.c 2009-02-10 20:32:10.000000000 +0100 @@ -147,7 +147,7 @@ struct pt_regs *save_v86_state(struct ke do_exit(SIGSEGV); } - tss = &per_cpu(init_tss, get_cpu()); + tss = init_tss + get_cpu(); current->thread.sp0 = current->thread.saved_sp0; current->thread.sysenter_cs = __KERNEL_CS; load_sp0(tss, ¤t->thread); @@ -324,7 +324,7 @@ static void do_sys_vm86(struct kernel_vm tsk->thread.saved_fs = info->regs32->fs; savesegment(gs, tsk->thread.saved_gs); - tss = &per_cpu(init_tss, get_cpu()); + tss = init_tss + get_cpu(); tsk->thread.sp0 = (unsigned long) &info->VM86_TSS_ESP0; if (cpu_has_sep) tsk->thread.sysenter_cs = 0; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/vmi_32.c linux-2.6.27.15-g-v/arch/x86/kernel/vmi_32.c --- linux-2.6.27.15/arch/x86/kernel/vmi_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/vmi_32.c 2009-02-10 20:32:11.000000000 +0100 @@ -102,18 +102,43 @@ static unsigned patch_internal(int call, { u64 reloc; struct vmi_relocation_info *const rel = (struct vmi_relocation_info *)&reloc; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + reloc = call_vrom_long_func(vmi_rom, get_reloc, call); switch(rel->type) { case VMI_RELOCATION_CALL_REL: BUG_ON(len < 5); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + *(char *)insnbuf = MNEM_CALL; patch_offset(insnbuf, ip, (unsigned long)rel->eip); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + return 5; case VMI_RELOCATION_JUMP_REL: BUG_ON(len < 5); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + *(char *)insnbuf = MNEM_JMP; patch_offset(insnbuf, ip, (unsigned long)rel->eip); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + return 5; case VMI_RELOCATION_NOP: @@ -516,14 +541,14 @@ static void vmi_set_pud(pud_t *pudp, pud static void vmi_pte_clear(struct mm_struct *mm, unsigned long addr, pte_t *ptep) { - const pte_t pte = { .pte = 0 }; + const pte_t pte = __pte(0ULL); vmi_check_page_type(__pa(ptep) >> PAGE_SHIFT, VMI_PAGE_PTE); vmi_ops.set_pte(pte, ptep, vmi_flags_addr(mm, addr, VMI_PAGE_PT, 0)); } static void vmi_pmd_clear(pmd_t *pmd) { - const pte_t pte = { .pte = 0 }; + const pte_t pte = __pte(0ULL); vmi_check_page_type(__pa(pmd) >> PAGE_SHIFT, VMI_PAGE_PMD); vmi_ops.set_pte(pte, (pte_t *)pmd, VMI_PAGE_PD); } @@ -552,8 +577,8 @@ vmi_startup_ipi_hook(int phys_apicid, un ap.ss = __KERNEL_DS; ap.esp = (unsigned long) start_esp; - ap.ds = __USER_DS; - ap.es = __USER_DS; + ap.ds = __KERNEL_DS; + ap.es = __KERNEL_DS; ap.fs = __KERNEL_PERCPU; ap.gs = 0; @@ -748,12 +773,20 @@ static inline int __init activate_vmi(vo u64 reloc; const struct vmi_relocation_info *rel = (struct vmi_relocation_info *)&reloc; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + if (call_vrom_func(vmi_rom, vmi_init) != 0) { printk(KERN_ERR "VMI ROM failed to initialize!"); return 0; } savesegment(cs, kernel_cs); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + pv_info.paravirt_enabled = 1; pv_info.kernel_rpl = kernel_cs & SEGMENT_RPL_MASK; pv_info.name = "vmi"; @@ -943,6 +976,10 @@ static inline int __init activate_vmi(vo para_fill(pv_irq_ops.safe_halt, Halt); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* * Alternative instruction rewriting doesn't happen soon enough * to convert VMI_IRET to a call instead of a jump; so we have diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/vmlinux_32.lds.S linux-2.6.27.15-g-v/arch/x86/kernel/vmlinux_32.lds.S --- linux-2.6.27.15/arch/x86/kernel/vmlinux_32.lds.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/vmlinux_32.lds.S 2009-02-10 20:32:11.000000000 +0100 @@ -15,6 +15,20 @@ #include #include #include +#include + +#ifdef CONFIG_X86_PAE +#define PMD_SHIFT 21 +#else +#define PMD_SHIFT 22 +#endif +#define PMD_SIZE (1 << PMD_SHIFT) + +#ifdef CONFIG_PAX_KERNEXEC +#define __KERNEL_TEXT_OFFSET (__PAGE_OFFSET + (((____LOAD_PHYSICAL_ADDR + 2*(PMD_SIZE - 1)) - 1) & ~(PMD_SIZE - 1))) +#else +#define __KERNEL_TEXT_OFFSET 0 +#endif OUTPUT_FORMAT("elf32-i386", "elf32-i386", "elf32-i386") OUTPUT_ARCH(i386) @@ -22,81 +36,23 @@ ENTRY(phys_startup_32) jiffies = jiffies_64; PHDRS { - text PT_LOAD FLAGS(5); /* R_E */ - data PT_LOAD FLAGS(7); /* RWE */ - note PT_NOTE FLAGS(0); /* ___ */ + initdata PT_LOAD FLAGS(6); /* RW_ */ + percpu PT_LOAD FLAGS(6); /* RW_ */ + inittext PT_LOAD FLAGS(5); /* R_E */ + text PT_LOAD FLAGS(5); /* R_E */ + rodata PT_LOAD FLAGS(4); /* R__ */ + data PT_LOAD FLAGS(6); /* RW_ */ + note PT_NOTE FLAGS(0); /* ___ */ } SECTIONS { - . = LOAD_OFFSET + LOAD_PHYSICAL_ADDR; - phys_startup_32 = startup_32 - LOAD_OFFSET; - - .text.head : AT(ADDR(.text.head) - LOAD_OFFSET) { - _text = .; /* Text and read-only data */ - *(.text.head) - } :text = 0x9090 - - /* read-only */ - .text : AT(ADDR(.text) - LOAD_OFFSET) { - . = ALIGN(PAGE_SIZE); /* not really needed, already page aligned */ - *(.text.page_aligned) - TEXT_TEXT - SCHED_TEXT - LOCK_TEXT - KPROBES_TEXT - *(.fixup) - *(.gnu.warning) - _etext = .; /* End of text section */ - } :text = 0x9090 - - NOTES :text :note - - . = ALIGN(16); /* Exception table */ - __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { - __start___ex_table = .; - *(__ex_table) - __stop___ex_table = .; - } :text = 0x9090 - - RODATA - - /* writeable */ - . = ALIGN(PAGE_SIZE); - .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ - DATA_DATA - CONSTRUCTORS - } :data - - . = ALIGN(PAGE_SIZE); - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { - __nosave_begin = .; - *(.data.nosave) - . = ALIGN(PAGE_SIZE); - __nosave_end = .; - } - - . = ALIGN(PAGE_SIZE); - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { - *(.data.page_aligned) - *(.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 */ - } + . = LOAD_OFFSET + ____LOAD_PHYSICAL_ADDR; - . = ALIGN(THREAD_SIZE); /* init_task */ - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { - *(.data.init_task) - } + .text.startup : AT(ADDR(.text.startup) - LOAD_OFFSET) { + __LOAD_PHYSICAL_ADDR = . - LOAD_OFFSET; + phys_startup_32 = startup_32 - LOAD_OFFSET + __KERNEL_TEXT_OFFSET; + *(.text.startup) + } :initdata /* might get freed after init */ . = ALIGN(PAGE_SIZE); @@ -114,14 +70,8 @@ SECTIONS . = ALIGN(PAGE_SIZE); /* will be freed after init */ - . = ALIGN(PAGE_SIZE); /* Init code and data */ - .init.text : AT(ADDR(.init.text) - LOAD_OFFSET) { - __init_begin = .; - _sinittext = .; - INIT_TEXT - _einittext = .; - } .init.data : AT(ADDR(.init.data) - LOAD_OFFSET) { + __init_begin = .; INIT_DATA } . = ALIGN(16); @@ -161,11 +111,6 @@ SECTIONS *(.parainstructions) __parainstructions_end = .; } - /* .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 } @@ -178,17 +123,136 @@ SECTIONS } #endif . = ALIGN(PAGE_SIZE); - .data.percpu : AT(ADDR(.data.percpu) - LOAD_OFFSET) { - __per_cpu_start = .; + per_cpu_start = .; + .data.percpu (0) : AT(ADDR(.data.percpu) - LOAD_OFFSET + per_cpu_start) { + __per_cpu_start = . + per_cpu_start; + LONG(0) *(.data.percpu) *(.data.percpu.shared_aligned) - __per_cpu_end = .; - } + __per_cpu_end = . + per_cpu_start; + } :percpu + . += per_cpu_start; . = ALIGN(PAGE_SIZE); /* freed after init ends here */ + . = ALIGN(PAGE_SIZE); /* Init code and data */ + .init.text (. - __KERNEL_TEXT_OFFSET) : AT(ADDR(.init.text) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { + _sinittext = .; + INIT_TEXT + _einittext = .; + } :inittext + + /* .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 + } + + .filler : AT(ADDR(.filler) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { + BYTE(0) + . = ALIGN(2*PMD_SIZE) - 1; + } + + /* freed after init ends here */ + + .text.head : AT(ADDR(.text.head) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { + __init_end = . + __KERNEL_TEXT_OFFSET; + KERNEL_TEXT_OFFSET = . + __KERNEL_TEXT_OFFSET; + _text = .; /* Text and read-only data */ + *(.text.head) + } :text = 0x9090 + + /* read-only */ + .text : AT(ADDR(.text) - LOAD_OFFSET + __KERNEL_TEXT_OFFSET) { + . = ALIGN(PAGE_SIZE); /* not really needed, already page aligned */ + *(.text.page_aligned) + TEXT_TEXT + SCHED_TEXT + LOCK_TEXT + KPROBES_TEXT + *(.fixup) + *(.gnu.warning) + _etext = .; /* End of text section */ + } :text = 0x9090 + + . += __KERNEL_TEXT_OFFSET; + + . = ALIGN(4096); /* Exception table */ + __ex_table : AT(ADDR(__ex_table) - LOAD_OFFSET) { + __start___ex_table = .; + *(__ex_table) + __stop___ex_table = .; + } :rodata + + NOTES :rodata :note + + RO_DATA(PAGE_SIZE) + + . = ALIGN(PAGE_SIZE); + .rodata.page_aligned : AT(ADDR(.rodata.page_aligned) - LOAD_OFFSET) { + *(.idt) + . = ALIGN(PAGE_SIZE); + *(.empty_zero_page) + *(.swapper_pg_pmd) + *(.swapper_pg_dir) + } + +#ifdef CONFIG_PAX_KERNEXEC + +#ifdef CONFIG_MODULES + . = ALIGN(PAGE_SIZE); + .module.text : AT(ADDR(.module.text) - LOAD_OFFSET) { + MODULES_VADDR = .; + BYTE(0) + . += (6 * 1024 * 1024); + . = ALIGN( PMD_SIZE) - 1; + MODULES_END = .; + } +#else + . = ALIGN(PMD_SIZE) - 1; +#endif + +#endif + + /* writeable */ + . = ALIGN(PAGE_SIZE); + .data : AT(ADDR(.data) - LOAD_OFFSET) { /* Data */ + _data = .; + DATA_DATA + CONSTRUCTORS + } :data + + . = ALIGN(PAGE_SIZE); + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { + __nosave_begin = .; + *(.data.nosave) + . = ALIGN(PAGE_SIZE); + __nosave_end = .; + } + + . = ALIGN(PAGE_SIZE); + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + *(.data.page_aligned) + } + + . = 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) + } + .bss : AT(ADDR(.bss) - LOAD_OFFSET) { - __init_end = .; __bss_start = .; /* BSS */ *(.bss.page_aligned) *(.bss) diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/vmlinux_64.lds.S linux-2.6.27.15-g-v/arch/x86/kernel/vmlinux_64.lds.S --- linux-2.6.27.15/arch/x86/kernel/vmlinux_64.lds.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/vmlinux_64.lds.S 2009-02-10 20:32:11.000000000 +0100 @@ -16,7 +16,7 @@ jiffies_64 = jiffies; _proxy_pda = 1; PHDRS { text PT_LOAD FLAGS(5); /* R_E */ - data PT_LOAD FLAGS(7); /* RWE */ + data PT_LOAD FLAGS(6); /* RW_ */ user PT_LOAD FLAGS(7); /* RWE */ data.init PT_LOAD FLAGS(7); /* RWE */ note PT_NOTE FLAGS(0); /* ___ */ @@ -49,17 +49,20 @@ SECTIONS __stop___ex_table = .; } :text = 0x9090 - RODATA + RO_DATA(PAGE_SIZE) +#ifdef CONFIG_PAX_KERNEXEC + . = ALIGN(2*1024*1024); /* Align data segment to PMD size boundary */ +#else . = ALIGN(PAGE_SIZE); /* Align data segment to page size boundary */ +#endif /* Data */ + _data = .; .data : AT(ADDR(.data) - LOAD_OFFSET) { DATA_DATA CONSTRUCTORS } :data - _edata = .; /* End of data section */ - . = ALIGN(PAGE_SIZE); . = ALIGN(CONFIG_X86_L1_CACHE_BYTES); .data.cacheline_aligned : AT(ADDR(.data.cacheline_aligned) - LOAD_OFFSET) { @@ -70,9 +73,27 @@ SECTIONS *(.data.read_mostly) } + . = ALIGN(THREAD_SIZE); /* init_task */ + .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { + *(.data.init_task) + } + + . = ALIGN(PAGE_SIZE); + .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { + *(.data.page_aligned) + } + + . = ALIGN(PAGE_SIZE); + __nosave_begin = .; + .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } + . = ALIGN(PAGE_SIZE); + __nosave_end = .; + + _edata = .; /* End of data section */ + #define VSYSCALL_ADDR (-10*1024*1024) -#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) -#define VSYSCALL_VIRT_ADDR ((ADDR(.data.read_mostly) + SIZEOF(.data.read_mostly) + 4095) & ~(4095)) +#define VSYSCALL_PHYS_ADDR ((LOADADDR(.data_nosave) + SIZEOF(.data_nosave) + 4095) & ~(4095)) +#define VSYSCALL_VIRT_ADDR ((ADDR(.data_nosave) + SIZEOF(.data_nosave) + 4095) & ~(4095)) #define VLOAD_OFFSET (VSYSCALL_ADDR - VSYSCALL_PHYS_ADDR) #define VLOAD(x) (ADDR(x) - VLOAD_OFFSET) @@ -120,23 +141,13 @@ SECTIONS #undef VVIRT_OFFSET #undef VVIRT - . = ALIGN(THREAD_SIZE); /* init_task */ - .data.init_task : AT(ADDR(.data.init_task) - LOAD_OFFSET) { - *(.data.init_task) - }:data.init - - . = ALIGN(PAGE_SIZE); - .data.page_aligned : AT(ADDR(.data.page_aligned) - LOAD_OFFSET) { - *(.data.page_aligned) - } - /* might get freed after init */ . = ALIGN(PAGE_SIZE); __smp_alt_begin = .; __smp_locks = .; .smp_locks : AT(ADDR(.smp_locks) - LOAD_OFFSET) { *(.smp_locks) - } + } :data.init __smp_locks_end = .; . = ALIGN(PAGE_SIZE); __smp_alt_end = .; @@ -213,16 +224,11 @@ SECTIONS . = ALIGN(PAGE_SIZE); __init_end = .; - . = ALIGN(PAGE_SIZE); - __nosave_begin = .; - .data_nosave : AT(ADDR(.data_nosave) - LOAD_OFFSET) { *(.data.nosave) } - . = ALIGN(PAGE_SIZE); - __nosave_end = .; - __bss_start = .; /* BSS */ .bss : AT(ADDR(.bss) - LOAD_OFFSET) { *(.bss.page_aligned) *(.bss) + . = ALIGN(2*1024*1024); } __bss_stop = .; diff -NurpP --minimal linux-2.6.27.15/arch/x86/kernel/vsyscall_64.c linux-2.6.27.15-g-v/arch/x86/kernel/vsyscall_64.c --- linux-2.6.27.15/arch/x86/kernel/vsyscall_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kernel/vsyscall_64.c 2009-02-10 20:32:11.000000000 +0100 @@ -236,13 +236,13 @@ static ctl_table kernel_table2[] = { .data = &vsyscall_gtod_data.sysctl_enabled, .maxlen = sizeof(int), .mode = 0644, .proc_handler = vsyscall_sysctl_change }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static ctl_table kernel_root_table2[] = { { .ctl_name = CTL_KERN, .procname = "kernel", .mode = 0555, .child = kernel_table2 }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; #endif diff -NurpP --minimal linux-2.6.27.15/arch/x86/kvm/svm.c linux-2.6.27.15-g-v/arch/x86/kvm/svm.c --- linux-2.6.27.15/arch/x86/kvm/svm.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kvm/svm.c 2009-02-10 20:32:11.000000000 +0100 @@ -1515,7 +1515,19 @@ static void reload_tss(struct kvm_vcpu * int cpu = raw_smp_processor_id(); struct svm_cpu_data *svm_data = per_cpu(svm_data, cpu); + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + svm_data->tss_desc->type = 9; /* available 32/64-bit TSS */ + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + load_TR_desc(); } diff -NurpP --minimal linux-2.6.27.15/arch/x86/kvm/vmx.c linux-2.6.27.15-g-v/arch/x86/kvm/vmx.c --- linux-2.6.27.15/arch/x86/kvm/vmx.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kvm/vmx.c 2009-02-10 20:32:11.000000000 +0100 @@ -115,7 +115,7 @@ static struct vmcs_config { u32 vmentry_ctrl; } vmcs_config; -struct vmx_capability { +static struct vmx_capability { u32 ept; u32 vpid; } vmx_capability; @@ -484,9 +484,23 @@ static void reload_tss(void) struct descriptor_table gdt; struct desc_struct *descs; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + kvm_get_gdt(&gdt); descs = (void *)gdt.base; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + descs[GDT_ENTRY_TSS].type = 9; /* available TSS */ + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + load_TR_desc(); } @@ -3069,7 +3083,7 @@ static void vmx_vcpu_run(struct kvm_vcpu (vmcs_read32(GUEST_INTERRUPTIBILITY_INFO) & (GUEST_INTR_STATE_STI | GUEST_INTR_STATE_MOV_SS)) == 0; - asm("mov %0, %%ds; mov %0, %%es" : : "r"(__USER_DS)); + asm("mov %0, %%ds; mov %0, %%es" : : "r"(__KERNEL_DS)); vmx->launched = 1; intr_info = vmcs_read32(VM_EXIT_INTR_INFO); diff -NurpP --minimal linux-2.6.27.15/arch/x86/kvm/x86.c linux-2.6.27.15-g-v/arch/x86/kvm/x86.c --- linux-2.6.27.15/arch/x86/kvm/x86.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/kvm/x86.c 2009-02-10 20:32:11.000000000 +0100 @@ -63,35 +63,35 @@ static int kvm_dev_ioctl_get_supported_c struct kvm_x86_ops *kvm_x86_ops; struct kvm_stats_debugfs_item debugfs_entries[] = { - { "pf_fixed", VCPU_STAT(pf_fixed) }, - { "pf_guest", VCPU_STAT(pf_guest) }, - { "tlb_flush", VCPU_STAT(tlb_flush) }, - { "invlpg", VCPU_STAT(invlpg) }, - { "exits", VCPU_STAT(exits) }, - { "io_exits", VCPU_STAT(io_exits) }, - { "mmio_exits", VCPU_STAT(mmio_exits) }, - { "signal_exits", VCPU_STAT(signal_exits) }, - { "irq_window", VCPU_STAT(irq_window_exits) }, - { "nmi_window", VCPU_STAT(nmi_window_exits) }, - { "halt_exits", VCPU_STAT(halt_exits) }, - { "halt_wakeup", VCPU_STAT(halt_wakeup) }, - { "hypercalls", VCPU_STAT(hypercalls) }, - { "request_irq", VCPU_STAT(request_irq_exits) }, - { "irq_exits", VCPU_STAT(irq_exits) }, - { "host_state_reload", VCPU_STAT(host_state_reload) }, - { "efer_reload", VCPU_STAT(efer_reload) }, - { "fpu_reload", VCPU_STAT(fpu_reload) }, - { "insn_emulation", VCPU_STAT(insn_emulation) }, - { "insn_emulation_fail", VCPU_STAT(insn_emulation_fail) }, - { "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped) }, - { "mmu_pte_write", VM_STAT(mmu_pte_write) }, - { "mmu_pte_updated", VM_STAT(mmu_pte_updated) }, - { "mmu_pde_zapped", VM_STAT(mmu_pde_zapped) }, - { "mmu_flooded", VM_STAT(mmu_flooded) }, - { "mmu_recycled", VM_STAT(mmu_recycled) }, - { "mmu_cache_miss", VM_STAT(mmu_cache_miss) }, - { "remote_tlb_flush", VM_STAT(remote_tlb_flush) }, - { "largepages", VM_STAT(lpages) }, + { "pf_fixed", VCPU_STAT(pf_fixed), NULL }, + { "pf_guest", VCPU_STAT(pf_guest), NULL }, + { "tlb_flush", VCPU_STAT(tlb_flush), NULL }, + { "invlpg", VCPU_STAT(invlpg), NULL }, + { "exits", VCPU_STAT(exits), NULL }, + { "io_exits", VCPU_STAT(io_exits), NULL }, + { "mmio_exits", VCPU_STAT(mmio_exits), NULL }, + { "signal_exits", VCPU_STAT(signal_exits), NULL }, + { "irq_window", VCPU_STAT(irq_window_exits), NULL }, + { "nmi_window", VCPU_STAT(nmi_window_exits), NULL }, + { "halt_exits", VCPU_STAT(halt_exits), NULL }, + { "halt_wakeup", VCPU_STAT(halt_wakeup), NULL }, + { "hypercalls", VCPU_STAT(hypercalls), NULL }, + { "request_irq", VCPU_STAT(request_irq_exits), NULL }, + { "irq_exits", VCPU_STAT(irq_exits), NULL }, + { "host_state_reload", VCPU_STAT(host_state_reload), NULL }, + { "efer_reload", VCPU_STAT(efer_reload), NULL }, + { "fpu_reload", VCPU_STAT(fpu_reload), NULL }, + { "insn_emulation", VCPU_STAT(insn_emulation), NULL }, + { "insn_emulation_fail", VCPU_STAT(insn_emulation_fail), NULL }, + { "mmu_shadow_zapped", VM_STAT(mmu_shadow_zapped), NULL }, + { "mmu_pte_write", VM_STAT(mmu_pte_write), NULL }, + { "mmu_pte_updated", VM_STAT(mmu_pte_updated), NULL }, + { "mmu_pde_zapped", VM_STAT(mmu_pde_zapped), NULL }, + { "mmu_flooded", VM_STAT(mmu_flooded), NULL }, + { "mmu_recycled", VM_STAT(mmu_recycled), NULL }, + { "mmu_cache_miss", VM_STAT(mmu_cache_miss), NULL }, + { "remote_tlb_flush", VM_STAT(remote_tlb_flush), NULL }, + { "largepages", VM_STAT(lpages), NULL }, { NULL } }; @@ -1274,7 +1274,7 @@ static int kvm_vcpu_ioctl_set_lapic(stru static int kvm_vcpu_ioctl_interrupt(struct kvm_vcpu *vcpu, struct kvm_interrupt *irq) { - if (irq->irq < 0 || irq->irq >= 256) + if (irq->irq >= 256) return -EINVAL; if (irqchip_in_kernel(vcpu->kvm)) return -ENXIO; diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/checksum_32.S linux-2.6.27.15-g-v/arch/x86/lib/checksum_32.S --- linux-2.6.27.15/arch/x86/lib/checksum_32.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/checksum_32.S 2009-02-10 20:32:11.000000000 +0100 @@ -28,7 +28,8 @@ #include #include #include - +#include + /* * computes a partial checksum, e.g. for TCP/UDP fragments */ @@ -304,9 +305,22 @@ unsigned int csum_partial_copy_generic ( #define ARGBASE 16 #define FP 12 - -ENTRY(csum_partial_copy_generic) + +ENTRY(csum_partial_copy_generic_to_user) CFI_STARTPROC + pushl $(__USER_DS) + CFI_ADJUST_CFA_OFFSET 4 + popl %es + CFI_ADJUST_CFA_OFFSET -4 + jmp csum_partial_copy_generic + +ENTRY(csum_partial_copy_generic_from_user) + pushl $(__USER_DS) + CFI_ADJUST_CFA_OFFSET 4 + popl %ds + CFI_ADJUST_CFA_OFFSET -4 + +ENTRY(csum_partial_copy_generic) subl $4,%esp CFI_ADJUST_CFA_OFFSET 4 pushl %edi @@ -331,7 +345,7 @@ ENTRY(csum_partial_copy_generic) jmp 4f SRC(1: movw (%esi), %bx ) addl $2, %esi -DST( movw %bx, (%edi) ) +DST( movw %bx, %es:(%edi) ) addl $2, %edi addw %bx, %ax adcl $0, %eax @@ -343,30 +357,30 @@ DST( movw %bx, (%edi) ) SRC(1: movl (%esi), %ebx ) SRC( movl 4(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, (%edi) ) +DST( movl %ebx, %es:(%edi) ) adcl %edx, %eax -DST( movl %edx, 4(%edi) ) +DST( movl %edx, %es:4(%edi) ) SRC( movl 8(%esi), %ebx ) SRC( movl 12(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 8(%edi) ) +DST( movl %ebx, %es:8(%edi) ) adcl %edx, %eax -DST( movl %edx, 12(%edi) ) +DST( movl %edx, %es:12(%edi) ) SRC( movl 16(%esi), %ebx ) SRC( movl 20(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 16(%edi) ) +DST( movl %ebx, %es:16(%edi) ) adcl %edx, %eax -DST( movl %edx, 20(%edi) ) +DST( movl %edx, %es:20(%edi) ) SRC( movl 24(%esi), %ebx ) SRC( movl 28(%esi), %edx ) adcl %ebx, %eax -DST( movl %ebx, 24(%edi) ) +DST( movl %ebx, %es:24(%edi) ) adcl %edx, %eax -DST( movl %edx, 28(%edi) ) +DST( movl %edx, %es:28(%edi) ) lea 32(%esi), %esi lea 32(%edi), %edi @@ -380,7 +394,7 @@ DST( movl %edx, 28(%edi) ) shrl $2, %edx # This clears CF SRC(3: movl (%esi), %ebx ) adcl %ebx, %eax -DST( movl %ebx, (%edi) ) +DST( movl %ebx, %es:(%edi) ) lea 4(%esi), %esi lea 4(%edi), %edi dec %edx @@ -392,12 +406,12 @@ DST( movl %ebx, (%edi) ) jb 5f SRC( movw (%esi), %cx ) leal 2(%esi), %esi -DST( movw %cx, (%edi) ) +DST( movw %cx, %es:(%edi) ) leal 2(%edi), %edi je 6f shll $16,%ecx SRC(5: movb (%esi), %cl ) -DST( movb %cl, (%edi) ) +DST( movb %cl, %es:(%edi) ) 6: addl %ecx, %eax adcl $0, %eax 7: @@ -408,7 +422,7 @@ DST( movb %cl, (%edi) ) 6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) # zero the complete destination - computing the rest # is too much work @@ -421,11 +435,19 @@ DST( movb %cl, (%edi) ) 6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT,(%ebx) + movl $-EFAULT,%ss:(%ebx) jmp 5000b .previous + pushl %ss + CFI_ADJUST_CFA_OFFSET 4 + popl %ds + CFI_ADJUST_CFA_OFFSET -4 + pushl %ss + CFI_ADJUST_CFA_OFFSET 4 + popl %es + CFI_ADJUST_CFA_OFFSET -4 popl %ebx CFI_ADJUST_CFA_OFFSET -4 CFI_RESTORE ebx @@ -439,26 +461,41 @@ DST( movb %cl, (%edi) ) CFI_ADJUST_CFA_OFFSET -4 ret CFI_ENDPROC -ENDPROC(csum_partial_copy_generic) +ENDPROC(csum_partial_copy_generic_to_user) #else /* Version for PentiumII/PPro */ #define ROUND1(x) \ + nop; nop; nop; \ SRC(movl x(%esi), %ebx ) ; \ addl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; + DST(movl %ebx, %es:x(%edi)) ; #define ROUND(x) \ + nop; nop; nop; \ SRC(movl x(%esi), %ebx ) ; \ adcl %ebx, %eax ; \ - DST(movl %ebx, x(%edi) ) ; + DST(movl %ebx, %es:x(%edi)) ; #define ARGBASE 12 - -ENTRY(csum_partial_copy_generic) + +ENTRY(csum_partial_copy_generic_to_user) CFI_STARTPROC + pushl $(__USER_DS) + CFI_ADJUST_CFA_OFFSET 4 + popl %es + CFI_ADJUST_CFA_OFFSET -4 + jmp csum_partial_copy_generic + +ENTRY(csum_partial_copy_generic_from_user) + pushl $(__USER_DS) + CFI_ADJUST_CFA_OFFSET 4 + popl %ds + CFI_ADJUST_CFA_OFFSET -4 + +ENTRY(csum_partial_copy_generic) pushl %ebx CFI_ADJUST_CFA_OFFSET 4 CFI_REL_OFFSET ebx, 0 @@ -482,7 +519,7 @@ ENTRY(csum_partial_copy_generic) subl %ebx, %edi lea -1(%esi),%edx andl $-32,%edx - lea 3f(%ebx,%ebx), %ebx + lea 3f(%ebx,%ebx,2), %ebx testl %esi, %esi jmp *%ebx 1: addl $64,%esi @@ -503,19 +540,19 @@ ENTRY(csum_partial_copy_generic) jb 5f SRC( movw (%esi), %dx ) leal 2(%esi), %esi -DST( movw %dx, (%edi) ) +DST( movw %dx, %es:(%edi) ) leal 2(%edi), %edi je 6f shll $16,%edx 5: SRC( movb (%esi), %dl ) -DST( movb %dl, (%edi) ) +DST( movb %dl, %es:(%edi) ) 6: addl %edx, %eax adcl $0, %eax 7: .section .fixup, "ax" 6001: movl ARGBASE+20(%esp), %ebx # src_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) # zero the complete destination (computing the rest is too much work) movl ARGBASE+8(%esp),%edi # dst movl ARGBASE+12(%esp),%ecx # len @@ -523,10 +560,18 @@ DST( movb %dl, (%edi) ) rep; stosb jmp 7b 6002: movl ARGBASE+24(%esp), %ebx # dst_err_ptr - movl $-EFAULT, (%ebx) + movl $-EFAULT, %ss:(%ebx) jmp 7b .previous + pushl %ss + CFI_ADJUST_CFA_OFFSET 4 + popl %ds + CFI_ADJUST_CFA_OFFSET -4 + pushl %ss + CFI_ADJUST_CFA_OFFSET 4 + popl %es + CFI_ADJUST_CFA_OFFSET -4 popl %esi CFI_ADJUST_CFA_OFFSET -4 CFI_RESTORE esi @@ -538,7 +583,7 @@ DST( movb %dl, (%edi) ) CFI_RESTORE ebx ret CFI_ENDPROC -ENDPROC(csum_partial_copy_generic) +ENDPROC(csum_partial_copy_generic_to_user) #undef ROUND #undef ROUND1 diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/clear_page_64.S linux-2.6.27.15-g-v/arch/x86/lib/clear_page_64.S --- linux-2.6.27.15/arch/x86/lib/clear_page_64.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/clear_page_64.S 2009-02-10 20:32:11.000000000 +0100 @@ -44,7 +44,7 @@ ENDPROC(clear_page) #include - .section .altinstr_replacement,"ax" + .section .altinstr_replacement,"a" 1: .byte 0xeb /* jmp */ .byte (clear_page_c - clear_page) - (2f - 1b) /* offset */ 2: diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/copy_page_64.S linux-2.6.27.15-g-v/arch/x86/lib/copy_page_64.S --- linux-2.6.27.15/arch/x86/lib/copy_page_64.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/copy_page_64.S 2009-02-10 20:32:11.000000000 +0100 @@ -104,7 +104,7 @@ ENDPROC(copy_page) #include - .section .altinstr_replacement,"ax" + .section .altinstr_replacement,"a" 1: .byte 0xeb /* jmp */ .byte (copy_page_c - copy_page) - (2f - 1b) /* offset */ 2: diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/copy_user_64.S linux-2.6.27.15-g-v/arch/x86/lib/copy_user_64.S --- linux-2.6.27.15/arch/x86/lib/copy_user_64.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/copy_user_64.S 2009-02-10 20:32:11.000000000 +0100 @@ -21,7 +21,7 @@ .byte 0xe9 /* 32bit jump */ .long \orig-1f /* by default jump to orig */ 1: - .section .altinstr_replacement,"ax" + .section .altinstr_replacement,"a" 2: .byte 0xe9 /* near jump with 32bit immediate */ .long \alt-1b /* offset */ /* or alternatively to alt */ .previous @@ -106,6 +106,8 @@ ENDPROC(__copy_from_user_inatomic) ENTRY(bad_from_user) bad_from_user: CFI_STARTPROC + testl %edx,%edx + js bad_to_user movl %edx,%ecx xorl %eax,%eax rep diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/getuser.S linux-2.6.27.15-g-v/arch/x86/lib/getuser.S --- linux-2.6.27.15/arch/x86/lib/getuser.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/getuser.S 2009-02-10 20:32:11.000000000 +0100 @@ -33,6 +33,7 @@ #include #include #include +#include .text ENTRY(__get_user_1) @@ -40,7 +41,19 @@ ENTRY(__get_user_1) GET_THREAD_INFO(%_ASM_DX) cmp TI_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user + +#ifdef CONFIG_X86_32 + pushl $(__USER_DS) + popl %ds +#endif + 1: movzb (%_ASM_AX),%edx + +#ifdef CONFIG_X86_32 + pushl %ss + pop %ds +#endif + xor %eax,%eax ret CFI_ENDPROC @@ -53,7 +66,19 @@ ENTRY(__get_user_2) GET_THREAD_INFO(%_ASM_DX) cmp TI_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user + +#ifdef CONFIG_X86_32 + pushl $(__USER_DS) + popl %ds +#endif + 2: movzwl -1(%_ASM_AX),%edx + +#ifdef CONFIG_X86_32 + pushl %ss + pop %ds +#endif + xor %eax,%eax ret CFI_ENDPROC @@ -66,7 +91,19 @@ ENTRY(__get_user_4) GET_THREAD_INFO(%_ASM_DX) cmp TI_addr_limit(%_ASM_DX),%_ASM_AX jae bad_get_user + +#ifdef CONFIG_X86_32 + pushl $(__USER_DS) + popl %ds +#endif + 3: mov -3(%_ASM_AX),%edx + +#ifdef CONFIG_X86_32 + pushl %ss + pop %ds +#endif + xor %eax,%eax ret CFI_ENDPROC @@ -89,6 +126,12 @@ ENDPROC(__get_user_8) bad_get_user: CFI_STARTPROC + +#ifdef CONFIG_X86_32 + pushl %ss + pop %ds +#endif + xor %edx,%edx mov $(-EFAULT),%_ASM_AX ret diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/memcpy_64.S linux-2.6.27.15-g-v/arch/x86/lib/memcpy_64.S --- linux-2.6.27.15/arch/x86/lib/memcpy_64.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/memcpy_64.S 2009-02-10 20:32:11.000000000 +0100 @@ -114,7 +114,7 @@ ENDPROC(__memcpy) /* Some CPUs run faster using the string copy instructions. It is also a lot simpler. Use this when possible */ - .section .altinstr_replacement,"ax" + .section .altinstr_replacement,"a" 1: .byte 0xeb /* jmp */ .byte (memcpy_c - memcpy) - (2f - 1b) /* offset */ 2: diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/memset_64.S linux-2.6.27.15-g-v/arch/x86/lib/memset_64.S --- linux-2.6.27.15/arch/x86/lib/memset_64.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/memset_64.S 2009-02-10 20:32:11.000000000 +0100 @@ -118,7 +118,7 @@ ENDPROC(__memset) #include - .section .altinstr_replacement,"ax" + .section .altinstr_replacement,"a" 1: .byte 0xeb /* jmp */ .byte (memset_c - memset) - (2f - 1b) /* offset */ 2: diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/mmx_32.c linux-2.6.27.15-g-v/arch/x86/lib/mmx_32.c --- linux-2.6.27.15/arch/x86/lib/mmx_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/mmx_32.c 2009-02-10 20:32:11.000000000 +0100 @@ -29,6 +29,7 @@ void *_mmx_memcpy(void *to, const void * { void *p; int i; + unsigned long cr0; if (unlikely(in_interrupt())) return __memcpy(to, from, len); @@ -39,44 +40,72 @@ void *_mmx_memcpy(void *to, const void * kernel_fpu_begin(); __asm__ __volatile__ ( - "1: prefetch (%0)\n" /* This set is 28 bytes */ - " prefetch 64(%0)\n" - " prefetch 128(%0)\n" - " prefetch 192(%0)\n" - " prefetch 256(%0)\n" + "1: prefetch (%1)\n" /* This set is 28 bytes */ + " prefetch 64(%1)\n" + " prefetch 128(%1)\n" + " prefetch 192(%1)\n" + " prefetch 256(%1)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" _ASM_EXTABLE(1b, 3b) - : : "r" (from)); + : "=&r" (cr0) : "r" (from) : "ax"); for ( ; i > 5; i--) { __asm__ __volatile__ ( - "1: prefetch 320(%0)\n" - "2: movq (%0), %%mm0\n" - " movq 8(%0), %%mm1\n" - " movq 16(%0), %%mm2\n" - " movq 24(%0), %%mm3\n" - " movq %%mm0, (%1)\n" - " movq %%mm1, 8(%1)\n" - " movq %%mm2, 16(%1)\n" - " movq %%mm3, 24(%1)\n" - " movq 32(%0), %%mm0\n" - " movq 40(%0), %%mm1\n" - " movq 48(%0), %%mm2\n" - " movq 56(%0), %%mm3\n" - " movq %%mm0, 32(%1)\n" - " movq %%mm1, 40(%1)\n" - " movq %%mm2, 48(%1)\n" - " movq %%mm3, 56(%1)\n" + "1: prefetch 320(%1)\n" + "2: movq (%1), %%mm0\n" + " movq 8(%1), %%mm1\n" + " movq 16(%1), %%mm2\n" + " movq 24(%1), %%mm3\n" + " movq %%mm0, (%2)\n" + " movq %%mm1, 8(%2)\n" + " movq %%mm2, 16(%2)\n" + " movq %%mm3, 24(%2)\n" + " movq 32(%1), %%mm0\n" + " movq 40(%1), %%mm1\n" + " movq 48(%1), %%mm2\n" + " movq 56(%1), %%mm3\n" + " movq %%mm0, 32(%2)\n" + " movq %%mm1, 40(%2)\n" + " movq %%mm2, 48(%2)\n" + " movq %%mm3, 56(%2)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" _ASM_EXTABLE(1b, 3b) - : : "r" (from), "r" (to) : "memory"); + : "=&r" (cr0) : "r" (from), "r" (to) : "memory", "ax"); from += 64; to += 64; @@ -158,6 +187,7 @@ static void fast_clear_page(void *page) static void fast_copy_page(void *to, void *from) { int i; + unsigned long cr0; kernel_fpu_begin(); @@ -166,42 +196,70 @@ static void fast_copy_page(void *to, voi * but that is for later. -AV */ __asm__ __volatile__( - "1: prefetch (%0)\n" - " prefetch 64(%0)\n" - " prefetch 128(%0)\n" - " prefetch 192(%0)\n" - " prefetch 256(%0)\n" + "1: prefetch (%1)\n" + " prefetch 64(%1)\n" + " prefetch 128(%1)\n" + " prefetch 192(%1)\n" + " prefetch 256(%1)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" - _ASM_EXTABLE(1b, 3b) : : "r" (from)); + _ASM_EXTABLE(1b, 3b) : "=&r" (cr0) : "r" (from) : "ax"); for (i = 0; i < (4096-320)/64; i++) { __asm__ __volatile__ ( - "1: prefetch 320(%0)\n" - "2: movq (%0), %%mm0\n" - " movntq %%mm0, (%1)\n" - " movq 8(%0), %%mm1\n" - " movntq %%mm1, 8(%1)\n" - " movq 16(%0), %%mm2\n" - " movntq %%mm2, 16(%1)\n" - " movq 24(%0), %%mm3\n" - " movntq %%mm3, 24(%1)\n" - " movq 32(%0), %%mm4\n" - " movntq %%mm4, 32(%1)\n" - " movq 40(%0), %%mm5\n" - " movntq %%mm5, 40(%1)\n" - " movq 48(%0), %%mm6\n" - " movntq %%mm6, 48(%1)\n" - " movq 56(%0), %%mm7\n" - " movntq %%mm7, 56(%1)\n" + "1: prefetch 320(%1)\n" + "2: movq (%1), %%mm0\n" + " movntq %%mm0, (%2)\n" + " movq 8(%1), %%mm1\n" + " movntq %%mm1, 8(%2)\n" + " movq 16(%1), %%mm2\n" + " movntq %%mm2, 16(%2)\n" + " movq 24(%1), %%mm3\n" + " movntq %%mm3, 24(%2)\n" + " movq 32(%1), %%mm4\n" + " movntq %%mm4, 32(%2)\n" + " movq 40(%1), %%mm5\n" + " movntq %%mm5, 40(%2)\n" + " movq 48(%1), %%mm6\n" + " movntq %%mm6, 48(%2)\n" + " movq 56(%1), %%mm7\n" + " movntq %%mm7, 56(%2)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" - _ASM_EXTABLE(1b, 3b) : : "r" (from), "r" (to) : "memory"); + _ASM_EXTABLE(1b, 3b) : "=&r" (cr0) : "r" (from), "r" (to) : "memory", "ax"); from += 64; to += 64; @@ -280,47 +338,76 @@ static void fast_clear_page(void *page) static void fast_copy_page(void *to, void *from) { int i; + unsigned long cr0; kernel_fpu_begin(); __asm__ __volatile__ ( - "1: prefetch (%0)\n" - " prefetch 64(%0)\n" - " prefetch 128(%0)\n" - " prefetch 192(%0)\n" - " prefetch 256(%0)\n" + "1: prefetch (%1)\n" + " prefetch 64(%1)\n" + " prefetch 128(%1)\n" + " prefetch 192(%1)\n" + " prefetch 256(%1)\n" "2: \n" ".section .fixup, \"ax\"\n" - "3: movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + "3: \n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x1AEB, 1b\n" /* jmp on 26 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" - _ASM_EXTABLE(1b, 3b) : : "r" (from)); + _ASM_EXTABLE(1b, 3b) : "=&r" (cr0) : "r" (from) : "ax"); for (i = 0; i < 4096/64; i++) { __asm__ __volatile__ ( - "1: prefetch 320(%0)\n" - "2: movq (%0), %%mm0\n" - " movq 8(%0), %%mm1\n" - " movq 16(%0), %%mm2\n" - " movq 24(%0), %%mm3\n" - " movq %%mm0, (%1)\n" - " movq %%mm1, 8(%1)\n" - " movq %%mm2, 16(%1)\n" - " movq %%mm3, 24(%1)\n" - " movq 32(%0), %%mm0\n" - " movq 40(%0), %%mm1\n" - " movq 48(%0), %%mm2\n" - " movq 56(%0), %%mm3\n" - " movq %%mm0, 32(%1)\n" - " movq %%mm1, 40(%1)\n" - " movq %%mm2, 48(%1)\n" - " movq %%mm3, 56(%1)\n" + "1: prefetch 320(%1)\n" + "2: movq (%1), %%mm0\n" + " movq 8(%1), %%mm1\n" + " movq 16(%1), %%mm2\n" + " movq 24(%1), %%mm3\n" + " movq %%mm0, (%2)\n" + " movq %%mm1, 8(%2)\n" + " movq %%mm2, 16(%2)\n" + " movq %%mm3, 24(%2)\n" + " movq 32(%1), %%mm0\n" + " movq 40(%1), %%mm1\n" + " movq 48(%1), %%mm2\n" + " movq 56(%1), %%mm3\n" + " movq %%mm0, 32(%2)\n" + " movq %%mm1, 40(%2)\n" + " movq %%mm2, 48(%2)\n" + " movq %%mm3, 56(%2)\n" ".section .fixup, \"ax\"\n" - "3: movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + "3:\n" + +#ifdef CONFIG_PAX_KERNEXEC + " movl %%cr0, %0\n" + " movl %0, %%eax\n" + " andl $0xFFFEFFFF, %%eax\n" + " movl %%eax, %%cr0\n" +#endif + + " movw $0x05EB, 1b\n" /* jmp on 5 bytes */ + +#ifdef CONFIG_PAX_KERNEXEC + " movl %0, %%cr0\n" +#endif + " jmp 2b\n" ".previous\n" _ASM_EXTABLE(1b, 3b) - : : "r" (from), "r" (to) : "memory"); + : "=&r" (cr0) : "r" (from), "r" (to) : "memory", "ax"); from += 64; to += 64; diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/putuser.S linux-2.6.27.15-g-v/arch/x86/lib/putuser.S --- linux-2.6.27.15/arch/x86/lib/putuser.S 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/putuser.S 2009-02-10 20:32:11.000000000 +0100 @@ -15,6 +15,7 @@ #include #include #include +#include /* @@ -39,7 +40,19 @@ ENTRY(__put_user_1) ENTER cmp TI_addr_limit(%_ASM_BX),%_ASM_CX jae bad_put_user + +#ifdef CONFIG_X86_32 + pushl $(__USER_DS) + popl %ds +#endif + 1: movb %al,(%_ASM_CX) + +#ifdef CONFIG_X86_32 + pushl %ss + popl %ds +#endif + xor %eax,%eax EXIT ENDPROC(__put_user_1) @@ -50,7 +63,19 @@ ENTRY(__put_user_2) sub $1,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user + +#ifdef CONFIG_X86_32 + pushl $(__USER_DS) + popl %ds +#endif + 2: movw %ax,(%_ASM_CX) + +#ifdef CONFIG_X86_32 + pushl %ss + popl %ds +#endif + xor %eax,%eax EXIT ENDPROC(__put_user_2) @@ -61,7 +86,19 @@ ENTRY(__put_user_4) sub $3,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user + +#ifdef CONFIG_X86_32 + pushl $(__USER_DS) + popl %ds +#endif + 3: movl %eax,(%_ASM_CX) + +#ifdef CONFIG_X86_32 + pushl %ss + popl %ds +#endif + xor %eax,%eax EXIT ENDPROC(__put_user_4) @@ -72,16 +109,34 @@ ENTRY(__put_user_8) sub $7,%_ASM_BX cmp %_ASM_BX,%_ASM_CX jae bad_put_user + +#ifdef CONFIG_X86_32 + pushl $(__USER_DS) + popl %ds +#endif + 4: mov %_ASM_AX,(%_ASM_CX) #ifdef CONFIG_X86_32 5: movl %edx,4(%_ASM_CX) #endif + +#ifdef CONFIG_X86_32 + pushl %ss + popl %ds +#endif + xor %eax,%eax EXIT ENDPROC(__put_user_8) bad_put_user: CFI_STARTPROC + +#ifdef CONFIG_X86_32 + pushl %ss + popl %ds +#endif + movl $-EFAULT,%eax EXIT END(bad_put_user) diff -NurpP --minimal linux-2.6.27.15/arch/x86/lib/usercopy_32.c linux-2.6.27.15-g-v/arch/x86/lib/usercopy_32.c --- linux-2.6.27.15/arch/x86/lib/usercopy_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/lib/usercopy_32.c 2009-02-10 20:32:11.000000000 +0100 @@ -29,31 +29,38 @@ static inline int __movsl_is_ok(unsigned * Copy a null terminated string from userspace. */ -#define __do_strncpy_from_user(dst, src, count, res) \ -do { \ - int __d0, __d1, __d2; \ - might_sleep(); \ - __asm__ __volatile__( \ - " testl %1,%1\n" \ - " jz 2f\n" \ - "0: lodsb\n" \ - " stosb\n" \ - " testb %%al,%%al\n" \ - " jz 1f\n" \ - " decl %1\n" \ - " jnz 0b\n" \ - "1: subl %1,%0\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: movl %5,%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(0b,3b) \ - : "=&d"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), \ - "=&D" (__d2) \ - : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst) \ - : "memory"); \ -} while (0) +static long __do_strncpy_from_user(char *dst, const char __user *src, long count) +{ + int __d0, __d1, __d2; + long res = -EFAULT; + + might_sleep(); + __asm__ __volatile__( + " movw %w10,%%ds\n" + " testl %1,%1\n" + " jz 2f\n" + "0: lodsb\n" + " stosb\n" + " testb %%al,%%al\n" + " jz 1f\n" + " decl %1\n" + " jnz 0b\n" + "1: subl %1,%0\n" + "2:\n" + " pushl %%ss\n" + " popl %%ds\n" + ".section .fixup,\"ax\"\n" + "3: movl %5,%0\n" + " jmp 2b\n" + ".previous\n" + _ASM_EXTABLE(0b,3b) + : "=&d"(res), "=&c"(count), "=&a" (__d0), "=&S" (__d1), + "=&D" (__d2) + : "i"(-EFAULT), "0"(count), "1"(count), "3"(src), "4"(dst), + "r"(__USER_DS) + : "memory"); + return res; +} /** * __strncpy_from_user: - Copy a NUL terminated string from userspace, with less checking. @@ -78,9 +85,7 @@ do { \ long __strncpy_from_user(char *dst, const char __user *src, long count) { - long res; - __do_strncpy_from_user(dst, src, count, res); - return res; + return __do_strncpy_from_user(dst, src, count); } EXPORT_SYMBOL(__strncpy_from_user); @@ -107,7 +112,7 @@ strncpy_from_user(char *dst, const char { long res = -EFAULT; if (access_ok(VERIFY_READ, src, 1)) - __do_strncpy_from_user(dst, src, count, res); + res = __do_strncpy_from_user(dst, src, count); return res; } EXPORT_SYMBOL(strncpy_from_user); @@ -116,24 +121,30 @@ EXPORT_SYMBOL(strncpy_from_user); * Zero Userspace */ -#define __do_clear_user(addr,size) \ -do { \ - int __d0; \ - might_sleep(); \ - __asm__ __volatile__( \ - "0: rep; stosl\n" \ - " movl %2,%0\n" \ - "1: rep; stosb\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "3: lea 0(%2,%0,4),%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - _ASM_EXTABLE(0b,3b) \ - _ASM_EXTABLE(1b,2b) \ - : "=&c"(size), "=&D" (__d0) \ - : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0)); \ -} while (0) +static unsigned long __do_clear_user(void __user *addr, unsigned long size) +{ + int __d0; + + might_sleep(); + __asm__ __volatile__( + " movw %w6,%%es\n" + "0: rep; stosl\n" + " movl %2,%0\n" + "1: rep; stosb\n" + "2:\n" + " pushl %%ss\n" + " popl %%es\n" + ".section .fixup,\"ax\"\n" + "3: lea 0(%2,%0,4),%0\n" + " jmp 2b\n" + ".previous\n" + _ASM_EXTABLE(0b,3b) + _ASM_EXTABLE(1b,2b) + : "=&c"(size), "=&D" (__d0) + : "r"(size & 3), "0"(size / 4), "1"(addr), "a"(0), + "r"(__USER_DS)); + return size; +} /** * clear_user: - Zero a block of memory in user space. @@ -150,7 +161,7 @@ clear_user(void __user *to, unsigned lon { might_sleep(); if (access_ok(VERIFY_WRITE, to, n)) - __do_clear_user(to, n); + n = __do_clear_user(to, n); return n; } EXPORT_SYMBOL(clear_user); @@ -169,8 +180,7 @@ EXPORT_SYMBOL(clear_user); unsigned long __clear_user(void __user *to, unsigned long n) { - __do_clear_user(to, n); - return n; + return __do_clear_user(to, n); } EXPORT_SYMBOL(__clear_user); @@ -193,14 +203,17 @@ long strnlen_user(const char __user *s, might_sleep(); __asm__ __volatile__( + " movw %w8,%%es\n" " testl %0, %0\n" " jz 3f\n" - " andl %0,%%ecx\n" + " movl %0,%%ecx\n" "0: repne; scasb\n" " setne %%al\n" " subl %%ecx,%0\n" " addl %0,%%eax\n" "1:\n" + " pushl %%ss\n" + " popl %%es\n" ".section .fixup,\"ax\"\n" "2: xorl %%eax,%%eax\n" " jmp 1b\n" @@ -212,7 +225,7 @@ long strnlen_user(const char __user *s, " .long 0b,2b\n" ".previous" :"=&r" (n), "=&D" (s), "=&a" (res), "=&c" (tmp) - :"0" (n), "1" (s), "2" (0), "3" (mask) + :"0" (n), "1" (s), "2" (0), "3" (mask), "r" (__USER_DS) :"cc"); return res & mask; } @@ -220,10 +233,11 @@ EXPORT_SYMBOL(strnlen_user); #ifdef CONFIG_X86_INTEL_USERCOPY static unsigned long -__copy_user_intel(void __user *to, const void *from, unsigned long size) +__generic_copy_to_user_intel(void __user *to, const void *from, unsigned long size) { int d0, d1; __asm__ __volatile__( + " movw %w6, %%es\n" " .align 2,0x90\n" "1: movl 32(%4), %%eax\n" " cmpl $67, %0\n" @@ -232,36 +246,36 @@ __copy_user_intel(void __user *to, const " .align 2,0x90\n" "3: movl 0(%4), %%eax\n" "4: movl 4(%4), %%edx\n" - "5: movl %%eax, 0(%3)\n" - "6: movl %%edx, 4(%3)\n" + "5: movl %%eax, %%es:0(%3)\n" + "6: movl %%edx, %%es:4(%3)\n" "7: movl 8(%4), %%eax\n" "8: movl 12(%4),%%edx\n" - "9: movl %%eax, 8(%3)\n" - "10: movl %%edx, 12(%3)\n" + "9: movl %%eax, %%es:8(%3)\n" + "10: movl %%edx, %%es:12(%3)\n" "11: movl 16(%4), %%eax\n" "12: movl 20(%4), %%edx\n" - "13: movl %%eax, 16(%3)\n" - "14: movl %%edx, 20(%3)\n" + "13: movl %%eax, %%es:16(%3)\n" + "14: movl %%edx, %%es:20(%3)\n" "15: movl 24(%4), %%eax\n" "16: movl 28(%4), %%edx\n" - "17: movl %%eax, 24(%3)\n" - "18: movl %%edx, 28(%3)\n" + "17: movl %%eax, %%es:24(%3)\n" + "18: movl %%edx, %%es:28(%3)\n" "19: movl 32(%4), %%eax\n" "20: movl 36(%4), %%edx\n" - "21: movl %%eax, 32(%3)\n" - "22: movl %%edx, 36(%3)\n" + "21: movl %%eax, %%es:32(%3)\n" + "22: movl %%edx, %%es:36(%3)\n" "23: movl 40(%4), %%eax\n" "24: movl 44(%4), %%edx\n" - "25: movl %%eax, 40(%3)\n" - "26: movl %%edx, 44(%3)\n" + "25: movl %%eax, %%es:40(%3)\n" + "26: movl %%edx, %%es:44(%3)\n" "27: movl 48(%4), %%eax\n" "28: movl 52(%4), %%edx\n" - "29: movl %%eax, 48(%3)\n" - "30: movl %%edx, 52(%3)\n" + "29: movl %%eax, %%es:48(%3)\n" + "30: movl %%edx, %%es:52(%3)\n" "31: movl 56(%4), %%eax\n" "32: movl 60(%4), %%edx\n" - "33: movl %%eax, 56(%3)\n" - "34: movl %%edx, 60(%3)\n" + "33: movl %%eax, %%es:56(%3)\n" + "34: movl %%edx, %%es:60(%3)\n" " addl $-64, %0\n" " addl $64, %4\n" " addl $64, %3\n" @@ -275,6 +289,8 @@ __copy_user_intel(void __user *to, const "36: movl %%eax, %0\n" "37: rep; movsb\n" "100:\n" + " pushl %%ss\n" + " popl %%es\n" ".section .fixup,\"ax\"\n" "101: lea 0(%%eax,%0,4),%0\n" " jmp 100b\n" @@ -321,7 +337,117 @@ __copy_user_intel(void __user *to, const " .long 99b,101b\n" ".previous" : "=&c"(size), "=&D" (d0), "=&S" (d1) - : "1"(to), "2"(from), "0"(size) + : "1"(to), "2"(from), "0"(size), "r"(__USER_DS) + : "eax", "edx", "memory"); + return size; +} + +static unsigned long +__generic_copy_from_user_intel(void *to, const void __user *from, unsigned long size) +{ + int d0, d1; + __asm__ __volatile__( + " movw %w6, %%ds\n" + " .align 2,0x90\n" + "1: movl 32(%4), %%eax\n" + " cmpl $67, %0\n" + " jbe 3f\n" + "2: movl 64(%4), %%eax\n" + " .align 2,0x90\n" + "3: movl 0(%4), %%eax\n" + "4: movl 4(%4), %%edx\n" + "5: movl %%eax, %%es:0(%3)\n" + "6: movl %%edx, %%es:4(%3)\n" + "7: movl 8(%4), %%eax\n" + "8: movl 12(%4),%%edx\n" + "9: movl %%eax, %%es:8(%3)\n" + "10: movl %%edx, %%es:12(%3)\n" + "11: movl 16(%4), %%eax\n" + "12: movl 20(%4), %%edx\n" + "13: movl %%eax, %%es:16(%3)\n" + "14: movl %%edx, %%es:20(%3)\n" + "15: movl 24(%4), %%eax\n" + "16: movl 28(%4), %%edx\n" + "17: movl %%eax, %%es:24(%3)\n" + "18: movl %%edx, %%es:28(%3)\n" + "19: movl 32(%4), %%eax\n" + "20: movl 36(%4), %%edx\n" + "21: movl %%eax, %%es:32(%3)\n" + "22: movl %%edx, %%es:36(%3)\n" + "23: movl 40(%4), %%eax\n" + "24: movl 44(%4), %%edx\n" + "25: movl %%eax, %%es:40(%3)\n" + "26: movl %%edx, %%es:44(%3)\n" + "27: movl 48(%4), %%eax\n" + "28: movl 52(%4), %%edx\n" + "29: movl %%eax, %%es:48(%3)\n" + "30: movl %%edx, %%es:52(%3)\n" + "31: movl 56(%4), %%eax\n" + "32: movl 60(%4), %%edx\n" + "33: movl %%eax, %%es:56(%3)\n" + "34: movl %%edx, %%es:60(%3)\n" + " addl $-64, %0\n" + " addl $64, %4\n" + " addl $64, %3\n" + " cmpl $63, %0\n" + " ja 1b\n" + "35: movl %0, %%eax\n" + " shrl $2, %0\n" + " andl $3, %%eax\n" + " cld\n" + "99: rep; movsl\n" + "36: movl %%eax, %0\n" + "37: rep; movsb\n" + "100:\n" + " pushl %%ss\n" + " popl %%ds\n" + ".section .fixup,\"ax\"\n" + "101: lea 0(%%eax,%0,4),%0\n" + " jmp 100b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 1b,100b\n" + " .long 2b,100b\n" + " .long 3b,100b\n" + " .long 4b,100b\n" + " .long 5b,100b\n" + " .long 6b,100b\n" + " .long 7b,100b\n" + " .long 8b,100b\n" + " .long 9b,100b\n" + " .long 10b,100b\n" + " .long 11b,100b\n" + " .long 12b,100b\n" + " .long 13b,100b\n" + " .long 14b,100b\n" + " .long 15b,100b\n" + " .long 16b,100b\n" + " .long 17b,100b\n" + " .long 18b,100b\n" + " .long 19b,100b\n" + " .long 20b,100b\n" + " .long 21b,100b\n" + " .long 22b,100b\n" + " .long 23b,100b\n" + " .long 24b,100b\n" + " .long 25b,100b\n" + " .long 26b,100b\n" + " .long 27b,100b\n" + " .long 28b,100b\n" + " .long 29b,100b\n" + " .long 30b,100b\n" + " .long 31b,100b\n" + " .long 32b,100b\n" + " .long 33b,100b\n" + " .long 34b,100b\n" + " .long 35b,100b\n" + " .long 36b,100b\n" + " .long 37b,100b\n" + " .long 99b,101b\n" + ".previous" + : "=&c"(size), "=&D" (d0), "=&S" (d1) + : "1"(to), "2"(from), "0"(size), "r"(__USER_DS) : "eax", "edx", "memory"); return size; } @@ -331,6 +457,7 @@ __copy_user_zeroing_intel(void *to, cons { int d0, d1; __asm__ __volatile__( + " movw %w6, %%ds\n" " .align 2,0x90\n" "0: movl 32(%4), %%eax\n" " cmpl $67, %0\n" @@ -339,36 +466,36 @@ __copy_user_zeroing_intel(void *to, cons " .align 2,0x90\n" "2: movl 0(%4), %%eax\n" "21: movl 4(%4), %%edx\n" - " movl %%eax, 0(%3)\n" - " movl %%edx, 4(%3)\n" + " movl %%eax, %%es:0(%3)\n" + " movl %%edx, %%es:4(%3)\n" "3: movl 8(%4), %%eax\n" "31: movl 12(%4),%%edx\n" - " movl %%eax, 8(%3)\n" - " movl %%edx, 12(%3)\n" + " movl %%eax, %%es:8(%3)\n" + " movl %%edx, %%es:12(%3)\n" "4: movl 16(%4), %%eax\n" "41: movl 20(%4), %%edx\n" - " movl %%eax, 16(%3)\n" - " movl %%edx, 20(%3)\n" + " movl %%eax, %%es:16(%3)\n" + " movl %%edx, %%es:20(%3)\n" "10: movl 24(%4), %%eax\n" "51: movl 28(%4), %%edx\n" - " movl %%eax, 24(%3)\n" - " movl %%edx, 28(%3)\n" + " movl %%eax, %%es:24(%3)\n" + " movl %%edx, %%es:28(%3)\n" "11: movl 32(%4), %%eax\n" "61: movl 36(%4), %%edx\n" - " movl %%eax, 32(%3)\n" - " movl %%edx, 36(%3)\n" + " movl %%eax, %%es:32(%3)\n" + " movl %%edx, %%es:36(%3)\n" "12: movl 40(%4), %%eax\n" "71: movl 44(%4), %%edx\n" - " movl %%eax, 40(%3)\n" - " movl %%edx, 44(%3)\n" + " movl %%eax, %%es:40(%3)\n" + " movl %%edx, %%es:44(%3)\n" "13: movl 48(%4), %%eax\n" "81: movl 52(%4), %%edx\n" - " movl %%eax, 48(%3)\n" - " movl %%edx, 52(%3)\n" + " movl %%eax, %%es:48(%3)\n" + " movl %%edx, %%es:52(%3)\n" "14: movl 56(%4), %%eax\n" "91: movl 60(%4), %%edx\n" - " movl %%eax, 56(%3)\n" - " movl %%edx, 60(%3)\n" + " movl %%eax, %%es:56(%3)\n" + " movl %%edx, %%es:60(%3)\n" " addl $-64, %0\n" " addl $64, %4\n" " addl $64, %3\n" @@ -382,6 +509,8 @@ __copy_user_zeroing_intel(void *to, cons " movl %%eax,%0\n" "7: rep; movsb\n" "8:\n" + " pushl %%ss\n" + " popl %%ds\n" ".section .fixup,\"ax\"\n" "9: lea 0(%%eax,%0,4),%0\n" "16: pushl %0\n" @@ -416,7 +545,7 @@ __copy_user_zeroing_intel(void *to, cons " .long 7b,16b\n" ".previous" : "=&c"(size), "=&D" (d0), "=&S" (d1) - : "1"(to), "2"(from), "0"(size) + : "1"(to), "2"(from), "0"(size), "r"(__USER_DS) : "eax", "edx", "memory"); return size; } @@ -432,6 +561,7 @@ static unsigned long __copy_user_zeroing int d0, d1; __asm__ __volatile__( + " movw %w6, %%ds\n" " .align 2,0x90\n" "0: movl 32(%4), %%eax\n" " cmpl $67, %0\n" @@ -440,36 +570,36 @@ static unsigned long __copy_user_zeroing " .align 2,0x90\n" "2: movl 0(%4), %%eax\n" "21: movl 4(%4), %%edx\n" - " movnti %%eax, 0(%3)\n" - " movnti %%edx, 4(%3)\n" + " movnti %%eax, %%es:0(%3)\n" + " movnti %%edx, %%es:4(%3)\n" "3: movl 8(%4), %%eax\n" "31: movl 12(%4),%%edx\n" - " movnti %%eax, 8(%3)\n" - " movnti %%edx, 12(%3)\n" + " movnti %%eax, %%es:8(%3)\n" + " movnti %%edx, %%es:12(%3)\n" "4: movl 16(%4), %%eax\n" "41: movl 20(%4), %%edx\n" - " movnti %%eax, 16(%3)\n" - " movnti %%edx, 20(%3)\n" + " movnti %%eax, %%es:16(%3)\n" + " movnti %%edx, %%es:20(%3)\n" "10: movl 24(%4), %%eax\n" "51: movl 28(%4), %%edx\n" - " movnti %%eax, 24(%3)\n" - " movnti %%edx, 28(%3)\n" + " movnti %%eax, %%es:24(%3)\n" + " movnti %%edx, %%es:28(%3)\n" "11: movl 32(%4), %%eax\n" "61: movl 36(%4), %%edx\n" - " movnti %%eax, 32(%3)\n" - " movnti %%edx, 36(%3)\n" + " movnti %%eax, %%es:32(%3)\n" + " movnti %%edx, %%es:36(%3)\n" "12: movl 40(%4), %%eax\n" "71: movl 44(%4), %%edx\n" - " movnti %%eax, 40(%3)\n" - " movnti %%edx, 44(%3)\n" + " movnti %%eax, %%es:40(%3)\n" + " movnti %%edx, %%es:44(%3)\n" "13: movl 48(%4), %%eax\n" "81: movl 52(%4), %%edx\n" - " movnti %%eax, 48(%3)\n" - " movnti %%edx, 52(%3)\n" + " movnti %%eax, %%es:48(%3)\n" + " movnti %%edx, %%es:52(%3)\n" "14: movl 56(%4), %%eax\n" "91: movl 60(%4), %%edx\n" - " movnti %%eax, 56(%3)\n" - " movnti %%edx, 60(%3)\n" + " movnti %%eax, %%es:56(%3)\n" + " movnti %%edx, %%es:60(%3)\n" " addl $-64, %0\n" " addl $64, %4\n" " addl $64, %3\n" @@ -484,6 +614,8 @@ static unsigned long __copy_user_zeroing " movl %%eax,%0\n" "7: rep; movsb\n" "8:\n" + " pushl %%ss\n" + " popl %%ds\n" ".section .fixup,\"ax\"\n" "9: lea 0(%%eax,%0,4),%0\n" "16: pushl %0\n" @@ -518,7 +650,7 @@ static unsigned long __copy_user_zeroing " .long 7b,16b\n" ".previous" : "=&c"(size), "=&D" (d0), "=&S" (d1) - : "1"(to), "2"(from), "0"(size) + : "1"(to), "2"(from), "0"(size), "r"(__USER_DS) : "eax", "edx", "memory"); return size; } @@ -529,6 +661,7 @@ static unsigned long __copy_user_intel_n int d0, d1; __asm__ __volatile__( + " movw %w6, %%ds\n" " .align 2,0x90\n" "0: movl 32(%4), %%eax\n" " cmpl $67, %0\n" @@ -537,36 +670,36 @@ static unsigned long __copy_user_intel_n " .align 2,0x90\n" "2: movl 0(%4), %%eax\n" "21: movl 4(%4), %%edx\n" - " movnti %%eax, 0(%3)\n" - " movnti %%edx, 4(%3)\n" + " movnti %%eax, %%es:0(%3)\n" + " movnti %%edx, %%es:4(%3)\n" "3: movl 8(%4), %%eax\n" "31: movl 12(%4),%%edx\n" - " movnti %%eax, 8(%3)\n" - " movnti %%edx, 12(%3)\n" + " movnti %%eax, %%es:8(%3)\n" + " movnti %%edx, %%es:12(%3)\n" "4: movl 16(%4), %%eax\n" "41: movl 20(%4), %%edx\n" - " movnti %%eax, 16(%3)\n" - " movnti %%edx, 20(%3)\n" + " movnti %%eax, %%es:16(%3)\n" + " movnti %%edx, %%es:20(%3)\n" "10: movl 24(%4), %%eax\n" "51: movl 28(%4), %%edx\n" - " movnti %%eax, 24(%3)\n" - " movnti %%edx, 28(%3)\n" + " movnti %%eax, %%es:24(%3)\n" + " movnti %%edx, %%es:28(%3)\n" "11: movl 32(%4), %%eax\n" "61: movl 36(%4), %%edx\n" - " movnti %%eax, 32(%3)\n" - " movnti %%edx, 36(%3)\n" + " movnti %%eax, %%es:32(%3)\n" + " movnti %%edx, %%es:36(%3)\n" "12: movl 40(%4), %%eax\n" "71: movl 44(%4), %%edx\n" - " movnti %%eax, 40(%3)\n" - " movnti %%edx, 44(%3)\n" + " movnti %%eax, %%es:40(%3)\n" + " movnti %%edx, %%es:44(%3)\n" "13: movl 48(%4), %%eax\n" "81: movl 52(%4), %%edx\n" - " movnti %%eax, 48(%3)\n" - " movnti %%edx, 52(%3)\n" + " movnti %%eax, %%es:48(%3)\n" + " movnti %%edx, %%es:52(%3)\n" "14: movl 56(%4), %%eax\n" "91: movl 60(%4), %%edx\n" - " movnti %%eax, 56(%3)\n" - " movnti %%edx, 60(%3)\n" + " movnti %%eax, %%es:56(%3)\n" + " movnti %%edx, %%es:60(%3)\n" " addl $-64, %0\n" " addl $64, %4\n" " addl $64, %3\n" @@ -581,6 +714,8 @@ static unsigned long __copy_user_intel_n " movl %%eax,%0\n" "7: rep; movsb\n" "8:\n" + " pushl %%ss\n" + " popl %%ds\n" ".section .fixup,\"ax\"\n" "9: lea 0(%%eax,%0,4),%0\n" "16: jmp 8b\n" @@ -609,7 +744,7 @@ static unsigned long __copy_user_intel_n " .long 7b,16b\n" ".previous" : "=&c"(size), "=&D" (d0), "=&S" (d1) - : "1"(to), "2"(from), "0"(size) + : "1"(to), "2"(from), "0"(size), "r"(__USER_DS) : "eax", "edx", "memory"); return size; } @@ -622,90 +757,146 @@ static unsigned long __copy_user_intel_n */ unsigned long __copy_user_zeroing_intel(void *to, const void __user *from, unsigned long size); -unsigned long __copy_user_intel(void __user *to, const void *from, +unsigned long __generic_copy_to_user_intel(void __user *to, const void *from, + unsigned long size); +unsigned long __generic_copy_from_user_intel(void *to, const void __user *from, unsigned long size); unsigned long __copy_user_zeroing_intel_nocache(void *to, const void __user *from, unsigned long size); #endif /* CONFIG_X86_INTEL_USERCOPY */ /* Generic arbitrary sized copy. */ -#define __copy_user(to, from, size) \ -do { \ - int __d0, __d1, __d2; \ - __asm__ __volatile__( \ - " cmp $7,%0\n" \ - " jbe 1f\n" \ - " movl %1,%0\n" \ - " negl %0\n" \ - " andl $7,%0\n" \ - " subl %0,%3\n" \ - "4: rep; movsb\n" \ - " movl %3,%0\n" \ - " shrl $2,%0\n" \ - " andl $3,%3\n" \ - " .align 2,0x90\n" \ - "0: rep; movsl\n" \ - " movl %3,%0\n" \ - "1: rep; movsb\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "5: addl %3,%0\n" \ - " jmp 2b\n" \ - "3: lea 0(%3,%0,4),%0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 4b,5b\n" \ - " .long 0b,3b\n" \ - " .long 1b,2b\n" \ - ".previous" \ - : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \ - : "3"(size), "0"(size), "1"(to), "2"(from) \ - : "memory"); \ -} while (0) +static unsigned long +__generic_copy_to_user(void __user *to, const void *from, unsigned long size) +{ + int __d0, __d1, __d2; -#define __copy_user_zeroing(to, from, size) \ -do { \ - int __d0, __d1, __d2; \ - __asm__ __volatile__( \ - " cmp $7,%0\n" \ - " jbe 1f\n" \ - " movl %1,%0\n" \ - " negl %0\n" \ - " andl $7,%0\n" \ - " subl %0,%3\n" \ - "4: rep; movsb\n" \ - " movl %3,%0\n" \ - " shrl $2,%0\n" \ - " andl $3,%3\n" \ - " .align 2,0x90\n" \ - "0: rep; movsl\n" \ - " movl %3,%0\n" \ - "1: rep; movsb\n" \ - "2:\n" \ - ".section .fixup,\"ax\"\n" \ - "5: addl %3,%0\n" \ - " jmp 6f\n" \ - "3: lea 0(%3,%0,4),%0\n" \ - "6: pushl %0\n" \ - " pushl %%eax\n" \ - " xorl %%eax,%%eax\n" \ - " rep; stosb\n" \ - " popl %%eax\n" \ - " popl %0\n" \ - " jmp 2b\n" \ - ".previous\n" \ - ".section __ex_table,\"a\"\n" \ - " .align 4\n" \ - " .long 4b,5b\n" \ - " .long 0b,3b\n" \ - " .long 1b,6b\n" \ - ".previous" \ - : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) \ - : "3"(size), "0"(size), "1"(to), "2"(from) \ - : "memory"); \ -} while (0) + __asm__ __volatile__( + " movw %w8,%%es\n" + " cmp $7,%0\n" + " jbe 1f\n" + " movl %1,%0\n" + " negl %0\n" + " andl $7,%0\n" + " subl %0,%3\n" + "4: rep; movsb\n" + " movl %3,%0\n" + " shrl $2,%0\n" + " andl $3,%3\n" + " .align 2,0x90\n" + "0: rep; movsl\n" + " movl %3,%0\n" + "1: rep; movsb\n" + "2:\n" + " pushl %%ss\n" + " popl %%es\n" + ".section .fixup,\"ax\"\n" + "5: addl %3,%0\n" + " jmp 2b\n" + "3: lea 0(%3,%0,4),%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 4b,5b\n" + " .long 0b,3b\n" + " .long 1b,2b\n" + ".previous" + : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) + : "3"(size), "0"(size), "1"(to), "2"(from), "r"(__USER_DS) + : "memory"); + return size; +} + +static unsigned long +__generic_copy_from_user(void *to, const void __user *from, unsigned long size) +{ + int __d0, __d1, __d2; + + __asm__ __volatile__( + " movw %w8,%%ds\n" + " cmp $7,%0\n" + " jbe 1f\n" + " movl %1,%0\n" + " negl %0\n" + " andl $7,%0\n" + " subl %0,%3\n" + "4: rep; movsb\n" + " movl %3,%0\n" + " shrl $2,%0\n" + " andl $3,%3\n" + " .align 2,0x90\n" + "0: rep; movsl\n" + " movl %3,%0\n" + "1: rep; movsb\n" + "2:\n" + " pushl %%ss\n" + " popl %%ds\n" + ".section .fixup,\"ax\"\n" + "5: addl %3,%0\n" + " jmp 2b\n" + "3: lea 0(%3,%0,4),%0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 4b,5b\n" + " .long 0b,3b\n" + " .long 1b,2b\n" + ".previous" + : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) + : "3"(size), "0"(size), "1"(to), "2"(from), "r"(__USER_DS) + : "memory"); + return size; +} + +static unsigned long +__copy_user_zeroing(void *to, const void __user *from, unsigned long size) +{ + int __d0, __d1, __d2; + + __asm__ __volatile__( + " movw %w8,%%ds\n" + " cmp $7,%0\n" + " jbe 1f\n" + " movl %1,%0\n" + " negl %0\n" + " andl $7,%0\n" + " subl %0,%3\n" + "4: rep; movsb\n" + " movl %3,%0\n" + " shrl $2,%0\n" + " andl $3,%3\n" + " .align 2,0x90\n" + "0: rep; movsl\n" + " movl %3,%0\n" + "1: rep; movsb\n" + "2:\n" + " pushl %%ss\n" + " popl %%ds\n" + ".section .fixup,\"ax\"\n" + "5: addl %3,%0\n" + " jmp 6f\n" + "3: lea 0(%3,%0,4),%0\n" + "6: pushl %0\n" + " pushl %%eax\n" + " xorl %%eax,%%eax\n" + " rep; stosb\n" + " popl %%eax\n" + " popl %0\n" + " jmp 2b\n" + ".previous\n" + ".section __ex_table,\"a\"\n" + " .align 4\n" + " .long 4b,5b\n" + " .long 0b,3b\n" + " .long 1b,6b\n" + ".previous" + : "=&c"(size), "=&D" (__d0), "=&S" (__d1), "=r"(__d2) + : "3"(size), "0"(size), "1"(to), "2"(from), "r"(__USER_DS) + : "memory"); + return size; +} unsigned long __copy_to_user_ll(void __user *to, const void *from, unsigned long n) @@ -768,9 +959,9 @@ survive: } #endif if (movsl_is_ok(to, from, n)) - __copy_user(to, from, n); + n = __generic_copy_to_user(to, from, n); else - n = __copy_user_intel(to, from, n); + n = __generic_copy_to_user_intel(to, from, n); return n; } EXPORT_SYMBOL(__copy_to_user_ll); @@ -779,7 +970,7 @@ unsigned long __copy_from_user_ll(void * unsigned long n) { if (movsl_is_ok(to, from, n)) - __copy_user_zeroing(to, from, n); + n = __copy_user_zeroing(to, from, n); else n = __copy_user_zeroing_intel(to, from, n); return n; @@ -790,10 +981,9 @@ unsigned long __copy_from_user_ll_nozero unsigned long n) { if (movsl_is_ok(to, from, n)) - __copy_user(to, from, n); + n = __generic_copy_from_user(to, from, n); else - n = __copy_user_intel((void __user *)to, - (const void *)from, n); + n = __generic_copy_from_user_intel(to, from, n); return n; } EXPORT_SYMBOL(__copy_from_user_ll_nozero); @@ -802,12 +992,12 @@ unsigned long __copy_from_user_ll_nocach unsigned long n) { #ifdef CONFIG_X86_INTEL_USERCOPY - if (n > 64 && cpu_has_xmm2) + if ( n > 64 && cpu_has_xmm2) n = __copy_user_zeroing_intel_nocache(to, from, n); else - __copy_user_zeroing(to, from, n); + n = __copy_user_zeroing(to, from, n); #else - __copy_user_zeroing(to, from, n); + n = __copy_user_zeroing(to, from, n); #endif return n; } @@ -817,12 +1007,12 @@ unsigned long __copy_from_user_ll_nocach unsigned long n) { #ifdef CONFIG_X86_INTEL_USERCOPY - if (n > 64 && cpu_has_xmm2) + if ( n > 64 && cpu_has_xmm2) n = __copy_user_intel_nocache(to, from, n); else - __copy_user(to, from, n); + n = __generic_copy_from_user(to, from, n); #else - __copy_user(to, from, n); + n = __generic_copy_from_user(to, from, n); #endif return n; } @@ -871,8 +1061,35 @@ copy_from_user(void *to, const void __us { if (access_ok(VERIFY_READ, from, n)) n = __copy_from_user(to, from, n); - else + else if ((long)n > 0) memset(to, 0, n); return n; } EXPORT_SYMBOL(copy_from_user); + +#ifdef CONFIG_PAX_MEMORY_UDEREF +void __set_fs(mm_segment_t x, int cpu) +{ + unsigned long limit = x.seg; + struct desc_struct d; + + current_thread_info()->addr_limit = x; + if (likely(limit)) + limit = (limit - 1UL) >> PAGE_SHIFT; + pack_descriptor(&d, 0UL, limit, 0xF3, 0xC); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_DEFAULT_USER_DS, &d, DESCTYPE_S); +} + +void set_fs(mm_segment_t x) +{ + __set_fs(x, get_cpu()); + put_cpu_no_resched(); +} +#else +void set_fs(mm_segment_t x) +{ + current_thread_info()->addr_limit = x; +} +#endif + +EXPORT_SYMBOL(set_fs); diff -NurpP --minimal linux-2.6.27.15/arch/x86/mach-voyager/voyager_basic.c linux-2.6.27.15-g-v/arch/x86/mach-voyager/voyager_basic.c --- linux-2.6.27.15/arch/x86/mach-voyager/voyager_basic.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mach-voyager/voyager_basic.c 2009-02-10 20:32:11.000000000 +0100 @@ -123,7 +123,7 @@ int __init voyager_memory_detect(int reg __u8 cmos[4]; ClickMap_t *map; unsigned long map_addr; - unsigned long old; + pte_t old; if (region >= CLICK_ENTRIES) { printk("Voyager: Illegal ClickMap region %d\n", region); @@ -138,7 +138,7 @@ int __init voyager_memory_detect(int reg /* steal page 0 for this */ old = pg0[0]; - pg0[0] = ((map_addr & PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT); + pg0[0] = __pte((map_addr & PAGE_MASK) | _PAGE_RW | _PAGE_PRESENT); local_flush_tlb(); /* now clear everything out but page 0 */ map = (ClickMap_t *) (map_addr & (~PAGE_MASK)); diff -NurpP --minimal linux-2.6.27.15/arch/x86/mach-voyager/voyager_smp.c linux-2.6.27.15-g-v/arch/x86/mach-voyager/voyager_smp.c --- linux-2.6.27.15/arch/x86/mach-voyager/voyager_smp.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mach-voyager/voyager_smp.c 2009-02-10 20:32:11.000000000 +0100 @@ -510,6 +510,10 @@ static void __init do_boot_cpu(__u8 cpu) __u32 *hijack_vector; __u32 start_phys_address = setup_trampoline(); +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + /* There's a clever trick to this: The linux trampoline is * compiled to begin at absolute location zero, so make the * address zero but have the data segment selector compensate @@ -529,7 +533,17 @@ static void __init do_boot_cpu(__u8 cpu) init_gdt(cpu); per_cpu(current_task, cpu) = idle; - early_gdt_descr.address = (unsigned long)get_cpu_gdt_table(cpu); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + early_gdt_descr.address = get_cpu_gdt_table(cpu); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + irq_ctx_init(cpu); /* Note: Don't modify initial ss override */ @@ -1141,7 +1155,7 @@ void smp_local_timer_interrupt(void) per_cpu(prof_counter, cpu); } - update_process_times(user_mode_vm(get_irq_regs())); + update_process_times(user_mode(get_irq_regs())); } if (((1 << cpu) & voyager_extended_vic_processors) == 0) diff -NurpP --minimal linux-2.6.27.15/arch/x86/Makefile linux-2.6.27.15-g-v/arch/x86/Makefile --- linux-2.6.27.15/arch/x86/Makefile 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/Makefile 2009-02-10 20:32:11.000000000 +0100 @@ -232,3 +232,12 @@ endef CLEAN_FILES += arch/x86/boot/fdimage \ arch/x86/boot/image.iso \ arch/x86/boot/mtools.conf + +define OLD_LD + +*** ${VERSION}.${PATCHLEVEL} PaX kernels no longer build correctly with old versions of binutils. +*** Please upgrade your binutils to 2.18 or newer +endef + +archprepare: + $(if $(LDFLAGS_BUILD_ID),,$(error $(OLD_LD))) diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/discontig_32.c linux-2.6.27.15-g-v/arch/x86/mm/discontig_32.c --- linux-2.6.27.15/arch/x86/mm/discontig_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/discontig_32.c 2009-02-10 20:32:11.000000000 +0100 @@ -98,7 +98,6 @@ unsigned long node_memmap_size_bytes(int } #endif -extern unsigned long find_max_low_pfn(void); extern unsigned long highend_pfn, highstart_pfn; #define LARGE_PAGE_BYTES (PTRS_PER_PTE * PAGE_SIZE) diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/extable.c linux-2.6.27.15-g-v/arch/x86/mm/extable.c --- linux-2.6.27.15/arch/x86/mm/extable.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/extable.c 2009-02-10 20:32:11.000000000 +0100 @@ -1,14 +1,62 @@ #include #include +#include #include +/* + * The exception table needs to be sorted so that the binary + * search that we use to find entries in it works properly. + * This is used both for the kernel exception table and for + * the exception tables of modules that get loaded. + */ +static int cmp_ex(const void *a, const void *b) +{ + const struct exception_table_entry *x = a, *y = b; + + /* avoid overflow */ + if (x->insn > y->insn) + return 1; + if (x->insn < y->insn) + return -1; + return 0; +} + +static void swap_ex(void *a, void *b, int size) +{ + struct exception_table_entry t, *x = a, *y = b; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + + t = *x; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + *x = *y; + *y = t; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + +} + +void sort_extable(struct exception_table_entry *start, + struct exception_table_entry *finish) +{ + sort(start, finish - start, sizeof(struct exception_table_entry), + cmp_ex, swap_ex); +} int fixup_exception(struct pt_regs *regs) { const struct exception_table_entry *fixup; #ifdef CONFIG_PNPBIOS - if (unlikely(SEGMENT_IS_PNP_CODE(regs->cs))) { + if (unlikely(!v8086_mode(regs) && SEGMENT_IS_PNP_CODE(regs->cs))) { extern u32 pnp_bios_fault_eip, pnp_bios_fault_esp; extern u32 pnp_bios_is_utter_crap; pnp_bios_is_utter_crap = 1; diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/fault.c linux-2.6.27.15-g-v/arch/x86/mm/fault.c --- linux-2.6.27.15/arch/x86/mm/fault.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/fault.c 2009-02-10 20:32:11.000000000 +0100 @@ -26,6 +26,8 @@ #include #include #include +#include +#include #include #include @@ -66,7 +68,7 @@ static inline int notify_page_fault(stru int ret = 0; /* kprobe_running() needs smp_processor_id() */ - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { preempt_disable(); if (kprobe_running() && kprobe_fault_handler(regs, 14)) ret = 1; @@ -264,6 +266,30 @@ bad: #endif } +#ifdef CONFIG_PAX_EMUTRAMP +static int pax_handle_fetch_fault(struct pt_regs *regs); +#endif + +#ifdef CONFIG_PAX_PAGEEXEC +static inline pmd_t * pax_get_pmd(struct mm_struct *mm, unsigned long address) +{ + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + + pgd = pgd_offset(mm, address); + if (!pgd_present(*pgd)) + return NULL; + pud = pud_offset(pgd, address); + if (!pud_present(*pud)) + return NULL; + pmd = pmd_offset(pud, address); + if (!pmd_present(*pmd)) + return NULL; + return pmd; +} +#endif + #ifdef CONFIG_X86_32 static inline pmd_t *vmalloc_sync_one(pgd_t *pgd, unsigned long address) { @@ -350,7 +376,7 @@ static int is_errata93(struct pt_regs *r static int is_errata100(struct pt_regs *regs, unsigned long address) { #ifdef CONFIG_X86_64 - if ((regs->cs == __USER32_CS || (regs->cs & (1<<2))) && + if ((regs->cs == __USER32_CS || (regs->cs & SEGMENT_LDT)) && (address >> 32)) return 1; #endif @@ -387,14 +413,31 @@ static void show_fault_oops(struct pt_re #endif #ifdef CONFIG_X86_PAE - if (error_code & PF_INSTR) { + if (nx_enabled && (error_code & PF_INSTR)) { unsigned int level; pte_t *pte = lookup_address(address, &level); if (pte && pte_present(*pte) && !pte_exec(*pte)) printk(KERN_CRIT "kernel tried to execute " "NX-protected page - exploit attempt? " - "(uid: %d)\n", current->uid); + "(uid: %d, task: %s, pid: %d)\n", + current->uid, current->comm, task_pid_nr(current)); + } +#endif + +#ifdef CONFIG_PAX_KERNEXEC +#ifdef CONFIG_MODULES + if (init_mm.start_code <= address && address < (unsigned long)MODULES_END) +#else + if (init_mm.start_code <= address && address < init_mm.end_code) +#endif + { + if (current->signal->curr_ip) + printk(KERN_ERR "PAX: From %u.%u.%u.%u: %s:%d, uid/euid: %u/%u, attempted to modify kernel code\n", + NIPQUAD(current->signal->curr_ip), current->comm, task_pid_nr(current), current->uid, current->euid); + else + printk(KERN_ERR "PAX: %s:%d, uid/euid: %u/%u, attempted to modify kernel code\n", + current->comm, task_pid_nr(current), current->uid, current->euid); } #endif @@ -586,13 +629,22 @@ void __kprobes do_page_fault(struct pt_r struct task_struct *tsk; struct mm_struct *mm; struct vm_area_struct *vma; - unsigned long address; int write, si_code; int fault; #ifdef CONFIG_X86_64 unsigned long flags; #endif +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_PAGEEXEC) + pte_t *pte; + pmd_t *pmd; + spinlock_t *ptl; + unsigned char pte_mask; +#endif + + /* get the address */ + const unsigned long address = read_cr2(); + /* * We can fault from pretty much anywhere, with unknown IRQ state. */ @@ -602,9 +654,6 @@ void __kprobes do_page_fault(struct pt_r mm = tsk->mm; prefetchw(&mm->mmap_sem); - /* get the address */ - address = read_cr2(); - si_code = SEGV_MAPERR; if (notify_page_fault(regs)) @@ -657,7 +706,7 @@ void __kprobes do_page_fault(struct pt_r * atomic region then we must not take the fault. */ if (in_atomic() || !mm) - goto bad_area_nosemaphore; + goto bad_area_nopax; #else /* CONFIG_X86_64 */ if (likely(regs->flags & X86_EFLAGS_IF)) local_irq_enable(); @@ -670,13 +719,13 @@ void __kprobes do_page_fault(struct pt_r * atomic region then we must not take the fault. */ if (unlikely(in_atomic() || !mm)) - goto bad_area_nosemaphore; + goto bad_area_nopax; /* * User-mode registers count as a user access even for any * potential system fault or CPU buglet. */ - if (user_mode_vm(regs)) + if (user_mode(regs)) error_code |= PF_USER; again: #endif @@ -698,10 +747,104 @@ again: if (!down_read_trylock(&mm->mmap_sem)) { if ((error_code & PF_USER) == 0 && !search_exception_tables(regs->ip)) - goto bad_area_nosemaphore; + goto bad_area_nopax; down_read(&mm->mmap_sem); } +#if defined(CONFIG_X86_32) && defined(CONFIG_PAX_PAGEEXEC) + if (nx_enabled || (error_code & (PF_PROT|PF_USER)) != (PF_PROT|PF_USER) || v8086_mode(regs) || + !(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 & PF_WRITE) && (regs->ip == address))) { + /* instruction fetch attempt from a protected page in user mode */ + up_read(&mm->mmap_sem); + +#ifdef CONFIG_PAX_EMUTRAMP + switch (pax_handle_fetch_fault(regs)) { + case 2: + return; + } +#endif + + pax_report_fault(regs, (void *)regs->ip, (void *)regs->sp); + do_group_exit(SIGKILL); + } + + pmd = pax_get_pmd(mm, address); + if (unlikely(!pmd)) + goto not_pax_fault; + + pte = pte_offset_map_lock(mm, pmd, address, &ptl); + if (unlikely(!(pte_val(*pte) & _PAGE_PRESENT) || pte_user(*pte))) { + pte_unmap_unlock(pte, ptl); + goto not_pax_fault; + } + + if (unlikely((error_code & PF_WRITE) && !pte_write(*pte))) { + /* write attempt to a protected page in user mode */ + pte_unmap_unlock(pte, ptl); + goto not_pax_fault; + } + +#ifdef CONFIG_SMP + if (likely(address > get_limit(regs->cs) && cpu_isset(smp_processor_id(), mm->context.cpu_user_cs_mask))) +#else + if (likely(address > get_limit(regs->cs))) +#endif + { + set_pte(pte, pte_mkread(*pte)); + __flush_tlb_one(address); + pte_unmap_unlock(pte, ptl); + up_read(&mm->mmap_sem); + return; + } + + pte_mask = _PAGE_ACCESSED | _PAGE_USER | ((error_code & PF_WRITE) << (_PAGE_BIT_DIRTY-1)); + + /* + * PaX: fill DTLB with user rights and retry + */ + __asm__ __volatile__ ( +#ifdef CONFIG_PAX_MEMORY_UDEREF + "movw %w4,%%es\n" +#endif + "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,%%es:(%0)\n" + "xorb %3,(%1)\n" +#ifdef CONFIG_PAX_MEMORY_UDEREF + "pushl %%ss\n" + "popl %%es\n" +#endif + : + : "r" (address), "r" (pte), "q" (pte_mask), "i" (_PAGE_USER), "r" (__USER_DS) + : "memory", "cc"); + pte_unmap_unlock(pte, ptl); + up_read(&mm->mmap_sem); + return; + +not_pax_fault: +#endif + vma = find_vma(mm, address); if (!vma) goto bad_area; @@ -709,16 +852,20 @@ again: goto good_area; if (!(vma->vm_flags & VM_GROWSDOWN)) goto bad_area; - if (error_code & PF_USER) { - /* - * Accessing the stack below %sp is always a bug. - * The large cushion allows instructions like enter - * and pusha to work. ("enter $65535,$31" pushes - * 32 pointers and then decrements %sp by 65535.) - */ - if (address + 65536 + 32 * sizeof(unsigned long) < regs->sp) - goto bad_area; - } + /* + * Accessing the stack below %sp is always a bug. + * The large cushion allows instructions like enter + * and pusha to work. ("enter $65535,$31" pushes + * 32 pointers and then decrements %sp by 65535.) + */ + if (address + 65536 + 32 * sizeof(unsigned long) < regs->sp) + goto bad_area; + +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && vma->vm_end - SEGMEXEC_TASK_SIZE - 1 < address - SEGMEXEC_TASK_SIZE - 1) + goto bad_area; +#endif + if (expand_stack(vma, address)) goto bad_area; /* @@ -728,6 +875,8 @@ again: good_area: si_code = SEGV_ACCERR; write = 0; + if (nx_enabled && (error_code & PF_INSTR) && !(vma->vm_flags & VM_EXEC)) + goto bad_area; switch (error_code & (PF_PROT|PF_WRITE)) { default: /* 3: write, present */ /* fall through */ @@ -785,6 +934,54 @@ bad_area: up_read(&mm->mmap_sem); bad_area_nosemaphore: + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (mm && (error_code & PF_USER)) { + unsigned long ip = regs->ip; + + if (v8086_mode(regs)) + ip = ((regs->cs & 0xffff) << 4) + (regs->ip & 0xffff); + + /* + * It's possible to have interrupts off here. + */ + local_irq_enable(); + +#ifdef CONFIG_PAX_PAGEEXEC + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && + ((nx_enabled && (error_code & PF_INSTR)) || (!(error_code & (PF_PROT | PF_WRITE)) && regs->ip == address))) { + +#ifdef CONFIG_PAX_EMUTRAMP + switch (pax_handle_fetch_fault(regs)) { + case 2: + return; + } +#endif + + pax_report_fault(regs, (void *)regs->ip, (void *)regs->sp); + do_group_exit(SIGKILL); + } +#endif + +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && !(error_code & (PF_PROT | PF_WRITE)) && (regs->ip + SEGMEXEC_TASK_SIZE == address)) { + +#ifdef CONFIG_PAX_EMUTRAMP + switch (pax_handle_fetch_fault(regs)) { + case 2: + return; + } +#endif + + pax_report_fault(regs, (void *)regs->ip, (void *)regs->sp); + do_group_exit(SIGKILL); + } +#endif + + } +#endif + +bad_area_nopax: /* User mode accesses just cause a SIGSEGV */ if (error_code & PF_USER) { /* @@ -863,7 +1060,7 @@ no_context: #ifdef CONFIG_X86_32 die("Oops", regs, error_code); bust_spinlocks(0); - do_exit(SIGKILL); + do_group_exit(SIGKILL); #else if (__die("Oops", regs, error_code)) regs = NULL; @@ -877,17 +1074,17 @@ no_context: * us unable to handle the page fault gracefully. */ out_of_memory: - up_read(&mm->mmap_sem); if (is_global_init(tsk)) { yield(); #ifdef CONFIG_X86_32 - down_read(&mm->mmap_sem); goto survive; #else + up_read(&mm->mmap_sem); goto again; #endif } + up_read(&mm->mmap_sem); printk("VM: killing process %s\n", tsk->comm); if (error_code & PF_USER) do_group_exit(SIGKILL); @@ -959,3 +1156,174 @@ void vmalloc_sync_all(void) } #endif } + +#ifdef CONFIG_PAX_EMUTRAMP +static int pax_handle_fetch_fault_32(struct pt_regs *regs) +{ + int err; + + do { /* PaX: gcc trampoline emulation #1 */ + unsigned char mov1, mov2; + unsigned short jmp; + unsigned int addr1, addr2; + +#ifdef CONFIG_X86_64 + if ((regs->ip + 11) >> 32) + break; +#endif + + err = get_user(mov1, (unsigned char __user *)regs->ip); + err |= get_user(addr1, (unsigned int __user *)(regs->ip + 1)); + err |= get_user(mov2, (unsigned char __user *)(regs->ip + 5)); + err |= get_user(addr2, (unsigned int __user *)(regs->ip + 6)); + err |= get_user(jmp, (unsigned short __user *)(regs->ip + 10)); + + if (err) + break; + + if (mov1 == 0xB9 && mov2 == 0xB8 && jmp == 0xE0FF) { + regs->cx = addr1; + regs->ax = addr2; + regs->ip = addr2; + return 2; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #2 */ + unsigned char mov, jmp; + unsigned int addr1, addr2; + +#ifdef CONFIG_X86_64 + if ((regs->ip + 9) >> 32) + break; +#endif + + err = get_user(mov, (unsigned char __user *)regs->ip); + err |= get_user(addr1, (unsigned int __user *)(regs->ip + 1)); + err |= get_user(jmp, (unsigned char __user *)(regs->ip + 5)); + err |= get_user(addr2, (unsigned int __user *)(regs->ip + 6)); + + if (err) + break; + + if (mov == 0xB9 && jmp == 0xE9) { + regs->cx = addr1; + regs->ip = (unsigned int)(regs->ip + addr2 + 10); + return 2; + } + } while (0); + + return 1; /* PaX in action */ +} + +#ifdef CONFIG_X86_64 +static int pax_handle_fetch_fault_64(struct pt_regs *regs) +{ + int err; + + do { /* PaX: gcc trampoline emulation #1 */ + unsigned short mov1, mov2, jmp1; + unsigned char jmp2; + unsigned int addr1; + unsigned long addr2; + + err = get_user(mov1, (unsigned short __user *)regs->ip); + err |= get_user(addr1, (unsigned int __user *)(regs->ip + 2)); + err |= get_user(mov2, (unsigned short __user *)(regs->ip + 6)); + err |= get_user(addr2, (unsigned long __user *)(regs->ip + 8)); + err |= get_user(jmp1, (unsigned short __user *)(regs->ip + 16)); + err |= get_user(jmp2, (unsigned char __user *)(regs->ip + 18)); + + if (err) + break; + + if (mov1 == 0xBB41 && mov2 == 0xBA49 && jmp1 == 0xFF49 && jmp2 == 0xE3) { + regs->r11 = addr1; + regs->r10 = addr2; + regs->ip = addr1; + return 2; + } + } while (0); + + do { /* PaX: gcc trampoline emulation #2 */ + unsigned short mov1, mov2, jmp1; + unsigned char jmp2; + unsigned long addr1, addr2; + + err = get_user(mov1, (unsigned short __user *)regs->ip); + err |= get_user(addr1, (unsigned long __user *)(regs->ip + 2)); + err |= get_user(mov2, (unsigned short __user *)(regs->ip + 10)); + err |= get_user(addr2, (unsigned long __user *)(regs->ip + 12)); + err |= get_user(jmp1, (unsigned short __user *)(regs->ip + 20)); + err |= get_user(jmp2, (unsigned char __user *)(regs->ip + 22)); + + if (err) + break; + + if (mov1 == 0xBB49 && mov2 == 0xBA49 && jmp1 == 0xFF49 && jmp2 == 0xE3) { + regs->r11 = addr1; + regs->r10 = addr2; + regs->ip = addr1; + return 2; + } + } while (0); + + return 1; /* PaX in action */ +} +#endif + +/* + * PaX: decide what to do with offenders (regs->ip = 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) +{ + if (v8086_mode(regs)) + return 1; + + if (!(current->mm->pax_flags & MF_PAX_EMUTRAMP)) + return 1; + +#ifdef CONFIG_X86_32 + return pax_handle_fetch_fault_32(regs); +#else + if (regs->cs == __USER32_CS || (regs->cs & SEGMENT_LDT)) + return pax_handle_fetch_fault_32(regs); + else + return pax_handle_fetch_fault_64(regs); +#endif +} +#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(KERN_CONT "?? "); + else + printk(KERN_CONT "%02x ", c); + } + printk("\n"); + + printk(KERN_ERR "PAX: bytes at SP-%lu: ", (unsigned long)sizeof(long)); + for (i = -1; i < 80 / sizeof(long); i++) { + unsigned long c; + if (get_user(c, (unsigned long __user *)sp+i)) +#ifdef CONFIG_X86_32 + printk(KERN_CONT "???????? "); +#else + printk(KERN_CONT "???????????????? "); +#endif + else + printk(KERN_CONT "%0*lx ", 2 * (int)sizeof(long), c); + } + printk("\n"); +} +#endif diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/highmem_32.c linux-2.6.27.15-g-v/arch/x86/mm/highmem_32.c --- linux-2.6.27.15/arch/x86/mm/highmem_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/highmem_32.c 2009-02-10 20:32:11.000000000 +0100 @@ -74,6 +74,10 @@ void *kmap_atomic_prot(struct page *page enum fixed_addresses idx; unsigned long vaddr; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + /* even !CONFIG_PREEMPT needs this, for in_atomic in do_page_fault */ pagefault_disable(); @@ -85,7 +89,17 @@ void *kmap_atomic_prot(struct page *page idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); BUG_ON(!pte_none(*(kmap_pte-idx))); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + set_pte(kmap_pte-idx, mk_pte(page, prot)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + arch_flush_lazy_mmu_mode(); return (void *)vaddr; @@ -101,15 +115,29 @@ void kunmap_atomic(void *kvaddr, enum km unsigned long vaddr = (unsigned long) kvaddr & PAGE_MASK; enum fixed_addresses idx = type + KM_TYPE_NR*smp_processor_id(); +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + /* * Force other mappings to Oops if they'll try to access this pte * without first remap it. Keeping stale mappings around is a bad idea * also, in case the page changes cacheability attributes or becomes * a protected page in a hypervisor. */ - if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx)) + if (vaddr == __fix_to_virt(FIX_KMAP_BEGIN+idx)) { + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + kpte_clear_flush(kmap_pte-idx, vaddr); - else { + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + } else { #ifdef CONFIG_DEBUG_HIGHMEM BUG_ON(vaddr < PAGE_OFFSET); BUG_ON(vaddr >= (unsigned long)high_memory); @@ -128,11 +156,25 @@ void *kmap_atomic_pfn(unsigned long pfn, enum fixed_addresses idx; unsigned long vaddr; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + pagefault_disable(); idx = type + KM_TYPE_NR*smp_processor_id(); vaddr = __fix_to_virt(FIX_KMAP_BEGIN + idx); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + set_pte(kmap_pte-idx, pfn_pte(pfn, kmap_prot)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + arch_flush_lazy_mmu_mode(); return (void*) vaddr; diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/hugetlbpage.c linux-2.6.27.15-g-v/arch/x86/mm/hugetlbpage.c --- linux-2.6.27.15/arch/x86/mm/hugetlbpage.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/hugetlbpage.c 2009-02-10 20:32:11.000000000 +0100 @@ -263,13 +263,18 @@ static unsigned long hugetlb_get_unmappe struct hstate *h = hstate_file(file); struct mm_struct *mm = current->mm; struct vm_area_struct *vma; - unsigned long start_addr; + unsigned long start_addr, pax_task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif if (len > mm->cached_hole_size) { - start_addr = mm->free_area_cache; + start_addr = mm->free_area_cache; } else { - start_addr = TASK_UNMAPPED_BASE; - mm->cached_hole_size = 0; + start_addr = mm->mmap_base; + mm->cached_hole_size = 0; } full_search: @@ -277,13 +282,13 @@ 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 (pax_task_size - len < addr) { /* * Start a new search - just in case we missed * some holes. */ - if (start_addr != TASK_UNMAPPED_BASE) { - start_addr = TASK_UNMAPPED_BASE; + if (start_addr != mm->mmap_base) { + start_addr = mm->mmap_base; mm->cached_hole_size = 0; goto full_search; } @@ -306,9 +311,8 @@ static unsigned long hugetlb_get_unmappe struct hstate *h = hstate_file(file); 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) @@ -318,7 +322,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; @@ -360,22 +364,26 @@ 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() * allocations. */ - mm->free_area_cache = TASK_UNMAPPED_BASE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + mm->mmap_base = SEGMEXEC_TASK_UNMAPPED_BASE; + else +#endif + + 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 = hugetlb_get_unmapped_area_bottomup(file, addr0, len, pgoff, flags); @@ -383,6 +391,7 @@ fail: /* * Restore the topdown base: */ + mm->mmap_base = base; mm->free_area_cache = base; mm->cached_hole_size = ~0UL; @@ -396,10 +405,17 @@ hugetlb_get_unmapped_area(struct file *f struct hstate *h = hstate_file(file); struct mm_struct *mm = current->mm; struct vm_area_struct *vma; + unsigned long pax_task_size = TASK_SIZE; if (len & ~huge_page_mask(h)) return -EINVAL; - if (len > TASK_SIZE) + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + if (len > pax_task_size) return -ENOMEM; if (flags & MAP_FIXED) { @@ -411,7 +427,7 @@ hugetlb_get_unmapped_area(struct file *f if (addr) { addr = ALIGN(addr, huge_page_size(h)); vma = find_vma(mm, addr); - if (TASK_SIZE - len >= addr && + if (pax_task_size - len >= addr && (!vma || addr + len <= vma->vm_start)) return addr; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/init_32.c linux-2.6.27.15-g-v/arch/x86/mm/init_32.c --- linux-2.6.27.15/arch/x86/mm/init_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/init_32.c 2009-02-10 20:32:11.000000000 +0100 @@ -47,6 +47,7 @@ #include #include #include +#include unsigned int __VMALLOC_RESERVE = 128 << 20; @@ -80,35 +81,6 @@ static __init void *alloc_low_page(unsig } /* - * 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 - unsigned long phys; - if (!(pgd_val(*pgd) & _PAGE_PRESENT)) { - if (after_init_bootmem) - pmd_table = (pmd_t *)alloc_bootmem_low_pages(PAGE_SIZE); - else - pmd_table = (pmd_t *)alloc_low_page(&phys); - paravirt_alloc_pmd(&init_mm, __pa(pmd_table) >> PAGE_SHIFT); - set_pgd(pgd, __pgd(__pa(pmd_table) | _PAGE_PRESENT)); - pud = pud_offset(pgd, 0); - BUG_ON(pmd_table != pmd_offset(pud, 0)); - } -#endif - pud = pud_offset(pgd, 0); - pmd_table = pmd_offset(pud, 0); - - return pmd_table; -} - -/* * Create a page table and place a pointer to it in a middle page * directory entry: */ @@ -130,7 +102,11 @@ static pte_t * __init one_page_table_ini } paravirt_alloc_pte(&init_mm, __pa(page_table) >> PAGE_SHIFT); +#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 BUG_ON(page_table != pte_offset_kernel(pmd, 0)); } @@ -152,6 +128,7 @@ page_table_range_init(unsigned long star int pgd_idx, pmd_idx; unsigned long vaddr; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; vaddr = start; @@ -160,8 +137,13 @@ page_table_range_init(unsigned long star pgd = pgd_base + pgd_idx; for ( ; (pgd_idx < PTRS_PER_PGD) && (vaddr != end); pgd++, pgd_idx++) { - pmd = one_md_table_init(pgd); - pmd = pmd + pmd_index(vaddr); + pud = pud_offset(pgd, vaddr); + pmd = pmd_offset(pud, vaddr); + +#ifdef CONFIG_X86_PAE + paravirt_alloc_pmd(&init_mm, __pa(pmd) >> PAGE_SHIFT); +#endif + for (; (pmd_idx < PTRS_PER_PMD) && (vaddr != end); pmd++, pmd_idx++) { one_page_table_init(pmd); @@ -172,11 +154,23 @@ page_table_range_init(unsigned long star } } -static inline int is_kernel_text(unsigned long addr) +static inline int is_kernel_text(unsigned long start, unsigned long end) { - if (addr >= PAGE_OFFSET && addr <= (unsigned long)__init_end) - return 1; - return 0; + unsigned long etext; + +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + etext = ktva_ktla((unsigned long)&MODULES_END); +#else + etext = (unsigned long)&_etext; +#endif + + if ((start > ktla_ktva(etext) || + end <= ktla_ktva((unsigned long)_stext)) && + (start > ktla_ktva((unsigned long)_einittext) || + end <= ktla_ktva((unsigned long)_sinittext)) && + (start > (unsigned long)__va(0xfffff) || end <= (unsigned long)__va(0xc0000))) + return 0; + return 1; } /* @@ -189,9 +183,10 @@ static void __init kernel_physical_mappi unsigned long end_pfn, int use_pse) { - int pgd_idx, pmd_idx, pte_ofs; + unsigned int pgd_idx, pmd_idx, pte_ofs; unsigned long pfn; pgd_t *pgd; + pud_t *pud; pmd_t *pmd; pte_t *pte; unsigned pages_2m = 0, pages_4k = 0; @@ -202,8 +197,13 @@ static void __init kernel_physical_mappi pfn = start_pfn; pgd_idx = pgd_index((pfn<> PAGE_SHIFT); +#endif if (pfn >= end_pfn) continue; @@ -215,21 +215,16 @@ static void __init kernel_physical_mappi #endif for (; pmd_idx < PTRS_PER_PMD && pfn < end_pfn; pmd++, pmd_idx++) { - unsigned int addr = 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 (use_pse) { - unsigned int addr2; pgprot_t prot = PAGE_KERNEL_LARGE; - addr2 = (pfn + PTRS_PER_PTE-1) * PAGE_SIZE + - PAGE_OFFSET + PAGE_SIZE-1; - - if (is_kernel_text(addr) || - is_kernel_text(addr2)) + if (is_kernel_text(address, address + PMD_SIZE)) prot = PAGE_KERNEL_LARGE_EXEC; pages_2m++; @@ -243,10 +238,10 @@ static void __init kernel_physical_mappi pte_ofs = pte_index((pfn<> PAGE_SHIFT) <= pagenr && pagenr < (ISA_END_ADDRESS >> PAGE_SHIFT)) return 1; if (!page_is_ram(pagenr)) return 1; @@ -404,7 +401,7 @@ void __init native_pagetable_setup_start pud = pud_offset(pgd, va); pmd = pmd_offset(pud, va); - if (!pmd_present(*pmd)) + if (!pmd_present(*pmd) || pmd_huge(*pmd)) break; pte = pte_offset_kernel(pmd, va); @@ -456,9 +453,7 @@ static void __init early_ioremap_page_ta static void __init pagetable_init(void) { - pgd_t *pgd_base = swapper_pg_dir; - - permanent_kmaps_init(pgd_base); + permanent_kmaps_init(swapper_pg_dir); } #ifdef CONFIG_ACPI_SLEEP @@ -466,12 +461,12 @@ static void __init pagetable_init(void) * ACPI suspend needs this for resume, because things like the intel-agp * driver might have split up a kernel 4MB mapping. */ -char swsusp_pg_dir[PAGE_SIZE] +pgd_t swsusp_pg_dir[PTRS_PER_PGD] __attribute__ ((aligned(PAGE_SIZE))); static inline void save_pg_dir(void) { - memcpy(swsusp_pg_dir, swapper_pg_dir, PAGE_SIZE); + clone_pgd_range(swsusp_pg_dir, swapper_pg_dir, PTRS_PER_PGD); } #else /* !CONFIG_ACPI_SLEEP */ static inline void save_pg_dir(void) @@ -501,13 +496,11 @@ void zap_low_mappings(void) int nx_enabled; -pteval_t __supported_pte_mask __read_mostly = ~(_PAGE_NX | _PAGE_GLOBAL); +pteval_t __supported_pte_mask __read_only = ~(_PAGE_NX | _PAGE_GLOBAL); EXPORT_SYMBOL_GPL(__supported_pte_mask); #ifdef CONFIG_X86_PAE -static int disable_nx __initdata; - /* * noexec = on|off * @@ -516,40 +509,33 @@ static int disable_nx __initdata; * on Enable * off Disable */ +#if !defined(CONFIG_PAX_PAGEEXEC) static int __init noexec_setup(char *str) { if (!str || !strcmp(str, "on")) { - if (cpu_has_nx) { - __supported_pte_mask |= _PAGE_NX; - disable_nx = 0; - } + if (cpu_has_nx) + nx_enabled = 1; } else { - if (!strcmp(str, "off")) { - disable_nx = 1; - __supported_pte_mask &= ~_PAGE_NX; - } else { + if (!strcmp(str, "off")) + nx_enabled = 0; + else return -EINVAL; - } } return 0; } early_param("noexec", noexec_setup); +#endif static void __init set_nx(void) { - unsigned int v[4], l, h; - - if (cpu_has_pae && (cpuid_eax(0x80000000) > 0x80000001)) { - cpuid(0x80000001, &v[0], &v[1], &v[2], &v[3]); + if (!nx_enabled && cpu_has_nx) { + unsigned l, h; - 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); } } #endif @@ -930,7 +916,7 @@ void __init mem_init(void) set_highmem_pages_init(); 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); @@ -976,10 +962,10 @@ void __init mem_init(void) ((unsigned long)&__init_end - (unsigned long)&__init_begin) >> 10, - (unsigned long)&_etext, (unsigned long)&_edata, - ((unsigned long)&_edata - (unsigned long)&_etext) >> 10, + (unsigned long)&_data, (unsigned long)&_edata, + ((unsigned long)&_edata - (unsigned long)&_data) >> 10, - (unsigned long)&_text, (unsigned long)&_etext, + ktla_ktva((unsigned long)&_text), ktla_ktva((unsigned long)&_etext), ((unsigned long)&_etext - (unsigned long)&_text) >> 10); #ifdef CONFIG_HIGHMEM @@ -1109,6 +1095,46 @@ void free_init_pages(char *what, unsigne void free_initmem(void) { + +#ifdef CONFIG_PAX_KERNEXEC + /* PaX: limit KERNEL_CS to actual size */ + unsigned long addr, limit; + struct desc_struct d; + int cpu; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + +#ifdef CONFIG_MODULES + limit = ktva_ktla((unsigned long)&MODULES_END); +#else + limit = (unsigned long)&_etext; +#endif + limit = (limit - 1UL) >> PAGE_SHIFT; + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + pack_descriptor(&d, get_desc_base(&get_cpu_gdt_table(cpu)[GDT_ENTRY_KERNEL_CS]), limit, 0x9B, 0xC); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_KERNEL_CS, &d, DESCTYPE_S); + } + + /* PaX: make KERNEL_CS read-only */ + for (addr = ktla_ktva((unsigned long)&_text); 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)); + } +#ifdef CONFIG_X86_PAE + for (addr = (unsigned long)&__init_begin; addr < (unsigned long)&__init_end; 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_NX & __supported_pte_mask))); + } +#endif + flush_tlb_all(); +#endif + free_init_pages("unused kernel memory", (unsigned long)(&__init_begin), (unsigned long)(&__init_end)); diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/init_64.c linux-2.6.27.15-g-v/arch/x86/mm/init_64.c --- linux-2.6.27.15/arch/x86/mm/init_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/init_64.c 2009-02-10 20:32:11.000000000 +0100 @@ -118,6 +118,10 @@ set_pte_vaddr_pud(pud_t *pud_page, unsig pmd_t *pmd; pte_t *pte; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + pud = pud_page + pud_index(vaddr); if (pud_none(*pud)) { pmd = (pmd_t *) spp_getpage(); @@ -142,8 +146,17 @@ set_pte_vaddr_pud(pud_t *pud_page, unsig if (!pte_none(*pte) && pte_val(new_pte) && pte_val(*pte) != (pte_val(new_pte) & __supported_pte_mask)) pte_ERROR(*pte); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + set_pte(pte, new_pte); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* * It's enough to flush this one mapping. * (PGE mappings get flushed as well) @@ -184,14 +197,12 @@ static void __init __init_extra_mapping( pgd = pgd_offset_k((unsigned long)__va(phys)); if (pgd_none(*pgd)) { pud = (pud_t *) spp_getpage(); - set_pgd(pgd, __pgd(__pa(pud) | _KERNPG_TABLE | - _PAGE_USER)); + set_pgd(pgd, __pgd(__pa(pud) | _PAGE_TABLE)); } pud = pud_offset(pgd, (unsigned long)__va(phys)); if (pud_none(*pud)) { pmd = (pmd_t *) spp_getpage(); - set_pud(pud, __pud(__pa(pmd) | _KERNPG_TABLE | - _PAGE_USER)); + set_pud(pud, __pud(__pa(pmd) | _PAGE_TABLE)); } pmd = pmd_offset(pud, phys); BUG_ON(!pmd_none(*pmd)); @@ -768,7 +779,9 @@ EXPORT_SYMBOL_GPL(memory_add_physaddr_to */ int devmem_is_allowed(unsigned long pagenr) { - if (pagenr <= 256) + if (!pagenr) + return 1; + if ((ISA_START_ADDRESS >> PAGE_SHIFT) <= pagenr && pagenr < (ISA_END_ADDRESS >> PAGE_SHIFT)) return 1; if (!page_is_ram(pagenr)) return 1; @@ -856,6 +869,39 @@ void free_init_pages(char *what, unsigne void free_initmem(void) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long addr, end; + pgd_t *pgd; + pud_t *pud; + pmd_t *pmd; + + /* PaX: make kernel code/rodata read-only, rest non-executable */ + for (addr = __START_KERNEL_map; addr < __START_KERNEL_map + KERNEL_IMAGE_SIZE; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + if ((unsigned long)_text <= addr && addr < (unsigned long)_data) + set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW)); + else + set_pmd(pmd, __pmd(pmd_val(*pmd) | (_PAGE_NX & __supported_pte_mask))); + } + + addr = (unsigned long)__va(__pa(__START_KERNEL_map)); + end = addr + KERNEL_IMAGE_SIZE; + for (; addr < end; addr += PMD_SIZE) { + pgd = pgd_offset_k(addr); + pud = pud_offset(pgd, addr); + pmd = pmd_offset(pud, addr); + if ((unsigned long)__va(__pa(_text)) <= addr && addr < (unsigned long)__va(__pa(_data))) + set_pmd(pmd, __pmd(pmd_val(*pmd) & ~_PAGE_RW)); + else + set_pmd(pmd, __pmd(pmd_val(*pmd) | (_PAGE_NX & __supported_pte_mask))); + } + + flush_tlb_all(); +#endif + free_init_pages("unused kernel memory", (unsigned long)(&__init_begin), (unsigned long)(&__init_end)); @@ -1028,7 +1074,7 @@ int in_gate_area_no_task(unsigned long a const char *arch_vma_name(struct vm_area_struct *vma) { - if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) + if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso) return "[vdso]"; if (vma == &gate_vma) return "[vsyscall]"; diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/ioremap.c linux-2.6.27.15-g-v/arch/x86/mm/ioremap.c --- linux-2.6.27.15/arch/x86/mm/ioremap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/ioremap.c 2009-02-10 20:32:11.000000000 +0100 @@ -63,8 +63,8 @@ int page_is_ram(unsigned long pagenr) * Second special case: Some BIOSen report the PC BIOS * area (640->1Mb) as ram even though it is not. */ - if (pagenr >= (BIOS_BEGIN >> PAGE_SHIFT) && - pagenr < (BIOS_END >> PAGE_SHIFT)) + if (pagenr >= (ISA_START_ADDRESS >> PAGE_SHIFT) && + pagenr < (ISA_END_ADDRESS >> PAGE_SHIFT)) return 0; for (i = 0; i < e820.nr_map; i++) { @@ -217,6 +217,8 @@ static void __iomem *__ioremap_caller(re break; } + prot = canon_pgprot(prot); + /* * Ok, go for it.. */ diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/mmap.c linux-2.6.27.15-g-v/arch/x86/mm/mmap.c --- linux-2.6.27.15/arch/x86/mm/mmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/mmap.c 2009-02-10 20:32:11.000000000 +0100 @@ -36,7 +36,7 @@ * Leave an at least ~128 MB hole. */ #define MIN_GAP (128*1024*1024) -#define MAX_GAP (TASK_SIZE/6*5) +#define MAX_GAP (pax_task_size/6*5) /* * True on X86_32 or when emulating IA32 on X86_64 @@ -81,27 +81,40 @@ static unsigned long mmap_rnd(void) return rnd << PAGE_SHIFT; } -static unsigned long mmap_base(void) +static unsigned long mmap_base(struct mm_struct *mm) { unsigned long gap = current->signal->rlim[RLIMIT_STACK].rlim_cur; + unsigned long pax_task_size = TASK_SIZE; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif if (gap < MIN_GAP) gap = MIN_GAP; else if (gap > MAX_GAP) gap = MAX_GAP; - return PAGE_ALIGN(TASK_SIZE - gap - mmap_rnd()); + return PAGE_ALIGN(pax_task_size - gap - mmap_rnd()); } /* * Bottom-up (legacy) layout on X86_32 did not support randomization, X86_64 * does, but not when emulating X86_32 */ -static unsigned long mmap_legacy_base(void) +static unsigned long mmap_legacy_base(struct mm_struct *mm) { - if (mmap_is_ia32()) + if (mmap_is_ia32()) { + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) + return SEGMEXEC_TASK_UNMAPPED_BASE; + else +#endif + return TASK_UNMAPPED_BASE; - else + } else return TASK_UNMAPPED_BASE + mmap_rnd(); } @@ -112,11 +125,23 @@ static unsigned long mmap_legacy_base(vo void arch_pick_mmap_layout(struct mm_struct *mm) { if (mmap_is_legacy()) { - mm->mmap_base = mmap_legacy_base(); + mm->mmap_base = mmap_legacy_base(mm); + +#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->mmap_base = mmap_base(mm); + +#ifdef CONFIG_PAX_RANDMMAP + if (mm->pax_flags & MF_PAX_RANDMMAP) + mm->mmap_base -= mm->delta_mmap + mm->delta_stack; +#endif + mm->get_unmapped_area = arch_get_unmapped_area_topdown; mm->unmap_area = arch_unmap_area_topdown; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/pageattr.c linux-2.6.27.15-g-v/arch/x86/mm/pageattr.c --- linux-2.6.27.15/arch/x86/mm/pageattr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/pageattr.c 2009-02-10 20:32:11.000000000 +0100 @@ -20,6 +20,7 @@ #include #include #include +#include /* * The current flushing context - we pass it instead of 5 arguments: @@ -213,7 +214,7 @@ static inline pgprot_t static_protection * Does not cover __inittext since that is gone later on. On * 64bit we do not enforce !NX on the low mapping */ - if (within(address, (unsigned long)_text, (unsigned long)_etext)) + if (within(address, ktla_ktva((unsigned long)_text), ktla_ktva((unsigned long)_etext))) pgprot_val(forbidden) |= _PAGE_NX; /* @@ -275,8 +276,20 @@ EXPORT_SYMBOL_GPL(lookup_address); */ static void __set_pmd_pte(pte_t *kpte, unsigned long address, pte_t pte) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + /* change init_mm */ set_pte_atomic(kpte, pte); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + #ifdef CONFIG_X86_32 if (!SHARED_KERNEL_PMD) { struct page *page; diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/pat.c linux-2.6.27.15-g-v/arch/x86/mm/pat.c --- linux-2.6.27.15/arch/x86/mm/pat.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/pat.c 2009-02-10 20:32:11.000000000 +0100 @@ -396,7 +396,7 @@ pgprot_t phys_mem_access_prot(struct fil return vma_prot; } -#ifdef CONFIG_STRICT_DEVMEM +#ifndef CONFIG_STRICT_DEVMEM /* This check is done in drivers/char/mem.c in case of STRICT_DEVMEM*/ static inline int range_is_allowed(unsigned long pfn, unsigned long size) { diff -NurpP --minimal linux-2.6.27.15/arch/x86/mm/pgtable_32.c linux-2.6.27.15-g-v/arch/x86/mm/pgtable_32.c --- linux-2.6.27.15/arch/x86/mm/pgtable_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/mm/pgtable_32.c 2009-02-10 20:32:11.000000000 +0100 @@ -31,6 +31,10 @@ void set_pte_vaddr(unsigned long vaddr, pmd_t *pmd; pte_t *pte; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + pgd = swapper_pg_dir + pgd_index(vaddr); if (pgd_none(*pgd)) { BUG(); @@ -47,11 +51,20 @@ void set_pte_vaddr(unsigned long vaddr, return; } pte = pte_offset_kernel(pmd, vaddr); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + if (pte_val(pteval)) set_pte_present(&init_mm, vaddr, pte, pteval); else pte_clear(&init_mm, vaddr, pte); +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* * It's enough to flush this one mapping. * (PGE mappings get flushed as well) diff -NurpP --minimal linux-2.6.27.15/arch/x86/oprofile/backtrace.c linux-2.6.27.15-g-v/arch/x86/oprofile/backtrace.c --- linux-2.6.27.15/arch/x86/oprofile/backtrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/oprofile/backtrace.c 2009-02-10 20:32:11.000000000 +0100 @@ -37,7 +37,7 @@ static void backtrace_address(void *data unsigned int *depth = data; if ((*depth)--) - oprofile_add_trace(addr); + oprofile_add_trace(ktla_ktva(addr)); } static struct stacktrace_ops backtrace_ops = { @@ -79,7 +79,7 @@ x86_backtrace(struct pt_regs * const reg struct frame_head *head = (struct frame_head *)frame_pointer(regs); unsigned long stack = kernel_trap_sp(regs); - if (!user_mode_vm(regs)) { + if (!user_mode(regs)) { if (depth) dump_trace(NULL, regs, (unsigned long *)stack, 0, &backtrace_ops, &depth); diff -NurpP --minimal linux-2.6.27.15/arch/x86/oprofile/op_model_p4.c linux-2.6.27.15-g-v/arch/x86/oprofile/op_model_p4.c --- linux-2.6.27.15/arch/x86/oprofile/op_model_p4.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/oprofile/op_model_p4.c 2009-02-10 20:32:11.000000000 +0100 @@ -47,7 +47,7 @@ static inline void setup_num_counters(vo #endif } -static int inline addr_increment(void) +static inline int addr_increment(void) { #ifdef CONFIG_SMP return smp_num_siblings == 2 ? 2 : 1; diff -NurpP --minimal linux-2.6.27.15/arch/x86/pci/common.c linux-2.6.27.15-g-v/arch/x86/pci/common.c --- linux-2.6.27.15/arch/x86/pci/common.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/pci/common.c 2009-02-10 20:32:11.000000000 +0100 @@ -362,7 +362,7 @@ static struct dmi_system_id __devinitdat DMI_MATCH(DMI_PRODUCT_NAME, "ProLiant DL585 G2"), }, }, - {} + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL} }; void __init dmi_check_pciprobe(void) diff -NurpP --minimal linux-2.6.27.15/arch/x86/pci/fixup.c linux-2.6.27.15-g-v/arch/x86/pci/fixup.c --- linux-2.6.27.15/arch/x86/pci/fixup.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/pci/fixup.c 2009-02-10 20:32:11.000000000 +0100 @@ -365,7 +365,7 @@ static struct dmi_system_id __devinitdat DMI_MATCH(DMI_PRODUCT_NAME, "MS-6702E"), }, }, - {} + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; /* @@ -436,7 +436,7 @@ static struct dmi_system_id __devinitdat DMI_MATCH(DMI_PRODUCT_VERSION, "PSA40U"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; static void __devinit pci_pre_fixup_toshiba_ohci1394(struct pci_dev *dev) diff -NurpP --minimal linux-2.6.27.15/arch/x86/pci/irq.c linux-2.6.27.15-g-v/arch/x86/pci/irq.c --- linux-2.6.27.15/arch/x86/pci/irq.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/pci/irq.c 2009-02-10 20:32:11.000000000 +0100 @@ -544,7 +544,7 @@ static __init int intel_router_probe(str static struct pci_device_id __initdata pirq_440gx[] = { { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_0) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82443GX_2) }, - { }, + { PCI_DEVICE(0, 0) } }; /* 440GX has a proprietary PIRQ router -- don't use it */ @@ -1132,7 +1132,7 @@ static struct dmi_system_id __initdata p DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 360"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; int __init pcibios_irq_init(void) diff -NurpP --minimal linux-2.6.27.15/arch/x86/pci/pcbios.c linux-2.6.27.15-g-v/arch/x86/pci/pcbios.c --- linux-2.6.27.15/arch/x86/pci/pcbios.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/pci/pcbios.c 2009-02-10 20:32:11.000000000 +0100 @@ -57,50 +57,120 @@ union bios32 { static struct { unsigned long address; unsigned short segment; -} bios32_indirect = { 0, __KERNEL_CS }; +} bios32_indirect __read_only = { 0, __PCIBIOS_CS }; /* * Returns the entry point for the given service, NULL on error */ -static unsigned long bios32_service(unsigned long service) +static unsigned long __devinit bios32_service(unsigned long service) { unsigned char return_code; /* %al */ unsigned long address; /* %ebx */ unsigned long length; /* %ecx */ unsigned long entry; /* %edx */ unsigned long flags; + struct desc_struct d, *gdt; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif local_irq_save(flags); - __asm__("lcall *(%%edi); cld" + + gdt = get_cpu_gdt_table(smp_processor_id()); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + pack_descriptor(&d, 0UL, 0xFFFFFUL, 0x9B, 0xC); + write_gdt_entry(gdt, GDT_ENTRY_PCIBIOS_CS, &d, DESCTYPE_S); + pack_descriptor(&d, 0UL, 0xFFFFFUL, 0x93, 0xC); + write_gdt_entry(gdt, GDT_ENTRY_PCIBIOS_DS, &d, DESCTYPE_S); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + __asm__("movw %w7, %%ds; lcall *(%%edi); push %%ss; pop %%ds; cld" : "=a" (return_code), "=b" (address), "=c" (length), "=d" (entry) : "0" (service), "1" (0), - "D" (&bios32_indirect)); + "D" (&bios32_indirect), + "r"(__PCIBIOS_DS) + : "memory"); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + gdt[GDT_ENTRY_PCIBIOS_CS].a = 0; + gdt[GDT_ENTRY_PCIBIOS_CS].b = 0; + gdt[GDT_ENTRY_PCIBIOS_DS].a = 0; + gdt[GDT_ENTRY_PCIBIOS_DS].b = 0; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + local_irq_restore(flags); switch (return_code) { - case 0: - return address + entry; - case 0x80: /* Not present */ - printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service); - return 0; - default: /* Shouldn't happen */ - printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n", - service, return_code); + case 0: { + int cpu; + unsigned char flags; + + printk(KERN_INFO "bios32_service: base:%08lx length:%08lx entry:%08lx\n", address, length, entry); + if (address >= 0xFFFF0 || length > 0x100000 - address || length <= entry) { + printk(KERN_WARNING "bios32_service: not valid\n"); return 0; + } + address = address + PAGE_OFFSET; + length += 16UL; /* some BIOSs underreport this... */ + flags = 4; + if (length >= 64*1024*1024) { + length >>= PAGE_SHIFT; + flags |= 8; + } + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + for (cpu = 0; cpu < NR_CPUS; cpu++) { + gdt = get_cpu_gdt_table(cpu); + pack_descriptor(&d, address, length, 0x9b, flags); + write_gdt_entry(gdt, GDT_ENTRY_PCIBIOS_CS, &d, DESCTYPE_S); + pack_descriptor(&d, address, length, 0x93, flags); + write_gdt_entry(gdt, GDT_ENTRY_PCIBIOS_DS, &d, DESCTYPE_S); + } + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + return entry; + } + case 0x80: /* Not present */ + printk(KERN_WARNING "bios32_service(0x%lx): not present\n", service); + return 0; + default: /* Shouldn't happen */ + printk(KERN_WARNING "bios32_service(0x%lx): returned 0x%x -- BIOS bug!\n", + service, return_code); + return 0; } } static struct { unsigned long address; unsigned short segment; -} pci_indirect = { 0, __KERNEL_CS }; +} pci_indirect __read_only = { 0, __PCIBIOS_CS }; -static int pci_bios_present; +static int pci_bios_present __read_only; static int __devinit check_pcibios(void) { @@ -109,11 +179,13 @@ static int __devinit check_pcibios(void) unsigned long flags, pcibios_entry; if ((pcibios_entry = bios32_service(PCI_SERVICE))) { - pci_indirect.address = pcibios_entry + PAGE_OFFSET; + pci_indirect.address = pcibios_entry; local_irq_save(flags); - __asm__( - "lcall *(%%edi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%edi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -122,7 +194,8 @@ static int __devinit check_pcibios(void) "=b" (ebx), "=c" (ecx) : "1" (PCIBIOS_PCI_BIOS_PRESENT), - "D" (&pci_indirect) + "D" (&pci_indirect), + "r" (__PCIBIOS_DS) : "memory"); local_irq_restore(flags); @@ -166,7 +239,10 @@ static int pci_bios_read(unsigned int se switch (len) { case 1: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -175,7 +251,8 @@ static int pci_bios_read(unsigned int se : "1" (PCIBIOS_READ_CONFIG_BYTE), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); /* * Zero-extend the result beyond 8 bits, do not trust the * BIOS having done it: @@ -183,7 +260,10 @@ static int pci_bios_read(unsigned int se *value &= 0xff; break; case 2: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -192,7 +272,8 @@ static int pci_bios_read(unsigned int se : "1" (PCIBIOS_READ_CONFIG_WORD), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); /* * Zero-extend the result beyond 16 bits, do not trust the * BIOS having done it: @@ -200,7 +281,10 @@ static int pci_bios_read(unsigned int se *value &= 0xffff; break; case 4: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -209,7 +293,8 @@ static int pci_bios_read(unsigned int se : "1" (PCIBIOS_READ_CONFIG_DWORD), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); break; } @@ -232,7 +317,10 @@ static int pci_bios_write(unsigned int s switch (len) { case 1: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -241,10 +329,14 @@ static int pci_bios_write(unsigned int s "c" (value), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); break; case 2: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -253,10 +345,14 @@ static int pci_bios_write(unsigned int s "c" (value), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); break; case 4: - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w6, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n\t" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -265,7 +361,8 @@ static int pci_bios_write(unsigned int s "c" (value), "b" (bx), "D" ((long)reg), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); break; } @@ -369,10 +466,13 @@ struct irq_routing_table * pcibios_get_i DBG("PCI: Fetching IRQ routing table... "); __asm__("push %%es\n\t" + "movw %w8, %%ds\n\t" "push %%ds\n\t" "pop %%es\n\t" - "lcall *(%%esi); cld\n\t" + "lcall *%%ss:(%%esi); cld\n\t" "pop %%es\n\t" + "push %%ss\n\t" + "pop %%ds\n" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -383,7 +483,8 @@ struct irq_routing_table * pcibios_get_i "1" (0), "D" ((long) &opt), "S" (&pci_indirect), - "m" (opt) + "m" (opt), + "r" (__PCIBIOS_DS) : "memory"); DBG("OK ret=%d, size=%d, map=%x\n", ret, opt.size, map); if (ret & 0xff00) @@ -407,7 +508,10 @@ int pcibios_set_irq_routing(struct pci_d { int ret; - __asm__("lcall *(%%esi); cld\n\t" + __asm__("movw %w5, %%ds\n\t" + "lcall *%%ss:(%%esi); cld\n\t" + "push %%ss\n\t" + "pop %%ds\n" "jc 1f\n\t" "xor %%ah, %%ah\n" "1:" @@ -415,7 +519,8 @@ int pcibios_set_irq_routing(struct pci_d : "0" (PCIBIOS_SET_PCI_HW_INT), "b" ((dev->bus->number << 8) | dev->devfn), "c" ((irq << 8) | (pin + 10)), - "S" (&pci_indirect)); + "S" (&pci_indirect), + "r" (__PCIBIOS_DS)); return !(ret & 0xff00); } EXPORT_SYMBOL(pcibios_set_irq_routing); diff -NurpP --minimal linux-2.6.27.15/arch/x86/power/cpu_32.c linux-2.6.27.15-g-v/arch/x86/power/cpu_32.c --- linux-2.6.27.15/arch/x86/power/cpu_32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/power/cpu_32.c 2009-02-10 20:32:11.000000000 +0100 @@ -66,7 +66,7 @@ static void do_fpu_end(void) static void fix_processor_context(void) { int cpu = smp_processor_id(); - struct tss_struct *t = &per_cpu(init_tss, cpu); + struct tss_struct *t = init_tss + cpu; set_tss_desc(cpu, t); /* * This just modifies memory; should not be diff -NurpP --minimal linux-2.6.27.15/arch/x86/power/cpu_64.c linux-2.6.27.15-g-v/arch/x86/power/cpu_64.c --- linux-2.6.27.15/arch/x86/power/cpu_64.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/power/cpu_64.c 2009-02-10 20:32:11.000000000 +0100 @@ -136,7 +136,11 @@ void restore_processor_state(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; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif /* * This just modifies memory; should not be necessary. But... This @@ -145,8 +149,16 @@ static void fix_processor_context(void) */ set_tss_desc(cpu, t); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + get_cpu_gdt_table(cpu)[GDT_ENTRY_TSS].type = 9; +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + syscall_init(); /* This sets MSR_*STAR and related */ load_TR_desc(); /* This does ltr */ load_LDT(¤t->active_mm->context); /* This does lldt */ diff -NurpP --minimal linux-2.6.27.15/arch/x86/vdso/vdso32-setup.c linux-2.6.27.15-g-v/arch/x86/vdso/vdso32-setup.c --- linux-2.6.27.15/arch/x86/vdso/vdso32-setup.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/vdso/vdso32-setup.c 2009-02-10 20:32:11.000000000 +0100 @@ -226,7 +226,7 @@ static inline void map_compat_vdso(int m 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(); @@ -249,7 +249,7 @@ static int __init gate_vma_init(void) gate_vma.vm_start = FIXADDR_USER_START; gate_vma.vm_end = FIXADDR_USER_END; gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC; - gate_vma.vm_page_prot = __P101; + gate_vma.vm_page_prot = vm_get_page_prot(gate_vma.vm_flags); /* * Make sure the vDSO gets into every core dump. * Dumping its contents makes post-mortem fully interpretable later @@ -331,7 +331,7 @@ int arch_setup_additional_pages(struct l if (compat) addr = VDSO_HIGH_BASE; else { - addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, 0); + addr = get_unmapped_area(NULL, 0, PAGE_SIZE, 0, MAP_EXECUTABLE); if (IS_ERR_VALUE(addr)) { ret = addr; goto up_fail; @@ -358,7 +358,7 @@ int arch_setup_additional_pages(struct l goto up_fail; } - current->mm->context.vdso = (void *)addr; + current->mm->context.vdso = addr; current_thread_info()->sysenter_return = VDSO32_SYMBOL(addr, SYSENTER_RETURN); @@ -384,7 +384,7 @@ static ctl_table abi_table2[] = { .mode = 0644, .proc_handler = proc_dointvec }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static ctl_table abi_root_table2[] = { @@ -394,7 +394,7 @@ static ctl_table abi_root_table2[] = { .mode = 0555, .child = abi_table2 }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static __init int ia32_binfmt_init(void) @@ -409,8 +409,14 @@ __initcall(ia32_binfmt_init); const char *arch_vma_name(struct vm_area_struct *vma) { - if (vma->vm_mm && vma->vm_start == (long)vma->vm_mm->context.vdso) + if (vma->vm_mm && vma->vm_start == vma->vm_mm->context.vdso) return "[vdso]"; + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma->vm_mm && vma->vm_mirror && vma->vm_mirror->vm_start == vma->vm_mm->context.vdso) + return "[vdso]"; +#endif + return NULL; } @@ -419,7 +425,7 @@ struct vm_area_struct *get_gate_vma(stru struct mm_struct *mm = tsk->mm; /* Check to see if this task was created in compat vdso mode */ - if (mm && mm->context.vdso == (void *)VDSO_HIGH_BASE) + if (mm && mm->context.vdso == VDSO_HIGH_BASE) return &gate_vma; return NULL; } diff -NurpP --minimal linux-2.6.27.15/arch/x86/vdso/vma.c linux-2.6.27.15-g-v/arch/x86/vdso/vma.c --- linux-2.6.27.15/arch/x86/vdso/vma.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/vdso/vma.c 2009-02-10 20:32:11.000000000 +0100 @@ -123,7 +123,7 @@ int arch_setup_additional_pages(struct l if (ret) goto up_fail; - current->mm->context.vdso = (void *)addr; + current->mm->context.vdso = addr; up_fail: up_write(&mm->mmap_sem); return ret; diff -NurpP --minimal linux-2.6.27.15/arch/x86/xen/enlighten.c linux-2.6.27.15-g-v/arch/x86/xen/enlighten.c --- linux-2.6.27.15/arch/x86/xen/enlighten.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/xen/enlighten.c 2009-02-10 20:32:11.000000000 +0100 @@ -343,7 +343,7 @@ static void xen_set_ldt(const void *addr static void xen_load_gdt(const struct desc_ptr *dtr) { unsigned long *frames; - unsigned long va = dtr->address; + unsigned long va = (unsigned long)dtr->address; unsigned int size = dtr->size + 1; unsigned pages = (size + PAGE_SIZE - 1) / PAGE_SIZE; int f; @@ -358,7 +358,7 @@ static void xen_load_gdt(const struct de mcs = xen_mc_entry(sizeof(*frames) * pages); frames = mcs.args; - for (f = 0; va < dtr->address + size; va += PAGE_SIZE, f++) { + for (f = 0; va < (unsigned long)dtr->address + size; va += PAGE_SIZE, f++) { frames[f] = virt_to_mfn(va); make_lowmem_page_readonly((void *)va); } @@ -467,7 +467,7 @@ static void xen_write_idt_entry(gate_des preempt_disable(); - start = __get_cpu_var(idt_desc).address; + start = (unsigned long)__get_cpu_var(idt_desc).address; end = start + __get_cpu_var(idt_desc).size + 1; xen_mc_flush(); @@ -1574,6 +1574,8 @@ static __init pgd_t *xen_setup_kernel_pa convert_pfn_mfn(init_level4_pgt); convert_pfn_mfn(level3_ident_pgt); convert_pfn_mfn(level3_kernel_pgt); + convert_pfn_mfn(level3_vmalloc_pgt); + convert_pfn_mfn(level3_vmemmap_pgt); l3 = m2v(pgd[pgd_index(__START_KERNEL_map)].pgd); l2 = m2v(l3[pud_index(__START_KERNEL_map)].pud); @@ -1592,9 +1594,12 @@ static __init pgd_t *xen_setup_kernel_pa set_page_prot(init_level4_pgt, PAGE_KERNEL_RO); set_page_prot(level3_ident_pgt, PAGE_KERNEL_RO); set_page_prot(level3_kernel_pgt, PAGE_KERNEL_RO); + set_page_prot(level3_vmalloc_pgt, PAGE_KERNEL_RO); + set_page_prot(level3_vmemmap_pgt, PAGE_KERNEL_RO); set_page_prot(level3_user_vsyscall, PAGE_KERNEL_RO); set_page_prot(level2_kernel_pgt, PAGE_KERNEL_RO); set_page_prot(level2_fixmap_pgt, PAGE_KERNEL_RO); + set_page_prot(level1_fixmap_pgt, PAGE_KERNEL_RO); /* Pin down new L4 */ pin_pagetable_pfn(MMUEXT_PIN_L4_TABLE, diff -NurpP --minimal linux-2.6.27.15/arch/x86/xen/smp.c linux-2.6.27.15-g-v/arch/x86/xen/smp.c --- linux-2.6.27.15/arch/x86/xen/smp.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/arch/x86/xen/smp.c 2009-02-10 20:32:11.000000000 +0100 @@ -170,11 +170,6 @@ static void __init xen_smp_prepare_boot_ { BUG_ON(smp_processor_id() != 0); native_smp_prepare_boot_cpu(); - - /* We've switched to the "real" per-cpu gdt, so make sure the - old memory can be recycled */ - make_lowmem_page_readwrite(&per_cpu_var(gdt_page)); - xen_setup_vcpu_info_placement(); } @@ -232,8 +227,8 @@ cpu_initialize_context(unsigned int cpu, gdt = get_cpu_gdt_table(cpu); ctxt->flags = VGCF_IN_KERNEL; - ctxt->user_regs.ds = __USER_DS; - ctxt->user_regs.es = __USER_DS; + ctxt->user_regs.ds = __KERNEL_DS; + ctxt->user_regs.es = __KERNEL_DS; ctxt->user_regs.ss = __KERNEL_DS; #ifdef CONFIG_X86_32 ctxt->user_regs.fs = __KERNEL_PERCPU; diff -NurpP --minimal linux-2.6.27.15/crypto/async_tx/async_tx.c linux-2.6.27.15-g-v/crypto/async_tx/async_tx.c --- linux-2.6.27.15/crypto/async_tx/async_tx.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/crypto/async_tx/async_tx.c 2009-02-10 20:32:11.000000000 +0100 @@ -358,8 +358,8 @@ async_tx_init(void) err: printk(KERN_ERR "async_tx: initialization failure\n"); - while (--cap >= 0) - free_percpu(channel_table[cap]); + while (cap) + free_percpu(channel_table[--cap]); return 1; } diff -NurpP --minimal linux-2.6.27.15/crypto/lrw.c linux-2.6.27.15-g-v/crypto/lrw.c --- linux-2.6.27.15/crypto/lrw.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/crypto/lrw.c 2009-02-10 20:32:11.000000000 +0100 @@ -54,7 +54,7 @@ static int setkey(struct crypto_tfm *par struct priv *ctx = crypto_tfm_ctx(parent); struct crypto_cipher *child = ctx->child; int err, i; - be128 tmp = { 0 }; + be128 tmp = { 0, 0 }; int bsize = crypto_cipher_blocksize(child); crypto_cipher_clear_flags(child, CRYPTO_TFM_REQ_MASK); diff -NurpP --minimal linux-2.6.27.15/Documentation/dontdiff linux-2.6.27.15-g-v/Documentation/dontdiff --- linux-2.6.27.15/Documentation/dontdiff 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/Documentation/dontdiff 2009-02-10 20:32:11.000000000 +0100 @@ -3,6 +3,7 @@ *.bin *.cpio *.css +*.dbg *.dvi *.eps *.fw.gen.S @@ -53,9 +54,14 @@ COPYING CREDITS CVS ChangeSet +GPATH +GRTAGS +GSYMS +GTAGS Image Kerntypes MODS.txt +Module.markers Module.symvers PENDING SCCS @@ -66,7 +72,6 @@ aic7*reg_print.c* aic7*seq.h* aicasm aicdb.h* -asm asm-offsets.h asm_offsets.h autoconf.h* @@ -74,6 +79,7 @@ bbootsect bin2c binkernel.spec bootsect +bounds.h bsetup btfixupprep build @@ -90,6 +96,7 @@ config_data.gz* conmakehash consolemap_deftbl.c* crc32table.h* +cpustr.h cscope.* defkeymap.c* devlist.h* @@ -138,6 +145,7 @@ miboot* mk_elfconfig mkboot mkbugboot +mkcpustr mkdep mkprep mktables @@ -179,16 +187,21 @@ times.h* tkparse trix_boot.h utsrelease.h* -vdso.lds +vdso*.lds version.h* vmlinux vmlinux-* vmlinux.aout -vmlinux*.lds* +vmlinux.bin.all +vmlinux*.lds +vmlinux.relocs vmlinux*.scr -vsyscall.lds +vsyscall*.lds +wakeup.elf +wakeup.lds wanxlfw.inc uImage unifdef +utsrelease.h zImage* zconf.hash.c diff -NurpP --minimal linux-2.6.27.15/Documentation/vserver/debug.txt linux-2.6.27.15-g-v/Documentation/vserver/debug.txt --- linux-2.6.27.15/Documentation/vserver/debug.txt 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/Documentation/vserver/debug.txt 2009-02-10 20:32:11.000000000 +0100 @@ -0,0 +1,154 @@ + +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 %ld,%ld [mult=%d]" + 3 8 "ext3_has_free_blocks(%p): %lu<%lu+1, %c, %u!=%u r=%d" + "ext3_has_free_blocks(%p): free=%lu, root=%lu" + "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_misc: + + 0 1 "destroy_dqhash: %p [#0x%08x] c=%d" + "new_dqhash: %p [#0x%08x]" + "vroot[%d]_clr_dev: dev=%p[%lu,%d:%d]" + "vroot[%d]_get_real_bdev: dev=%p[%lu,%d:%d]" + "vroot[%d]_set_dev: dev=%p[%lu,%d:%d]" + "vroot_get_real_bdev not set" + 1 2 "cow_break_link(»%s«)" + "temp copy »%s«" + 2 4 "dentry_open(new): %p" + "dentry_open(old): %p" + "lookup_create(new): %p" + "old path »%s«" + "path_lookup(old): %d" + "vfs_create(new): %d" + "vfs_rename: %d" + "vfs_sendfile: %d" + 3 8 "fput(new_file=%p[#%d])" + "fput(old_file=%p[#%d])" + 4 10 "vx_info_kill(%p[#%d],%d,%d) = %d" + "vx_info_kill(%p[#%d],%d,%d)*" + 5 20 "vs_reboot(%p[#%d],%d)" + 6 40 "dropping task %p[#%u,%u] for %p[#%u,%u]" + +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.%d.%d]" + 5 20 "moved task %p into nxi:%p[#%d]" + "nx_migrate_task(%p,%p[#%d.%d.%d])" + "task_get_nx_info(%p)" + 6 40 "nx_clear_persistent(%p[#%d])" + +debug_quota: + + 0 1 "quota_sync_dqh(%p,%d) discard inode %p" + 1 2 "quota_sync_dqh(%p,%d)" + "sync_dquots(%p,%d)" + "sync_dquots_dqh(%p,%d)" + 3 8 "do_quotactl(%p,%d,cmd=%d,id=%d,%p)" + +debug_switch: + + 0 1 "vc: VCMD_%02d_%d[%d], %d,%p [%d,%d,%x,%x]" + 1 2 "vc: VCMD_%02d_%d[%d] = %08lx(%ld) [%d,%d]" + 4 10 "%s: (%s %s) returned %s with %d" + +debug_tag: + + 7 80 "dx_parse_tag(»%s«): %d:#%d" + "dx_propagate_tag(%p[#%lu.%d]): %d,%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)" + "loc_vx_info(%d) = %p (found)" + "loc_vx_info(%d) = %p (new)" + "loc_vx_info(%d) = %p (not available)" + 1 2 "create_vx_info(%d)*" + "loc_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.%d.%d]" + "__vx_dynamic_id: [#%d]" + 5 20 "enter_vx_info(%p[#%d],%p) %p[#%d,%p]" + "leave_vx_info(%p[#%d,%p]) %p[#%d,%p]" + "moved task %p into vxi:%p[#%d]" + "task_get_vx_info(%p)" + "vx_migrate_task(%p,%p[#%d.%d])" + 6 40 "vx_clear_persistent(%p[#%d])" + "vx_exit_init(%p[#%d],%p[#%d,%d,%d])" + "vx_set_init(%p[#%d],%p[#%d,%d,%d])" + "vx_set_persistent(%p[#%d])" + "vx_set_reaper(%p[#%d],%p[#%d,%d])" + 7 80 "vx_child_reaper(%p[#%u,%u]) = %p[#%u,%u]" + + +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 --minimal linux-2.6.27.15/drivers/acpi/blacklist.c linux-2.6.27.15-g-v/drivers/acpi/blacklist.c --- linux-2.6.27.15/drivers/acpi/blacklist.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/acpi/blacklist.c 2009-02-10 20:32:11.000000000 +0100 @@ -71,7 +71,7 @@ static struct acpi_blacklist_item acpi_b {"IBM ", "TP600E ", 0x00000105, ACPI_SIG_DSDT, less_than_or_equal, "Incorrect _ADR", 1}, - {""} + {"", "", 0, 0, 0, all_versions, 0} }; #if CONFIG_ACPI_BLACKLIST_YEAR diff -NurpP --minimal linux-2.6.27.15/drivers/acpi/osl.c linux-2.6.27.15-g-v/drivers/acpi/osl.c --- linux-2.6.27.15/drivers/acpi/osl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/acpi/osl.c 2009-02-10 20:32:11.000000000 +0100 @@ -494,6 +494,8 @@ acpi_os_read_memory(acpi_physical_addres void __iomem *virt_addr; virt_addr = ioremap(phys_addr, width); + if (!virt_addr) + return AE_NO_MEMORY; if (!value) value = &dummy; @@ -522,6 +524,8 @@ acpi_os_write_memory(acpi_physical_addre void __iomem *virt_addr; virt_addr = ioremap(phys_addr, width); + if (!virt_addr) + return AE_NO_MEMORY; switch (width) { case 8: diff -NurpP --minimal linux-2.6.27.15/drivers/acpi/processor_core.c linux-2.6.27.15-g-v/drivers/acpi/processor_core.c --- linux-2.6.27.15/drivers/acpi/processor_core.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/acpi/processor_core.c 2009-02-10 20:32:11.000000000 +0100 @@ -667,7 +667,7 @@ static int __cpuinit acpi_processor_star return 0; } - BUG_ON((pr->id >= nr_cpu_ids) || (pr->id < 0)); + BUG_ON(pr->id >= nr_cpu_ids); /* * Buggy BIOS check diff -NurpP --minimal linux-2.6.27.15/drivers/acpi/processor_idle.c linux-2.6.27.15-g-v/drivers/acpi/processor_idle.c --- linux-2.6.27.15/drivers/acpi/processor_idle.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/acpi/processor_idle.c 2009-02-10 20:32:11.000000000 +0100 @@ -182,7 +182,7 @@ static struct dmi_system_id __cpuinitdat DMI_MATCH(DMI_BIOS_VENDOR,"Phoenix Technologies LTD"), DMI_MATCH(DMI_BIOS_VERSION,"SHE845M0.86C.0013.D.0302131307")}, (void *)2}, - {}, + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL}, }; static inline u32 ticks_elapsed(u32 t1, u32 t2) diff -NurpP --minimal linux-2.6.27.15/drivers/acpi/tables/tbfadt.c linux-2.6.27.15-g-v/drivers/acpi/tables/tbfadt.c --- linux-2.6.27.15/drivers/acpi/tables/tbfadt.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/acpi/tables/tbfadt.c 2009-02-10 20:32:11.000000000 +0100 @@ -48,7 +48,7 @@ ACPI_MODULE_NAME("tbfadt") /* Local prototypes */ -static void inline +static inline void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, u8 bit_width, u64 address); @@ -122,7 +122,7 @@ static struct acpi_fadt_info fadt_info_t * ******************************************************************************/ -static void inline +static inline void acpi_tb_init_generic_address(struct acpi_generic_address *generic_address, u8 bit_width, u64 address) { diff -NurpP --minimal linux-2.6.27.15/drivers/ata/ahci.c linux-2.6.27.15-g-v/drivers/ata/ahci.c --- linux-2.6.27.15/drivers/ata/ahci.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ata/ahci.c 2009-02-10 20:32:11.000000000 +0100 @@ -591,7 +591,7 @@ static const struct pci_device_id ahci_p { PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_STORAGE_SATA_AHCI, 0xffffff, board_ahci }, - { } /* terminate list */ + { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */ }; diff -NurpP --minimal linux-2.6.27.15/drivers/ata/ata_piix.c linux-2.6.27.15-g-v/drivers/ata/ata_piix.c --- linux-2.6.27.15/drivers/ata/ata_piix.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ata/ata_piix.c 2009-02-10 20:32:11.000000000 +0100 @@ -284,7 +284,7 @@ static const struct pci_device_id piix_p /* SATA Controller IDE (PCH) */ { 0x8086, 0x3b2e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, ich8_sata }, - { } /* terminate list */ + { 0, 0, 0, 0, 0, 0, 0 } /* terminate list */ }; static struct pci_driver piix_pci_driver = { @@ -587,7 +587,7 @@ static const struct ich_laptop ich_lapto { 0x266F, 0x1025, 0x0066 }, /* ICH6 on ACER Aspire 1694WLMi */ { 0x2653, 0x1043, 0x82D8 }, /* ICH6M on Asus Eee 701 */ /* end marker */ - { 0, } + { 0, 0, 0 } }; /** @@ -1143,7 +1143,7 @@ static int piix_broken_suspend(void) }, }, - { } /* terminate list */ + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } /* terminate list */ }; static const char *oemstrs[] = { "Tecra M3,", diff -NurpP --minimal linux-2.6.27.15/drivers/ata/libata-core.c linux-2.6.27.15-g-v/drivers/ata/libata-core.c --- linux-2.6.27.15/drivers/ata/libata-core.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ata/libata-core.c 2009-02-10 20:32:11.000000000 +0100 @@ -746,7 +746,7 @@ static const struct ata_xfer_ent { { ATA_SHIFT_PIO, ATA_NR_PIO_MODES, XFER_PIO_0 }, { ATA_SHIFT_MWDMA, ATA_NR_MWDMA_MODES, XFER_MW_DMA_0 }, { ATA_SHIFT_UDMA, ATA_NR_UDMA_MODES, XFER_UDMA_0 }, - { -1, }, + { -1, 0, 0 } }; /** @@ -2917,7 +2917,7 @@ static const struct ata_timing ata_timin { XFER_UDMA_5, 0, 0, 0, 0, 0, 0, 0, 20 }, { XFER_UDMA_6, 0, 0, 0, 0, 0, 0, 0, 15 }, - { 0xFF } + { 0xFF, 0, 0, 0, 0, 0, 0, 0, 0 } }; #define ENOUGH(v, unit) (((v)-1)/(unit)+1) @@ -4073,7 +4073,7 @@ static const struct ata_blacklist_entry { "TSSTcorp CDDVDW SH-S202N", "SB01", ATA_HORKAGE_IVB, }, /* End Marker */ - { } + { NULL, NULL, 0 } }; static int strn_pattern_cmp(const char *patt, const char *name, int wildchar) diff -NurpP --minimal linux-2.6.27.15/drivers/block/Kconfig linux-2.6.27.15-g-v/drivers/block/Kconfig --- linux-2.6.27.15/drivers/block/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/block/Kconfig 2009-02-10 20:32:12.000000000 +0100 @@ -263,6 +263,13 @@ config BLK_DEV_CRYPTOLOOP instead, which can be configured to be on-disk compatible with the cryptoloop device. +config BLK_DEV_VROOT + tristate "Virtual Root device support" + depends on QUOTACTL + ---help--- + Saying Y here will allow you to use quota/fs ioctls on a shared + partition within a virtual server without compromising security. + config BLK_DEV_NBD tristate "Network block device support" depends on NET diff -NurpP --minimal linux-2.6.27.15/drivers/block/loop.c linux-2.6.27.15-g-v/drivers/block/loop.c --- linux-2.6.27.15/drivers/block/loop.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/block/loop.c 2009-02-10 20:32:12.000000000 +0100 @@ -76,6 +76,7 @@ #include #include #include +#include #include @@ -794,6 +795,7 @@ static int loop_set_fd(struct loop_devic lo->lo_blocksize = lo_blocksize; lo->lo_device = bdev; lo->lo_flags = lo_flags; + lo->lo_xid = vx_current_xid(); lo->lo_backing_file = file; lo->transfer = transfer_none; lo->ioctl = NULL; @@ -915,6 +917,7 @@ static int loop_clr_fd(struct loop_devic lo->lo_encrypt_key_size = 0; lo->lo_flags = 0; lo->lo_thread = NULL; + lo->lo_xid = 0; memset(lo->lo_encrypt_key, 0, LO_KEY_SIZE); memset(lo->lo_crypt_name, 0, LO_NAME_SIZE); memset(lo->lo_file_name, 0, LO_NAME_SIZE); @@ -938,7 +941,7 @@ loop_set_status(struct loop_device *lo, struct loop_func_table *xfer; if (lo->lo_encrypt_key_size && lo->lo_key_owner != current->uid && - !capable(CAP_SYS_ADMIN)) + !vx_capable(CAP_SYS_ADMIN, VXC_ADMIN_CLOOP)) return -EPERM; if (lo->lo_state != Lo_bound) return -ENXIO; @@ -1022,7 +1025,8 @@ loop_get_status(struct loop_device *lo, memcpy(info->lo_crypt_name, lo->lo_crypt_name, LO_NAME_SIZE); info->lo_encrypt_type = lo->lo_encryption ? lo->lo_encryption->number : 0; - if (lo->lo_encrypt_key_size && capable(CAP_SYS_ADMIN)) { + if (lo->lo_encrypt_key_size && + vx_capable(CAP_SYS_ADMIN, VXC_ADMIN_CLOOP)) { info->lo_encrypt_key_size = lo->lo_encrypt_key_size; memcpy(info->lo_encrypt_key, lo->lo_encrypt_key, lo->lo_encrypt_key_size); @@ -1331,6 +1335,9 @@ static int lo_open(struct inode *inode, { struct loop_device *lo = inode->i_bdev->bd_disk->private_data; + if (!vx_check(lo->lo_xid, VS_IDENT|VS_HOSTID|VS_ADMIN_P)) + return -EACCES; + mutex_lock(&lo->lo_ctl_mutex); lo->lo_refcnt++; mutex_unlock(&lo->lo_ctl_mutex); diff -NurpP --minimal linux-2.6.27.15/drivers/block/Makefile linux-2.6.27.15-g-v/drivers/block/Makefile --- linux-2.6.27.15/drivers/block/Makefile 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/block/Makefile 2009-02-10 20:32:12.000000000 +0100 @@ -30,5 +30,6 @@ obj-$(CONFIG_VIODASD) += viodasd.o obj-$(CONFIG_BLK_DEV_SX8) += sx8.o obj-$(CONFIG_BLK_DEV_UB) += ub.o obj-$(CONFIG_BLK_DEV_HD) += hd.o +obj-$(CONFIG_BLK_DEV_VROOT) += vroot.o obj-$(CONFIG_XEN_BLKDEV_FRONTEND) += xen-blkfront.o diff -NurpP --minimal linux-2.6.27.15/drivers/block/vroot.c linux-2.6.27.15-g-v/drivers/block/vroot.c --- linux-2.6.27.15/drivers/block/vroot.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/block/vroot.c 2009-02-10 20:32:12.000000000 +0100 @@ -0,0 +1,283 @@ +/* + * 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-2007 by Herbert Pötzl. + * Redistribution of this file is permitted under the + * GNU General Public License. + * + */ + +#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; + disks[i]->queue = blk_alloc_queue(GFP_KERNEL); + if (!disks[i]->queue) + goto out_mem3; + } + + 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); + disk->private_data = vr; + } + + err = register_vroot_grb(&__vroot_get_real_bdev); + if (err) + goto out_mem3; + + 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_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]); + } + unregister_blkdev(VROOT_MAJOR, "vroot"); + + kfree(disks); + kfree(vroot_dev); +} + +module_init(vroot_init); +module_exit(vroot_exit); + +#ifndef MODULE + +static int __init max_vroot_setup(char *str) +{ + max_vroot = simple_strtol(str, NULL, 0); + return 1; +} + +__setup("max_vroot=", max_vroot_setup); + +#endif + diff -NurpP --minimal linux-2.6.27.15/drivers/char/agp/frontend.c linux-2.6.27.15-g-v/drivers/char/agp/frontend.c --- linux-2.6.27.15/drivers/char/agp/frontend.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/agp/frontend.c 2009-02-10 20:32:12.000000000 +0100 @@ -824,7 +824,7 @@ static int agpioc_reserve_wrap(struct ag if (copy_from_user(&reserve, arg, sizeof(struct agp_region))) return -EFAULT; - if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment)) + if ((unsigned) reserve.seg_count >= ~0U/sizeof(struct agp_segment_priv)) return -EFAULT; client = agp_find_client_by_pid(reserve.pid); diff -NurpP --minimal linux-2.6.27.15/drivers/char/agp/intel-agp.c linux-2.6.27.15-g-v/drivers/char/agp/intel-agp.c --- linux-2.6.27.15/drivers/char/agp/intel-agp.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/agp/intel-agp.c 2009-02-10 20:32:12.000000000 +0100 @@ -2332,7 +2332,7 @@ static struct pci_device_id agp_intel_pc ID(PCI_DEVICE_ID_INTEL_IGD_E_HB), ID(PCI_DEVICE_ID_INTEL_Q45_HB), ID(PCI_DEVICE_ID_INTEL_G45_HB), - { } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, agp_intel_pci_table); diff -NurpP --minimal linux-2.6.27.15/drivers/char/hpet.c linux-2.6.27.15-g-v/drivers/char/hpet.c --- linux-2.6.27.15/drivers/char/hpet.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/hpet.c 2009-02-10 20:32:12.000000000 +0100 @@ -959,7 +959,7 @@ static struct acpi_driver hpet_acpi_driv }, }; -static struct miscdevice hpet_misc = { HPET_MINOR, "hpet", &hpet_fops }; +static struct miscdevice hpet_misc = { HPET_MINOR, "hpet", &hpet_fops, {NULL, NULL}, NULL, NULL }; static int __init hpet_init(void) { diff -NurpP --minimal linux-2.6.27.15/drivers/char/keyboard.c linux-2.6.27.15-g-v/drivers/char/keyboard.c --- linux-2.6.27.15/drivers/char/keyboard.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/keyboard.c 2009-02-10 20:32:12.000000000 +0100 @@ -635,6 +635,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); } @@ -1388,7 +1398,7 @@ static const struct input_device_id kbd_ .evbit = { BIT_MASK(EV_SND) }, }, - { }, /* Terminating entry */ + { 0 }, /* Terminating entry */ }; MODULE_DEVICE_TABLE(input, kbd_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/char/mem.c linux-2.6.27.15-g-v/drivers/char/mem.c --- linux-2.6.27.15/drivers/char/mem.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/mem.c 2009-02-10 20:32:12.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. @@ -192,6 +197,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 @@ -350,6 +360,11 @@ static int mmap_mem(struct file * file, &vma->vm_page_prot)) return -EINVAL; +#ifdef CONFIG_GRKERNSEC_KMEM + if (gr_handle_mem_mmap(vma->vm_pgoff << PAGE_SHIFT, vma)) + return -EPERM; +#endif + vma->vm_page_prot = phys_mem_access_prot(file, vma->vm_pgoff, size, vma->vm_page_prot); @@ -588,6 +603,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; @@ -791,6 +811,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; } @@ -798,7 +828,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 @@ -938,6 +967,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: unlock_kernel(); return -ENXIO; @@ -974,6 +1008,9 @@ static const struct { #ifdef CONFIG_CRASH_DUMP {12,"oldmem", S_IRUSR | S_IWUSR | S_IRGRP, &oldmem_fops}, #endif +#ifdef CONFIG_GRKERNSEC + {13,"grsec", S_IRUSR | S_IWUGO, &grsec_fops}, +#endif }; static struct class *mem_class; diff -NurpP --minimal linux-2.6.27.15/drivers/char/nvram.c linux-2.6.27.15-g-v/drivers/char/nvram.c --- linux-2.6.27.15/drivers/char/nvram.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/nvram.c 2009-02-10 20:32:12.000000000 +0100 @@ -433,7 +433,10 @@ static const struct file_operations nvra static struct miscdevice nvram_dev = { NVRAM_MINOR, "nvram", - &nvram_fops + &nvram_fops, + {NULL, NULL}, + NULL, + NULL }; static int __init diff -NurpP --minimal linux-2.6.27.15/drivers/char/random.c linux-2.6.27.15-g-v/drivers/char/random.c --- linux-2.6.27.15/drivers/char/random.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/random.c 2009-02-10 20:32:13.000000000 +0100 @@ -249,8 +249,13 @@ /* * Configuration information */ +#ifdef CONFIG_GRKERNSEC_RANDNET +#define INPUT_POOL_WORDS 512 +#define OUTPUT_POOL_WORDS 128 +#else #define INPUT_POOL_WORDS 128 #define OUTPUT_POOL_WORDS 32 +#endif #define SEC_XFER_SIZE 512 /* @@ -287,10 +292,17 @@ static struct poolinfo { int poolwords; int tap1, tap2, tap3, tap4, tap5; } poolinfo_table[] = { +#ifdef CONFIG_GRKERNSEC_RANDNET + /* x^512 + x^411 + x^308 + x^208 +x^104 + x + 1 -- 225 */ + { 512, 411, 308, 208, 104, 1 }, + /* x^128 + x^103 + x^76 + x^51 + x^25 + x + 1 -- 105 */ + { 128, 103, 76, 51, 25, 1 }, +#else /* x^128 + x^103 + x^76 + x^51 +x^25 + x + 1 -- 105 */ { 128, 103, 76, 51, 25, 1 }, /* x^32 + x^26 + x^20 + x^14 + x^7 + x + 1 -- 15 */ { 32, 26, 20, 14, 7, 1 }, +#endif #if 0 /* x^2048 + x^1638 + x^1231 + x^819 + x^411 + x + 1 -- 115 */ { 2048, 1638, 1231, 819, 411, 1 }, @@ -1166,7 +1178,7 @@ EXPORT_SYMBOL(generate_random_uuid); #include static int min_read_thresh = 8, min_write_thresh; -static int max_read_thresh = INPUT_POOL_WORDS * 32; +static int max_read_thresh = OUTPUT_POOL_WORDS * 32; static int max_write_thresh = INPUT_POOL_WORDS * 32; static char sysctl_bootid[16]; diff -NurpP --minimal linux-2.6.27.15/drivers/char/sysrq.c linux-2.6.27.15-g-v/drivers/char/sysrq.c --- linux-2.6.27.15/drivers/char/sysrq.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/sysrq.c 2009-02-10 20:32:13.000000000 +0100 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -351,6 +352,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 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); @@ -404,7 +420,11 @@ static struct sysrq_key_op *sysrq_key_ta NULL, /* x */ /* y: May be registered on sparc64 for global register dump */ NULL, /* y */ - NULL /* z */ +#ifdef CONFIG_VSERVER_DEBUG + &sysrq_showvxinfo_op, /* z */ +#else + NULL, /* z */ +#endif }; /* key2index calculation, -1 on invalid index */ @@ -416,6 +436,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; return retval; diff -NurpP --minimal linux-2.6.27.15/drivers/char/tpm/tpm.c linux-2.6.27.15-g-v/drivers/char/tpm/tpm.c --- linux-2.6.27.15/drivers/char/tpm/tpm.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/tpm/tpm.c 2009-02-10 20:32:13.000000000 +0100 @@ -1037,7 +1037,7 @@ ssize_t tpm_write(struct file *file, con mutex_lock(&chip->buffer_mutex); - if (in_size > TPM_BUFSIZE) + if (in_size > (unsigned int)TPM_BUFSIZE) in_size = TPM_BUFSIZE; if (copy_from_user diff -NurpP --minimal linux-2.6.27.15/drivers/char/tty_io.c linux-2.6.27.15-g-v/drivers/char/tty_io.c --- linux-2.6.27.15/drivers/char/tty_io.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/tty_io.c 2009-02-10 20:32:13.000000000 +0100 @@ -106,6 +106,7 @@ #include #include +#include #undef TTY_DEBUG_HANGUP @@ -2770,6 +2771,7 @@ static int tiocspgrp(struct tty_struct * return -ENOTTY; if (get_user(pgrp_nr, p)) return -EFAULT; + pgrp_nr = vx_rmap_pid(pgrp_nr); if (pgrp_nr < 0) return -EINVAL; rcu_read_lock(); diff -NurpP --minimal linux-2.6.27.15/drivers/char/vt_ioctl.c linux-2.6.27.15-g-v/drivers/char/vt_ioctl.c --- linux-2.6.27.15/drivers/char/vt_ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/char/vt_ioctl.c 2009-02-10 20:32:13.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) { /* deallocate map */ key_map = key_maps[s]; @@ -236,6 +242,13 @@ do_kdgkb_ioctl(int cmd, struct kbsentry goto reterr; } +#ifdef CONFIG_GRKERNSEC + if (!capable(CAP_SYS_TTY_CONFIG)) { + ret = -EPERM; + goto reterr; + } +#endif + q = func_table[i]; first_free = funcbufptr + (funcbufsize - funcbufleft); for (j = i+1; j < MAX_NR_FUNC && !func_table[j]; j++) diff -NurpP --minimal linux-2.6.27.15/drivers/edac/edac_core.h linux-2.6.27.15-g-v/drivers/edac/edac_core.h --- linux-2.6.27.15/drivers/edac/edac_core.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/edac/edac_core.h 2009-02-10 20:32:13.000000000 +0100 @@ -85,11 +85,11 @@ extern int edac_debug_level; #else /* !CONFIG_EDAC_DEBUG */ -#define debugf0( ... ) -#define debugf1( ... ) -#define debugf2( ... ) -#define debugf3( ... ) -#define debugf4( ... ) +#define debugf0( ... ) do {} while (0) +#define debugf1( ... ) do {} while (0) +#define debugf2( ... ) do {} while (0) +#define debugf3( ... ) do {} while (0) +#define debugf4( ... ) do {} while (0) #endif /* !CONFIG_EDAC_DEBUG */ diff -NurpP --minimal linux-2.6.27.15/drivers/firmware/dmi_scan.c linux-2.6.27.15-g-v/drivers/firmware/dmi_scan.c --- linux-2.6.27.15/drivers/firmware/dmi_scan.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/firmware/dmi_scan.c 2009-02-10 20:32:13.000000000 +0100 @@ -384,11 +384,6 @@ void __init dmi_scan_machine(void) } } else { - /* - * no iounmap() for that ioremap(); it would be a no-op, but - * it's so early in setup that sucker gets confused into doing - * what it shouldn't if we actually call it. - */ p = dmi_ioremap(0xF0000, 0x10000); if (p == NULL) goto out; diff -NurpP --minimal linux-2.6.27.15/drivers/hwmon/fscpos.c linux-2.6.27.15-g-v/drivers/hwmon/fscpos.c --- linux-2.6.27.15/drivers/hwmon/fscpos.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/hwmon/fscpos.c 2009-02-10 20:32:13.000000000 +0100 @@ -240,7 +240,6 @@ static ssize_t set_pwm(struct i2c_client unsigned long v = simple_strtoul(buf, NULL, 10); /* Range: 0..255 */ - if (v < 0) v = 0; if (v > 255) v = 255; mutex_lock(&data->update_lock); diff -NurpP --minimal linux-2.6.27.15/drivers/hwmon/k8temp.c linux-2.6.27.15-g-v/drivers/hwmon/k8temp.c --- linux-2.6.27.15/drivers/hwmon/k8temp.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/hwmon/k8temp.c 2009-02-10 20:32:13.000000000 +0100 @@ -130,7 +130,7 @@ static DEVICE_ATTR(name, S_IRUGO, show_n static struct pci_device_id k8temp_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) }, - { 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, }; MODULE_DEVICE_TABLE(pci, k8temp_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/hwmon/sis5595.c linux-2.6.27.15-g-v/drivers/hwmon/sis5595.c --- linux-2.6.27.15/drivers/hwmon/sis5595.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/hwmon/sis5595.c 2009-02-10 20:32:13.000000000 +0100 @@ -698,7 +698,7 @@ static struct sis5595_data *sis5595_upda static struct pci_device_id sis5595_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, sis5595_pci_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/hwmon/via686a.c linux-2.6.27.15-g-v/drivers/hwmon/via686a.c --- linux-2.6.27.15/drivers/hwmon/via686a.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/hwmon/via686a.c 2009-02-10 20:32:13.000000000 +0100 @@ -768,7 +768,7 @@ static struct via686a_data *via686a_upda static struct pci_device_id via686a_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_82C686_4) }, - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, via686a_pci_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/hwmon/vt8231.c linux-2.6.27.15-g-v/drivers/hwmon/vt8231.c --- linux-2.6.27.15/drivers/hwmon/vt8231.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/hwmon/vt8231.c 2009-02-10 20:32:13.000000000 +0100 @@ -698,7 +698,7 @@ static struct platform_driver vt8231_dri static struct pci_device_id vt8231_pci_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_VIA, PCI_DEVICE_ID_VIA_8231_4) }, - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, vt8231_pci_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/hwmon/w83791d.c linux-2.6.27.15-g-v/drivers/hwmon/w83791d.c --- linux-2.6.27.15/drivers/hwmon/w83791d.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/hwmon/w83791d.c 2009-02-10 20:32:13.000000000 +0100 @@ -289,8 +289,8 @@ static int w83791d_detect(struct i2c_cli struct i2c_board_info *info); static int w83791d_remove(struct i2c_client *client); -static int w83791d_read(struct i2c_client *client, u8 register); -static int w83791d_write(struct i2c_client *client, u8 register, u8 value); +static int w83791d_read(struct i2c_client *client, u8 reg); +static int w83791d_write(struct i2c_client *client, u8 reg, u8 value); static struct w83791d_data *w83791d_update_device(struct device *dev); #ifdef DEBUG diff -NurpP --minimal linux-2.6.27.15/drivers/i2c/busses/i2c-i801.c linux-2.6.27.15-g-v/drivers/i2c/busses/i2c-i801.c --- linux-2.6.27.15/drivers/i2c/busses/i2c-i801.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/i2c/busses/i2c-i801.c 2009-02-10 20:32:13.000000000 +0100 @@ -576,7 +576,7 @@ static struct pci_device_id i801_ids[] = { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_TOLAPAI_1) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_4) }, { PCI_DEVICE(PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_ICH10_5) }, - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE (pci, i801_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/i2c/busses/i2c-piix4.c linux-2.6.27.15-g-v/drivers/i2c/busses/i2c-piix4.c --- linux-2.6.27.15/drivers/i2c/busses/i2c-piix4.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/i2c/busses/i2c-piix4.c 2009-02-10 20:32:13.000000000 +0100 @@ -123,7 +123,7 @@ static struct dmi_system_id __devinitdat .ident = "IBM", .matches = { DMI_MATCH(DMI_SYS_VENDOR, "IBM"), }, }, - { }, + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL }, }; static int __devinit piix4_setup(struct pci_dev *PIIX4_dev, @@ -424,7 +424,7 @@ static struct pci_device_id piix4_ids[] PCI_DEVICE_ID_SERVERWORKS_CSB6) }, { PCI_DEVICE(PCI_VENDOR_ID_SERVERWORKS, PCI_DEVICE_ID_SERVERWORKS_HT1000SB) }, - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE (pci, piix4_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/i2c/busses/i2c-sis630.c linux-2.6.27.15-g-v/drivers/i2c/busses/i2c-sis630.c --- linux-2.6.27.15/drivers/i2c/busses/i2c-sis630.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/i2c/busses/i2c-sis630.c 2009-02-10 20:32:13.000000000 +0100 @@ -472,7 +472,7 @@ static struct i2c_adapter sis630_adapter static struct pci_device_id sis630_ids[] __devinitdata = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_503) }, { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_LPC) }, - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE (pci, sis630_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/i2c/busses/i2c-sis96x.c linux-2.6.27.15-g-v/drivers/i2c/busses/i2c-sis96x.c --- linux-2.6.27.15/drivers/i2c/busses/i2c-sis96x.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/i2c/busses/i2c-sis96x.c 2009-02-10 20:32:13.000000000 +0100 @@ -248,7 +248,7 @@ static struct i2c_adapter sis96x_adapter static struct pci_device_id sis96x_ids[] = { { PCI_DEVICE(PCI_VENDOR_ID_SI, PCI_DEVICE_ID_SI_SMBUS) }, - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE (pci, sis96x_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/ieee1394/dv1394.c linux-2.6.27.15-g-v/drivers/ieee1394/dv1394.c --- linux-2.6.27.15/drivers/ieee1394/dv1394.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ieee1394/dv1394.c 2009-02-10 20:32:13.000000000 +0100 @@ -739,7 +739,7 @@ static void frame_prepare(struct video_c based upon DIF section and sequence */ -static void inline +static inline void frame_put_packet (struct frame *f, struct packet *p) { int section_type = p->data[0] >> 5; /* section type is in bits 5 - 7 */ @@ -918,7 +918,7 @@ static int do_dv1394_init(struct video_c /* default SYT offset is 3 cycles */ init->syt_offset = 3; - if ( (init->channel > 63) || (init->channel < 0) ) + if (init->channel > 63) init->channel = 63; chan_mask = (u64)1 << init->channel; @@ -2174,7 +2174,7 @@ static struct ieee1394_device_id dv1394_ .specifier_id = AVC_UNIT_SPEC_ID_ENTRY & 0xffffff, .version = AVC_SW_VERSION_ENTRY & 0xffffff }, - { } + { 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(ieee1394, dv1394_id_table); diff -NurpP --minimal linux-2.6.27.15/drivers/ieee1394/eth1394.c linux-2.6.27.15-g-v/drivers/ieee1394/eth1394.c --- linux-2.6.27.15/drivers/ieee1394/eth1394.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ieee1394/eth1394.c 2009-02-10 20:32:13.000000000 +0100 @@ -451,7 +451,7 @@ static struct ieee1394_device_id eth1394 .specifier_id = ETHER1394_GASP_SPECIFIER_ID, .version = ETHER1394_GASP_VERSION, }, - {} + { 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(ieee1394, eth1394_id_table); diff -NurpP --minimal linux-2.6.27.15/drivers/ieee1394/hosts.c linux-2.6.27.15-g-v/drivers/ieee1394/hosts.c --- linux-2.6.27.15/drivers/ieee1394/hosts.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ieee1394/hosts.c 2009-02-10 20:32:13.000000000 +0100 @@ -78,6 +78,7 @@ static int dummy_isoctl(struct hpsb_iso } static struct hpsb_host_driver dummy_driver = { + .name = "dummy", .transmit_packet = dummy_transmit_packet, .devctl = dummy_devctl, .isoctl = dummy_isoctl diff -NurpP --minimal linux-2.6.27.15/drivers/ieee1394/ohci1394.c linux-2.6.27.15-g-v/drivers/ieee1394/ohci1394.c --- linux-2.6.27.15/drivers/ieee1394/ohci1394.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ieee1394/ohci1394.c 2009-02-10 20:32:13.000000000 +0100 @@ -147,9 +147,9 @@ printk(level "%s: " fmt "\n" , OHCI1394_ printk(level "%s: fw-host%d: " fmt "\n" , OHCI1394_DRIVER_NAME, ohci->host->id , ## args) /* Module Parameters */ -static int phys_dma = 1; +static int phys_dma; module_param(phys_dma, int, 0444); -MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 1)."); +MODULE_PARM_DESC(phys_dma, "Enable physical DMA (default = 0)."); static void dma_trm_tasklet(unsigned long data); static void dma_trm_reset(struct dma_trm_ctx *d); @@ -3437,7 +3437,7 @@ static struct pci_device_id ohci1394_pci .subvendor = PCI_ANY_ID, .subdevice = PCI_ANY_ID, }, - { 0, }, + { 0, 0, 0, 0, 0, 0, 0 }, }; MODULE_DEVICE_TABLE(pci, ohci1394_pci_tbl); diff -NurpP --minimal linux-2.6.27.15/drivers/ieee1394/raw1394.c linux-2.6.27.15-g-v/drivers/ieee1394/raw1394.c --- linux-2.6.27.15/drivers/ieee1394/raw1394.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ieee1394/raw1394.c 2009-02-10 20:32:13.000000000 +0100 @@ -2968,7 +2968,7 @@ static struct ieee1394_device_id raw1394 .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff}, - {} + { 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(ieee1394, raw1394_id_table); diff -NurpP --minimal linux-2.6.27.15/drivers/ieee1394/sbp2.c linux-2.6.27.15-g-v/drivers/ieee1394/sbp2.c --- linux-2.6.27.15/drivers/ieee1394/sbp2.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ieee1394/sbp2.c 2009-02-10 20:32:13.000000000 +0100 @@ -290,7 +290,7 @@ static struct ieee1394_device_id sbp2_id .match_flags = IEEE1394_MATCH_SPECIFIER_ID | IEEE1394_MATCH_VERSION, .specifier_id = SBP2_UNIT_SPEC_ID_ENTRY & 0xffffff, .version = SBP2_SW_VERSION_ENTRY & 0xffffff}, - {} + { 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(ieee1394, sbp2_id_table); @@ -2135,7 +2135,7 @@ MODULE_DESCRIPTION("IEEE-1394 SBP-2 prot MODULE_SUPPORTED_DEVICE(SBP2_DEVICE_NAME); MODULE_LICENSE("GPL"); -static int sbp2_module_init(void) +static int __init sbp2_module_init(void) { int ret; diff -NurpP --minimal linux-2.6.27.15/drivers/ieee1394/video1394.c linux-2.6.27.15-g-v/drivers/ieee1394/video1394.c --- linux-2.6.27.15/drivers/ieee1394/video1394.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/ieee1394/video1394.c 2009-02-10 20:32:13.000000000 +0100 @@ -893,7 +893,7 @@ static long video1394_ioctl(struct file if (unlikely(d == NULL)) return -EFAULT; - if (unlikely((v.buffer<0) || (v.buffer>=d->num_desc - 1))) { + if (unlikely(v.buffer>=d->num_desc - 1)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -959,7 +959,7 @@ static long video1394_ioctl(struct file if (unlikely(d == NULL)) return -EFAULT; - if (unlikely((v.buffer<0) || (v.buffer>d->num_desc - 1))) { + if (unlikely(v.buffer>d->num_desc - 1)) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -1030,7 +1030,7 @@ static long video1394_ioctl(struct file d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if (d == NULL) return -EFAULT; - if ((v.buffer<0) || (v.buffer>=d->num_desc - 1)) { + if (v.buffer>=d->num_desc - 1) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -1137,7 +1137,7 @@ static long video1394_ioctl(struct file d = find_ctx(&ctx->context_list, OHCI_ISO_TRANSMIT, v.channel); if (d == NULL) return -EFAULT; - if ((v.buffer<0) || (v.buffer>=d->num_desc-1)) { + if (v.buffer>=d->num_desc-1) { PRINT(KERN_ERR, ohci->host->id, "Buffer %d out of range",v.buffer); return -EINVAL; @@ -1310,7 +1310,7 @@ static struct ieee1394_device_id video13 .specifier_id = CAMERA_UNIT_SPEC_ID_ENTRY & 0xffffff, .version = (CAMERA_SW_VERSION_ENTRY + 2) & 0xffffff }, - { } + { 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(ieee1394, video1394_id_table); diff -NurpP --minimal linux-2.6.27.15/drivers/infiniband/hw/ipath/ipath_user_pages.c linux-2.6.27.15-g-v/drivers/infiniband/hw/ipath/ipath_user_pages.c --- linux-2.6.27.15/drivers/infiniband/hw/ipath/ipath_user_pages.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/infiniband/hw/ipath/ipath_user_pages.c 2009-02-10 20:32:13.000000000 +0100 @@ -33,6 +33,7 @@ #include #include +#include #include "ipath_kernel.h" @@ -61,7 +62,8 @@ static int __get_user_pages(unsigned lon lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; - if (num_pages > lock_limit) { + if (num_pages > lock_limit || + !vx_vmlocked_avail(current->mm, num_pages)) { ret = -ENOMEM; goto bail; } @@ -78,7 +80,7 @@ static int __get_user_pages(unsigned lon goto bail_release; } - current->mm->locked_vm += num_pages; + vx_vmlocked_add(current->mm, num_pages); ret = 0; goto bail; @@ -177,7 +179,7 @@ void ipath_release_user_pages(struct pag __ipath_release_user_pages(p, num_pages, 1); - current->mm->locked_vm -= num_pages; + vx_vmlocked_sub(current->mm, num_pages); up_write(¤t->mm->mmap_sem); } @@ -194,7 +196,7 @@ static void user_pages_account(struct wo container_of(_work, struct ipath_user_pages_work, work); down_write(&work->mm->mmap_sem); - work->mm->locked_vm -= work->num_pages; + vx_vmlocked_sub(work->mm, work->num_pages); up_write(&work->mm->mmap_sem); mmput(work->mm); kfree(work); diff -NurpP --minimal linux-2.6.27.15/drivers/input/keyboard/atkbd.c linux-2.6.27.15-g-v/drivers/input/keyboard/atkbd.c --- linux-2.6.27.15/drivers/input/keyboard/atkbd.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/input/keyboard/atkbd.c 2009-02-10 20:32:13.000000000 +0100 @@ -1164,7 +1164,7 @@ static struct serio_device_id atkbd_seri .id = SERIO_ANY, .extra = SERIO_ANY, }, - { 0 } + { 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(serio, atkbd_serio_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/input/mouse/lifebook.c linux-2.6.27.15-g-v/drivers/input/mouse/lifebook.c --- linux-2.6.27.15/drivers/input/mouse/lifebook.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/input/mouse/lifebook.c 2009-02-10 20:32:13.000000000 +0100 @@ -110,7 +110,7 @@ static const struct dmi_system_id lifebo DMI_MATCH(DMI_PRODUCT_NAME, "LifeBook B142"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL} }; static psmouse_ret_t lifebook_process_byte(struct psmouse *psmouse) diff -NurpP --minimal linux-2.6.27.15/drivers/input/mouse/psmouse-base.c linux-2.6.27.15-g-v/drivers/input/mouse/psmouse-base.c --- linux-2.6.27.15/drivers/input/mouse/psmouse-base.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/input/mouse/psmouse-base.c 2009-02-10 20:32:13.000000000 +0100 @@ -1328,7 +1328,7 @@ static struct serio_device_id psmouse_se .id = SERIO_ANY, .extra = SERIO_ANY, }, - { 0 } + { 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(serio, psmouse_serio_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/input/mouse/synaptics.c linux-2.6.27.15-g-v/drivers/input/mouse/synaptics.c --- linux-2.6.27.15/drivers/input/mouse/synaptics.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/input/mouse/synaptics.c 2009-02-10 20:32:13.000000000 +0100 @@ -417,7 +417,7 @@ static void synaptics_process_packet(str break; case 2: if (SYN_MODEL_PEN(priv->model_id)) - ; /* Nothing, treat a pen as a single finger */ + break; /* Nothing, treat a pen as a single finger */ break; case 4 ... 15: if (SYN_CAP_PALMDETECT(priv->capabilities)) @@ -624,7 +624,7 @@ static const struct dmi_system_id toshib DMI_MATCH(DMI_PRODUCT_NAME, "PORTEGE M300"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; #endif diff -NurpP --minimal linux-2.6.27.15/drivers/input/mousedev.c linux-2.6.27.15-g-v/drivers/input/mousedev.c --- linux-2.6.27.15/drivers/input/mousedev.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/input/mousedev.c 2009-02-10 20:32:13.000000000 +0100 @@ -1064,7 +1064,7 @@ static struct input_handler mousedev_han #ifdef CONFIG_INPUT_MOUSEDEV_PSAUX static struct miscdevice psaux_mouse = { - PSMOUSE_MINOR, "psaux", &mousedev_fops + PSMOUSE_MINOR, "psaux", &mousedev_fops, {NULL, NULL}, NULL, NULL }; static int psaux_registered; #endif diff -NurpP --minimal linux-2.6.27.15/drivers/input/serio/i8042-x86ia64io.h linux-2.6.27.15-g-v/drivers/input/serio/i8042-x86ia64io.h --- linux-2.6.27.15/drivers/input/serio/i8042-x86ia64io.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/input/serio/i8042-x86ia64io.h 2009-02-10 20:32:13.000000000 +0100 @@ -143,7 +143,7 @@ static struct dmi_system_id __initdata i DMI_MATCH(DMI_PRODUCT_VERSION, "M606"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; /* @@ -351,7 +351,7 @@ static struct dmi_system_id __initdata i DMI_MATCH(DMI_PRODUCT_NAME, "HEL80I"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; #ifdef CONFIG_PNP @@ -363,7 +363,7 @@ static struct dmi_system_id __initdata i DMI_MATCH(DMI_BOARD_VENDOR, "Intel Corporation"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; #endif @@ -430,7 +430,7 @@ static struct dmi_system_id __initdata i DMI_MATCH(DMI_PRODUCT_NAME, "TravelMate 4280"), }, }, - { } + { NULL, NULL, {DMI_MATCH(DMI_NONE, NULL)}, NULL } }; #endif /* CONFIG_X86 */ diff -NurpP --minimal linux-2.6.27.15/drivers/input/serio/serio_raw.c linux-2.6.27.15-g-v/drivers/input/serio/serio_raw.c --- linux-2.6.27.15/drivers/input/serio/serio_raw.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/input/serio/serio_raw.c 2009-02-10 20:32:13.000000000 +0100 @@ -373,7 +373,7 @@ static struct serio_device_id serio_raw_ .id = SERIO_ANY, .extra = SERIO_ANY, }, - { 0 } + { 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(serio, serio_raw_serio_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/md/bitmap.c linux-2.6.27.15-g-v/drivers/md/bitmap.c --- linux-2.6.27.15/drivers/md/bitmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/md/bitmap.c 2009-02-10 20:32:13.000000000 +0100 @@ -57,7 +57,7 @@ # if DEBUG > 0 # define PRINTK(x...) printk(KERN_DEBUG x) # else -# define PRINTK(x...) +# define PRINTK(x...) do {} while (0) # endif #endif diff -NurpP --minimal linux-2.6.27.15/drivers/md/dm.c linux-2.6.27.15-g-v/drivers/md/dm.c --- linux-2.6.27.15/drivers/md/dm.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/md/dm.c 2009-02-10 20:32:13.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #define DM_MSG_PREFIX "core" @@ -91,6 +92,7 @@ struct mapped_device { rwlock_t map_lock; atomic_t holders; atomic_t open_count; + xid_t xid; unsigned long flags; @@ -252,6 +254,7 @@ static void __exit dm_exit(void) static int dm_blk_open(struct inode *inode, struct file *file) { struct mapped_device *md; + int ret = -ENXIO; spin_lock(&_minor_lock); @@ -260,18 +263,19 @@ static int dm_blk_open(struct inode *ino goto out; if (test_bit(DMF_FREEING, &md->flags) || - test_bit(DMF_DELETING, &md->flags)) { - md = NULL; + test_bit(DMF_DELETING, &md->flags)) + goto out; + + ret = -EACCES; + if (!vx_check(md->xid, VS_IDENT|VS_HOSTID)) goto out; - } dm_get(md); atomic_inc(&md->open_count); - + ret = 0; out: spin_unlock(&_minor_lock); - - return md ? 0 : -ENXIO; + return ret; } static int dm_blk_close(struct inode *inode, struct file *file) @@ -467,6 +471,14 @@ int dm_set_geometry(struct mapped_device return 0; } +/* + * Get the xid associated with a dm device + */ +xid_t dm_get_xid(struct mapped_device *md) +{ + return md->xid; +} + /*----------------------------------------------------------------- * CRUD START: * A more elegant soln is in the works that uses the queue @@ -1069,6 +1081,7 @@ static struct mapped_device *alloc_dev(i INIT_LIST_HEAD(&md->uevent_list); spin_lock_init(&md->uevent_lock); + md->xid = vx_current_xid(); md->queue = blk_alloc_queue(GFP_KERNEL); if (!md->queue) goto bad_queue; diff -NurpP --minimal linux-2.6.27.15/drivers/md/dm.h linux-2.6.27.15-g-v/drivers/md/dm.h --- linux-2.6.27.15/drivers/md/dm.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/md/dm.h 2009-02-10 20:32:13.000000000 +0100 @@ -66,6 +66,8 @@ void dm_put_target_type(struct target_ty int dm_target_iterate(void (*iter_func)(struct target_type *tt, void *param), void *param); +xid_t dm_get_xid(struct mapped_device *md); + /*----------------------------------------------------------------- * Useful inlines. *---------------------------------------------------------------*/ diff -NurpP --minimal linux-2.6.27.15/drivers/md/dm-ioctl.c linux-2.6.27.15-g-v/drivers/md/dm-ioctl.c --- linux-2.6.27.15/drivers/md/dm-ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/md/dm-ioctl.c 2009-02-10 20:32:13.000000000 +0100 @@ -16,6 +16,7 @@ #include #include #include +#include #include @@ -101,7 +102,8 @@ static struct hash_cell *__get_name_cell unsigned int h = hash_str(str); list_for_each_entry (hc, _name_buckets + h, name_list) - if (!strcmp(hc->name, str)) { + if (vx_check(dm_get_xid(hc->md), VS_WATCH_P | VS_IDENT) && + !strcmp(hc->name, str)) { dm_get(hc->md); return hc; } @@ -115,7 +117,8 @@ static struct hash_cell *__get_uuid_cell unsigned int h = hash_str(str); list_for_each_entry (hc, _uuid_buckets + h, uuid_list) - if (!strcmp(hc->uuid, str)) { + if (vx_check(dm_get_xid(hc->md), VS_WATCH_P | VS_IDENT) && + !strcmp(hc->uuid, str)) { dm_get(hc->md); return hc; } @@ -352,6 +355,9 @@ typedef int (*ioctl_fn)(struct dm_ioctl static int remove_all(struct dm_ioctl *param, size_t param_size) { + if (!vx_check(0, VS_ADMIN)) + return -EPERM; + dm_hash_remove_all(1); param->data_size = 0; return 0; @@ -399,6 +405,8 @@ static int list_devices(struct dm_ioctl */ for (i = 0; i < NUM_BUCKETS; i++) { list_for_each_entry (hc, _name_buckets + i, name_list) { + if (!vx_check(dm_get_xid(hc->md), VS_WATCH_P | VS_IDENT)) + continue; needed += sizeof(struct dm_name_list); needed += strlen(hc->name) + 1; needed += ALIGN_MASK; @@ -422,6 +430,8 @@ static int list_devices(struct dm_ioctl */ for (i = 0; i < NUM_BUCKETS; i++) { list_for_each_entry (hc, _name_buckets + i, name_list) { + if (!vx_check(dm_get_xid(hc->md), VS_WATCH_P | VS_IDENT)) + continue; if (old_nl) old_nl->next = (uint32_t) ((void *) nl - (void *) old_nl); @@ -612,10 +622,11 @@ static struct hash_cell *__find_device_h if (!md) goto out; - mdptr = dm_get_mdptr(md); + if (vx_check(dm_get_xid(md), VS_WATCH_P | VS_IDENT)) + mdptr = dm_get_mdptr(md); + if (!mdptr) dm_put(md); - out: return mdptr; } @@ -1406,8 +1417,8 @@ static int ctl_ioctl(uint command, struc ioctl_fn fn = NULL; size_t param_size; - /* only root can play with this */ - if (!capable(CAP_SYS_ADMIN)) + /* only root and certain contexts can play with this */ + if (!vx_capable(CAP_SYS_ADMIN, VXC_ADMIN_MAPPER)) return -EACCES; if (_IOC_TYPE(command) != DM_IOCTL) diff -NurpP --minimal linux-2.6.27.15/drivers/mtd/devices/doc2000.c linux-2.6.27.15-g-v/drivers/mtd/devices/doc2000.c --- linux-2.6.27.15/drivers/mtd/devices/doc2000.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/mtd/devices/doc2000.c 2009-02-10 20:32:13.000000000 +0100 @@ -777,7 +777,7 @@ static int doc_write(struct mtd_info *mt /* The ECC will not be calculated correctly if less than 512 is written */ /* DBB- - if (len != 0x200 && eccbuf) + if (len != 0x200) printk(KERN_WARNING "ECC needs a full sector write (adr: %lx size %lx)\n", (long) to, (long) len); diff -NurpP --minimal linux-2.6.27.15/drivers/mtd/devices/doc2001.c linux-2.6.27.15-g-v/drivers/mtd/devices/doc2001.c --- linux-2.6.27.15/drivers/mtd/devices/doc2001.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/mtd/devices/doc2001.c 2009-02-10 20:32:13.000000000 +0100 @@ -396,6 +396,8 @@ static int doc_read (struct mtd_info *mt /* Don't allow read past end of device */ if (from >= this->totlen) return -EINVAL; + if (!len) + return -EINVAL; /* Don't allow a single read to cross a 512-byte block boundary */ if (from + len > ((from | 0x1ff) + 1)) diff -NurpP --minimal linux-2.6.27.15/drivers/mtd/devices/slram.c linux-2.6.27.15-g-v/drivers/mtd/devices/slram.c --- linux-2.6.27.15/drivers/mtd/devices/slram.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/mtd/devices/slram.c 2009-02-10 20:32:13.000000000 +0100 @@ -273,7 +273,7 @@ static int parse_cmdline(char *devname, } T("slram: devname=%s, devstart=0x%lx, devlength=0x%lx\n", devname, devstart, devlength); - if ((devstart < 0) || (devlength < 0) || (devlength % SLRAM_BLK_SZ != 0)) { + if (devlength % SLRAM_BLK_SZ != 0) { E("slram: Illegal start / length parameter.\n"); return(-EINVAL); } diff -NurpP --minimal linux-2.6.27.15/drivers/mtd/ubi/build.c linux-2.6.27.15-g-v/drivers/mtd/ubi/build.c --- linux-2.6.27.15/drivers/mtd/ubi/build.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/mtd/ubi/build.c 2009-02-10 20:32:13.000000000 +0100 @@ -1104,7 +1104,7 @@ static int __init bytes_str_to_int(const unsigned long result; result = simple_strtoul(str, &endp, 0); - if (str == endp || result < 0) { + if (str == endp) { printk(KERN_ERR "UBI error: incorrect bytes count: \"%s\"\n", str); return -EINVAL; diff -NurpP --minimal linux-2.6.27.15/drivers/net/eepro100.c linux-2.6.27.15-g-v/drivers/net/eepro100.c --- linux-2.6.27.15/drivers/net/eepro100.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/net/eepro100.c 2009-02-10 20:32:13.000000000 +0100 @@ -47,7 +47,7 @@ static int rxdmacount /* = 0 */; # define rx_align(skb) skb_reserve((skb), 2) # define RxFD_ALIGNMENT __attribute__ ((aligned (2), packed)) #else -# define rx_align(skb) +# define rx_align(skb) do {} while (0) # define RxFD_ALIGNMENT #endif @@ -2334,33 +2334,33 @@ static void __devexit eepro100_remove_on } static struct pci_device_id eepro100_pci_tbl[] = { - { PCI_VENDOR_ID_INTEL, 0x1229, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1209, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1029, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1030, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1031, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1032, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1033, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1034, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1035, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1036, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1037, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1038, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1039, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103A, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103B, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103C, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103D, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x103E, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1050, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1059, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x1227, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x2449, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x2459, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x245D, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x5200, PCI_ANY_ID, PCI_ANY_ID, }, - { PCI_VENDOR_ID_INTEL, 0x5201, PCI_ANY_ID, PCI_ANY_ID, }, - { 0,} + { PCI_VENDOR_ID_INTEL, 0x1229, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1209, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1029, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1030, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1031, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1032, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1033, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1034, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1035, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1036, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1037, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1038, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1039, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x103A, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x103B, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x103C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x103D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x103E, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1050, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1059, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x1227, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x2449, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x2459, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x245D, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x5200, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { PCI_VENDOR_ID_INTEL, 0x5201, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0 }, + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, eepro100_pci_tbl); diff -NurpP --minimal linux-2.6.27.15/drivers/net/irda/vlsi_ir.c linux-2.6.27.15-g-v/drivers/net/irda/vlsi_ir.c --- linux-2.6.27.15/drivers/net/irda/vlsi_ir.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/net/irda/vlsi_ir.c 2009-02-10 20:32:13.000000000 +0100 @@ -906,13 +906,12 @@ static int vlsi_hard_start_xmit(struct s /* no race - tx-ring already empty */ vlsi_set_baud(idev, iobase); netif_wake_queue(ndev); - } - else - ; + } else { /* keep the speed change pending like it would * for any len>0 packet. tx completion interrupt * will apply it when the tx ring becomes empty. */ + } spin_unlock_irqrestore(&idev->lock, flags); dev_kfree_skb_any(skb); return 0; diff -NurpP --minimal linux-2.6.27.15/drivers/net/pcnet32.c linux-2.6.27.15-g-v/drivers/net/pcnet32.c --- linux-2.6.27.15/drivers/net/pcnet32.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/net/pcnet32.c 2009-02-10 20:32:13.000000000 +0100 @@ -78,7 +78,7 @@ static int cards_found; /* * VLB I/O addresses */ -static unsigned int pcnet32_portlist[] __initdata = +static unsigned int pcnet32_portlist[] __devinitdata = { 0x300, 0x320, 0x340, 0x360, 0 }; static int pcnet32_debug = 0; diff -NurpP --minimal linux-2.6.27.15/drivers/net/tg3.h linux-2.6.27.15-g-v/drivers/net/tg3.h --- linux-2.6.27.15/drivers/net/tg3.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/net/tg3.h 2009-02-10 20:32:13.000000000 +0100 @@ -102,6 +102,7 @@ #define CHIPREV_ID_5750_A0 0x4000 #define CHIPREV_ID_5750_A1 0x4001 #define CHIPREV_ID_5750_A3 0x4003 +#define CHIPREV_ID_5750_C1 0x4201 #define CHIPREV_ID_5750_C2 0x4202 #define CHIPREV_ID_5752_A0_HW 0x5000 #define CHIPREV_ID_5752_A0 0x6000 diff -NurpP --minimal linux-2.6.27.15/drivers/net/tun.c linux-2.6.27.15-g-v/drivers/net/tun.c --- linux-2.6.27.15/drivers/net/tun.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/net/tun.c 2009-02-10 20:32:13.000000000 +0100 @@ -61,6 +61,7 @@ #include #include #include +#include #include #include @@ -93,6 +94,7 @@ struct tun_struct { int attached; uid_t owner; gid_t group; + nid_t nid; wait_queue_head_t read_wait; struct sk_buff_head readq; @@ -675,6 +677,7 @@ static void tun_setup(struct net_device tun->owner = -1; tun->group = -1; + tun->nid = current->nid; dev->open = tun_net_open; dev->hard_start_xmit = tun_net_xmit; @@ -707,6 +710,9 @@ static int tun_set_iff(struct net *net, tn = net_generic(net, tun_net_id); tun = tun_get_by_name(tn, ifr->ifr_name); if (tun) { + if (!nx_check(tun->nid, VS_IDENT | VS_HOSTID | VS_ADMIN_P)) + return -EPERM; + if (tun->attached) return -EBUSY; @@ -715,7 +721,7 @@ static int tun_set_iff(struct net *net, current->euid != tun->owner) || (tun->group != -1 && current->egid != tun->group)) && - !capable(CAP_NET_ADMIN)) + !cap_raised(current->cap_effective, CAP_NET_ADMIN)) return -EPERM; } else if (__dev_get_by_name(net, ifr->ifr_name)) @@ -726,7 +732,7 @@ static int tun_set_iff(struct net *net, err = -EINVAL; - if (!capable(CAP_NET_ADMIN)) + if (!nx_capable(CAP_NET_ADMIN, NXC_TUN_CREATE)) return -EPERM; /* Set dev type */ @@ -966,6 +972,16 @@ static int tun_chr_ioctl(struct inode *i DBG(KERN_INFO "%s: group set to %d\n", tun->dev->name, tun->group); break; + case TUNSETNID: + if (!capable(CAP_CONTEXT)) + return -EPERM; + + /* Set nid owner of the device */ + tun->nid = (nid_t) arg; + + DBG(KERN_INFO "%s: nid owner set to %u\n", tun->dev->name, tun->nid); + break; + case TUNSETLINK: /* Only allow setting the type when the interface is down */ rtnl_lock(); diff -NurpP --minimal linux-2.6.27.15/drivers/net/wireless/iwlwifi/iwl3945-base.c linux-2.6.27.15-g-v/drivers/net/wireless/iwlwifi/iwl3945-base.c --- linux-2.6.27.15/drivers/net/wireless/iwlwifi/iwl3945-base.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/net/wireless/iwlwifi/iwl3945-base.c 2009-02-10 20:32:13.000000000 +0100 @@ -785,7 +785,7 @@ static int iwl3945_send_cmd_sync(struct IWL_ERROR("Error: Response NULL in '%s'\n", get_cmd_string(cmd->id)); ret = -EIO; - goto out; + goto cancel; } ret = 0; diff -NurpP --minimal linux-2.6.27.15/drivers/pci/hotplug/cpqphp_nvram.c linux-2.6.27.15-g-v/drivers/pci/hotplug/cpqphp_nvram.c --- linux-2.6.27.15/drivers/pci/hotplug/cpqphp_nvram.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pci/hotplug/cpqphp_nvram.c 2009-02-10 20:32:13.000000000 +0100 @@ -425,9 +425,13 @@ static u32 store_HRT (void __iomem *rom_ void compaq_nvram_init (void __iomem *rom_start) { + +#ifndef CONFIG_PAX_KERNEXEC if (rom_start) { compaq_int15_entry_point = (rom_start + ROM_INT15_PHY_ADDR - ROM_PHY_ADDR); } +#endif + dbg("int15 entry = %p\n", compaq_int15_entry_point); /* initialize our int15 lock */ diff -NurpP --minimal linux-2.6.27.15/drivers/pci/pcie/aer/aerdrv.c linux-2.6.27.15-g-v/drivers/pci/pcie/aer/aerdrv.c --- linux-2.6.27.15/drivers/pci/pcie/aer/aerdrv.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pci/pcie/aer/aerdrv.c 2009-02-10 20:32:13.000000000 +0100 @@ -59,7 +59,7 @@ static struct pcie_port_service_id aer_i .port_type = PCIE_RC_PORT, .service_type = PCIE_PORT_SERVICE_AER, }, - { /* end: all zeroes */ } + { 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; static struct pci_error_handlers aer_error_handlers = { diff -NurpP --minimal linux-2.6.27.15/drivers/pci/pcie/aer/aerdrv_core.c linux-2.6.27.15-g-v/drivers/pci/pcie/aer/aerdrv_core.c --- linux-2.6.27.15/drivers/pci/pcie/aer/aerdrv_core.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pci/pcie/aer/aerdrv_core.c 2009-02-10 20:32:13.000000000 +0100 @@ -663,7 +663,7 @@ static void aer_isr_one_error(struct pci struct aer_err_source *e_src) { struct device *s_device; - struct aer_err_info e_info = {0, 0, 0,}; + struct aer_err_info e_info = {0, 0, 0, {0, 0, 0, 0}}; int i; u16 id; diff -NurpP --minimal linux-2.6.27.15/drivers/pci/pcie/portdrv_pci.c linux-2.6.27.15-g-v/drivers/pci/pcie/portdrv_pci.c --- linux-2.6.27.15/drivers/pci/pcie/portdrv_pci.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pci/pcie/portdrv_pci.c 2009-02-10 20:32:13.000000000 +0100 @@ -273,7 +273,7 @@ static void pcie_portdrv_err_resume(stru static const struct pci_device_id port_pci_ids[] = { { /* handle any PCI-Express port */ PCI_DEVICE_CLASS(((PCI_CLASS_BRIDGE_PCI << 8) | 0x00), ~0), - }, { /* end: all zeroes */ } + }, { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, port_pci_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/pci/proc.c linux-2.6.27.15-g-v/drivers/pci/proc.c --- linux-2.6.27.15/drivers/pci/proc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pci/proc.c 2009-02-10 20:32:13.000000000 +0100 @@ -470,7 +470,16 @@ static const struct file_operations proc static int __init pci_proc_init(void) { struct pci_dev *dev = NULL; + +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + proc_bus_pci_dir = proc_mkdir_mode("bus/pci", S_IRUSR | S_IXUSR, NULL); +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + proc_bus_pci_dir = proc_mkdir_mode("bus/pci", S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP, NULL); +#endif +#else proc_bus_pci_dir = proc_mkdir("bus/pci", NULL); +#endif proc_create("devices", 0, proc_bus_pci_dir, &proc_bus_pci_dev_operations); proc_initialized = 1; diff -NurpP --minimal linux-2.6.27.15/drivers/pcmcia/ti113x.h linux-2.6.27.15-g-v/drivers/pcmcia/ti113x.h --- linux-2.6.27.15/drivers/pcmcia/ti113x.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pcmcia/ti113x.h 2009-02-10 20:32:13.000000000 +0100 @@ -897,7 +897,7 @@ static struct pci_device_id ene_tune_tbl DEVID(PCI_VENDOR_ID_MOTOROLA, 0x3410, 0xECC0, PCI_ANY_ID, ENE_TEST_C9_TLTENABLE | ENE_TEST_C9_PFENABLE, ENE_TEST_C9_TLTENABLE), - {} + { 0, 0, 0, 0, 0, 0, 0 } }; static void ene_tune_bridge(struct pcmcia_socket *sock, struct pci_bus *bus) diff -NurpP --minimal linux-2.6.27.15/drivers/pcmcia/yenta_socket.c linux-2.6.27.15-g-v/drivers/pcmcia/yenta_socket.c --- linux-2.6.27.15/drivers/pcmcia/yenta_socket.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pcmcia/yenta_socket.c 2009-02-10 20:32:13.000000000 +0100 @@ -1358,7 +1358,7 @@ static struct pci_device_id yenta_table /* match any cardbus bridge */ CB_ID(PCI_ANY_ID, PCI_ANY_ID, DEFAULT), - { /* all zeroes */ } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, yenta_table); diff -NurpP --minimal linux-2.6.27.15/drivers/pnp/pnpbios/bioscalls.c linux-2.6.27.15-g-v/drivers/pnp/pnpbios/bioscalls.c --- linux-2.6.27.15/drivers/pnp/pnpbios/bioscalls.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pnp/pnpbios/bioscalls.c 2009-02-10 20:32:13.000000000 +0100 @@ -60,7 +60,7 @@ set_base(gdt[(selname) >> 3], (u32)(addr set_limit(gdt[(selname) >> 3], size); \ } while(0) -static struct desc_struct bad_bios_desc; +static struct desc_struct bad_bios_desc __read_only; /* * At some point we want to use this stack frame pointer to unwind @@ -87,6 +87,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. @@ -96,8 +100,17 @@ static inline u16 call_pnp_bios(u16 func cpu = get_cpu(); save_desc_40 = get_cpu_gdt_table(cpu)[0x40 / 8]; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + get_cpu_gdt_table(cpu)[0x40 / 8] = bad_bios_desc; +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* On some boxes IRQ's during PnP BIOS calls are deadly. */ spin_lock_irqsave(&pnp_bios_lock, flags); @@ -134,7 +147,16 @@ static inline u16 call_pnp_bios(u16 func :"memory"); spin_unlock_irqrestore(&pnp_bios_lock, flags); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + get_cpu_gdt_table(cpu)[0x40 / 8] = save_desc_40; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + put_cpu(); /* If we get here and this is set then the PnP BIOS faulted on us. */ @@ -468,16 +490,24 @@ int pnp_bios_read_escd(char *data, u32 n return status; } -void pnpbios_calls_init(union pnp_bios_install_struct *header) +void __init pnpbios_calls_init(union pnp_bios_install_struct *header) { int i; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + spin_lock_init(&pnp_bios_lock); pnp_bios_callpoint.offset = header->fields.pm16offset; pnp_bios_callpoint.segment = PNP_CS16; +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + bad_bios_desc.a = 0; - bad_bios_desc.b = 0x00409200; + bad_bios_desc.b = 0x00409300; set_base(bad_bios_desc, __va((unsigned long)0x40 << 4)); _set_limit((char *)&bad_bios_desc, 4095 - (0x40 << 4)); @@ -491,4 +521,9 @@ void pnpbios_calls_init(union pnp_bios_i set_base(gdt[GDT_ENTRY_PNPBIOS_DS], __va(header->fields.pm16dseg)); } + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } diff -NurpP --minimal linux-2.6.27.15/drivers/pnp/quirks.c linux-2.6.27.15-g-v/drivers/pnp/quirks.c --- linux-2.6.27.15/drivers/pnp/quirks.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pnp/quirks.c 2009-02-10 20:32:13.000000000 +0100 @@ -327,7 +327,7 @@ static struct pnp_fixup pnp_fixups[] = { /* PnP resources that might overlap PCI BARs */ {"PNP0c01", quirk_system_pci_resources}, {"PNP0c02", quirk_system_pci_resources}, - {""} + {"", NULL} }; void pnp_fixup_device(struct pnp_dev *dev) diff -NurpP --minimal linux-2.6.27.15/drivers/pnp/resource.c linux-2.6.27.15-g-v/drivers/pnp/resource.c --- linux-2.6.27.15/drivers/pnp/resource.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/pnp/resource.c 2009-02-10 20:32:13.000000000 +0100 @@ -355,7 +355,7 @@ int pnp_check_irq(struct pnp_dev *dev, s return 1; /* check if the resource is valid */ - if (*irq < 0 || *irq > 15) + if (*irq > 15) return 0; /* check if the resource is reserved */ @@ -419,7 +419,7 @@ int pnp_check_dma(struct pnp_dev *dev, s return 1; /* check if the resource is valid */ - if (*dma < 0 || *dma == 4 || *dma > 7) + if (*dma == 4 || *dma > 7) return 0; /* check if the resource is reserved */ diff -NurpP --minimal linux-2.6.27.15/drivers/scsi/scsi_logging.h linux-2.6.27.15-g-v/drivers/scsi/scsi_logging.h --- linux-2.6.27.15/drivers/scsi/scsi_logging.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/scsi/scsi_logging.h 2009-02-10 20:32:13.000000000 +0100 @@ -51,7 +51,7 @@ do { \ } while (0); \ } while (0) #else -#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD) +#define SCSI_CHECK_LOGGING(SHIFT, BITS, LEVEL, CMD) do {} while (0) #endif /* CONFIG_SCSI_LOGGING */ /* diff -NurpP --minimal linux-2.6.27.15/drivers/serial/8250_pci.c linux-2.6.27.15-g-v/drivers/serial/8250_pci.c --- linux-2.6.27.15/drivers/serial/8250_pci.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/serial/8250_pci.c 2009-02-10 20:32:13.000000000 +0100 @@ -2862,7 +2862,7 @@ static struct pci_device_id serial_pci_t PCI_ANY_ID, PCI_ANY_ID, PCI_CLASS_COMMUNICATION_MULTISERIAL << 8, 0xffff00, pbn_default }, - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; static struct pci_driver serial_pci_driver = { diff -NurpP --minimal linux-2.6.27.15/drivers/usb/class/cdc-acm.c linux-2.6.27.15-g-v/drivers/usb/class/cdc-acm.c --- linux-2.6.27.15/drivers/usb/class/cdc-acm.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/usb/class/cdc-acm.c 2009-02-10 20:32:14.000000000 +0100 @@ -1381,7 +1381,7 @@ static struct usb_device_id acm_ids[] = USB_CDC_ACM_PROTO_AT_CDMA) }, /* NOTE: COMM/ACM/0xff is likely MSFT RNDIS ... NOT a modem!! */ - { } + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE (usb, acm_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/usb/class/usblp.c linux-2.6.27.15-g-v/drivers/usb/class/usblp.c --- linux-2.6.27.15/drivers/usb/class/usblp.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/usb/class/usblp.c 2009-02-10 20:32:14.000000000 +0100 @@ -227,7 +227,7 @@ static const struct quirk_printer_struct { 0x0409, 0xf1be, USBLP_QUIRK_BIDIR }, /* NEC Picty800 (HP OEM) */ { 0x0482, 0x0010, USBLP_QUIRK_BIDIR }, /* Kyocera Mita FS 820, by zut */ { 0x04b8, 0x0202, USBLP_QUIRK_BAD_CLASS }, /* Seiko Epson Receipt Printer M129C */ - { 0, 0 } + { 0, 0, 0 } }; static int usblp_wwait(struct usblp *usblp, int nonblock); @@ -1401,7 +1401,7 @@ static struct usb_device_id usblp_ids [] { USB_INTERFACE_INFO(7, 1, 2) }, { USB_INTERFACE_INFO(7, 1, 3) }, { USB_DEVICE(0x04b8, 0x0202) }, /* Seiko Epson Receipt Printer M129C */ - { } /* Terminating entry */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, usblp_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/usb/core/hub.c linux-2.6.27.15-g-v/drivers/usb/core/hub.c --- linux-2.6.27.15/drivers/usb/core/hub.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/usb/core/hub.c 2009-02-10 20:32:14.000000000 +0100 @@ -3111,7 +3111,7 @@ static struct usb_device_id hub_id_table .bDeviceClass = USB_CLASS_HUB}, { .match_flags = USB_DEVICE_ID_MATCH_INT_CLASS, .bInterfaceClass = USB_CLASS_HUB}, - { } /* Terminating entry */ + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } /* Terminating entry */ }; MODULE_DEVICE_TABLE (usb, hub_id_table); diff -NurpP --minimal linux-2.6.27.15/drivers/usb/host/ehci-pci.c linux-2.6.27.15-g-v/drivers/usb/host/ehci-pci.c --- linux-2.6.27.15/drivers/usb/host/ehci-pci.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/usb/host/ehci-pci.c 2009-02-10 20:32:14.000000000 +0100 @@ -414,7 +414,7 @@ static const struct pci_device_id pci_id PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_EHCI, ~0), .driver_data = (unsigned long) &ehci_pci_hc_driver, }, - { /* end: all zeroes */ } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, pci_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/usb/host/uhci-hcd.c linux-2.6.27.15-g-v/drivers/usb/host/uhci-hcd.c --- linux-2.6.27.15/drivers/usb/host/uhci-hcd.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/usb/host/uhci-hcd.c 2009-02-10 20:32:14.000000000 +0100 @@ -928,7 +928,7 @@ static const struct pci_device_id uhci_p /* handle any USB UHCI controller */ PCI_DEVICE_CLASS(PCI_CLASS_SERIAL_USB_UHCI, ~0), .driver_data = (unsigned long) &uhci_driver, - }, { /* end: all zeroes */ } + }, { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, uhci_pci_ids); diff -NurpP --minimal linux-2.6.27.15/drivers/usb/storage/debug.h linux-2.6.27.15-g-v/drivers/usb/storage/debug.h --- linux-2.6.27.15/drivers/usb/storage/debug.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/usb/storage/debug.h 2009-02-10 20:32:14.000000000 +0100 @@ -54,9 +54,9 @@ void usb_stor_show_sense( unsigned char #define US_DEBUGPX(x...) printk( x ) #define US_DEBUG(x) x #else -#define US_DEBUGP(x...) -#define US_DEBUGPX(x...) -#define US_DEBUG(x) +#define US_DEBUGP(x...) do {} while (0) +#define US_DEBUGPX(x...) do {} while (0) +#define US_DEBUG(x) do {} while (0) #endif #endif diff -NurpP --minimal linux-2.6.27.15/drivers/usb/storage/usb.c linux-2.6.27.15-g-v/drivers/usb/storage/usb.c --- linux-2.6.27.15/drivers/usb/storage/usb.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/usb/storage/usb.c 2009-02-10 20:32:14.000000000 +0100 @@ -139,7 +139,7 @@ static struct usb_device_id storage_usb_ #undef COMPLIANT_DEV #undef USUAL_DEV /* Terminating entry */ - { } + { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE (usb, storage_usb_ids); @@ -182,7 +182,7 @@ static struct us_unusual_dev us_unusual_ # undef USUAL_DEV /* Terminating entry */ - { NULL } + { NULL, NULL, 0, 0, NULL } }; diff -NurpP --minimal linux-2.6.27.15/drivers/video/fbcmap.c linux-2.6.27.15-g-v/drivers/video/fbcmap.c --- linux-2.6.27.15/drivers/video/fbcmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/video/fbcmap.c 2009-02-10 20:32:14.000000000 +0100 @@ -250,8 +250,7 @@ int fb_set_user_cmap(struct fb_cmap_user int rc, size = cmap->len * sizeof(u16); struct fb_cmap umap; - if (cmap->start < 0 || (!info->fbops->fb_setcolreg && - !info->fbops->fb_setcmap)) + if (!info->fbops->fb_setcolreg && !info->fbops->fb_setcmap) return -EINVAL; memset(&umap, 0, sizeof(struct fb_cmap)); diff -NurpP --minimal linux-2.6.27.15/drivers/video/fbmem.c linux-2.6.27.15-g-v/drivers/video/fbmem.c --- linux-2.6.27.15/drivers/video/fbmem.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/video/fbmem.c 2009-02-10 20:32:14.000000000 +0100 @@ -395,7 +395,7 @@ static void fb_do_show_logo(struct fb_in image->dx += image->width + 8; } } else if (rotate == FB_ROTATE_UD) { - for (x = 0; x < num && image->dx >= 0; x++) { + for (x = 0; x < num && (__s32)image->dx >= 0; x++) { info->fbops->fb_imageblit(info, image); image->dx -= image->width + 8; } @@ -407,7 +407,7 @@ static void fb_do_show_logo(struct fb_in image->dy += image->height + 8; } } else if (rotate == FB_ROTATE_CCW) { - for (x = 0; x < num && image->dy >= 0; x++) { + for (x = 0; x < num && (__s32)image->dy >= 0; x++) { info->fbops->fb_imageblit(info, image); image->dy -= image->height + 8; } @@ -1083,7 +1083,7 @@ fb_ioctl(struct inode *inode, struct fil return - EFAULT; if (con2fb.console < 1 || con2fb.console > MAX_NR_CONSOLES) return -EINVAL; - if (con2fb.framebuffer < 0 || con2fb.framebuffer >= FB_MAX) + if (con2fb.framebuffer >= FB_MAX) return -EINVAL; #ifdef CONFIG_KMOD if (!registered_fb[con2fb.framebuffer]) diff -NurpP --minimal linux-2.6.27.15/drivers/video/fbmon.c linux-2.6.27.15-g-v/drivers/video/fbmon.c --- linux-2.6.27.15/drivers/video/fbmon.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/video/fbmon.c 2009-02-10 20:32:14.000000000 +0100 @@ -45,7 +45,7 @@ #ifdef DEBUG #define DPRINTK(fmt, args...) printk(fmt,## args) #else -#define DPRINTK(fmt, args...) +#define DPRINTK(fmt, args...) do {} while (0) #endif #define FBMON_FIX_HEADER 1 diff -NurpP --minimal linux-2.6.27.15/drivers/video/i810/i810_accel.c linux-2.6.27.15-g-v/drivers/video/i810/i810_accel.c --- linux-2.6.27.15/drivers/video/i810/i810_accel.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/video/i810/i810_accel.c 2009-02-10 20:32:14.000000000 +0100 @@ -73,6 +73,7 @@ static inline int wait_for_space(struct } } printk("ringbuffer lockup!!!\n"); + printk("head:%u tail:%u iring.size:%u space:%u\n", head, tail, par->iring.size, space); i810_report_error(mmio); par->dev_flags |= LOCKUP; info->pixmap.scan_align = 1; diff -NurpP --minimal linux-2.6.27.15/drivers/video/i810/i810_main.c linux-2.6.27.15-g-v/drivers/video/i810/i810_main.c --- linux-2.6.27.15/drivers/video/i810/i810_main.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/video/i810/i810_main.c 2009-02-10 20:32:14.000000000 +0100 @@ -120,7 +120,7 @@ static struct pci_device_id i810fb_pci_t PCI_ANY_ID, PCI_ANY_ID, 0, 0, 4 }, { PCI_VENDOR_ID_INTEL, PCI_DEVICE_ID_INTEL_82815_CGC, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 5 }, - { 0 }, + { 0, 0, 0, 0, 0, 0, 0 }, }; static struct pci_driver i810fb_driver = { @@ -1509,7 +1509,7 @@ static int i810fb_cursor(struct fb_info int size = ((cursor->image.width + 7) >> 3) * cursor->image.height; int i; - u8 *data = kmalloc(64 * 8, GFP_ATOMIC); + u8 *data = kmalloc(64 * 8, GFP_KERNEL); if (data == NULL) return -ENOMEM; diff -NurpP --minimal linux-2.6.27.15/drivers/video/modedb.c linux-2.6.27.15-g-v/drivers/video/modedb.c --- linux-2.6.27.15/drivers/video/modedb.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/video/modedb.c 2009-02-10 20:32:14.000000000 +0100 @@ -38,232 +38,232 @@ static const struct fb_videomode modedb[ { /* 640x400 @ 70 Hz, 31.5 kHz hsync */ NULL, 70, 640, 400, 39721, 40, 24, 39, 9, 96, 2, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 640x480 @ 60 Hz, 31.5 kHz hsync */ NULL, 60, 640, 480, 39721, 40, 24, 32, 11, 96, 2, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 800x600 @ 56 Hz, 35.15 kHz hsync */ NULL, 56, 800, 600, 27777, 128, 24, 22, 1, 72, 2, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1024x768 @ 87 Hz interlaced, 35.5 kHz hsync */ NULL, 87, 1024, 768, 22271, 56, 24, 33, 8, 160, 8, - 0, FB_VMODE_INTERLACED + 0, FB_VMODE_INTERLACED, FB_MODE_IS_UNKNOWN }, { /* 640x400 @ 85 Hz, 37.86 kHz hsync */ NULL, 85, 640, 400, 31746, 96, 32, 41, 1, 64, 3, - FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 640x480 @ 72 Hz, 36.5 kHz hsync */ NULL, 72, 640, 480, 31746, 144, 40, 30, 8, 40, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 640x480 @ 75 Hz, 37.50 kHz hsync */ NULL, 75, 640, 480, 31746, 120, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 800x600 @ 60 Hz, 37.8 kHz hsync */ NULL, 60, 800, 600, 25000, 88, 40, 23, 1, 128, 4, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 640x480 @ 85 Hz, 43.27 kHz hsync */ NULL, 85, 640, 480, 27777, 80, 56, 25, 1, 56, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1152x864 @ 89 Hz interlaced, 44 kHz hsync */ NULL, 89, 1152, 864, 15384, 96, 16, 110, 1, 216, 10, - 0, FB_VMODE_INTERLACED + 0, FB_VMODE_INTERLACED, FB_MODE_IS_UNKNOWN }, { /* 800x600 @ 72 Hz, 48.0 kHz hsync */ NULL, 72, 800, 600, 20000, 64, 56, 23, 37, 120, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1024x768 @ 60 Hz, 48.4 kHz hsync */ NULL, 60, 1024, 768, 15384, 168, 8, 29, 3, 144, 6, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 640x480 @ 100 Hz, 53.01 kHz hsync */ NULL, 100, 640, 480, 21834, 96, 32, 36, 8, 96, 6, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1152x864 @ 60 Hz, 53.5 kHz hsync */ NULL, 60, 1152, 864, 11123, 208, 64, 16, 4, 256, 8, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 800x600 @ 85 Hz, 55.84 kHz hsync */ NULL, 85, 800, 600, 16460, 160, 64, 36, 16, 64, 5, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1024x768 @ 70 Hz, 56.5 kHz hsync */ NULL, 70, 1024, 768, 13333, 144, 24, 29, 3, 136, 6, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1280x1024 @ 87 Hz interlaced, 51 kHz hsync */ NULL, 87, 1280, 1024, 12500, 56, 16, 128, 1, 216, 12, - 0, FB_VMODE_INTERLACED + 0, FB_VMODE_INTERLACED, FB_MODE_IS_UNKNOWN }, { /* 800x600 @ 100 Hz, 64.02 kHz hsync */ NULL, 100, 800, 600, 14357, 160, 64, 30, 4, 64, 6, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1024x768 @ 76 Hz, 62.5 kHz hsync */ NULL, 76, 1024, 768, 11764, 208, 8, 36, 16, 120, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1152x864 @ 70 Hz, 62.4 kHz hsync */ NULL, 70, 1152, 864, 10869, 106, 56, 20, 1, 160, 10, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1280x1024 @ 61 Hz, 64.2 kHz hsync */ NULL, 61, 1280, 1024, 9090, 200, 48, 26, 1, 184, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1400x1050 @ 60Hz, 63.9 kHz hsync */ NULL, 60, 1400, 1050, 9259, 136, 40, 13, 1, 112, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1400x1050 @ 75,107 Hz, 82,392 kHz +hsync +vsync*/ NULL, 75, 1400, 1050, 7190, 120, 56, 23, 10, 112, 13, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1400x1050 @ 60 Hz, ? kHz +hsync +vsync*/ NULL, 60, 1400, 1050, 9259, 128, 40, 12, 0, 112, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1024x768 @ 85 Hz, 70.24 kHz hsync */ NULL, 85, 1024, 768, 10111, 192, 32, 34, 14, 160, 6, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1152x864 @ 78 Hz, 70.8 kHz hsync */ NULL, 78, 1152, 864, 9090, 228, 88, 32, 0, 84, 12, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1280x1024 @ 70 Hz, 74.59 kHz hsync */ NULL, 70, 1280, 1024, 7905, 224, 32, 28, 8, 160, 8, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1600x1200 @ 60Hz, 75.00 kHz hsync */ NULL, 60, 1600, 1200, 6172, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1152x864 @ 84 Hz, 76.0 kHz hsync */ NULL, 84, 1152, 864, 7407, 184, 312, 32, 0, 128, 12, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1280x1024 @ 74 Hz, 78.85 kHz hsync */ NULL, 74, 1280, 1024, 7407, 256, 32, 34, 3, 144, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1024x768 @ 100Hz, 80.21 kHz hsync */ NULL, 100, 1024, 768, 8658, 192, 32, 21, 3, 192, 10, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1280x1024 @ 76 Hz, 81.13 kHz hsync */ NULL, 76, 1280, 1024, 7407, 248, 32, 34, 3, 104, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1600x1200 @ 70 Hz, 87.50 kHz hsync */ NULL, 70, 1600, 1200, 5291, 304, 64, 46, 1, 192, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1152x864 @ 100 Hz, 89.62 kHz hsync */ NULL, 100, 1152, 864, 7264, 224, 32, 17, 2, 128, 19, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1280x1024 @ 85 Hz, 91.15 kHz hsync */ NULL, 85, 1280, 1024, 6349, 224, 64, 44, 1, 160, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1600x1200 @ 75 Hz, 93.75 kHz hsync */ NULL, 75, 1600, 1200, 4938, 304, 64, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1680x1050 @ 60 Hz, 65.191 kHz hsync */ NULL, 60, 1680, 1050, 6848, 280, 104, 30, 3, 176, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1600x1200 @ 85 Hz, 105.77 kHz hsync */ NULL, 85, 1600, 1200, 4545, 272, 16, 37, 4, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1280x1024 @ 100 Hz, 107.16 kHz hsync */ NULL, 100, 1280, 1024, 5502, 256, 32, 26, 7, 128, 15, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1800x1440 @ 64Hz, 96.15 kHz hsync */ NULL, 64, 1800, 1440, 4347, 304, 96, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1800x1440 @ 70Hz, 104.52 kHz hsync */ NULL, 70, 1800, 1440, 4000, 304, 96, 46, 1, 192, 3, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 512x384 @ 78 Hz, 31.50 kHz hsync */ NULL, 78, 512, 384, 49603, 48, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 512x384 @ 85 Hz, 34.38 kHz hsync */ NULL, 85, 512, 384, 45454, 48, 16, 16, 1, 64, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 320x200 @ 70 Hz, 31.5 kHz hsync, 8:5 aspect ratio */ NULL, 70, 320, 200, 79440, 16, 16, 20, 4, 48, 1, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 320x240 @ 60 Hz, 31.5 kHz hsync, 4:3 aspect ratio */ NULL, 60, 320, 240, 79440, 16, 16, 16, 5, 48, 1, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 320x240 @ 72 Hz, 36.5 kHz hsync */ NULL, 72, 320, 240, 63492, 16, 16, 16, 4, 48, 2, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 400x300 @ 56 Hz, 35.2 kHz hsync, 4:3 aspect ratio */ NULL, 56, 400, 300, 55555, 64, 16, 10, 1, 32, 1, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 400x300 @ 60 Hz, 37.8 kHz hsync */ NULL, 60, 400, 300, 50000, 48, 16, 11, 1, 64, 2, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 400x300 @ 72 Hz, 48.0 kHz hsync */ NULL, 72, 400, 300, 40000, 32, 24, 11, 19, 64, 3, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 480x300 @ 56 Hz, 35.2 kHz hsync, 8:5 aspect ratio */ NULL, 56, 480, 300, 46176, 80, 16, 10, 1, 40, 1, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 480x300 @ 60 Hz, 37.8 kHz hsync */ NULL, 60, 480, 300, 41858, 56, 16, 11, 1, 80, 2, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 480x300 @ 63 Hz, 39.6 kHz hsync */ NULL, 63, 480, 300, 40000, 56, 16, 11, 1, 80, 2, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 480x300 @ 72 Hz, 48.0 kHz hsync */ NULL, 72, 480, 300, 33386, 40, 24, 11, 19, 80, 3, - 0, FB_VMODE_DOUBLE + 0, FB_VMODE_DOUBLE, FB_MODE_IS_UNKNOWN }, { /* 1920x1200 @ 60 Hz, 74.5 Khz hsync */ NULL, 60, 1920, 1200, 5177, 128, 336, 1, 38, 208, 3, FB_SYNC_HOR_HIGH_ACT | FB_SYNC_VERT_HIGH_ACT, - FB_VMODE_NONINTERLACED + FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1152x768, 60 Hz, PowerBook G4 Titanium I and II */ NULL, 60, 1152, 768, 14047, 158, 26, 29, 3, 136, 6, - FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED + FB_SYNC_HOR_HIGH_ACT|FB_SYNC_VERT_HIGH_ACT, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1366x768, 60 Hz, 47.403 kHz hsync, WXGA 16:9 aspect ratio */ NULL, 60, 1366, 768, 13806, 120, 10, 14, 3, 32, 5, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, { /* 1280x800, 60 Hz, 47.403 kHz hsync, WXGA 16:10 aspect ratio */ NULL, 60, 1280, 800, 12048, 200, 64, 24, 1, 136, 3, - 0, FB_VMODE_NONINTERLACED + 0, FB_VMODE_NONINTERLACED, FB_MODE_IS_UNKNOWN }, }; diff -NurpP --minimal linux-2.6.27.15/drivers/video/uvesafb.c linux-2.6.27.15-g-v/drivers/video/uvesafb.c --- linux-2.6.27.15/drivers/video/uvesafb.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/video/uvesafb.c 2009-02-10 20:32:14.000000000 +0100 @@ -18,6 +18,7 @@ #include #include #include +#include #include #include #ifdef CONFIG_X86 @@ -117,7 +118,7 @@ static int uvesafb_helper_start(void) NULL, }; - return call_usermodehelper(v86d_path, argv, envp, 1); + return call_usermodehelper(v86d_path, argv, envp, UMH_WAIT_PROC); } /* @@ -569,10 +570,34 @@ static int __devinit uvesafb_vbe_getpmi( if ((task->t.regs.eax & 0xffff) != 0x4f || task->t.regs.es < 0xc000) { par->pmi_setpal = par->ypan = 0; } else { + +#ifdef CONFIG_PAX_KERNEXEC +#ifdef CONFIG_MODULES + unsigned long cr0; + + par->pmi_code = module_alloc_exec((u16)task->t.regs.ecx); +#endif + if (!par->pmi_code) { + par->pmi_setpal = par->ypan = 0; + return 0; + } +#endif + par->pmi_base = (u16 *)phys_to_virt(((u32)task->t.regs.es << 4) + task->t.regs.edi); + +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + pax_open_kernel(cr0); + memcpy(par->pmi_code, par->pmi_base, (u16)task->t.regs.ecx); + pax_close_kernel(cr0); + + par->pmi_start = ktva_ktla(par->pmi_code + par->pmi_base[1]); + par->pmi_pal = ktva_ktla(par->pmi_code + par->pmi_base[2]); +#else par->pmi_start = (u8 *)par->pmi_base + par->pmi_base[1]; par->pmi_pal = (u8 *)par->pmi_base + par->pmi_base[2]; +#endif + printk(KERN_INFO "uvesafb: protected mode interface info at " "%04x:%04x\n", (u16)task->t.regs.es, (u16)task->t.regs.edi); @@ -1827,6 +1852,11 @@ out: if (par->vbe_modes) kfree(par->vbe_modes); +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + if (par->pmi_code) + module_free_exec(NULL, par->pmi_code); +#endif + framebuffer_release(info); return err; } @@ -1853,6 +1883,12 @@ static int uvesafb_remove(struct platfor kfree(par->vbe_state_orig); if (par->vbe_state_saved) kfree(par->vbe_state_saved); + +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + if (par->pmi_code) + module_free_exec(NULL, par->pmi_code); +#endif + } framebuffer_release(info); diff -NurpP --minimal linux-2.6.27.15/drivers/video/vesafb.c linux-2.6.27.15-g-v/drivers/video/vesafb.c --- linux-2.6.27.15/drivers/video/vesafb.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/drivers/video/vesafb.c 2009-02-10 20:32:14.000000000 +0100 @@ -9,6 +9,7 @@ */ #include +#include #include #include #include @@ -53,8 +54,8 @@ static int vram_remap __initdata; /* static int vram_total __initdata; /* Set total amount of memory */ static int pmi_setpal __read_mostly = 1; /* pmi for palette changes ??? */ static int ypan __read_mostly; /* 0..nothing, 1..ypan, 2..ywrap */ -static void (*pmi_start)(void) __read_mostly; -static void (*pmi_pal) (void) __read_mostly; +static void (*pmi_start)(void) __read_only; +static void (*pmi_pal) (void) __read_only; static int depth __read_mostly; static int vga_compat __read_mostly; /* --------------------------------------------------------------------- */ @@ -224,6 +225,7 @@ static int __init vesafb_probe(struct pl unsigned int size_vmode; unsigned int size_remap; unsigned int size_total; + void *pmi_code = NULL; if (screen_info.orig_video_isVGA != VIDEO_TYPE_VLFB) return -ENODEV; @@ -266,10 +268,6 @@ static int __init vesafb_probe(struct pl size_remap = size_total; vesafb_fix.smem_len = size_remap; -#ifndef __i386__ - screen_info.vesapm_seg = 0; -#endif - if (!request_mem_region(vesafb_fix.smem_start, size_total, "vesafb")) { printk(KERN_WARNING "vesafb: cannot reserve video memory at 0x%lx\n", @@ -302,9 +300,21 @@ static int __init vesafb_probe(struct pl printk(KERN_INFO "vesafb: mode is %dx%dx%d, linelength=%d, pages=%d\n", vesafb_defined.xres, vesafb_defined.yres, vesafb_defined.bits_per_pixel, vesafb_fix.line_length, screen_info.pages); +#ifdef __i386__ + +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + pmi_code = module_alloc_exec(screen_info.vesapm_size); + if (!pmi_code) +#elif !defined(CONFIG_PAX_KERNEXEC) + if (0) +#endif + +#endif + screen_info.vesapm_seg = 0; + if (screen_info.vesapm_seg) { - printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x\n", - screen_info.vesapm_seg,screen_info.vesapm_off); + printk(KERN_INFO "vesafb: protected mode interface info at %04x:%04x %04x bytes\n", + screen_info.vesapm_seg,screen_info.vesapm_off,screen_info.vesapm_size); } if (screen_info.vesapm_seg < 0xc000) @@ -312,9 +322,29 @@ static int __init vesafb_probe(struct pl if (ypan || pmi_setpal) { unsigned short *pmi_base; - pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); - pmi_start = (void*)((char*)pmi_base + pmi_base[1]); - pmi_pal = (void*)((char*)pmi_base + pmi_base[2]); + +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + unsigned long cr0; +#endif + + pmi_base = (unsigned short*)phys_to_virt(((unsigned long)screen_info.vesapm_seg << 4) + screen_info.vesapm_off); + +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + pax_open_kernel(cr0); + memcpy(pmi_code, pmi_base, screen_info.vesapm_size); +#else + pmi_code = pmi_base; +#endif + + pmi_start = (void*)((char*)pmi_code + pmi_base[1]); + pmi_pal = (void*)((char*)pmi_code + pmi_base[2]); + +#if defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + pmi_start = ktva_ktla(pmi_start); + pmi_pal = ktva_ktla(pmi_pal); + pax_close_kernel(cr0); +#endif + printk(KERN_INFO "vesafb: pmi: set display start = %p, set palette = %p\n",pmi_start,pmi_pal); if (pmi_base[3]) { printk(KERN_INFO "vesafb: pmi: ports = "); @@ -456,6 +486,11 @@ static int __init vesafb_probe(struct pl info->node, info->fix.id); return 0; err: + +#if defined(__i386__) && defined(CONFIG_MODULES) && defined(CONFIG_PAX_KERNEXEC) + module_free_exec(NULL, pmi_code); +#endif + if (info->screen_base) iounmap(info->screen_base); framebuffer_release(info); diff -NurpP --minimal linux-2.6.27.15/fs/9p/vfs_inode.c linux-2.6.27.15-g-v/fs/9p/vfs_inode.c --- linux-2.6.27.15/fs/9p/vfs_inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/9p/vfs_inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -1021,7 +1021,7 @@ static void *v9fs_vfs_follow_link(struct static void v9fs_vfs_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { - char *s = nd_get_link(nd); + const char *s = nd_get_link(nd); P9_DPRINTK(P9_DEBUG_VFS, " %s %s\n", dentry->d_name.name, s); if (!IS_ERR(s)) diff -NurpP --minimal linux-2.6.27.15/fs/aio.c linux-2.6.27.15-g-v/fs/aio.c --- linux-2.6.27.15/fs/aio.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/aio.c 2009-02-10 20:32:14.000000000 +0100 @@ -114,7 +114,7 @@ static int aio_setup_ring(struct kioctx size += sizeof(struct io_event) * nr_events; nr_pages = (size + PAGE_SIZE-1) >> PAGE_SHIFT; - if (nr_pages < 0) + if (nr_pages <= 0) return -EINVAL; nr_events = (PAGE_SIZE * nr_pages - sizeof(struct aio_ring)) / sizeof(struct io_event); diff -NurpP --minimal linux-2.6.27.15/fs/attr.c linux-2.6.27.15-g-v/fs/attr.c --- linux-2.6.27.15/fs/attr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/attr.c 2009-02-10 20:32:14.000000000 +0100 @@ -14,6 +14,9 @@ #include #include #include +#include +#include +#include /* Taken over from the old code... */ @@ -55,6 +58,10 @@ int inode_change_ok(struct inode *inode, if (!is_owner_or_cap(inode)) goto error; } + + if (dx_permission(inode, MAY_WRITE)) + goto error; + fine: retval = 0; error: @@ -78,6 +85,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_TAG) && IS_TAGGED(inode)) + inode->i_tag = attr->ia_tag; if (ia_valid & ATTR_ATIME) inode->i_atime = timespec_trunc(attr->ia_atime, inode->i_sb->s_time_gran); @@ -172,7 +181,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_TAG && attr->ia_tag != inode->i_tag)) error = DQUOT_TRANSFER(inode, attr) ? -EDQUOT : 0; if (!error) error = inode_setattr(inode, attr); diff -NurpP --minimal linux-2.6.27.15/fs/autofs4/symlink.c linux-2.6.27.15-g-v/fs/autofs4/symlink.c --- linux-2.6.27.15/fs/autofs4/symlink.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/autofs4/symlink.c 2009-02-10 20:32:14.000000000 +0100 @@ -15,7 +15,7 @@ static void *autofs4_follow_link(struct dentry *dentry, struct nameidata *nd) { struct autofs_info *ino = autofs4_dentry_ino(dentry); - nd_set_link(nd, (char *)ino->u.symlink); + nd_set_link(nd, ino->u.symlink); return NULL; } diff -NurpP --minimal linux-2.6.27.15/fs/befs/linuxvfs.c linux-2.6.27.15-g-v/fs/befs/linuxvfs.c --- linux-2.6.27.15/fs/befs/linuxvfs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/befs/linuxvfs.c 2009-02-10 20:32:14.000000000 +0100 @@ -490,7 +490,7 @@ static void befs_put_link(struct dentry { befs_inode_info *befs_ino = BEFS_I(dentry->d_inode); if (befs_ino->i_flags & BEFS_LONG_SYMLINK) { - char *link = nd_get_link(nd); + const char *link = nd_get_link(nd); if (!IS_ERR(link)) kfree(link); } diff -NurpP --minimal linux-2.6.27.15/fs/binfmt_aout.c linux-2.6.27.15-g-v/fs/binfmt_aout.c --- linux-2.6.27.15/fs/binfmt_aout.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/binfmt_aout.c 2009-02-10 20:32:14.000000000 +0100 @@ -24,6 +24,8 @@ #include #include #include +#include +#include #include #include @@ -124,18 +126,22 @@ 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) > limit) 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 > limit) dump.u_dsize = 0; #endif /* 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 > limit) 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 > limit) dump.u_ssize = 0; #endif @@ -291,6 +297,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 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; @@ -413,7 +443,7 @@ static int load_aout_binary(struct linux down_write(¤t->mm->mmap_sem); error = do_mmap(bprm->file, N_DATADDR(ex), ex.a_data, - PROT_READ | PROT_WRITE | PROT_EXEC, + PROT_READ | PROT_WRITE, MAP_FIXED | MAP_PRIVATE | MAP_DENYWRITE | MAP_EXECUTABLE, fd_offset + ex.a_text); up_write(¤t->mm->mmap_sem); diff -NurpP --minimal linux-2.6.27.15/fs/binfmt_elf.c linux-2.6.27.15-g-v/fs/binfmt_elf.c --- linux-2.6.27.15/fs/binfmt_elf.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/binfmt_elf.c 2009-02-10 20:32:14.000000000 +0100 @@ -38,10 +38,17 @@ #include #include #include +#include +#include + #include #include #include +#ifdef CONFIG_PAX_SEGMEXEC +#include +#endif + static int load_elf_binary(struct linux_binprm *bprm, struct pt_regs *regs); static int load_elf_library(struct file *); static unsigned long elf_map(struct file *, unsigned long, struct elf_phdr *, @@ -57,6 +64,10 @@ static int elf_core_dump(long signr, str #define elf_core_dump NULL #endif +#ifdef CONFIG_PAX_MPROTECT +static void elf_handle_mprotect(struct vm_area_struct *vma, unsigned long newflags); +#endif + #if ELF_EXEC_PAGESIZE > PAGE_SIZE #define ELF_MIN_ALIGN ELF_EXEC_PAGESIZE #else @@ -76,6 +87,11 @@ static struct linux_binfmt elf_format = .load_binary = load_elf_binary, .load_shlib = load_elf_library, .core_dump = elf_core_dump, + +#ifdef CONFIG_PAX_MPROTECT + .handle_mprotect= elf_handle_mprotect, +#endif + .min_coredump = ELF_EXEC_PAGESIZE, .hasvdso = 1 }; @@ -84,6 +100,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) { @@ -94,7 +112,7 @@ static int set_brk(unsigned long start, if (BAD_ADDR(addr)) return addr; } - current->mm->start_brk = current->mm->brk = end; + current->mm->start_brk = current->mm->brk = e; return 0; } @@ -380,10 +398,10 @@ static unsigned long load_elf_interp(str { struct elf_phdr *elf_phdata; struct elf_phdr *eppnt; - unsigned long load_addr = 0; + unsigned long load_addr = 0, pax_task_size = TASK_SIZE; int load_addr_set = 0; unsigned long last_bss = 0, elf_bss = 0; - unsigned long error = ~0UL; + unsigned long error = -EINVAL; unsigned long total_size; int retval, i, size; @@ -429,6 +447,11 @@ static unsigned long load_elf_interp(str goto out_close; } +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + eppnt = elf_phdata; for (i = 0; i < interp_elf_ex->e_phnum; i++, eppnt++) { if (eppnt->p_type == PT_LOAD) { @@ -472,8 +495,8 @@ static unsigned long load_elf_interp(str k = load_addr + eppnt->p_vaddr; if (BAD_ADDR(k) || eppnt->p_filesz > eppnt->p_memsz || - eppnt->p_memsz > TASK_SIZE || - TASK_SIZE - eppnt->p_memsz < k) { + eppnt->p_memsz > pax_task_size || + pax_task_size - eppnt->p_memsz < k) { error = -ENOMEM; goto out_close; } @@ -527,6 +550,177 @@ out: return error; } +#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 + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_PAX_SEGMEXEC) + if ((pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) == (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) { + if (nx_enabled) + pax_flags &= ~MF_PAX_SEGMEXEC; + else + 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 + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_PAX_SEGMEXEC) + if ((pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) == (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) { + if (nx_enabled) + pax_flags &= ~MF_PAX_SEGMEXEC; + else + 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 + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_PAX_SEGMEXEC) + if ((pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) == (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) { + if (nx_enabled) + pax_flags &= ~MF_PAX_SEGMEXEC; + else + 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. @@ -543,6 +737,11 @@ static unsigned long randomize_stack_top { unsigned int random_variable = 0; +#ifdef CONFIG_PAX_RANDUSTACK + if (randomize_va_space) + return stack_top - current->mm->delta_stack; +#endif + if ((current->flags & PF_RANDOMIZE) && !(current->personality & ADDR_NO_RANDOMIZE)) { random_variable = get_random_int() & STACK_RND_MASK; @@ -561,7 +760,7 @@ static int load_elf_binary(struct linux_ unsigned long load_addr = 0, load_bias = 0; int load_addr_set = 0; char * elf_interpreter = NULL; - unsigned long error; + unsigned long error = 0; struct elf_phdr *elf_ppnt, *elf_phdata; unsigned long elf_bss, elf_brk; int elf_exec_fileno; @@ -572,11 +771,11 @@ static int load_elf_binary(struct linux_ unsigned long start_code, end_code, start_data, end_data; unsigned long reloc_func_desc = 0; int executable_stack = EXSTACK_DEFAULT; - unsigned long def_flags = 0; struct { struct elfhdr elf_ex; struct elfhdr interp_elf_ex; } *loc; + unsigned long pax_task_size = TASK_SIZE; loc = kmalloc(sizeof(*loc), GFP_KERNEL); if (!loc) { @@ -744,11 +943,80 @@ static int load_elf_binary(struct linux_ /* OK, This is the point of no return */ current->flags &= ~PF_FORKNOEXEC; - current->mm->def_flags = def_flags; + +#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_stack = 0UL; +#endif + + current->mm->def_flags = 0; + +#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) && !nx_enabled) { + current->mm->context.user_cs_limit = PAGE_SIZE; + current->mm->def_flags |= VM_PAGEEXEC; + } +#endif + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) { + current->mm->context.user_cs_base = SEGMEXEC_TASK_SIZE; + current->mm->context.user_cs_limit = TASK_SIZE-SEGMEXEC_TASK_SIZE; + pax_task_size = SEGMEXEC_TASK_SIZE; + } +#endif + +#if defined(CONFIG_ARCH_TRACK_EXEC_LIMIT) || defined(CONFIG_PAX_SEGMEXEC) + if (current->mm->pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) { + set_user_cs(current->mm->context.user_cs_base, current->mm->context.user_cs_limit, get_cpu()); + put_cpu_no_resched(); + } +#endif + +#ifdef CONFIG_PAX_ASLR + if (current->mm->pax_flags & MF_PAX_RANDMMAP) { + current->mm->delta_mmap = (pax_get_random_long() & ((1UL << PAX_DELTA_MMAP_LEN)-1)) << PAGE_SHIFT; + current->mm->delta_stack = (pax_get_random_long() & ((1UL << PAX_DELTA_STACK_LEN)-1)) << PAGE_SHIFT; + } +#endif /* Do this immediately, since STACK_TOP as used in setup_arg_pages may depend on the personality. */ SET_PERSONALITY(loc->elf_ex, 0); + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (current->mm->pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) { + executable_stack = EXSTACK_DISABLE_X; + current->personality &= ~READ_IMPLIES_EXEC; + } else +#endif + if (elf_read_implies_exec(loc->elf_ex, executable_stack)) current->personality |= READ_IMPLIES_EXEC; @@ -829,6 +1097,20 @@ static int load_elf_binary(struct linux_ #else load_bias = ELF_PAGESTART(ELF_ET_DYN_BASE - vaddr); #endif + +#ifdef CONFIG_PAX_RANDMMAP + /* PaX: randomize base address at the default exe base if requested */ + if ((current->mm->pax_flags & MF_PAX_RANDMMAP) && elf_interpreter) { +#ifdef CONFIG_SPARC64 + load_bias = (pax_get_random_long() & ((1UL << PAX_DELTA_MMAP_LEN) - 1)) << (PAGE_SHIFT+1); +#else + load_bias = (pax_get_random_long() & ((1UL << PAX_DELTA_MMAP_LEN) - 1)) << PAGE_SHIFT; +#endif + load_bias = ELF_PAGESTART(PAX_ELF_ET_DYN_BASE - vaddr + load_bias); + elf_flags |= MAP_FIXED; + } +#endif + } error = elf_map(bprm->file, load_bias + vaddr, elf_ppnt, @@ -861,9 +1143,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 (BAD_ADDR(k) || elf_ppnt->p_filesz > elf_ppnt->p_memsz || - elf_ppnt->p_memsz > TASK_SIZE || - TASK_SIZE - elf_ppnt->p_memsz < k) { + if (k >= pax_task_size || elf_ppnt->p_filesz > elf_ppnt->p_memsz || + elf_ppnt->p_memsz > pax_task_size || + pax_task_size - elf_ppnt->p_memsz < k) { /* set_brk can never work. Avoid overflows. */ send_sig(SIGKILL, current, 0); retval = -EINVAL; @@ -891,6 +1173,11 @@ static int load_elf_binary(struct linux_ start_data += load_bias; end_data += load_bias; +#ifdef CONFIG_PAX_RANDMMAP + if (current->mm->pax_flags & MF_PAX_RANDMMAP) + elf_brk += PAGE_SIZE + ((pax_get_random_long() & ~PAGE_MASK) << 4); +#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 @@ -902,9 +1189,11 @@ static int load_elf_binary(struct linux_ goto out_free_dentry; } if (likely(elf_bss != elf_brk) && unlikely(padzero(elf_bss))) { - send_sig(SIGSEGV, current, 0); - retval = -EFAULT; /* Nobody gets to see this, but.. */ - goto out_free_dentry; + /* + * This bss-zeroing can fail if the ELF + * file specifies odd protections. So + * we don't check the return value + */ } if (elf_interpreter) { @@ -1141,8 +1430,10 @@ static int dump_seek(struct file *file, unsigned long n = off; if (n > PAGE_SIZE) n = PAGE_SIZE; - if (!dump_write(file, buf, n)) + if (!dump_write(file, buf, n)) { + free_page((unsigned long)buf); return 0; + } off -= n; } free_page((unsigned long)buf); @@ -1154,7 +1445,7 @@ static int dump_seek(struct file *file, * Decide what to dump of a segment, part, all or none. */ static unsigned long vma_dump_size(struct vm_area_struct *vma, - unsigned long mm_flags) + unsigned long mm_flags, long signr) { /* The vma can be set up to tell us the answer directly. */ if (vma->vm_flags & VM_ALWAYSDUMP) @@ -1180,7 +1471,7 @@ static unsigned long vma_dump_size(struc if (vma->vm_file == NULL) return 0; - if (FILTER(MAPPED_PRIVATE)) + if (signr == SIGKILL || FILTER(MAPPED_PRIVATE)) goto whole; /* @@ -1266,8 +1557,11 @@ static int writenote(struct memelfnote * #undef DUMP_WRITE #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; @@ -1973,7 +2267,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 = vma_dump_size(vma, mm_flags); + phdr.p_filesz = vma_dump_size(vma, mm_flags, signr); phdr.p_memsz = vma->vm_end - vma->vm_start; offset += phdr.p_filesz; phdr.p_flags = vma->vm_flags & VM_READ ? PF_R : 0; @@ -2005,7 +2299,7 @@ static int elf_core_dump(long signr, str unsigned long addr; unsigned long end; - end = vma->vm_start + vma_dump_size(vma, mm_flags); + end = vma->vm_start + vma_dump_size(vma, mm_flags, signr); for (addr = vma->vm_start; addr < end; addr += PAGE_SIZE) { struct page *page; @@ -2025,6 +2319,7 @@ static int elf_core_dump(long signr, str flush_cache_page(tmp_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)) { @@ -2055,6 +2350,99 @@ out: #endif /* USE_ELF_CORE_DUMP */ +#ifdef CONFIG_PAX_MPROTECT +/* PaX: non-PIC ELF libraries need relocations on their executable segments + * therefore we'll grant them VM_MAYWRITE once during their life. Similarly + * we'll remove VM_MAYWRITE for good on RELRO segments. + * + * The checks favour ld-linux.so behaviour which operates on a per ELF segment + * basis because we want to allow the common case and not the special ones. + */ +static void elf_handle_mprotect(struct vm_area_struct *vma, unsigned long newflags) +{ + struct elfhdr elf_h; + struct elf_phdr elf_p; + unsigned long i; + unsigned long oldflags; + bool is_textrel_rw, is_textrel_rx, is_relro; + + if (!(vma->vm_mm->pax_flags & MF_PAX_MPROTECT)) + return; + + oldflags = vma->vm_flags & (VM_MAYEXEC | VM_MAYWRITE | VM_MAYREAD | VM_EXEC | VM_WRITE | VM_READ); + newflags &= VM_MAYEXEC | VM_MAYWRITE | VM_MAYREAD | VM_EXEC | VM_WRITE | VM_READ; + +#ifdef CONFIG_PAX_NOELFRELOCS + is_textrel_rw = false; + is_textrel_rx = false; +#else + /* possible TEXTREL */ + is_textrel_rw = vma->vm_file && !vma->anon_vma && !vma->vm_pgoff && oldflags == (VM_MAYEXEC | VM_MAYREAD | VM_EXEC | VM_READ) && newflags == (VM_WRITE | VM_READ); + is_textrel_rx = vma->vm_file && vma->anon_vma && !vma->vm_pgoff && oldflags == (VM_MAYEXEC | VM_MAYWRITE | VM_MAYREAD | VM_WRITE | VM_READ) && newflags == (VM_EXEC | VM_READ); +#endif + + /* possible RELRO */ + is_relro = vma->vm_file && vma->anon_vma && oldflags == (VM_MAYWRITE | VM_MAYREAD | VM_READ) && newflags == (VM_MAYWRITE | VM_MAYREAD | VM_READ); + + if (!is_textrel_rw && !is_textrel_rx && !is_relro) + return; + + if (sizeof(elf_h) != kernel_read(vma->vm_file, 0UL, (char *)&elf_h, sizeof(elf_h)) || + memcmp(elf_h.e_ident, ELFMAG, SELFMAG) || + +#ifdef CONFIG_PAX_ETEXECRELOCS + ((is_textrel_rw || is_textrel_rx) && (elf_h.e_type != ET_DYN && elf_h.e_type != ET_EXEC)) || +#else + ((is_textrel_rw || is_textrel_rx) && elf_h.e_type != ET_DYN) || +#endif + + (is_relro && (elf_h.e_type != ET_DYN && elf_h.e_type != ET_EXEC)) || + !elf_check_arch(&elf_h) || + elf_h.e_phentsize != sizeof(struct elf_phdr) || + elf_h.e_phnum > 65536UL / sizeof(struct elf_phdr)) + return; + + for (i = 0UL; i < elf_h.e_phnum; i++) { + if (sizeof(elf_p) != kernel_read(vma->vm_file, elf_h.e_phoff + i*sizeof(elf_p), (char *)&elf_p, sizeof(elf_p))) + return; + switch (elf_p.p_type) { + case PT_DYNAMIC: { + elf_addr_t dyn_offset = 0UL; + elf_dyn dyn; + + if (!is_textrel_rw && !is_textrel_rx) + continue; + dyn_offset = elf_p.p_offset; + i = 0UL; + do { + if (sizeof(dyn) != kernel_read(vma->vm_file, dyn_offset + i*sizeof(dyn), (char *)&dyn, sizeof(dyn))) + return; + if (dyn.d_tag == DT_TEXTREL || (dyn.d_tag == DT_FLAGS && (dyn.d_un.d_val & DF_TEXTREL))) { + gr_log_textrel(vma); + if (is_textrel_rw) + vma->vm_flags |= VM_MAYWRITE; + else + /* PaX: disallow write access after relocs are done, hopefully noone else needs it... */ + vma->vm_flags &= ~VM_MAYWRITE; + return; + } + i++; + } while (dyn.d_tag != DT_NULL); + return; + } + + case PT_GNU_RELRO: + if (!is_relro) + continue; + if ((elf_p.p_offset >> PAGE_SHIFT) == vma->vm_pgoff && ELF_PAGEALIGN(elf_p.p_memsz) == vma->vm_end - vma->vm_start) { + vma->vm_flags &= ~VM_MAYWRITE; + } + return; + } + } +} +#endif + static int __init init_elf_binfmt(void) { return register_binfmt(&elf_format); diff -NurpP --minimal linux-2.6.27.15/fs/binfmt_flat.c linux-2.6.27.15-g-v/fs/binfmt_flat.c --- linux-2.6.27.15/fs/binfmt_flat.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/binfmt_flat.c 2009-02-10 20:32:14.000000000 +0100 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include @@ -561,7 +562,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)-realdatastart); + down_write(¤t->mm->mmap_sem); do_munmap(current->mm, textpos, text_len); + up_write(¤t->mm->mmap_sem); ret = realdatastart; goto err; } @@ -583,8 +586,10 @@ static int load_flat_file(struct linux_b } if (result >= (unsigned long)-4096) { printk("Unable to read data+bss, errno %d\n", (int)-result); + down_write(¤t->mm->mmap_sem); do_munmap(current->mm, textpos, text_len); do_munmap(current->mm, realdatastart, data_len + extra); + up_write(¤t->mm->mmap_sem); ret = result; goto err; } @@ -657,8 +662,10 @@ static int load_flat_file(struct linux_b } if (result >= (unsigned long)-4096) { printk("Unable to read code+data+bss, errno %d\n",(int)-result); + down_write(¤t->mm->mmap_sem); do_munmap(current->mm, textpos, text_len + data_len + extra + MAX_SHARED_LIBS * sizeof(unsigned long)); + up_write(¤t->mm->mmap_sem); ret = result; goto err; } diff -NurpP --minimal linux-2.6.27.15/fs/binfmt_misc.c linux-2.6.27.15-g-v/fs/binfmt_misc.c --- linux-2.6.27.15/fs/binfmt_misc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/binfmt_misc.c 2009-02-10 20:32:14.000000000 +0100 @@ -696,7 +696,7 @@ static int bm_fill_super(struct super_bl static struct tree_descr bm_files[] = { [2] = {"status", &bm_status_operations, S_IWUSR|S_IRUGO}, [3] = {"register", &bm_register_operations, S_IWUSR}, - /* last one */ {""} + /* last one */ {"", NULL, 0} }; int err = simple_fill_super(sb, 0x42494e4d, bm_files); if (!err) diff -NurpP --minimal linux-2.6.27.15/fs/binfmt_som.c linux-2.6.27.15-g-v/fs/binfmt_som.c --- linux-2.6.27.15/fs/binfmt_som.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/binfmt_som.c 2009-02-10 20:32:14.000000000 +0100 @@ -28,6 +28,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/fs/bio.c linux-2.6.27.15-g-v/fs/bio.c --- linux-2.6.27.15/fs/bio.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/bio.c 2009-02-10 20:32:14.000000000 +0100 @@ -507,7 +507,7 @@ static int __bio_copy_iov(struct bio *bi while (bv_len && iov_idx < iov_count) { unsigned int bytes; - char *iov_addr; + char __user *iov_addr; bytes = min_t(unsigned int, iov[iov_idx].iov_len - iov_off, bv_len); diff -NurpP --minimal linux-2.6.27.15/fs/block_dev.c linux-2.6.27.15-g-v/fs/block_dev.c --- linux-2.6.27.15/fs/block_dev.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/block_dev.c 2009-02-10 20:32:14.000000000 +0100 @@ -24,6 +24,7 @@ #include #include #include +#include #include #include "internal.h" @@ -389,6 +390,7 @@ struct block_device *bdget(dev_t dev) bdev->bd_invalidated = 0; inode->i_mode = S_IFBLK; inode->i_rdev = dev; + inode->i_mdev = dev; inode->i_bdev = bdev; inode->i_data.a_ops = &def_blk_aops; mapping_set_gfp_mask(&inode->i_data, GFP_USER); @@ -425,6 +427,11 @@ EXPORT_SYMBOL(bdput); static struct block_device *bd_acquire(struct inode *inode) { struct block_device *bdev; + dev_t mdev; + + if (!vs_map_blkdev(inode->i_rdev, &mdev, DATTR_OPEN)) + return NULL; + inode->i_mdev = mdev; spin_lock(&bdev_lock); bdev = inode->i_bdev; @@ -435,7 +442,7 @@ static struct block_device *bd_acquire(s } spin_unlock(&bdev_lock); - bdev = bdget(inode->i_rdev); + bdev = bdget(mdev); if (bdev) { spin_lock(&bdev_lock); if (!inode->i_bdev) { diff -NurpP --minimal linux-2.6.27.15/fs/buffer.c linux-2.6.27.15-g-v/fs/buffer.c --- linux-2.6.27.15/fs/buffer.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/buffer.c 2009-02-10 20:32:14.000000000 +0100 @@ -41,6 +41,7 @@ #include #include #include +#include static int fsync_buffers_list(spinlock_t *lock, struct list_head *list); @@ -2249,6 +2250,7 @@ int generic_cont_expand_simple(struct 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 --minimal linux-2.6.27.15/fs/char_dev.c linux-2.6.27.15-g-v/fs/char_dev.c --- linux-2.6.27.15/fs/char_dev.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/char_dev.c 2009-02-10 20:32:14.000000000 +0100 @@ -21,6 +21,8 @@ #include #include #include +#include +#include #ifdef CONFIG_KMOD #include @@ -361,14 +363,21 @@ static int chrdev_open(struct inode *ino struct cdev *p; struct cdev *new = NULL; int ret = 0; + dev_t mdev; + + if (!vs_map_chrdev(inode->i_rdev, &mdev, DATTR_OPEN)) + return -EPERM; + inode->i_mdev = mdev; spin_lock(&cdev_lock); p = inode->i_cdev; if (!p) { struct kobject *kobj; int idx; + spin_unlock(&cdev_lock); - kobj = kobj_lookup(cdev_map, inode->i_rdev, &idx); + + kobj = kobj_lookup(cdev_map, mdev, &idx); if (!kobj) return -ENXIO; new = container_of(kobj, struct cdev, kobj); diff -NurpP --minimal linux-2.6.27.15/fs/cifs/cifs_uniupr.h linux-2.6.27.15-g-v/fs/cifs/cifs_uniupr.h --- linux-2.6.27.15/fs/cifs/cifs_uniupr.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/cifs/cifs_uniupr.h 2009-02-10 20:32:14.000000000 +0100 @@ -132,7 +132,7 @@ const struct UniCaseRange CifsUniUpperRa {0x0490, 0x04cc, UniCaseRangeU0490}, {0x1e00, 0x1ffc, UniCaseRangeU1e00}, {0xff40, 0xff5a, UniCaseRangeUff40}, - {0} + {0, 0, NULL} }; #endif diff -NurpP --minimal linux-2.6.27.15/fs/cifs/link.c linux-2.6.27.15-g-v/fs/cifs/link.c --- linux-2.6.27.15/fs/cifs/link.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/cifs/link.c 2009-02-10 20:32:14.000000000 +0100 @@ -318,7 +318,7 @@ cifs_readlink(struct dentry *direntry, c void cifs_put_link(struct dentry *direntry, struct nameidata *nd, void *cookie) { - char *p = nd_get_link(nd); + const char *p = nd_get_link(nd); if (!IS_ERR(p)) kfree(p); } diff -NurpP --minimal linux-2.6.27.15/fs/compat.c linux-2.6.27.15-g-v/fs/compat.c --- linux-2.6.27.15/fs/compat.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/compat.c 2009-02-10 20:32:14.000000000 +0100 @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -1298,14 +1299,12 @@ static int compat_copy_strings(int argc, if (!kmapped_page || kpos != (pos & PAGE_MASK)) { struct page *page; -#ifdef CONFIG_STACK_GROWSUP ret = expand_stack_downwards(bprm->vma, pos); if (ret < 0) { /* We've exceed the stack rlimit. */ ret = -E2BIG; goto out; } -#endif ret = get_user_pages(current, bprm->mm, pos, 1, 1, 1, &page, NULL); if (ret <= 0) { @@ -1351,6 +1350,11 @@ int compat_do_execve(char * filename, compat_uptr_t __user *envp, struct pt_regs * regs) { +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif struct linux_binprm *bprm; struct file *file; int retval; @@ -1371,6 +1375,14 @@ int compat_do_execve(char * filename, 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; + retval = bprm_mm_init(bprm); if (retval) goto out_file; @@ -1404,8 +1416,36 @@ 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) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif /* execve success */ security_bprm_free(bprm); acct_update_integrals(current); @@ -1413,6 +1453,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: if (bprm->security) security_bprm_free(bprm); diff -NurpP --minimal linux-2.6.27.15/fs/compat_ioctl.c linux-2.6.27.15-g-v/fs/compat_ioctl.c --- linux-2.6.27.15/fs/compat_ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/compat_ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -1831,15 +1831,15 @@ struct ioctl_trans { }; #define HANDLE_IOCTL(cmd,handler) \ - { (cmd), (ioctl_trans_handler_t)(handler) }, + { (cmd), (ioctl_trans_handler_t)(handler), NULL }, /* pointer to compatible structure or no argument */ #define COMPATIBLE_IOCTL(cmd) \ - { (cmd), do_ioctl32_pointer }, + { (cmd), do_ioctl32_pointer, NULL }, /* argument is an unsigned long integer, not a pointer */ #define ULONG_IOCTL(cmd) \ - { (cmd), (ioctl_trans_handler_t)sys_ioctl }, + { (cmd), (ioctl_trans_handler_t)sys_ioctl, NULL }, /* ioctl should not be warned about even if it's not implemented. Valid reasons to use this: diff -NurpP --minimal linux-2.6.27.15/fs/dcache.c linux-2.6.27.15-g-v/fs/dcache.c --- linux-2.6.27.15/fs/dcache.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/dcache.c 2009-02-10 20:32:14.000000000 +0100 @@ -32,6 +32,7 @@ #include #include #include +#include #include "internal.h" @@ -226,6 +227,8 @@ repeat: return; } + vx_dentry_dec(dentry); + /* * AV: ->d_delete() is _NOT_ allowed to block now. */ @@ -317,6 +320,7 @@ static inline struct dentry * __dget_loc { atomic_inc(&dentry->d_count); dentry_lru_del_init(dentry); + vx_dentry_inc(dentry); return dentry; } @@ -914,6 +918,9 @@ struct dentry *d_alloc(struct dentry * p struct dentry *dentry; char *dname; + if (!vx_dentry_avail(1)) + return NULL; + dentry = kmem_cache_alloc(dentry_cache, GFP_KERNEL); if (!dentry) return NULL; @@ -962,6 +969,7 @@ struct dentry *d_alloc(struct dentry * p if (parent) list_add(&dentry->d_u.d_child, &parent->d_subdirs); dentry_stat.nr_dentry++; + vx_dentry_inc(dentry); spin_unlock(&dcache_lock); return dentry; @@ -1415,6 +1423,7 @@ struct dentry * __d_lookup(struct dentry } atomic_inc(&dentry->d_count); + vx_dentry_inc(dentry); found = dentry; spin_unlock(&dentry->d_lock); break; diff -NurpP --minimal linux-2.6.27.15/fs/debugfs/inode.c linux-2.6.27.15-g-v/fs/debugfs/inode.c --- linux-2.6.27.15/fs/debugfs/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/debugfs/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -121,7 +121,7 @@ static inline int debugfs_positive(struc static int debug_fill_super(struct super_block *sb, void *data, int silent) { - static struct tree_descr debug_files[] = Template:""; + static struct tree_descr debug_files[] = Template:"", NULL, 0; return simple_fill_super(sb, DEBUGFS_MAGIC, debug_files); } diff -NurpP --minimal linux-2.6.27.15/fs/devpts/inode.c linux-2.6.27.15-g-v/fs/devpts/inode.c --- linux-2.6.27.15/fs/devpts/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/devpts/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -19,15 +19,29 @@ #include #include #include +#include #include #include #include #include - -#define DEVPTS_SUPER_MAGIC 0x1cd1 +#include #define DEVPTS_DEFAULT_MODE 0600 +static int devpts_permission(struct inode *inode, int mask) +{ + int ret = -EACCES; + + /* devpts is xid tagged */ + if (vx_check((xid_t)inode->i_tag, VS_WATCH_P | VS_IDENT)) + ret = generic_permission(inode, mask, NULL); + return ret; +} + +static struct inode_operations devpts_file_inode_operations = { + .permission = devpts_permission, +}; + extern int pty_limit; /* Config limit on Unix98 ptys */ static DEFINE_IDA(allocated_ptys); static DEFINE_MUTEX(allocated_ptys_lock); @@ -112,6 +126,25 @@ static int devpts_show_options(struct se return 0; } +static int devpts_filter(struct dentry *de) +{ + /* devpts is xid tagged */ + return vx_check((xid_t)de->d_inode->i_tag, VS_WATCH_P | VS_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 const struct super_operations devpts_sops = { .statfs = simple_statfs, .remount_fs = devpts_remount, @@ -138,8 +171,10 @@ 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; + /* devpts is xid tagged */ + inode->i_tag = (tag_t)vx_current_xid(); devpts_root = s->s_root = d_alloc_root(inode); if (s->s_root) @@ -232,6 +267,9 @@ 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); + /* devpts is xid tagged */ + inode->i_tag = (tag_t)vx_current_xid(); + inode->i_op = &devpts_file_inode_operations; inode->i_private = tty; dentry = get_node(number); diff -NurpP --minimal linux-2.6.27.15/fs/exec.c linux-2.6.27.15-g-v/fs/exec.c --- linux-2.6.27.15/fs/exec.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/exec.c 2009-02-10 20:32:14.000000000 +0100 @@ -50,6 +50,13 @@ #include #include #include +#include +#include + +#ifdef CONFIG_PAX_REFCOUNT +#include +#include +#endif #include #include @@ -64,6 +71,11 @@ #include #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 core_uses_pid; char core_pattern[CORENAME_MAX_SIZE] = "core"; int suid_dumpable = 0; @@ -172,18 +184,10 @@ static struct page *get_arg_page(struct int write) { struct page *page; - int ret; -#ifdef CONFIG_STACK_GROWSUP - if (write) { - ret = expand_stack_downwards(bprm->vma, pos); - if (ret < 0) - return NULL; - } -#endif - ret = get_user_pages(current, bprm->mm, pos, - 1, write, 1, &page, NULL); - if (ret <= 0) + if (0 > expand_stack_downwards(bprm->vma, pos)) + return NULL; + if (0 >= get_user_pages(current, bprm->mm, pos, 1, write, 1, &page, NULL)) return NULL; if (write) { @@ -256,6 +260,11 @@ static int __bprm_mm_init(struct linux_b vma->vm_start = vma->vm_end - PAGE_SIZE; vma->vm_flags = VM_STACK_FLAGS; + +#ifdef CONFIG_PAX_SEGMEXEC + vma->vm_flags &= ~(VM_EXEC | VM_MAYEXEC); +#endif + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); err = insert_vm_struct(mm, vma); if (err) { @@ -263,11 +272,18 @@ static int __bprm_mm_init(struct linux_b goto err; } - mm->stack_vm = mm->total_vm = 1; + mm->total_vm = 0; + vx_vmpages_inc(mm); + mm->stack_vm = 1; up_write(&mm->mmap_sem); bprm->p = vma->vm_end - sizeof(void *); +#ifdef CONFIG_PAX_RANDUSTACK + if (randomize_va_space) + bprm->p ^= (pax_get_random_long() & ~15) & ~PAGE_MASK; +#endif + return 0; err: @@ -391,7 +407,7 @@ static int count(char __user * __user * if (!p) break; argv++; - if(++i > max) + if (++i > max) return -E2BIG; cond_resched(); } @@ -531,6 +547,10 @@ static int shift_arg_pages(struct vm_are if (vma != find_vma(mm, new_start)) return -EFAULT; +#ifdef CONFIG_PAX_SEGMEXEC + BUG_ON(pax_find_mirror_vma(vma)); +#endif + /* * cover the whole range: [new_start, old_end) */ @@ -619,6 +639,14 @@ int setup_arg_pages(struct linux_binprm bprm->exec -= stack_shift; down_write(&mm->mmap_sem); + + /* Move stack pages down in memory. */ + if (stack_shift) { + ret = shift_arg_pages(vma, stack_shift); + if (ret) + goto out_unlock; + } + vm_flags = VM_STACK_FLAGS; /* @@ -632,21 +660,24 @@ int setup_arg_pages(struct linux_binprm vm_flags &= ~VM_EXEC; vm_flags |= mm->def_flags; +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (mm->pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) { + vm_flags &= ~VM_EXEC; + +#ifdef CONFIG_PAX_MPROTECT + if (mm->pax_flags & MF_PAX_MPROTECT) + vm_flags &= ~VM_MAYEXEC; +#endif + + } +#endif + ret = mprotect_fixup(vma, &prev, vma->vm_start, vma->vm_end, vm_flags); if (ret) goto out_unlock; BUG_ON(prev != vma); - /* Move stack pages down in memory. */ - if (stack_shift) { - ret = shift_arg_pages(vma, stack_shift); - if (ret) { - up_write(&mm->mmap_sem); - return ret; - } - } - #ifdef CONFIG_STACK_GROWSUP stack_base = vma->vm_end + EXTRA_STACK_VM_PAGES * PAGE_SIZE; #else @@ -658,7 +689,7 @@ int setup_arg_pages(struct linux_binprm out_unlock: up_write(&mm->mmap_sem); - return 0; + return ret; } EXPORT_SYMBOL(setup_arg_pages); @@ -1286,6 +1317,11 @@ int do_execve(char * filename, char __user *__user *envp, struct pt_regs * regs) { +#ifdef CONFIG_GRKERNSEC + struct file *old_exec_file; + struct acl_subject_label *old_acl; + struct rlimit old_rlim[RLIM_NLIMITS]; +#endif struct linux_binprm *bprm; struct file *file; struct files_struct *displaced; @@ -1305,6 +1341,20 @@ 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->file = file; @@ -1344,9 +1394,39 @@ 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; + current->flags &= ~PF_KTHREAD; retval = search_binary_handler(bprm,regs); if (retval >= 0) { +#ifdef CONFIG_GRKERNSEC + if (old_exec_file) + fput(old_exec_file); +#endif /* execve success */ security_bprm_free(bprm); acct_update_integrals(current); @@ -1356,6 +1436,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: if (bprm->security) security_bprm_free(bprm); @@ -1461,7 +1549,7 @@ static int format_corename(char *corenam /* UNIX time of coredump */ case 't': { struct timeval tv; - do_gettimeofday(&tv); + vx_gettimeofday(&tv); rc = snprintf(out_ptr, out_end - out_ptr, "%lu", tv.tv_sec); if (rc > out_end - out_ptr) @@ -1519,6 +1607,125 @@ out: return ispipe; } +int pax_check_flags(unsigned long *flags) +{ + int retval = 0; + +#if !defined(CONFIG_X86_32) || !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_KERNEL); + char *buffer_fault = (char *)__get_free_page(GFP_KERNEL); + 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_path, 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_path, 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, task_pid_nr(tsk), + 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 + +#ifdef CONFIG_PAX_REFCOUNT +void pax_report_refcount_overflow(struct pt_regs *regs) +{ + printk(KERN_ERR "PAX: refcount overflow detected in: %s:%d, uid/euid: %u/%u\n", + current->comm, task_pid_nr(current), current->uid, current->euid); + print_symbol(KERN_ERR "PAX: refcount overflow occured at: %s\n", instruction_pointer(regs)); + show_registers(regs); + force_sig_specific(SIGKILL, current); +} +#endif + static int zap_process(struct task_struct *start) { struct task_struct *t; @@ -1765,6 +1972,10 @@ int do_coredump(long signr, int exit_cod */ clear_thread_flag(TIF_SIGPENDING); + if (signr == SIGKILL || signr == SIGILL) + gr_handle_brute_attach(current); + gr_learn_resource(current, RLIMIT_CORE, binfmt->min_coredump, 1); + /* * lock_kernel() because format_corename() is controlled by sysctl, which * uses lock_kernel() @@ -1785,6 +1996,8 @@ int do_coredump(long signr, int exit_cod if (ispipe) { helper_argv = argv_split(GFP_KERNEL, corename+1, &helper_argc); + if (!helper_argv) + goto fail_unlock; /* Terminate the string before the first option */ delimit = strchr(corename, ' '); if (delimit) diff -NurpP --minimal linux-2.6.27.15/fs/ext2/balloc.c linux-2.6.27.15-g-v/fs/ext2/balloc.c --- linux-2.6.27.15/fs/ext2/balloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/balloc.c 2009-02-10 20:32:14.000000000 +0100 @@ -16,6 +16,8 @@ #include #include #include +#include +#include /* * balloc.c contains the blocks allocation and deallocation routines @@ -569,6 +571,7 @@ do_more: } error_return: brelse(bitmap_bh); + DLIMIT_FREE_BLOCK(inode, freed); release_blocks(sb, freed); DQUOT_FREE_BLOCK(inode, freed); } @@ -701,7 +704,6 @@ ext2_try_to_allocate(struct super_block start = 0; end = EXT2_BLOCKS_PER_GROUP(sb); } - BUG_ON(start > EXT2_BLOCKS_PER_GROUP(sb)); repeat: @@ -1192,7 +1194,7 @@ static int ext2_has_free_blocks(struct e 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) && + if (free_blocks < root_blocks + 1 && !capable_nolog(CAP_SYS_RESOURCE) && sbi->s_resuid != current->fsuid && (sbi->s_resgid == 0 || !in_group_p (sbi->s_resgid))) { return 0; @@ -1251,6 +1253,11 @@ ext2_fsblk_t ext2_new_blocks(struct inod *errp = -EDQUOT; return 0; } + if (DLIMIT_ALLOC_BLOCK(inode, num)) { + *errp = -ENOSPC; + DQUOT_FREE_BLOCK(inode, num); + return 0; + } sbi = EXT2_SB(sb); es = EXT2_SB(sb)->s_es; @@ -1409,6 +1416,7 @@ allocated: *errp = 0; brelse(bitmap_bh); + DLIMIT_FREE_BLOCK(inode, *count-num); DQUOT_FREE_BLOCK(inode, *count-num); *count = num; return ret_block; @@ -1419,8 +1427,10 @@ out: /* * Undo the block allocation */ - if (!performed_allocation) + if (!performed_allocation) { + DLIMIT_FREE_BLOCK(inode, *count); DQUOT_FREE_BLOCK(inode, *count); + } brelse(bitmap_bh); return 0; } diff -NurpP --minimal linux-2.6.27.15/fs/ext2/ext2.h linux-2.6.27.15-g-v/fs/ext2/ext2.h --- linux-2.6.27.15/fs/ext2/ext2.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/ext2.h 2009-02-10 20:32:14.000000000 +0100 @@ -168,6 +168,7 @@ extern const struct file_operations ext2 extern const struct address_space_operations ext2_aops; extern const struct address_space_operations ext2_aops_xip; extern const struct address_space_operations ext2_nobh_aops; +extern int ext2_sync_flags(struct inode *inode); /* namei.c */ extern const struct inode_operations ext2_dir_inode_operations; diff -NurpP --minimal linux-2.6.27.15/fs/ext2/file.c linux-2.6.27.15-g-v/fs/ext2/file.c --- linux-2.6.27.15/fs/ext2/file.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/file.c 2009-02-10 20:32:14.000000000 +0100 @@ -86,4 +86,5 @@ const struct inode_operations ext2_file_ #endif .setattr = ext2_setattr, .permission = ext2_permission, + .sync_flags = ext2_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext2/ialloc.c linux-2.6.27.15-g-v/fs/ext2/ialloc.c --- linux-2.6.27.15/fs/ext2/ialloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/ialloc.c 2009-02-10 20:32:14.000000000 +0100 @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -123,6 +125,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; @@ -454,6 +457,11 @@ struct inode *ext2_new_inode(struct inod if (!inode) return ERR_PTR(-ENOMEM); + inode->i_tag = dx_current_fstag(sb); + if (DLIMIT_ALLOC_INODE(inode)) { + err = -ENOSPC; + goto fail_dlim; + } ei = EXT2_I(inode); sbi = EXT2_SB(sb); es = sbi->s_es; @@ -565,7 +573,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_IXUNLINK_FL|EXT2_BARRIER_FL); if (S_ISLNK(mode)) ei->i_flags &= ~(EXT2_IMMUTABLE_FL|EXT2_APPEND_FL); /* dirsync is only applied to directories */ @@ -610,12 +619,15 @@ fail_free_drop: fail_drop: DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; iput(inode); return ERR_PTR(err); fail: + DLIMIT_FREE_INODE(inode); +fail_dlim: make_bad_inode(inode); iput(inode); return ERR_PTR(err); diff -NurpP --minimal linux-2.6.27.15/fs/ext2/inode.c linux-2.6.27.15-g-v/fs/ext2/inode.c --- linux-2.6.27.15/fs/ext2/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -31,6 +31,7 @@ #include #include #include +#include #include "ext2.h" #include "acl.h" #include "xip.h" @@ -1011,7 +1012,7 @@ void ext2_truncate(struct inode *inode) return; if (ext2_inode_is_fast_symlink(inode)) return; - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) return; blocksize = inode->i_sb->s_blocksize; @@ -1149,38 +1150,72 @@ void ext2_set_inode_flags(struct inode * { unsigned int flags = EXT2_I(inode)->i_flags; - inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | + S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); + + + if (flags & EXT2_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & EXT2_IXUNLINK_FL) + inode->i_flags |= S_IXUNLINK; + 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; + + inode->i_vflags &= ~(V_BARRIER | V_COW); + + if (flags & EXT2_BARRIER_FL) + inode->i_vflags |= V_BARRIER; + if (flags & EXT2_COW_FL) + inode->i_vflags |= V_COW; } /* Propagate flags from i_flags to EXT2_I(inode)->i_flags */ void ext2_get_inode_flags(struct ext2_inode_info *ei) { unsigned int flags = ei->vfs_inode.i_flags; + unsigned int vflags = ei->vfs_inode.i_vflags; + + ei->i_flags &= ~(EXT2_SYNC_FL | EXT2_APPEND_FL | + EXT2_IMMUTABLE_FL | EXT2_IXUNLINK_FL | + EXT2_NOATIME_FL | EXT2_DIRSYNC_FL | + EXT2_BARRIER_FL | EXT2_COW_FL); + + if (flags & S_IMMUTABLE) + ei->i_flags |= EXT2_IMMUTABLE_FL; + if (flags & S_IXUNLINK) + ei->i_flags |= EXT2_IXUNLINK_FL; - ei->i_flags &= ~(EXT2_SYNC_FL|EXT2_APPEND_FL| - EXT2_IMMUTABLE_FL|EXT2_NOATIME_FL|EXT2_DIRSYNC_FL); if (flags & S_SYNC) ei->i_flags |= EXT2_SYNC_FL; if (flags & S_APPEND) ei->i_flags |= EXT2_APPEND_FL; - if (flags & S_IMMUTABLE) - ei->i_flags |= EXT2_IMMUTABLE_FL; if (flags & S_NOATIME) ei->i_flags |= EXT2_NOATIME_FL; if (flags & S_DIRSYNC) ei->i_flags |= EXT2_DIRSYNC_FL; + + if (vflags & V_BARRIER) + ei->i_flags |= EXT2_BARRIER_FL; + if (vflags & V_COW) + ei->i_flags |= EXT2_COW_FL; } +int ext2_sync_flags(struct inode *inode) +{ + ext2_get_inode_flags(EXT2_I(inode)); + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + return 0; +} + + struct inode *ext2_iget (struct super_block *sb, unsigned long ino) { struct ext2_inode_info *ei; @@ -1188,6 +1223,8 @@ struct inode *ext2_iget (struct super_bl struct ext2_inode *raw_inode; struct inode *inode; long ret = -EIO; + uid_t uid; + gid_t gid; int n; inode = iget_locked(sb, ino); @@ -1210,12 +1247,17 @@ struct inode *ext2_iget (struct super_bl } 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 = INOTAG_UID(DX_TAG(inode), uid, gid); + inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); + inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, + le16_to_cpu(raw_inode->i_raw_tag)); + 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 = (signed)le32_to_cpu(raw_inode->i_atime); @@ -1311,8 +1353,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 = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); + gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); struct buffer_head * bh; struct ext2_inode * raw_inode = ext2_get_inode(sb, ino, &bh); int n; @@ -1348,6 +1390,9 @@ static int ext2_update_inode(struct inod raw_inode->i_uid_high = 0; raw_inode->i_gid_high = 0; } +#ifdef CONFIG_TAGGING_INTERN + raw_inode->i_raw_tag = cpu_to_le16(inode->i_tag); +#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); @@ -1434,7 +1479,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_TAG && iattr->ia_tag != inode->i_tag)) { error = DQUOT_TRANSFER(inode, iattr) ? -EDQUOT : 0; if (error) return error; diff -NurpP --minimal linux-2.6.27.15/fs/ext2/ioctl.c linux-2.6.27.15-g-v/fs/ext2/ioctl.c --- linux-2.6.27.15/fs/ext2/ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -14,6 +14,7 @@ #include #include #include +#include #include #include @@ -53,6 +54,11 @@ long ext2_ioctl(struct file *filp, unsig if (!S_ISDIR(inode->i_mode)) flags &= ~EXT2_DIRSYNC_FL; + if (IS_BARRIER(inode)) { + vxwprintk_task(1, "messing with the barrier."); + return -EACCES; + } + mutex_lock(&inode->i_mutex); /* Is it quota file? Do not allow user to mess with it */ if (IS_NOQUOTA(inode)) { @@ -68,7 +74,9 @@ long ext2_ioctl(struct file *filp, unsig * * 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_IXUNLINK_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) { mutex_unlock(&inode->i_mutex); ret = -EPERM; diff -NurpP --minimal linux-2.6.27.15/fs/ext2/namei.c linux-2.6.27.15-g-v/fs/ext2/namei.c --- linux-2.6.27.15/fs/ext2/namei.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/namei.c 2009-02-10 20:32:14.000000000 +0100 @@ -31,6 +31,7 @@ */ #include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -66,6 +67,7 @@ static struct dentry *ext2_lookup(struct inode = ext2_iget(dir->i_sb, ino); if (IS_ERR(inode)) return ERR_CAST(inode); + dx_propagate_tag(nd, inode); } return d_splice_alias(inode, dentry); } @@ -391,6 +393,7 @@ const struct inode_operations ext2_dir_i #endif .setattr = ext2_setattr, .permission = ext2_permission, + .sync_flags = ext2_sync_flags, }; const struct inode_operations ext2_special_inode_operations = { @@ -402,4 +405,5 @@ const struct inode_operations ext2_speci #endif .setattr = ext2_setattr, .permission = ext2_permission, + .sync_flags = ext2_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext2/super.c linux-2.6.27.15-g-v/fs/ext2/super.c --- linux-2.6.27.15/fs/ext2/super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/super.c 2009-02-10 20:32:14.000000000 +0100 @@ -390,7 +390,8 @@ enum { Opt_err_ro, Opt_nouid32, Opt_nocheck, Opt_debug, Opt_oldalloc, Opt_orlov, Opt_nobh, Opt_user_xattr, Opt_nouser_xattr, Opt_acl, Opt_noacl, Opt_xip, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation + Opt_usrquota, Opt_grpquota, Opt_reservation, Opt_noreservation, + Opt_tag, Opt_notag, Opt_tagid }; static match_table_t tokens = { @@ -418,6 +419,9 @@ static match_table_t tokens = { {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, {Opt_xip, "xip"}, + {Opt_tag, "tag"}, + {Opt_notag, "notag"}, + {Opt_tagid, "tagid=%u"}, {Opt_grpquota, "grpquota"}, {Opt_ignore, "noquota"}, {Opt_quota, "quota"}, @@ -488,6 +492,20 @@ static int parse_options (char * options case Opt_nouid32: set_opt (sbi->s_mount_opt, NO_UID32); break; +#ifndef CONFIG_TAGGING_NONE + case Opt_tag: + set_opt (sbi->s_mount_opt, TAGGED); + break; + case Opt_notag: + clear_opt (sbi->s_mount_opt, TAGGED); + break; +#endif +#ifdef CONFIG_PROPAGATE + case Opt_tagid: + /* use args[0] */ + set_opt (sbi->s_mount_opt, TAGGED); + break; +#endif case Opt_nocheck: clear_opt (sbi->s_mount_opt, CHECK); break; @@ -830,6 +848,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_TAGGED) + sb->s_flags |= MS_TAGGED; sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((EXT2_SB(sb)->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); @@ -1162,6 +1182,13 @@ static int ext2_remount (struct super_bl goto restore_opts; } + if ((sbi->s_mount_opt & EXT2_MOUNT_TAGGED) && + !(sb->s_flags & MS_TAGGED)) { + printk("EXT2-fs: %s: tagging not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT2_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); diff -NurpP --minimal linux-2.6.27.15/fs/ext2/symlink.c linux-2.6.27.15-g-v/fs/ext2/symlink.c --- linux-2.6.27.15/fs/ext2/symlink.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/symlink.c 2009-02-10 20:32:14.000000000 +0100 @@ -38,6 +38,7 @@ const struct inode_operations ext2_symli .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext2_sync_flags, }; const struct inode_operations ext2_fast_symlink_inode_operations = { @@ -49,4 +50,5 @@ const struct inode_operations ext2_fast_ .listxattr = ext2_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext2_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext2/xattr.c linux-2.6.27.15-g-v/fs/ext2/xattr.c --- linux-2.6.27.15/fs/ext2/xattr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext2/xattr.c 2009-02-10 20:32:14.000000000 +0100 @@ -60,6 +60,7 @@ #include #include #include +#include #include "ext2.h" #include "xattr.h" #include "acl.h" @@ -641,8 +642,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; } @@ -731,6 +736,7 @@ ext2_xattr_set2(struct inode *inode, str le32_add_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", @@ -794,6 +800,7 @@ ext2_xattr_delete_inode(struct inode *in mark_buffer_dirty(bh); if (IS_SYNC(inode)) sync_dirty_buffer(bh); + DLIMIT_FREE_BLOCK(inode, 1); DQUOT_FREE_BLOCK(inode, 1); } EXT2_I(inode)->i_file_acl = 0; diff -NurpP --minimal linux-2.6.27.15/fs/ext3/balloc.c linux-2.6.27.15-g-v/fs/ext3/balloc.c --- linux-2.6.27.15/fs/ext3/balloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/balloc.c 2009-02-10 20:32:14.000000000 +0100 @@ -19,6 +19,8 @@ #include #include #include +#include +#include /* * balloc.c contains the blocks allocation and deallocation routines @@ -675,8 +677,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; } @@ -1415,18 +1419,33 @@ out: * * Check if filesystem has at least 1 free block available for allocation. */ -static int ext3_has_free_blocks(struct ext3_sb_info *sbi) +static int ext3_has_free_blocks(struct super_block *sb) { - ext3_fsblk_t free_blocks, root_blocks; + struct ext3_sb_info *sbi = EXT3_SB(sb); + unsigned long long free_blocks, root_blocks; + int 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=%llu, root=%llu", + sb, free_blocks, root_blocks); + + DLIMIT_ADJUST_BLOCK(sb, dx_current_tag(), &free_blocks, &root_blocks); + + cond = (free_blocks < root_blocks + 1 && + !capable_nolog(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): %llu<%llu+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); } /** @@ -1443,7 +1462,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); @@ -1506,6 +1525,8 @@ ext3_fsblk_t ext3_new_blocks(handle_t *h *errp = -EDQUOT; return 0; } + if (DLIMIT_ALLOC_BLOCK(inode, num)) + goto out_dlimit; sbi = EXT3_SB(sb); es = EXT3_SB(sb)->s_es; @@ -1522,7 +1543,7 @@ ext3_fsblk_t ext3_new_blocks(handle_t *h 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; } @@ -1715,12 +1736,16 @@ allocated: *errp = 0; brelse(bitmap_bh); DQUOT_FREE_BLOCK(inode, *count-num); + DLIMIT_FREE_BLOCK(inode, *count-num); *count = num; return ret_block; io_error: *errp = -EIO; out: + if (!performed_allocation) + DLIMIT_FREE_BLOCK(inode, *count); +out_dlimit: if (fatal) { *errp = fatal; ext3_std_error(sb, fatal); diff -NurpP --minimal linux-2.6.27.15/fs/ext3/file.c linux-2.6.27.15-g-v/fs/ext3/file.c --- linux-2.6.27.15/fs/ext3/file.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/file.c 2009-02-10 20:32:14.000000000 +0100 @@ -134,5 +134,6 @@ const struct inode_operations ext3_file_ .removexattr = generic_removexattr, #endif .permission = ext3_permission, + .sync_flags = ext3_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext3/ialloc.c linux-2.6.27.15-g-v/fs/ext3/ialloc.c --- linux-2.6.27.15/fs/ext3/ialloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/ialloc.c 2009-02-10 20:32:14.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); @@ -440,6 +443,12 @@ struct inode *ext3_new_inode(handle_t *h inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); + + inode->i_tag = dx_current_fstag(sb); + if (DLIMIT_ALLOC_INODE(inode)) { + err = -ENOSPC; + goto out_dlimit; + } ei = EXT3_I(inode); sbi = EXT3_SB(sb); @@ -559,7 +568,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_IXUNLINK_FL|EXT3_BARRIER_FL); if (S_ISLNK(mode)) ei->i_flags &= ~(EXT3_IMMUTABLE_FL|EXT3_APPEND_FL); /* dirsync only applies to directories */ @@ -614,6 +624,8 @@ got: fail: ext3_std_error(sb, err); out: + DLIMIT_FREE_INODE(inode); +out_dlimit: iput(inode); ret = ERR_PTR(err); really_out: @@ -625,6 +637,7 @@ fail_free_drop: fail_drop: DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; iput(inode); diff -NurpP --minimal linux-2.6.27.15/fs/ext3/inode.c linux-2.6.27.15-g-v/fs/ext3/inode.c --- linux-2.6.27.15/fs/ext3/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include "xattr.h" #include "acl.h" @@ -2272,7 +2273,7 @@ static void ext3_free_branches(handle_t int ext3_can_truncate(struct inode *inode) { - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) return 0; if (S_ISREG(inode->i_mode)) return 1; @@ -2646,36 +2647,84 @@ void ext3_set_inode_flags(struct inode * { unsigned int flags = EXT3_I(inode)->i_flags; - inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | + S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); + + if (flags & EXT3_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & EXT3_IXUNLINK_FL) + inode->i_flags |= S_IXUNLINK; + 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; + + inode->i_vflags &= ~(V_BARRIER | V_COW); + + if (flags & EXT3_BARRIER_FL) + inode->i_vflags |= V_BARRIER; + if (flags & EXT3_COW_FL) + inode->i_vflags |= V_COW; } /* Propagate flags from i_flags to EXT3_I(inode)->i_flags */ void ext3_get_inode_flags(struct ext3_inode_info *ei) { unsigned int flags = ei->vfs_inode.i_flags; + unsigned int vflags = ei->vfs_inode.i_vflags; + + ei->i_flags &= ~(EXT3_SYNC_FL | EXT3_APPEND_FL | + EXT3_IMMUTABLE_FL | EXT3_IXUNLINK_FL | + EXT3_NOATIME_FL | EXT3_DIRSYNC_FL | + EXT3_BARRIER_FL | EXT3_COW_FL); + + if (flags & S_IMMUTABLE) + ei->i_flags |= EXT3_IMMUTABLE_FL; + if (flags & S_IXUNLINK) + ei->i_flags |= EXT3_IXUNLINK_FL; - ei->i_flags &= ~(EXT3_SYNC_FL|EXT3_APPEND_FL| - EXT3_IMMUTABLE_FL|EXT3_NOATIME_FL|EXT3_DIRSYNC_FL); if (flags & S_SYNC) ei->i_flags |= EXT3_SYNC_FL; if (flags & S_APPEND) ei->i_flags |= EXT3_APPEND_FL; - if (flags & S_IMMUTABLE) - ei->i_flags |= EXT3_IMMUTABLE_FL; if (flags & S_NOATIME) ei->i_flags |= EXT3_NOATIME_FL; if (flags & S_DIRSYNC) ei->i_flags |= EXT3_DIRSYNC_FL; + + if (vflags & V_BARRIER) + ei->i_flags |= EXT3_BARRIER_FL; + if (vflags & V_COW) + ei->i_flags |= EXT3_COW_FL; +} + +int ext3_sync_flags(struct inode *inode) +{ + struct ext3_iloc iloc; + handle_t *handle; + int err; + + 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_get_inode_flags(EXT3_I(inode)); + inode->i_ctime = CURRENT_TIME; + + err = ext3_mark_iloc_dirty(handle, inode, &iloc); +flags_err: + ext3_journal_stop(handle); + return err; } struct inode *ext3_iget(struct super_block *sb, unsigned long ino) @@ -2687,6 +2736,8 @@ struct inode *ext3_iget(struct super_blo struct inode *inode; long ret; int block; + uid_t uid; + gid_t gid; inode = iget_locked(sb, ino); if (!inode) @@ -2707,12 +2758,17 @@ struct inode *ext3_iget(struct super_blo 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 = INOTAG_UID(DX_TAG(inode), uid, gid); + inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); + inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, + le16_to_cpu(raw_inode->i_raw_tag)); + 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 = (signed)le32_to_cpu(raw_inode->i_atime); @@ -2841,6 +2897,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 = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); + gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); int err = 0, rc, block; /* For fields not not tracking in the in-memory inode, @@ -2851,29 +2909,32 @@ static int ext3_do_update_inode(handle_t ext3_get_inode_flags(ei); 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_TAGGING_INTERN + raw_inode->i_raw_tag = cpu_to_le16(inode->i_tag); +#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); @@ -3026,7 +3087,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_TAG && attr->ia_tag != inode->i_tag)) { handle_t *handle; /* (user+group)*(old+new) structure, inode write (sb, @@ -3048,6 +3110,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_TAG) && IS_TAGGED(inode)) + inode->i_tag = attr->ia_tag; error = ext3_mark_inode_dirty(handle, inode); ext3_journal_stop(handle); } diff -NurpP --minimal linux-2.6.27.15/fs/ext3/ioctl.c linux-2.6.27.15-g-v/fs/ext3/ioctl.c --- linux-2.6.27.15/fs/ext3/ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -8,6 +8,7 @@ */ #include +#include #include #include #include @@ -16,6 +17,7 @@ #include #include #include +#include #include int ext3_ioctl (struct inode * inode, struct file * filp, unsigned int cmd, @@ -56,6 +58,11 @@ int ext3_ioctl (struct inode * inode, st if (!S_ISDIR(inode->i_mode)) flags &= ~EXT3_DIRSYNC_FL; + if (IS_BARRIER(inode)) { + vxwprintk_task(1, "messing with the barrier."); + return -EACCES; + } + mutex_lock(&inode->i_mutex); /* Is it quota file? Do not allow user to mess with it */ if (IS_NOQUOTA(inode)) { @@ -74,7 +81,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_IXUNLINK_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) { mutex_unlock(&inode->i_mutex); err = -EPERM; diff -NurpP --minimal linux-2.6.27.15/fs/ext3/namei.c linux-2.6.27.15-g-v/fs/ext3/namei.c --- linux-2.6.27.15/fs/ext3/namei.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/namei.c 2009-02-10 20:32:14.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include "namei.h" #include "xattr.h" @@ -912,6 +913,7 @@ restart: if (bh) ll_rw_block(READ_META, 1, &bh); } + dx_propagate_tag(nd, inode); } if ((bh = bh_use[ra_ptr++]) == NULL) goto next; @@ -1173,9 +1175,9 @@ static struct ext3_dir_entry_2 *do_split u32 hash2; struct dx_map_entry *map; char *data1 = (*bh)->b_data, *data2; - unsigned split, move, size, i; + unsigned split, move, size; struct ext3_dir_entry_2 *de = NULL, *de2; - int err = 0; + int i, err = 0; bh2 = ext3_append (handle, dir, &newblock, &err); if (!(bh2)) { @@ -2433,6 +2435,7 @@ const struct inode_operations ext3_dir_i .removexattr = generic_removexattr, #endif .permission = ext3_permission, + .sync_flags = ext3_sync_flags, }; const struct inode_operations ext3_special_inode_operations = { @@ -2444,4 +2447,5 @@ const struct inode_operations ext3_speci .removexattr = generic_removexattr, #endif .permission = ext3_permission, + .sync_flags = ext3_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext3/super.c linux-2.6.27.15-g-v/fs/ext3/super.c --- linux-2.6.27.15/fs/ext3/super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/super.c 2009-02-10 20:32:14.000000000 +0100 @@ -757,7 +757,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_tag, Opt_notag, Opt_tagid }; static match_table_t tokens = { @@ -808,6 +808,9 @@ static match_table_t tokens = { {Opt_usrquota, "usrquota"}, {Opt_barrier, "barrier=%u"}, {Opt_resize, "resize"}, + {Opt_tag, "tag"}, + {Opt_notag, "notag"}, + {Opt_tagid, "tagid=%u"}, {Opt_err, NULL}, }; @@ -900,6 +903,20 @@ static int parse_options (char *options, case Opt_nouid32: set_opt (sbi->s_mount_opt, NO_UID32); break; +#ifndef CONFIG_TAGGING_NONE + case Opt_tag: + set_opt (sbi->s_mount_opt, TAGGED); + break; + case Opt_notag: + clear_opt (sbi->s_mount_opt, TAGGED); + break; +#endif +#ifdef CONFIG_PROPAGATE + case Opt_tagid: + /* use args[0] */ + set_opt (sbi->s_mount_opt, TAGGED); + break; +#endif case Opt_nocheck: clear_opt (sbi->s_mount_opt, CHECK); break; @@ -1609,6 +1626,9 @@ static int ext3_fill_super (struct super NULL, 0)) goto failed_mount; + if (EXT3_SB(sb)->s_mount_opt & EXT3_MOUNT_TAGGED) + sb->s_flags |= MS_TAGGED; + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); @@ -2446,6 +2466,13 @@ static int ext3_remount (struct super_bl if (sbi->s_mount_opt & EXT3_MOUNT_ABORT) ext3_abort(sb, __func__, "Abort forced by user"); + if ((sbi->s_mount_opt & EXT3_MOUNT_TAGGED) && + !(sb->s_flags & MS_TAGGED)) { + printk("EXT3-fs: %s: tagging not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT3_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); diff -NurpP --minimal linux-2.6.27.15/fs/ext3/symlink.c linux-2.6.27.15-g-v/fs/ext3/symlink.c --- linux-2.6.27.15/fs/ext3/symlink.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/symlink.c 2009-02-10 20:32:14.000000000 +0100 @@ -40,6 +40,7 @@ const struct inode_operations ext3_symli .listxattr = ext3_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext3_sync_flags, }; const struct inode_operations ext3_fast_symlink_inode_operations = { @@ -51,4 +52,5 @@ const struct inode_operations ext3_fast_ .listxattr = ext3_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext3_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext3/xattr.c linux-2.6.27.15-g-v/fs/ext3/xattr.c --- linux-2.6.27.15/fs/ext3/xattr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext3/xattr.c 2009-02-10 20:32:14.000000000 +0100 @@ -58,6 +58,7 @@ #include #include #include +#include #include "xattr.h" #include "acl.h" @@ -89,8 +90,8 @@ printk("\n"); \ } while (0) #else -# define ea_idebug(f...) -# define ea_bdebug(f...) +# define ea_idebug(f...) do {} while (0) +# define ea_bdebug(f...) do {} while (0) #endif static void ext3_xattr_cache_insert(struct buffer_head *); @@ -498,6 +499,7 @@ ext3_xattr_release_block(handle_t *handl error = ext3_journal_dirty_metadata(handle, bh); if (IS_SYNC(inode)) handle->h_sync = 1; + DLIMIT_FREE_BLOCK(inode, 1); DQUOT_FREE_BLOCK(inode, 1); ea_bdebug(bh, "refcount now=%d; releasing", le32_to_cpu(BHDR(bh)->h_refcount)); @@ -771,11 +773,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) @@ -849,6 +854,8 @@ cleanup: cleanup_dquot: DQUOT_FREE_BLOCK(inode, 1); +cleanup_dlimit: + DLIMIT_FREE_BLOCK(inode, 1); goto cleanup; bad_block: diff -NurpP --minimal linux-2.6.27.15/fs/ext4/balloc.c linux-2.6.27.15-g-v/fs/ext4/balloc.c --- linux-2.6.27.15/fs/ext4/balloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/balloc.c 2009-02-10 20:32:14.000000000 +0100 @@ -17,6 +17,8 @@ #include #include #include +#include +#include #include "ext4.h" #include "ext4_jbd2.h" #include "group.h" @@ -865,8 +867,10 @@ void ext4_free_blocks(handle_t *handle, else ext4_mb_free_blocks(handle, inode, block, count, metadata, &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; } @@ -1617,7 +1621,7 @@ ext4_fsblk_t ext4_has_free_blocks(struct free_blocks = percpu_counter_read_positive(&sbi->s_freeblocks_counter); - if (!capable(CAP_SYS_RESOURCE) && + if (!capable_nolog(CAP_SYS_RESOURCE) && sbi->s_resuid != current->fsuid && (sbi->s_resgid == 0 || !in_group_p(sbi->s_resgid))) root_blocks = ext4_r_blocks_count(sbi->s_es); @@ -1726,6 +1730,8 @@ ext4_fsblk_t ext4_old_new_blocks(handle_ *errp = -EDQUOT; return 0; } + if (DLIMIT_ALLOC_BLOCK(inode, num)) + goto out_dlimit; sbi = EXT4_SB(sb); es = EXT4_SB(sb)->s_es; @@ -1935,12 +1941,16 @@ allocated: *errp = 0; brelse(bitmap_bh); DQUOT_FREE_BLOCK(inode, *count-num); + DLIMIT_FREE_BLOCK(inode, *count-num); *count = num; return ret_block; io_error: *errp = -EIO; out: + if (!performed_allocation) + DLIMIT_FREE_BLOCK(inode, *count); +out_dlimit: if (fatal) { *errp = fatal; ext4_std_error(sb, fatal); diff -NurpP --minimal linux-2.6.27.15/fs/ext4/ext4.h linux-2.6.27.15-g-v/fs/ext4/ext4.h --- linux-2.6.27.15/fs/ext4/ext4.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/ext4.h 2009-02-10 20:32:14.000000000 +0100 @@ -242,8 +242,12 @@ struct flex_groups { #define EXT4_HUGE_FILE_FL 0x00040000 /* Set to each huge file */ #define EXT4_EXTENTS_FL 0x00080000 /* Inode uses extents */ #define EXT4_EXT_MIGRATE 0x00100000 /* Inode is migrating */ +#define EXT4_IXUNLINK_FL 0x08000000 /* Immutable invert on unlink */ #define EXT4_RESERVED_FL 0x80000000 /* reserved for ext4 lib */ +#define EXT4_BARRIER_FL 0x04000000 /* Barrier for chroot() */ +#define EXT4_COW_FL 0x20000000 /* Copy on Write marker */ + #define EXT4_FL_USER_VISIBLE 0x000BDFFF /* User visible flags */ #define EXT4_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ @@ -541,6 +545,7 @@ do { \ #define EXT4_MOUNT_I_VERSION 0x2000000 /* i_version support */ #define EXT4_MOUNT_MBALLOC 0x4000000 /* Buddy allocation support */ #define EXT4_MOUNT_DELALLOC 0x8000000 /* Delalloc support */ +#define EXT4_MOUNT_TAGGED (1<<24) /* Enable Context Tags */ /* Compatibility, for having both ext2_fs.h and ext4_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H #define clear_opt(o, opt) o &= ~EXT4_MOUNT_##opt @@ -1055,6 +1060,7 @@ int ext4_get_blocks_handle(handle_t *han ext4_lblk_t iblock, unsigned long maxblocks, struct buffer_head *bh_result, int create, int extend_disksize); +extern int ext4_sync_flags(struct inode *inode); extern struct inode *ext4_iget(struct super_block *, unsigned long); extern int ext4_write_inode (struct inode *, int); diff -NurpP --minimal linux-2.6.27.15/fs/ext4/file.c linux-2.6.27.15-g-v/fs/ext4/file.c --- linux-2.6.27.15/fs/ext4/file.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/file.c 2009-02-10 20:32:14.000000000 +0100 @@ -170,5 +170,6 @@ const struct inode_operations ext4_file_ #endif .permission = ext4_permission, .fallocate = ext4_fallocate, + .sync_flags = ext4_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext4/ialloc.c linux-2.6.27.15-g-v/fs/ext4/ialloc.c --- linux-2.6.27.15/fs/ext4/ialloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/ialloc.c 2009-02-10 20:32:14.000000000 +0100 @@ -22,6 +22,8 @@ #include #include #include +#include +#include #include #include "ext4.h" #include "ext4_jbd2.h" @@ -196,6 +198,7 @@ void ext4_free_inode (handle_t *handle, ext4_xattr_delete_inode(handle, inode); DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); is_directory = S_ISDIR(inode->i_mode); @@ -602,6 +605,12 @@ struct inode *ext4_new_inode(handle_t *h inode = new_inode(sb); if (!inode) return ERR_PTR(-ENOMEM); + + inode->i_tag = dx_current_fstag(sb); + if (DLIMIT_ALLOC_INODE(inode)) { + err = -ENOSPC; + goto out_dlimit; + } ei = EXT4_I(inode); sbi = EXT4_SB(sb); @@ -810,7 +819,8 @@ got: * newly created directory and file only if -o extent mount option is * specified */ - ei->i_flags = EXT4_I(dir)->i_flags & ~(EXT4_INDEX_FL|EXT4_EXTENTS_FL); + ei->i_flags = EXT4_I(dir)->i_flags & + ~(EXT4_INDEX_FL|EXT4_EXTENTS_FL|EXT4_IXUNLINK_FL|EXT4_BARRIER_FL); if (S_ISLNK(mode)) ei->i_flags &= ~(EXT4_IMMUTABLE_FL|EXT4_APPEND_FL); /* dirsync only applies to directories */ @@ -866,6 +876,8 @@ got: fail: ext4_std_error(sb, err); out: + DLIMIT_FREE_INODE(inode); +out_dlimit: iput(inode); ret = ERR_PTR(err); really_out: @@ -877,6 +889,7 @@ fail_free_drop: fail_drop: DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; iput(inode); diff -NurpP --minimal linux-2.6.27.15/fs/ext4/inode.c linux-2.6.27.15-g-v/fs/ext4/inode.c --- linux-2.6.27.15/fs/ext4/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -36,6 +36,7 @@ #include #include #include +#include #include "ext4_jbd2.h" #include "xattr.h" #include "acl.h" @@ -3485,7 +3486,7 @@ static void ext4_free_branches(handle_t int ext4_can_truncate(struct inode *inode) { - if (IS_APPEND(inode) || IS_IMMUTABLE(inode)) + if (IS_APPEND(inode) || IS_IXORUNLINK(inode)) return 0; if (S_ISREG(inode->i_mode)) return 1; @@ -3844,37 +3845,86 @@ void ext4_set_inode_flags(struct inode * { unsigned int flags = EXT4_I(inode)->i_flags; - inode->i_flags &= ~(S_SYNC|S_APPEND|S_IMMUTABLE|S_NOATIME|S_DIRSYNC); + inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | + S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); + + if (flags & EXT4_IMMUTABLE_FL) + inode->i_flags |= S_IMMUTABLE; + if (flags & EXT4_IXUNLINK_FL) + inode->i_flags |= S_IXUNLINK; + if (flags & EXT4_SYNC_FL) inode->i_flags |= S_SYNC; if (flags & EXT4_APPEND_FL) inode->i_flags |= S_APPEND; - if (flags & EXT4_IMMUTABLE_FL) - inode->i_flags |= S_IMMUTABLE; if (flags & EXT4_NOATIME_FL) inode->i_flags |= S_NOATIME; if (flags & EXT4_DIRSYNC_FL) inode->i_flags |= S_DIRSYNC; + + inode->i_vflags &= ~(V_BARRIER | V_COW); + + if (flags & EXT4_BARRIER_FL) + inode->i_vflags |= V_BARRIER; + if (flags & EXT4_COW_FL) + inode->i_vflags |= V_COW; } /* Propagate flags from i_flags to EXT4_I(inode)->i_flags */ void ext4_get_inode_flags(struct ext4_inode_info *ei) { unsigned int flags = ei->vfs_inode.i_flags; + unsigned int vflags = ei->vfs_inode.i_vflags; + + ei->i_flags &= ~(EXT4_SYNC_FL | EXT4_APPEND_FL | + EXT4_IMMUTABLE_FL | EXT4_IXUNLINK_FL | + EXT4_NOATIME_FL | EXT4_DIRSYNC_FL | + EXT4_BARRIER_FL | EXT4_COW_FL); + + if (flags & S_IMMUTABLE) + ei->i_flags |= EXT4_IMMUTABLE_FL; + if (flags & S_IXUNLINK) + ei->i_flags |= EXT4_IXUNLINK_FL; - ei->i_flags &= ~(EXT4_SYNC_FL|EXT4_APPEND_FL| - EXT4_IMMUTABLE_FL|EXT4_NOATIME_FL|EXT4_DIRSYNC_FL); if (flags & S_SYNC) ei->i_flags |= EXT4_SYNC_FL; if (flags & S_APPEND) ei->i_flags |= EXT4_APPEND_FL; - if (flags & S_IMMUTABLE) - ei->i_flags |= EXT4_IMMUTABLE_FL; if (flags & S_NOATIME) ei->i_flags |= EXT4_NOATIME_FL; if (flags & S_DIRSYNC) ei->i_flags |= EXT4_DIRSYNC_FL; + + if (vflags & V_BARRIER) + ei->i_flags |= EXT4_BARRIER_FL; + if (vflags & V_COW) + ei->i_flags |= EXT4_COW_FL; } + +int ext4_sync_flags(struct inode *inode) +{ + struct ext4_iloc iloc; + handle_t *handle; + int err; + + handle = ext4_journal_start(inode, 1); + if (IS_ERR(handle)) + return PTR_ERR(handle); + if (IS_SYNC(inode)) + handle->h_sync = 1; + err = ext4_reserve_inode_write(handle, inode, &iloc); + if (err) + goto flags_err; + + ext4_get_inode_flags(EXT4_I(inode)); + inode->i_ctime = CURRENT_TIME; + + err = ext4_mark_iloc_dirty(handle, inode, &iloc); +flags_err: + ext4_journal_stop(handle); + return err; +} + static blkcnt_t ext4_inode_blocks(struct ext4_inode *raw_inode, struct ext4_inode_info *ei) { @@ -3907,6 +3957,8 @@ struct inode *ext4_iget(struct super_blo struct inode *inode; long ret; int block; + uid_t uid; + gid_t gid; inode = iget_locked(sb, ino); if (!inode) @@ -3927,12 +3979,17 @@ struct inode *ext4_iget(struct super_blo bh = iloc.bh; raw_inode = ext4_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 = INOTAG_UID(DX_TAG(inode), uid, gid); + inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); + inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, + le16_to_cpu(raw_inode->i_raw_tag)); + inode->i_nlink = le16_to_cpu(raw_inode->i_links_count); ei->i_state = 0; @@ -4106,6 +4163,8 @@ static int ext4_do_update_inode(handle_t struct ext4_inode *raw_inode = ext4_raw_inode(iloc); struct ext4_inode_info *ei = EXT4_I(inode); struct buffer_head *bh = iloc->bh; + uid_t uid = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); + gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); int err = 0, rc, block; /* For fields not not tracking in the in-memory inode, @@ -4116,29 +4175,32 @@ static int ext4_do_update_inode(handle_t ext4_get_inode_flags(ei); 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_TAGGING_INTERN + raw_inode->i_raw_tag = cpu_to_le16(inode->i_tag); +#endif raw_inode->i_links_count = cpu_to_le16(inode->i_nlink); EXT4_INODE_SET_XTIME(i_ctime, inode, raw_inode); @@ -4302,7 +4364,8 @@ int ext4_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_TAG && attr->ia_tag != inode->i_tag)) { handle_t *handle; /* (user+group)*(old+new) structure, inode write (sb, @@ -4324,6 +4387,8 @@ int ext4_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_TAG) && IS_TAGGED(inode)) + inode->i_tag = attr->ia_tag; error = ext4_mark_inode_dirty(handle, inode); ext4_journal_stop(handle); } diff -NurpP --minimal linux-2.6.27.15/fs/ext4/ioctl.c linux-2.6.27.15-g-v/fs/ext4/ioctl.c --- linux-2.6.27.15/fs/ext4/ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -8,12 +8,14 @@ */ #include +#include #include #include #include #include #include #include +#include #include #include "ext4_jbd2.h" #include "ext4.h" @@ -52,6 +54,11 @@ long ext4_ioctl(struct file *filp, unsig if (!S_ISDIR(inode->i_mode)) flags &= ~EXT4_DIRSYNC_FL; + if (IS_BARRIER(inode)) { + vxwprintk_task(1, "messing with the barrier."); + return -EACCES; + } + err = -EPERM; mutex_lock(&inode->i_mutex); /* Is it quota file? Do not allow user to mess with it */ @@ -69,7 +76,9 @@ long ext4_ioctl(struct file *filp, unsig * * This test looks nicer. Thanks to Pauline Middelink */ - if ((flags ^ oldflags) & (EXT4_APPEND_FL | EXT4_IMMUTABLE_FL)) { + if ((oldflags & EXT4_IMMUTABLE_FL) || + ((flags ^ oldflags) & (EXT4_APPEND_FL | + EXT4_IMMUTABLE_FL | EXT4_IXUNLINK_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) goto flags_out; } diff -NurpP --minimal linux-2.6.27.15/fs/ext4/namei.c linux-2.6.27.15-g-v/fs/ext4/namei.c --- linux-2.6.27.15/fs/ext4/namei.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/namei.c 2009-02-10 20:32:14.000000000 +0100 @@ -34,6 +34,7 @@ #include #include #include +#include #include "ext4.h" #include "ext4_jbd2.h" @@ -914,6 +915,7 @@ restart: if (bh) ll_rw_block(READ_META, 1, &bh); } + dx_propagate_tag(nd, inode); } if ((bh = bh_use[ra_ptr++]) == NULL) goto next; @@ -1176,9 +1178,9 @@ static struct ext4_dir_entry_2 *do_split u32 hash2; struct dx_map_entry *map; char *data1 = (*bh)->b_data, *data2; - unsigned split, move, size, i; + unsigned split, move, size; struct ext4_dir_entry_2 *de = NULL, *de2; - int err = 0; + int i, err = 0; bh2 = ext4_append (handle, dir, &newblock, &err); if (!(bh2)) { @@ -2460,6 +2462,7 @@ const struct inode_operations ext4_dir_i .removexattr = generic_removexattr, #endif .permission = ext4_permission, + .sync_flags = ext4_sync_flags, }; const struct inode_operations ext4_special_inode_operations = { @@ -2471,4 +2474,5 @@ const struct inode_operations ext4_speci .removexattr = generic_removexattr, #endif .permission = ext4_permission, + .sync_flags = ext4_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext4/super.c linux-2.6.27.15-g-v/fs/ext4/super.c --- linux-2.6.27.15/fs/ext4/super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/super.c 2009-02-10 20:32:14.000000000 +0100 @@ -907,6 +907,7 @@ enum { Opt_ignore, Opt_barrier, Opt_err, Opt_resize, Opt_usrquota, Opt_grpquota, Opt_extents, Opt_noextents, Opt_i_version, Opt_mballoc, Opt_nomballoc, Opt_stripe, Opt_delalloc, Opt_nodelalloc, + Opt_tag, Opt_notag, Opt_tagid }; static match_table_t tokens = { @@ -967,6 +968,9 @@ static match_table_t tokens = { {Opt_resize, "resize"}, {Opt_delalloc, "delalloc"}, {Opt_nodelalloc, "nodelalloc"}, + {Opt_tag, "tag"}, + {Opt_notag, "notag"}, + {Opt_tagid, "tagid=%u"}, {Opt_err, NULL}, }; @@ -1060,6 +1064,20 @@ static int parse_options(char *options, case Opt_nouid32: set_opt(sbi->s_mount_opt, NO_UID32); break; +#ifndef CONFIG_TAGGING_NONE + case Opt_tag: + set_opt (sbi->s_mount_opt, TAGGED); + break; + case Opt_notag: + clear_opt (sbi->s_mount_opt, TAGGED); + break; +#endif +#ifdef CONFIG_PROPAGATE + case Opt_tagid: + /* use args[0] */ + set_opt (sbi->s_mount_opt, TAGGED); + break; +#endif case Opt_nocheck: clear_opt(sbi->s_mount_opt, CHECK); break; @@ -2033,6 +2051,9 @@ static int ext4_fill_super(struct super_ NULL, 0)) goto failed_mount; + if (EXT4_SB(sb)->s_mount_opt & EXT4_MOUNT_TAGGED) + sb->s_flags |= MS_TAGGED; + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); @@ -3015,6 +3036,13 @@ static int ext4_remount(struct super_blo if (sbi->s_mount_opt & EXT4_MOUNT_ABORT) ext4_abort(sb, __func__, "Abort forced by user"); + if ((sbi->s_mount_opt & EXT4_MOUNT_TAGGED) && + !(sb->s_flags & MS_TAGGED)) { + printk("EXT4-fs: %s: tagging not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } + sb->s_flags = (sb->s_flags & ~MS_POSIXACL) | ((sbi->s_mount_opt & EXT4_MOUNT_POSIX_ACL) ? MS_POSIXACL : 0); diff -NurpP --minimal linux-2.6.27.15/fs/ext4/symlink.c linux-2.6.27.15-g-v/fs/ext4/symlink.c --- linux-2.6.27.15/fs/ext4/symlink.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/symlink.c 2009-02-10 20:32:14.000000000 +0100 @@ -40,6 +40,7 @@ const struct inode_operations ext4_symli .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext4_sync_flags, }; const struct inode_operations ext4_fast_symlink_inode_operations = { @@ -51,4 +52,5 @@ const struct inode_operations ext4_fast_ .listxattr = ext4_listxattr, .removexattr = generic_removexattr, #endif + .sync_flags = ext4_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/ext4/xattr.c linux-2.6.27.15-g-v/fs/ext4/xattr.c --- linux-2.6.27.15/fs/ext4/xattr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ext4/xattr.c 2009-02-10 20:32:14.000000000 +0100 @@ -56,6 +56,7 @@ #include #include #include +#include #include "ext4_jbd2.h" #include "ext4.h" #include "xattr.h" @@ -490,6 +491,7 @@ ext4_xattr_release_block(handle_t *handl error = ext4_journal_dirty_metadata(handle, bh); if (IS_SYNC(inode)) handle->h_sync = 1; + DLIMIT_FREE_BLOCK(inode, 1); DQUOT_FREE_BLOCK(inode, 1); ea_bdebug(bh, "refcount now=%d; releasing", le32_to_cpu(BHDR(bh)->h_refcount)); @@ -780,11 +782,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 = ext4_journal_get_write_access(handle, new_bh); if (error) @@ -858,6 +863,8 @@ cleanup: cleanup_dquot: DQUOT_FREE_BLOCK(inode, 1); +cleanup_dlimit: + DLIMIT_FREE_BLOCK(inode, 1); goto cleanup; bad_block: diff -NurpP --minimal linux-2.6.27.15/fs/fcntl.c linux-2.6.27.15-g-v/fs/fcntl.c --- linux-2.6.27.15/fs/fcntl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/fcntl.c 2009-02-10 20:32:14.000000000 +0100 @@ -19,7 +19,9 @@ #include #include #include +#include #include +#include #include #include @@ -103,6 +105,8 @@ SYSCALL_DEFINE3(dup3, unsigned int, oldf if (tofree) filp_close(tofree, files); + else + vx_openfd_inc(newfd); /* fd was unused */ return newfd; @@ -266,6 +270,7 @@ static long do_fcntl(int fd, unsigned in switch (cmd) { case F_DUPFD: case F_DUPFD_CLOEXEC: + gr_learn_resource(current, RLIMIT_NOFILE, arg, 0); if (arg >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) break; err = alloc_fd(arg, cmd == F_DUPFD_CLOEXEC ? O_CLOEXEC : 0); @@ -342,6 +347,8 @@ SYSCALL_DEFINE3(fcntl, unsigned int, fd, filp = fget(fd); if (!filp) goto out; + if (!vx_files_avail(1)) + goto out; err = security_file_fcntl(filp, cmd, arg); if (err) { @@ -411,7 +418,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, diff -NurpP --minimal linux-2.6.27.15/fs/file.c linux-2.6.27.15-g-v/fs/file.c --- linux-2.6.27.15/fs/file.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/file.c 2009-02-10 20:32:14.000000000 +0100 @@ -19,6 +19,8 @@ #include #include #include +#include +#include struct fdtable_defer { spinlock_t lock; @@ -256,6 +258,8 @@ int expand_files(struct files_struct *fi * 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, nr, 0); if (nr >= current->signal->rlim[RLIMIT_NOFILE].rlim_cur) return -EMFILE; @@ -367,6 +371,8 @@ struct files_struct *dup_fd(struct files struct file *f = *old_fds++; if (f) { get_file(f); + /* TODO: sum it first for check and performance */ + vx_openfd_inc(open_files - i); } else { /* * The fd may be claimed in the fd bitmap but not yet @@ -475,6 +481,7 @@ repeat: else FD_CLR(fd, fdt->close_on_exec); error = fd; + vx_openfd_inc(fd); #if 1 /* Sanity check */ if (rcu_dereference(fdt->fd[fd]) != NULL) { diff -NurpP --minimal linux-2.6.27.15/fs/file_table.c linux-2.6.27.15-g-v/fs/file_table.c --- linux-2.6.27.15/fs/file_table.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/file_table.c 2009-02-10 20:32:14.000000000 +0100 @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include @@ -126,6 +128,8 @@ struct file *get_empty_filp(void) f->f_gid = tsk->fsgid; eventpoll_init_file(f); /* f->f_version: 0 */ + f->f_xid = vx_current_xid(); + vx_files_inc(f); return f; over: @@ -276,6 +280,8 @@ void __fput(struct file *file) cdev_put(inode->i_cdev); fops_put(file->f_op); put_pid(file->f_owner.pid); + vx_files_dec(file); + file->f_xid = 0; file_kill(file); if (file->f_mode & FMODE_WRITE) drop_file_write_access(file); @@ -343,6 +349,8 @@ void put_filp(struct file *file) { if (atomic_long_dec_and_test(&file->f_count)) { security_file_free(file); + vx_files_dec(file); + file->f_xid = 0; file_kill(file); file_free(file); } diff -NurpP --minimal linux-2.6.27.15/fs/fuse/control.c linux-2.6.27.15-g-v/fs/fuse/control.c --- linux-2.6.27.15/fs/fuse/control.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/fuse/control.c 2009-02-10 20:32:14.000000000 +0100 @@ -159,7 +159,7 @@ void fuse_ctl_remove_conn(struct fuse_co static int fuse_ctl_fill_super(struct super_block *sb, void *data, int silent) { - struct tree_descr empty_descr = {""}; + struct tree_descr empty_descr = {"", NULL, 0}; struct fuse_conn *fc; int err; diff -NurpP --minimal linux-2.6.27.15/fs/fuse/dir.c linux-2.6.27.15-g-v/fs/fuse/dir.c --- linux-2.6.27.15/fs/fuse/dir.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/fuse/dir.c 2009-02-10 20:32:14.000000000 +0100 @@ -1072,7 +1072,7 @@ static char *read_link(struct dentry *de return link; } -static void free_link(char *link) +static void free_link(const char *link) { if (!IS_ERR(link)) free_page((unsigned long) link); diff -NurpP --minimal linux-2.6.27.15/fs/hfs/inode.c linux-2.6.27.15-g-v/fs/hfs/inode.c --- linux-2.6.27.15/fs/hfs/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/hfs/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -419,7 +419,7 @@ int hfs_write_inode(struct inode *inode, if (S_ISDIR(main_inode->i_mode)) { if (fd.entrylength < sizeof(struct hfs_cat_dir)) - /* panic? */; + {/* panic? */} hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, sizeof(struct hfs_cat_dir)); if (rec.type != HFS_CDR_DIR || @@ -440,7 +440,7 @@ int hfs_write_inode(struct inode *inode, sizeof(struct hfs_cat_file)); } else { if (fd.entrylength < sizeof(struct hfs_cat_file)) - /* panic? */; + {/* panic? */} hfs_bnode_read(fd.bnode, &rec, fd.entryoffset, sizeof(struct hfs_cat_file)); if (rec.type != HFS_CDR_FIL || diff -NurpP --minimal linux-2.6.27.15/fs/hfsplus/inode.c linux-2.6.27.15-g-v/fs/hfsplus/inode.c --- linux-2.6.27.15/fs/hfsplus/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/hfsplus/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -417,7 +417,7 @@ int hfsplus_cat_read_inode(struct inode struct hfsplus_cat_folder *folder = &entry.folder; if (fd->entrylength < sizeof(struct hfsplus_cat_folder)) - /* panic? */; + {/* panic? */} hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, sizeof(struct hfsplus_cat_folder)); hfsplus_get_perms(inode, &folder->permissions, 1); @@ -434,7 +434,7 @@ int hfsplus_cat_read_inode(struct inode struct hfsplus_cat_file *file = &entry.file; if (fd->entrylength < sizeof(struct hfsplus_cat_file)) - /* panic? */; + {/* panic? */} hfs_bnode_read(fd->bnode, &entry, fd->entryoffset, sizeof(struct hfsplus_cat_file)); @@ -490,7 +490,7 @@ int hfsplus_cat_write_inode(struct inode struct hfsplus_cat_folder *folder = &entry.folder; if (fd.entrylength < sizeof(struct hfsplus_cat_folder)) - /* panic? */; + {/* panic? */} hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, sizeof(struct hfsplus_cat_folder)); /* simple node checks? */ @@ -512,7 +512,7 @@ int hfsplus_cat_write_inode(struct inode struct hfsplus_cat_file *file = &entry.file; if (fd.entrylength < sizeof(struct hfsplus_cat_file)) - /* panic? */; + {/* panic? */} hfs_bnode_read(fd.bnode, &entry, fd.entryoffset, sizeof(struct hfsplus_cat_file)); hfsplus_inode_write_fork(inode, &file->data_fork); diff -NurpP --minimal linux-2.6.27.15/fs/hfsplus/ioctl.c linux-2.6.27.15-g-v/fs/hfsplus/ioctl.c --- linux-2.6.27.15/fs/hfsplus/ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/hfsplus/ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include "hfsplus_fs.h" diff -NurpP --minimal linux-2.6.27.15/fs/inode.c linux-2.6.27.15-g-v/fs/inode.c --- linux-2.6.27.15/fs/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -124,6 +124,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_tag = 0; inode->i_blkbits = sb->s_blocksize_bits; inode->i_flags = 0; atomic_set(&inode->i_count, 1); @@ -142,6 +145,7 @@ static struct inode *alloc_inode(struct inode->i_bdev = NULL; inode->i_cdev = NULL; inode->i_rdev = 0; + inode->i_mdev = 0; inode->dirtied_when = 0; if (security_inode_alloc(inode)) { if (inode->i_sb->s_op->destroy_inode) @@ -247,6 +251,8 @@ void __iget(struct inode * inode) inodes_stat.nr_unused--; } +EXPORT_SYMBOL_GPL(__iget); + /** * clear_inode - clear an inode * @inode: inode to clear @@ -1427,9 +1433,11 @@ void init_special_inode(struct inode *in if (S_ISCHR(mode)) { inode->i_fop = &def_chr_fops; inode->i_rdev = rdev; + inode->i_mdev = rdev; } else if (S_ISBLK(mode)) { inode->i_fop = &def_blk_fops; inode->i_rdev = rdev; + inode->i_mdev = rdev; } else if (S_ISFIFO(mode)) inode->i_fop = &def_fifo_fops; else if (S_ISSOCK(mode)) diff -NurpP --minimal linux-2.6.27.15/fs/ioctl.c linux-2.6.27.15-g-v/fs/ioctl.c --- linux-2.6.27.15/fs/ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -13,6 +13,9 @@ #include #include #include +#include +#include +#include #include diff -NurpP --minimal linux-2.6.27.15/fs/ioprio.c linux-2.6.27.15-g-v/fs/ioprio.c --- linux-2.6.27.15/fs/ioprio.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ioprio.c 2009-02-10 20:32:14.000000000 +0100 @@ -26,6 +26,7 @@ #include #include #include +#include static int set_task_ioprio(struct task_struct *task, int ioprio) { @@ -116,6 +117,8 @@ SYSCALL_DEFINE3(ioprio_set, int, which, else pgrp = find_vpid(who); do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { + if (!vx_check(p->xid, VS_ADMIN_P | VS_IDENT)) + continue; ret = set_task_ioprio(p, ioprio); if (ret) break; @@ -205,6 +208,8 @@ SYSCALL_DEFINE2(ioprio_get, int, which, else pgrp = find_vpid(who); do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { + if (!vx_check(p->xid, VS_ADMIN_P | VS_IDENT)) + continue; tmpio = get_task_ioprio(p); if (tmpio < 0) continue; diff -NurpP --minimal linux-2.6.27.15/fs/jffs2/debug.h linux-2.6.27.15-g-v/fs/jffs2/debug.h --- linux-2.6.27.15/fs/jffs2/debug.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jffs2/debug.h 2009-02-10 20:32:14.000000000 +0100 @@ -52,13 +52,13 @@ #if CONFIG_JFFS2_FS_DEBUG > 0 #define D1(x) x #else -#define D1(x) +#define D1(x) do {} while (0); #endif #if CONFIG_JFFS2_FS_DEBUG > 1 #define D2(x) x #else -#define D2(x) +#define D2(x) do {} while (0); #endif /* The prefixes of JFFS2 messages */ @@ -114,73 +114,73 @@ #ifdef JFFS2_DBG_READINODE_MESSAGES #define dbg_readinode(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_readinode(fmt, ...) +#define dbg_readinode(fmt, ...) do {} while (0) #endif #ifdef JFFS2_DBG_READINODE2_MESSAGES #define dbg_readinode2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_readinode2(fmt, ...) +#define dbg_readinode2(fmt, ...) do {} while (0) #endif /* Fragtree build debugging messages */ #ifdef JFFS2_DBG_FRAGTREE_MESSAGES #define dbg_fragtree(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_fragtree(fmt, ...) +#define dbg_fragtree(fmt, ...) do {} while (0) #endif #ifdef JFFS2_DBG_FRAGTREE2_MESSAGES #define dbg_fragtree2(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_fragtree2(fmt, ...) +#define dbg_fragtree2(fmt, ...) do {} while (0) #endif /* Directory entry list manilulation debugging messages */ #ifdef JFFS2_DBG_DENTLIST_MESSAGES #define dbg_dentlist(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_dentlist(fmt, ...) +#define dbg_dentlist(fmt, ...) do {} while (0) #endif /* Print the messages about manipulating node_refs */ #ifdef JFFS2_DBG_NODEREF_MESSAGES #define dbg_noderef(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_noderef(fmt, ...) +#define dbg_noderef(fmt, ...) do {} while (0) #endif /* Manipulations with the list of inodes (JFFS2 inocache) */ #ifdef JFFS2_DBG_INOCACHE_MESSAGES #define dbg_inocache(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_inocache(fmt, ...) +#define dbg_inocache(fmt, ...) do {} while (0) #endif /* Summary debugging messages */ #ifdef JFFS2_DBG_SUMMARY_MESSAGES #define dbg_summary(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_summary(fmt, ...) +#define dbg_summary(fmt, ...) do {} while (0) #endif /* File system build messages */ #ifdef JFFS2_DBG_FSBUILD_MESSAGES #define dbg_fsbuild(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_fsbuild(fmt, ...) +#define dbg_fsbuild(fmt, ...) do {} while (0) #endif /* Watch the object allocations */ #ifdef JFFS2_DBG_MEMALLOC_MESSAGES #define dbg_memalloc(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_memalloc(fmt, ...) +#define dbg_memalloc(fmt, ...) do {} while (0) #endif /* Watch the XATTR subsystem */ #ifdef JFFS2_DBG_XATTR_MESSAGES #define dbg_xattr(fmt, ...) JFFS2_DEBUG(fmt, ##__VA_ARGS__) #else -#define dbg_xattr(fmt, ...) +#define dbg_xattr(fmt, ...) do {} while (0) #endif /* "Sanity" checks */ diff -NurpP --minimal linux-2.6.27.15/fs/jffs2/erase.c linux-2.6.27.15-g-v/fs/jffs2/erase.c --- linux-2.6.27.15/fs/jffs2/erase.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jffs2/erase.c 2009-02-10 20:32:14.000000000 +0100 @@ -431,7 +431,8 @@ static void jffs2_mark_erased_block(stru struct jffs2_unknown_node marker = { .magic = cpu_to_je16(JFFS2_MAGIC_BITMASK), .nodetype = cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), - .totlen = cpu_to_je32(c->cleanmarker_size) + .totlen = cpu_to_je32(c->cleanmarker_size), + .hdr_crc = cpu_to_je32(0) }; jffs2_prealloc_raw_node_refs(c, jeb, 1); diff -NurpP --minimal linux-2.6.27.15/fs/jffs2/summary.h linux-2.6.27.15-g-v/fs/jffs2/summary.h --- linux-2.6.27.15/fs/jffs2/summary.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jffs2/summary.h 2009-02-10 20:32:14.000000000 +0100 @@ -194,18 +194,18 @@ int jffs2_sum_scan_sumnode(struct jffs2_ #define jffs2_sum_active() (0) #define jffs2_sum_init(a) (0) -#define jffs2_sum_exit(a) -#define jffs2_sum_disable_collecting(a) +#define jffs2_sum_exit(a) do {} while (0) +#define jffs2_sum_disable_collecting(a) do {} while (0) #define jffs2_sum_is_disabled(a) (0) -#define jffs2_sum_reset_collected(a) +#define jffs2_sum_reset_collected(a) do {} while (0) #define jffs2_sum_add_kvec(a,b,c,d) (0) -#define jffs2_sum_move_collected(a,b) +#define jffs2_sum_move_collected(a,b) do {} while (0) #define jffs2_sum_write_sumnode(a) (0) -#define jffs2_sum_add_padding_mem(a,b) -#define jffs2_sum_add_inode_mem(a,b,c) -#define jffs2_sum_add_dirent_mem(a,b,c) -#define jffs2_sum_add_xattr_mem(a,b,c) -#define jffs2_sum_add_xref_mem(a,b,c) +#define jffs2_sum_add_padding_mem(a,b) do {} while (0) +#define jffs2_sum_add_inode_mem(a,b,c) do {} while (0) +#define jffs2_sum_add_dirent_mem(a,b,c) do {} while (0) +#define jffs2_sum_add_xattr_mem(a,b,c) do {} while (0) +#define jffs2_sum_add_xref_mem(a,b,c) do {} while (0) #define jffs2_sum_scan_sumnode(a,b,c,d,e) (0) #endif /* CONFIG_JFFS2_SUMMARY */ diff -NurpP --minimal linux-2.6.27.15/fs/jffs2/wbuf.c linux-2.6.27.15-g-v/fs/jffs2/wbuf.c --- linux-2.6.27.15/fs/jffs2/wbuf.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jffs2/wbuf.c 2009-02-10 20:32:14.000000000 +0100 @@ -1015,7 +1015,8 @@ static const struct jffs2_unknown_node o { .magic = constant_cpu_to_je16(JFFS2_MAGIC_BITMASK), .nodetype = constant_cpu_to_je16(JFFS2_NODETYPE_CLEANMARKER), - .totlen = constant_cpu_to_je32(8) + .totlen = constant_cpu_to_je32(8), + .hdr_crc = constant_cpu_to_je32(0) }; /* diff -NurpP --minimal linux-2.6.27.15/fs/jfs/acl.c linux-2.6.27.15-g-v/fs/jfs/acl.c --- linux-2.6.27.15/fs/jfs/acl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/acl.c 2009-02-10 20:32:14.000000000 +0100 @@ -232,7 +232,8 @@ int jfs_setattr(struct dentry *dentry, s return rc; if ((iattr->ia_valid & ATTR_UID && iattr->ia_uid != inode->i_uid) || - (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid)) { + (iattr->ia_valid & ATTR_GID && iattr->ia_gid != inode->i_gid) || + (iattr->ia_valid & ATTR_TAG && iattr->ia_tag != inode->i_tag)) { if (DQUOT_TRANSFER(inode, iattr)) return -EDQUOT; } diff -NurpP --minimal linux-2.6.27.15/fs/jfs/file.c linux-2.6.27.15-g-v/fs/jfs/file.c --- linux-2.6.27.15/fs/jfs/file.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/file.c 2009-02-10 20:32:14.000000000 +0100 @@ -98,6 +98,7 @@ const struct inode_operations jfs_file_i .setattr = jfs_setattr, .permission = jfs_permission, #endif + .sync_flags = jfs_sync_flags, }; const struct file_operations jfs_file_operations = { diff -NurpP --minimal linux-2.6.27.15/fs/jfs/inode.c linux-2.6.27.15-g-v/fs/jfs/inode.c --- linux-2.6.27.15/fs/jfs/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_filsys.h" @@ -155,6 +156,7 @@ void jfs_delete_inode(struct inode *inod DQUOT_INIT(inode); DQUOT_FREE_INODE(inode); DQUOT_DROP(inode); + DLIMIT_FREE_INODE(inode); } clear_inode(inode); diff -NurpP --minimal linux-2.6.27.15/fs/jfs/ioctl.c linux-2.6.27.15-g-v/fs/jfs/ioctl.c --- linux-2.6.27.15/fs/jfs/ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -11,6 +11,7 @@ #include #include #include +#include #include #include @@ -85,6 +86,11 @@ long jfs_ioctl(struct file *filp, unsign if (!S_ISDIR(inode->i_mode)) flags &= ~JFS_DIRSYNC_FL; + if (IS_BARRIER(inode)) { + vxwprintk_task(1, "messing with the barrier."); + return -EACCES; + } + /* Is it quota file? Do not allow user to mess with it */ if (IS_NOQUOTA(inode)) { err = -EPERM; @@ -102,8 +108,8 @@ long jfs_ioctl(struct file *filp, unsign * the relevant capability. */ if ((oldflags & JFS_IMMUTABLE_FL) || - ((flags ^ oldflags) & - (JFS_APPEND_FL | JFS_IMMUTABLE_FL))) { + ((flags ^ oldflags) & (JFS_APPEND_FL | + JFS_IMMUTABLE_FL | JFS_IXUNLINK_FL))) { if (!capable(CAP_LINUX_IMMUTABLE)) { mutex_unlock(&inode->i_mutex); err = -EPERM; diff -NurpP --minimal linux-2.6.27.15/fs/jfs/jfs_dinode.h linux-2.6.27.15-g-v/fs/jfs/jfs_dinode.h --- linux-2.6.27.15/fs/jfs/jfs_dinode.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/jfs_dinode.h 2009-02-10 20:32:14.000000000 +0100 @@ -161,9 +161,13 @@ struct dinode { #define JFS_APPEND_FL 0x01000000 /* writes to file may only append */ #define JFS_IMMUTABLE_FL 0x02000000 /* Immutable file */ +#define JFS_IXUNLINK_FL 0x08000000 /* Immutable invert on unlink */ -#define JFS_FL_USER_VISIBLE 0x03F80000 -#define JFS_FL_USER_MODIFIABLE 0x03F80000 +#define JFS_BARRIER_FL 0x04000000 /* Barrier for chroot() */ +#define JFS_COW_FL 0x20000000 /* Copy on Write marker */ + +#define JFS_FL_USER_VISIBLE 0x07F80000 +#define JFS_FL_USER_MODIFIABLE 0x07F80000 #define JFS_FL_INHERIT 0x03C80000 /* These are identical to EXT[23]_IOC_GETFLAGS/SETFLAGS */ diff -NurpP --minimal linux-2.6.27.15/fs/jfs/jfs_dtree.c linux-2.6.27.15-g-v/fs/jfs/jfs_dtree.c --- linux-2.6.27.15/fs/jfs/jfs_dtree.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/jfs_dtree.c 2009-02-10 20:32:14.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 @@ -480,6 +481,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--; @@ -951,6 +958,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 +1041,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; @@ -1306,6 +1320,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); @@ -1373,6 +1390,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); @@ -1920,6 +1943,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); /* @@ -2286,6 +2315,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); @@ -2362,6 +2393,8 @@ static int dtDeleteUp(tid_t tid, struct xlen = lengthPXD(&p->header.self); + /* Free dlimit allocation */ + DLIMIT_FREE_BLOCK(ip, xlen); /* Free quota allocation */ DQUOT_FREE_BLOCK(ip, xlen); diff -NurpP --minimal linux-2.6.27.15/fs/jfs/jfs_extent.c linux-2.6.27.15-g-v/fs/jfs/jfs_extent.c --- linux-2.6.27.15/fs/jfs/jfs_extent.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/jfs_extent.c 2009-02-10 20:32:14.000000000 +0100 @@ -18,6 +18,7 @@ #include #include +#include #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_superblock.h" @@ -147,6 +148,14 @@ extAlloc(struct inode *ip, s64 xlen, s64 return -EDQUOT; } + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, nxlen)) { + DQUOT_FREE_BLOCK(ip, nxlen); + dbFree(ip, nxaddr, (s64) nxlen); + mutex_unlock(&JFS_IP(ip)->commit_mutex); + return -ENOSPC; + } + /* determine the value of the extent flag */ xflag = abnr ? XAD_NOTRECORDED : 0; @@ -164,6 +173,7 @@ extAlloc(struct inode *ip, s64 xlen, s64 */ if (rc) { dbFree(ip, nxaddr, nxlen); + DLIMIT_FREE_BLOCK(ip, nxlen); DQUOT_FREE_BLOCK(ip, nxlen); mutex_unlock(&JFS_IP(ip)->commit_mutex); return (rc); @@ -261,6 +271,13 @@ int extRealloc(struct inode *ip, s64 nxl mutex_unlock(&JFS_IP(ip)->commit_mutex); return -EDQUOT; } + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, nxlen)) { + DQUOT_FREE_BLOCK(ip, nxlen); + dbFree(ip, nxaddr, (s64) nxlen); + up(&JFS_IP(ip)->commit_sem); + return -ENOSPC; + } delta = nxlen - xlen; @@ -297,6 +314,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 +326,7 @@ int extRealloc(struct inode *ip, s64 nxl */ if ((rc = xtTailgate(0, ip, xoff, (int) ntail, nxaddr, 0))) { dbFree(ip, nxaddr, nxlen); + DLIMIT_FREE_BLOCK(ip, nxlen); DQUOT_FREE_BLOCK(ip, nxlen); goto exit; } diff -NurpP --minimal linux-2.6.27.15/fs/jfs/jfs_filsys.h linux-2.6.27.15-g-v/fs/jfs/jfs_filsys.h --- linux-2.6.27.15/fs/jfs/jfs_filsys.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/jfs_filsys.h 2009-02-10 20:32:14.000000000 +0100 @@ -263,6 +263,7 @@ #define JFS_NAME_MAX 255 #define JFS_PATH_MAX BPSIZE +#define JFS_TAGGED 0x00800000 /* Context Tagging */ /* * file system state (superblock state) diff -NurpP --minimal linux-2.6.27.15/fs/jfs/jfs_imap.c linux-2.6.27.15-g-v/fs/jfs/jfs_imap.c --- linux-2.6.27.15/fs/jfs/jfs_imap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/jfs_imap.c 2009-02-10 20:32:14.000000000 +0100 @@ -45,6 +45,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_inode.h" @@ -3058,6 +3059,8 @@ static int copy_from_dinode(struct dinod { struct jfs_inode_info *jfs_ip = JFS_IP(ip); struct jfs_sb_info *sbi = JFS_SBI(ip->i_sb); + uid_t uid; + gid_t gid; jfs_ip->fileset = le32_to_cpu(dip->di_fileset); jfs_ip->mode2 = le32_to_cpu(dip->di_mode); @@ -3078,14 +3081,18 @@ static int copy_from_dinode(struct dinod } ip->i_nlink = le32_to_cpu(dip->di_nlink); - jfs_ip->saved_uid = le32_to_cpu(dip->di_uid); + uid = le32_to_cpu(dip->di_uid); + gid = le32_to_cpu(dip->di_gid); + ip->i_tag = INOTAG_TAG(DX_TAG(ip), uid, gid, 0); + + jfs_ip->saved_uid = INOTAG_UID(DX_TAG(ip), uid, gid); if (sbi->uid == -1) ip->i_uid = jfs_ip->saved_uid; else { ip->i_uid = sbi->uid; } - jfs_ip->saved_gid = le32_to_cpu(dip->di_gid); + jfs_ip->saved_gid = INOTAG_GID(DX_TAG(ip), uid, gid); if (sbi->gid == -1) ip->i_gid = jfs_ip->saved_gid; else { @@ -3150,14 +3157,12 @@ static void copy_to_dinode(struct dinode dip->di_size = cpu_to_le64(ip->i_size); dip->di_nblocks = cpu_to_le64(PBLK2LBLK(ip->i_sb, ip->i_blocks)); dip->di_nlink = cpu_to_le32(ip->i_nlink); - if (sbi->uid == -1) - dip->di_uid = cpu_to_le32(ip->i_uid); - else - dip->di_uid = cpu_to_le32(jfs_ip->saved_uid); - if (sbi->gid == -1) - dip->di_gid = cpu_to_le32(ip->i_gid); - else - dip->di_gid = cpu_to_le32(jfs_ip->saved_gid); + + dip->di_uid = cpu_to_le32(TAGINO_UID(DX_TAG(ip), + (sbi->uid == -1) ? ip->i_uid : jfs_ip->saved_uid, ip->i_tag)); + dip->di_gid = cpu_to_le32(TAGINO_GID(DX_TAG(ip), + (sbi->gid == -1) ? ip->i_gid : jfs_ip->saved_gid, ip->i_tag)); + jfs_get_inode_flags(jfs_ip); /* * mode2 is only needed for storing the higher order bits. diff -NurpP --minimal linux-2.6.27.15/fs/jfs/jfs_inode.c linux-2.6.27.15-g-v/fs/jfs/jfs_inode.c --- linux-2.6.27.15/fs/jfs/jfs_inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/jfs_inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -18,6 +18,8 @@ #include #include +#include +#include #include "jfs_incore.h" #include "jfs_inode.h" #include "jfs_filsys.h" @@ -30,29 +32,46 @@ void jfs_set_inode_flags(struct inode *i { unsigned int flags = JFS_IP(inode)->mode2; - inode->i_flags &= ~(S_IMMUTABLE | S_APPEND | - S_NOATIME | S_DIRSYNC | S_SYNC); + inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | + S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); if (flags & JFS_IMMUTABLE_FL) inode->i_flags |= S_IMMUTABLE; + if (flags & JFS_IXUNLINK_FL) + inode->i_flags |= S_IXUNLINK; + + if (flags & JFS_SYNC_FL) + inode->i_flags |= S_SYNC; if (flags & JFS_APPEND_FL) inode->i_flags |= S_APPEND; if (flags & JFS_NOATIME_FL) inode->i_flags |= S_NOATIME; if (flags & JFS_DIRSYNC_FL) inode->i_flags |= S_DIRSYNC; - if (flags & JFS_SYNC_FL) - inode->i_flags |= S_SYNC; + + inode->i_vflags &= ~(V_BARRIER | V_COW); + + if (flags & JFS_BARRIER_FL) + inode->i_vflags |= V_BARRIER; + if (flags & JFS_COW_FL) + inode->i_vflags |= V_COW; } void jfs_get_inode_flags(struct jfs_inode_info *jfs_ip) { unsigned int flags = jfs_ip->vfs_inode.i_flags; + unsigned int vflags = jfs_ip->vfs_inode.i_vflags; + + jfs_ip->mode2 &= ~(JFS_IMMUTABLE_FL | JFS_IXUNLINK_FL | + JFS_APPEND_FL | JFS_NOATIME_FL | + JFS_DIRSYNC_FL | JFS_SYNC_FL | + JFS_BARRIER_FL | JFS_COW_FL); - jfs_ip->mode2 &= ~(JFS_IMMUTABLE_FL | JFS_APPEND_FL | JFS_NOATIME_FL | - JFS_DIRSYNC_FL | JFS_SYNC_FL); if (flags & S_IMMUTABLE) jfs_ip->mode2 |= JFS_IMMUTABLE_FL; + if (flags & S_IXUNLINK) + jfs_ip->mode2 |= JFS_IXUNLINK_FL; + if (flags & S_APPEND) jfs_ip->mode2 |= JFS_APPEND_FL; if (flags & S_NOATIME) @@ -61,6 +80,19 @@ void jfs_get_inode_flags(struct jfs_inod jfs_ip->mode2 |= JFS_DIRSYNC_FL; if (flags & S_SYNC) jfs_ip->mode2 |= JFS_SYNC_FL; + + if (vflags & V_BARRIER) + jfs_ip->mode2 |= JFS_BARRIER_FL; + if (vflags & V_COW) + jfs_ip->mode2 |= JFS_COW_FL; +} + +int jfs_sync_flags(struct inode *inode) +{ + jfs_get_inode_flags(JFS_IP(inode)); + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + return 0; } /* @@ -108,10 +140,17 @@ struct inode *ialloc(struct inode *paren jfs_inode->saved_uid = inode->i_uid; jfs_inode->saved_gid = inode->i_gid; + inode->i_tag = dx_current_fstag(sb); + if (DLIMIT_ALLOC_INODE(inode)) { + iput(inode); + return ERR_PTR(-ENOSPC); + } + /* * Allocate inode to quota. */ if (DQUOT_ALLOC_INODE(inode)) { + DLIMIT_FREE_INODE(inode); DQUOT_DROP(inode); inode->i_flags |= S_NOQUOTA; inode->i_nlink = 0; diff -NurpP --minimal linux-2.6.27.15/fs/jfs/jfs_inode.h linux-2.6.27.15-g-v/fs/jfs/jfs_inode.h --- linux-2.6.27.15/fs/jfs/jfs_inode.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/jfs_inode.h 2009-02-10 20:32:14.000000000 +0100 @@ -39,6 +39,7 @@ extern struct dentry *jfs_fh_to_dentry(s extern struct dentry *jfs_fh_to_parent(struct super_block *sb, struct fid *fid, int fh_len, int fh_type); extern void jfs_set_inode_flags(struct inode *); +extern int jfs_sync_flags(struct inode *); extern int jfs_get_block(struct inode *, sector_t, struct buffer_head *, int); extern const struct address_space_operations jfs_aops; diff -NurpP --minimal linux-2.6.27.15/fs/jfs/jfs_xtree.c linux-2.6.27.15-g-v/fs/jfs/jfs_xtree.c --- linux-2.6.27.15/fs/jfs/jfs_xtree.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/jfs_xtree.c 2009-02-10 20:32:14.000000000 +0100 @@ -23,6 +23,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_filsys.h" #include "jfs_metapage.h" @@ -848,7 +849,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; } @@ -878,6 +884,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; @@ -1234,6 +1241,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); @@ -1253,6 +1261,13 @@ xtSplitPage(tid_t tid, struct inode *ip, quota_allocation += lengthPXD(pxd); + /* Allocate blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, lengthPXD(pxd))) { + rc = -ENOSPC; + goto clean_up; + } + dlimit_allocation += lengthPXD(pxd); + /* * allocate the new right page for the split */ @@ -1454,6 +1469,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); @@ -1517,6 +1535,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); @@ -3940,6 +3964,8 @@ s64 xtTruncate(tid_t tid, struct inode * else ip->i_size = newsize; + /* update dlimit allocation to reflect freed blocks */ + DLIMIT_FREE_BLOCK(ip, nfreed); /* update quota allocation to reflect freed blocks */ DQUOT_FREE_BLOCK(ip, nfreed); diff -NurpP --minimal linux-2.6.27.15/fs/jfs/namei.c linux-2.6.27.15-g-v/fs/jfs/namei.c --- linux-2.6.27.15/fs/jfs/namei.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/namei.c 2009-02-10 20:32:14.000000000 +0100 @@ -21,6 +21,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_inode.h" @@ -1468,6 +1469,7 @@ static struct dentry *jfs_lookup(struct return ERR_CAST(ip); } + dx_propagate_tag(nd, ip); dentry = d_splice_alias(ip, dentry); if (dentry && (JFS_SBI(dip->i_sb)->mntflag & JFS_OS2)) @@ -1550,6 +1552,7 @@ const struct inode_operations jfs_dir_in .setattr = jfs_setattr, .permission = jfs_permission, #endif + .sync_flags = jfs_sync_flags, }; const struct file_operations jfs_dir_operations = { diff -NurpP --minimal linux-2.6.27.15/fs/jfs/super.c linux-2.6.27.15-g-v/fs/jfs/super.c --- linux-2.6.27.15/fs/jfs/super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/super.c 2009-02-10 20:32:14.000000000 +0100 @@ -196,7 +196,8 @@ static void jfs_put_super(struct super_b enum { Opt_integrity, Opt_nointegrity, Opt_iocharset, Opt_resize, Opt_resize_nosize, Opt_errors, Opt_ignore, Opt_err, Opt_quota, - Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask + Opt_usrquota, Opt_grpquota, Opt_uid, Opt_gid, Opt_umask, + Opt_tag, Opt_notag, Opt_tagid }; static match_table_t tokens = { @@ -206,6 +207,10 @@ static match_table_t tokens = { {Opt_resize, "resize=%u"}, {Opt_resize_nosize, "resize"}, {Opt_errors, "errors=%s"}, + {Opt_tag, "tag"}, + {Opt_notag, "notag"}, + {Opt_tagid, "tagid=%u"}, + {Opt_tag, "tagxid"}, {Opt_ignore, "noquota"}, {Opt_ignore, "quota"}, {Opt_usrquota, "usrquota"}, @@ -340,6 +345,20 @@ static int parse_options(char *options, } break; } +#ifndef CONFIG_TAGGING_NONE + case Opt_tag: + *flag |= JFS_TAGGED; + break; + case Opt_notag: + *flag &= JFS_TAGGED; + break; +#endif +#ifdef CONFIG_PROPAGATE + case Opt_tagid: + /* use args[0] */ + *flag |= JFS_TAGGED; + break; +#endif default: printk("jfs: Unrecognized mount option \"%s\" " " or missing value\n", p); @@ -370,6 +389,13 @@ static int jfs_remount(struct super_bloc if (!parse_options(data, sb, &newLVSize, &flag)) { return -EINVAL; } + + if ((flag & JFS_TAGGED) && !(sb->s_flags & MS_TAGGED)) { + printk(KERN_ERR "JFS: %s: tagging not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } + if (newLVSize) { if (sb->s_flags & MS_RDONLY) { printk(KERN_ERR @@ -441,6 +467,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_TAGGED) + sb->s_flags |= MS_TAGGED; if (newLVSize) { printk(KERN_ERR "resize option for remount only\n"); diff -NurpP --minimal linux-2.6.27.15/fs/jfs/xattr.c linux-2.6.27.15-g-v/fs/jfs/xattr.c --- linux-2.6.27.15/fs/jfs/xattr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/jfs/xattr.c 2009-02-10 20:32:14.000000000 +0100 @@ -23,6 +23,7 @@ #include #include #include +#include #include "jfs_incore.h" #include "jfs_superblock.h" #include "jfs_dmap.h" @@ -263,9 +264,16 @@ static int ea_write(struct inode *ip, st if (DQUOT_ALLOC_BLOCK(ip, nblocks)) { return -EDQUOT; } + /* Allocate new blocks to dlimit. */ + if (DLIMIT_ALLOC_BLOCK(ip, nblocks)) { + DQUOT_FREE_BLOCK(ip, nblocks); + return -ENOSPC; + } rc = dbAlloc(ip, INOHINT(ip), nblocks, &blkno); if (rc) { + /*Rollback dlimit allocation. */ + DLIMIT_FREE_BLOCK(ip, nblocks); /*Rollback quota allocation. */ DQUOT_FREE_BLOCK(ip, nblocks); return rc; @@ -332,6 +340,8 @@ static int ea_write(struct inode *ip, st failed: /* Rollback quota allocation. */ + DLIMIT_FREE_BLOCK(ip, nblocks); + /* Rollback quota allocation. */ DQUOT_FREE_BLOCK(ip, nblocks); dbFree(ip, blkno, nblocks); @@ -468,6 +478,7 @@ static int ea_get(struct inode *inode, s s64 blkno; int rc; int quota_allocation = 0; + int dlimit_allocation = 0; /* When fsck.jfs clears a bad ea, it doesn't clear the size */ if (ji->ea.flag == 0) @@ -543,6 +554,12 @@ static int ea_get(struct inode *inode, s quota_allocation = blocks_needed; + /* Allocate new blocks to dlimit. */ + rc = -ENOSPC; + if (DLIMIT_ALLOC_BLOCK(inode, blocks_needed)) + goto clean_up; + dlimit_allocation = blocks_needed; + rc = dbAlloc(inode, INOHINT(inode), (s64) blocks_needed, &blkno); if (rc) @@ -600,6 +617,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); @@ -676,8 +696,10 @@ static int ea_put(tid_t tid, struct inod } /* If old blocks exist, they must be removed from quota allocation. */ - if (old_blocks) + if (old_blocks) { + DLIMIT_FREE_BLOCK(inode, old_blocks); DQUOT_FREE_BLOCK(inode, old_blocks); + } inode->i_ctime = CURRENT_TIME; diff -NurpP --minimal linux-2.6.27.15/fs/libfs.c linux-2.6.27.15-g-v/fs/libfs.c --- linux-2.6.27.15/fs/libfs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/libfs.c 2009-02-10 20:32:14.000000000 +0100 @@ -125,7 +125,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_path.dentry; struct dentry *cursor = filp->private_data; @@ -158,6 +159,8 @@ int dcache_readdir(struct file * filp, v next = list_entry(p, struct dentry, d_u.d_child); if (d_unhashed(next) || !next->d_inode) continue; + if (filter && !filter(next)) + continue; spin_unlock(&dcache_lock); if (filldir(dirent, next->d_name.name, @@ -176,6 +179,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; @@ -823,6 +838,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_write_begin); diff -NurpP --minimal linux-2.6.27.15/fs/locks.c linux-2.6.27.15-g-v/fs/locks.c --- linux-2.6.27.15/fs/locks.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/locks.c 2009-02-10 20:32:14.000000000 +0100 @@ -127,6 +127,8 @@ #include #include #include +#include +#include #include @@ -148,6 +150,8 @@ static struct kmem_cache *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, GFP_KERNEL); } @@ -173,6 +177,7 @@ static void locks_free_lock(struct file_ BUG_ON(!list_empty(&fl->fl_block)); BUG_ON(!list_empty(&fl->fl_link)); + vx_locks_dec(fl); locks_release_private(fl); kmem_cache_free(filelock_cache, fl); } @@ -193,6 +198,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); @@ -247,6 +253,7 @@ void locks_copy_lock(struct file_lock *n new->fl_file = fl->fl_file; new->fl_ops = fl->fl_ops; new->fl_lmops = fl->fl_lmops; + new->fl_xid = fl->fl_xid; locks_copy_private(new, fl); } @@ -285,6 +292,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; @@ -450,6 +462,7 @@ static int lease_init(struct file *filp, fl->fl_owner = current->files; fl->fl_pid = current->tgid; + fl->fl_xid = vx_current_xid(); fl->fl_file = filp; fl->fl_flags = FL_LEASE; @@ -469,6 +482,11 @@ static struct file_lock *lease_alloc(str if (fl == NULL) return ERR_PTR(error); + 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) { locks_free_lock(fl); @@ -769,6 +787,7 @@ static int flock_lock_file(struct file * if (found) cond_resched_bkl(); + new_fl->fl_xid = -1; find_conflict: for_each_lock(inode, before) { struct file_lock *fl = *before; @@ -789,6 +808,7 @@ find_conflict: goto out; locks_copy_lock(new_fl, request); locks_insert_lock(before, new_fl); + vx_locks_inc(new_fl); new_fl = NULL; error = 0; @@ -799,7 +819,8 @@ out: return error; } -static int __posix_lock_file(struct inode *inode, struct file_lock *request, struct file_lock *conflock) +static int __posix_lock_file(struct inode *inode, struct file_lock *request, + struct file_lock *conflock, xid_t xid) { struct file_lock *fl; struct file_lock *new_fl = NULL; @@ -809,6 +830,8 @@ 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. @@ -819,7 +842,11 @@ static int __posix_lock_file(struct inod (request->fl_type != F_UNLCK || request->fl_start != 0 || request->fl_end != OFFSET_MAX)) { 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(); @@ -1018,7 +1045,8 @@ static int __posix_lock_file(struct inod int posix_lock_file(struct file *filp, struct file_lock *fl, struct file_lock *conflock) { - return __posix_lock_file(filp->f_path.dentry->d_inode, fl, conflock); + return __posix_lock_file(filp->f_path.dentry->d_inode, + fl, conflock, filp->f_xid); } EXPORT_SYMBOL(posix_lock_file); @@ -1108,7 +1136,7 @@ int locks_mandatory_area(int read_write, fl.fl_end = offset + count - 1; for (;;) { - error = __posix_lock_file(inode, &fl, NULL); + error = __posix_lock_file(inode, &fl, NULL, filp->f_xid); if (error != FILE_LOCK_DEFERRED) break; error = wait_event_interruptible(fl.fl_wait, !fl.fl_next); @@ -1423,6 +1451,7 @@ int generic_setlease(struct file *filp, locks_copy_lock(new_fl, lease); locks_insert_lock(before, new_fl); + vx_locks_inc(new_fl); *flp = new_fl; return 0; @@ -1777,6 +1806,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. */ @@ -1895,6 +1929,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. */ @@ -2005,16 +2044,16 @@ void locks_remove_flock(struct file *fil return; if (filp->f_op && filp->f_op->flock) { - struct file_lock fl = { + struct file_lock flock = { .fl_pid = current->tgid, .fl_file = filp, .fl_flags = FL_FLOCK, .fl_type = F_UNLCK, .fl_end = OFFSET_MAX, }; - filp->f_op->flock(filp, F_SETLKW, &fl); - if (fl.fl_ops && fl.fl_ops->fl_release_private) - fl.fl_ops->fl_release_private(&fl); + filp->f_op->flock(filp, F_SETLKW, &flock); + if (flock.fl_ops && flock.fl_ops->fl_release_private) + flock.fl_ops->fl_release_private(&flock); } lock_kernel(); @@ -2159,8 +2198,11 @@ static int locks_show(struct seq_file *f lock_get_status(f, fl, (long)f->private, ""); - list_for_each_entry(bfl, &fl->fl_block, fl_block) + list_for_each_entry(bfl, &fl->fl_block, fl_block) { + if (!vx_check(fl->fl_xid, VS_WATCH_P | VS_IDENT)) + continue; lock_get_status(f, bfl, (long)f->private, " ->"); + } f->private++; return 0; diff -NurpP --minimal linux-2.6.27.15/fs/namei.c linux-2.6.27.15-g-v/fs/namei.c --- linux-2.6.27.15/fs/namei.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/namei.c 2009-02-10 20:32:14.000000000 +0100 @@ -31,6 +31,16 @@ #include #include #include +#include +#include +#include +#include +#include +#include +#include +#include +#include + #include #define ACC_MODE(x) ("\000\004\002\006"[(x)&O_ACCMODE]) @@ -167,6 +177,77 @@ void putname(const char *name) EXPORT_SYMBOL(putname); #endif +static inline int dx_barrier(struct inode *inode) +{ + if (IS_BARRIER(inode) && !vx_check(0, VS_ADMIN | VS_WATCH)) { + vxwprintk_task(1, "did hit the barrier."); + return 1; + } + return 0; +} + +static int __dx_permission(struct inode *inode, int mask) +{ + if (dx_barrier(inode)) + return -EACCES; + + if (inode->i_sb->s_magic == DEVPTS_SUPER_MAGIC) { + /* devpts is xid tagged */ + if (S_ISDIR(inode->i_mode) || + vx_check((xid_t)inode->i_tag, VS_IDENT | VS_WATCH_P)) + return 0; + } + else 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 out; + + if ((mask & (MAY_WRITE | MAY_APPEND))) { + struct pid *pid; + struct task_struct *tsk; + + if (vx_check(0, VS_ADMIN | VS_WATCH_P) || + vx_flags(VXF_STATE_SETUP, 0)) + return 0; + + pid = PROC_I(inode)->pid; + if (!pid) + goto out; + + tsk = pid_task(pid, PIDTYPE_PID); + vxdprintk(VXD_CBIT(tag, 0), "accessing %p[#%u]", + tsk, (tsk ? vx_task_xid(tsk) : 0)); + if (tsk && vx_check(vx_task_xid(tsk), VS_IDENT | VS_WATCH_P)) + return 0; + } + else { + /* FIXME: Should we block some entries here? */ + return 0; + } + } + else { + if (dx_notagcheck(inode->i_sb) || + dx_check(inode->i_tag, DX_HOSTID | DX_ADMIN | DX_WATCH | + DX_IDENT)) + return 0; + } + +out: + return -EACCES; +} + +int dx_permission(struct inode *inode, int mask) +{ + int ret = __dx_permission(inode, mask); + if (unlikely(ret)) { + vxwprintk_task(1, "denied %x access to %s:%p[#%d,%lu]", + mask, inode->i_sb->s_id, inode, inode->i_tag, + inode->i_ino); + } + return ret; +} + /** * generic_permission - check for access rights on a Posix-like filesystem @@ -244,10 +325,14 @@ int inode_permission(struct inode *inode /* * Nobody gets write access to an immutable file. */ - if (IS_IMMUTABLE(inode)) + if (IS_IMMUTABLE(inode) && !IS_COW(inode)) return -EACCES; } + retval = dx_permission(inode, mask); + if (retval) + return retval; + /* Ordinary permission routines do not understand MAY_APPEND. */ if (inode->i_op && inode->i_op->permission) { retval = inode->i_op->permission(inode, mask); @@ -451,6 +536,8 @@ static int exec_permission_lite(struct i { umode_t mode = inode->i_mode; + if (dx_barrier(inode)) + return -EACCES; if (inode->i_op && inode->i_op->permission) return -EAGAIN; @@ -646,7 +733,7 @@ static __always_inline int __do_follow_l cookie = dentry->d_inode->i_op->follow_link(dentry, nd); error = PTR_ERR(cookie); if (!IS_ERR(cookie)) { - char *s = nd_get_link(nd); + const char *s = nd_get_link(nd); error = 0; if (s) error = __vfs_follow_link(nd, s); @@ -677,6 +764,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->path.mnt)) { + err = -EACCES; + goto loop; + } + current->link_count++; current->total_link_count++; nd->depth++; @@ -773,7 +867,8 @@ static __always_inline void follow_dotdo if (nd->path.dentry == fs->root.dentry && nd->path.mnt == fs->root.mnt) { read_unlock(&fs->lock); - break; + /* for sane '/' avoid follow_mount() */ + return; } read_unlock(&fs->lock); spin_lock(&dcache_lock); @@ -810,16 +905,30 @@ static int do_lookup(struct nameidata *n { struct vfsmount *mnt = nd->path.mnt; struct dentry *dentry = __d_lookup(nd->path.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 (__dx_permission(inode, MAY_ACCESS)) + goto hidden; + done: path->mnt = mnt; path->dentry = dentry; __follow_mount(path); return 0; +hidden: + vxwprintk_task(1, "did lookup hidden %s:%p[#%d,%lu] »%s«.", + inode->i_sb->s_id, inode, inode->i_tag, inode->i_ino, + vxd_path(&nd->path)); + dput(dentry); + return -ENOENT; need_lookup: dentry = real_lookup(nd->path.dentry, name, nd); @@ -1025,11 +1134,18 @@ return_reval: break; } return_base: + if (!gr_acl_handle_hidden_file(nd->path.dentry, nd->path.mnt)) { + path_put(&nd->path); + return -ENOENT; + } return 0; out_dput: path_put_conditional(&next, nd); break; } + if (!gr_acl_handle_hidden_file(nd->path.dentry, nd->path.mnt)) + err = -ENOENT; + path_put(&nd->path); return_err: return err; @@ -1407,7 +1523,7 @@ static int may_delete(struct inode *dir, 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)) @@ -1551,6 +1667,14 @@ int may_open(struct nameidata *nd, int a flag &= ~O_TRUNC; } +#ifdef CONFIG_VSERVER_COWBL + if (IS_COW(inode) && (flag & FMODE_WRITE)) { + if (IS_COW_LINK(inode)) + return -EMLINK; + inode->i_flags &= ~(S_IXUNLINK|S_IMMUTABLE); + mark_inode_dirty(inode); + } +#endif error = vfs_permission(nd, acc_mode); if (error) return error; @@ -1613,9 +1737,17 @@ static int __open_namei_create(struct na int error; struct dentry *dir = nd->path.dentry; + if (!gr_acl_handle_creat(path->dentry, nd->path.dentry, nd->path.mnt, flag, mode)) { + error = -EACCES; + goto out_unlock_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->path.mnt); +out_unlock_dput: mutex_unlock(&dir->d_inode->i_mutex); dput(nd->path.dentry); nd->path.dentry = path->dentry; @@ -1677,6 +1809,11 @@ struct file *do_filp_open(int dfd, const int will_write; int flag = open_to_namei_flags(open_flag); +#ifdef CONFIG_VSERVER_COWBL + int rflag = flag; + int rmode = mode; +restart: +#endif acc_mode = MAY_OPEN | ACC_MODE(flag); /* O_TRUNC implies we need access checks for write permissions */ @@ -1696,6 +1833,17 @@ struct file *do_filp_open(int dfd, const &nd, flag); if (error) return ERR_PTR(error); + + if (gr_handle_rawio(nd.path.dentry->d_inode)) { + error = -EPERM; + goto exit; + } + + if (!gr_acl_handle_open(nd.path.dentry, nd.path.mnt, flag)) { + error = -EACCES; + goto exit; + } + goto ok; } @@ -1759,6 +1907,20 @@ do_last: /* * It already exists. */ + + if (gr_handle_rawio(path.dentry->d_inode)) { + error = -EPERM; + goto exit_mutex_unlock; + } + if (!gr_acl_handle_open(path.dentry, nd.path.mnt, flag)) { + error = -EACCES; + goto exit_mutex_unlock; + } + if (gr_handle_fifo(path.dentry, nd.path.mnt, dir, flag, acc_mode)) { + error = -EACCES; + goto exit_mutex_unlock; + } + mutex_unlock(&dir->d_inode->i_mutex); audit_inode(pathname, path.dentry); @@ -1800,6 +1962,25 @@ ok: goto exit; } error = may_open(&nd, acc_mode, flag); +#ifdef CONFIG_VSERVER_COWBL + if (error == -EMLINK) { + struct dentry *dentry; + dentry = cow_break_link(pathname); + if (IS_ERR(dentry)) { + error = PTR_ERR(dentry); + goto exit_cow; + } + dput(dentry); + if (will_write) + mnt_drop_write(nd.path.mnt); + release_open_intent(&nd); + path_put(&nd.path); + flag = rflag; + mode = rmode; + goto restart; + } +exit_cow: +#endif if (error) { if (will_write) mnt_drop_write(nd.path.mnt); @@ -1843,6 +2024,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.path.mnt)) { + error = -EACCES; + goto exit_dput; + } + error = __do_follow_link(&path, &nd); if (error) { /* Does someone understand code flow here? Or it is only @@ -1952,9 +2140,17 @@ int vfs_mknod(struct inode *dir, struct if (error) return error; - if ((S_ISCHR(mode) || S_ISBLK(mode)) && !capable(CAP_MKNOD)) + if (!(S_ISCHR(mode) || S_ISBLK(mode))) + goto okay; + + if (!capable(CAP_MKNOD)) return -EPERM; + if (S_ISCHR(mode) && !vs_chrdev_perm(dev, DATTR_CREATE)) + return -EPERM; + if (S_ISBLK(mode) && !vs_blkdev_perm(dev, DATTR_CREATE)) + return -EPERM; +okay: if (!dir->i_op || !dir->i_op->mknod) return -EPERM; @@ -2015,9 +2211,21 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const error = may_mknod(mode); if (error) goto out_dput; + + if (gr_handle_chroot_mknod(dentry, nd.path.mnt, mode)) { + error = -EPERM; + goto out_dput; + } + + if (!gr_acl_handle_mknod(dentry, nd.path.dentry, nd.path.mnt, mode)) { + error = -EACCES; + goto out_dput; + } + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; + switch (mode & S_IFMT) { case 0: case S_IFREG: error = vfs_create(nd.path.dentry->d_inode,dentry,mode,&nd); @@ -2031,6 +2239,9 @@ SYSCALL_DEFINE4(mknodat, int, dfd, const break; } mnt_drop_write(nd.path.mnt); + + if (!error) + gr_handle_create(dentry, nd.path.mnt); out_dput: dput(dentry); out_unlock: @@ -2084,6 +2295,11 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const if (IS_ERR(dentry)) goto out_unlock; + if (!gr_acl_handle_mkdir(dentry, nd.path.dentry, nd.path.mnt)) { + error = -EACCES; + goto out_dput; + } + if (!IS_POSIXACL(nd.path.dentry->d_inode)) mode &= ~current->fs->umask; error = mnt_want_write(nd.path.mnt); @@ -2091,6 +2307,10 @@ SYSCALL_DEFINE3(mkdirat, int, dfd, const goto out_dput; error = vfs_mkdir(nd.path.dentry->d_inode, dentry, mode); mnt_drop_write(nd.path.mnt); + + if (!error) + gr_handle_create(dentry, nd.path.mnt); + out_dput: dput(dentry); out_unlock: @@ -2172,6 +2392,8 @@ static long do_rmdir(int dfd, const char char * name; struct dentry *dentry; struct nameidata nd; + ino_t saved_ino = 0; + dev_t saved_dev = 0; error = user_path_parent(dfd, pathname, &nd, &name); if (error) @@ -2193,11 +2415,26 @@ static long do_rmdir(int dfd, const char error = PTR_ERR(dentry); if (IS_ERR(dentry)) goto exit2; + + if (dentry->d_inode != NULL) { + 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.path.mnt)) { + error = -EACCES; + goto exit3; + } + } + error = mnt_want_write(nd.path.mnt); if (error) goto exit3; error = vfs_rmdir(nd.path.dentry->d_inode, dentry); mnt_drop_write(nd.path.mnt); + if (!error && (saved_dev || saved_ino)) + gr_handle_delete(saved_ino, saved_dev); exit3: dput(dentry); exit2: @@ -2257,6 +2494,8 @@ static long do_unlinkat(int dfd, const c struct dentry *dentry; struct nameidata nd; struct inode *inode = NULL; + ino_t saved_ino = 0; + dev_t saved_dev = 0; error = user_path_parent(dfd, pathname, &nd, &name); if (error) @@ -2273,12 +2512,25 @@ static long do_unlinkat(int dfd, const c 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; + } + atomic_inc(&inode->i_count); + + if (!gr_acl_handle_unlink(dentry, nd.path.mnt)) { + error = -EACCES; + goto exit2; + } + } error = mnt_want_write(nd.path.mnt); if (error) goto exit2; error = vfs_unlink(nd.path.dentry->d_inode, dentry); + if (!error && (saved_ino || saved_dev)) + gr_handle_delete(saved_ino, saved_dev); mnt_drop_write(nd.path.mnt); exit2: dput(dentry); @@ -2356,10 +2608,17 @@ SYSCALL_DEFINE3(symlinkat, const char __ if (IS_ERR(dentry)) goto out_unlock; + if (!gr_acl_handle_symlink(dentry, nd.path.dentry, nd.path.mnt, from)) { + error = -EACCES; + goto out_dput; + } + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; error = vfs_symlink(nd.path.dentry->d_inode, dentry, from); + if (!error) + gr_handle_create(dentry, nd.path.mnt); mnt_drop_write(nd.path.mnt); out_dput: dput(dentry); @@ -2395,7 +2654,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; @@ -2452,10 +2711,26 @@ SYSCALL_DEFINE5(linkat, int, olddfd, con error = PTR_ERR(new_dentry); if (IS_ERR(new_dentry)) goto out_unlock; + + if (gr_handle_hardlink(old_path.dentry, old_path.mnt, + old_path.dentry->d_inode, + old_path.dentry->d_inode->i_mode, to)) { + error = -EACCES; + goto out_dput; + } + + if (!gr_acl_handle_link(new_dentry, nd.path.dentry, nd.path.mnt, + old_path.dentry, old_path.mnt, to)) { + error = -EACCES; + goto out_dput; + } + error = mnt_want_write(nd.path.mnt); if (error) goto out_dput; error = vfs_link(old_path.dentry, nd.path.dentry->d_inode, new_dentry); + if (!error) + gr_handle_create(new_dentry, nd.path.mnt); mnt_drop_write(nd.path.mnt); out_dput: dput(new_dentry); @@ -2611,8 +2886,10 @@ int vfs_rename(struct inode *old_dir, st error = vfs_rename_dir(old_dir,old_dentry,new_dir,new_dentry); else error = vfs_rename_other(old_dir,old_dentry,new_dir,new_dentry); + if (!error) { const char *new_name = old_dentry->d_name.name; + fsnotify_move(old_dir, new_dir, old_name, new_name, is_dir, new_dentry->d_inode, old_dentry); } @@ -2684,11 +2961,21 @@ SYSCALL_DEFINE4(renameat, int, olddfd, c if (new_dentry == trap) goto exit5; + error = gr_acl_handle_rename(new_dentry, new_dir, newnd.path.mnt, + old_dentry, old_dir->d_inode, oldnd.path.mnt, + to); + if (error) + goto exit5; + error = mnt_want_write(oldnd.path.mnt); if (error) goto exit5; error = vfs_rename(old_dir->d_inode, old_dentry, new_dir->d_inode, new_dentry); + if (!error) + gr_handle_rename(old_dir->d_inode, new_dir->d_inode, old_dentry, + new_dentry, oldnd.path.mnt, new_dentry->d_inode ? 1 : 0); + mnt_drop_write(oldnd.path.mnt); exit5: dput(new_dentry); @@ -2755,6 +3042,217 @@ int vfs_follow_link(struct nameidata *nd return __vfs_follow_link(nd, link); } + +#ifdef CONFIG_VSERVER_COWBL + +#include + +static inline +long do_cow_splice(struct file *in, struct file *out, size_t len) +{ + loff_t ppos = 0; + + return do_splice_direct(in, &ppos, out, len, 0); +} + +struct dentry *cow_break_link(const char *pathname) +{ + int ret, mode, pathlen, redo = 0; + struct nameidata old_nd, dir_nd; + struct path old_path, new_path; + struct dentry *dir, *res = NULL; + struct file *old_file; + struct file *new_file; + char *to, *path, pad='\251'; + loff_t size; + + vxdprintk(VXD_CBIT(misc, 1), "cow_break_link(»%s«)", pathname); + path = kmalloc(PATH_MAX, GFP_KERNEL); + ret = -ENOMEM; + if (!path) + goto out; + + /* old_nd will have refs to dentry and mnt */ + ret = path_lookup(pathname, LOOKUP_FOLLOW, &old_nd); + vxdprintk(VXD_CBIT(misc, 2), "path_lookup(old): %d", ret); + if (ret < 0) + goto out_free_path; + + old_path = old_nd.path; + mode = old_path.dentry->d_inode->i_mode; + + to = d_path(&old_path, path, PATH_MAX-2); + pathlen = strlen(to); + vxdprintk(VXD_CBIT(misc, 2), "old path »%s« [»%.*s«:%d]", to, + old_path.dentry->d_name.len, old_path.dentry->d_name.name, + old_path.dentry->d_name.len); + + to[pathlen + 1] = 0; +retry: + to[pathlen] = pad--; + ret = -EMLINK; + if (pad <= '\240') + goto out_rel_old; + + vxdprintk(VXD_CBIT(misc, 1), "temp copy »%s«", to); + /* dir_nd will have refs to dentry and mnt */ + ret = path_lookup(to, + LOOKUP_PARENT | LOOKUP_OPEN | LOOKUP_CREATE, &dir_nd); + vxdprintk(VXD_CBIT(misc, 2), + "path_lookup(new): %d", ret); + if (ret < 0) + goto retry; + + /* this puppy downs the inode mutex */ + new_path.dentry = lookup_create(&dir_nd, 0); + if (!new_path.dentry || IS_ERR(new_path.dentry)) { + vxdprintk(VXD_CBIT(misc, 2), + "lookup_create(new): %p", new_path.dentry); + mutex_unlock(&dir_nd.path.dentry->d_inode->i_mutex); + path_put(&dir_nd.path); + goto retry; + } + vxdprintk(VXD_CBIT(misc, 2), + "lookup_create(new): %p [»%.*s«:%d]", new_path.dentry, + new_path.dentry->d_name.len, new_path.dentry->d_name.name, + new_path.dentry->d_name.len); + dir = dir_nd.path.dentry; + + ret = vfs_create(dir_nd.path.dentry->d_inode, new_path.dentry, mode, &dir_nd); + vxdprintk(VXD_CBIT(misc, 2), + "vfs_create(new): %d", ret); + if (ret == -EEXIST) { + mutex_unlock(&dir->d_inode->i_mutex); + dput(new_path.dentry); + path_put(&dir_nd.path); + goto retry; + } + else if (ret < 0) + goto out_unlock_new; + + /* drop out early, ret passes ENOENT */ + ret = -ENOENT; + if ((redo = d_unhashed(old_path.dentry))) + goto out_unlock_new; + + new_path.mnt = dir_nd.path.mnt; + dget(old_path.dentry); + mntget(old_path.mnt); + /* this one cleans up the dentry/mnt in case of failure */ + old_file = dentry_open(old_path.dentry, old_path.mnt, O_RDONLY); + vxdprintk(VXD_CBIT(misc, 2), + "dentry_open(old): %p", old_file); + if (!old_file || IS_ERR(old_file)) { + res = IS_ERR(old_file) ? (void *) old_file : res; + goto out_unlock_new; + } + + dget(new_path.dentry); + mntget(new_path.mnt); + /* this one cleans up the dentry/mnt in case of failure */ + new_file = dentry_open(new_path.dentry, new_path.mnt, O_WRONLY); + vxdprintk(VXD_CBIT(misc, 2), + "dentry_open(new): %p", new_file); + + ret = IS_ERR(new_file) ? PTR_ERR(new_file) : -ENOENT; + if (!new_file || IS_ERR(new_file)) + goto out_fput_old; + + size = i_size_read(old_file->f_dentry->d_inode); + ret = do_cow_splice(old_file, new_file, size); + vxdprintk(VXD_CBIT(misc, 2), "do_splice_direct: %d", ret); + if (ret < 0) { + goto out_fput_both; + } else if (ret < size) { + ret = -ENOSPC; + goto out_fput_both; + } else { + struct inode *old_inode = old_path.dentry->d_inode; + struct inode *new_inode = new_path.dentry->d_inode; + struct iattr attr = { + .ia_uid = old_inode->i_uid, + .ia_gid = old_inode->i_gid, + .ia_valid = ATTR_UID | ATTR_GID + }; + + ret = inode_setattr(new_inode, &attr); + if (ret) + goto out_fput_both; + } + + mutex_lock(&old_path.dentry->d_inode->i_sb->s_vfs_rename_mutex); + + /* drop out late */ + ret = -ENOENT; + if ((redo = d_unhashed(old_path.dentry))) + goto out_unlock; + + vxdprintk(VXD_CBIT(misc, 2), + "vfs_rename: [»%*s«:%d] -> [»%*s«:%d]", + new_path.dentry->d_name.len, new_path.dentry->d_name.name, + new_path.dentry->d_name.len, + old_path.dentry->d_name.len, old_path.dentry->d_name.name, + old_path.dentry->d_name.len); + ret = vfs_rename(dir_nd.path.dentry->d_inode, new_path.dentry, + old_nd.path.dentry->d_parent->d_inode, old_path.dentry); + vxdprintk(VXD_CBIT(misc, 2), "vfs_rename: %d", ret); + res = new_path.dentry; + +out_unlock: + mutex_unlock(&old_path.dentry->d_inode->i_sb->s_vfs_rename_mutex); + +out_fput_both: + vxdprintk(VXD_CBIT(misc, 3), + "fput(new_file=%p[#%ld])", new_file, + atomic_read(&new_file->f_count)); + fput(new_file); + +out_fput_old: + vxdprintk(VXD_CBIT(misc, 3), + "fput(old_file=%p[#%ld])", old_file, + atomic_read(&old_file->f_count)); + fput(old_file); + +out_unlock_new: + mutex_unlock(&dir->d_inode->i_mutex); + if (!ret) + goto out_redo; + + /* error path cleanup */ + vfs_unlink(dir->d_inode, new_path.dentry); + dput(new_path.dentry); + +out_redo: + if (!redo) + goto out_rel_both; + /* lookup dentry once again */ + path_put(&old_nd.path); + ret = path_lookup(pathname, LOOKUP_FOLLOW, &old_nd); + if (ret) + goto out_rel_both; + + new_path.dentry = old_nd.path.dentry; + vxdprintk(VXD_CBIT(misc, 2), + "path_lookup(redo): %p [»%.*s«:%d]", new_path.dentry, + new_path.dentry->d_name.len, new_path.dentry->d_name.name, + new_path.dentry->d_name.len); + dget(new_path.dentry); + res = new_path.dentry; + +out_rel_both: + path_put(&dir_nd.path); +out_rel_old: + path_put(&old_nd.path); +out_free_path: + kfree(path); +out: + if (ret) + res = ERR_PTR(ret); + return res; +} + +#endif + /* get the link contents into pagecache */ static char *page_getlink(struct dentry * dentry, struct page **ppage) { diff -NurpP --minimal linux-2.6.27.15/fs/namespace.c linux-2.6.27.15-g-v/fs/namespace.c --- linux-2.6.27.15/fs/namespace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/namespace.c 2009-02-10 20:32:14.000000000 +0100 @@ -27,6 +27,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include #include "pnode.h" @@ -573,6 +579,7 @@ static struct vfsmount *clone_mnt(struct mnt->mnt_root = dget(root); mnt->mnt_mountpoint = mnt->mnt_root; mnt->mnt_parent = mnt; + mnt->mnt_tag = old->mnt_tag; if (flag & CL_SLAVE) { list_add(&mnt->mnt_slave, &old->mnt_slave_list); @@ -685,6 +692,31 @@ static inline void mangle(struct seq_fil seq_escape(m, s, " \t\n\\"); } +static int mnt_is_reachable(struct vfsmount *mnt) +{ + struct path root; + struct dentry *point; + int ret; + + if (mnt == mnt->mnt_ns->root) + return 1; + + spin_lock(&vfsmount_lock); + root = current->fs->root; + point = root.dentry; + + while ((mnt != mnt->mnt_parent) && (mnt != root.mnt)) { + point = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + } + + ret = (mnt == root.mnt) && is_subdir(point, root.dentry); + + spin_unlock(&vfsmount_lock); + + return ret; +} + /* * Simple .show_options callback for filesystems which don't want to * implement more complex mount option showing. @@ -757,6 +789,8 @@ static int show_sb_opts(struct seq_file { MS_SYNCHRONOUS, ",sync" }, { MS_DIRSYNC, ",dirsync" }, { MS_MANDLOCK, ",mand" }, + { MS_TAGGED, ",tag" }, + { MS_NOTAGCHECK, ",notagcheck" }, { 0, NULL } }; const struct proc_fs_info *fs_infop; @@ -803,10 +837,20 @@ static int show_vfsmnt(struct seq_file * int err = 0; struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; - mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); - seq_putc(m, ' '); - seq_path(m, &mnt_path, " \t\n\\"); - seq_putc(m, ' '); + if (vx_flags(VXF_HIDE_MOUNT, 0)) + return SEQ_SKIP; + if (!mnt_is_reachable(mnt) && !vx_check(0, VS_WATCH_P)) + return SEQ_SKIP; + + if (!vx_check(0, VS_ADMIN|VS_WATCH) && + mnt == current->fs->root.mnt) { + seq_puts(m, "/dev/root / "); + } else { + mangle(m, mnt->mnt_devname ? mnt->mnt_devname : "none"); + seq_putc(m, ' '); + seq_path(m, &mnt_path, " \t\n\\"); + seq_putc(m, ' '); + } show_type(m, mnt->mnt_sb); seq_puts(m, __mnt_is_readonly(mnt) ? " ro" : " rw"); err = show_sb_opts(m, mnt->mnt_sb); @@ -836,6 +880,11 @@ static int show_mountinfo(struct seq_fil struct path root = p->root; int err = 0; + if (vx_flags(VXF_HIDE_MOUNT, 0)) + return SEQ_SKIP; + if (!mnt_is_reachable(mnt) && !vx_check(0, VS_WATCH_P)) + return SEQ_SKIP; + seq_printf(m, "%i %i %u:%u ", mnt->mnt_id, mnt->mnt_parent->mnt_id, MAJOR(sb->s_dev), MINOR(sb->s_dev)); seq_dentry(m, mnt->mnt_root, " \t\n\\"); @@ -894,17 +943,27 @@ static int show_vfsstat(struct seq_file struct path mnt_path = { .dentry = mnt->mnt_root, .mnt = mnt }; int err = 0; - /* device */ - if (mnt->mnt_devname) { - seq_puts(m, "device "); - mangle(m, mnt->mnt_devname); - } else - seq_puts(m, "no device"); + if (vx_flags(VXF_HIDE_MOUNT, 0)) + return SEQ_SKIP; + if (!mnt_is_reachable(mnt) && !vx_check(0, VS_WATCH_P)) + return SEQ_SKIP; - /* mount point */ - seq_puts(m, " mounted on "); - seq_path(m, &mnt_path, " \t\n\\"); - seq_putc(m, ' '); + if (!vx_check(0, VS_ADMIN|VS_WATCH) && + mnt == current->fs->root.mnt) { + seq_puts(m, "device /dev/root mounted on / "); + } else { + /* device */ + if (mnt->mnt_devname) { + seq_puts(m, "device "); + mangle(m, mnt->mnt_devname); + } else + seq_puts(m, "no device"); + + /* mount point */ + seq_puts(m, " mounted on "); + seq_path(m, &mnt_path, " \t\n\\"); + seq_putc(m, ' '); + } /* file system type */ seq_puts(m, "with fstype "); @@ -1094,6 +1153,8 @@ static int do_umount(struct vfsmount *mn lock_kernel(); 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; @@ -1117,6 +1178,9 @@ static int do_umount(struct vfsmount *mn security_sb_umount_busy(mnt); up_write(&namespace_sem); release_mounts(&umount_list); + + gr_log_unmount(mnt->mnt_devname, retval); + return retval; } @@ -1143,7 +1207,7 @@ SYSCALL_DEFINE2(umount, char __user *, n goto dput_and_out; retval = -EPERM; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) goto dput_and_out; retval = do_umount(path.mnt, flags); @@ -1169,7 +1233,7 @@ SYSCALL_DEFINE1(oldumount, char __user * static int mount_is_safe(struct nameidata *nd) { - if (capable(CAP_SYS_ADMIN)) + if (vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) return 0; return -EPERM; #ifdef notyet @@ -1462,11 +1526,13 @@ static noinline int do_change_type(struc * noinline this do_mount helper to save do_mount stack space. */ static noinline int do_loopback(struct nameidata *nd, char *old_name, - int recurse) + tag_t tag, 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) @@ -1500,6 +1566,7 @@ static noinline int do_loopback(struct n spin_unlock(&vfsmount_lock); release_mounts(&umount_list); } + mnt->mnt_flags = mnt_flags; out: up_write(&namespace_sem); @@ -1531,12 +1598,12 @@ static int change_mount_flags(struct vfs * noinline this do_mount helper to save do_mount stack space. */ static noinline 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->path.mnt->mnt_sb; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_REMOUNT)) return -EPERM; if (!check_mnt(nd->path.mnt)) @@ -1582,7 +1649,7 @@ static noinline int do_move_mount(struct struct path parent_path; struct vfsmount *p; int err = 0; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) return -EPERM; if (!old_name || !*old_name) return -EINVAL; @@ -1665,7 +1732,7 @@ static noinline int do_new_mount(struct return -EINVAL; /* we need capabilities... */ - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SECURE_MOUNT)) return -EPERM; mnt = do_kern_mount(type, flags, name, data); @@ -1910,6 +1977,7 @@ long do_mount(char *dev_name, char *dir_ struct nameidata nd; int retval = 0; int mnt_flags = 0; + tag_t tag = 0; /* Discard magic */ if ((flags & MS_MGC_MSK) == MS_MGC_VAL) @@ -1925,6 +1993,12 @@ long do_mount(char *dev_name, char *dir_ if (data_page) ((char *)data_page)[PAGE_SIZE - 1] = 0; + if (dx_parse_tag(data_page, &tag, 1, &mnt_flags, &flags)) { + /* FIXME: bind and re-mounts get the tag flag? */ + if (flags & (MS_BIND|MS_REMOUNT)) + flags |= MS_TAGID; + } + /* Separate the per-mountpoint flags */ if (flags & MS_NOSUID) mnt_flags |= MNT_NOSUID; @@ -1941,6 +2015,8 @@ long do_mount(char *dev_name, char *dir_ if (flags & MS_RDONLY) mnt_flags |= MNT_READONLY; + if (!capable(CAP_SYS_ADMIN)) + mnt_flags |= MNT_NODEV; flags &= ~(MS_NOSUID | MS_NOEXEC | MS_NODEV | MS_ACTIVE | MS_NOATIME | MS_NODIRATIME | MS_RELATIME| MS_KERNMOUNT); @@ -1954,11 +2030,16 @@ long do_mount(char *dev_name, char *dir_ if (retval) goto dput_out; + if (gr_handle_chroot_mount(nd.path.dentry, nd.path.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, tag); else if (flags & MS_BIND) - retval = do_loopback(&nd, dev_name, flags & MS_REC); + retval = do_loopback(&nd, dev_name, tag, flags, mnt_flags); else if (flags & (MS_SHARED | MS_PRIVATE | MS_SLAVE | MS_UNBINDABLE)) retval = do_change_type(&nd, flags); else if (flags & MS_MOVE) @@ -1968,6 +2049,9 @@ long do_mount(char *dev_name, char *dir_ dev_name, data_page); dput_out: path_put(&nd.path); + + gr_log_mount(dev_name, dir_name, retval); + return retval; } @@ -2027,6 +2111,7 @@ static struct mnt_namespace *dup_mnt_ns( q = next_mnt(q, new_ns->root); } up_write(&namespace_sem); + atomic_inc(&vs_global_mnt_ns); if (rootmnt) mntput(rootmnt); @@ -2079,6 +2164,9 @@ SYSCALL_DEFINE5(mount, char __user *, de if (retval < 0) goto out3; + if (gr_handle_chroot_pivot()) + return -EPERM; + lock_kernel(); retval = do_mount((char *)dev_page, dir_page, (char *)type_page, flags, (void *)data_page); @@ -2354,5 +2442,6 @@ void __put_mnt_ns(struct mnt_namespace * spin_unlock(&vfsmount_lock); up_write(&namespace_sem); release_mounts(&umount_list); + atomic_dec(&vs_global_mnt_ns); kfree(ns); } diff -NurpP --minimal linux-2.6.27.15/fs/nfs/client.c linux-2.6.27.15-g-v/fs/nfs/client.c --- linux-2.6.27.15/fs/nfs/client.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfs/client.c 2009-02-10 20:32:14.000000000 +0100 @@ -601,6 +601,9 @@ static int nfs_init_server_rpcclient(str if (server->flags & NFS_MOUNT_SOFT) server->client->cl_softrtry = 1; + server->client->cl_tag = 0; + if (server->flags & NFS_MOUNT_TAGGED) + server->client->cl_tag = 1; return 0; } @@ -766,6 +769,10 @@ static void nfs_server_set_fsinfo(struct server->acdirmin = server->acdirmax = 0; } + /* FIXME: needs fsinfo + if (server->flags & NFS_MOUNT_TAGGED) + sb->s_flags |= MS_TAGGED; */ + server->maxfilesize = fsinfo->maxfilesize; /* We're airborne Set socket buffersize */ diff -NurpP --minimal linux-2.6.27.15/fs/nfs/dir.c linux-2.6.27.15-g-v/fs/nfs/dir.c --- linux-2.6.27.15/fs/nfs/dir.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfs/dir.c 2009-02-10 20:32:14.000000000 +0100 @@ -34,6 +34,7 @@ #include #include #include +#include #include "nfs4_fs.h" #include "delegation.h" @@ -938,6 +939,7 @@ static struct dentry *nfs_lookup(struct if (IS_ERR(res)) goto out_unblock_sillyrename; + dx_propagate_tag(nd, inode); no_entry: res = d_materialise_unique(dentry, inode); if (res != NULL) { diff -NurpP --minimal linux-2.6.27.15/fs/nfs/inode.c linux-2.6.27.15-g-v/fs/nfs/inode.c --- linux-2.6.27.15/fs/nfs/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfs/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -314,8 +315,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 = INOTAG_UID(DX_TAG(inode), fattr->uid, fattr->gid); + inode->i_gid = INOTAG_GID(DX_TAG(inode), fattr->uid, fattr->gid); + inode->i_tag = INOTAG_TAG(DX_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 @@ -462,6 +465,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_TAG) && IS_TAGGED(inode)) + inode->i_tag = attr->ia_tag; spin_lock(&inode->i_lock); NFS_I(inode)->cache_validity |= NFS_INO_INVALID_ACCESS|NFS_INO_INVALID_ACL; spin_unlock(&inode->i_lock); @@ -900,6 +905,9 @@ static int nfs_check_inode_attributes(st struct nfs_inode *nfsi = NFS_I(inode); loff_t cur_size, new_isize; unsigned long invalid = 0; + uid_t uid; + gid_t gid; + tag_t tag; /* Has the inode gone and changed behind our back? */ @@ -924,10 +932,15 @@ static int nfs_check_inode_attributes(st if (cur_size != new_isize && nfsi->npages == 0) invalid |= NFS_INO_INVALID_ATTR|NFS_INO_REVAL_PAGECACHE; + uid = INOTAG_UID(DX_TAG(inode), fattr->uid, fattr->gid); + gid = INOTAG_GID(DX_TAG(inode), fattr->uid, fattr->gid); + tag = INOTAG_TAG(DX_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_tag != tag) invalid |= NFS_INO_INVALID_ATTR | NFS_INO_INVALID_ACCESS | NFS_INO_INVALID_ACL; /* Has the link count changed? */ @@ -1048,6 +1061,9 @@ static int nfs_update_inode(struct inode loff_t cur_isize, new_isize; unsigned long invalid = 0; unsigned long now = jiffies; + uid_t uid; + gid_t gid; + tag_t tag; dfprintk(VFS, "NFS: %s(%s/%ld ct=%d info=0x%x)\n", __func__, inode->i_sb->s_id, inode->i_ino, @@ -1121,15 +1137,21 @@ static int nfs_update_inode(struct inode memcpy(&inode->i_atime, &fattr->atime, sizeof(inode->i_atime)); nfsi->change_attr = fattr->change_attr; + uid = INOTAG_UID(DX_TAG(inode), fattr->uid, fattr->gid); + gid = INOTAG_GID(DX_TAG(inode), fattr->uid, fattr->gid); + tag = INOTAG_TAG(DX_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_tag != tag) 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_tag = tag; if (fattr->valid & (NFS_ATTR_FATTR_V3 | NFS_ATTR_FATTR_V4)) { /* diff -NurpP --minimal linux-2.6.27.15/fs/nfs/nfs3xdr.c linux-2.6.27.15-g-v/fs/nfs/nfs3xdr.c --- linux-2.6.27.15/fs/nfs/nfs3xdr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfs/nfs3xdr.c 2009-02-10 20:32:14.000000000 +0100 @@ -22,6 +22,7 @@ #include #include #include +#include #include "internal.h" #define NFSDBG_FACILITY NFSDBG_XDR @@ -180,7 +181,7 @@ xdr_decode_fattr(__be32 *p, struct nfs_f } static inline __be32 * -xdr_encode_sattr(__be32 *p, struct iattr *attr) +xdr_encode_sattr(__be32 *p, struct iattr *attr, int tag) { if (attr->ia_valid & ATTR_MODE) { *p++ = xdr_one; @@ -188,15 +189,17 @@ xdr_encode_sattr(__be32 *p, struct iattr } else { *p++ = xdr_zero; } - if (attr->ia_valid & ATTR_UID) { + if (attr->ia_valid & ATTR_UID || + (tag && (attr->ia_valid & ATTR_TAG))) { *p++ = xdr_one; - *p++ = htonl(attr->ia_uid); + *p++ = htonl(TAGINO_UID(tag, attr->ia_uid, attr->ia_tag)); } else { *p++ = xdr_zero; } - if (attr->ia_valid & ATTR_GID) { + if (attr->ia_valid & ATTR_GID || + (tag && (attr->ia_valid & ATTR_TAG))) { *p++ = xdr_one; - *p++ = htonl(attr->ia_gid); + *p++ = htonl(TAGINO_GID(tag, attr->ia_gid, attr->ia_tag)); } else { *p++ = xdr_zero; } @@ -281,7 +284,8 @@ static int nfs3_xdr_sattrargs(struct rpc_rqst *req, __be32 *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_tag); *p++ = htonl(args->guard); if (args->guard) p = xdr_encode_time3(p, &args->guardtime); @@ -386,7 +390,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_tag); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; @@ -400,7 +405,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_tag); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); return 0; } @@ -413,7 +419,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_tag); *p++ = htonl(args->pathlen); req->rq_slen = xdr_adjust_iovec(req->rq_svec, p); @@ -431,7 +438,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_tag); if (args->type == NF3CHR || args->type == NF3BLK) { *p++ = htonl(MAJOR(args->rdev)); *p++ = htonl(MINOR(args->rdev)); diff -NurpP --minimal linux-2.6.27.15/fs/nfs/nfs4proc.c linux-2.6.27.15-g-v/fs/nfs/nfs4proc.c --- linux-2.6.27.15/fs/nfs/nfs4proc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfs/nfs4proc.c 2009-02-10 20:32:14.000000000 +0100 @@ -653,7 +653,7 @@ static int _nfs4_do_open_reclaim(struct static int nfs4_do_open_reclaim(struct nfs_open_context *ctx, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(state->inode); - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = _nfs4_do_open_reclaim(ctx, state); @@ -695,7 +695,7 @@ static int _nfs4_open_delegation_recall( int nfs4_open_delegation_recall(struct nfs_open_context *ctx, struct nfs4_state *state, const nfs4_stateid *stateid) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; struct nfs_server *server = NFS_SERVER(state->inode); int err; do { @@ -988,7 +988,7 @@ static int _nfs4_open_expired(struct nfs static inline int nfs4_do_open_expired(struct nfs_open_context *ctx, struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(state->inode); - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { @@ -1090,7 +1090,7 @@ out_err: static struct nfs4_state *nfs4_do_open(struct inode *dir, struct path *path, int flags, struct iattr *sattr, struct rpc_cred *cred) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; struct nfs4_state *res; int status; @@ -1181,7 +1181,7 @@ static int nfs4_do_setattr(struct inode struct nfs4_state *state) { struct nfs_server *server = NFS_SERVER(inode); - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(server, @@ -1494,7 +1494,7 @@ static int _nfs4_server_capabilities(str int nfs4_server_capabilities(struct nfs_server *server, struct nfs_fh *fhandle) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(server, @@ -1527,7 +1527,7 @@ static int _nfs4_lookup_root(struct nfs_ static int nfs4_lookup_root(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *info) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(server, @@ -1616,7 +1616,7 @@ static int _nfs4_proc_getattr(struct nfs static int nfs4_proc_getattr(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(server, @@ -1702,7 +1702,7 @@ static int nfs4_proc_lookupfh(struct nfs struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = _nfs4_proc_lookupfh(server, dirfh, name, fhandle, fattr); @@ -1731,7 +1731,7 @@ static int _nfs4_proc_lookup(struct inod static int nfs4_proc_lookup(struct inode *dir, struct qstr *name, struct nfs_fh *fhandle, struct nfs_fattr *fattr) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(dir), @@ -1795,7 +1795,7 @@ static int _nfs4_proc_access(struct inod static int nfs4_proc_access(struct inode *inode, struct nfs_access_entry *entry) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(inode), @@ -1850,7 +1850,7 @@ static int _nfs4_proc_readlink(struct in static int nfs4_proc_readlink(struct inode *inode, struct page *page, unsigned int pgbase, unsigned int pglen) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(inode), @@ -1947,7 +1947,7 @@ static int _nfs4_proc_remove(struct inod static int nfs4_proc_remove(struct inode *dir, struct qstr *name) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(dir), @@ -2019,7 +2019,7 @@ static int _nfs4_proc_rename(struct inod static int nfs4_proc_rename(struct inode *old_dir, struct qstr *old_name, struct inode *new_dir, struct qstr *new_name) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(old_dir), @@ -2066,7 +2066,7 @@ static int _nfs4_proc_link(struct inode static int nfs4_proc_link(struct inode *inode, struct inode *dir, struct qstr *name) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(inode), @@ -2157,7 +2157,7 @@ out: static int nfs4_proc_symlink(struct inode *dir, struct dentry *dentry, struct page *page, unsigned int len, struct iattr *sattr) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(dir), @@ -2188,7 +2188,7 @@ out: static int nfs4_proc_mkdir(struct inode *dir, struct dentry *dentry, struct iattr *sattr) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(dir), @@ -2237,7 +2237,7 @@ static int _nfs4_proc_readdir(struct den static int nfs4_proc_readdir(struct dentry *dentry, struct rpc_cred *cred, u64 cookie, struct page *page, unsigned int count, int plus) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(dentry->d_inode), @@ -2285,7 +2285,7 @@ out: static int nfs4_proc_mknod(struct inode *dir, struct dentry *dentry, struct iattr *sattr, dev_t rdev) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(dir), @@ -2314,7 +2314,7 @@ static int _nfs4_proc_statfs(struct nfs_ static int nfs4_proc_statfs(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsstat *fsstat) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(server, @@ -2342,7 +2342,7 @@ static int _nfs4_do_fsinfo(struct nfs_se static int nfs4_do_fsinfo(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_fsinfo *fsinfo) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { @@ -2385,7 +2385,7 @@ static int _nfs4_proc_pathconf(struct nf static int nfs4_proc_pathconf(struct nfs_server *server, struct nfs_fh *fhandle, struct nfs_pathconf *pathconf) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { @@ -2672,7 +2672,7 @@ out_free: static ssize_t nfs4_get_acl_uncached(struct inode *inode, void *buf, size_t buflen) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; ssize_t ret; do { ret = __nfs4_get_acl_uncached(inode, buf, buflen); @@ -2729,7 +2729,7 @@ static int __nfs4_proc_set_acl(struct in static int nfs4_proc_set_acl(struct inode *inode, const void *buf, size_t buflen) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = nfs4_handle_exception(NFS_SERVER(inode), @@ -3020,7 +3020,7 @@ out: int nfs4_proc_delegreturn(struct inode *inode, struct rpc_cred *cred, const nfs4_stateid *stateid, int issync) { struct nfs_server *server = NFS_SERVER(inode); - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { err = _nfs4_proc_delegreturn(inode, cred, stateid, issync); @@ -3095,7 +3095,7 @@ out: static int nfs4_proc_getlk(struct nfs4_state *state, int cmd, struct file_lock *request) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { @@ -3445,7 +3445,7 @@ static int _nfs4_do_setlk(struct nfs4_st static int nfs4_lock_reclaim(struct nfs4_state *state, struct file_lock *request) { struct nfs_server *server = NFS_SERVER(state->inode); - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { @@ -3463,7 +3463,7 @@ static int nfs4_lock_reclaim(struct nfs4 static int nfs4_lock_expired(struct nfs4_state *state, struct file_lock *request) { struct nfs_server *server = NFS_SERVER(state->inode); - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; err = nfs4_set_lock_state(state, request); @@ -3524,7 +3524,7 @@ out: static int nfs4_proc_setlk(struct nfs4_state *state, int cmd, struct file_lock *request) { - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; do { @@ -3574,7 +3574,7 @@ nfs4_proc_lock(struct file *filp, int cm int nfs4_lock_delegation_recall(struct nfs4_state *state, struct file_lock *fl) { struct nfs_server *server = NFS_SERVER(state->inode); - struct nfs4_exception exception = { }; + struct nfs4_exception exception = {0, 0}; int err; err = nfs4_set_lock_state(state, fl); diff -NurpP --minimal linux-2.6.27.15/fs/nfs/nfsroot.c linux-2.6.27.15-g-v/fs/nfs/nfsroot.c --- linux-2.6.27.15/fs/nfs/nfsroot.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfs/nfsroot.c 2009-02-10 20:32:14.000000000 +0100 @@ -117,12 +117,12 @@ static int mount_port __initdata = 0; / enum { /* Options that take integer arguments */ Opt_port, Opt_rsize, Opt_wsize, Opt_timeo, Opt_retrans, Opt_acregmin, - Opt_acregmax, Opt_acdirmin, Opt_acdirmax, + Opt_acregmax, Opt_acdirmin, Opt_acdirmax, Opt_tagid, /* Options that take no arguments */ 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_tag, Opt_notag, /* Error token */ Opt_err }; @@ -159,6 +159,9 @@ static match_table_t __initdata tokens = {Opt_tcp, "tcp"}, {Opt_acl, "acl"}, {Opt_noacl, "noacl"}, + {Opt_tag, "tag"}, + {Opt_notag, "notag"}, + {Opt_tagid, "tagid=%u"}, {Opt_err, NULL} }; @@ -270,6 +273,20 @@ static int __init root_nfs_parse(char *n case Opt_noacl: nfs_data.flags |= NFS_MOUNT_NOACL; break; +#ifndef CONFIG_TAGGING_NONE + case Opt_tag: + nfs_data.flags |= NFS_MOUNT_TAGGED; + break; + case Opt_notag: + nfs_data.flags &= ~NFS_MOUNT_TAGGED; + break; +#endif +#ifdef CONFIG_PROPAGATE + case Opt_tagid: + /* use args[0] */ + nfs_data.flags |= NFS_MOUNT_TAGGED; + break; +#endif default: printk(KERN_WARNING "Root-NFS: unknown " "option: %s\n", p); diff -NurpP --minimal linux-2.6.27.15/fs/nfs/super.c linux-2.6.27.15-g-v/fs/nfs/super.c --- linux-2.6.27.15/fs/nfs/super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfs/super.c 2009-02-10 20:32:14.000000000 +0100 @@ -51,6 +51,7 @@ #include #include #include +#include #include #include @@ -504,6 +505,7 @@ static void nfs_show_mount_options(struc { NFS_MOUNT_NOACL, ",noacl", "" }, { NFS_MOUNT_NORDIRPLUS, ",nordirplus", "" }, { NFS_MOUNT_UNSHARED, ",nosharecache", ""}, + { NFS_MOUNT_TAGGED, ",tag", "" }, { 0, NULL, NULL } }; const struct proc_nfs_info *nfs_infop; diff -NurpP --minimal linux-2.6.27.15/fs/nfsd/auth.c linux-2.6.27.15-g-v/fs/nfsd/auth.c --- linux-2.6.27.15/fs/nfsd/auth.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfsd/auth.c 2009-02-10 20:32:14.000000000 +0100 @@ -10,6 +10,7 @@ #include #include #include +#include #include "auth.h" int nfsexp_flags(struct svc_rqst *rqstp, struct svc_export *exp) @@ -55,19 +56,23 @@ int nfsd_setuser(struct svc_rqst *rqstp, get_group_info(cred.cr_group_info); if (cred.cr_uid != (uid_t) -1) - current->fsuid = cred.cr_uid; + current->fsuid = INOTAG_UID(DX_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 = INOTAG_GID(DX_TAG_NFSD, cred.cr_uid, cred.cr_gid); else current->fsgid = exp->ex_anon_gid; + /* this desperately needs a tag :) */ + current->xid = (xid_t)INOTAG_TAG(DX_TAG_NFSD, cred.cr_uid, cred.cr_gid, 0); + if (!cred.cr_group_info) return -ENOMEM; ret = set_current_groups(cred.cr_group_info); put_group_info(cred.cr_group_info); - if ((cred.cr_uid)) { + + if (INOTAG_UID(DX_TAG_NFSD, cred.cr_uid, cred.cr_gid)) { current->cap_effective = cap_drop_nfsd_set(current->cap_effective); } else { diff -NurpP --minimal linux-2.6.27.15/fs/nfsd/export.c linux-2.6.27.15-g-v/fs/nfsd/export.c --- linux-2.6.27.15/fs/nfsd/export.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfsd/export.c 2009-02-10 20:32:14.000000000 +0100 @@ -473,7 +473,7 @@ static int secinfo_parse(char **mesg, ch * probably discover the problem when someone fails to * authenticate. */ - if (f->pseudoflavor < 0) + if ((s32)f->pseudoflavor < 0) return -EINVAL; err = get_int(mesg, &f->flags); if (err) diff -NurpP --minimal linux-2.6.27.15/fs/nfsd/nfs3xdr.c linux-2.6.27.15-g-v/fs/nfsd/nfs3xdr.c --- linux-2.6.27.15/fs/nfsd/nfs3xdr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfsd/nfs3xdr.c 2009-02-10 20:32:14.000000000 +0100 @@ -21,6 +21,7 @@ #include #include #include +#include #include "auth.h" #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -108,6 +109,8 @@ static __be32 * decode_sattr3(__be32 *p, struct iattr *iap) { u32 tmp; + uid_t uid = 0; + gid_t gid = 0; iap->ia_valid = 0; @@ -117,12 +120,15 @@ decode_sattr3(__be32 *p, struct iattr *i } 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 = INOTAG_UID(DX_TAG_NFSD, uid, gid); + iap->ia_gid = INOTAG_GID(DX_TAG_NFSD, uid, gid); + iap->ia_tag = INOTAG_TAG(DX_TAG_NFSD, uid, gid, 0); if (*p++) { u64 newsize; @@ -178,8 +184,12 @@ encode_fattr3(struct svc_rqst *rqstp, __ *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, + TAGINO_UID(0 /* FIXME: DX_TAG(dentry->d_inode) */, + stat->uid, stat->tag))); + *p++ = htonl((u32) nfsd_rgid(rqstp, + TAGINO_GID(0 /* FIXME: DX_TAG(dentry->d_inode) */, + stat->gid, stat->tag))); if (S_ISLNK(stat->mode) && stat->size > NFS3_MAXPATHLEN) { p = xdr_encode_hyper(p, (u64) NFS3_MAXPATHLEN); } else { diff -NurpP --minimal linux-2.6.27.15/fs/nfsd/nfs4xdr.c linux-2.6.27.15-g-v/fs/nfsd/nfs4xdr.c --- linux-2.6.27.15/fs/nfsd/nfs4xdr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfsd/nfs4xdr.c 2009-02-10 20:32:14.000000000 +0100 @@ -58,6 +58,7 @@ #include #include #include +#include #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -1704,14 +1705,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, + TAGINO_UID(DX_TAG(dentry->d_inode), + stat.uid, stat.tag), &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, + TAGINO_GID(DX_TAG(dentry->d_inode), + stat.gid, stat.tag), &p, &buflen); if (status == nfserr_resource) goto out_resource; if (status) diff -NurpP --minimal linux-2.6.27.15/fs/nfsd/nfsxdr.c linux-2.6.27.15-g-v/fs/nfsd/nfsxdr.c --- linux-2.6.27.15/fs/nfsd/nfsxdr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nfsd/nfsxdr.c 2009-02-10 20:32:14.000000000 +0100 @@ -15,6 +15,7 @@ #include #include #include +#include #include "auth.h" #define NFSDDBG_FACILITY NFSDDBG_XDR @@ -98,6 +99,8 @@ static __be32 * decode_sattr(__be32 *p, struct iattr *iap) { u32 tmp, tmp1; + uid_t uid = 0; + gid_t gid = 0; iap->ia_valid = 0; @@ -111,12 +114,15 @@ decode_sattr(__be32 *p, struct iattr *ia } 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 = INOTAG_UID(DX_TAG_NFSD, uid, gid); + iap->ia_gid = INOTAG_GID(DX_TAG_NFSD, uid, gid); + iap->ia_tag = INOTAG_TAG(DX_TAG_NFSD, uid, gid, 0); if ((tmp = ntohl(*p++)) != (u32)-1) { iap->ia_valid |= ATTR_SIZE; iap->ia_size = tmp; @@ -161,8 +167,10 @@ encode_fattr(struct svc_rqst *rqstp, __b *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, + TAGINO_UID(DX_TAG(dentry->d_inode), stat->uid, stat->tag))); + *p++ = htonl((u32) nfsd_rgid(rqstp, + TAGINO_GID(DX_TAG(dentry->d_inode), stat->gid, stat->tag))); if (S_ISLNK(type) && stat->size > NFS_MAXPATHLEN) { *p++ = htonl(NFS_MAXPATHLEN); diff -NurpP --minimal linux-2.6.27.15/fs/nls/nls_base.c linux-2.6.27.15-g-v/fs/nls/nls_base.c --- linux-2.6.27.15/fs/nls/nls_base.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/nls/nls_base.c 2009-02-10 20:32:14.000000000 +0100 @@ -42,7 +42,7 @@ static const struct utf8_table utf8_tabl {0xF8, 0xF0, 3*6, 0x1FFFFF, 0x10000, /* 4 byte sequence */}, {0xFC, 0xF8, 4*6, 0x3FFFFFF, 0x200000, /* 5 byte sequence */}, {0xFE, 0xFC, 5*6, 0x7FFFFFFF, 0x4000000, /* 6 byte sequence */}, - {0, /* end of table */} + {0, 0, 0, 0, 0, /* end of table */} }; int diff -NurpP --minimal linux-2.6.27.15/fs/ntfs/file.c linux-2.6.27.15-g-v/fs/ntfs/file.c --- linux-2.6.27.15/fs/ntfs/file.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ntfs/file.c 2009-02-10 20:32:14.000000000 +0100 @@ -2291,6 +2291,6 @@ const struct inode_operations ntfs_file_ #endif /* NTFS_RW */ }; -const struct file_operations ntfs_empty_file_ops = {}; +const struct file_operations ntfs_empty_file_ops; -const struct inode_operations ntfs_empty_inode_ops = {}; +const struct inode_operations ntfs_empty_inode_ops; diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/dlm/dlmfs.c linux-2.6.27.15-g-v/fs/ocfs2/dlm/dlmfs.c --- linux-2.6.27.15/fs/ocfs2/dlm/dlmfs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/dlm/dlmfs.c 2009-02-10 20:32:14.000000000 +0100 @@ -43,6 +43,7 @@ #include #include #include +#include #include @@ -341,6 +342,7 @@ static struct inode *dlmfs_get_root_inod inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; + inode->i_tag = dx_current_fstag(sb); inode->i_blocks = 0; inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; @@ -367,6 +369,7 @@ static struct inode *dlmfs_get_inode(str inode->i_mode = mode; inode->i_uid = current->fsuid; inode->i_gid = current->fsgid; + inode->i_tag = dx_current_fstag(sb); inode->i_blocks = 0; inode->i_mapping->backing_dev_info = &dlmfs_backing_dev_info; inode->i_atime = inode->i_mtime = inode->i_ctime = CURRENT_TIME; diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/dlmglue.c linux-2.6.27.15-g-v/fs/ocfs2/dlmglue.c --- linux-2.6.27.15/fs/ocfs2/dlmglue.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/dlmglue.c 2009-02-10 20:32:14.000000000 +0100 @@ -1846,6 +1846,7 @@ static void __ocfs2_stuff_meta_lvb(struc lvb->lvb_iclusters = cpu_to_be32(oi->ip_clusters); lvb->lvb_iuid = cpu_to_be32(inode->i_uid); lvb->lvb_igid = cpu_to_be32(inode->i_gid); + lvb->lvb_itag = cpu_to_be16(inode->i_tag); lvb->lvb_imode = cpu_to_be16(inode->i_mode); lvb->lvb_inlink = cpu_to_be16(inode->i_nlink); lvb->lvb_iatime_packed = @@ -1900,6 +1901,7 @@ static void ocfs2_refresh_inode_from_lvb inode->i_uid = be32_to_cpu(lvb->lvb_iuid); inode->i_gid = be32_to_cpu(lvb->lvb_igid); + inode->i_tag = be16_to_cpu(lvb->lvb_itag); inode->i_mode = be16_to_cpu(lvb->lvb_imode); inode->i_nlink = be16_to_cpu(lvb->lvb_inlink); ocfs2_unpack_timespec(&inode->i_atime, diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/dlmglue.h linux-2.6.27.15-g-v/fs/ocfs2/dlmglue.h --- linux-2.6.27.15/fs/ocfs2/dlmglue.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/dlmglue.h 2009-02-10 20:32:14.000000000 +0100 @@ -46,7 +46,8 @@ struct ocfs2_meta_lvb { __be16 lvb_inlink; __be32 lvb_iattr; __be32 lvb_igeneration; - __be32 lvb_reserved2; + __be16 lvb_itag; + __be16 lvb_reserved2; }; /* ocfs2_inode_lock_full() 'arg_flags' flags */ diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/file.c linux-2.6.27.15-g-v/fs/ocfs2/file.c --- linux-2.6.27.15/fs/ocfs2/file.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/file.c 2009-02-10 20:32:14.000000000 +0100 @@ -1058,13 +1058,15 @@ int ocfs2_setattr(struct dentry *dentry, mlog(0, "uid change: %d\n", attr->ia_uid); if (attr->ia_valid & ATTR_GID) mlog(0, "gid change: %d\n", attr->ia_gid); + if (attr->ia_valid & ATTR_TAG) + mlog(0, "tag change: %d\n", attr->ia_tag); if (attr->ia_valid & ATTR_SIZE) mlog(0, "size change...\n"); if (attr->ia_valid & (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME)) mlog(0, "time change...\n"); #define OCFS2_VALID_ATTRS (ATTR_ATIME | ATTR_MTIME | ATTR_CTIME | ATTR_SIZE \ - | ATTR_GID | ATTR_UID | ATTR_MODE) + | ATTR_GID | ATTR_UID | ATTR_TAG | ATTR_MODE) if (!(attr->ia_valid & OCFS2_VALID_ATTRS)) { mlog(0, "can't handle attrs: 0x%x\n", attr->ia_valid); return 0; @@ -2227,6 +2229,7 @@ const struct inode_operations ocfs2_file .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, .permission = ocfs2_permission, + .sync_flags = ocfs2_sync_flags, .fallocate = ocfs2_fallocate, }; diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/inode.c linux-2.6.27.15-g-v/fs/ocfs2/inode.c --- linux-2.6.27.15/fs/ocfs2/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -28,6 +28,7 @@ #include #include #include +#include #include @@ -42,6 +43,7 @@ #include "file.h" #include "heartbeat.h" #include "inode.h" +#include "ioctl.h" #include "journal.h" #include "namei.h" #include "suballoc.h" @@ -74,11 +76,13 @@ void ocfs2_set_inode_flags(struct inode { unsigned int flags = OCFS2_I(inode)->ip_attr; - inode->i_flags &= ~(S_IMMUTABLE | + inode->i_flags &= ~(S_IMMUTABLE | S_IXUNLINK | S_SYNC | S_APPEND | S_NOATIME | S_DIRSYNC); if (flags & OCFS2_IMMUTABLE_FL) inode->i_flags |= S_IMMUTABLE; + if (flags & OCFS2_IXUNLINK_FL) + inode->i_flags |= S_IXUNLINK; if (flags & OCFS2_SYNC_FL) inode->i_flags |= S_SYNC; @@ -88,25 +92,85 @@ void ocfs2_set_inode_flags(struct inode inode->i_flags |= S_NOATIME; if (flags & OCFS2_DIRSYNC_FL) inode->i_flags |= S_DIRSYNC; + + inode->i_vflags &= ~(V_BARRIER | V_COW); + + if (flags & OCFS2_BARRIER_FL) + inode->i_vflags |= V_BARRIER; + if (flags & OCFS2_COW_FL) + inode->i_vflags |= V_COW; } /* Propagate flags from i_flags to OCFS2_I(inode)->ip_attr */ void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi) { unsigned int flags = oi->vfs_inode.i_flags; + unsigned int vflags = oi->vfs_inode.i_vflags; + + oi->ip_attr &= ~(OCFS2_SYNC_FL | OCFS2_APPEND_FL | + OCFS2_IMMUTABLE_FL | OCFS2_IXUNLINK_FL | + OCFS2_NOATIME_FL | OCFS2_DIRSYNC_FL | + OCFS2_BARRIER_FL | OCFS2_COW_FL); + + if (flags & S_IMMUTABLE) + oi->ip_attr |= OCFS2_IMMUTABLE_FL; + if (flags & S_IXUNLINK) + oi->ip_attr |= OCFS2_IXUNLINK_FL; - oi->ip_attr &= ~(OCFS2_SYNC_FL|OCFS2_APPEND_FL| - OCFS2_IMMUTABLE_FL|OCFS2_NOATIME_FL|OCFS2_DIRSYNC_FL); if (flags & S_SYNC) oi->ip_attr |= OCFS2_SYNC_FL; if (flags & S_APPEND) oi->ip_attr |= OCFS2_APPEND_FL; - if (flags & S_IMMUTABLE) - oi->ip_attr |= OCFS2_IMMUTABLE_FL; if (flags & S_NOATIME) oi->ip_attr |= OCFS2_NOATIME_FL; if (flags & S_DIRSYNC) oi->ip_attr |= OCFS2_DIRSYNC_FL; + + if (vflags & V_BARRIER) + oi->ip_attr |= OCFS2_BARRIER_FL; + if (vflags & V_COW) + oi->ip_attr |= OCFS2_COW_FL; +} + +int ocfs2_sync_flags(struct inode *inode) +{ + struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); + struct ocfs2_super *osb = OCFS2_SB(inode->i_sb); + handle_t *handle = NULL; + struct buffer_head *bh = NULL; + int status; + + status = ocfs2_inode_lock(inode, &bh, 1); + if (status < 0) { + mlog_errno(status); + goto bail; + } + + status = -EROFS; + if (IS_RDONLY(inode)) + goto bail_unlock; + + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); + if (IS_ERR(handle)) { + status = PTR_ERR(handle); + mlog_errno(status); + goto bail_unlock; + } + + ocfs2_get_inode_flags(ocfs2_inode); + status = ocfs2_mark_inode_dirty(handle, inode, bh); + if (status < 0) + mlog_errno(status); + + ocfs2_commit_trans(osb, handle); +bail_unlock: + ocfs2_inode_unlock(inode, 1); +bail: + if (bh) + brelse(bh); + + mlog_exit(status); + return status; } struct inode *ocfs2_iget(struct ocfs2_super *osb, u64 blkno, unsigned flags, @@ -219,6 +283,8 @@ int ocfs2_populate_inode(struct inode *i struct super_block *sb; struct ocfs2_super *osb; int status = -EINVAL; + uid_t uid; + gid_t gid; mlog_entry("(0x%p, size:%llu)\n", inode, (unsigned long long)le64_to_cpu(fe->i_size)); @@ -254,8 +320,12 @@ int ocfs2_populate_inode(struct inode *i inode->i_generation = le32_to_cpu(fe->i_generation); inode->i_rdev = huge_decode_dev(le64_to_cpu(fe->id1.dev1.i_rdev)); inode->i_mode = le16_to_cpu(fe->i_mode); - inode->i_uid = le32_to_cpu(fe->i_uid); - inode->i_gid = le32_to_cpu(fe->i_gid); + uid = le32_to_cpu(fe->i_uid); + gid = le32_to_cpu(fe->i_gid); + inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); + inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); + inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, + /* le16_to_cpu(raw_inode->i_raw_tag)i */ 0); /* Fast symlinks will have i_size but no allocated clusters. */ if (S_ISLNK(inode->i_mode) && !fe->i_clusters) @@ -1230,8 +1300,11 @@ int ocfs2_mark_inode_dirty(handle_t *han fe->i_size = cpu_to_le64(i_size_read(inode)); fe->i_links_count = cpu_to_le16(inode->i_nlink); - fe->i_uid = cpu_to_le32(inode->i_uid); - fe->i_gid = cpu_to_le32(inode->i_gid); + fe->i_uid = cpu_to_le32(TAGINO_UID(DX_TAG(inode), + inode->i_uid, inode->i_tag)); + fe->i_gid = cpu_to_le32(TAGINO_GID(DX_TAG(inode), + inode->i_gid, inode->i_tag)); + /* i_tag = = cpu_to_le16(inode->i_tag); */ fe->i_mode = cpu_to_le16(inode->i_mode); fe->i_atime = cpu_to_le64(inode->i_atime.tv_sec); fe->i_atime_nsec = cpu_to_le32(inode->i_atime.tv_nsec); @@ -1259,16 +1332,25 @@ leave: void ocfs2_refresh_inode(struct inode *inode, struct ocfs2_dinode *fe) { + uid_t uid; + gid_t gid; + spin_lock(&OCFS2_I(inode)->ip_lock); OCFS2_I(inode)->ip_clusters = le32_to_cpu(fe->i_clusters); OCFS2_I(inode)->ip_attr = le32_to_cpu(fe->i_attr); + /* OCFS2_I(inode)->ip_flags &= ~OCFS2_FL_MASK; + OCFS2_I(inode)->ip_flags |= le32_to_cpu(fe->i_flags) & OCFS2_FL_MASK; */ OCFS2_I(inode)->ip_dyn_features = le16_to_cpu(fe->i_dyn_features); ocfs2_set_inode_flags(inode); i_size_write(inode, le64_to_cpu(fe->i_size)); inode->i_nlink = le16_to_cpu(fe->i_links_count); - inode->i_uid = le32_to_cpu(fe->i_uid); - inode->i_gid = le32_to_cpu(fe->i_gid); + uid = le32_to_cpu(fe->i_uid); + gid = le32_to_cpu(fe->i_gid); + inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); + inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); + inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, + /* le16_to_cpu(raw_inode->i_raw_tag)i */ 0); inode->i_mode = le16_to_cpu(fe->i_mode); if (S_ISLNK(inode->i_mode) && le32_to_cpu(fe->i_clusters) == 0) inode->i_blocks = 0; diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/inode.h linux-2.6.27.15-g-v/fs/ocfs2/inode.h --- linux-2.6.27.15/fs/ocfs2/inode.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/inode.h 2009-02-10 20:32:14.000000000 +0100 @@ -143,6 +143,7 @@ int ocfs2_aio_write(struct file *file, s void ocfs2_set_inode_flags(struct inode *inode); void ocfs2_get_inode_flags(struct ocfs2_inode_info *oi); +int ocfs2_sync_flags(struct inode *inode); static inline blkcnt_t ocfs2_inode_sector_count(struct inode *inode) { diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/ioctl.c linux-2.6.27.15-g-v/fs/ocfs2/ioctl.c --- linux-2.6.27.15/fs/ocfs2/ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -42,7 +42,7 @@ static int ocfs2_get_inode_attr(struct i return status; } -static int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, +int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, unsigned mask) { struct ocfs2_inode_info *ocfs2_inode = OCFS2_I(inode); @@ -67,6 +67,11 @@ static int ocfs2_set_inode_attr(struct i if (!S_ISDIR(inode->i_mode)) flags &= ~OCFS2_DIRSYNC_FL; + if (IS_BARRIER(inode)) { + vxwprintk_task(1, "messing with the barrier."); + goto bail_unlock; + } + handle = ocfs2_start_trans(osb, OCFS2_INODE_UPDATE_CREDITS); if (IS_ERR(handle)) { status = PTR_ERR(handle); diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/ioctl.h linux-2.6.27.15-g-v/fs/ocfs2/ioctl.h --- linux-2.6.27.15/fs/ocfs2/ioctl.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/ioctl.h 2009-02-10 20:32:14.000000000 +0100 @@ -10,6 +10,9 @@ #ifndef OCFS2_IOCTL_H #define OCFS2_IOCTL_H +int ocfs2_set_inode_attr(struct inode *inode, unsigned flags, + unsigned mask); + long ocfs2_ioctl(struct file *filp, unsigned int cmd, unsigned long arg); long ocfs2_compat_ioctl(struct file *file, unsigned cmd, unsigned long arg); diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/namei.c linux-2.6.27.15-g-v/fs/ocfs2/namei.c --- linux-2.6.27.15/fs/ocfs2/namei.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/namei.c 2009-02-10 20:32:14.000000000 +0100 @@ -40,6 +40,7 @@ #include #include #include +#include #define MLOG_MASK_PREFIX ML_NAMEI #include @@ -366,6 +367,9 @@ static int ocfs2_mknod_locked(struct ocf u64 fe_blkno = 0; u16 suballoc_bit; struct inode *inode = NULL; + uid_t uid; + gid_t gid; + tag_t tag; mlog_entry("(0x%p, 0x%p, %d, %lu, '%.*s')\n", dir, dentry, mode, (unsigned long)dev, dentry->d_name.len, @@ -425,13 +429,19 @@ static int ocfs2_mknod_locked(struct ocf fe->i_blkno = cpu_to_le64(fe_blkno); fe->i_suballoc_bit = cpu_to_le16(suballoc_bit); fe->i_suballoc_slot = cpu_to_le16(inode_ac->ac_alloc_slot); - fe->i_uid = cpu_to_le32(current->fsuid); + + tag = dx_current_fstag(osb->sb); + uid = current->fsuid; if (dir->i_mode & S_ISGID) { - fe->i_gid = cpu_to_le32(dir->i_gid); + gid = dir->i_gid; if (S_ISDIR(mode)) mode |= S_ISGID; } else - fe->i_gid = cpu_to_le32(current->fsgid); + gid = current->fsgid; + + fe->i_uid = cpu_to_le32(TAGINO_UID(DX_TAG(inode), uid, tag)); + fe->i_gid = cpu_to_le32(TAGINO_GID(DX_TAG(inode), gid, tag)); + inode->i_tag = tag; fe->i_mode = cpu_to_le16(mode); if (S_ISCHR(mode) || S_ISBLK(mode)) fe->id1.dev1.i_rdev = cpu_to_le64(huge_encode_dev(dev)); @@ -1917,5 +1927,6 @@ const struct inode_operations ocfs2_dir_ .rename = ocfs2_rename, .setattr = ocfs2_setattr, .getattr = ocfs2_getattr, + .sync_flags = ocfs2_sync_flags, .permission = ocfs2_permission, }; diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/ocfs2_fs.h linux-2.6.27.15-g-v/fs/ocfs2/ocfs2_fs.h --- linux-2.6.27.15/fs/ocfs2/ocfs2_fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/ocfs2_fs.h 2009-02-10 20:32:14.000000000 +0100 @@ -195,18 +195,23 @@ #define OCFS2_INDEXED_DIR_FL (0x0008) /* Inode attributes, keep in sync with EXT2 */ -#define OCFS2_SECRM_FL (0x00000001) /* Secure deletion */ -#define OCFS2_UNRM_FL (0x00000002) /* Undelete */ -#define OCFS2_COMPR_FL (0x00000004) /* Compress file */ -#define OCFS2_SYNC_FL (0x00000008) /* Synchronous updates */ -#define OCFS2_IMMUTABLE_FL (0x00000010) /* Immutable file */ -#define OCFS2_APPEND_FL (0x00000020) /* writes to file may only append */ -#define OCFS2_NODUMP_FL (0x00000040) /* do not dump file */ -#define OCFS2_NOATIME_FL (0x00000080) /* do not update atime */ -#define OCFS2_DIRSYNC_FL (0x00010000) /* dirsync behaviour (directories only) */ +#define OCFS2_SECRM_FL FS_SECRM_FL /* Secure deletion */ +#define OCFS2_UNRM_FL FS_UNRM_FL /* Undelete */ +#define OCFS2_COMPR_FL FS_COMPR_FL /* Compress file */ +#define OCFS2_SYNC_FL FS_SYNC_FL /* Synchronous updates */ +#define OCFS2_IMMUTABLE_FL FS_IMMUTABLE_FL /* Immutable file */ +#define OCFS2_APPEND_FL FS_APPEND_FL /* writes to file may only append */ +#define OCFS2_NODUMP_FL FS_NODUMP_FL /* do not dump file */ +#define OCFS2_NOATIME_FL FS_NOATIME_FL /* do not update atime */ -#define OCFS2_FL_VISIBLE (0x000100FF) /* User visible flags */ -#define OCFS2_FL_MODIFIABLE (0x000100FF) /* User modifiable flags */ +#define OCFS2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */ +#define OCFS2_IXUNLINK_FL FS_IXUNLINK_FL /* Immutable invert on unlink */ + +#define OCFS2_BARRIER_FL FS_BARRIER_FL /* Barrier for chroot() */ +#define OCFS2_COW_FL FS_COW_FL /* Copy on Write marker */ + +#define OCFS2_FL_VISIBLE (0x010300FF) /* User visible flags */ +#define OCFS2_FL_MODIFIABLE (0x010300FF) /* User modifiable flags */ /* * Extent record flags (e_node.leaf.flags) diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/ocfs2.h linux-2.6.27.15-g-v/fs/ocfs2/ocfs2.h --- linux-2.6.27.15/fs/ocfs2/ocfs2.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/ocfs2.h 2009-02-10 20:32:14.000000000 +0100 @@ -184,6 +184,7 @@ enum ocfs2_mount_options OCFS2_MOUNT_ERRORS_PANIC = 1 << 3, /* Panic on errors */ OCFS2_MOUNT_DATA_WRITEBACK = 1 << 4, /* No data ordering */ OCFS2_MOUNT_LOCALFLOCKS = 1 << 5, /* No cluster aware user file locks */ + OCFS2_MOUNT_TAGGED = 1 << 8, /* use tagging */ }; #define OCFS2_OSB_SOFT_RO 0x0001 diff -NurpP --minimal linux-2.6.27.15/fs/ocfs2/super.c linux-2.6.27.15-g-v/fs/ocfs2/super.c --- linux-2.6.27.15/fs/ocfs2/super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ocfs2/super.c 2009-02-10 20:32:14.000000000 +0100 @@ -154,6 +154,7 @@ enum { Opt_localalloc, Opt_localflocks, Opt_stack, + Opt_tag, Opt_notag, Opt_tagid, Opt_err, }; @@ -173,6 +174,9 @@ static match_table_t tokens = { {Opt_localalloc, "localalloc=%d"}, {Opt_localflocks, "localflocks"}, {Opt_stack, "cluster_stack=%s"}, + {Opt_tag, "tag"}, + {Opt_notag, "notag"}, + {Opt_tagid, "tagid=%u"}, {Opt_err, NULL} }; @@ -392,6 +396,13 @@ static int ocfs2_remount(struct super_bl goto out; } + if ((parsed_options.mount_opt & OCFS2_MOUNT_TAGGED) && + !(sb->s_flags & MS_TAGGED)) { + ret = -EINVAL; + mlog(ML_ERROR, "Cannot change tagging on remount\n"); + goto out; + } + if ((osb->s_mount_opt & OCFS2_MOUNT_HB_LOCAL) != (parsed_options.mount_opt & OCFS2_MOUNT_HB_LOCAL)) { ret = -EINVAL; @@ -725,6 +736,9 @@ static int ocfs2_fill_super(struct super ocfs2_complete_mount_recovery(osb); + if (osb->s_mount_opt & OCFS2_MOUNT_TAGGED) + sb->s_flags |= MS_TAGGED; + if (ocfs2_mount_local(osb)) snprintf(nodestr, sizeof(nodestr), "local"); else @@ -918,6 +932,20 @@ static int ocfs2_parse_options(struct su OCFS2_STACK_LABEL_LEN); mopt->cluster_stack[OCFS2_STACK_LABEL_LEN] = '\0'; break; +#ifndef CONFIG_TAGGING_NONE + case Opt_tag: + mopt->mount_opt |= OCFS2_MOUNT_TAGGED; + break; + case Opt_notag: + mopt->mount_opt &= ~OCFS2_MOUNT_TAGGED; + break; +#endif +#ifdef CONFIG_PROPAGATE + case Opt_tagid: + /* use args[0] */ + mopt->mount_opt |= OCFS2_MOUNT_TAGGED; + break; +#endif default: mlog(ML_ERROR, "Unrecognized mount option \"%s\" " diff -NurpP --minimal linux-2.6.27.15/fs/open.c linux-2.6.27.15-g-v/fs/open.c --- linux-2.6.27.15/fs/open.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/open.c 2009-02-10 20:32:14.000000000 +0100 @@ -29,22 +29,32 @@ #include #include #include +#include +#include +#include +#include +#include +#include int vfs_statfs(struct dentry *dentry, struct kstatfs *buf) { int retval = -ENODEV; if (dentry) { + struct super_block *sb = dentry->d_sb; + retval = -ENOSYS; - if (dentry->d_sb->s_op->statfs) { + if (sb->s_op->statfs) { memset(buf, 0, sizeof(*buf)); retval = security_sb_statfs(dentry); if (retval) return retval; - retval = dentry->d_sb->s_op->statfs(dentry, buf); + retval = sb->s_op->statfs(dentry, buf); if (retval == 0 && buf->f_frsize == 0) buf->f_frsize = buf->f_bsize; } + if (!vx_check(0, VS_ADMIN|VS_WATCH)) + vx_vsi_statfs(sb, buf); } return retval; } @@ -205,6 +215,9 @@ int do_truncate(struct dentry *dentry, l if (length < 0) return -EINVAL; + if (filp && !gr_acl_handle_truncate(dentry, filp->f_path.mnt)) + return -EACCES; + newattrs.ia_size = length; newattrs.ia_valid = ATTR_SIZE | time_attrs; if (filp) { @@ -510,6 +523,9 @@ SYSCALL_DEFINE3(faccessat, int, dfd, con if (__mnt_is_readonly(path.mnt)) res = -EROFS; + if (!res && !gr_acl_handle_access(path.dentry, path.mnt, mode)) + res = -EACCES; + out_path_release: path_put(&path); out: @@ -540,6 +556,8 @@ SYSCALL_DEFINE1(chdir, const char __user if (error) goto dput_and_out; + gr_log_chdir(path.dentry, path.mnt); + set_fs_pwd(current->fs, &path); dput_and_out: @@ -566,6 +584,13 @@ SYSCALL_DEFINE1(fchdir, unsigned int, fd goto out_putf; error = inode_permission(inode, MAY_EXEC | MAY_ACCESS); + + if (!error && !gr_chroot_fchdir(file->f_path.dentry, file->f_path.mnt)) + error = -EPERM; + + if (!error) + gr_log_chdir(file->f_path.dentry, file->f_path.mnt); + if (!error) set_fs_pwd(current->fs, &file->f_path); out_putf: @@ -591,7 +616,14 @@ SYSCALL_DEFINE1(chroot, const char __use if (!capable(CAP_SYS_CHROOT)) goto dput_and_out; + if (gr_handle_chroot_chroot(path.dentry, path.mnt)) + goto dput_and_out; + set_fs_root(current->fs, &path); + + gr_handle_chroot_caps(current); + gr_handle_chroot_chdir(&path); + error = 0; dput_and_out: path_put(&path); @@ -619,13 +651,28 @@ SYSCALL_DEFINE2(fchmod, unsigned int, fd err = mnt_want_write(file->f_path.mnt); if (err) goto out_putf; + + if (!gr_acl_handle_fchmod(dentry, file->f_path.mnt, mode)) { + err = -EACCES; + goto out_drop_write; + } + mutex_lock(&inode->i_mutex); if (mode == (mode_t) -1) mode = inode->i_mode; + + if (gr_handle_chroot_chmod(dentry, file->f_path.mnt, mode)) { + err = -EPERM; + mutex_unlock(&inode->i_mutex); + goto out_drop_write; + } + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; err = notify_change(dentry, &newattrs); mutex_unlock(&inode->i_mutex); + +out_drop_write: mnt_drop_write(file->f_path.mnt); out_putf: fput(file); @@ -643,18 +690,37 @@ SYSCALL_DEFINE3(fchmodat, int, dfd, cons error = user_path_at(dfd, filename, LOOKUP_FOLLOW, &path); if (error) goto out; + + error = cow_check_and_break(&path); + if (error) + goto dput_and_out; inode = path.dentry->d_inode; error = mnt_want_write(path.mnt); if (error) goto dput_and_out; + + if (!gr_acl_handle_chmod(path.dentry, path.mnt, mode)) { + error = -EACCES; + goto out_drop_write; + } + mutex_lock(&inode->i_mutex); if (mode == (mode_t) -1) mode = inode->i_mode; + + if (gr_handle_chroot_chmod(path.dentry, path.mnt, mode)) { + error = -EACCES; + mutex_unlock(&inode->i_mutex); + goto out_drop_write; + } + newattrs.ia_mode = (mode & S_IALLUGO) | (inode->i_mode & ~S_IALLUGO); newattrs.ia_valid = ATTR_MODE | ATTR_CTIME; error = notify_change(path.dentry, &newattrs); mutex_unlock(&inode->i_mutex); + +out_drop_write: mnt_drop_write(path.mnt); dput_and_out: path_put(&path); @@ -667,20 +733,23 @@ SYSCALL_DEFINE2(chmod, const char __user return sys_fchmodat(AT_FDCWD, filename, mode); } -static int chown_common(struct dentry * dentry, uid_t user, gid_t group) +static int chown_common(struct dentry * dentry, uid_t user, gid_t group, struct vfsmount *mnt) { struct inode *inode = dentry->d_inode; int error; struct iattr newattrs; + if (!gr_acl_handle_chown(dentry, mnt)) + return -EACCES; + newattrs.ia_valid = ATTR_CTIME; if (user != (uid_t) -1) { newattrs.ia_valid |= ATTR_UID; - newattrs.ia_uid = user; + newattrs.ia_uid = dx_map_uid(user); } if (group != (gid_t) -1) { newattrs.ia_valid |= ATTR_GID; - newattrs.ia_gid = group; + newattrs.ia_gid = dx_map_gid(group); } if (!S_ISDIR(inode->i_mode)) newattrs.ia_valid |= @@ -703,7 +772,11 @@ SYSCALL_DEFINE3(chown, const char __user error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); +#ifdef CONFIG_VSERVER_COWBL + error = cow_check_and_break(&path); + if (!error) +#endif + error = chown_common(path.dentry, user, group, path.mnt); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -728,7 +801,11 @@ SYSCALL_DEFINE5(fchownat, int, dfd, cons error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); +#ifdef CONFIG_VSERVER_COWBL + error = cow_check_and_break(&path); + if (!error) +#endif + error = chown_common(path.dentry, user, group, path.mnt); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -747,7 +824,11 @@ SYSCALL_DEFINE3(lchown, const char __use error = mnt_want_write(path.mnt); if (error) goto out_release; - error = chown_common(path.dentry, user, group); +#ifdef CONFIG_VSERVER_COWBL + error = cow_check_and_break(&path); + if (!error) +#endif + error = chown_common(path.dentry, user, group, path.mnt); mnt_drop_write(path.mnt); out_release: path_put(&path); @@ -770,7 +851,7 @@ SYSCALL_DEFINE3(fchown, unsigned int, fd goto out_fput; dentry = file->f_path.dentry; audit_inode(NULL, dentry); - error = chown_common(dentry, user, group); + error = chown_common(dentry, user, group, file->f_path.mnt); mnt_drop_write(file->f_path.mnt); out_fput: fput(file); @@ -986,6 +1067,7 @@ static void __put_unused_fd(struct files __FD_CLR(fd, fdt->open_fds); if (fd < files->next_fd) files->next_fd = fd; + vx_openfd_dec(fd); } void put_unused_fd(unsigned int fd) diff -NurpP --minimal linux-2.6.27.15/fs/pipe.c linux-2.6.27.15-g-v/fs/pipe.c --- linux-2.6.27.15/fs/pipe.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/pipe.c 2009-02-10 20:32:14.000000000 +0100 @@ -851,7 +851,7 @@ void free_pipe_info(struct inode *inode) inode->i_pipe = NULL; } -static struct vfsmount *pipe_mnt __read_mostly; +struct vfsmount *pipe_mnt __read_mostly; static int pipefs_delete_dentry(struct dentry *dentry) { /* diff -NurpP --minimal linux-2.6.27.15/fs/proc/array.c linux-2.6.27.15-g-v/fs/proc/array.c --- linux-2.6.27.15/fs/proc/array.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/array.c 2009-02-10 20:32:14.000000000 +0100 @@ -81,6 +81,8 @@ #include #include #include +#include +#include #include #include @@ -142,8 +144,9 @@ static const char *task_state_array[] = "D (disk sleep)", /* 2 */ "T (stopped)", /* 4 */ "T (tracing stop)", /* 8 */ - "Z (zombie)", /* 16 */ - "X (dead)" /* 32 */ + "H (on hold)", /* 16 */ + "Z (zombie)", /* 32 */ + "X (dead)", /* 64 */ }; static inline const char *get_task_state(struct task_struct *tsk) @@ -164,6 +167,7 @@ static inline void task_state(struct seq struct group_info *group_info; int g; struct fdtable *fdt = NULL; +/* + pid_t pid, ptgid, tppid, tgid; */ pid_t ppid, tpid; rcu_read_lock(); @@ -175,6 +179,12 @@ static inline void task_state(struct seq if (tracer) tpid = task_pid_nr_ns(tracer, ns); } +/* tgid = vx_map_tgid(p->tgid); + pid = vx_map_pid(p->pid); + ptgid = vx_map_pid(pid_alive(p) ? + rcu_dereference(p->real_parent)->tgid : 0); + tppid = vx_map_pid(pid_alive(p) && p->ptrace ? + rcu_dereference(p->parent)->pid : 0); */ seq_printf(m, "State:\t%s\n" "Tgid:\t%d\n" @@ -286,7 +296,7 @@ static inline void task_sig(struct seq_f } static void render_cap_t(struct seq_file *m, const char *header, - kernel_cap_t *a) + struct vx_info *vxi, kernel_cap_t *a) { unsigned __capi; @@ -300,10 +310,10 @@ static void render_cap_t(struct seq_file static inline void task_cap(struct seq_file *m, struct task_struct *p) { - render_cap_t(m, "CapInh:\t", &p->cap_inheritable); - render_cap_t(m, "CapPrm:\t", &p->cap_permitted); - render_cap_t(m, "CapEff:\t", &p->cap_effective); - render_cap_t(m, "CapBnd:\t", &p->cap_bset); + render_cap_t(m, "CapInh:\t", p->vx_info, &p->cap_inheritable); + render_cap_t(m, "CapPrm:\t", p->vx_info, &p->cap_permitted); + render_cap_t(m, "CapEff:\t", p->vx_info, &p->cap_effective); + render_cap_t(m, "CapBnd:\t", p->vx_info, &p->cap_bset); } static inline void task_context_switch_counts(struct seq_file *m, @@ -315,6 +325,60 @@ static inline void task_context_switch_c p->nivcsw); } +int proc_pid_nsproxy(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task) +{ + seq_printf(m, "Proxy:\t%p(%c)\n" + "Count:\t%u\n" + "uts:\t%p(%c)\n" + "ipc:\t%p(%c)\n" + "mnt:\t%p(%c)\n" + "pid:\t%p(%c)\n" + "user:\t%p(%c)\n" + "net:\t%p(%c)\n", + task->nsproxy, + (task->nsproxy == init_task.nsproxy ? 'I' : '-'), + atomic_read(&task->nsproxy->count), + task->nsproxy->uts_ns, + (task->nsproxy->uts_ns == init_task.nsproxy->uts_ns ? 'I' : '-'), + task->nsproxy->ipc_ns, + (task->nsproxy->ipc_ns == init_task.nsproxy->ipc_ns ? 'I' : '-'), + task->nsproxy->mnt_ns, + (task->nsproxy->mnt_ns == init_task.nsproxy->mnt_ns ? 'I' : '-'), + task->nsproxy->pid_ns, + (task->nsproxy->pid_ns == init_task.nsproxy->pid_ns ? 'I' : '-'), + task->nsproxy->user_ns, + (task->nsproxy->user_ns == init_task.nsproxy->user_ns ? 'I' : '-'), + task->nsproxy->net_ns, + (task->nsproxy->net_ns == init_task.nsproxy->net_ns ? 'I' : '-')); + return 0; +} + +void task_vs_id(struct seq_file *m, struct task_struct *task) +{ + if (task_vx_flags(task, VXF_HIDE_VINFO, 0)) + return; + + seq_printf(m, "VxID: %d\n", vx_task_xid(task)); + seq_printf(m, "NxID: %d\n", nx_task_nid(task)); +} + + +#if defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) +static inline void task_pax(struct seq_file *m, struct task_struct *p) +{ + if (p->mm) + seq_printf(m, "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 + seq_printf(m, "PaX:\t-----\n"); +} +#endif + int proc_pid_status(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task) { @@ -330,13 +394,25 @@ int proc_pid_status(struct seq_file *m, task_sig(m, task); task_cap(m, task); cpuset_task_status_allowed(m, task); + task_vs_id(m, task); #if defined(CONFIG_S390) task_show_regs(m, task); #endif task_context_switch_counts(m, task); + +#if defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) + task_pax(m, task); +#endif + return 0; } +#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 seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task, int whole) { @@ -429,6 +505,19 @@ static int do_task_stat(struct seq_file gtime = task_gtime(task); } +#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); @@ -442,6 +531,17 @@ static int do_task_stat(struct seq_file /* 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; + } + seq_printf(m, "%d (%s) %c %d %d %d %d %d %u %lu \ %lu %lu %lu %lu %lu %ld %ld %ld %ld %d 0 %llu %lu %ld %lu %lu %lu %lu %lu \ %lu %lu %lu %lu %lu %lu %lu %lu %d %d %u %u %llu %lu %ld\n", @@ -469,9 +569,15 @@ static int do_task_stat(struct seq_file vsize, mm ? get_mm_rss(mm) : 0, 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. @@ -524,3 +630,10 @@ int proc_pid_statm(struct seq_file *m, s return 0; } + +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR +int proc_pid_ipaddr(struct task_struct *task, char *buffer) +{ + return sprintf(buffer, "%u.%u.%u.%u\n", NIPQUAD(task->signal->curr_ip)); +} +#endif diff -NurpP --minimal linux-2.6.27.15/fs/proc/base.c linux-2.6.27.15-g-v/fs/proc/base.c --- linux-2.6.27.15/fs/proc/base.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/base.c 2009-02-10 20:32:14.000000000 +0100 @@ -79,6 +79,9 @@ #include #include #include +#include +#include +#include #include "internal.h" /* NOTE: @@ -148,7 +151,7 @@ static unsigned int pid_entry_count_dirs return count; } -int maps_protect; +int maps_protect = 1; EXPORT_SYMBOL(maps_protect); static struct fs_struct *get_fs_struct(struct task_struct *task) @@ -229,6 +232,9 @@ static int check_mem_permission(struct t if (task == current) return 0; + if (gr_handle_proc_ptrace(task) || gr_acl_handle_procpidmem(task)) + return -EPERM; + /* * If current is actively ptrace'ing, and would also be * permitted to freshly attach with ptrace now, permit it. @@ -312,9 +318,9 @@ static int proc_pid_auxv(struct task_str struct mm_struct *mm = get_task_mm(task); if (mm) { unsigned int nwords = 0; - do + do { nwords += 2; - while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ + } while (mm->saved_auxv[nwords - 2] != 0); /* AT_NULL */ res = nwords * sizeof(mm->saved_auxv[0]); if (res > PAGE_SIZE) res = PAGE_SIZE; @@ -1437,8 +1443,14 @@ static struct inode *proc_pid_make_inode inode->i_gid = 0; if (task_dumpable(task)) { inode->i_uid = task->euid; +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#else inode->i_gid = task->egid; +#endif } + /* procfs is xid tagged */ + inode->i_tag = (tag_t)vx_task_xid(task); security_task_to_inode(task, inode); out: @@ -1453,17 +1465,45 @@ static int pid_getattr(struct vfsmount * { struct inode *inode = dentry->d_inode; struct task_struct *task; +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + struct task_struct *tmp = current; +#endif + generic_fillattr(inode, stat); rcu_read_lock(); stat->uid = 0; stat->gid = 0; task = pid_task(proc_pid(inode), PIDTYPE_PID); - if (task) { + + if (task && (gr_pid_is_chrooted(task) || gr_check_hidden_task(task))) { + rcu_read_unlock(); + return -ENOENT; + } + + + if (task +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + && (!tmp->uid || (tmp->uid == task->uid) +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + || in_group_p(CONFIG_GRKERNSEC_PROC_GID) +#endif + ) +#endif + ) { if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || +#ifdef CONFIG_GRKERNSEC_PROC_USER + (inode->i_mode == (S_IFDIR|S_IRUSR|S_IXUSR)) || +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + (inode->i_mode == (S_IFDIR|S_IRUSR|S_IRGRP|S_IXUSR|S_IXGRP)) || +#endif task_dumpable(task)) { stat->uid = task->euid; +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + stat->gid = CONFIG_GRKERNSEC_PROC_GID; +#else stat->gid = task->egid; +#endif } } rcu_read_unlock(); @@ -1491,11 +1531,21 @@ static int pid_revalidate(struct dentry { struct inode *inode = dentry->d_inode; struct task_struct *task = get_proc_task(inode); + if (task) { if ((inode->i_mode == (S_IFDIR|S_IRUGO|S_IXUGO)) || +#ifdef CONFIG_GRKERNSEC_PROC_USER + (inode->i_mode == (S_IFDIR|S_IRUSR|S_IXUSR)) || +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + (inode->i_mode == (S_IFDIR|S_IRUSR|S_IRGRP|S_IXUSR|S_IXGRP)) || +#endif task_dumpable(task)) { inode->i_uid = task->euid; +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#else inode->i_gid = task->egid; +#endif } else { inode->i_uid = 0; inode->i_gid = 0; @@ -1863,12 +1913,22 @@ static const struct file_operations proc static int proc_fd_permission(struct inode *inode, int mask) { int rv; + struct task_struct *task; rv = generic_permission(inode, mask, NULL); - if (rv == 0) - return 0; + if (task_pid(current) == proc_pid(inode)) rv = 0; + + task = get_proc_task(inode); + if (task == NULL) + return rv; + + if (gr_acl_handle_procpidmem(task)) + rv = -EACCES; + + put_task_struct(task); + return rv; } @@ -1979,6 +2039,16 @@ static struct dentry *proc_pident_lookup if (!task) goto out_no_task; + /* TODO: maybe we can come up with a generic approach? */ + if (task_vx_flags(task, VXF_HIDE_VINFO, 0) && + (dentry->d_name.len == 5) && + (!memcmp(dentry->d_name.name, "vinfo", 5) || + !memcmp(dentry->d_name.name, "ninfo", 5))) + goto out; + + if (gr_pid_is_chrooted(task) || gr_check_hidden_task(task)) + goto out; + /* * Yes, it does not scale. And it should not. Don't add * new entries into /proc// without very good reasons. @@ -2023,6 +2093,9 @@ static int proc_pident_readdir(struct fi if (!task) goto out_no_task; + if (gr_pid_is_chrooted(task) || gr_check_hidden_task(task)) + goto out; + ret = 0; i = filp->f_pos; switch (i) { @@ -2366,7 +2439,7 @@ out_iput: static struct dentry *proc_base_lookup(struct inode *dir, struct dentry *dentry) { struct dentry *error; - struct task_struct *task = get_proc_task(dir); + struct task_struct *task = get_proc_task_real(dir); const struct pid_entry *p, *last; error = ERR_PTR(-ENOENT); @@ -2385,6 +2458,9 @@ static struct dentry *proc_base_lookup(s if (p > last) goto out; + if (gr_pid_is_chrooted(task) || gr_check_hidden_task(task)) + goto out; + error = proc_base_instantiate(dir, dentry, task, p); out: @@ -2449,6 +2525,9 @@ static int proc_tgid_io_accounting(struc static const struct file_operations proc_task_operations; static const struct inode_operations proc_task_inode_operations; +extern int proc_pid_vx_info(struct task_struct *, char *); +extern int proc_pid_nx_info(struct task_struct *, char *); + static const struct pid_entry tgid_base_stuff[] = { DIR("task", S_IRUGO|S_IXUGO, task), DIR("fd", S_IRUSR|S_IXUSR, fd), @@ -2503,6 +2582,8 @@ static const struct pid_entry tgid_base_ #ifdef CONFIG_CGROUPS REG("cgroup", S_IRUGO, cgroup), #endif + INF("vinfo", S_IRUGO, pid_vx_info), + INF("ninfo", S_IRUGO, pid_nx_info), INF("oom_score", S_IRUGO, oom_score), REG("oom_adj", S_IRUGO|S_IWUSR, oom_adjust), #ifdef CONFIG_AUDITSYSCALL @@ -2518,6 +2599,7 @@ static const struct pid_entry tgid_base_ #ifdef CONFIG_TASK_IO_ACCOUNTING INF("io", S_IRUGO, tgid_io_accounting), #endif + ONE("nsproxy", S_IRUGO, pid_nsproxy), }; static int proc_tgid_base_readdir(struct file * filp, @@ -2646,8 +2728,14 @@ static struct dentry *proc_pid_instantia inode = proc_pid_make_inode(dir->i_sb, task); if (!inode) goto out; - +#ifdef CONFIG_GRKERNSEC_PROC_USER + inode->i_mode = S_IFDIR|S_IRUSR|S_IXUSR; +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; + inode->i_mode = S_IFDIR|S_IRUSR|S_IRGRP|S_IXUSR|S_IXGRP; +#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; @@ -2689,7 +2777,11 @@ struct dentry *proc_pid_lookup(struct in if (!task) goto out; + if (gr_check_hidden_task(task)) + goto out_put_task; + result = proc_pid_instantiate(dir, dentry, task, NULL); +out_put_task: put_task_struct(task); out: return result; @@ -2714,7 +2806,7 @@ retry: iter.task = NULL; pid = find_ge_pid(iter.tgid, ns); if (pid) { - iter.tgid = pid_nr_ns(pid, ns); + iter.tgid = pid_unmapped_nr_ns(pid, ns); iter.task = pid_task(pid, PIDTYPE_PID); /* What we to know is if the pid we have find is the * pid of a thread_group_leader. Testing for task @@ -2744,7 +2836,7 @@ static int proc_pid_fill_cache(struct fi struct tgid_iter iter) { char name[PROC_NUMBUF]; - int len = snprintf(name, sizeof(name), "%d", iter.tgid); + int len = snprintf(name, sizeof(name), "%d", vx_map_tgid(iter.tgid)); return proc_fill_cache(filp, dirent, filldir, name, len, proc_pid_instantiate, iter.task, NULL); } @@ -2753,7 +2845,10 @@ static int proc_pid_fill_cache(struct fi int proc_pid_readdir(struct file * filp, void * dirent, filldir_t filldir) { unsigned int nr = filp->f_pos - FIRST_PROCESS_ENTRY; - struct task_struct *reaper = get_proc_task(filp->f_path.dentry->d_inode); + struct task_struct *reaper = get_proc_task_real(filp->f_path.dentry->d_inode); +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + struct task_struct *tmp = current; +#endif struct tgid_iter iter; struct pid_namespace *ns; @@ -2772,7 +2867,20 @@ int proc_pid_readdir(struct file * filp, for (iter = next_tgid(ns, iter); iter.task; iter.tgid += 1, iter = next_tgid(ns, iter)) { + if (gr_pid_is_chrooted(iter.task) || gr_check_hidden_task(iter.task) +#if defined(CONFIG_GRKERNSEC_PROC_USER) || defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + || (tmp->uid && (iter.task->uid != tmp->uid) +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + && !in_group_p(CONFIG_GRKERNSEC_PROC_GID) +#endif + ) +#endif + ) + continue; + filp->f_pos = iter.tgid + TGID_OFFSET; + if (!vx_proc_task_visible(iter.task)) + continue; if (proc_pid_fill_cache(filp, dirent, filldir, iter) < 0) { put_task_struct(iter.task); goto out; @@ -2849,6 +2957,9 @@ static const struct pid_entry tid_base_s #ifdef CONFIG_TASK_IO_ACCOUNTING INF("io", S_IRUGO, tid_io_accounting), #endif +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR + INF("ipaddr", S_IRUSR, pid_ipaddr), +#endif }; static int proc_tid_base_readdir(struct file * filp, @@ -2915,6 +3026,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; ns = dentry->d_sb->s_fs_info; rcu_read_lock(); diff -NurpP --minimal linux-2.6.27.15/fs/proc/generic.c linux-2.6.27.15-g-v/fs/proc/generic.c --- linux-2.6.27.15/fs/proc/generic.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/generic.c 2009-02-10 20:32:14.000000000 +0100 @@ -21,6 +21,7 @@ #include #include #include +#include #include #include "internal.h" @@ -384,6 +385,8 @@ struct dentry *proc_lookup_de(struct pro for (de = de->subdir; de ; de = de->next) { if (de->namelen != dentry->d_name.len) continue; + if (!vx_hide_check(0, de->vx_flags)) + continue; if (!memcmp(dentry->d_name.name, de->name, de->namelen)) { unsigned int ino; @@ -392,6 +395,8 @@ struct dentry *proc_lookup_de(struct pro spin_unlock(&proc_subdir_lock); error = -EINVAL; inode = proc_get_inode(dir->i_sb, ino, de); + /* generic proc entries belong to the host */ + inode->i_tag = 0; goto out_unlock; } } @@ -472,6 +477,8 @@ int proc_readdir_de(struct proc_dir_entr /* filldir passes info to user space */ de_get(de); + if (!vx_hide_check(0, de->vx_flags)) + goto skip; spin_unlock(&proc_subdir_lock); if (filldir(dirent, de->name, de->namelen, filp->f_pos, de->low_ino, de->mode >> 12) < 0) { @@ -479,6 +486,7 @@ int proc_readdir_de(struct proc_dir_entr goto out; } spin_lock(&proc_subdir_lock); + skip: filp->f_pos++; next = de->next; de_put(de); @@ -593,6 +601,7 @@ static struct proc_dir_entry *__proc_cre ent->nlink = nlink; atomic_set(&ent->count, 1); ent->pde_users = 0; + ent->vx_flags = IATTR_PROC_DEFAULT; spin_lock_init(&ent->pde_unload_lock); ent->pde_unload_completion = NULL; INIT_LIST_HEAD(&ent->pde_openers); @@ -616,7 +625,8 @@ struct proc_dir_entry *proc_symlink(cons kfree(ent->data); kfree(ent); ent = NULL; - } + } else + ent->vx_flags = IATTR_PROC_SYMLINK; } else { kfree(ent); ent = NULL; diff -NurpP --minimal linux-2.6.27.15/fs/proc/inode.c linux-2.6.27.15-g-v/fs/proc/inode.c --- linux-2.6.27.15/fs/proc/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -467,8 +467,14 @@ struct inode *proc_get_inode(struct supe if (de->mode) { inode->i_mode = de->mode; inode->i_uid = de->uid; +#ifdef CONFIG_GRKERNSEC_PROC_USERGROUP + inode->i_gid = CONFIG_GRKERNSEC_PROC_GID; +#else inode->i_gid = de->gid; +#endif } + if (de->vx_flags) + PROC_I(inode)->vx_flags = de->vx_flags; if (de->size) inode->i_size = de->size; if (de->nlink) diff -NurpP --minimal linux-2.6.27.15/fs/proc/internal.h linux-2.6.27.15-g-v/fs/proc/internal.h --- linux-2.6.27.15/fs/proc/internal.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/internal.h 2009-02-10 20:32:14.000000000 +0100 @@ -10,6 +10,7 @@ */ #include +#include extern struct proc_dir_entry proc_root; #ifdef CONFIG_PROC_SYSCTL @@ -55,6 +56,12 @@ extern int proc_pid_status(struct seq_fi struct pid *pid, struct task_struct *task); extern int proc_pid_statm(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task); +extern int proc_pid_nsproxy(struct seq_file *m, struct pid_namespace *ns, + struct pid *pid, struct task_struct *task); +#ifdef CONFIG_GRKERNSEC_PROC_IPADDR +extern int proc_pid_ipaddr(struct task_struct *task, char *buffer); +#endif + extern loff_t mem_lseek(struct file *file, loff_t offset, int orig); extern const struct file_operations proc_maps_operations; @@ -75,11 +82,16 @@ static inline struct pid *proc_pid(struc return PROC_I(inode)->pid; } -static inline struct task_struct *get_proc_task(struct inode *inode) +static inline struct task_struct *get_proc_task_real(struct inode *inode) { return get_pid_task(proc_pid(inode), PIDTYPE_PID); } +static inline struct task_struct *get_proc_task(struct inode *inode) +{ + return vx_get_proc_task(inode, proc_pid(inode)); +} + static inline int proc_fd(struct inode *inode) { return PROC_I(inode)->fd; diff -NurpP --minimal linux-2.6.27.15/fs/proc/Kconfig linux-2.6.27.15-g-v/fs/proc/Kconfig --- linux-2.6.27.15/fs/proc/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/Kconfig 2009-02-10 20:32:14.000000000 +0100 @@ -30,12 +30,12 @@ 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)" - depends on PROC_FS && CRASH_DUMP - default y + depends on PROC_FS && CRASH_DUMP && !GRKERNSEC + default n help Exports the dump image of crashed kernel in ELF format. diff -NurpP --minimal linux-2.6.27.15/fs/proc/proc_misc.c linux-2.6.27.15-g-v/fs/proc/proc_misc.c --- linux-2.6.27.15/fs/proc/proc_misc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/proc_misc.c 2009-02-10 20:32:14.000000000 +0100 @@ -57,6 +57,8 @@ #include #include "internal.h" +#include + #define LOAD_INT(x) ((x) >> FSHIFT) #define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1-1)) * 100) /* @@ -84,22 +86,38 @@ static int proc_calc_metrics(char *page, static int loadavg_read_proc(char *page, char **start, off_t off, int count, int *eof, void *data) { + unsigned long running; + unsigned int threads; int a, b, c; int len; unsigned long seq; do { seq = read_seqbegin(&xtime_lock); - a = avenrun[0] + (FIXED_1/200); - b = avenrun[1] + (FIXED_1/200); - c = avenrun[2] + (FIXED_1/200); + if (vx_flags(VXF_VIRT_LOAD, 0)) { + struct vx_info *vxi = current->vx_info; + + a = vxi->cvirt.load[0] + (FIXED_1/200); + b = vxi->cvirt.load[1] + (FIXED_1/200); + c = vxi->cvirt.load[2] + (FIXED_1/200); + + running = atomic_read(&vxi->cvirt.nr_running); + threads = atomic_read(&vxi->cvirt.nr_threads); + } else { + a = avenrun[0] + (FIXED_1/200); + b = avenrun[1] + (FIXED_1/200); + c = avenrun[2] + (FIXED_1/200); + + running = nr_running(); + threads = nr_threads; + } } while (read_seqretry(&xtime_lock, seq)); len = sprintf(page,"%d.%02d %d.%02d %d.%02d %ld/%d %d\n", LOAD_INT(a), LOAD_FRAC(a), LOAD_INT(b), LOAD_FRAC(b), LOAD_INT(c), LOAD_FRAC(c), - nr_running(), nr_threads, + running, threads, task_active_pid_ns(current)->last_pid); return proc_calc_metrics(page, start, off, count, eof, len); } @@ -115,6 +133,9 @@ static int uptime_read_proc(char *page, do_posix_clock_monotonic_gettime(&uptime); monotonic_to_bootbased(&uptime); cputime_to_timespec(idletime, &idle); + if (vx_flags(VXF_VIRT_UPTIME, 0)) + vx_vsi_uptime(&uptime, &idle); + len = sprintf(page,"%lu.%02lu %lu.%02lu\n", (unsigned long) uptime.tv_sec, (uptime.tv_nsec / (NSEC_PER_SEC / 100)), @@ -151,7 +172,7 @@ static int meminfo_read_proc(char *page, cached = global_page_state(NR_FILE_PAGES) - total_swapcache_pages - i.bufferram; - if (cached < 0) + if (cached < 0 || vx_flags(VXF_VIRT_MEM, 0)) cached = 0; get_vmalloc_info(&vmi); @@ -860,6 +881,8 @@ struct proc_dir_entry *proc_root_kcore; void __init proc_misc_init(void) { + int gr_mode = 0; + static struct { char *name; int (*read_proc)(char*,char**,off_t,int,int*,void*); @@ -875,13 +898,24 @@ void __init proc_misc_init(void) {"stram", stram_read_proc}, #endif {"filesystems", filesystems_read_proc}, +#ifndef CONFIG_GRKERNSEC_PROC_ADD {"cmdline", cmdline_read_proc}, +#endif {"execdomains", execdomains_read_proc}, {NULL,} }; for (p = simple_ones; p->name; p++) create_proc_read_entry(p->name, 0, NULL, p->read_proc, NULL); +#ifdef CONFIG_GRKERNSEC_PROC_USER + gr_mode = S_IRUSR; +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + gr_mode = S_IRUSR | S_IRGRP; +#endif +#ifdef CONFIG_GRKERNSEC_PROC_ADD + create_proc_read_entry("cmdline", gr_mode, NULL, &cmdline_read_proc, NULL); +#endif + proc_symlink("mounts", NULL, "self/mounts"); /* And now for trickier ones */ @@ -889,14 +923,18 @@ void __init proc_misc_init(void) proc_create("kmsg", S_IRUSR, NULL, &proc_kmsg_operations); #endif proc_create("locks", 0, NULL, &proc_locks_operations); +#ifdef CONFIG_GRKERNSEC_PROC_ADD + proc_create("devices", gr_mode, NULL, &proc_devinfo_operations); +#else proc_create("devices", 0, NULL, &proc_devinfo_operations); +#endif proc_create("cpuinfo", 0, NULL, &proc_cpuinfo_operations); #ifdef CONFIG_BLOCK proc_create("partitions", 0, NULL, &proc_partitions_operations); #endif proc_create("stat", 0, NULL, &proc_stat_operations); proc_create("interrupts", 0, NULL, &proc_interrupts_operations); -#ifdef CONFIG_SLABINFO +#if defined(CONFIG_SLABINFO) && !defined(CONFIG_GRKERNSEC_PROC_ADD) proc_create("slabinfo",S_IWUSR|S_IRUGO,NULL,&proc_slabinfo_operations); #ifdef CONFIG_DEBUG_SLAB_LEAK proc_create("slab_allocators", 0, NULL, &proc_slabstats_operations); @@ -918,7 +956,7 @@ void __init proc_misc_init(void) #ifdef CONFIG_SCHEDSTATS proc_create("schedstat", 0, NULL, &proc_schedstat_operations); #endif -#ifdef CONFIG_PROC_KCORE +#if defined(CONFIG_PROC_KCORE) && !defined(CONFIG_GRKERNSEC_PROC_ADD) proc_root_kcore = proc_create("kcore", S_IRUSR, NULL, &proc_kcore_operations); if (proc_root_kcore) proc_root_kcore->size = diff -NurpP --minimal linux-2.6.27.15/fs/proc/proc_net.c linux-2.6.27.15-g-v/fs/proc/proc_net.c --- linux-2.6.27.15/fs/proc/proc_net.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/proc_net.c 2009-02-10 20:32:14.000000000 +0100 @@ -106,6 +106,14 @@ static struct net *get_proc_task_net(str struct nsproxy *ns; struct net *net = NULL; +#ifdef CONFIG_GRKERNSEC_PROC_USER + if (current->fsuid) + return net; +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + if (current->fsuid && !in_group_p(CONFIG_GRKERNSEC_PROC_GID)) + return net; +#endif + rcu_read_lock(); task = pid_task(proc_pid(dir), PIDTYPE_PID); if (task != NULL) { diff -NurpP --minimal linux-2.6.27.15/fs/proc/proc_sysctl.c linux-2.6.27.15-g-v/fs/proc/proc_sysctl.c --- linux-2.6.27.15/fs/proc/proc_sysctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/proc_sysctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -7,6 +7,8 @@ #include #include "internal.h" +extern __u32 gr_handle_sysctl(const struct ctl_table *table, const int op); + static struct dentry_operations proc_sys_dentry_operations; static const struct file_operations proc_sys_file_operations; static const struct inode_operations proc_sys_inode_operations; @@ -110,6 +112,9 @@ static struct dentry *proc_sys_lookup(st if (!p) goto out; + if (gr_handle_sysctl(p, MAY_EXEC)) + goto out; + err = ERR_PTR(-ENOMEM); inode = proc_sys_make_inode(dir->i_sb, h ? h : head, p); if (h) @@ -229,6 +234,9 @@ static int scan(struct ctl_table_header if (*pos < file->f_pos) continue; + if (gr_handle_sysctl(table, 0)) + continue; + res = proc_sys_fill_cache(file, dirent, filldir, head, table); if (res) return res; @@ -339,6 +347,9 @@ static int proc_sys_getattr(struct vfsmo if (IS_ERR(head)) return PTR_ERR(head); + if (table && gr_handle_sysctl(table, MAY_EXEC)) + return -ENOENT; + generic_fillattr(inode, stat); if (table) stat->mode = (stat->mode & S_IFMT) | table->mode; diff -NurpP --minimal linux-2.6.27.15/fs/proc/root.c linux-2.6.27.15-g-v/fs/proc/root.c --- linux-2.6.27.15/fs/proc/root.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/root.c 2009-02-10 20:32:14.000000000 +0100 @@ -19,9 +19,14 @@ #include #include #include +#include #include "internal.h" +struct proc_dir_entry *proc_virtual; + +extern void proc_vx_init(void); + static int proc_test_super(struct super_block *sb, void *data) { return sb->s_fs_info == data; @@ -135,8 +140,17 @@ void __init proc_root_init(void) #ifdef CONFIG_PROC_DEVICETREE proc_device_tree_init(); #endif +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + proc_mkdir_mode("bus", S_IRUSR | S_IXUSR, NULL); +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + proc_mkdir_mode("bus", S_IRUSR | S_IXUSR | S_IRGRP | S_IXGRP, NULL); +#endif +#else proc_mkdir("bus", NULL); +#endif proc_sys_init(); + proc_vx_init(); } static int proc_root_getattr(struct vfsmount *mnt, struct dentry *dentry, struct kstat *stat @@ -209,6 +223,7 @@ struct proc_dir_entry proc_root = { .proc_iops = &proc_root_inode_operations, .proc_fops = &proc_root_operations, .parent = &proc_root, + .vx_flags = IATTR_ADMIN | IATTR_WATCH, }; int pid_ns_prepare_proc(struct pid_namespace *ns) diff -NurpP --minimal linux-2.6.27.15/fs/proc/task_mmu.c linux-2.6.27.15-g-v/fs/proc/task_mmu.c --- linux-2.6.27.15/fs/proc/task_mmu.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/proc/task_mmu.c 2009-02-10 20:32:14.000000000 +0100 @@ -46,15 +46,26 @@ void task_mem(struct seq_file *m, struct "VmStk:\t%8lu kB\n" "VmExe:\t%8lu kB\n" "VmLib:\t%8lu kB\n" - "VmPTE:\t%8lu kB\n", - hiwater_vm << (PAGE_SHIFT-10), + "VmPTE:\t%8lu kB\n" + +#ifdef CONFIG_ARCH_TRACK_EXEC_LIMIT + "CsBase:\t%8lx\nCsLim:\t%8lx\n" +#endif + + ,hiwater_vm << (PAGE_SHIFT-10), (total_vm - mm->reserved_vm) << (PAGE_SHIFT-10), mm->locked_vm << (PAGE_SHIFT-10), hiwater_rss << (PAGE_SHIFT-10), total_rss << (PAGE_SHIFT-10), data << (PAGE_SHIFT-10), mm->stack_vm << (PAGE_SHIFT-10), text, lib, - (PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10); + (PTRS_PER_PTE*sizeof(pte_t)*mm->nr_ptes) >> 10 + +#ifdef CONFIG_ARCH_TRACK_EXEC_LIMIT + , mm->context.user_cs_base, mm->context.user_cs_limit +#endif + + ); } unsigned long task_vsize(struct mm_struct *mm) @@ -198,6 +209,12 @@ static int do_maps_open(struct inode *in return ret; } +#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 void show_map_vma(struct seq_file *m, struct vm_area_struct *vma) { struct mm_struct *mm = vma->vm_mm; @@ -214,13 +231,22 @@ static void show_map_vma(struct seq_file } seq_printf(m, "%08lx-%08lx %c%c%c%c %08llx %02x:%02x %lu %n", +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + PAX_RAND_FLAGS(mm) ? 0UL : vma->vm_start, + PAX_RAND_FLAGS(mm) ? 0UL : vma->vm_end, +#else vma->vm_start, vma->vm_end, +#endif flags & VM_READ ? 'r' : '-', flags & VM_WRITE ? 'w' : '-', flags & VM_EXEC ? 'x' : '-', flags & VM_MAYSHARE ? 's' : 'p', +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + PAX_RAND_FLAGS(mm) ? 0UL : ((loff_t)vma->vm_pgoff) << PAGE_SHIFT, +#else ((loff_t)vma->vm_pgoff) << PAGE_SHIFT, +#endif MAJOR(dev), MINOR(dev), ino, &len); /* @@ -234,11 +260,11 @@ static void show_map_vma(struct seq_file const char *name = arch_vma_name(vma); if (!name) { if (mm) { - if (vma->vm_start <= mm->start_brk && - vma->vm_end >= mm->brk) { + if (vma->vm_start <= mm->brk && vma->vm_end >= mm->start_brk) { name = "[heap]"; - } else if (vma->vm_start <= mm->start_stack && - vma->vm_end >= mm->start_stack) { + } else if ((vma->vm_flags & (VM_GROWSDOWN | VM_GROWSUP)) || + (vma->vm_start <= mm->start_stack && + vma->vm_end >= mm->start_stack)) { name = "[stack]"; } } else { @@ -387,9 +413,16 @@ static int show_smap(struct seq_file *m, return -EACCES; memset(&mss, 0, sizeof mss); - mss.vma = vma; - if (vma->vm_mm && !is_vm_hugetlb_page(vma)) - walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); + +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + if (!PAX_RAND_FLAGS(vma->vm_mm)) { +#endif + mss.vma = vma; + if (vma->vm_mm && !is_vm_hugetlb_page(vma)) + walk_page_range(vma->vm_start, vma->vm_end, &smaps_walk); +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + } +#endif show_map_vma(m, vma); @@ -403,7 +436,11 @@ static int show_smap(struct seq_file *m, "Private_Dirty: %8lu kB\n" "Referenced: %8lu kB\n" "Swap: %8lu kB\n", +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + PAX_RAND_FLAGS(vma->vm_mm) ? 0UL : (vma->vm_end - vma->vm_start) >> 10, +#else (vma->vm_end - vma->vm_start) >> 10, +#endif mss.resident >> 10, (unsigned long)(mss.pss >> (10 + PSS_SHIFT)), mss.shared_clean >> 10, @@ -757,6 +794,11 @@ static int show_numa_map_checked(struct struct proc_maps_private *priv = m->private; struct task_struct *task = priv->task; +#ifdef CONFIG_GRKERNSEC_PROC_MEMMAP + if (!ptrace_may_access(task, PTRACE_MODE_READ)) + return -EACCES; +#endif + if (maps_protect && !ptrace_may_access(task, PTRACE_MODE_READ)) return -EACCES; diff -NurpP --minimal linux-2.6.27.15/fs/quota.c linux-2.6.27.15-g-v/fs/quota.c --- linux-2.6.27.15/fs/quota.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/quota.c 2009-02-10 20:32:14.000000000 +0100 @@ -18,6 +18,7 @@ #include #include #include +#include /* Check validity of generic quotactl commands */ static int generic_quotactl_valid(struct super_block *sb, int type, int cmd, qid_t id) @@ -81,11 +82,11 @@ static int generic_quotactl_valid(struct if (cmd == Q_GETQUOTA) { if (((type == USRQUOTA && current->euid != id) || (type == GRPQUOTA && !in_egroup_p(id))) && - !capable(CAP_SYS_ADMIN)) + !vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) return -EPERM; } else if (cmd != Q_GETFMT && cmd != Q_SYNC && cmd != Q_GETINFO) - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) return -EPERM; return 0; @@ -132,10 +133,10 @@ static int xqm_quotactl_valid(struct sup if (cmd == Q_XGETQUOTA) { if (((type == XQM_USRQUOTA && current->euid != id) || (type == XQM_GRPQUOTA && !in_egroup_p(id))) && - !capable(CAP_SYS_ADMIN)) + !vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) return -EPERM; } else if (cmd != Q_XGETQSTAT && cmd != Q_XQUOTASYNC) { - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) return -EPERM; } @@ -334,6 +335,46 @@ static int do_quotactl(struct super_bloc return 0; } +#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE) + +#include +#include +#include +#include +#include + +static vroot_grb_func *vroot_get_real_bdev = NULL; + +static spinlock_t vroot_grb_lock = SPIN_LOCK_UNLOCKED; + +int register_vroot_grb(vroot_grb_func *func) { + int ret = -EBUSY; + + spin_lock(&vroot_grb_lock); + if (!vroot_get_real_bdev) { + vroot_get_real_bdev = func; + ret = 0; + } + spin_unlock(&vroot_grb_lock); + return ret; +} +EXPORT_SYMBOL(register_vroot_grb); + +int unregister_vroot_grb(vroot_grb_func *func) { + int ret = -EINVAL; + + spin_lock(&vroot_grb_lock); + if (vroot_get_real_bdev) { + vroot_get_real_bdev = NULL; + ret = 0; + } + spin_unlock(&vroot_grb_lock); + return ret; +} +EXPORT_SYMBOL(unregister_vroot_grb); + +#endif + /* * look up a superblock on which quota ops will be performed * - use the name of a block device to find the superblock thereon @@ -351,6 +392,22 @@ static inline struct super_block *quotac putname(tmp); if (IS_ERR(bdev)) return ERR_CAST(bdev); +#if defined(CONFIG_BLK_DEV_VROOT) || defined(CONFIG_BLK_DEV_VROOT_MODULE) + if (bdev && bdev->bd_inode && + imajor(bdev->bd_inode) == VROOT_MAJOR) { + struct block_device *bdnew = (void *)-EINVAL; + + if (vroot_get_real_bdev) + bdnew = vroot_get_real_bdev(bdev); + else + vxdprintk(VXD_CBIT(misc, 0), + "vroot_get_real_bdev not set"); + bdput(bdev); + if (IS_ERR(bdnew)) + return ERR_PTR(PTR_ERR(bdnew)); + bdev = bdnew; + } +#endif sb = get_super(bdev); bdput(bdev); if (!sb) diff -NurpP --minimal linux-2.6.27.15/fs/readdir.c linux-2.6.27.15-g-v/fs/readdir.c --- linux-2.6.27.15/fs/readdir.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/readdir.c 2009-02-10 20:32:14.000000000 +0100 @@ -16,6 +16,8 @@ #include #include #include +#include +#include #include @@ -67,6 +69,7 @@ struct old_linux_dirent { struct readdir_callback { struct old_linux_dirent __user * dirent; + struct file * file; int result; }; @@ -84,6 +87,10 @@ static int fillonedir(void * __buf, cons buf->result = -EOVERFLOW; return -EOVERFLOW; } + + if (!gr_acl_handle_filldir(buf->file, name, namlen, ino)) + return 0; + buf->result++; dirent = buf->dirent; if (!access_ok(VERIFY_WRITE, dirent, @@ -116,6 +123,7 @@ SYSCALL_DEFINE3(old_readdir, unsigned in buf.result = 0; buf.dirent = dirent; + buf.file = file; error = vfs_readdir(file, fillonedir, &buf); if (error >= 0) @@ -142,6 +150,7 @@ struct linux_dirent { struct getdents_callback { struct linux_dirent __user * current_dir; struct linux_dirent __user * previous; + struct file * file; int count; int error; }; @@ -162,6 +171,10 @@ static int filldir(void * __buf, const c buf->error = -EOVERFLOW; return -EOVERFLOW; } + + if (!gr_acl_handle_filldir(buf->file, name, namlen, ino)) + return 0; + dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) @@ -209,6 +222,7 @@ SYSCALL_DEFINE3(getdents, unsigned int, buf.previous = NULL; buf.count = count; buf.error = 0; + buf.file = file; error = vfs_readdir(file, filldir, &buf); if (error < 0) @@ -231,6 +245,7 @@ out: struct getdents_callback64 { struct linux_dirent64 __user * current_dir; struct linux_dirent64 __user * previous; + struct file *file; int count; int error; }; @@ -245,6 +260,10 @@ static int filldir64(void * __buf, const buf->error = -EINVAL; /* only used if we fail.. */ if (reclen > buf->count) return -EINVAL; + + if (!gr_acl_handle_filldir(buf->file, name, namlen, ino)) + return 0; + dirent = buf->previous; if (dirent) { if (__put_user(offset, &dirent->d_off)) @@ -292,6 +311,7 @@ SYSCALL_DEFINE3(getdents64, unsigned int buf.current_dir = dirent; buf.previous = NULL; + buf.file = file; buf.count = count; buf.error = 0; diff -NurpP --minimal linux-2.6.27.15/fs/reiserfs/bitmap.c linux-2.6.27.15-g-v/fs/reiserfs/bitmap.c --- linux-2.6.27.15/fs/reiserfs/bitmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/reiserfs/bitmap.c 2009-02-10 20:32:14.000000000 +0100 @@ -13,6 +13,7 @@ #include #include #include +#include #define PREALLOCATION_SIZE 9 @@ -429,8 +430,10 @@ static void _reiserfs_free_block(struct set_sb_free_blocks(rs, sb_free_blocks(rs) + 1); journal_mark_dirty(th, s, sbh); - if (for_unformatted) + if (for_unformatted) { + DLIMIT_FREE_BLOCK(inode, 1); DQUOT_FREE_BLOCK_NODIRTY(inode, 1); + } } void reiserfs_free_block(struct reiserfs_transaction_handle *th, @@ -1045,6 +1048,7 @@ static inline int blocknrs_and_prealloc_ b_blocknr_t finish = SB_BLOCK_COUNT(s) - 1; int passno = 0; int nr_allocated = 0; + int blocks; determine_prealloc_size(hint); if (!hint->formatted_node) { @@ -1054,19 +1058,30 @@ static inline int blocknrs_and_prealloc_ "reiserquota: allocating %d blocks id=%u", amount_needed, hint->inode->i_uid); #endif - quota_ret = - DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, amount_needed); - if (quota_ret) /* Quota exceeded? */ + quota_ret = DQUOT_ALLOC_BLOCK_NODIRTY(hint->inode, + amount_needed); + if (quota_ret) return QUOTA_EXCEEDED; + if (DLIMIT_ALLOC_BLOCK(hint->inode, amount_needed)) { + DQUOT_FREE_BLOCK_NODIRTY(hint->inode, + amount_needed); + return NO_DISK_SPACE; + } + if (hint->preallocate && hint->prealloc_size) { #ifdef REISERQUOTA_DEBUG reiserfs_debug(s, REISERFS_DEBUG_CODE, "reiserquota: allocating (prealloc) %d blocks id=%u", hint->prealloc_size, hint->inode->i_uid); #endif - quota_ret = - DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode, - hint->prealloc_size); + quota_ret = DQUOT_PREALLOC_BLOCK_NODIRTY(hint->inode, + hint->prealloc_size); + if (!quota_ret && + DLIMIT_ALLOC_BLOCK(hint->inode, hint->prealloc_size)) { + DQUOT_FREE_BLOCK_NODIRTY(hint->inode, + hint->prealloc_size); + quota_ret = 1; + } if (quota_ret) hint->preallocate = hint->prealloc_size = 0; } @@ -1098,7 +1113,10 @@ static inline int blocknrs_and_prealloc_ nr_allocated, hint->inode->i_uid); #endif - DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + hint->prealloc_size - nr_allocated); /* Free not allocated blocks */ + /* Free not allocated blocks */ + blocks = amount_needed + hint->prealloc_size - nr_allocated; + DLIMIT_FREE_BLOCK(hint->inode, blocks); + DQUOT_FREE_BLOCK_NODIRTY(hint->inode, blocks); } while (nr_allocated--) reiserfs_free_block(hint->th, hint->inode, @@ -1129,10 +1147,10 @@ static inline int blocknrs_and_prealloc_ REISERFS_I(hint->inode)->i_prealloc_count, hint->inode->i_uid); #endif - DQUOT_FREE_BLOCK_NODIRTY(hint->inode, amount_needed + - hint->prealloc_size - nr_allocated - - REISERFS_I(hint->inode)-> - i_prealloc_count); + blocks = amount_needed + hint->prealloc_size - nr_allocated - + REISERFS_I(hint->inode)->i_prealloc_count; + DLIMIT_FREE_BLOCK(hint->inode, blocks); + DQUOT_FREE_BLOCK_NODIRTY(hint->inode, blocks); } return CARRY_ON; diff -NurpP --minimal linux-2.6.27.15/fs/reiserfs/file.c linux-2.6.27.15-g-v/fs/reiserfs/file.c --- linux-2.6.27.15/fs/reiserfs/file.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/reiserfs/file.c 2009-02-10 20:32:14.000000000 +0100 @@ -306,4 +306,5 @@ const struct inode_operations reiserfs_f .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, + .sync_flags = reiserfs_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/reiserfs/inode.c linux-2.6.27.15-g-v/fs/reiserfs/inode.c --- linux-2.6.27.15/fs/reiserfs/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/reiserfs/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -18,6 +18,8 @@ #include #include #include +#include +#include int reiserfs_commit_write(struct file *f, struct page *page, unsigned from, unsigned to); @@ -54,6 +56,7 @@ void reiserfs_delete_inode(struct inode * stat data deletion */ if (!err) DQUOT_FREE_INODE(inode); + DLIMIT_FREE_INODE(inode); if (journal_end(&th, inode->i_sb, jbegin_count)) goto out; @@ -1116,6 +1119,8 @@ static void init_inode(struct inode *ino struct buffer_head *bh; struct item_head *ih; __u32 rdev; + uid_t uid; + gid_t gid; //int version = ITEM_VERSION_1; bh = PATH_PLAST_BUFFER(path); @@ -1139,12 +1144,13 @@ static void init_inode(struct inode *ino (struct stat_data_v1 *)B_I_PITEM(bh, ih); unsigned long blocks; + uid = sd_v1_uid(sd); + gid = sd_v1_gid(sd); + set_inode_item_key_version(inode, KEY_FORMAT_3_5); set_inode_sd_version(inode, STAT_DATA_V1); inode->i_mode = sd_v1_mode(sd); inode->i_nlink = sd_v1_nlink(sd); - inode->i_uid = sd_v1_uid(sd); - inode->i_gid = sd_v1_gid(sd); inode->i_size = sd_v1_size(sd); inode->i_atime.tv_sec = sd_v1_atime(sd); inode->i_mtime.tv_sec = sd_v1_mtime(sd); @@ -1186,11 +1192,12 @@ static void init_inode(struct inode *ino // (directories and symlinks) struct stat_data *sd = (struct stat_data *)B_I_PITEM(bh, ih); + uid = sd_v2_uid(sd); + gid = sd_v2_gid(sd); + inode->i_mode = sd_v2_mode(sd); inode->i_nlink = sd_v2_nlink(sd); - inode->i_uid = sd_v2_uid(sd); inode->i_size = sd_v2_size(sd); - inode->i_gid = sd_v2_gid(sd); inode->i_mtime.tv_sec = sd_v2_mtime(sd); inode->i_atime.tv_sec = sd_v2_atime(sd); inode->i_ctime.tv_sec = sd_v2_ctime(sd); @@ -1220,6 +1227,10 @@ static void init_inode(struct inode *ino sd_attrs_to_i_attrs(sd_v2_attrs(sd), inode); } + inode->i_uid = INOTAG_UID(DX_TAG(inode), uid, gid); + inode->i_gid = INOTAG_GID(DX_TAG(inode), uid, gid); + inode->i_tag = INOTAG_TAG(DX_TAG(inode), uid, gid, 0); + pathrelse(path); if (S_ISREG(inode->i_mode)) { inode->i_op = &reiserfs_file_inode_operations; @@ -1242,13 +1253,15 @@ static void init_inode(struct inode *ino static void inode2sd(void *sd, struct inode *inode, loff_t size) { struct stat_data *sd_v2 = (struct stat_data *)sd; + uid_t uid = TAGINO_UID(DX_TAG(inode), inode->i_uid, inode->i_tag); + gid_t gid = TAGINO_GID(DX_TAG(inode), inode->i_gid, inode->i_tag); __u16 flags; + set_sd_v2_uid(sd_v2, uid); + set_sd_v2_gid(sd_v2, gid); set_sd_v2_mode(sd_v2, inode->i_mode); set_sd_v2_nlink(sd_v2, inode->i_nlink); - set_sd_v2_uid(sd_v2, inode->i_uid); set_sd_v2_size(sd_v2, size); - set_sd_v2_gid(sd_v2, inode->i_gid); set_sd_v2_mtime(sd_v2, inode->i_mtime.tv_sec); set_sd_v2_atime(sd_v2, inode->i_atime.tv_sec); set_sd_v2_ctime(sd_v2, inode->i_ctime.tv_sec); @@ -1771,6 +1784,10 @@ int reiserfs_new_inode(struct reiserfs_t BUG_ON(!th->t_trans_id); + if (DLIMIT_ALLOC_INODE(inode)) { + err = -ENOSPC; + goto out_bad_dlimit; + } if (DQUOT_ALLOC_INODE(inode)) { err = -EDQUOT; goto out_end_trans; @@ -1956,6 +1973,9 @@ int reiserfs_new_inode(struct reiserfs_t DQUOT_FREE_INODE(inode); out_end_trans: + DLIMIT_FREE_INODE(inode); + + out_bad_dlimit: journal_end(th, th->t_super, th->t_blocks_allocated); /* Drop can be outside and it needs more credits so it's better to have it outside */ DQUOT_DROP(inode); @@ -2842,14 +2862,19 @@ int reiserfs_commit_write(struct file *f void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode) { if (reiserfs_attrs(inode->i_sb)) { - if (sd_attrs & REISERFS_SYNC_FL) - inode->i_flags |= S_SYNC; - else - inode->i_flags &= ~S_SYNC; if (sd_attrs & REISERFS_IMMUTABLE_FL) inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; + if (sd_attrs & REISERFS_IXUNLINK_FL) + inode->i_flags |= S_IXUNLINK; + else + inode->i_flags &= ~S_IXUNLINK; + + if (sd_attrs & REISERFS_SYNC_FL) + inode->i_flags |= S_SYNC; + else + inode->i_flags &= ~S_SYNC; if (sd_attrs & REISERFS_APPEND_FL) inode->i_flags |= S_APPEND; else @@ -2862,6 +2887,15 @@ void sd_attrs_to_i_attrs(__u16 sd_attrs, REISERFS_I(inode)->i_flags |= i_nopack_mask; else REISERFS_I(inode)->i_flags &= ~i_nopack_mask; + + if (sd_attrs & REISERFS_BARRIER_FL) + inode->i_vflags |= V_BARRIER; + else + inode->i_vflags &= ~V_BARRIER; + if (sd_attrs & REISERFS_COW_FL) + inode->i_vflags |= V_COW; + else + inode->i_vflags &= ~V_COW; } } @@ -2872,6 +2906,11 @@ void i_attrs_to_sd_attrs(struct inode *i *sd_attrs |= REISERFS_IMMUTABLE_FL; else *sd_attrs &= ~REISERFS_IMMUTABLE_FL; + if (inode->i_flags & S_IXUNLINK) + *sd_attrs |= REISERFS_IXUNLINK_FL; + else + *sd_attrs &= ~REISERFS_IXUNLINK_FL; + if (inode->i_flags & S_SYNC) *sd_attrs |= REISERFS_SYNC_FL; else @@ -2884,6 +2923,15 @@ void i_attrs_to_sd_attrs(struct inode *i *sd_attrs |= REISERFS_NOTAIL_FL; else *sd_attrs &= ~REISERFS_NOTAIL_FL; + + if (inode->i_vflags & V_BARRIER) + *sd_attrs |= REISERFS_BARRIER_FL; + else + *sd_attrs &= ~REISERFS_BARRIER_FL; + if (inode->i_vflags & V_COW) + *sd_attrs |= REISERFS_COW_FL; + else + *sd_attrs &= ~REISERFS_COW_FL; } } @@ -3051,6 +3099,22 @@ static ssize_t reiserfs_direct_IO(int rw reiserfs_get_blocks_direct_io, NULL); } +int reiserfs_sync_flags(struct inode *inode) +{ + u16 oldflags, newflags; + + oldflags = REISERFS_I(inode)->i_attrs; + newflags = oldflags; + i_attrs_to_sd_attrs(inode, &newflags); + + if (oldflags ^ newflags) { + REISERFS_I(inode)->i_attrs = newflags; + inode->i_ctime = CURRENT_TIME_SEC; + mark_inode_dirty(inode); + } + return 0; +} + int reiserfs_setattr(struct dentry *dentry, struct iattr *attr) { struct inode *inode = dentry->d_inode; @@ -3104,9 +3168,11 @@ int reiserfs_setattr(struct dentry *dent } error = inode_change_ok(inode, 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_TAG && attr->ia_tag != inode->i_tag)) { error = reiserfs_chown_xattrs(inode, attr); if (!error) { @@ -3136,6 +3202,9 @@ int reiserfs_setattr(struct dentry *dent inode->i_uid = attr->ia_uid; if (attr->ia_valid & ATTR_GID) inode->i_gid = attr->ia_gid; + if ((attr->ia_valid & ATTR_TAG) && + IS_TAGGED(inode)) + inode->i_tag = attr->ia_tag; mark_inode_dirty(inode); error = journal_end(&th, inode->i_sb, jbegin_count); diff -NurpP --minimal linux-2.6.27.15/fs/reiserfs/ioctl.c linux-2.6.27.15-g-v/fs/reiserfs/ioctl.c --- linux-2.6.27.15/fs/reiserfs/ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/reiserfs/ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -7,6 +7,7 @@ #include #include #include +#include #include #include #include @@ -23,7 +24,7 @@ int reiserfs_ioctl(struct inode *inode, struct file *filp, unsigned int cmd, unsigned long arg) { - unsigned int flags; + unsigned int flags, oldflags; int err = 0; switch (cmd) { @@ -43,6 +44,7 @@ int reiserfs_ioctl(struct inode *inode, flags = REISERFS_I(inode)->i_attrs; i_attrs_to_sd_attrs(inode, (__u16 *) & flags); + flags &= REISERFS_FL_USER_VISIBLE; return put_user(flags, (int __user *)arg); case REISERFS_IOC_SETFLAGS:{ if (!reiserfs_attrs(inode->i_sb)) @@ -60,6 +62,10 @@ int reiserfs_ioctl(struct inode *inode, err = -EFAULT; goto setflags_out; } + if (IS_BARRIER(inode)) { + vxwprintk_task(1, "messing with the barrier."); + return -EACCES; + } /* * Is it quota file? Do not allow user to mess with it */ @@ -84,6 +90,10 @@ int reiserfs_ioctl(struct inode *inode, goto setflags_out; } } + + oldflags = REISERFS_I(inode)->i_attrs; + flags = flags & REISERFS_FL_USER_MODIFIABLE; + flags |= oldflags & ~REISERFS_FL_USER_MODIFIABLE; sd_attrs_to_i_attrs(flags, inode); REISERFS_I(inode)->i_attrs = flags; inode->i_ctime = CURRENT_TIME_SEC; diff -NurpP --minimal linux-2.6.27.15/fs/reiserfs/namei.c linux-2.6.27.15-g-v/fs/reiserfs/namei.c --- linux-2.6.27.15/fs/reiserfs/namei.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/reiserfs/namei.c 2009-02-10 20:32:14.000000000 +0100 @@ -17,6 +17,7 @@ #include #include #include +#include #define INC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) { inc_nlink(i); if (i->i_nlink >= REISERFS_LINK_MAX) i->i_nlink=1; } #define DEC_DIR_INODE_NLINK(i) if (i->i_nlink != 1) drop_nlink(i); @@ -360,6 +361,7 @@ static struct dentry *reiserfs_lookup(st reiserfs_write_unlock(dir->i_sb); return ERR_PTR(-EACCES); } + dx_propagate_tag(nd, inode); /* Propogate the priv_object flag so we know we're in the priv tree */ if (is_reiserfs_priv_object(dir)) @@ -595,6 +597,7 @@ static int new_inode_init(struct inode * } else { inode->i_gid = current->fsgid; } + inode->i_tag = dx_current_fstag(inode->i_sb); DQUOT_INIT(inode); return 0; } @@ -1541,6 +1544,7 @@ const struct inode_operations reiserfs_d .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, + .sync_flags = reiserfs_sync_flags, }; /* @@ -1557,6 +1561,7 @@ const struct inode_operations reiserfs_s .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, + .sync_flags = reiserfs_sync_flags, }; @@ -1570,5 +1575,6 @@ const struct inode_operations reiserfs_s .listxattr = reiserfs_listxattr, .removexattr = reiserfs_removexattr, .permission = reiserfs_permission, + .sync_flags = reiserfs_sync_flags, }; diff -NurpP --minimal linux-2.6.27.15/fs/reiserfs/stree.c linux-2.6.27.15-g-v/fs/reiserfs/stree.c --- linux-2.6.27.15/fs/reiserfs/stree.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/reiserfs/stree.c 2009-02-10 20:32:14.000000000 +0100 @@ -55,6 +55,7 @@ #include #include #include +#include /* Does the buffer contain a disk block which is in the tree. */ inline int B_IS_IN_TREE(const struct buffer_head *p_s_bh) @@ -1297,6 +1298,7 @@ int reiserfs_delete_item(struct reiserfs "reiserquota delete_item(): freeing %u, id=%u type=%c", quota_cut_bytes, p_s_inode->i_uid, head2type(&s_ih)); #endif + DLIMIT_FREE_SPACE(p_s_inode, quota_cut_bytes); DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes); /* Return deleted body length */ @@ -1385,6 +1387,7 @@ void reiserfs_delete_solid_item(struct r #endif DQUOT_FREE_SPACE_NODIRTY(inode, quota_cut_bytes); + DLIMIT_FREE_SPACE(inode, quota_cut_bytes); } break; } @@ -1734,6 +1737,7 @@ int reiserfs_cut_from_item(struct reiser "reiserquota cut_from_item(): freeing %u id=%u type=%c", quota_cut_bytes, p_s_inode->i_uid, '?'); #endif + DLIMIT_FREE_SPACE(p_s_inode, quota_cut_bytes); DQUOT_FREE_SPACE_NODIRTY(p_s_inode, quota_cut_bytes); return n_ret_value; } @@ -1975,6 +1979,11 @@ int reiserfs_paste_into_item(struct reis pathrelse(p_s_search_path); return -EDQUOT; } + if (DLIMIT_ALLOC_SPACE(inode, n_pasted_size)) { + DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size); + pathrelse(p_s_search_path); + return -ENOSPC; + } init_tb_struct(th, &s_paste_balance, th->t_super, p_s_search_path, n_pasted_size); #ifdef DISPLACE_NEW_PACKING_LOCALITIES @@ -2027,6 +2036,7 @@ int reiserfs_paste_into_item(struct reis n_pasted_size, inode->i_uid, key2type(&(p_s_key->on_disk_key))); #endif + DLIMIT_FREE_SPACE(inode, n_pasted_size); DQUOT_FREE_SPACE_NODIRTY(inode, n_pasted_size); return retval; } @@ -2064,6 +2074,11 @@ int reiserfs_insert_item(struct reiserfs pathrelse(p_s_path); return -EDQUOT; } + if (DLIMIT_ALLOC_SPACE(inode, quota_bytes)) { + DQUOT_FREE_SPACE_NODIRTY(inode, quota_bytes); + pathrelse(p_s_path); + return -ENOSPC; + } } init_tb_struct(th, &s_ins_balance, th->t_super, p_s_path, IH_SIZE + ih_item_len(p_s_ih)); @@ -2111,7 +2126,9 @@ int reiserfs_insert_item(struct reiserfs "reiserquota insert_item(): freeing %u id=%u type=%c", quota_bytes, inode->i_uid, head2type(p_s_ih)); #endif - if (inode) + if (inode) { + DLIMIT_FREE_SPACE(inode, quota_bytes); DQUOT_FREE_SPACE_NODIRTY(inode, quota_bytes); + } return retval; } diff -NurpP --minimal linux-2.6.27.15/fs/reiserfs/super.c linux-2.6.27.15-g-v/fs/reiserfs/super.c --- linux-2.6.27.15/fs/reiserfs/super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/reiserfs/super.c 2009-02-10 20:32:14.000000000 +0100 @@ -898,6 +898,14 @@ static int reiserfs_parse_options(struct {"user_xattr",.setmask = 1 << REISERFS_UNSUPPORTED_OPT}, {"nouser_xattr",.clrmask = 1 << REISERFS_UNSUPPORTED_OPT}, #endif +#ifndef CONFIG_TAGGING_NONE + {"tagxid",.setmask = 1 << REISERFS_TAGGED}, + {"tag",.setmask = 1 << REISERFS_TAGGED}, + {"notag",.clrmask = 1 << REISERFS_TAGGED}, +#endif +#ifdef CONFIG_PROPAGATE + {"tag",.arg_required = 'T',.values = NULL}, +#endif #ifdef CONFIG_REISERFS_FS_POSIX_ACL {"acl",.setmask = 1 << REISERFS_POSIXACL}, {"noacl",.clrmask = 1 << REISERFS_POSIXACL}, @@ -1193,6 +1201,12 @@ static int reiserfs_remount(struct super handle_quota_files(s, qf_names, &qfmt); #endif + if ((mount_options & (1 << REISERFS_TAGGED)) && + !(s->s_flags & MS_TAGGED)) { + reiserfs_warning(s, "reiserfs: tagging not permitted on remount."); + return -EINVAL; + } + handle_attrs(s); /* Add options that are safe here */ @@ -1657,6 +1671,10 @@ static int reiserfs_fill_super(struct su goto error; } + /* map mount option tagxid */ + if (REISERFS_SB(s)->s_mount_opt & (1 << REISERFS_TAGGED)) + s->s_flags |= MS_TAGGED; + rs = SB_DISK_SUPER_BLOCK(s); /* Let's do basic sanity check to verify that underlying device is not smaller than the filesystem. If the check fails then abort and scream, diff -NurpP --minimal linux-2.6.27.15/fs/reiserfs/xattr.c linux-2.6.27.15-g-v/fs/reiserfs/xattr.c --- linux-2.6.27.15/fs/reiserfs/xattr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/reiserfs/xattr.c 2009-02-10 20:32:14.000000000 +0100 @@ -35,6 +35,7 @@ #include #include #include +#include #include #include #include diff -NurpP --minimal linux-2.6.27.15/fs/select.c linux-2.6.27.15-g-v/fs/select.c --- linux-2.6.27.15/fs/select.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/select.c 2009-02-10 20:32:14.000000000 +0100 @@ -24,6 +24,7 @@ #include #include #include +#include #include @@ -659,6 +660,7 @@ int do_sys_poll(struct pollfd __user *uf struct poll_list *walk = head; unsigned long todo = nfds; + gr_learn_resource(current, RLIMIT_NOFILE, nfds, 1); if (nfds > current->signal->rlim[RLIMIT_NOFILE].rlim_cur) return -EINVAL; diff -NurpP --minimal linux-2.6.27.15/fs/smbfs/symlink.c linux-2.6.27.15-g-v/fs/smbfs/symlink.c --- linux-2.6.27.15/fs/smbfs/symlink.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/smbfs/symlink.c 2009-02-10 20:32:14.000000000 +0100 @@ -55,7 +55,7 @@ static void *smb_follow_link(struct dent static void smb_put_link(struct dentry *dentry, struct nameidata *nd, void *p) { - char *s = nd_get_link(nd); + const char *s = nd_get_link(nd); if (!IS_ERR(s)) __putname(s); } diff -NurpP --minimal linux-2.6.27.15/fs/stat.c linux-2.6.27.15-g-v/fs/stat.c --- linux-2.6.27.15/fs/stat.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/stat.c 2009-02-10 20:32:14.000000000 +0100 @@ -26,6 +26,7 @@ void generic_fillattr(struct inode *inod stat->nlink = inode->i_nlink; stat->uid = inode->i_uid; stat->gid = inode->i_gid; + stat->tag = inode->i_tag; stat->rdev = inode->i_rdev; stat->atime = inode->i_atime; stat->mtime = inode->i_mtime; diff -NurpP --minimal linux-2.6.27.15/fs/super.c linux-2.6.27.15-g-v/fs/super.c --- linux-2.6.27.15/fs/super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/super.c 2009-02-10 20:32:14.000000000 +0100 @@ -38,6 +38,9 @@ #include #include #include +#include +#include +#include #include #include "internal.h" @@ -887,12 +890,18 @@ struct vfsmount * vfs_kern_mount(struct file_system_type *type, int flags, const char *name, void *data) { struct vfsmount *mnt; + struct super_block *sb; char *secdata = NULL; int error; if (!type) return ERR_PTR(-ENODEV); + error = -EPERM; + if ((type->fs_flags & FS_BINARY_MOUNTDATA) && + !vx_capable(CAP_SYS_ADMIN, VXC_BINARY_MOUNT)) + goto out; + error = -ENOMEM; mnt = alloc_vfsmnt(name); if (!mnt) @@ -913,7 +922,14 @@ vfs_kern_mount(struct file_system_type * goto out_free_secdata; BUG_ON(!mnt->mnt_sb); - error = security_sb_kern_mount(mnt->mnt_sb, secdata); + sb = mnt->mnt_sb; + error = -EPERM; + if (!vx_capable(CAP_SYS_ADMIN, VXC_BINARY_MOUNT) && !sb->s_bdev && + (sb->s_magic != PROC_SUPER_MAGIC) && + (sb->s_magic != DEVPTS_SUPER_MAGIC)) + goto out_sb; + + error = security_sb_kern_mount(sb, secdata); if (error) goto out_sb; diff -NurpP --minimal linux-2.6.27.15/fs/sysfs/mount.c linux-2.6.27.15-g-v/fs/sysfs/mount.c --- linux-2.6.27.15/fs/sysfs/mount.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/sysfs/mount.c 2009-02-10 20:32:14.000000000 +0100 @@ -19,8 +19,6 @@ #include "sysfs.h" -/* Random magic number */ -#define SYSFS_MAGIC 0x62656572 static struct vfsmount *sysfs_mount; struct super_block * sysfs_sb = NULL; @@ -46,7 +44,7 @@ static int sysfs_fill_super(struct super sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = SYSFS_MAGIC; + sb->s_magic = SYSFS_SUPER_MAGIC; sb->s_op = &sysfs_ops; sb->s_time_gran = 1; sysfs_sb = sb; diff -NurpP --minimal linux-2.6.27.15/fs/sysfs/symlink.c linux-2.6.27.15-g-v/fs/sysfs/symlink.c --- linux-2.6.27.15/fs/sysfs/symlink.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/sysfs/symlink.c 2009-02-10 20:32:14.000000000 +0100 @@ -200,7 +200,7 @@ static void *sysfs_follow_link(struct de static void sysfs_put_link(struct dentry *dentry, struct nameidata *nd, void *cookie) { - char *page = nd_get_link(nd); + const char *page = nd_get_link(nd); if (!IS_ERR(page)) free_page((unsigned long)page); } diff -NurpP --minimal linux-2.6.27.15/fs/udf/balloc.c linux-2.6.27.15-g-v/fs/udf/balloc.c --- linux-2.6.27.15/fs/udf/balloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/udf/balloc.c 2009-02-10 20:32:14.000000000 +0100 @@ -169,9 +169,7 @@ static void udf_bitmap_free_blocks(struc unsigned long overflow; mutex_lock(&sbi->s_alloc_mutex); - if (bloc.logicalBlockNum < 0 || - (bloc.logicalBlockNum + count) > - sbi->s_partmaps[bloc.partitionReferenceNum].s_partition_len) { + if (bloc.logicalBlockNum + count > sbi->s_partmaps[bloc.partitionReferenceNum].s_partition_len) { udf_debug("%d < %d || %d + %d > %d\n", bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count, sbi->s_partmaps[bloc.partitionReferenceNum]. @@ -239,7 +237,7 @@ static int udf_bitmap_prealloc_blocks(st mutex_lock(&sbi->s_alloc_mutex); part_len = sbi->s_partmaps[partition].s_partition_len; - if (first_block < 0 || first_block >= part_len) + if (first_block >= part_len) goto out; if (first_block + block_count > part_len) @@ -300,7 +298,7 @@ static int udf_bitmap_new_block(struct s mutex_lock(&sbi->s_alloc_mutex); repeat: - if (goal < 0 || goal >= sbi->s_partmaps[partition].s_partition_len) + if (goal >= sbi->s_partmaps[partition].s_partition_len) goal = 0; nr_groups = bitmap->s_nr_groups; @@ -438,9 +436,7 @@ static void udf_table_free_blocks(struct struct udf_inode_info *iinfo; mutex_lock(&sbi->s_alloc_mutex); - if (bloc.logicalBlockNum < 0 || - (bloc.logicalBlockNum + count) > - sbi->s_partmaps[bloc.partitionReferenceNum].s_partition_len) { + if (bloc.logicalBlockNum + count > sbi->s_partmaps[bloc.partitionReferenceNum].s_partition_len) { udf_debug("%d < %d || %d + %d > %d\n", bloc.logicalBlockNum, 0, bloc.logicalBlockNum, count, sbi->s_partmaps[bloc.partitionReferenceNum]. @@ -671,8 +667,7 @@ static int udf_table_prealloc_blocks(str int8_t etype = -1; struct udf_inode_info *iinfo; - if (first_block < 0 || - first_block >= sbi->s_partmaps[partition].s_partition_len) + if (first_block >= sbi->s_partmaps[partition].s_partition_len) return 0; iinfo = UDF_I(table); @@ -750,7 +745,7 @@ static int udf_table_new_block(struct su return newblock; mutex_lock(&sbi->s_alloc_mutex); - if (goal < 0 || goal >= sbi->s_partmaps[partition].s_partition_len) + if (goal >= sbi->s_partmaps[partition].s_partition_len) goal = 0; /* We search for the closest matching block to goal. If we find diff -NurpP --minimal linux-2.6.27.15/fs/ufs/inode.c linux-2.6.27.15-g-v/fs/ufs/inode.c --- linux-2.6.27.15/fs/ufs/inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/ufs/inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -56,9 +56,7 @@ static int ufs_block_to_path(struct inod UFSD("ptrs=uspi->s_apb = %d,double_blocks=%ld \n",ptrs,double_blocks); - if (i_block < 0) { - ufs_warning(inode->i_sb, "ufs_block_to_path", "block < 0"); - } else if (i_block < direct_blocks) { + if (i_block < direct_blocks) { offsets[n++] = i_block; } else if ((i_block -= direct_blocks) < indirect_blocks) { offsets[n++] = UFS_IND_BLOCK; @@ -440,8 +438,6 @@ int ufs_getfrag_block(struct inode *inod lock_kernel(); UFSD("ENTER, ino %lu, fragment %llu\n", inode->i_ino, (unsigned long long)fragment); - if (fragment < 0) - goto abort_negative; if (fragment > ((UFS_NDADDR + uspi->s_apb + uspi->s_2apb + uspi->s_3apb) << uspi->s_fpbshift)) @@ -504,10 +500,6 @@ abort: unlock_kernel(); return err; -abort_negative: - ufs_warning(sb, "ufs_get_block", "block < 0"); - goto abort; - abort_too_big: ufs_warning(sb, "ufs_get_block", "block > big"); goto abort; diff -NurpP --minimal linux-2.6.27.15/fs/utimes.c linux-2.6.27.15-g-v/fs/utimes.c --- linux-2.6.27.15/fs/utimes.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/utimes.c 2009-02-10 20:32:14.000000000 +0100 @@ -8,6 +8,9 @@ #include #include #include +#include +#include +#include #include #include @@ -101,6 +104,12 @@ static int utimes_common(struct path *pa goto mnt_drop_write_and_out; } } + + if (!gr_acl_handle_utime(path->dentry, path->mnt)) { + error = -EACCES; + goto mnt_drop_write_and_out; + } + mutex_lock(&inode->i_mutex); error = notify_change(path->dentry, &newattrs); mutex_unlock(&inode->i_mutex); diff -NurpP --minimal linux-2.6.27.15/fs/xattr.c linux-2.6.27.15-g-v/fs/xattr.c --- linux-2.6.27.15/fs/xattr.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xattr.c 2009-02-10 20:32:14.000000000 +0100 @@ -18,6 +18,7 @@ #include #include #include +#include #include diff -NurpP --minimal linux-2.6.27.15/fs/xfs/linux-2.6/xfs_ioctl.c linux-2.6.27.15-g-v/fs/xfs/linux-2.6/xfs_ioctl.c --- linux-2.6.27.15/fs/xfs/linux-2.6/xfs_ioctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/linux-2.6/xfs_ioctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -806,6 +806,10 @@ xfs_merge_ioc_xflags( xflags |= XFS_XFLAG_IMMUTABLE; else xflags &= ~XFS_XFLAG_IMMUTABLE; + if (flags & FS_IXUNLINK_FL) + xflags |= XFS_XFLAG_IXUNLINK; + else + xflags &= ~XFS_XFLAG_IXUNLINK; if (flags & FS_APPEND_FL) xflags |= XFS_XFLAG_APPEND; else @@ -834,6 +838,8 @@ xfs_di2lxflags( if (di_flags & XFS_DIFLAG_IMMUTABLE) flags |= FS_IMMUTABLE_FL; + if (di_flags & XFS_DIFLAG_IXUNLINK) + flags |= FS_IXUNLINK_FL; if (di_flags & XFS_DIFLAG_APPEND) flags |= FS_APPEND_FL; if (di_flags & XFS_DIFLAG_SYNC) @@ -892,6 +898,8 @@ xfs_set_diflags( di_flags = (ip->i_d.di_flags & XFS_DIFLAG_PREALLOC); if (xflags & XFS_XFLAG_IMMUTABLE) di_flags |= XFS_DIFLAG_IMMUTABLE; + if (xflags & XFS_XFLAG_IXUNLINK) + di_flags |= XFS_DIFLAG_IXUNLINK; if (xflags & XFS_XFLAG_APPEND) di_flags |= XFS_DIFLAG_APPEND; if (xflags & XFS_XFLAG_SYNC) @@ -934,6 +942,10 @@ xfs_diflags_to_linux( inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; + if (xflags & XFS_XFLAG_IXUNLINK) + inode->i_flags |= S_IXUNLINK; + else + inode->i_flags &= ~S_IXUNLINK; if (xflags & XFS_XFLAG_APPEND) inode->i_flags |= S_APPEND; else @@ -1392,10 +1404,18 @@ xfs_ioctl( case XFS_IOC_FSGETXATTRA: return xfs_ioc_fsgetxattr(ip, 1, arg); case XFS_IOC_FSSETXATTR: + if (IS_BARRIER(inode)) { + vxwprintk_task(1, "messing with the barrier."); + return -XFS_ERROR(EACCES); + } return xfs_ioc_fssetxattr(ip, filp, arg); case XFS_IOC_GETXFLAGS: return xfs_ioc_getxflags(ip, arg); case XFS_IOC_SETXFLAGS: + if (IS_BARRIER(inode)) { + vxwprintk_task(1, "messing with the barrier."); + return -XFS_ERROR(EACCES); + } return xfs_ioc_setxflags(ip, filp, arg); case XFS_IOC_FSSETDM: { diff -NurpP --minimal linux-2.6.27.15/fs/xfs/linux-2.6/xfs_iops.c linux-2.6.27.15-g-v/fs/xfs/linux-2.6/xfs_iops.c --- linux-2.6.27.15/fs/xfs/linux-2.6/xfs_iops.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/linux-2.6/xfs_iops.c 2009-02-10 20:32:14.000000000 +0100 @@ -53,6 +53,7 @@ #include #include #include +#include /* * Bring the atime in the XFS inode uptodate. @@ -500,7 +501,7 @@ xfs_vn_put_link( struct nameidata *nd, void *p) { - char *s = nd_get_link(nd); + const char *s = nd_get_link(nd); if (!IS_ERR(s)) kfree(s); @@ -558,6 +559,7 @@ xfs_vn_getattr( stat->nlink = ip->i_d.di_nlink; stat->uid = ip->i_d.di_uid; stat->gid = ip->i_d.di_gid; + stat->tag = ip->i_d.di_tag; stat->ino = ip->i_ino; #if XFS_BIG_INUMS stat->ino += mp->m_inoadd; @@ -597,6 +599,12 @@ xfs_vn_getattr( } STATIC int +xfs_vn_sync_xflags(struct inode *inode) +{ + return -xfs_sync_xflags(XFS_I(inode)); +} + +STATIC int xfs_vn_setattr( struct dentry *dentry, struct iattr *iattr) @@ -671,6 +679,7 @@ static const struct inode_operations xfs .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, .fallocate = xfs_vn_fallocate, + .sync_flags = xfs_vn_sync_xflags, }; static const struct inode_operations xfs_dir_inode_operations = { @@ -696,6 +705,7 @@ static const struct inode_operations xfs .getxattr = generic_getxattr, .removexattr = generic_removexattr, .listxattr = xfs_vn_listxattr, + .sync_flags = xfs_vn_sync_xflags, }; static const struct inode_operations xfs_dir_ci_inode_operations = { @@ -745,6 +755,10 @@ xfs_diflags_to_iflags( inode->i_flags |= S_IMMUTABLE; else inode->i_flags &= ~S_IMMUTABLE; + if (ip->i_d.di_flags & XFS_DIFLAG_IXUNLINK) + inode->i_flags |= S_IXUNLINK; + else + inode->i_flags &= ~S_IXUNLINK; if (ip->i_d.di_flags & XFS_DIFLAG_APPEND) inode->i_flags |= S_APPEND; else @@ -757,6 +771,15 @@ xfs_diflags_to_iflags( inode->i_flags |= S_NOATIME; else inode->i_flags &= ~S_NOATIME; + + if (ip->i_d.di_vflags & XFS_DIVFLAG_BARRIER) + inode->i_vflags |= V_BARRIER; + else + inode->i_vflags &= ~V_BARRIER; + if (ip->i_d.di_vflags & XFS_DIVFLAG_COW) + inode->i_vflags |= V_COW; + else + inode->i_vflags &= ~V_COW; } /* @@ -777,6 +800,7 @@ xfs_setup_inode( inode->i_nlink = ip->i_d.di_nlink; inode->i_uid = ip->i_d.di_uid; inode->i_gid = ip->i_d.di_gid; + inode->i_tag = ip->i_d.di_tag; switch (inode->i_mode & S_IFMT) { case S_IFBLK: diff -NurpP --minimal linux-2.6.27.15/fs/xfs/linux-2.6/xfs_linux.h linux-2.6.27.15-g-v/fs/xfs/linux-2.6/xfs_linux.h --- linux-2.6.27.15/fs/xfs/linux-2.6/xfs_linux.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/linux-2.6/xfs_linux.h 2009-02-10 20:32:14.000000000 +0100 @@ -126,6 +126,7 @@ #define current_cpu() (raw_smp_processor_id()) #define current_pid() (current->pid) +#define current_fstag(cred,vp) (dx_current_fstag(vp->i_sb)) #define current_test_flags(f) (current->flags & (f)) #define current_set_flags_nested(sp, f) \ (*(sp) = current->flags, current->flags |= (f)) diff -NurpP --minimal linux-2.6.27.15/fs/xfs/linux-2.6/xfs_super.c linux-2.6.27.15-g-v/fs/xfs/linux-2.6/xfs_super.c --- linux-2.6.27.15/fs/xfs/linux-2.6/xfs_super.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/linux-2.6/xfs_super.c 2009-02-10 20:32:14.000000000 +0100 @@ -147,6 +147,9 @@ xfs_args_allocate( #define MNTOPT_DMAPI "dmapi" /* DMI enabled (DMAPI / XDSM) */ #define MNTOPT_XDSM "xdsm" /* DMI enabled (DMAPI / XDSM) */ #define MNTOPT_DMI "dmi" /* DMI enabled (DMAPI / XDSM) */ +#define MNTOPT_TAGXID "tagxid" /* context tagging for inodes */ +#define MNTOPT_TAGGED "tag" /* context tagging for inodes */ +#define MNTOPT_NOTAGTAG "notag" /* do not use context tagging */ /* * Table driven mount option parser. @@ -155,10 +158,14 @@ xfs_args_allocate( * in the future, too. */ enum { + Opt_tag, Opt_notag, Opt_barrier, Opt_nobarrier, Opt_err }; static match_table_t tokens = { + {Opt_tag, "tagxid"}, + {Opt_tag, "tag"}, + {Opt_notag, "notag"}, {Opt_barrier, "barrier"}, {Opt_nobarrier, "nobarrier"}, {Opt_err, NULL} @@ -383,6 +390,19 @@ xfs_parseargs( } else if (!strcmp(this_char, "irixsgid")) { cmn_err(CE_WARN, "XFS: irixsgid is now a sysctl(2) variable, option is deprecated."); +#ifndef CONFIG_TAGGING_NONE + } else if (!strcmp(this_char, MNTOPT_TAGGED)) { + args->flags2 |= XFSMNT2_TAGGED; + } else if (!strcmp(this_char, MNTOPT_NOTAGTAG)) { + args->flags2 &= ~XFSMNT2_TAGGED; + } else if (!strcmp(this_char, MNTOPT_TAGXID)) { + args->flags2 |= XFSMNT2_TAGGED; +#endif +#ifdef CONFIG_PROPAGATE + } else if (!strcmp(this_char, MNTOPT_TAGGED)) { + /* use value */ + args->flags2 |= XFSMNT2_TAGGED; +#endif } else { cmn_err(CE_WARN, "XFS: unknown mount option [%s].", this_char); @@ -1301,6 +1321,16 @@ xfs_fs_remount( case Opt_nobarrier: mp->m_flags &= ~XFS_MOUNT_BARRIER; break; + case Opt_tag: + if (!(sb->s_flags & MS_TAGGED)) { + printk(KERN_INFO + "XFS: %s: tagging not permitted on remount.\n", + sb->s_id); + return -EINVAL; + } + break; + case Opt_notag: + break; default: /* * Logically we would return an error here to prevent @@ -1555,6 +1585,9 @@ xfs_start_flags( if (ap->flags & XFSMNT_DMAPI) mp->m_flags |= XFS_MOUNT_DMAPI; + + if (ap->flags2 & XFSMNT2_TAGGED) + mp->m_flags |= XFS_MOUNT_TAGGED; return 0; @@ -1749,6 +1782,9 @@ xfs_fs_fill_super( XFS_SEND_MOUNT(mp, DM_RIGHT_NULL, args->mtpt, args->fsname); + if (mp->m_flags & XFS_MOUNT_TAGGED) + sb->s_flags |= MS_TAGGED; + sb->s_dirt = 1; sb->s_magic = XFS_SB_MAGIC; sb->s_blocksize = mp->m_sb.sb_blocksize; diff -NurpP --minimal linux-2.6.27.15/fs/xfs/quota/xfs_qm_syscalls.c linux-2.6.27.15-g-v/fs/xfs/quota/xfs_qm_syscalls.c --- linux-2.6.27.15/fs/xfs/quota/xfs_qm_syscalls.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/quota/xfs_qm_syscalls.c 2009-02-10 20:32:14.000000000 +0100 @@ -426,7 +426,7 @@ xfs_qm_scall_quotaon( uint accflags; __int64_t sbflags; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_QUOTA_CTL)) return XFS_ERROR(EPERM); flags &= (XFS_ALL_QUOTA_ACCT | XFS_ALL_QUOTA_ENFD); diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_bmap.c linux-2.6.27.15-g-v/fs/xfs/xfs_bmap.c --- linux-2.6.27.15/fs/xfs/xfs_bmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_bmap.c 2009-02-10 20:32:14.000000000 +0100 @@ -360,7 +360,7 @@ xfs_bmap_validate_ret( int nmap, int ret_nmap); #else -#define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) +#define xfs_bmap_validate_ret(bno,len,flags,mval,onmap,nmap) do {} while (0) #endif /* DEBUG */ #if defined(XFS_RW_TRACE) diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_clnt.h linux-2.6.27.15-g-v/fs/xfs/xfs_clnt.h --- linux-2.6.27.15/fs/xfs/xfs_clnt.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_clnt.h 2009-02-10 20:32:14.000000000 +0100 @@ -101,5 +101,6 @@ struct xfs_mount_args { * I/O size in stat(2) */ #define XFSMNT2_FILESTREAMS 0x00000002 /* enable the filestreams * allocator */ +#define XFSMNT2_TAGGED 0x10000000 /* context tagging */ #endif /* __XFS_CLNT_H__ */ diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_dinode.h linux-2.6.27.15-g-v/fs/xfs/xfs_dinode.h --- linux-2.6.27.15/fs/xfs/xfs_dinode.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_dinode.h 2009-02-10 20:32:14.000000000 +0100 @@ -53,7 +53,9 @@ typedef struct xfs_dinode_core { __be32 di_gid; /* owner's group id */ __be32 di_nlink; /* number of links to file */ __be16 di_projid; /* owner's project id */ - __u8 di_pad[8]; /* unused, zeroed space */ + __be16 di_tag; /* context tagging */ + __be16 di_vflags; /* vserver specific flags */ + __u8 di_pad[4]; /* unused, zeroed space */ __be16 di_flushiter; /* incremented on flush */ xfs_timestamp_t di_atime; /* time last accessed */ xfs_timestamp_t di_mtime; /* time last modified */ @@ -136,7 +138,9 @@ typedef struct xfs_dinode #define XFS_DI_NEXT_UNLINKED 0x1000000 #define XFS_DI_U 0x2000000 #define XFS_DI_A 0x4000000 -#define XFS_DI_NUM_BITS 27 +#define XFS_DI_TAG 0x8000000 +#define XFS_DI_VFLAGS 0x10000000 +#define XFS_DI_NUM_BITS 29 #define XFS_DI_ALL_BITS ((1 << XFS_DI_NUM_BITS) - 1) #define XFS_DI_CORE_BITS (XFS_DI_ALL_BITS & ~(XFS_DI_U|XFS_DI_A)) @@ -223,6 +227,8 @@ typedef enum xfs_dinode_fmt #define XFS_DIFLAG_EXTSZINHERIT_BIT 12 /* inherit inode extent size */ #define XFS_DIFLAG_NODEFRAG_BIT 13 /* do not reorganize/defragment */ #define XFS_DIFLAG_FILESTREAM_BIT 14 /* use filestream allocator */ +#define XFS_DIFLAG_IXUNLINK_BIT 15 /* Immutable inver on unlink */ + #define XFS_DIFLAG_REALTIME (1 << XFS_DIFLAG_REALTIME_BIT) #define XFS_DIFLAG_PREALLOC (1 << XFS_DIFLAG_PREALLOC_BIT) #define XFS_DIFLAG_NEWRTBM (1 << XFS_DIFLAG_NEWRTBM_BIT) @@ -238,6 +244,7 @@ typedef enum xfs_dinode_fmt #define XFS_DIFLAG_EXTSZINHERIT (1 << XFS_DIFLAG_EXTSZINHERIT_BIT) #define XFS_DIFLAG_NODEFRAG (1 << XFS_DIFLAG_NODEFRAG_BIT) #define XFS_DIFLAG_FILESTREAM (1 << XFS_DIFLAG_FILESTREAM_BIT) +#define XFS_DIFLAG_IXUNLINK (1 << XFS_DIFLAG_IXUNLINK_BIT) #ifdef CONFIG_XFS_RT #define XFS_IS_REALTIME_INODE(ip) ((ip)->i_d.di_flags & XFS_DIFLAG_REALTIME) @@ -250,6 +257,10 @@ typedef enum xfs_dinode_fmt XFS_DIFLAG_IMMUTABLE | XFS_DIFLAG_APPEND | XFS_DIFLAG_SYNC | \ XFS_DIFLAG_NOATIME | XFS_DIFLAG_NODUMP | XFS_DIFLAG_RTINHERIT | \ XFS_DIFLAG_PROJINHERIT | XFS_DIFLAG_NOSYMLINKS | XFS_DIFLAG_EXTSIZE | \ - XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM) + XFS_DIFLAG_EXTSZINHERIT | XFS_DIFLAG_NODEFRAG | XFS_DIFLAG_FILESTREAM | \ + XFS_DIFLAG_IXUNLINK) + +#define XFS_DIVFLAG_BARRIER 0x01 +#define XFS_DIVFLAG_COW 0x02 #endif /* __XFS_DINODE_H__ */ diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_fs.h linux-2.6.27.15-g-v/fs/xfs/xfs_fs.h --- linux-2.6.27.15/fs/xfs/xfs_fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_fs.h 2009-02-10 20:32:14.000000000 +0100 @@ -67,6 +67,9 @@ struct fsxattr { #define XFS_XFLAG_EXTSZINHERIT 0x00001000 /* inherit inode extent size */ #define XFS_XFLAG_NODEFRAG 0x00002000 /* do not defragment */ #define XFS_XFLAG_FILESTREAM 0x00004000 /* use filestream allocator */ +#define XFS_XFLAG_IXUNLINK 0x00008000 /* immutable invert on unlink */ +#define XFS_XFLAG_BARRIER 0x10000000 /* chroot() barrier */ +#define XFS_XFLAG_COW 0x20000000 /* copy on write mark */ #define XFS_XFLAG_HASATTR 0x80000000 /* no DIFLAG for this */ /* @@ -297,7 +300,8 @@ typedef struct xfs_bstat { __s32 bs_extents; /* number of extents */ __u32 bs_gen; /* generation count */ __u16 bs_projid; /* project id */ - unsigned char bs_pad[14]; /* pad space, unused */ + __u16 bs_tag; /* context tagging */ + unsigned char bs_pad[12]; /* pad space, unused */ __u32 bs_dmevmask; /* DMIG event mask */ __u16 bs_dmstate; /* DMIG state info */ __u16 bs_aextents; /* attribute number of extents */ diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_ialloc.c linux-2.6.27.15-g-v/fs/xfs/xfs_ialloc.c --- linux-2.6.27.15/fs/xfs/xfs_ialloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_ialloc.c 2009-02-10 20:32:14.000000000 +0100 @@ -84,6 +84,8 @@ xfs_ialloc_log_di( offsetof(xfs_dinode_t, di_next_unlinked), offsetof(xfs_dinode_t, di_u), offsetof(xfs_dinode_t, di_a), + offsetof(xfs_dinode_core_t, di_tag), + offsetof(xfs_dinode_core_t, di_vflags), sizeof(xfs_dinode_t) }; diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_inode.c linux-2.6.27.15-g-v/fs/xfs/xfs_inode.c --- linux-2.6.27.15/fs/xfs/xfs_inode.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_inode.c 2009-02-10 20:32:14.000000000 +0100 @@ -249,6 +249,7 @@ xfs_inotobp( return 0; } +#include /* * This routine is called to map an inode to the buffer containing @@ -660,15 +661,25 @@ xfs_iformat_btree( void xfs_dinode_from_disk( xfs_icdinode_t *to, - xfs_dinode_core_t *from) + xfs_dinode_core_t *from, + int tagged) { + uint32_t uid, gid, tag; + to->di_magic = be16_to_cpu(from->di_magic); to->di_mode = be16_to_cpu(from->di_mode); to->di_version = from ->di_version; to->di_format = from->di_format; to->di_onlink = be16_to_cpu(from->di_onlink); - to->di_uid = be32_to_cpu(from->di_uid); - to->di_gid = be32_to_cpu(from->di_gid); + + uid = be32_to_cpu(from->di_uid); + gid = be32_to_cpu(from->di_gid); + tag = be16_to_cpu(from->di_tag); + + to->di_uid = INOTAG_UID(tagged, uid, gid); + to->di_gid = INOTAG_GID(tagged, uid, gid); + to->di_tag = INOTAG_TAG(tagged, uid, gid, tag); + to->di_nlink = be32_to_cpu(from->di_nlink); to->di_projid = be16_to_cpu(from->di_projid); memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); @@ -689,21 +700,26 @@ xfs_dinode_from_disk( to->di_dmevmask = be32_to_cpu(from->di_dmevmask); to->di_dmstate = be16_to_cpu(from->di_dmstate); to->di_flags = be16_to_cpu(from->di_flags); + to->di_vflags = be16_to_cpu(from->di_vflags); to->di_gen = be32_to_cpu(from->di_gen); } void xfs_dinode_to_disk( xfs_dinode_core_t *to, - xfs_icdinode_t *from) + xfs_icdinode_t *from, + int tagged) { to->di_magic = cpu_to_be16(from->di_magic); to->di_mode = cpu_to_be16(from->di_mode); to->di_version = from ->di_version; to->di_format = from->di_format; to->di_onlink = cpu_to_be16(from->di_onlink); - to->di_uid = cpu_to_be32(from->di_uid); - to->di_gid = cpu_to_be32(from->di_gid); + + to->di_uid = cpu_to_be32(TAGINO_UID(tagged, from->di_uid, from->di_tag)); + to->di_gid = cpu_to_be32(TAGINO_GID(tagged, from->di_gid, from->di_tag)); + to->di_tag = cpu_to_be16(TAGINO_TAG(tagged, from->di_tag)); + to->di_nlink = cpu_to_be32(from->di_nlink); to->di_projid = cpu_to_be16(from->di_projid); memcpy(to->di_pad, from->di_pad, sizeof(to->di_pad)); @@ -724,12 +740,14 @@ xfs_dinode_to_disk( to->di_dmevmask = cpu_to_be32(from->di_dmevmask); to->di_dmstate = cpu_to_be16(from->di_dmstate); to->di_flags = cpu_to_be16(from->di_flags); + to->di_vflags = cpu_to_be16(from->di_vflags); to->di_gen = cpu_to_be32(from->di_gen); } STATIC uint _xfs_dic2xflags( - __uint16_t di_flags) + __uint16_t di_flags, + __uint16_t di_vflags) { uint flags = 0; @@ -740,6 +758,8 @@ _xfs_dic2xflags( flags |= XFS_XFLAG_PREALLOC; if (di_flags & XFS_DIFLAG_IMMUTABLE) flags |= XFS_XFLAG_IMMUTABLE; + if (di_flags & XFS_DIFLAG_IXUNLINK) + flags |= XFS_XFLAG_IXUNLINK; if (di_flags & XFS_DIFLAG_APPEND) flags |= XFS_XFLAG_APPEND; if (di_flags & XFS_DIFLAG_SYNC) @@ -764,6 +784,10 @@ _xfs_dic2xflags( flags |= XFS_XFLAG_FILESTREAM; } + if (di_vflags & XFS_DIVFLAG_BARRIER) + flags |= FS_BARRIER_FL; + if (di_vflags & XFS_DIVFLAG_COW) + flags |= FS_COW_FL; return flags; } @@ -773,7 +797,7 @@ xfs_ip2xflags( { xfs_icdinode_t *dic = &ip->i_d; - return _xfs_dic2xflags(dic->di_flags) | + return _xfs_dic2xflags(dic->di_flags, dic->di_vflags) | (XFS_IFORK_Q(ip) ? XFS_XFLAG_HASATTR : 0); } @@ -783,7 +807,8 @@ xfs_dic2xflags( { xfs_dinode_core_t *dic = &dip->di_core; - return _xfs_dic2xflags(be16_to_cpu(dic->di_flags)) | + return _xfs_dic2xflags(be16_to_cpu(dic->di_flags), + be16_to_cpu(dic->di_vflags)) | (XFS_DFORK_Q(dip) ? XFS_XFLAG_HASATTR : 0); } @@ -878,7 +903,8 @@ xfs_iread( * Otherwise, just get the truly permanent information. */ if (dip->di_core.di_mode) { - xfs_dinode_from_disk(&ip->i_d, &dip->di_core); + xfs_dinode_from_disk(&ip->i_d, &dip->di_core, + mp->m_flags & XFS_MOUNT_TAGGED); error = xfs_iformat(ip, dip); if (error) { kmem_zone_free(xfs_inode_zone, ip); @@ -1083,6 +1109,7 @@ xfs_ialloc( ASSERT(ip->i_d.di_nlink == nlink); ip->i_d.di_uid = current_fsuid(); ip->i_d.di_gid = current_fsgid(); + ip->i_d.di_tag = current_fstag(cr, ip->i_vnode); ip->i_d.di_projid = prid; memset(&(ip->i_d.di_pad[0]), 0, sizeof(ip->i_d.di_pad)); @@ -1143,6 +1170,7 @@ xfs_ialloc( ip->i_d.di_dmevmask = 0; ip->i_d.di_dmstate = 0; ip->i_d.di_flags = 0; + ip->i_d.di_vflags = 0; flags = XFS_ILOG_CORE; switch (mode & S_IFMT) { case S_IFIFO: @@ -2249,6 +2277,7 @@ xfs_ifree( } ip->i_d.di_mode = 0; /* mark incore inode as free */ ip->i_d.di_flags = 0; + ip->i_d.di_vflags = 0; ip->i_d.di_dmevmask = 0; ip->i_d.di_forkoff = 0; /* mark the attr fork not in use */ ip->i_df.if_ext_max = @@ -3342,7 +3371,8 @@ xfs_iflush_int( * because if the inode is dirty at all the core must * be. */ - xfs_dinode_to_disk(&dip->di_core, &ip->i_d); + xfs_dinode_to_disk(&dip->di_core, &ip->i_d, + mp->m_flags & XFS_MOUNT_TAGGED); /* Wrap, we never let the log put out DI_MAX_FLUSH */ if (ip->i_d.di_flushiter == DI_MAX_FLUSH) diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_inode.h linux-2.6.27.15-g-v/fs/xfs/xfs_inode.h --- linux-2.6.27.15/fs/xfs/xfs_inode.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_inode.h 2009-02-10 20:32:14.000000000 +0100 @@ -173,7 +173,9 @@ typedef struct xfs_icdinode { __uint32_t di_gid; /* owner's group id */ __uint32_t di_nlink; /* number of links to file */ __uint16_t di_projid; /* owner's project id */ - __uint8_t di_pad[8]; /* unused, zeroed space */ + __uint16_t di_tag; /* context tagging */ + __uint16_t di_vflags; /* vserver specific flags */ + __uint8_t di_pad[4]; /* unused, zeroed space */ __uint16_t di_flushiter; /* incremented on flush */ xfs_ictimestamp_t di_atime; /* time last accessed */ xfs_ictimestamp_t di_mtime; /* time last modified */ @@ -500,9 +502,9 @@ int xfs_ialloc(struct xfs_trans *, xfs_ xfs_nlink_t, xfs_dev_t, struct cred *, xfs_prid_t, int, struct xfs_buf **, boolean_t *, xfs_inode_t **); void xfs_dinode_from_disk(struct xfs_icdinode *, - struct xfs_dinode_core *); + struct xfs_dinode_core *, int tagged); void xfs_dinode_to_disk(struct xfs_dinode_core *, - struct xfs_icdinode *); + struct xfs_icdinode *, int tagged); uint xfs_ip2xflags(struct xfs_inode *); uint xfs_dic2xflags(struct xfs_dinode *); diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_itable.c linux-2.6.27.15-g-v/fs/xfs/xfs_itable.c --- linux-2.6.27.15/fs/xfs/xfs_itable.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_itable.c 2009-02-10 20:32:14.000000000 +0100 @@ -82,6 +82,7 @@ xfs_bulkstat_one_iget( buf->bs_mode = dic->di_mode; buf->bs_uid = dic->di_uid; buf->bs_gid = dic->di_gid; + buf->bs_tag = dic->di_tag; buf->bs_size = dic->di_size; vn_atime_to_bstime(VFS_I(ip), &buf->bs_atime); buf->bs_mtime.tv_sec = dic->di_mtime.t_sec; diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_log_recover.c linux-2.6.27.15-g-v/fs/xfs/xfs_log_recover.c --- linux-2.6.27.15/fs/xfs/xfs_log_recover.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_log_recover.c 2009-02-10 20:32:14.000000000 +0100 @@ -2417,7 +2417,8 @@ xlog_recover_do_inode_trans( /* The core is in in-core format */ xfs_dinode_to_disk(&dip->di_core, - (xfs_icdinode_t *)item->ri_buf[1].i_addr); + (xfs_icdinode_t *)item->ri_buf[1].i_addr, + mp->m_flags & XFS_MOUNT_TAGGED); /* the rest is in on-disk format */ if (item->ri_buf[1].i_len > sizeof(xfs_dinode_core_t)) { diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_mount.h linux-2.6.27.15-g-v/fs/xfs/xfs_mount.h --- linux-2.6.27.15/fs/xfs/xfs_mount.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_mount.h 2009-02-10 20:32:14.000000000 +0100 @@ -384,6 +384,7 @@ typedef struct xfs_mount { allocator */ #define XFS_MOUNT_NOATTR2 (1ULL << 25) /* disable use of attr2 format */ +#define XFS_MOUNT_TAGGED (1ULL << 31) /* context tagging */ /* * Default minimum read and write sizes. diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_vnodeops.c linux-2.6.27.15-g-v/fs/xfs/xfs_vnodeops.c --- linux-2.6.27.15/fs/xfs/xfs_vnodeops.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_vnodeops.c 2009-02-10 20:32:14.000000000 +0100 @@ -75,6 +75,89 @@ xfs_open( return 0; } +STATIC void +xfs_get_inode_flags( + xfs_inode_t *ip) +{ + struct inode *inode = VFS_I(ip); + unsigned int flags = inode->i_flags; + unsigned int vflags = inode->i_vflags; + + if (flags & S_IMMUTABLE) + ip->i_d.di_flags |= XFS_DIFLAG_IMMUTABLE; + else + ip->i_d.di_flags &= ~XFS_DIFLAG_IMMUTABLE; + if (flags & S_IXUNLINK) + ip->i_d.di_flags |= XFS_DIFLAG_IXUNLINK; + else + ip->i_d.di_flags &= ~XFS_DIFLAG_IXUNLINK; + + if (vflags & V_BARRIER) + ip->i_d.di_vflags |= XFS_DIVFLAG_BARRIER; + else + ip->i_d.di_vflags &= ~XFS_DIVFLAG_BARRIER; + if (vflags & V_COW) + ip->i_d.di_vflags |= XFS_DIVFLAG_COW; + else + ip->i_d.di_vflags &= ~XFS_DIVFLAG_COW; +} + +int +xfs_sync_xflags( + xfs_inode_t *ip) +{ + struct xfs_mount *mp = ip->i_mount; + struct xfs_trans *tp; + unsigned int lock_flags = 0; + int code; + + xfs_itrace_entry(ip); + + if (mp->m_flags & XFS_MOUNT_RDONLY) + return XFS_ERROR(EROFS); + + /* + * we acquire the inode lock and do an error checking pass. + */ + tp = xfs_trans_alloc(mp, XFS_TRANS_SETATTR_NOT_SIZE); + code = xfs_trans_reserve(tp, 0, XFS_ICHANGE_LOG_RES(mp), 0, 0, 0); + if (code) + goto error_return; + + lock_flags = XFS_ILOCK_EXCL; + xfs_ilock(ip, lock_flags); + + xfs_trans_ijoin(tp, ip, lock_flags); + xfs_trans_ihold(tp, ip); + + xfs_get_inode_flags(ip); + // xfs_diflags_to_linux(ip); + + xfs_trans_log_inode(tp, ip, XFS_ILOG_CORE); + xfs_ichgtime(ip, XFS_ICHGTIME_CHG); + + XFS_STATS_INC(xs_ig_attrchg); + + /* + * If this is a synchronous mount, make sure that the + * transaction goes to disk before returning to the user. + */ + if (mp->m_flags & XFS_MOUNT_WSYNC) + xfs_trans_set_sync(tp); + code = xfs_trans_commit(tp, 0); + xfs_iunlock(ip, lock_flags); + + if (code) + return code; + return 0; + + error_return: + xfs_trans_cancel(tp, 0); + if (lock_flags) + xfs_iunlock(ip, lock_flags); + return code; +} + int xfs_setattr( struct xfs_inode *ip, @@ -91,6 +174,7 @@ xfs_setattr( uint commit_flags=0; uid_t uid=0, iuid=0; gid_t gid=0, igid=0; + tag_t tag=0, itag=0; int timeflags = 0; struct xfs_dquot *udqp, *gdqp, *olddquot1, *olddquot2; int file_owner; @@ -238,7 +322,7 @@ xfs_setattr( * and can change the group id only to a group of which he * or she is a member. */ - if (mask & (ATTR_UID|ATTR_GID)) { + if (mask & (ATTR_UID|ATTR_GID|ATTR_TAG)) { /* * These IDs could have changed since we last looked at them. * But, we're assured that if the ownership did change @@ -247,8 +331,10 @@ xfs_setattr( */ iuid = ip->i_d.di_uid; igid = ip->i_d.di_gid; + itag = ip->i_d.di_tag; gid = (mask & ATTR_GID) ? iattr->ia_gid : igid; uid = (mask & ATTR_UID) ? iattr->ia_uid : iuid; + tag = (mask & ATTR_TAG) ? iattr->ia_tag : itag; /* * CAP_CHOWN overrides the following restrictions: @@ -272,7 +358,9 @@ xfs_setattr( * going to change. */ if ((XFS_IS_UQUOTA_ON(mp) && iuid != uid) || - (XFS_IS_GQUOTA_ON(mp) && igid != gid)) { + (XFS_IS_GQUOTA_ON(mp) && igid != gid) || + (XFS_IS_GQUOTA_ON(mp) && itag != tag)) { + /* TODO: handle tagging? */ ASSERT(tp); code = XFS_QM_DQVOPCHOWNRESV(mp, tp, ip, udqp, gdqp, capable(CAP_FOWNER) ? @@ -461,7 +549,7 @@ xfs_setattr( * and can change the group id only to a group of which he * or she is a member. */ - if (mask & (ATTR_UID|ATTR_GID)) { + if (mask & (ATTR_UID|ATTR_GID|ATTR_TAG)) { /* * CAP_FSETID overrides the following restrictions: * @@ -477,6 +565,10 @@ xfs_setattr( * Change the ownerships and register quota modifications * in the transaction. */ + if (itag != tag) { + ip->i_d.di_tag = tag; + inode->i_tag = tag; + } if (iuid != uid) { if (XFS_IS_UQUOTA_ON(mp)) { ASSERT(mask & ATTR_UID); diff -NurpP --minimal linux-2.6.27.15/fs/xfs/xfs_vnodeops.h linux-2.6.27.15-g-v/fs/xfs/xfs_vnodeops.h --- linux-2.6.27.15/fs/xfs/xfs_vnodeops.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/fs/xfs/xfs_vnodeops.h 2009-02-10 20:32:14.000000000 +0100 @@ -15,6 +15,7 @@ struct xfs_iomap; int xfs_open(struct xfs_inode *ip); +int xfs_sync_xflags(struct xfs_inode *ip); int xfs_setattr(struct xfs_inode *ip, struct iattr *vap, int flags, struct cred *credp); #define XFS_ATTR_DMI 0x01 /* invocation from a DMI function */ diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl_alloc.c linux-2.6.27.15-g-v/grsecurity/gracl_alloc.c --- linux-2.6.27.15/grsecurity/gracl_alloc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl_alloc.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,91 @@ +#include +#include +#include +#include +#include +#include + +static unsigned long alloc_stack_next = 1; +static unsigned long alloc_stack_size = 1; +static void **alloc_stack; + +static __inline__ int +alloc_pop(void) +{ + if (alloc_stack_next == 1) + return 0; + + kfree(alloc_stack[alloc_stack_next - 2]); + + alloc_stack_next--; + + return 1; +} + +static __inline__ void +alloc_push(void *buf) +{ + if (alloc_stack_next >= alloc_stack_size) + BUG(); + + alloc_stack[alloc_stack_next - 1] = buf; + + alloc_stack_next++; + + return; +} + +void * +acl_alloc(unsigned long len) +{ + void *ret; + + if (len > PAGE_SIZE) + BUG(); + + ret = kmalloc(len, GFP_KERNEL); + + if (ret) + alloc_push(ret); + + return ret; +} + +void +acl_free_all(void) +{ + if (gr_acl_is_enabled() || !alloc_stack) + return; + + while (alloc_pop()) ; + + if (alloc_stack) { + if ((alloc_stack_size * sizeof (void *)) <= PAGE_SIZE) + kfree(alloc_stack); + else + vfree(alloc_stack); + } + + alloc_stack = NULL; + alloc_stack_size = 1; + alloc_stack_next = 1; + + return; +} + +int +acl_alloc_stack_init(unsigned long size) +{ + if ((size * sizeof (void *)) <= PAGE_SIZE) + alloc_stack = + (void **) kmalloc(size * sizeof (void *), GFP_KERNEL); + else + alloc_stack = (void **) vmalloc(size * sizeof (void *)); + + alloc_stack_size = size; + + if (!alloc_stack) + return 0; + else + return 1; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl.c linux-2.6.27.15-g-v/grsecurity/gracl.c --- linux-2.6.27.15/grsecurity/gracl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,3722 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +static struct acl_role_db acl_role_set; +static struct name_db name_set; +static struct inodev_db inodev_set; + +/* for keeping track of userspace pointers used for subjects, so we + can share references in the kernel as well +*/ + +static struct dentry *real_root; +static struct vfsmount *real_root_mnt; + +static struct acl_subj_map_db subj_map_set; + +static struct acl_role_label *default_role; + +static u16 acl_sp_role_value; + +extern char *gr_shared_page[4]; +static DECLARE_MUTEX(gr_dev_sem); +DEFINE_RWLOCK(gr_inode_lock); + +struct gr_arg *gr_usermode; + +static unsigned int gr_status = GR_STATUS_INIT; + +extern int chkpw(struct gr_arg *entry, unsigned char *salt, unsigned char *sum); +extern void gr_clear_learn_entries(void); + +#ifdef CONFIG_GRKERNSEC_RESLOG +extern void gr_log_resource(const struct task_struct *task, + const int res, const unsigned long wanted, const int gt); +#endif + +unsigned char *gr_system_salt; +unsigned char *gr_system_sum; + +static struct sprole_pw **acl_special_roles = NULL; +static __u16 num_sprole_pws = 0; + +static struct acl_role_label *kernel_role = NULL; + +static unsigned int gr_auth_attempts = 0; +static unsigned long gr_auth_expires = 0UL; + +extern struct vfsmount *sock_mnt; +extern struct vfsmount *pipe_mnt; +extern struct vfsmount *shm_mnt; +static struct acl_object_label *fakefs_obj; + +extern int gr_init_uidset(void); +extern void gr_free_uidset(void); +extern void gr_remove_uid(uid_t uid); +extern int gr_find_uid(uid_t uid); + +__inline__ int +gr_acl_is_enabled(void) +{ + return (gr_status & GR_READY); +} + +char gr_roletype_to_char(void) +{ + switch (current->role->roletype & + (GR_ROLE_DEFAULT | GR_ROLE_USER | GR_ROLE_GROUP | + GR_ROLE_SPECIAL)) { + case GR_ROLE_DEFAULT: + return 'D'; + case GR_ROLE_USER: + return 'U'; + case GR_ROLE_GROUP: + return 'G'; + case GR_ROLE_SPECIAL: + return 'S'; + } + + return 'X'; +} + +__inline__ int +gr_acl_tpe_check(void) +{ + if (unlikely(!(gr_status & GR_READY))) + return 0; + if (current->role->roletype & GR_ROLE_TPE) + return 1; + else + return 0; +} + +int +gr_handle_rawio(const struct inode *inode) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_CAPS + if (inode && S_ISBLK(inode->i_mode) && + grsec_enable_chroot_caps && proc_is_chrooted(current) && + !capable(CAP_SYS_RAWIO)) + return 1; +#endif + return 0; +} + +static int +gr_streq(const char *a, const char *b, const unsigned int lena, const unsigned int lenb) +{ + int i; + unsigned long *l1; + unsigned long *l2; + unsigned char *c1; + unsigned char *c2; + int num_longs; + + if (likely(lena != lenb)) + return 0; + + l1 = (unsigned long *)a; + l2 = (unsigned long *)b; + + num_longs = lena / sizeof(unsigned long); + + for (i = num_longs; i--; l1++, l2++) { + if (unlikely(*l1 != *l2)) + return 0; + } + + c1 = (unsigned char *) l1; + c2 = (unsigned char *) l2; + + i = lena - (num_longs * sizeof(unsigned long)); + + for (; i--; c1++, c2++) { + if (unlikely(*c1 != *c2)) + return 0; + } + + return 1; +} + +static char * __our_d_path(struct dentry *dentry, struct vfsmount *vfsmnt, + struct dentry *root, struct vfsmount *rootmnt, + char *buffer, int buflen) +{ + char * end = buffer+buflen; + char * retval; + int namelen; + + *--end = '\0'; + buflen--; + + if (buflen < 1) + goto Elong; + /* Get '/' right */ + retval = end-1; + *retval = '/'; + + for (;;) { + struct dentry * parent; + + if (dentry == root && vfsmnt == rootmnt) + break; + if (dentry == vfsmnt->mnt_root || IS_ROOT(dentry)) { + /* Global root? */ + spin_lock(&vfsmount_lock); + if (vfsmnt->mnt_parent == vfsmnt) { + spin_unlock(&vfsmount_lock); + goto global_root; + } + dentry = vfsmnt->mnt_mountpoint; + vfsmnt = vfsmnt->mnt_parent; + spin_unlock(&vfsmount_lock); + continue; + } + parent = dentry->d_parent; + prefetch(parent); + namelen = dentry->d_name.len; + buflen -= namelen + 1; + if (buflen < 0) + goto Elong; + end -= namelen; + memcpy(end, dentry->d_name.name, namelen); + *--end = '/'; + retval = end; + dentry = parent; + } + + return retval; + +global_root: + namelen = dentry->d_name.len; + buflen -= namelen; + if (buflen < 0) + goto Elong; + retval -= namelen-1; /* hit the slash */ + memcpy(retval, dentry->d_name.name, namelen); + return retval; +Elong: + return ERR_PTR(-ENAMETOOLONG); +} + +static char * +gen_full_path(struct dentry *dentry, struct vfsmount *vfsmnt, + struct dentry *root, struct vfsmount *rootmnt, char *buf, int buflen) +{ + char *retval; + + retval = __our_d_path(dentry, vfsmnt, root, rootmnt, buf, buflen); + if (unlikely(IS_ERR(retval))) + retval = strcpy(buf, ""); + else if (unlikely(retval[1] == '/' && retval[2] == '\0')) + retval[1] = '\0'; + + return retval; +} + +static char * +__d_real_path(const struct dentry *dentry, const struct vfsmount *vfsmnt, + char *buf, int buflen) +{ + char *res; + + /* we can use real_root, real_root_mnt, because this is only called + by the RBAC system */ + res = gen_full_path((struct dentry *)dentry, (struct vfsmount *)vfsmnt, real_root, real_root_mnt, buf, buflen); + + return res; +} + +static char * +d_real_path(const struct dentry *dentry, const struct vfsmount *vfsmnt, + char *buf, int buflen) +{ + char *res; + struct dentry *root; + struct vfsmount *rootmnt; + struct task_struct *reaper = current->nsproxy->pid_ns->child_reaper; + + /* we can't use real_root, real_root_mnt, because they belong only to the RBAC system */ + read_lock(&reaper->fs->lock); + root = dget(reaper->fs->root.dentry); + rootmnt = mntget(reaper->fs->root.mnt); + read_unlock(&reaper->fs->lock); + + spin_lock(&dcache_lock); + res = gen_full_path((struct dentry *)dentry, (struct vfsmount *)vfsmnt, root, rootmnt, buf, buflen); + spin_unlock(&dcache_lock); + + dput(root); + mntput(rootmnt); + return res; +} + +static char * +gr_to_filename_rbac(const struct dentry *dentry, const struct vfsmount *mnt) +{ + char *ret; + spin_lock(&dcache_lock); + ret = __d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[0],smp_processor_id()), + PAGE_SIZE); + spin_unlock(&dcache_lock); + return ret; +} + +char * +gr_to_filename_nolock(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return __d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[0],smp_processor_id()), + PAGE_SIZE); +} + +char * +gr_to_filename(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[0], smp_processor_id()), + PAGE_SIZE); +} + +char * +gr_to_filename1(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[1], smp_processor_id()), + PAGE_SIZE); +} + +char * +gr_to_filename2(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[2], smp_processor_id()), + PAGE_SIZE); +} + +char * +gr_to_filename3(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[3], smp_processor_id()), + PAGE_SIZE); +} + +__inline__ __u32 +to_gr_audit(const __u32 reqmode) +{ + /* masks off auditable permission flags, then shifts them to create + auditing flags, and adds the special case of append auditing if + we're requesting write */ + return (((reqmode & ~GR_AUDITS) << 10) | ((reqmode & GR_WRITE) ? GR_AUDIT_APPEND : 0)); +} + +struct acl_subject_label * +lookup_subject_map(const struct acl_subject_label *userp) +{ + unsigned int index = shash(userp, subj_map_set.s_size); + struct subject_map *match; + + match = subj_map_set.s_hash[index]; + + while (match && match->user != userp) + match = match->next; + + if (match != NULL) + return match->kernel; + else + return NULL; +} + +static void +insert_subj_map_entry(struct subject_map *subjmap) +{ + unsigned int index = shash(subjmap->user, subj_map_set.s_size); + struct subject_map **curr; + + subjmap->prev = NULL; + + curr = &subj_map_set.s_hash[index]; + if (*curr != NULL) + (*curr)->prev = subjmap; + + subjmap->next = *curr; + *curr = subjmap; + + return; +} + +static struct acl_role_label * +lookup_acl_role_label(const struct task_struct *task, const uid_t uid, + const gid_t gid) +{ + unsigned int index = rhash(uid, GR_ROLE_USER, acl_role_set.r_size); + struct acl_role_label *match; + struct role_allowed_ip *ipp; + unsigned int x; + + match = acl_role_set.r_hash[index]; + + while (match) { + if ((match->roletype & (GR_ROLE_DOMAIN | GR_ROLE_USER)) == (GR_ROLE_DOMAIN | GR_ROLE_USER)) { + for (x = 0; x < match->domain_child_num; x++) { + if (match->domain_children[x] == uid) + goto found; + } + } else if (match->uidgid == uid && match->roletype & GR_ROLE_USER) + break; + match = match->next; + } +found: + if (match == NULL) { + try_group: + index = rhash(gid, GR_ROLE_GROUP, acl_role_set.r_size); + match = acl_role_set.r_hash[index]; + + while (match) { + if ((match->roletype & (GR_ROLE_DOMAIN | GR_ROLE_GROUP)) == (GR_ROLE_DOMAIN | GR_ROLE_GROUP)) { + for (x = 0; x < match->domain_child_num; x++) { + if (match->domain_children[x] == gid) + goto found2; + } + } else if (match->uidgid == gid && match->roletype & GR_ROLE_GROUP) + break; + match = match->next; + } +found2: + if (match == NULL) + match = default_role; + if (match->allowed_ips == NULL) + return match; + else { + for (ipp = match->allowed_ips; ipp; ipp = ipp->next) { + if (likely + ((ntohl(task->signal->curr_ip) & ipp->netmask) == + (ntohl(ipp->addr) & ipp->netmask))) + return match; + } + match = default_role; + } + } else if (match->allowed_ips == NULL) { + return match; + } else { + for (ipp = match->allowed_ips; ipp; ipp = ipp->next) { + if (likely + ((ntohl(task->signal->curr_ip) & ipp->netmask) == + (ntohl(ipp->addr) & ipp->netmask))) + return match; + } + goto try_group; + } + + return match; +} + +struct acl_subject_label * +lookup_acl_subj_label(const ino_t ino, const dev_t dev, + const struct acl_role_label *role) +{ + unsigned int index = fhash(ino, dev, role->subj_hash_size); + struct acl_subject_label *match; + + match = role->subj_hash[index]; + + while (match && (match->inode != ino || match->device != dev || + (match->mode & GR_DELETED))) { + match = match->next; + } + + if (match && !(match->mode & GR_DELETED)) + return match; + else + return NULL; +} + +static struct acl_object_label * +lookup_acl_obj_label(const ino_t ino, const dev_t dev, + const struct acl_subject_label *subj) +{ + unsigned int index = fhash(ino, dev, subj->obj_hash_size); + struct acl_object_label *match; + + match = subj->obj_hash[index]; + + while (match && (match->inode != ino || match->device != dev || + (match->mode & GR_DELETED))) { + match = match->next; + } + + if (match && !(match->mode & GR_DELETED)) + return match; + else + return NULL; +} + +static struct acl_object_label * +lookup_acl_obj_label_create(const ino_t ino, const dev_t dev, + const struct acl_subject_label *subj) +{ + unsigned int index = fhash(ino, dev, subj->obj_hash_size); + struct acl_object_label *match; + + match = subj->obj_hash[index]; + + while (match && (match->inode != ino || match->device != dev || + !(match->mode & GR_DELETED))) { + match = match->next; + } + + if (match && (match->mode & GR_DELETED)) + return match; + + match = subj->obj_hash[index]; + + while (match && (match->inode != ino || match->device != dev || + (match->mode & GR_DELETED))) { + match = match->next; + } + + if (match && !(match->mode & GR_DELETED)) + return match; + else + return NULL; +} + +static struct name_entry * +lookup_name_entry(const char *name) +{ + unsigned int len = strlen(name); + unsigned int key = full_name_hash(name, len); + unsigned int index = key % name_set.n_size; + struct name_entry *match; + + match = name_set.n_hash[index]; + + while (match && (match->key != key || !gr_streq(match->name, name, match->len, len))) + match = match->next; + + return match; +} + +static struct name_entry * +lookup_name_entry_create(const char *name) +{ + unsigned int len = strlen(name); + unsigned int key = full_name_hash(name, len); + unsigned int index = key % name_set.n_size; + struct name_entry *match; + + match = name_set.n_hash[index]; + + while (match && (match->key != key || !gr_streq(match->name, name, match->len, len) || + !match->deleted)) + match = match->next; + + if (match && match->deleted) + return match; + + match = name_set.n_hash[index]; + + while (match && (match->key != key || !gr_streq(match->name, name, match->len, len) || + match->deleted)) + match = match->next; + + if (match && !match->deleted) + return match; + else + return NULL; +} + +static struct inodev_entry * +lookup_inodev_entry(const ino_t ino, const dev_t dev) +{ + unsigned int index = fhash(ino, dev, inodev_set.i_size); + struct inodev_entry *match; + + match = inodev_set.i_hash[index]; + + while (match && (match->nentry->inode != ino || match->nentry->device != dev)) + match = match->next; + + return match; +} + +static void +insert_inodev_entry(struct inodev_entry *entry) +{ + unsigned int index = fhash(entry->nentry->inode, entry->nentry->device, + inodev_set.i_size); + struct inodev_entry **curr; + + entry->prev = NULL; + + curr = &inodev_set.i_hash[index]; + if (*curr != NULL) + (*curr)->prev = entry; + + entry->next = *curr; + *curr = entry; + + return; +} + +static void +__insert_acl_role_label(struct acl_role_label *role, uid_t uidgid) +{ + unsigned int index = + rhash(uidgid, role->roletype & (GR_ROLE_USER | GR_ROLE_GROUP), acl_role_set.r_size); + struct acl_role_label **curr; + + role->prev = NULL; + + curr = &acl_role_set.r_hash[index]; + if (*curr != NULL) + (*curr)->prev = role; + + role->next = *curr; + *curr = role; + + return; +} + +static void +insert_acl_role_label(struct acl_role_label *role) +{ + int i; + + if (role->roletype & GR_ROLE_DOMAIN) { + for (i = 0; i < role->domain_child_num; i++) + __insert_acl_role_label(role, role->domain_children[i]); + } else + __insert_acl_role_label(role, role->uidgid); +} + +static int +insert_name_entry(char *name, const ino_t inode, const dev_t device, __u8 deleted) +{ + struct name_entry **curr, *nentry; + struct inodev_entry *ientry; + unsigned int len = strlen(name); + unsigned int key = full_name_hash(name, len); + unsigned int index = key % name_set.n_size; + + curr = &name_set.n_hash[index]; + + while (*curr && ((*curr)->key != key || !gr_streq((*curr)->name, name, (*curr)->len, len))) + curr = &((*curr)->next); + + if (*curr != NULL) + return 1; + + nentry = acl_alloc(sizeof (struct name_entry)); + if (nentry == NULL) + return 0; + ientry = acl_alloc(sizeof (struct inodev_entry)); + if (ientry == NULL) + return 0; + ientry->nentry = nentry; + + nentry->key = key; + nentry->name = name; + nentry->inode = inode; + nentry->device = device; + nentry->len = len; + nentry->deleted = deleted; + + nentry->prev = NULL; + curr = &name_set.n_hash[index]; + if (*curr != NULL) + (*curr)->prev = nentry; + nentry->next = *curr; + *curr = nentry; + + /* insert us into the table searchable by inode/dev */ + insert_inodev_entry(ientry); + + return 1; +} + +static void +insert_acl_obj_label(struct acl_object_label *obj, + struct acl_subject_label *subj) +{ + unsigned int index = + fhash(obj->inode, obj->device, subj->obj_hash_size); + struct acl_object_label **curr; + + + obj->prev = NULL; + + curr = &subj->obj_hash[index]; + if (*curr != NULL) + (*curr)->prev = obj; + + obj->next = *curr; + *curr = obj; + + return; +} + +static void +insert_acl_subj_label(struct acl_subject_label *obj, + struct acl_role_label *role) +{ + unsigned int index = fhash(obj->inode, obj->device, role->subj_hash_size); + struct acl_subject_label **curr; + + obj->prev = NULL; + + curr = &role->subj_hash[index]; + if (*curr != NULL) + (*curr)->prev = obj; + + obj->next = *curr; + *curr = obj; + + return; +} + +/* allocating chained hash tables, so optimal size is where lambda ~ 1 */ + +static void * +create_table(__u32 * len, int elementsize) +{ + unsigned int table_sizes[] = { + 7, 13, 31, 61, 127, 251, 509, 1021, 2039, 4093, 8191, 16381, + 32749, 65521, 131071, 262139, 524287, 1048573, 2097143, + 4194301, 8388593, 16777213, 33554393, 67108859, 134217689, + 268435399, 536870909, 1073741789, 2147483647 + }; + void *newtable = NULL; + unsigned int pwr = 0; + + while ((pwr < ((sizeof (table_sizes) / sizeof (table_sizes[0])) - 1)) && + table_sizes[pwr] <= *len) + pwr++; + + if (table_sizes[pwr] <= *len) + return newtable; + + if ((table_sizes[pwr] * elementsize) <= PAGE_SIZE) + newtable = + kmalloc(table_sizes[pwr] * elementsize, GFP_KERNEL); + else + newtable = vmalloc(table_sizes[pwr] * elementsize); + + *len = table_sizes[pwr]; + + return newtable; +} + +static int +init_variables(const struct gr_arg *arg) +{ + struct task_struct *reaper = current->nsproxy->pid_ns->child_reaper; + unsigned int stacksize; + + subj_map_set.s_size = arg->role_db.num_subjects; + acl_role_set.r_size = arg->role_db.num_roles + arg->role_db.num_domain_children; + name_set.n_size = arg->role_db.num_objects; + inodev_set.i_size = arg->role_db.num_objects; + + if (!subj_map_set.s_size || !acl_role_set.r_size || + !name_set.n_size || !inodev_set.i_size) + return 1; + + if (!gr_init_uidset()) + return 1; + + /* set up the stack that holds allocation info */ + + stacksize = arg->role_db.num_pointers + 5; + + if (!acl_alloc_stack_init(stacksize)) + return 1; + + /* grab reference for the real root dentry and vfsmount */ + read_lock(&reaper->fs->lock); + real_root_mnt = mntget(reaper->fs->root.mnt); + real_root = dget(reaper->fs->root.dentry); + read_unlock(&reaper->fs->lock); + + fakefs_obj = acl_alloc(sizeof(struct acl_object_label)); + if (fakefs_obj == NULL) + return 1; + fakefs_obj->mode = GR_FIND | GR_READ | GR_WRITE | GR_EXEC; + + subj_map_set.s_hash = + (struct subject_map **) create_table(&subj_map_set.s_size, sizeof(void *)); + acl_role_set.r_hash = + (struct acl_role_label **) create_table(&acl_role_set.r_size, sizeof(void *)); + name_set.n_hash = (struct name_entry **) create_table(&name_set.n_size, sizeof(void *)); + inodev_set.i_hash = + (struct inodev_entry **) create_table(&inodev_set.i_size, sizeof(void *)); + + if (!subj_map_set.s_hash || !acl_role_set.r_hash || + !name_set.n_hash || !inodev_set.i_hash) + return 1; + + memset(subj_map_set.s_hash, 0, + sizeof(struct subject_map *) * subj_map_set.s_size); + memset(acl_role_set.r_hash, 0, + sizeof (struct acl_role_label *) * acl_role_set.r_size); + memset(name_set.n_hash, 0, + sizeof (struct name_entry *) * name_set.n_size); + memset(inodev_set.i_hash, 0, + sizeof (struct inodev_entry *) * inodev_set.i_size); + + return 0; +} + +/* free information not needed after startup + currently contains user->kernel pointer mappings for subjects +*/ + +static void +free_init_variables(void) +{ + __u32 i; + + if (subj_map_set.s_hash) { + for (i = 0; i < subj_map_set.s_size; i++) { + if (subj_map_set.s_hash[i]) { + kfree(subj_map_set.s_hash[i]); + subj_map_set.s_hash[i] = NULL; + } + } + + if ((subj_map_set.s_size * sizeof (struct subject_map *)) <= + PAGE_SIZE) + kfree(subj_map_set.s_hash); + else + vfree(subj_map_set.s_hash); + } + + return; +} + +static void +free_variables(void) +{ + struct acl_subject_label *s; + struct acl_role_label *r; + struct task_struct *task, *task2; + unsigned int i, x; + + gr_clear_learn_entries(); + + read_lock(&tasklist_lock); + do_each_thread(task2, task) { + task->acl_sp_role = 0; + task->acl_role_id = 0; + task->acl = NULL; + task->role = NULL; + } while_each_thread(task2, task); + read_unlock(&tasklist_lock); + + /* release the reference to the real root dentry and vfsmount */ + if (real_root) + dput(real_root); + real_root = NULL; + if (real_root_mnt) + mntput(real_root_mnt); + real_root_mnt = NULL; + + /* free all object hash tables */ + + FOR_EACH_ROLE_START(r, i) + if (r->subj_hash == NULL) + break; + FOR_EACH_SUBJECT_START(r, s, x) + if (s->obj_hash == NULL) + break; + if ((s->obj_hash_size * sizeof (struct acl_object_label *)) <= PAGE_SIZE) + kfree(s->obj_hash); + else + vfree(s->obj_hash); + FOR_EACH_SUBJECT_END(s, x) + FOR_EACH_NESTED_SUBJECT_START(r, s) + if (s->obj_hash == NULL) + break; + if ((s->obj_hash_size * sizeof (struct acl_object_label *)) <= PAGE_SIZE) + kfree(s->obj_hash); + else + vfree(s->obj_hash); + FOR_EACH_NESTED_SUBJECT_END(s) + if ((r->subj_hash_size * sizeof (struct acl_subject_label *)) <= PAGE_SIZE) + kfree(r->subj_hash); + else + vfree(r->subj_hash); + r->subj_hash = NULL; + FOR_EACH_ROLE_END(r,i) + + acl_free_all(); + + if (acl_role_set.r_hash) { + if ((acl_role_set.r_size * sizeof (struct acl_role_label *)) <= + PAGE_SIZE) + kfree(acl_role_set.r_hash); + else + vfree(acl_role_set.r_hash); + } + if (name_set.n_hash) { + if ((name_set.n_size * sizeof (struct name_entry *)) <= + PAGE_SIZE) + kfree(name_set.n_hash); + else + vfree(name_set.n_hash); + } + + if (inodev_set.i_hash) { + if ((inodev_set.i_size * sizeof (struct inodev_entry *)) <= + PAGE_SIZE) + kfree(inodev_set.i_hash); + else + vfree(inodev_set.i_hash); + } + + gr_free_uidset(); + + memset(&name_set, 0, sizeof (struct name_db)); + memset(&inodev_set, 0, sizeof (struct inodev_db)); + memset(&acl_role_set, 0, sizeof (struct acl_role_db)); + memset(&subj_map_set, 0, sizeof (struct acl_subj_map_db)); + + default_role = NULL; + + return; +} + +static __u32 +count_user_objs(struct acl_object_label *userp) +{ + struct acl_object_label o_tmp; + __u32 num = 0; + + while (userp) { + if (copy_from_user(&o_tmp, userp, + sizeof (struct acl_object_label))) + break; + + userp = o_tmp.prev; + num++; + } + + return num; +} + +static struct acl_subject_label * +do_copy_user_subj(struct acl_subject_label *userp, struct acl_role_label *role); + +static int +copy_user_glob(struct acl_object_label *obj) +{ + struct acl_object_label *g_tmp, **guser; + unsigned int len; + char *tmp; + + if (obj->globbed == NULL) + return 0; + + guser = &obj->globbed; + while (*guser) { + g_tmp = (struct acl_object_label *) + acl_alloc(sizeof (struct acl_object_label)); + if (g_tmp == NULL) + return -ENOMEM; + + if (copy_from_user(g_tmp, *guser, + sizeof (struct acl_object_label))) + return -EFAULT; + + len = strnlen_user(g_tmp->filename, PATH_MAX); + + if (!len || len >= PATH_MAX) + return -EINVAL; + + if ((tmp = (char *) acl_alloc(len)) == NULL) + return -ENOMEM; + + if (copy_from_user(tmp, g_tmp->filename, len)) + return -EFAULT; + + g_tmp->filename = tmp; + + *guser = g_tmp; + guser = &(g_tmp->next); + } + + return 0; +} + +static int +copy_user_objs(struct acl_object_label *userp, struct acl_subject_label *subj, + struct acl_role_label *role) +{ + struct acl_object_label *o_tmp; + unsigned int len; + int ret; + char *tmp; + + while (userp) { + if ((o_tmp = (struct acl_object_label *) + acl_alloc(sizeof (struct acl_object_label))) == NULL) + return -ENOMEM; + + if (copy_from_user(o_tmp, userp, + sizeof (struct acl_object_label))) + return -EFAULT; + + userp = o_tmp->prev; + + len = strnlen_user(o_tmp->filename, PATH_MAX); + + if (!len || len >= PATH_MAX) + return -EINVAL; + + if ((tmp = (char *) acl_alloc(len)) == NULL) + return -ENOMEM; + + if (copy_from_user(tmp, o_tmp->filename, len)) + return -EFAULT; + + o_tmp->filename = tmp; + + insert_acl_obj_label(o_tmp, subj); + if (!insert_name_entry(o_tmp->filename, o_tmp->inode, + o_tmp->device, (o_tmp->mode & GR_DELETED) ? 1 : 0)) + return -ENOMEM; + + ret = copy_user_glob(o_tmp); + if (ret) + return ret; + + if (o_tmp->nested) { + o_tmp->nested = do_copy_user_subj(o_tmp->nested, role); + if (IS_ERR(o_tmp->nested)) + return PTR_ERR(o_tmp->nested); + + /* insert into nested subject list */ + o_tmp->nested->next = role->hash->first; + role->hash->first = o_tmp->nested; + } + } + + return 0; +} + +static __u32 +count_user_subjs(struct acl_subject_label *userp) +{ + struct acl_subject_label s_tmp; + __u32 num = 0; + + while (userp) { + if (copy_from_user(&s_tmp, userp, + sizeof (struct acl_subject_label))) + break; + + userp = s_tmp.prev; + /* do not count nested subjects against this count, since + they are not included in the hash table, but are + attached to objects. We have already counted + the subjects in userspace for the allocation + stack + */ + if (!(s_tmp.mode & GR_NESTED)) + num++; + } + + return num; +} + +static int +copy_user_allowedips(struct acl_role_label *rolep) +{ + struct role_allowed_ip *ruserip, *rtmp = NULL, *rlast; + + ruserip = rolep->allowed_ips; + + while (ruserip) { + rlast = rtmp; + + if ((rtmp = (struct role_allowed_ip *) + acl_alloc(sizeof (struct role_allowed_ip))) == NULL) + return -ENOMEM; + + if (copy_from_user(rtmp, ruserip, + sizeof (struct role_allowed_ip))) + return -EFAULT; + + ruserip = rtmp->prev; + + if (!rlast) { + rtmp->prev = NULL; + rolep->allowed_ips = rtmp; + } else { + rlast->next = rtmp; + rtmp->prev = rlast; + } + + if (!ruserip) + rtmp->next = NULL; + } + + return 0; +} + +static int +copy_user_transitions(struct acl_role_label *rolep) +{ + struct role_transition *rusertp, *rtmp = NULL, *rlast; + + unsigned int len; + char *tmp; + + rusertp = rolep->transitions; + + while (rusertp) { + rlast = rtmp; + + if ((rtmp = (struct role_transition *) + acl_alloc(sizeof (struct role_transition))) == NULL) + return -ENOMEM; + + if (copy_from_user(rtmp, rusertp, + sizeof (struct role_transition))) + return -EFAULT; + + rusertp = rtmp->prev; + + len = strnlen_user(rtmp->rolename, GR_SPROLE_LEN); + + if (!len || len >= GR_SPROLE_LEN) + return -EINVAL; + + if ((tmp = (char *) acl_alloc(len)) == NULL) + return -ENOMEM; + + if (copy_from_user(tmp, rtmp->rolename, len)) + return -EFAULT; + + rtmp->rolename = tmp; + + if (!rlast) { + rtmp->prev = NULL; + rolep->transitions = rtmp; + } else { + rlast->next = rtmp; + rtmp->prev = rlast; + } + + if (!rusertp) + rtmp->next = NULL; + } + + return 0; +} + +static struct acl_subject_label * +do_copy_user_subj(struct acl_subject_label *userp, struct acl_role_label *role) +{ + struct acl_subject_label *s_tmp = NULL, *s_tmp2; + unsigned int len; + char *tmp; + __u32 num_objs; + struct acl_ip_label **i_tmp, *i_utmp2; + struct gr_hash_struct ghash; + struct subject_map *subjmap; + unsigned int i_num; + int err; + + s_tmp = lookup_subject_map(userp); + + /* we've already copied this subject into the kernel, just return + the reference to it, and don't copy it over again + */ + if (s_tmp) + return(s_tmp); + + if ((s_tmp = (struct acl_subject_label *) + acl_alloc(sizeof (struct acl_subject_label))) == NULL) + return ERR_PTR(-ENOMEM); + + subjmap = (struct subject_map *)kmalloc(sizeof (struct subject_map), GFP_KERNEL); + if (subjmap == NULL) + return ERR_PTR(-ENOMEM); + + subjmap->user = userp; + subjmap->kernel = s_tmp; + insert_subj_map_entry(subjmap); + + if (copy_from_user(s_tmp, userp, + sizeof (struct acl_subject_label))) + return ERR_PTR(-EFAULT); + + len = strnlen_user(s_tmp->filename, PATH_MAX); + + if (!len || len >= PATH_MAX) + return ERR_PTR(-EINVAL); + + if ((tmp = (char *) acl_alloc(len)) == NULL) + return ERR_PTR(-ENOMEM); + + if (copy_from_user(tmp, s_tmp->filename, len)) + return ERR_PTR(-EFAULT); + + s_tmp->filename = tmp; + + if (!strcmp(s_tmp->filename, "/")) + role->root_label = s_tmp; + + if (copy_from_user(&ghash, s_tmp->hash, sizeof(struct gr_hash_struct))) + return ERR_PTR(-EFAULT); + + /* copy user and group transition tables */ + + if (s_tmp->user_trans_num) { + uid_t *uidlist; + + uidlist = (uid_t *)acl_alloc(s_tmp->user_trans_num * sizeof(uid_t)); + if (uidlist == NULL) + return ERR_PTR(-ENOMEM); + if (copy_from_user(uidlist, s_tmp->user_transitions, s_tmp->user_trans_num * sizeof(uid_t))) + return ERR_PTR(-EFAULT); + + s_tmp->user_transitions = uidlist; + } + + if (s_tmp->group_trans_num) { + gid_t *gidlist; + + gidlist = (gid_t *)acl_alloc(s_tmp->group_trans_num * sizeof(gid_t)); + if (gidlist == NULL) + return ERR_PTR(-ENOMEM); + if (copy_from_user(gidlist, s_tmp->group_transitions, s_tmp->group_trans_num * sizeof(gid_t))) + return ERR_PTR(-EFAULT); + + s_tmp->group_transitions = gidlist; + } + + /* set up object hash table */ + num_objs = count_user_objs(ghash.first); + + s_tmp->obj_hash_size = num_objs; + s_tmp->obj_hash = + (struct acl_object_label **) + create_table(&(s_tmp->obj_hash_size), sizeof(void *)); + + if (!s_tmp->obj_hash) + return ERR_PTR(-ENOMEM); + + memset(s_tmp->obj_hash, 0, + s_tmp->obj_hash_size * + sizeof (struct acl_object_label *)); + + /* add in objects */ + err = copy_user_objs(ghash.first, s_tmp, role); + + if (err) + return ERR_PTR(err); + + /* set pointer for parent subject */ + if (s_tmp->parent_subject) { + s_tmp2 = do_copy_user_subj(s_tmp->parent_subject, role); + + if (IS_ERR(s_tmp2)) + return s_tmp2; + + s_tmp->parent_subject = s_tmp2; + } + + /* add in ip acls */ + + if (!s_tmp->ip_num) { + s_tmp->ips = NULL; + goto insert; + } + + i_tmp = + (struct acl_ip_label **) acl_alloc(s_tmp->ip_num * + sizeof (struct + acl_ip_label *)); + + if (!i_tmp) + return ERR_PTR(-ENOMEM); + + for (i_num = 0; i_num < s_tmp->ip_num; i_num++) { + *(i_tmp + i_num) = + (struct acl_ip_label *) + acl_alloc(sizeof (struct acl_ip_label)); + if (!*(i_tmp + i_num)) + return ERR_PTR(-ENOMEM); + + if (copy_from_user + (&i_utmp2, s_tmp->ips + i_num, + sizeof (struct acl_ip_label *))) + return ERR_PTR(-EFAULT); + + if (copy_from_user + (*(i_tmp + i_num), i_utmp2, + sizeof (struct acl_ip_label))) + return ERR_PTR(-EFAULT); + + if ((*(i_tmp + i_num))->iface == NULL) + continue; + + len = strnlen_user((*(i_tmp + i_num))->iface, IFNAMSIZ); + if (!len || len >= IFNAMSIZ) + return ERR_PTR(-EINVAL); + tmp = acl_alloc(len); + if (tmp == NULL) + return ERR_PTR(-ENOMEM); + if (copy_from_user(tmp, (*(i_tmp + i_num))->iface, len)) + return ERR_PTR(-EFAULT); + (*(i_tmp + i_num))->iface = tmp; + } + + s_tmp->ips = i_tmp; + +insert: + if (!insert_name_entry(s_tmp->filename, s_tmp->inode, + s_tmp->device, (s_tmp->mode & GR_DELETED) ? 1 : 0)) + return ERR_PTR(-ENOMEM); + + return s_tmp; +} + +static int +copy_user_subjs(struct acl_subject_label *userp, struct acl_role_label *role) +{ + struct acl_subject_label s_pre; + struct acl_subject_label * ret; + int err; + + while (userp) { + if (copy_from_user(&s_pre, userp, + sizeof (struct acl_subject_label))) + return -EFAULT; + + /* do not add nested subjects here, add + while parsing objects + */ + + if (s_pre.mode & GR_NESTED) { + userp = s_pre.prev; + continue; + } + + ret = do_copy_user_subj(userp, role); + + err = PTR_ERR(ret); + if (IS_ERR(ret)) + return err; + + insert_acl_subj_label(ret, role); + + userp = s_pre.prev; + } + + return 0; +} + +static int +copy_user_acl(struct gr_arg *arg) +{ + struct acl_role_label *r_tmp = NULL, **r_utmp, *r_utmp2; + struct sprole_pw *sptmp; + struct gr_hash_struct *ghash; + uid_t *domainlist; + unsigned int r_num; + unsigned int len; + char *tmp; + int err = 0; + __u16 i; + __u32 num_subjs; + + /* we need a default and kernel role */ + if (arg->role_db.num_roles < 2) + return -EINVAL; + + /* copy special role authentication info from userspace */ + + num_sprole_pws = arg->num_sprole_pws; + acl_special_roles = (struct sprole_pw **) acl_alloc(num_sprole_pws * sizeof(struct sprole_pw *)); + + if (!acl_special_roles) { + err = -ENOMEM; + goto cleanup; + } + + for (i = 0; i < num_sprole_pws; i++) { + sptmp = (struct sprole_pw *) acl_alloc(sizeof(struct sprole_pw)); + if (!sptmp) { + err = -ENOMEM; + goto cleanup; + } + if (copy_from_user(sptmp, arg->sprole_pws + i, + sizeof (struct sprole_pw))) { + err = -EFAULT; + goto cleanup; + } + + len = + strnlen_user(sptmp->rolename, GR_SPROLE_LEN); + + if (!len || len >= GR_SPROLE_LEN) { + err = -EINVAL; + goto cleanup; + } + + if ((tmp = (char *) acl_alloc(len)) == NULL) { + err = -ENOMEM; + goto cleanup; + } + + if (copy_from_user(tmp, sptmp->rolename, len)) { + err = -EFAULT; + goto cleanup; + } + +#ifdef CONFIG_GRKERNSEC_ACL_DEBUG + printk(KERN_ALERT "Copying special role %s\n", tmp); +#endif + sptmp->rolename = tmp; + acl_special_roles[i] = sptmp; + } + + r_utmp = (struct acl_role_label **) arg->role_db.r_table; + + for (r_num = 0; r_num < arg->role_db.num_roles; r_num++) { + r_tmp = acl_alloc(sizeof (struct acl_role_label)); + + if (!r_tmp) { + err = -ENOMEM; + goto cleanup; + } + + if (copy_from_user(&r_utmp2, r_utmp + r_num, + sizeof (struct acl_role_label *))) { + err = -EFAULT; + goto cleanup; + } + + if (copy_from_user(r_tmp, r_utmp2, + sizeof (struct acl_role_label))) { + err = -EFAULT; + goto cleanup; + } + + len = strnlen_user(r_tmp->rolename, GR_SPROLE_LEN); + + if (!len || len >= PATH_MAX) { + err = -EINVAL; + goto cleanup; + } + + if ((tmp = (char *) acl_alloc(len)) == NULL) { + err = -ENOMEM; + goto cleanup; + } + if (copy_from_user(tmp, r_tmp->rolename, len)) { + err = -EFAULT; + goto cleanup; + } + r_tmp->rolename = tmp; + + if (!strcmp(r_tmp->rolename, "default") + && (r_tmp->roletype & GR_ROLE_DEFAULT)) { + default_role = r_tmp; + } else if (!strcmp(r_tmp->rolename, ":::kernel:::")) { + kernel_role = r_tmp; + } + + if ((ghash = (struct gr_hash_struct *) acl_alloc(sizeof(struct gr_hash_struct))) == NULL) { + err = -ENOMEM; + goto cleanup; + } + if (copy_from_user(ghash, r_tmp->hash, sizeof(struct gr_hash_struct))) { + err = -EFAULT; + goto cleanup; + } + + r_tmp->hash = ghash; + + num_subjs = count_user_subjs(r_tmp->hash->first); + + r_tmp->subj_hash_size = num_subjs; + r_tmp->subj_hash = + (struct acl_subject_label **) + create_table(&(r_tmp->subj_hash_size), sizeof(void *)); + + if (!r_tmp->subj_hash) { + err = -ENOMEM; + goto cleanup; + } + + err = copy_user_allowedips(r_tmp); + if (err) + goto cleanup; + + /* copy domain info */ + if (r_tmp->domain_children != NULL) { + domainlist = acl_alloc(r_tmp->domain_child_num * sizeof(uid_t)); + if (domainlist == NULL) { + err = -ENOMEM; + goto cleanup; + } + if (copy_from_user(domainlist, r_tmp->domain_children, r_tmp->domain_child_num * sizeof(uid_t))) { + err = -EFAULT; + goto cleanup; + } + r_tmp->domain_children = domainlist; + } + + err = copy_user_transitions(r_tmp); + if (err) + goto cleanup; + + memset(r_tmp->subj_hash, 0, + r_tmp->subj_hash_size * + sizeof (struct acl_subject_label *)); + + err = copy_user_subjs(r_tmp->hash->first, r_tmp); + + if (err) + goto cleanup; + + /* set nested subject list to null */ + r_tmp->hash->first = NULL; + + insert_acl_role_label(r_tmp); + } + + goto return_err; + cleanup: + free_variables(); + return_err: + return err; + +} + +static int +gracl_init(struct gr_arg *args) +{ + int error = 0; + + memcpy(gr_system_salt, args->salt, GR_SALT_LEN); + memcpy(gr_system_sum, args->sum, GR_SHA_LEN); + + if (init_variables(args)) { + gr_log_str(GR_DONT_AUDIT_GOOD, GR_INITF_ACL_MSG, GR_VERSION); + error = -ENOMEM; + free_variables(); + goto out; + } + + error = copy_user_acl(args); + free_init_variables(); + if (error) { + free_variables(); + goto out; + } + + if ((error = gr_set_acls(0))) { + free_variables(); + goto out; + } + + gr_status |= GR_READY; + out: + return error; +} + +/* derived from glibc fnmatch() 0: match, 1: no match*/ + +static int +glob_match(const char *p, const char *n) +{ + char c; + + while ((c = *p++) != '\0') { + switch (c) { + case '?': + if (*n == '\0') + return 1; + else if (*n == '/') + return 1; + break; + case '\\': + if (*n != c) + return 1; + break; + case '*': + for (c = *p++; c == '?' || c == '*'; c = *p++) { + if (*n == '/') + return 1; + else if (c == '?') { + if (*n == '\0') + return 1; + else + ++n; + } + } + if (c == '\0') { + return 0; + } else { + const char *endp; + + if ((endp = strchr(n, '/')) == NULL) + endp = n + strlen(n); + + if (c == '[') { + for (--p; n < endp; ++n) + if (!glob_match(p, n)) + return 0; + } else if (c == '/') { + while (*n != '\0' && *n != '/') + ++n; + if (*n == '/' && !glob_match(p, n + 1)) + return 0; + } else { + for (--p; n < endp; ++n) + if (*n == c && !glob_match(p, n)) + return 0; + } + + return 1; + } + case '[': + { + int not; + char cold; + + if (*n == '\0' || *n == '/') + return 1; + + not = (*p == '!' || *p == '^'); + if (not) + ++p; + + c = *p++; + for (;;) { + unsigned char fn = (unsigned char)*n; + + if (c == '\0') + return 1; + else { + if (c == fn) + goto matched; + cold = c; + c = *p++; + + if (c == '-' && *p != ']') { + unsigned char cend = *p++; + + if (cend == '\0') + return 1; + + if (cold <= fn && fn <= cend) + goto matched; + + c = *p++; + } + } + + if (c == ']') + break; + } + if (!not) + return 1; + break; + matched: + while (c != ']') { + if (c == '\0') + return 1; + + c = *p++; + } + if (not) + return 1; + } + break; + default: + if (c != *n) + return 1; + } + + ++n; + } + + if (*n == '\0') + return 0; + + if (*n == '/') + return 0; + + return 1; +} + +static struct acl_object_label * +chk_glob_label(struct acl_object_label *globbed, + struct dentry *dentry, struct vfsmount *mnt, char **path) +{ + struct acl_object_label *tmp; + + if (*path == NULL) + *path = gr_to_filename_nolock(dentry, mnt); + + tmp = globbed; + + while (tmp) { + if (!glob_match(tmp->filename, *path)) + return tmp; + tmp = tmp->next; + } + + return NULL; +} + +static struct acl_object_label * +__full_lookup(const struct dentry *orig_dentry, const struct vfsmount *orig_mnt, + const ino_t curr_ino, const dev_t curr_dev, + const struct acl_subject_label *subj, char **path) +{ + struct acl_subject_label *tmpsubj; + struct acl_object_label *retval; + struct acl_object_label *retval2; + + tmpsubj = (struct acl_subject_label *) subj; + read_lock(&gr_inode_lock); + do { + retval = lookup_acl_obj_label(curr_ino, curr_dev, tmpsubj); + if (retval) { + if (retval->globbed) { + retval2 = chk_glob_label(retval->globbed, (struct dentry *)orig_dentry, + (struct vfsmount *)orig_mnt, path); + if (retval2) + retval = retval2; + } + break; + } + } while ((tmpsubj = tmpsubj->parent_subject)); + read_unlock(&gr_inode_lock); + + return retval; +} + +static __inline__ struct acl_object_label * +full_lookup(const struct dentry *orig_dentry, const struct vfsmount *orig_mnt, + const struct dentry *curr_dentry, + const struct acl_subject_label *subj, char **path) +{ + return __full_lookup(orig_dentry, orig_mnt, + curr_dentry->d_inode->i_ino, + curr_dentry->d_inode->i_sb->s_dev, subj, path); +} + +static struct acl_object_label * +__chk_obj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt, + const struct acl_subject_label *subj, char *path) +{ + struct dentry *dentry = (struct dentry *) l_dentry; + struct vfsmount *mnt = (struct vfsmount *) l_mnt; + struct acl_object_label *retval; + + spin_lock(&dcache_lock); + + if (unlikely(mnt == shm_mnt || mnt == pipe_mnt || mnt == sock_mnt || + /* ignore Eric Biederman */ + IS_PRIVATE(l_dentry->d_inode))) { + retval = fakefs_obj; + goto out; + } + + for (;;) { + if (dentry == real_root && mnt == real_root_mnt) + break; + + if (dentry == mnt->mnt_root || IS_ROOT(dentry)) { + if (mnt->mnt_parent == mnt) + break; + + retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path); + if (retval != NULL) + goto out; + + dentry = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + continue; + } + + retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path); + if (retval != NULL) + goto out; + + dentry = dentry->d_parent; + } + + retval = full_lookup(l_dentry, l_mnt, dentry, subj, &path); + + if (retval == NULL) + retval = full_lookup(l_dentry, l_mnt, real_root, subj, &path); +out: + spin_unlock(&dcache_lock); + return retval; +} + +static __inline__ struct acl_object_label * +chk_obj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt, + const struct acl_subject_label *subj) +{ + char *path = NULL; + return __chk_obj_label(l_dentry, l_mnt, subj, path); +} + +static __inline__ struct acl_object_label * +chk_obj_create_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt, + const struct acl_subject_label *subj, char *path) +{ + return __chk_obj_label(l_dentry, l_mnt, subj, path); +} + +static struct acl_subject_label * +chk_subj_label(const struct dentry *l_dentry, const struct vfsmount *l_mnt, + const struct acl_role_label *role) +{ + struct dentry *dentry = (struct dentry *) l_dentry; + struct vfsmount *mnt = (struct vfsmount *) l_mnt; + struct acl_subject_label *retval; + + spin_lock(&dcache_lock); + + for (;;) { + if (dentry == real_root && mnt == real_root_mnt) + break; + if (dentry == mnt->mnt_root || IS_ROOT(dentry)) { + if (mnt->mnt_parent == mnt) + break; + + read_lock(&gr_inode_lock); + retval = + lookup_acl_subj_label(dentry->d_inode->i_ino, + dentry->d_inode->i_sb->s_dev, role); + read_unlock(&gr_inode_lock); + if (retval != NULL) + goto out; + + dentry = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + continue; + } + + read_lock(&gr_inode_lock); + retval = lookup_acl_subj_label(dentry->d_inode->i_ino, + dentry->d_inode->i_sb->s_dev, role); + read_unlock(&gr_inode_lock); + if (retval != NULL) + goto out; + + dentry = dentry->d_parent; + } + + read_lock(&gr_inode_lock); + retval = lookup_acl_subj_label(dentry->d_inode->i_ino, + dentry->d_inode->i_sb->s_dev, role); + read_unlock(&gr_inode_lock); + + if (unlikely(retval == NULL)) { + read_lock(&gr_inode_lock); + retval = lookup_acl_subj_label(real_root->d_inode->i_ino, + real_root->d_inode->i_sb->s_dev, role); + read_unlock(&gr_inode_lock); + } +out: + spin_unlock(&dcache_lock); + + return retval; +} + +static void +gr_log_learn(const struct task_struct *task, const struct dentry *dentry, const struct vfsmount *mnt, const __u32 mode) +{ + security_learn(GR_LEARN_AUDIT_MSG, task->role->rolename, task->role->roletype, + task->uid, task->gid, task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry, + task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename, + 1, 1, gr_to_filename(dentry, mnt), (unsigned long) mode, NIPQUAD(task->signal->curr_ip)); + + return; +} + +static void +gr_log_learn_sysctl(const struct task_struct *task, const char *path, const __u32 mode) +{ + security_learn(GR_LEARN_AUDIT_MSG, task->role->rolename, task->role->roletype, + task->uid, task->gid, task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry, + task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename, + 1, 1, path, (unsigned long) mode, NIPQUAD(task->signal->curr_ip)); + + return; +} + +static void +gr_log_learn_id_change(const struct task_struct *task, const char type, const unsigned int real, + const unsigned int effective, const unsigned int fs) +{ + security_learn(GR_ID_LEARN_MSG, task->role->rolename, task->role->roletype, + task->uid, task->gid, task->exec_file ? gr_to_filename1(task->exec_file->f_path.dentry, + task->exec_file->f_path.mnt) : task->acl->filename, task->acl->filename, + type, real, effective, fs, NIPQUAD(task->signal->curr_ip)); + + return; +} + +__u32 +gr_check_link(const struct dentry * new_dentry, + const struct dentry * parent_dentry, + const struct vfsmount * parent_mnt, + const struct dentry * old_dentry, const struct vfsmount * old_mnt) +{ + struct acl_object_label *obj; + __u32 oldmode, newmode; + __u32 needmode; + + if (unlikely(!(gr_status & GR_READY))) + return (GR_CREATE | GR_LINK); + + obj = chk_obj_label(old_dentry, old_mnt, current->acl); + oldmode = obj->mode; + + if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN)) + oldmode |= (GR_CREATE | GR_LINK); + + needmode = GR_CREATE | GR_AUDIT_CREATE | GR_SUPPRESS; + if (old_dentry->d_inode->i_mode & (S_ISUID | S_ISGID)) + needmode |= GR_SETID | GR_AUDIT_SETID; + + newmode = + gr_check_create(new_dentry, parent_dentry, parent_mnt, + oldmode | needmode); + + needmode = newmode & (GR_FIND | GR_APPEND | GR_WRITE | GR_EXEC | + GR_SETID | GR_READ | GR_FIND | GR_DELETE | + GR_INHERIT | GR_AUDIT_INHERIT); + + if (old_dentry->d_inode->i_mode & (S_ISUID | S_ISGID) && !(newmode & GR_SETID)) + goto bad; + + if ((oldmode & needmode) != needmode) + goto bad; + + needmode = oldmode & (GR_NOPTRACE | GR_PTRACERD | GR_INHERIT | GR_AUDITS); + if ((newmode & needmode) != needmode) + goto bad; + + if ((newmode & (GR_CREATE | GR_LINK)) == (GR_CREATE | GR_LINK)) + return newmode; +bad: + needmode = oldmode; + if (old_dentry->d_inode->i_mode & (S_ISUID | S_ISGID)) + needmode |= GR_SETID; + + if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN)) { + gr_log_learn(current, old_dentry, old_mnt, needmode); + return (GR_CREATE | GR_LINK); + } else if (newmode & GR_SUPPRESS) + return GR_SUPPRESS; + else + return 0; +} + +__u32 +gr_search_file(const struct dentry * dentry, const __u32 mode, + const struct vfsmount * mnt) +{ + __u32 retval = mode; + struct acl_subject_label *curracl; + struct acl_object_label *currobj; + + if (unlikely(!(gr_status & GR_READY))) + return (mode & ~GR_AUDITS); + + curracl = current->acl; + + currobj = chk_obj_label(dentry, mnt, curracl); + retval = currobj->mode & mode; + + if (unlikely + ((curracl->mode & (GR_LEARN | GR_INHERITLEARN)) && !(mode & GR_NOPTRACE) + && (retval != (mode & ~(GR_AUDITS | GR_SUPPRESS))))) { + __u32 new_mode = mode; + + new_mode &= ~(GR_AUDITS | GR_SUPPRESS); + + retval = new_mode; + + if (new_mode & GR_EXEC && curracl->mode & GR_INHERITLEARN) + new_mode |= GR_INHERIT; + + if (!(mode & GR_NOLEARN)) + gr_log_learn(current, dentry, mnt, new_mode); + } + + return retval; +} + +__u32 +gr_check_create(const struct dentry * new_dentry, const struct dentry * parent, + const struct vfsmount * mnt, const __u32 mode) +{ + struct name_entry *match; + struct acl_object_label *matchpo; + struct acl_subject_label *curracl; + char *path; + __u32 retval; + + if (unlikely(!(gr_status & GR_READY))) + return (mode & ~GR_AUDITS); + + preempt_disable(); + path = gr_to_filename_rbac(new_dentry, mnt); + match = lookup_name_entry_create(path); + + if (!match) + goto check_parent; + + curracl = current->acl; + + read_lock(&gr_inode_lock); + matchpo = lookup_acl_obj_label_create(match->inode, match->device, curracl); + read_unlock(&gr_inode_lock); + + if (matchpo) { + if ((matchpo->mode & mode) != + (mode & ~(GR_AUDITS | GR_SUPPRESS)) + && curracl->mode & (GR_LEARN | GR_INHERITLEARN)) { + __u32 new_mode = mode; + + new_mode &= ~(GR_AUDITS | GR_SUPPRESS); + + gr_log_learn(current, new_dentry, mnt, new_mode); + + preempt_enable(); + return new_mode; + } + preempt_enable(); + return (matchpo->mode & mode); + } + + check_parent: + curracl = current->acl; + + matchpo = chk_obj_create_label(parent, mnt, curracl, path); + retval = matchpo->mode & mode; + + if ((retval != (mode & ~(GR_AUDITS | GR_SUPPRESS))) + && (curracl->mode & (GR_LEARN | GR_INHERITLEARN))) { + __u32 new_mode = mode; + + new_mode &= ~(GR_AUDITS | GR_SUPPRESS); + + gr_log_learn(current, new_dentry, mnt, new_mode); + preempt_enable(); + return new_mode; + } + + preempt_enable(); + return retval; +} + +int +gr_check_hidden_task(const struct task_struct *task) +{ + if (unlikely(!(gr_status & GR_READY))) + return 0; + + if (!(task->acl->mode & GR_PROCFIND) && !(current->acl->mode & GR_VIEW)) + return 1; + + return 0; +} + +int +gr_check_protected_task(const struct task_struct *task) +{ + if (unlikely(!(gr_status & GR_READY) || !task)) + return 0; + + if ((task->acl->mode & GR_PROTECTED) && !(current->acl->mode & GR_KILL) && + task->acl != current->acl) + return 1; + + return 0; +} + +void +gr_copy_label(struct task_struct *tsk) +{ + tsk->signal->used_accept = 0; + tsk->acl_sp_role = 0; + tsk->acl_role_id = current->acl_role_id; + tsk->acl = current->acl; + tsk->role = current->role; + tsk->signal->curr_ip = current->signal->curr_ip; + if (current->exec_file) + get_file(current->exec_file); + tsk->exec_file = current->exec_file; + tsk->is_writable = current->is_writable; + if (unlikely(current->signal->used_accept)) + current->signal->curr_ip = 0; + + return; +} + +static void +gr_set_proc_res(struct task_struct *task) +{ + struct acl_subject_label *proc; + unsigned short i; + + proc = task->acl; + + if (proc->mode & (GR_LEARN | GR_INHERITLEARN)) + return; + + for (i = 0; i < (GR_NLIMITS - 1); i++) { + if (!(proc->resmask & (1 << i))) + continue; + + task->signal->rlim[i].rlim_cur = proc->res[i].rlim_cur; + task->signal->rlim[i].rlim_max = proc->res[i].rlim_max; + } + + return; +} + +int +gr_check_user_change(int real, int effective, int fs) +{ + unsigned int i; + __u16 num; + uid_t *uidlist; + int curuid; + int realok = 0; + int effectiveok = 0; + int fsok = 0; + + if (unlikely(!(gr_status & GR_READY))) + return 0; + + if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN)) + gr_log_learn_id_change(current, 'u', real, effective, fs); + + num = current->acl->user_trans_num; + uidlist = current->acl->user_transitions; + + if (uidlist == NULL) + return 0; + + if (real == -1) + realok = 1; + if (effective == -1) + effectiveok = 1; + if (fs == -1) + fsok = 1; + + if (current->acl->user_trans_type & GR_ID_ALLOW) { + for (i = 0; i < num; i++) { + curuid = (int)uidlist[i]; + if (real == curuid) + realok = 1; + if (effective == curuid) + effectiveok = 1; + if (fs == curuid) + fsok = 1; + } + } else if (current->acl->user_trans_type & GR_ID_DENY) { + for (i = 0; i < num; i++) { + curuid = (int)uidlist[i]; + if (real == curuid) + break; + if (effective == curuid) + break; + if (fs == curuid) + break; + } + /* not in deny list */ + if (i == num) { + realok = 1; + effectiveok = 1; + fsok = 1; + } + } + + if (realok && effectiveok && fsok) + return 0; + else { + gr_log_int(GR_DONT_AUDIT, GR_USRCHANGE_ACL_MSG, realok ? (effectiveok ? (fsok ? 0 : fs) : effective) : real); + return 1; + } +} + +int +gr_check_group_change(int real, int effective, int fs) +{ + unsigned int i; + __u16 num; + gid_t *gidlist; + int curgid; + int realok = 0; + int effectiveok = 0; + int fsok = 0; + + if (unlikely(!(gr_status & GR_READY))) + return 0; + + if (current->acl->mode & (GR_LEARN | GR_INHERITLEARN)) + gr_log_learn_id_change(current, 'g', real, effective, fs); + + num = current->acl->group_trans_num; + gidlist = current->acl->group_transitions; + + if (gidlist == NULL) + return 0; + + if (real == -1) + realok = 1; + if (effective == -1) + effectiveok = 1; + if (fs == -1) + fsok = 1; + + if (current->acl->group_trans_type & GR_ID_ALLOW) { + for (i = 0; i < num; i++) { + curgid = (int)gidlist[i]; + if (real == curgid) + realok = 1; + if (effective == curgid) + effectiveok = 1; + if (fs == curgid) + fsok = 1; + } + } else if (current->acl->group_trans_type & GR_ID_DENY) { + for (i = 0; i < num; i++) { + curgid = (int)gidlist[i]; + if (real == curgid) + break; + if (effective == curgid) + break; + if (fs == curgid) + break; + } + /* not in deny list */ + if (i == num) { + realok = 1; + effectiveok = 1; + fsok = 1; + } + } + + if (realok && effectiveok && fsok) + return 0; + else { + gr_log_int(GR_DONT_AUDIT, GR_GRPCHANGE_ACL_MSG, realok ? (effectiveok ? (fsok ? 0 : fs) : effective) : real); + return 1; + } +} + +void +gr_set_role_label(struct task_struct *task, const uid_t uid, const uid_t gid) +{ + struct acl_role_label *role = task->role; + struct acl_subject_label *subj = NULL; + struct acl_object_label *obj; + struct file *filp; + + if (unlikely(!(gr_status & GR_READY))) + return; + + filp = task->exec_file; + + /* kernel process, we'll give them the kernel role */ + if (unlikely(!filp)) { + task->role = kernel_role; + task->acl = kernel_role->root_label; + return; + } else if (!task->role || !(task->role->roletype & GR_ROLE_SPECIAL)) + role = lookup_acl_role_label(task, uid, gid); + + /* perform subject lookup in possibly new role + we can use this result below in the case where role == task->role + */ + subj = chk_subj_label(filp->f_path.dentry, filp->f_path.mnt, role); + + /* if we changed uid/gid, but result in the same role + and are using inheritance, don't lose the inherited subject + if current subject is other than what normal lookup + would result in, we arrived via inheritance, don't + lose subject + */ + if (role != task->role || (!(task->acl->mode & GR_INHERITLEARN) && + (subj == task->acl))) + task->acl = subj; + + task->role = role; + + task->is_writable = 0; + + /* ignore additional mmap checks for processes that are writable + by the default ACL */ + obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, default_role->root_label); + if (unlikely(obj->mode & GR_WRITE)) + task->is_writable = 1; + obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, task->role->root_label); + if (unlikely(obj->mode & GR_WRITE)) + task->is_writable = 1; + +#ifdef CONFIG_GRKERNSEC_ACL_DEBUG + printk(KERN_ALERT "Set role label for (%s:%d): role:%s, subject:%s\n", task->comm, task->pid, task->role->rolename, task->acl->filename); +#endif + + gr_set_proc_res(task); + + return; +} + +int +gr_set_proc_label(const struct dentry *dentry, const struct vfsmount *mnt) +{ + struct task_struct *task = current; + struct acl_subject_label *newacl; + struct acl_object_label *obj; + __u32 retmode; + + if (unlikely(!(gr_status & GR_READY))) + return 0; + + newacl = chk_subj_label(dentry, mnt, task->role); + + task_lock(task); + if (((task->ptrace & PT_PTRACED) && !(task->acl->mode & + GR_POVERRIDE) && (task->acl != newacl) && + !(task->role->roletype & GR_ROLE_GOD) && + !gr_search_file(dentry, GR_PTRACERD, mnt) && + !(task->acl->mode & (GR_LEARN | GR_INHERITLEARN))) || + (atomic_read(&task->fs->count) > 1 || + atomic_read(&task->files->count) > 1 || + atomic_read(&task->sighand->count) > 1)) { + task_unlock(task); + gr_log_fs_generic(GR_DONT_AUDIT, GR_PTRACE_EXEC_ACL_MSG, dentry, mnt); + return -EACCES; + } + task_unlock(task); + + obj = chk_obj_label(dentry, mnt, task->acl); + retmode = obj->mode & (GR_INHERIT | GR_AUDIT_INHERIT); + + if (!(task->acl->mode & GR_INHERITLEARN) && + ((newacl->mode & GR_LEARN) || !(retmode & GR_INHERIT))) { + if (obj->nested) + task->acl = obj->nested; + else + task->acl = newacl; + } else if (retmode & GR_INHERIT && retmode & GR_AUDIT_INHERIT) + gr_log_str_fs(GR_DO_AUDIT, GR_INHERIT_ACL_MSG, task->acl->filename, dentry, mnt); + + task->is_writable = 0; + + /* ignore additional mmap checks for processes that are writable + by the default ACL */ + obj = chk_obj_label(dentry, mnt, default_role->root_label); + if (unlikely(obj->mode & GR_WRITE)) + task->is_writable = 1; + obj = chk_obj_label(dentry, mnt, task->role->root_label); + if (unlikely(obj->mode & GR_WRITE)) + task->is_writable = 1; + + gr_set_proc_res(task); + +#ifdef CONFIG_GRKERNSEC_ACL_DEBUG + printk(KERN_ALERT "Set subject label for (%s:%d): role:%s, subject:%s\n", task->comm, task->pid, task->role->rolename, task->acl->filename); +#endif + return 0; +} + +/* always called with valid inodev ptr */ +static void +do_handle_delete(struct inodev_entry *inodev, const ino_t ino, const dev_t dev) +{ + struct acl_object_label *matchpo; + struct acl_subject_label *matchps; + struct acl_subject_label *subj; + struct acl_role_label *role; + unsigned int i, x; + + FOR_EACH_ROLE_START(role, i) + FOR_EACH_SUBJECT_START(role, subj, x) + if ((matchpo = lookup_acl_obj_label(ino, dev, subj)) != NULL) + matchpo->mode |= GR_DELETED; + FOR_EACH_SUBJECT_END(subj,x) + FOR_EACH_NESTED_SUBJECT_START(role, subj) + if (subj->inode == ino && subj->device == dev) + subj->mode |= GR_DELETED; + FOR_EACH_NESTED_SUBJECT_END(subj) + if ((matchps = lookup_acl_subj_label(ino, dev, role)) != NULL) + matchps->mode |= GR_DELETED; + FOR_EACH_ROLE_END(role,i) + + inodev->nentry->deleted = 1; + + return; +} + +void +gr_handle_delete(const ino_t ino, const dev_t dev) +{ + struct inodev_entry *inodev; + + if (unlikely(!(gr_status & GR_READY))) + return; + + write_lock(&gr_inode_lock); + inodev = lookup_inodev_entry(ino, dev); + if (inodev != NULL) + do_handle_delete(inodev, ino, dev); + write_unlock(&gr_inode_lock); + + return; +} + +static void +update_acl_obj_label(const ino_t oldinode, const dev_t olddevice, + const ino_t newinode, const dev_t newdevice, + struct acl_subject_label *subj) +{ + unsigned int index = fhash(oldinode, olddevice, subj->obj_hash_size); + struct acl_object_label *match; + + match = subj->obj_hash[index]; + + while (match && (match->inode != oldinode || + match->device != olddevice || + !(match->mode & GR_DELETED))) + match = match->next; + + if (match && (match->inode == oldinode) + && (match->device == olddevice) + && (match->mode & GR_DELETED)) { + if (match->prev == NULL) { + subj->obj_hash[index] = match->next; + if (match->next != NULL) + match->next->prev = NULL; + } else { + match->prev->next = match->next; + if (match->next != NULL) + match->next->prev = match->prev; + } + match->prev = NULL; + match->next = NULL; + match->inode = newinode; + match->device = newdevice; + match->mode &= ~GR_DELETED; + + insert_acl_obj_label(match, subj); + } + + return; +} + +static void +update_acl_subj_label(const ino_t oldinode, const dev_t olddevice, + const ino_t newinode, const dev_t newdevice, + struct acl_role_label *role) +{ + unsigned int index = fhash(oldinode, olddevice, role->subj_hash_size); + struct acl_subject_label *match; + + match = role->subj_hash[index]; + + while (match && (match->inode != oldinode || + match->device != olddevice || + !(match->mode & GR_DELETED))) + match = match->next; + + if (match && (match->inode == oldinode) + && (match->device == olddevice) + && (match->mode & GR_DELETED)) { + if (match->prev == NULL) { + role->subj_hash[index] = match->next; + if (match->next != NULL) + match->next->prev = NULL; + } else { + match->prev->next = match->next; + if (match->next != NULL) + match->next->prev = match->prev; + } + match->prev = NULL; + match->next = NULL; + match->inode = newinode; + match->device = newdevice; + match->mode &= ~GR_DELETED; + + insert_acl_subj_label(match, role); + } + + return; +} + +static void +update_inodev_entry(const ino_t oldinode, const dev_t olddevice, + const ino_t newinode, const dev_t newdevice) +{ + unsigned int index = fhash(oldinode, olddevice, inodev_set.i_size); + struct inodev_entry *match; + + match = inodev_set.i_hash[index]; + + while (match && (match->nentry->inode != oldinode || + match->nentry->device != olddevice || !match->nentry->deleted)) + match = match->next; + + if (match && (match->nentry->inode == oldinode) + && (match->nentry->device == olddevice) && + match->nentry->deleted) { + if (match->prev == NULL) { + inodev_set.i_hash[index] = match->next; + if (match->next != NULL) + match->next->prev = NULL; + } else { + match->prev->next = match->next; + if (match->next != NULL) + match->next->prev = match->prev; + } + match->prev = NULL; + match->next = NULL; + match->nentry->inode = newinode; + match->nentry->device = newdevice; + match->nentry->deleted = 0; + + insert_inodev_entry(match); + } + + return; +} + +static void +do_handle_create(const struct name_entry *matchn, const struct dentry *dentry, + const struct vfsmount *mnt) +{ + struct acl_subject_label *subj; + struct acl_role_label *role; + unsigned int i, x; + + FOR_EACH_ROLE_START(role, i) + update_acl_subj_label(matchn->inode, matchn->device, + dentry->d_inode->i_ino, + dentry->d_inode->i_sb->s_dev, role); + + FOR_EACH_NESTED_SUBJECT_START(role, subj) + if ((subj->inode == dentry->d_inode->i_ino) && + (subj->device == dentry->d_inode->i_sb->s_dev)) { + subj->inode = dentry->d_inode->i_ino; + subj->device = dentry->d_inode->i_sb->s_dev; + } + FOR_EACH_NESTED_SUBJECT_END(subj) + FOR_EACH_SUBJECT_START(role, subj, x) + update_acl_obj_label(matchn->inode, matchn->device, + dentry->d_inode->i_ino, + dentry->d_inode->i_sb->s_dev, subj); + FOR_EACH_SUBJECT_END(subj,x) + FOR_EACH_ROLE_END(role,i) + + update_inodev_entry(matchn->inode, matchn->device, + dentry->d_inode->i_ino, dentry->d_inode->i_sb->s_dev); + + return; +} + +void +gr_handle_create(const struct dentry *dentry, const struct vfsmount *mnt) +{ + struct name_entry *matchn; + + if (unlikely(!(gr_status & GR_READY))) + return; + + preempt_disable(); + matchn = lookup_name_entry(gr_to_filename_rbac(dentry, mnt)); + + if (unlikely((unsigned long)matchn)) { + write_lock(&gr_inode_lock); + do_handle_create(matchn, dentry, mnt); + write_unlock(&gr_inode_lock); + } + preempt_enable(); + + return; +} + +void +gr_handle_rename(struct inode *old_dir, struct inode *new_dir, + struct dentry *old_dentry, + struct dentry *new_dentry, + struct vfsmount *mnt, const __u8 replace) +{ + struct name_entry *matchn; + struct inodev_entry *inodev; + + /* vfs_rename swaps the name and parent link for old_dentry and + new_dentry + at this point, old_dentry has the new name, parent link, and inode + for the renamed file + if a file is being replaced by a rename, new_dentry has the inode + and name for the replaced file + */ + + if (unlikely(!(gr_status & GR_READY))) + return; + + preempt_disable(); + matchn = lookup_name_entry(gr_to_filename_rbac(old_dentry, mnt)); + + /* we wouldn't have to check d_inode if it weren't for + NFS silly-renaming + */ + + write_lock(&gr_inode_lock); + if (unlikely(replace && new_dentry->d_inode)) { + inodev = lookup_inodev_entry(new_dentry->d_inode->i_ino, + new_dentry->d_inode->i_sb->s_dev); + if (inodev != NULL && (new_dentry->d_inode->i_nlink <= 1)) + do_handle_delete(inodev, new_dentry->d_inode->i_ino, + new_dentry->d_inode->i_sb->s_dev); + } + + inodev = lookup_inodev_entry(old_dentry->d_inode->i_ino, + old_dentry->d_inode->i_sb->s_dev); + if (inodev != NULL && (old_dentry->d_inode->i_nlink <= 1)) + do_handle_delete(inodev, old_dentry->d_inode->i_ino, + old_dentry->d_inode->i_sb->s_dev); + + if (unlikely((unsigned long)matchn)) + do_handle_create(matchn, old_dentry, mnt); + + write_unlock(&gr_inode_lock); + preempt_enable(); + + return; +} + +static int +lookup_special_role_auth(__u16 mode, const char *rolename, unsigned char **salt, + unsigned char **sum) +{ + struct acl_role_label *r; + struct role_allowed_ip *ipp; + struct role_transition *trans; + unsigned int i; + int found = 0; + + /* check transition table */ + + for (trans = current->role->transitions; trans; trans = trans->next) { + if (!strcmp(rolename, trans->rolename)) { + found = 1; + break; + } + } + + if (!found) + return 0; + + /* handle special roles that do not require authentication + and check ip */ + + FOR_EACH_ROLE_START(r, i) + if (!strcmp(rolename, r->rolename) && + (r->roletype & GR_ROLE_SPECIAL)) { + found = 0; + if (r->allowed_ips != NULL) { + for (ipp = r->allowed_ips; ipp; ipp = ipp->next) { + if ((ntohl(current->signal->curr_ip) & ipp->netmask) == + (ntohl(ipp->addr) & ipp->netmask)) + found = 1; + } + } else + found = 2; + if (!found) + return 0; + + if (((mode == SPROLE) && (r->roletype & GR_ROLE_NOPW)) || + ((mode == SPROLEPAM) && (r->roletype & GR_ROLE_PAM))) { + *salt = NULL; + *sum = NULL; + return 1; + } + } + FOR_EACH_ROLE_END(r,i) + + for (i = 0; i < num_sprole_pws; i++) { + if (!strcmp(rolename, acl_special_roles[i]->rolename)) { + *salt = acl_special_roles[i]->salt; + *sum = acl_special_roles[i]->sum; + return 1; + } + } + + return 0; +} + +static void +assign_special_role(char *rolename) +{ + struct acl_object_label *obj; + struct acl_role_label *r; + struct acl_role_label *assigned = NULL; + struct task_struct *tsk; + struct file *filp; + unsigned int i; + + FOR_EACH_ROLE_START(r, i) + if (!strcmp(rolename, r->rolename) && + (r->roletype & GR_ROLE_SPECIAL)) + assigned = r; + FOR_EACH_ROLE_END(r,i) + + if (!assigned) + return; + + read_lock(&tasklist_lock); + read_lock(&grsec_exec_file_lock); + + tsk = current->parent; + if (tsk == NULL) + goto out_unlock; + + filp = tsk->exec_file; + if (filp == NULL) + goto out_unlock; + + tsk->is_writable = 0; + + tsk->acl_sp_role = 1; + tsk->acl_role_id = ++acl_sp_role_value; + tsk->role = assigned; + tsk->acl = chk_subj_label(filp->f_path.dentry, filp->f_path.mnt, tsk->role); + + /* ignore additional mmap checks for processes that are writable + by the default ACL */ + obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, default_role->root_label); + if (unlikely(obj->mode & GR_WRITE)) + tsk->is_writable = 1; + obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, tsk->role->root_label); + if (unlikely(obj->mode & GR_WRITE)) + tsk->is_writable = 1; + +#ifdef CONFIG_GRKERNSEC_ACL_DEBUG + printk(KERN_ALERT "Assigning special role:%s subject:%s to process (%s:%d)\n", tsk->role->rolename, tsk->acl->filename, tsk->comm, tsk->pid); +#endif + +out_unlock: + read_unlock(&grsec_exec_file_lock); + read_unlock(&tasklist_lock); + return; +} + +int gr_check_secure_terminal(struct task_struct *task) +{ + struct task_struct *p, *p2, *p3; + struct files_struct *files; + struct fdtable *fdt; + struct file *our_file = NULL, *file; + int i; + + if (task->signal->tty == NULL) + return 1; + + files = get_files_struct(task); + if (files != NULL) { + rcu_read_lock(); + fdt = files_fdtable(files); + for (i=0; i < fdt->max_fds; i++) { + file = fcheck_files(files, i); + if (file && (our_file == NULL) && (file->private_data == task->signal->tty)) { + get_file(file); + our_file = file; + } + } + rcu_read_unlock(); + put_files_struct(files); + } + + if (our_file == NULL) + return 1; + + read_lock(&tasklist_lock); + do_each_thread(p2, p) { + files = get_files_struct(p); + if (files == NULL || + (p->signal && p->signal->tty == task->signal->tty)) { + if (files != NULL) + put_files_struct(files); + continue; + } + rcu_read_lock(); + fdt = files_fdtable(files); + for (i=0; i < fdt->max_fds; i++) { + file = fcheck_files(files, i); + if (file && S_ISCHR(file->f_path.dentry->d_inode->i_mode) && + file->f_path.dentry->d_inode->i_rdev == our_file->f_path.dentry->d_inode->i_rdev) { + p3 = task; + while (p3->pid > 0) { + if (p3 == p) + break; + p3 = p3->parent; + } + if (p3 == p) + break; + gr_log_ttysniff(GR_DONT_AUDIT_GOOD, GR_TTYSNIFF_ACL_MSG, p); + gr_handle_alertkill(p); + rcu_read_unlock(); + put_files_struct(files); + read_unlock(&tasklist_lock); + fput(our_file); + return 0; + } + } + rcu_read_unlock(); + put_files_struct(files); + } while_each_thread(p2, p); + read_unlock(&tasklist_lock); + + fput(our_file); + return 1; +} + +ssize_t +write_grsec_handler(struct file *file, const char * buf, size_t count, loff_t *ppos) +{ + struct gr_arg_wrapper uwrap; + unsigned char *sprole_salt; + unsigned char *sprole_sum; + int error = sizeof (struct gr_arg_wrapper); + int error2 = 0; + + down(&gr_dev_sem); + + if ((gr_status & GR_READY) && !(current->acl->mode & GR_KERNELAUTH)) { + error = -EPERM; + goto out; + } + + if (count != sizeof (struct gr_arg_wrapper)) { + gr_log_int_int(GR_DONT_AUDIT_GOOD, GR_DEV_ACL_MSG, (int)count, (int)sizeof(struct gr_arg_wrapper)); + error = -EINVAL; + goto out; + } + + + if (gr_auth_expires && time_after_eq(get_seconds(), gr_auth_expires)) { + gr_auth_expires = 0; + gr_auth_attempts = 0; + } + + if (copy_from_user(&uwrap, buf, sizeof (struct gr_arg_wrapper))) { + error = -EFAULT; + goto out; + } + + if ((uwrap.version != GRSECURITY_VERSION) || (uwrap.size != sizeof(struct gr_arg))) { + error = -EINVAL; + goto out; + } + + if (copy_from_user(gr_usermode, uwrap.arg, sizeof (struct gr_arg))) { + error = -EFAULT; + goto out; + } + + if (gr_usermode->mode != SPROLE && gr_usermode->mode != SPROLEPAM && + gr_auth_attempts >= CONFIG_GRKERNSEC_ACL_MAXTRIES && + time_after(gr_auth_expires, get_seconds())) { + error = -EBUSY; + goto out; + } + + /* if non-root trying to do anything other than use a special role, + do not attempt authentication, do not count towards authentication + locking + */ + + if (gr_usermode->mode != SPROLE && gr_usermode->mode != STATUS && + gr_usermode->mode != UNSPROLE && gr_usermode->mode != SPROLEPAM && + current->uid) { + error = -EPERM; + goto out; + } + + /* ensure pw and special role name are null terminated */ + + gr_usermode->pw[GR_PW_LEN - 1] = '\0'; + gr_usermode->sp_role[GR_SPROLE_LEN - 1] = '\0'; + + /* Okay. + * We have our enough of the argument structure..(we have yet + * to copy_from_user the tables themselves) . Copy the tables + * only if we need them, i.e. for loading operations. */ + + switch (gr_usermode->mode) { + case STATUS: + if (gr_status & GR_READY) { + error = 1; + if (!gr_check_secure_terminal(current)) + error = 3; + } else + error = 2; + goto out; + case SHUTDOWN: + if ((gr_status & GR_READY) + && !(chkpw(gr_usermode, gr_system_salt, gr_system_sum))) { + gr_status &= ~GR_READY; + gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SHUTS_ACL_MSG); + free_variables(); + memset(gr_usermode, 0, sizeof (struct gr_arg)); + memset(gr_system_salt, 0, GR_SALT_LEN); + memset(gr_system_sum, 0, GR_SHA_LEN); + } else if (gr_status & GR_READY) { + gr_log_noargs(GR_DONT_AUDIT, GR_SHUTF_ACL_MSG); + error = -EPERM; + } else { + gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SHUTI_ACL_MSG); + error = -EAGAIN; + } + break; + case ENABLE: + if (!(gr_status & GR_READY) && !(error2 = gracl_init(gr_usermode))) + gr_log_str(GR_DONT_AUDIT_GOOD, GR_ENABLE_ACL_MSG, GR_VERSION); + else { + if (gr_status & GR_READY) + error = -EAGAIN; + else + error = error2; + gr_log_str(GR_DONT_AUDIT, GR_ENABLEF_ACL_MSG, GR_VERSION); + } + break; + case RELOAD: + if (!(gr_status & GR_READY)) { + gr_log_str(GR_DONT_AUDIT_GOOD, GR_RELOADI_ACL_MSG, GR_VERSION); + error = -EAGAIN; + } else if (!(chkpw(gr_usermode, gr_system_salt, gr_system_sum))) { + lock_kernel(); + gr_status &= ~GR_READY; + free_variables(); + if (!(error2 = gracl_init(gr_usermode))) { + unlock_kernel(); + gr_log_str(GR_DONT_AUDIT_GOOD, GR_RELOAD_ACL_MSG, GR_VERSION); + } else { + unlock_kernel(); + error = error2; + gr_log_str(GR_DONT_AUDIT, GR_RELOADF_ACL_MSG, GR_VERSION); + } + } else { + gr_log_str(GR_DONT_AUDIT, GR_RELOADF_ACL_MSG, GR_VERSION); + error = -EPERM; + } + break; + case SEGVMOD: + if (unlikely(!(gr_status & GR_READY))) { + gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SEGVMODI_ACL_MSG); + error = -EAGAIN; + break; + } + + if (!(chkpw(gr_usermode, gr_system_salt, gr_system_sum))) { + gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SEGVMODS_ACL_MSG); + if (gr_usermode->segv_device && gr_usermode->segv_inode) { + struct acl_subject_label *segvacl; + segvacl = + lookup_acl_subj_label(gr_usermode->segv_inode, + gr_usermode->segv_device, + current->role); + if (segvacl) { + segvacl->crashes = 0; + segvacl->expires = 0; + } + } else if (gr_find_uid(gr_usermode->segv_uid) >= 0) { + gr_remove_uid(gr_usermode->segv_uid); + } + } else { + gr_log_noargs(GR_DONT_AUDIT, GR_SEGVMODF_ACL_MSG); + error = -EPERM; + } + break; + case SPROLE: + case SPROLEPAM: + if (unlikely(!(gr_status & GR_READY))) { + gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_SPROLEI_ACL_MSG); + error = -EAGAIN; + break; + } + + if (current->role->expires && time_after_eq(get_seconds(), current->role->expires)) { + current->role->expires = 0; + current->role->auth_attempts = 0; + } + + if (current->role->auth_attempts >= CONFIG_GRKERNSEC_ACL_MAXTRIES && + time_after(current->role->expires, get_seconds())) { + error = -EBUSY; + goto out; + } + + if (lookup_special_role_auth + (gr_usermode->mode, gr_usermode->sp_role, &sprole_salt, &sprole_sum) + && ((!sprole_salt && !sprole_sum) + || !(chkpw(gr_usermode, sprole_salt, sprole_sum)))) { + char *p = ""; + assign_special_role(gr_usermode->sp_role); + read_lock(&tasklist_lock); + if (current->parent) + p = current->parent->role->rolename; + read_unlock(&tasklist_lock); + gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_SPROLES_ACL_MSG, + p, acl_sp_role_value); + } else { + gr_log_str(GR_DONT_AUDIT, GR_SPROLEF_ACL_MSG, gr_usermode->sp_role); + error = -EPERM; + if(!(current->role->auth_attempts++)) + current->role->expires = get_seconds() + CONFIG_GRKERNSEC_ACL_TIMEOUT; + + goto out; + } + break; + case UNSPROLE: + if (unlikely(!(gr_status & GR_READY))) { + gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_UNSPROLEI_ACL_MSG); + error = -EAGAIN; + break; + } + + if (current->role->roletype & GR_ROLE_SPECIAL) { + char *p = ""; + int i = 0; + + read_lock(&tasklist_lock); + if (current->parent) { + p = current->parent->role->rolename; + i = current->parent->acl_role_id; + } + read_unlock(&tasklist_lock); + + gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_UNSPROLES_ACL_MSG, p, i); + gr_set_acls(1); + } else { + gr_log_str(GR_DONT_AUDIT, GR_UNSPROLEF_ACL_MSG, current->role->rolename); + error = -EPERM; + goto out; + } + break; + default: + gr_log_int(GR_DONT_AUDIT, GR_INVMODE_ACL_MSG, gr_usermode->mode); + error = -EINVAL; + break; + } + + if (error != -EPERM) + goto out; + + if(!(gr_auth_attempts++)) + gr_auth_expires = get_seconds() + CONFIG_GRKERNSEC_ACL_TIMEOUT; + + out: + up(&gr_dev_sem); + return error; +} + +int +gr_set_acls(const int type) +{ + struct acl_object_label *obj; + struct task_struct *task, *task2; + struct file *filp; + struct acl_role_label *role = current->role; + __u16 acl_role_id = current->acl_role_id; + + read_lock(&tasklist_lock); + read_lock(&grsec_exec_file_lock); + do_each_thread(task2, task) { + /* check to see if we're called from the exit handler, + if so, only replace ACLs that have inherited the admin + ACL */ + + if (type && (task->role != role || + task->acl_role_id != acl_role_id)) + continue; + + task->acl_role_id = 0; + task->acl_sp_role = 0; + + if ((filp = task->exec_file)) { + task->role = lookup_acl_role_label(task, task->uid, task->gid); + + task->acl = + chk_subj_label(filp->f_path.dentry, filp->f_path.mnt, + task->role); + if (task->acl) { + struct acl_subject_label *curr; + curr = task->acl; + + task->is_writable = 0; + /* ignore additional mmap checks for processes that are writable + by the default ACL */ + obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, default_role->root_label); + if (unlikely(obj->mode & GR_WRITE)) + task->is_writable = 1; + obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, task->role->root_label); + if (unlikely(obj->mode & GR_WRITE)) + task->is_writable = 1; + + gr_set_proc_res(task); + +#ifdef CONFIG_GRKERNSEC_ACL_DEBUG + printk(KERN_ALERT "gr_set_acls for (%s:%d): role:%s, subject:%s\n", task->comm, task->pid, task->role->rolename, task->acl->filename); +#endif + } else { + read_unlock(&grsec_exec_file_lock); + read_unlock(&tasklist_lock); + gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_DEFACL_MSG, task->comm, task->pid); + return 1; + } + } else { + // it's a kernel process + task->role = kernel_role; + task->acl = kernel_role->root_label; +#ifdef CONFIG_GRKERNSEC_ACL_HIDEKERN + task->acl->mode &= ~GR_PROCFIND; +#endif + } + } while_each_thread(task2, task); + read_unlock(&grsec_exec_file_lock); + read_unlock(&tasklist_lock); + return 0; +} + +void +gr_learn_resource(const struct task_struct *task, + const int res, const unsigned long wanted, const int gt) +{ + struct acl_subject_label *acl; + + if (unlikely((gr_status & GR_READY) && + task->acl && (task->acl->mode & (GR_LEARN | GR_INHERITLEARN)))) + goto skip_reslog; + +#ifdef CONFIG_GRKERNSEC_RESLOG + gr_log_resource(task, res, wanted, gt); +#endif + skip_reslog: + + if (unlikely(!(gr_status & GR_READY) || !wanted)) + return; + + acl = task->acl; + + if (likely(!acl || !(acl->mode & (GR_LEARN | GR_INHERITLEARN)) || + !(acl->resmask & (1 << (unsigned short) res)))) + return; + + if (wanted >= acl->res[res].rlim_cur) { + unsigned long res_add; + + res_add = wanted; + switch (res) { + case RLIMIT_CPU: + res_add += GR_RLIM_CPU_BUMP; + break; + case RLIMIT_FSIZE: + res_add += GR_RLIM_FSIZE_BUMP; + break; + case RLIMIT_DATA: + res_add += GR_RLIM_DATA_BUMP; + break; + case RLIMIT_STACK: + res_add += GR_RLIM_STACK_BUMP; + break; + case RLIMIT_CORE: + res_add += GR_RLIM_CORE_BUMP; + break; + case RLIMIT_RSS: + res_add += GR_RLIM_RSS_BUMP; + break; + case RLIMIT_NPROC: + res_add += GR_RLIM_NPROC_BUMP; + break; + case RLIMIT_NOFILE: + res_add += GR_RLIM_NOFILE_BUMP; + break; + case RLIMIT_MEMLOCK: + res_add += GR_RLIM_MEMLOCK_BUMP; + break; + case RLIMIT_AS: + res_add += GR_RLIM_AS_BUMP; + break; + case RLIMIT_LOCKS: + res_add += GR_RLIM_LOCKS_BUMP; + break; + } + + acl->res[res].rlim_cur = res_add; + + if (wanted > acl->res[res].rlim_max) + acl->res[res].rlim_max = res_add; + + security_learn(GR_LEARN_AUDIT_MSG, task->role->rolename, + task->role->roletype, acl->filename, + acl->res[res].rlim_cur, acl->res[res].rlim_max, + "", (unsigned long) res); + } + + return; +} + +#ifdef CONFIG_PAX_HAVE_ACL_FLAGS +void +pax_set_initial_flags(struct linux_binprm *bprm) +{ + struct task_struct *task = current; + struct acl_subject_label *proc; + unsigned long flags; + + if (unlikely(!(gr_status & GR_READY))) + return; + + flags = pax_get_flags(task); + + proc = task->acl; + + if (proc->pax_flags & GR_PAX_DISABLE_PAGEEXEC) + flags &= ~MF_PAX_PAGEEXEC; + if (proc->pax_flags & GR_PAX_DISABLE_SEGMEXEC) + flags &= ~MF_PAX_SEGMEXEC; + if (proc->pax_flags & GR_PAX_DISABLE_RANDMMAP) + flags &= ~MF_PAX_RANDMMAP; + if (proc->pax_flags & GR_PAX_DISABLE_EMUTRAMP) + flags &= ~MF_PAX_EMUTRAMP; + if (proc->pax_flags & GR_PAX_DISABLE_MPROTECT) + flags &= ~MF_PAX_MPROTECT; + + if (proc->pax_flags & GR_PAX_ENABLE_PAGEEXEC) + flags |= MF_PAX_PAGEEXEC; + if (proc->pax_flags & GR_PAX_ENABLE_SEGMEXEC) + flags |= MF_PAX_SEGMEXEC; + if (proc->pax_flags & GR_PAX_ENABLE_RANDMMAP) + flags |= MF_PAX_RANDMMAP; + if (proc->pax_flags & GR_PAX_ENABLE_EMUTRAMP) + flags |= MF_PAX_EMUTRAMP; + if (proc->pax_flags & GR_PAX_ENABLE_MPROTECT) + flags |= MF_PAX_MPROTECT; + + pax_set_flags(task, flags); + + return; +} +#endif + +#ifdef CONFIG_SYSCTL +/* Eric Biederman likes breaking userland ABI and every inode-based security + system to save 35kb of memory */ + +/* we modify the passed in filename, but adjust it back before returning */ +static struct acl_object_label *gr_lookup_by_name(char *name, unsigned int len) +{ + struct name_entry *nmatch; + char *p, *lastp = NULL; + struct acl_object_label *obj = NULL, *tmp; + struct acl_subject_label *tmpsubj; + char c = '\0'; + + read_lock(&gr_inode_lock); + + p = name + len - 1; + do { + nmatch = lookup_name_entry(name); + if (lastp != NULL) + *lastp = c; + + if (nmatch == NULL) + goto next_component; + tmpsubj = current->acl; + do { + obj = lookup_acl_obj_label(nmatch->inode, nmatch->device, tmpsubj); + if (obj != NULL) { + tmp = obj->globbed; + while (tmp) { + if (!glob_match(tmp->filename, name)) { + obj = tmp; + goto found_obj; + } + tmp = tmp->next; + } + goto found_obj; + } + } while ((tmpsubj = tmpsubj->parent_subject)); +next_component: + /* end case */ + if (p == name) + break; + + while (*p != '/') + p--; + if (p == name) + lastp = p + 1; + else { + lastp = p; + p--; + } + c = *lastp; + *lastp = '\0'; + } while (1); +found_obj: + read_unlock(&gr_inode_lock); + /* obj returned will always be non-null */ + return obj; +} + +/* returns 0 when allowing, non-zero on error + op of 0 is used for readdir, so we don't log the names of hidden files +*/ +__u32 +gr_handle_sysctl(const struct ctl_table *table, const int op) +{ + ctl_table *tmp; + const char *proc_sys = "/proc/sys"; + char *path; + struct acl_object_label *obj; + unsigned short len = 0, pos = 0, depth = 0, i; + __u32 err = 0; + __u32 mode = 0; + + if (unlikely(!(gr_status & GR_READY))) + return 0; + + /* for now, ignore operations on non-sysctl entries if it's not a + readdir*/ + if (table->child != NULL && op != 0) + return 0; + + mode |= GR_FIND; + /* it's only a read if it's an entry, read on dirs is for readdir */ + if (op & MAY_READ) + mode |= GR_READ; + if (op & MAY_WRITE) + mode |= GR_WRITE; + + preempt_disable(); + + path = per_cpu_ptr(gr_shared_page[0], smp_processor_id()); + + /* it's only a read/write if it's an actual entry, not a dir + (which are opened for readdir) + */ + + /* convert the requested sysctl entry into a pathname */ + + for (tmp = (ctl_table *)table; tmp != NULL; tmp = tmp->parent) { + len += strlen(tmp->procname); + len++; + depth++; + } + + if ((len + depth + strlen(proc_sys) + 1) > PAGE_SIZE) { + /* deny */ + goto out; + } + + memset(path, 0, PAGE_SIZE); + + memcpy(path, proc_sys, strlen(proc_sys)); + + pos += strlen(proc_sys); + + for (; depth > 0; depth--) { + path[pos] = '/'; + pos++; + for (i = 1, tmp = (ctl_table *)table; tmp != NULL; tmp = tmp->parent) { + if (depth == i) { + memcpy(path + pos, tmp->procname, + strlen(tmp->procname)); + pos += strlen(tmp->procname); + } + i++; + } + } + + obj = gr_lookup_by_name(path, pos); + err = obj->mode & (mode | to_gr_audit(mode) | GR_SUPPRESS); + + if (unlikely((current->acl->mode & (GR_LEARN | GR_INHERITLEARN)) && + ((err & mode) != mode))) { + __u32 new_mode = mode; + + new_mode &= ~(GR_AUDITS | GR_SUPPRESS); + + err = 0; + gr_log_learn_sysctl(current, path, new_mode); + } else if (!(err & GR_FIND) && !(err & GR_SUPPRESS) && op != 0) { + gr_log_hidden_sysctl(GR_DONT_AUDIT, GR_HIDDEN_ACL_MSG, path); + err = -ENOENT; + } else if (!(err & GR_FIND)) { + err = -ENOENT; + } else if (((err & mode) & ~GR_FIND) != (mode & ~GR_FIND) && !(err & GR_SUPPRESS)) { + gr_log_str4(GR_DONT_AUDIT, GR_SYSCTL_ACL_MSG, "denied", + path, (mode & GR_READ) ? " reading" : "", + (mode & GR_WRITE) ? " writing" : ""); + err = -EACCES; + } else if ((err & mode) != mode) { + err = -EACCES; + } else if ((((err & mode) & ~GR_FIND) == (mode & ~GR_FIND)) && (err & GR_AUDITS)) { + gr_log_str4(GR_DO_AUDIT, GR_SYSCTL_ACL_MSG, "successful", + path, (mode & GR_READ) ? " reading" : "", + (mode & GR_WRITE) ? " writing" : ""); + err = 0; + } else + err = 0; + + out: + preempt_enable(); + + return err; +} +#endif + +int +gr_handle_proc_ptrace(struct task_struct *task) +{ + struct file *filp; + struct task_struct *tmp = task; + struct task_struct *curtemp = current; + __u32 retmode; + + if (unlikely(!(gr_status & GR_READY))) + return 0; + + read_lock(&tasklist_lock); + read_lock(&grsec_exec_file_lock); + filp = task->exec_file; + + while (tmp->pid > 0) { + if (tmp == curtemp) + break; + tmp = tmp->parent; + } + + if (!filp || (tmp->pid == 0 && !(current->acl->mode & GR_RELAXPTRACE))) { + read_unlock(&grsec_exec_file_lock); + read_unlock(&tasklist_lock); + return 1; + } + + retmode = gr_search_file(filp->f_path.dentry, GR_NOPTRACE, filp->f_path.mnt); + read_unlock(&grsec_exec_file_lock); + read_unlock(&tasklist_lock); + + if (retmode & GR_NOPTRACE) + return 1; + + if (!(current->acl->mode & GR_POVERRIDE) && !(current->role->roletype & GR_ROLE_GOD) + && (current->acl != task->acl || (current->acl != current->role->root_label + && current->pid != task->pid))) + return 1; + + return 0; +} + +int +gr_handle_ptrace(struct task_struct *task, const long request) +{ + struct task_struct *tmp = task; + struct task_struct *curtemp = current; + __u32 retmode; + + if (unlikely(!(gr_status & GR_READY))) + return 0; + + read_lock(&tasklist_lock); + while (tmp->pid > 0) { + if (tmp == curtemp) + break; + tmp = tmp->parent; + } + + if (tmp->pid == 0 && !(current->acl->mode & GR_RELAXPTRACE)) { + read_unlock(&tasklist_lock); + gr_log_ptrace(GR_DONT_AUDIT, GR_PTRACE_ACL_MSG, task); + return 1; + } + read_unlock(&tasklist_lock); + + read_lock(&grsec_exec_file_lock); + if (unlikely(!task->exec_file)) { + read_unlock(&grsec_exec_file_lock); + return 0; + } + + retmode = gr_search_file(task->exec_file->f_path.dentry, GR_PTRACERD | GR_NOPTRACE, task->exec_file->f_path.mnt); + read_unlock(&grsec_exec_file_lock); + + if (retmode & GR_NOPTRACE) { + gr_log_ptrace(GR_DONT_AUDIT, GR_PTRACE_ACL_MSG, task); + return 1; + } + + if (retmode & GR_PTRACERD) { + switch (request) { + case PTRACE_POKETEXT: + case PTRACE_POKEDATA: + case PTRACE_POKEUSR: +#if !defined(CONFIG_PPC32) && !defined(CONFIG_PPC64) && !defined(CONFIG_PARISC) && !defined(CONFIG_ALPHA) && !defined(CONFIG_IA64) + case PTRACE_SETREGS: + case PTRACE_SETFPREGS: +#endif +#ifdef CONFIG_X86 + case PTRACE_SETFPXREGS: +#endif +#ifdef CONFIG_ALTIVEC + case PTRACE_SETVRREGS: +#endif + return 1; + default: + return 0; + } + } else if (!(current->acl->mode & GR_POVERRIDE) && + !(current->role->roletype & GR_ROLE_GOD) && + (current->acl != task->acl)) { + gr_log_ptrace(GR_DONT_AUDIT, GR_PTRACE_ACL_MSG, task); + return 1; + } + + return 0; +} + +static int is_writable_mmap(const struct file *filp) +{ + struct task_struct *task = current; + struct acl_object_label *obj, *obj2; + + if (gr_status & GR_READY && !(task->acl->mode & GR_OVERRIDE) && + !task->is_writable && S_ISREG(filp->f_path.dentry->d_inode->i_mode)) { + obj = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, default_role->root_label); + obj2 = chk_obj_label(filp->f_path.dentry, filp->f_path.mnt, + task->role->root_label); + if (unlikely((obj->mode & GR_WRITE) || (obj2->mode & GR_WRITE))) { + gr_log_fs_generic(GR_DONT_AUDIT, GR_WRITLIB_ACL_MSG, filp->f_path.dentry, filp->f_path.mnt); + return 1; + } + } + return 0; +} + +int +gr_acl_handle_mmap(const struct file *file, const unsigned long prot) +{ + __u32 mode; + + if (unlikely(!file || !(prot & PROT_EXEC))) + return 1; + + if (is_writable_mmap(file)) + return 0; + + mode = + gr_search_file(file->f_path.dentry, + GR_EXEC | GR_AUDIT_EXEC | GR_SUPPRESS, + file->f_path.mnt); + + if (!gr_tpe_allow(file)) + return 0; + + if (unlikely(!(mode & GR_EXEC) && !(mode & GR_SUPPRESS))) { + gr_log_fs_rbac_generic(GR_DONT_AUDIT, GR_MMAP_ACL_MSG, file->f_path.dentry, file->f_path.mnt); + return 0; + } else if (unlikely(!(mode & GR_EXEC))) { + return 0; + } else if (unlikely(mode & GR_EXEC && mode & GR_AUDIT_EXEC)) { + gr_log_fs_rbac_generic(GR_DO_AUDIT, GR_MMAP_ACL_MSG, file->f_path.dentry, file->f_path.mnt); + return 1; + } + + return 1; +} + +int +gr_acl_handle_mprotect(const struct file *file, const unsigned long prot) +{ + __u32 mode; + + if (unlikely(!file || !(prot & PROT_EXEC))) + return 1; + + if (is_writable_mmap(file)) + return 0; + + mode = + gr_search_file(file->f_path.dentry, + GR_EXEC | GR_AUDIT_EXEC | GR_SUPPRESS, + file->f_path.mnt); + + if (!gr_tpe_allow(file)) + return 0; + + if (unlikely(!(mode & GR_EXEC) && !(mode & GR_SUPPRESS))) { + gr_log_fs_rbac_generic(GR_DONT_AUDIT, GR_MPROTECT_ACL_MSG, file->f_path.dentry, file->f_path.mnt); + return 0; + } else if (unlikely(!(mode & GR_EXEC))) { + return 0; + } else if (unlikely(mode & GR_EXEC && mode & GR_AUDIT_EXEC)) { + gr_log_fs_rbac_generic(GR_DO_AUDIT, GR_MPROTECT_ACL_MSG, file->f_path.dentry, file->f_path.mnt); + return 1; + } + + return 1; +} + +void +gr_acl_handle_psacct(struct task_struct *task, const long code) +{ + unsigned long runtime; + unsigned long cputime; + unsigned int wday, cday; + __u8 whr, chr; + __u8 wmin, cmin; + __u8 wsec, csec; + struct timespec timeval; + + if (unlikely(!(gr_status & GR_READY) || !task->acl || + !(task->acl->mode & GR_PROCACCT))) + return; + + do_posix_clock_monotonic_gettime(&timeval); + runtime = timeval.tv_sec - task->start_time.tv_sec; + wday = runtime / (3600 * 24); + runtime -= wday * (3600 * 24); + whr = runtime / 3600; + runtime -= whr * 3600; + wmin = runtime / 60; + runtime -= wmin * 60; + wsec = runtime; + + cputime = (task->utime + task->stime) / HZ; + cday = cputime / (3600 * 24); + cputime -= cday * (3600 * 24); + chr = cputime / 3600; + cputime -= chr * 3600; + cmin = cputime / 60; + cputime -= cmin * 60; + csec = cputime; + + gr_log_procacct(GR_DO_AUDIT, GR_ACL_PROCACCT_MSG, task, wday, whr, wmin, wsec, cday, chr, cmin, csec, code); + + return; +} + +void gr_set_kernel_label(struct task_struct *task) +{ + if (gr_status & GR_READY) { + task->role = kernel_role; + task->acl = kernel_role->root_label; + } + return; +} + +int gr_acl_handle_filldir(const struct file *file, const char *name, const unsigned int namelen, const ino_t ino) +{ + struct task_struct *task = current; + struct dentry *dentry = file->f_path.dentry; + struct vfsmount *mnt = file->f_path.mnt; + struct acl_object_label *obj, *tmp; + struct acl_subject_label *subj; + unsigned int bufsize; + int is_not_root; + char *path; + + if (unlikely(!(gr_status & GR_READY))) + return 1; + + if (task->acl->mode & (GR_LEARN | GR_INHERITLEARN)) + return 1; + + /* ignore Eric Biederman */ + if (IS_PRIVATE(dentry->d_inode)) + return 1; + + subj = task->acl; + do { + obj = lookup_acl_obj_label(ino, dentry->d_inode->i_sb->s_dev, subj); + if (obj != NULL) + return (obj->mode & GR_FIND) ? 1 : 0; + } while ((subj = subj->parent_subject)); + + obj = chk_obj_label(dentry, mnt, task->acl); + if (obj->globbed == NULL) + return (obj->mode & GR_FIND) ? 1 : 0; + + is_not_root = ((obj->filename[0] == '/') && + (obj->filename[1] == '\0')) ? 0 : 1; + bufsize = PAGE_SIZE - namelen - is_not_root; + + /* check bufsize > PAGE_SIZE || bufsize == 0 */ + if (unlikely((bufsize - 1) > (PAGE_SIZE - 1))) + return 1; + + preempt_disable(); + path = d_real_path(dentry, mnt, per_cpu_ptr(gr_shared_page[0], smp_processor_id()), + bufsize); + + bufsize = strlen(path); + + /* if base is "/", don't append an additional slash */ + if (is_not_root) + *(path + bufsize) = '/'; + memcpy(path + bufsize + is_not_root, name, namelen); + *(path + bufsize + namelen + is_not_root) = '\0'; + + tmp = obj->globbed; + while (tmp) { + if (!glob_match(tmp->filename, path)) { + preempt_enable(); + return (tmp->mode & GR_FIND) ? 1 : 0; + } + tmp = tmp->next; + } + preempt_enable(); + return (obj->mode & GR_FIND) ? 1 : 0; +} + +EXPORT_SYMBOL(gr_learn_resource); +EXPORT_SYMBOL(gr_set_kernel_label); +#ifdef CONFIG_SECURITY +EXPORT_SYMBOL(gr_check_user_change); +EXPORT_SYMBOL(gr_check_group_change); +#endif + diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl_cap.c linux-2.6.27.15-g-v/grsecurity/gracl_cap.c --- linux-2.6.27.15/grsecurity/gracl_cap.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl_cap.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,129 @@ +#include +#include +#include +#include +#include +#include + +static const char *captab_log[] = { + "CAP_CHOWN", + "CAP_DAC_OVERRIDE", + "CAP_DAC_READ_SEARCH", + "CAP_FOWNER", + "CAP_FSETID", + "CAP_KILL", + "CAP_SETGID", + "CAP_SETUID", + "CAP_SETPCAP", + "CAP_LINUX_IMMUTABLE", + "CAP_NET_BIND_SERVICE", + "CAP_NET_BROADCAST", + "CAP_NET_ADMIN", + "CAP_NET_RAW", + "CAP_IPC_LOCK", + "CAP_IPC_OWNER", + "CAP_SYS_MODULE", + "CAP_SYS_RAWIO", + "CAP_SYS_CHROOT", + "CAP_SYS_PTRACE", + "CAP_SYS_PACCT", + "CAP_SYS_ADMIN", + "CAP_SYS_BOOT", + "CAP_SYS_NICE", + "CAP_SYS_RESOURCE", + "CAP_SYS_TIME", + "CAP_SYS_TTY_CONFIG", + "CAP_MKNOD", + "CAP_LEASE", + "CAP_AUDIT_WRITE", + "CAP_AUDIT_CONTROL", + "CAP_SETFCAP", + "CAP_MAC_OVERRIDE", + "CAP_MAC_ADMIN" +}; + +EXPORT_SYMBOL(gr_task_is_capable); +EXPORT_SYMBOL(gr_is_capable_nolog); + +int +gr_task_is_capable(struct task_struct *task, const int cap) +{ + struct acl_subject_label *curracl; + kernel_cap_t cap_drop = __cap_empty_set, cap_mask = __cap_empty_set; + + if (!gr_acl_is_enabled()) + return 1; + + curracl = task->acl; + + cap_drop = curracl->cap_lower; + cap_mask = curracl->cap_mask; + + while ((curracl = curracl->parent_subject)) { + /* if the cap isn't specified in the current computed mask but is specified in the + current level subject, and is lowered in the current level subject, then add + it to the set of dropped capabilities + otherwise, add the current level subject's mask to the current computed mask + */ + if (!cap_raised(cap_mask, cap) && cap_raised(curracl->cap_mask, cap)) { + cap_raise(cap_mask, cap); + if (cap_raised(curracl->cap_lower, cap)) + cap_raise(cap_drop, cap); + } + } + + if (!cap_raised(cap_drop, cap)) + return 1; + + curracl = task->acl; + + if ((curracl->mode & (GR_LEARN | GR_INHERITLEARN)) + && cap_raised(task->cap_effective, cap)) { + security_learn(GR_LEARN_AUDIT_MSG, task->role->rolename, + task->role->roletype, task->uid, + task->gid, task->exec_file ? + gr_to_filename(task->exec_file->f_path.dentry, + task->exec_file->f_path.mnt) : curracl->filename, + curracl->filename, 0UL, + 0UL, "", (unsigned long) cap, NIPQUAD(task->signal->curr_ip)); + return 1; + } + + if ((cap >= 0) && (cap < (sizeof(captab_log)/sizeof(captab_log[0]))) && cap_raised(task->cap_effective, cap)) + gr_log_cap(GR_DONT_AUDIT, GR_CAP_ACL_MSG, task, captab_log[cap]); + return 0; +} + +int +gr_is_capable_nolog(const int cap) +{ + struct acl_subject_label *curracl; + kernel_cap_t cap_drop = __cap_empty_set, cap_mask = __cap_empty_set; + + if (!gr_acl_is_enabled()) + return 1; + + curracl = current->acl; + + cap_drop = curracl->cap_lower; + cap_mask = curracl->cap_mask; + + while ((curracl = curracl->parent_subject)) { + /* if the cap isn't specified in the current computed mask but is specified in the + current level subject, and is lowered in the current level subject, then add + it to the set of dropped capabilities + otherwise, add the current level subject's mask to the current computed mask + */ + if (!cap_raised(cap_mask, cap) && cap_raised(curracl->cap_mask, cap)) { + cap_raise(cap_mask, cap); + if (cap_raised(curracl->cap_lower, cap)) + cap_raise(cap_drop, cap); + } + } + + if (!cap_raised(cap_drop, cap)) + return 1; + + return 0; +} + diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl_fs.c linux-2.6.27.15-g-v/grsecurity/gracl_fs.c --- linux-2.6.27.15/grsecurity/gracl_fs.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl_fs.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,423 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include + +__u32 +gr_acl_handle_hidden_file(const struct dentry * dentry, + const struct vfsmount * mnt) +{ + __u32 mode; + + if (unlikely(!dentry->d_inode)) + return GR_FIND; + + mode = + gr_search_file(dentry, GR_FIND | GR_AUDIT_FIND | GR_SUPPRESS, mnt); + + if (unlikely(mode & GR_FIND && mode & GR_AUDIT_FIND)) { + gr_log_fs_rbac_generic(GR_DO_AUDIT, GR_HIDDEN_ACL_MSG, dentry, mnt); + return mode; + } else if (unlikely(!(mode & GR_FIND) && !(mode & GR_SUPPRESS))) { + gr_log_fs_rbac_generic(GR_DONT_AUDIT, GR_HIDDEN_ACL_MSG, dentry, mnt); + return 0; + } else if (unlikely(!(mode & GR_FIND))) + return 0; + + return GR_FIND; +} + +__u32 +gr_acl_handle_open(const struct dentry * dentry, const struct vfsmount * mnt, + const int fmode) +{ + __u32 reqmode = GR_FIND; + __u32 mode; + + if (unlikely(!dentry->d_inode)) + return reqmode; + + if (unlikely(fmode & O_APPEND)) + reqmode |= GR_APPEND; + else if (unlikely(fmode & FMODE_WRITE)) + reqmode |= GR_WRITE; + if (likely((fmode & FMODE_READ) && !(fmode & O_DIRECTORY))) + reqmode |= GR_READ; + + mode = + gr_search_file(dentry, reqmode | to_gr_audit(reqmode) | GR_SUPPRESS, + mnt); + + if (unlikely(((mode & reqmode) == reqmode) && mode & GR_AUDITS)) { + gr_log_fs_rbac_mode2(GR_DO_AUDIT, GR_OPEN_ACL_MSG, dentry, mnt, + reqmode & GR_READ ? " reading" : "", + reqmode & GR_WRITE ? " writing" : reqmode & + GR_APPEND ? " appending" : ""); + return reqmode; + } else + if (unlikely((mode & reqmode) != reqmode && !(mode & GR_SUPPRESS))) + { + gr_log_fs_rbac_mode2(GR_DONT_AUDIT, GR_OPEN_ACL_MSG, dentry, mnt, + reqmode & GR_READ ? " reading" : "", + reqmode & GR_WRITE ? " writing" : reqmode & + GR_APPEND ? " appending" : ""); + return 0; + } else if (unlikely((mode & reqmode) != reqmode)) + return 0; + + return reqmode; +} + +__u32 +gr_acl_handle_creat(const struct dentry * dentry, + const struct dentry * p_dentry, + const struct vfsmount * p_mnt, const int fmode, + const int imode) +{ + __u32 reqmode = GR_WRITE | GR_CREATE; + __u32 mode; + + if (unlikely(fmode & O_APPEND)) + reqmode |= GR_APPEND; + if (unlikely((fmode & FMODE_READ) && !(fmode & O_DIRECTORY))) + reqmode |= GR_READ; + if (unlikely((fmode & O_CREAT) && (imode & (S_ISUID | S_ISGID)))) + reqmode |= GR_SETID; + + mode = + gr_check_create(dentry, p_dentry, p_mnt, + reqmode | to_gr_audit(reqmode) | GR_SUPPRESS); + + if (unlikely(((mode & reqmode) == reqmode) && mode & GR_AUDITS)) { + gr_log_fs_rbac_mode2(GR_DO_AUDIT, GR_CREATE_ACL_MSG, dentry, p_mnt, + reqmode & GR_READ ? " reading" : "", + reqmode & GR_WRITE ? " writing" : reqmode & + GR_APPEND ? " appending" : ""); + return reqmode; + } else + if (unlikely((mode & reqmode) != reqmode && !(mode & GR_SUPPRESS))) + { + gr_log_fs_rbac_mode2(GR_DONT_AUDIT, GR_CREATE_ACL_MSG, dentry, p_mnt, + reqmode & GR_READ ? " reading" : "", + reqmode & GR_WRITE ? " writing" : reqmode & + GR_APPEND ? " appending" : ""); + return 0; + } else if (unlikely((mode & reqmode) != reqmode)) + return 0; + + return reqmode; +} + +__u32 +gr_acl_handle_access(const struct dentry * dentry, const struct vfsmount * mnt, + const int fmode) +{ + __u32 mode, reqmode = GR_FIND; + + if ((fmode & S_IXOTH) && !S_ISDIR(dentry->d_inode->i_mode)) + reqmode |= GR_EXEC; + if (fmode & S_IWOTH) + reqmode |= GR_WRITE; + if (fmode & S_IROTH) + reqmode |= GR_READ; + + mode = + gr_search_file(dentry, reqmode | to_gr_audit(reqmode) | GR_SUPPRESS, + mnt); + + if (unlikely(((mode & reqmode) == reqmode) && mode & GR_AUDITS)) { + gr_log_fs_rbac_mode3(GR_DO_AUDIT, GR_ACCESS_ACL_MSG, dentry, mnt, + reqmode & GR_READ ? " reading" : "", + reqmode & GR_WRITE ? " writing" : "", + reqmode & GR_EXEC ? " executing" : ""); + return reqmode; + } else + if (unlikely((mode & reqmode) != reqmode && !(mode & GR_SUPPRESS))) + { + gr_log_fs_rbac_mode3(GR_DONT_AUDIT, GR_ACCESS_ACL_MSG, dentry, mnt, + reqmode & GR_READ ? " reading" : "", + reqmode & GR_WRITE ? " writing" : "", + reqmode & GR_EXEC ? " executing" : ""); + return 0; + } else if (unlikely((mode & reqmode) != reqmode)) + return 0; + + return reqmode; +} + +static __u32 generic_fs_handler(const struct dentry *dentry, const struct vfsmount *mnt, __u32 reqmode, const char *fmt) +{ + __u32 mode; + + mode = gr_search_file(dentry, reqmode | to_gr_audit(reqmode) | GR_SUPPRESS, mnt); + + if (unlikely(((mode & (reqmode)) == (reqmode)) && mode & GR_AUDITS)) { + gr_log_fs_rbac_generic(GR_DO_AUDIT, fmt, dentry, mnt); + return mode; + } else if (unlikely((mode & (reqmode)) != (reqmode) && !(mode & GR_SUPPRESS))) { + gr_log_fs_rbac_generic(GR_DONT_AUDIT, fmt, dentry, mnt); + return 0; + } else if (unlikely((mode & (reqmode)) != (reqmode))) + return 0; + + return (reqmode); +} + +__u32 +gr_acl_handle_rmdir(const struct dentry * dentry, const struct vfsmount * mnt) +{ + return generic_fs_handler(dentry, mnt, GR_WRITE | GR_DELETE , GR_RMDIR_ACL_MSG); +} + +__u32 +gr_acl_handle_unlink(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return generic_fs_handler(dentry, mnt, GR_WRITE | GR_DELETE , GR_UNLINK_ACL_MSG); +} + +__u32 +gr_acl_handle_truncate(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return generic_fs_handler(dentry, mnt, GR_WRITE, GR_TRUNCATE_ACL_MSG); +} + +__u32 +gr_acl_handle_utime(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return generic_fs_handler(dentry, mnt, GR_WRITE, GR_ATIME_ACL_MSG); +} + +__u32 +gr_acl_handle_fchmod(const struct dentry *dentry, const struct vfsmount *mnt, + mode_t mode) +{ + if (unlikely(dentry->d_inode && S_ISSOCK(dentry->d_inode->i_mode))) + return 1; + + if (unlikely((mode != (mode_t)-1) && (mode & (S_ISUID | S_ISGID)))) { + return generic_fs_handler(dentry, mnt, GR_WRITE | GR_SETID, + GR_FCHMOD_ACL_MSG); + } else { + return generic_fs_handler(dentry, mnt, GR_WRITE, GR_FCHMOD_ACL_MSG); + } +} + +__u32 +gr_acl_handle_chmod(const struct dentry *dentry, const struct vfsmount *mnt, + mode_t mode) +{ + if (unlikely((mode != (mode_t)-1) && (mode & (S_ISUID | S_ISGID)))) { + return generic_fs_handler(dentry, mnt, GR_WRITE | GR_SETID, + GR_CHMOD_ACL_MSG); + } else { + return generic_fs_handler(dentry, mnt, GR_WRITE, GR_CHMOD_ACL_MSG); + } +} + +__u32 +gr_acl_handle_chown(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return generic_fs_handler(dentry, mnt, GR_WRITE, GR_CHOWN_ACL_MSG); +} + +__u32 +gr_acl_handle_execve(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return generic_fs_handler(dentry, mnt, GR_EXEC, GR_EXEC_ACL_MSG); +} + +__u32 +gr_acl_handle_unix(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return generic_fs_handler(dentry, mnt, GR_READ | GR_WRITE, + GR_UNIXCONNECT_ACL_MSG); +} + +/* hardlinks require at minimum create permission, + any additional privilege required is based on the + privilege of the file being linked to +*/ +__u32 +gr_acl_handle_link(const struct dentry * new_dentry, + const struct dentry * parent_dentry, + const struct vfsmount * parent_mnt, + const struct dentry * old_dentry, + const struct vfsmount * old_mnt, const char *to) +{ + __u32 mode; + __u32 needmode = GR_CREATE | GR_LINK; + __u32 needaudit = GR_AUDIT_CREATE | GR_AUDIT_LINK; + + mode = + gr_check_link(new_dentry, parent_dentry, parent_mnt, old_dentry, + old_mnt); + + if (unlikely(((mode & needmode) == needmode) && (mode & needaudit))) { + gr_log_fs_rbac_str(GR_DO_AUDIT, GR_LINK_ACL_MSG, old_dentry, old_mnt, to); + return mode; + } else if (unlikely(((mode & needmode) != needmode) && !(mode & GR_SUPPRESS))) { + gr_log_fs_rbac_str(GR_DONT_AUDIT, GR_LINK_ACL_MSG, old_dentry, old_mnt, to); + return 0; + } else if (unlikely((mode & needmode) != needmode)) + return 0; + + return 1; +} + +__u32 +gr_acl_handle_symlink(const struct dentry * new_dentry, + const struct dentry * parent_dentry, + const struct vfsmount * parent_mnt, const char *from) +{ + __u32 needmode = GR_WRITE | GR_CREATE; + __u32 mode; + + mode = + gr_check_create(new_dentry, parent_dentry, parent_mnt, + GR_CREATE | GR_AUDIT_CREATE | + GR_WRITE | GR_AUDIT_WRITE | GR_SUPPRESS); + + if (unlikely(mode & GR_WRITE && mode & GR_AUDITS)) { + gr_log_fs_str_rbac(GR_DO_AUDIT, GR_SYMLINK_ACL_MSG, from, new_dentry, parent_mnt); + return mode; + } else if (unlikely(((mode & needmode) != needmode) && !(mode & GR_SUPPRESS))) { + gr_log_fs_str_rbac(GR_DONT_AUDIT, GR_SYMLINK_ACL_MSG, from, new_dentry, parent_mnt); + return 0; + } else if (unlikely((mode & needmode) != needmode)) + return 0; + + return (GR_WRITE | GR_CREATE); +} + +static __u32 generic_fs_create_handler(const struct dentry *new_dentry, const struct dentry *parent_dentry, const struct vfsmount *parent_mnt, __u32 reqmode, const char *fmt) +{ + __u32 mode; + + mode = gr_check_create(new_dentry, parent_dentry, parent_mnt, reqmode | to_gr_audit(reqmode) | GR_SUPPRESS); + + if (unlikely(((mode & (reqmode)) == (reqmode)) && mode & GR_AUDITS)) { + gr_log_fs_rbac_generic(GR_DO_AUDIT, fmt, new_dentry, parent_mnt); + return mode; + } else if (unlikely((mode & (reqmode)) != (reqmode) && !(mode & GR_SUPPRESS))) { + gr_log_fs_rbac_generic(GR_DONT_AUDIT, fmt, new_dentry, parent_mnt); + return 0; + } else if (unlikely((mode & (reqmode)) != (reqmode))) + return 0; + + return (reqmode); +} + +__u32 +gr_acl_handle_mknod(const struct dentry * new_dentry, + const struct dentry * parent_dentry, + const struct vfsmount * parent_mnt, + const int mode) +{ + __u32 reqmode = GR_WRITE | GR_CREATE; + if (unlikely(mode & (S_ISUID | S_ISGID))) + reqmode |= GR_SETID; + + return generic_fs_create_handler(new_dentry, parent_dentry, parent_mnt, + reqmode, GR_MKNOD_ACL_MSG); +} + +__u32 +gr_acl_handle_mkdir(const struct dentry *new_dentry, + const struct dentry *parent_dentry, + const struct vfsmount *parent_mnt) +{ + return generic_fs_create_handler(new_dentry, parent_dentry, parent_mnt, + GR_WRITE | GR_CREATE, GR_MKDIR_ACL_MSG); +} + +#define RENAME_CHECK_SUCCESS(old, new) \ + (((old & (GR_WRITE | GR_READ)) == (GR_WRITE | GR_READ)) && \ + ((new & (GR_WRITE | GR_READ)) == (GR_WRITE | GR_READ))) + +int +gr_acl_handle_rename(struct dentry *new_dentry, + struct dentry *parent_dentry, + const struct vfsmount *parent_mnt, + struct dentry *old_dentry, + struct inode *old_parent_inode, + struct vfsmount *old_mnt, const char *newname) +{ + __u32 comp1, comp2; + int error = 0; + + if (unlikely(!gr_acl_is_enabled())) + return 0; + + if (!new_dentry->d_inode) { + comp1 = gr_check_create(new_dentry, parent_dentry, parent_mnt, + GR_READ | GR_WRITE | GR_CREATE | GR_AUDIT_READ | + GR_AUDIT_WRITE | GR_AUDIT_CREATE | GR_SUPPRESS); + comp2 = gr_search_file(old_dentry, GR_READ | GR_WRITE | + GR_DELETE | GR_AUDIT_DELETE | + GR_AUDIT_READ | GR_AUDIT_WRITE | + GR_SUPPRESS, old_mnt); + } else { + comp1 = gr_search_file(new_dentry, GR_READ | GR_WRITE | + GR_CREATE | GR_DELETE | + GR_AUDIT_CREATE | GR_AUDIT_DELETE | + GR_AUDIT_READ | GR_AUDIT_WRITE | + GR_SUPPRESS, parent_mnt); + comp2 = + gr_search_file(old_dentry, + GR_READ | GR_WRITE | GR_AUDIT_READ | + GR_DELETE | GR_AUDIT_DELETE | + GR_AUDIT_WRITE | GR_SUPPRESS, old_mnt); + } + + if (RENAME_CHECK_SUCCESS(comp1, comp2) && + ((comp1 & GR_AUDITS) || (comp2 & GR_AUDITS))) + gr_log_fs_rbac_str(GR_DO_AUDIT, GR_RENAME_ACL_MSG, old_dentry, old_mnt, newname); + else if (!RENAME_CHECK_SUCCESS(comp1, comp2) && !(comp1 & GR_SUPPRESS) + && !(comp2 & GR_SUPPRESS)) { + gr_log_fs_rbac_str(GR_DONT_AUDIT, GR_RENAME_ACL_MSG, old_dentry, old_mnt, newname); + error = -EACCES; + } else if (unlikely(!RENAME_CHECK_SUCCESS(comp1, comp2))) + error = -EACCES; + + return error; +} + +void +gr_acl_handle_exit(void) +{ + u16 id; + char *rolename; + struct file *exec_file; + + if (unlikely(current->acl_sp_role && gr_acl_is_enabled())) { + id = current->acl_role_id; + rolename = current->role->rolename; + gr_set_acls(1); + gr_log_str_int(GR_DONT_AUDIT_GOOD, GR_SPROLEL_ACL_MSG, rolename, id); + } + + write_lock(&grsec_exec_file_lock); + exec_file = current->exec_file; + current->exec_file = NULL; + write_unlock(&grsec_exec_file_lock); + + if (exec_file) + fput(exec_file); +} + +int +gr_acl_handle_procpidmem(const struct task_struct *task) +{ + if (unlikely(!gr_acl_is_enabled())) + return 0; + + if (task != current && task->acl->mode & GR_PROTPROCFD) + return -EACCES; + + return 0; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl_ip.c linux-2.6.27.15-g-v/grsecurity/gracl_ip.c --- linux-2.6.27.15/grsecurity/gracl_ip.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl_ip.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,313 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#define GR_BIND 0x01 +#define GR_CONNECT 0x02 +#define GR_INVERT 0x04 + +static const char * gr_protocols[256] = { + "ip", "icmp", "igmp", "ggp", "ipencap", "st", "tcp", "cbt", + "egp", "igp", "bbn-rcc", "nvp", "pup", "argus", "emcon", "xnet", + "chaos", "udp", "mux", "dcn", "hmp", "prm", "xns-idp", "trunk-1", + "trunk-2", "leaf-1", "leaf-2", "rdp", "irtp", "iso-tp4", "netblt", "mfe-nsp", + "merit-inp", "sep", "3pc", "idpr", "xtp", "ddp", "idpr-cmtp", "tp++", + "il", "ipv6", "sdrp", "ipv6-route", "ipv6-frag", "idrp", "rsvp", "gre", + "mhrp", "bna", "ipv6-crypt", "ipv6-auth", "i-nlsp", "swipe", "narp", "mobile", + "tlsp", "skip", "ipv6-icmp", "ipv6-nonxt", "ipv6-opts", "unknown:61", "cftp", "unknown:63", + "sat-expak", "kryptolan", "rvd", "ippc", "unknown:68", "sat-mon", "visa", "ipcv", + "cpnx", "cphb", "wsn", "pvp", "br-sat-mon", "sun-nd", "wb-mon", "wb-expak", + "iso-ip", "vmtp", "secure-vmtp", "vines", "ttp", "nfsnet-igp", "dgp", "tcf", + "eigrp", "ospf", "sprite-rpc", "larp", "mtp", "ax.25", "ipip", "micp", + "scc-sp", "etherip", "encap", "unknown:99", "gmtp", "ifmp", "pnni", "pim", + "aris", "scps", "qnx", "a/n", "ipcomp", "snp", "compaq-peer", "ipx-in-ip", + "vrrp", "pgm", "unknown:114", "l2tp", "ddx", "iatp", "stp", "srp", + "uti", "smp", "sm", "ptp", "isis", "fire", "crtp", "crdup", + "sscopmce", "iplt", "sps", "pipe", "sctp", "fc", "unkown:134", "unknown:135", + "unknown:136", "unknown:137", "unknown:138", "unknown:139", "unknown:140", "unknown:141", "unknown:142", "unknown:143", + "unknown:144", "unknown:145", "unknown:146", "unknown:147", "unknown:148", "unknown:149", "unknown:150", "unknown:151", + "unknown:152", "unknown:153", "unknown:154", "unknown:155", "unknown:156", "unknown:157", "unknown:158", "unknown:159", + "unknown:160", "unknown:161", "unknown:162", "unknown:163", "unknown:164", "unknown:165", "unknown:166", "unknown:167", + "unknown:168", "unknown:169", "unknown:170", "unknown:171", "unknown:172", "unknown:173", "unknown:174", "unknown:175", + "unknown:176", "unknown:177", "unknown:178", "unknown:179", "unknown:180", "unknown:181", "unknown:182", "unknown:183", + "unknown:184", "unknown:185", "unknown:186", "unknown:187", "unknown:188", "unknown:189", "unknown:190", "unknown:191", + "unknown:192", "unknown:193", "unknown:194", "unknown:195", "unknown:196", "unknown:197", "unknown:198", "unknown:199", + "unknown:200", "unknown:201", "unknown:202", "unknown:203", "unknown:204", "unknown:205", "unknown:206", "unknown:207", + "unknown:208", "unknown:209", "unknown:210", "unknown:211", "unknown:212", "unknown:213", "unknown:214", "unknown:215", + "unknown:216", "unknown:217", "unknown:218", "unknown:219", "unknown:220", "unknown:221", "unknown:222", "unknown:223", + "unknown:224", "unknown:225", "unknown:226", "unknown:227", "unknown:228", "unknown:229", "unknown:230", "unknown:231", + "unknown:232", "unknown:233", "unknown:234", "unknown:235", "unknown:236", "unknown:237", "unknown:238", "unknown:239", + "unknown:240", "unknown:241", "unknown:242", "unknown:243", "unknown:244", "unknown:245", "unknown:246", "unknown:247", + "unknown:248", "unknown:249", "unknown:250", "unknown:251", "unknown:252", "unknown:253", "unknown:254", "unknown:255", + }; + +static const char * gr_socktypes[11] = { + "unknown:0", "stream", "dgram", "raw", "rdm", "seqpacket", "unknown:6", + "unknown:7", "unknown:8", "unknown:9", "packet" + }; + +const char * +gr_proto_to_name(unsigned char proto) +{ + return gr_protocols[proto]; +} + +const char * +gr_socktype_to_name(unsigned char type) +{ + return gr_socktypes[type]; +} + +int +gr_search_socket(const int domain, const int type, const int protocol) +{ + struct acl_subject_label *curr; + + if (unlikely(!gr_acl_is_enabled())) + goto exit; + + if ((domain < 0) || (type < 0) || (protocol < 0) || (domain != PF_INET) + || (domain >= NPROTO) || (type >= SOCK_MAX) || (protocol > 255)) + goto exit; // let the kernel handle it + + curr = current->acl; + + if (!curr->ips) + goto exit; + + if ((curr->ip_type & (1 << type)) && + (curr->ip_proto[protocol / 32] & (1 << (protocol % 32)))) + goto exit; + + if (curr->mode & (GR_LEARN | GR_INHERITLEARN)) { + /* we don't place acls on raw sockets , and sometimes + dgram/ip sockets are opened for ioctl and not + bind/connect, so we'll fake a bind learn log */ + if (type == SOCK_RAW || type == SOCK_PACKET) { + __u32 fakeip = 0; + security_learn(GR_IP_LEARN_MSG, current->role->rolename, + current->role->roletype, current->uid, + current->gid, current->exec_file ? + gr_to_filename(current->exec_file->f_path.dentry, + current->exec_file->f_path.mnt) : + curr->filename, curr->filename, + NIPQUAD(fakeip), 0, type, + protocol, GR_CONNECT, +NIPQUAD(current->signal->curr_ip)); + } else if ((type == SOCK_DGRAM) && (protocol == IPPROTO_IP)) { + __u32 fakeip = 0; + security_learn(GR_IP_LEARN_MSG, current->role->rolename, + current->role->roletype, current->uid, + current->gid, current->exec_file ? + gr_to_filename(current->exec_file->f_path.dentry, + current->exec_file->f_path.mnt) : + curr->filename, curr->filename, + NIPQUAD(fakeip), 0, type, + protocol, GR_BIND, NIPQUAD(current->signal->curr_ip)); + } + /* we'll log when they use connect or bind */ + goto exit; + } + + gr_log_str3(GR_DONT_AUDIT, GR_SOCK_MSG, "inet", + gr_socktype_to_name(type), gr_proto_to_name(protocol)); + + return 0; + exit: + return 1; +} + +int check_ip_policy(struct acl_ip_label *ip, __u32 ip_addr, __u16 ip_port, __u8 protocol, const int mode, const int type, __u32 our_addr, __u32 our_netmask) +{ + if ((ip->mode & mode) && + (ip_port >= ip->low) && + (ip_port <= ip->high) && + ((ntohl(ip_addr) & our_netmask) == + (ntohl(our_addr) & our_netmask)) + && (ip->proto[protocol / 32] & (1 << (protocol % 32))) + && (ip->type & (1 << type))) { + if (ip->mode & GR_INVERT) + return 2; // specifically denied + else + return 1; // allowed + } + + return 0; // not specifically allowed, may continue parsing +} + +static int +gr_search_connectbind(const int mode, const struct sock *sk, + const struct sockaddr_in *addr, const int type) +{ + char iface[IFNAMSIZ] = {0}; + struct acl_subject_label *curr; + struct acl_ip_label *ip; + struct net_device *dev; + struct in_device *idev; + unsigned long i; + int ret; + __u32 ip_addr = 0; + __u32 our_addr; + __u32 our_netmask; + char *p; + __u16 ip_port = 0; + + if (unlikely(!gr_acl_is_enabled() || sk->sk_family != PF_INET)) + return 1; + + curr = current->acl; + + if (!curr->ips) + return 1; + + ip_addr = addr->sin_addr.s_addr; + ip_port = ntohs(addr->sin_port); + + if (curr->mode & (GR_LEARN | GR_INHERITLEARN)) { + security_learn(GR_IP_LEARN_MSG, current->role->rolename, + current->role->roletype, current->uid, + current->gid, current->exec_file ? + gr_to_filename(current->exec_file->f_path.dentry, + current->exec_file->f_path.mnt) : + curr->filename, curr->filename, + NIPQUAD(ip_addr), ip_port, type, + sk->sk_protocol, mode, NIPQUAD(current->signal->curr_ip)); + return 1; + } + + for (i = 0; i < curr->ip_num; i++) { + ip = *(curr->ips + i); + if (ip->iface != NULL) { + strncpy(iface, ip->iface, IFNAMSIZ - 1); + p = strchr(iface, ':'); + if (p != NULL) + *p = '\0'; + dev = dev_get_by_name(sock_net(sk), iface); + if (dev == NULL) + continue; + idev = in_dev_get(dev); + if (idev == NULL) { + dev_put(dev); + continue; + } + rcu_read_lock(); + for_ifa(idev) { + if (!strcmp(ip->iface, ifa->ifa_label)) { + our_addr = ifa->ifa_address; + our_netmask = 0xffffffff; + ret = check_ip_policy(ip, ip_addr, ip_port, sk->sk_protocol, mode, type, our_addr, our_netmask); + if (ret == 1) { + rcu_read_unlock(); + in_dev_put(idev); + dev_put(dev); + return 1; + } else if (ret == 2) { + rcu_read_unlock(); + in_dev_put(idev); + dev_put(dev); + goto denied; + } + } + } endfor_ifa(idev); + rcu_read_unlock(); + in_dev_put(idev); + dev_put(dev); + } else { + our_addr = ip->addr; + our_netmask = ip->netmask; + ret = check_ip_policy(ip, ip_addr, ip_port, sk->sk_protocol, mode, type, our_addr, our_netmask); + if (ret == 1) + return 1; + else if (ret == 2) + goto denied; + } + } + +denied: + if (mode == GR_BIND) + gr_log_int5_str2(GR_DONT_AUDIT, GR_BIND_ACL_MSG, NIPQUAD(ip_addr), ip_port, gr_socktype_to_name(type), gr_proto_to_name(sk->sk_protocol)); + else if (mode == GR_CONNECT) + gr_log_int5_str2(GR_DONT_AUDIT, GR_CONNECT_ACL_MSG, NIPQUAD(ip_addr), ip_port, gr_socktype_to_name(type), gr_proto_to_name(sk->sk_protocol)); + + return 0; +} + +int +gr_search_connect(const struct socket *sock, const struct sockaddr_in *addr) +{ + return gr_search_connectbind(GR_CONNECT, sock->sk, addr, sock->type); +} + +int +gr_search_bind(const struct socket *sock, const struct sockaddr_in *addr) +{ + return gr_search_connectbind(GR_BIND, sock->sk, addr, sock->type); +} + +int gr_search_listen(const struct socket *sock) +{ + struct sock *sk = sock->sk; + struct sockaddr_in addr; + + addr.sin_addr.s_addr = inet_sk(sk)->saddr; + addr.sin_port = inet_sk(sk)->sport; + + return gr_search_connectbind(GR_BIND, sock->sk, &addr, sock->type); +} + +int gr_search_accept(const struct socket *sock) +{ + struct sock *sk = sock->sk; + struct sockaddr_in addr; + + addr.sin_addr.s_addr = inet_sk(sk)->saddr; + addr.sin_port = inet_sk(sk)->sport; + + return gr_search_connectbind(GR_BIND, sock->sk, &addr, sock->type); +} + +int +gr_search_udp_sendmsg(const struct sock *sk, const struct sockaddr_in *addr) +{ + if (addr) + return gr_search_connectbind(GR_CONNECT, sk, addr, SOCK_DGRAM); + else { + struct sockaddr_in sin; + const struct inet_sock *inet = inet_sk(sk); + + sin.sin_addr.s_addr = inet->daddr; + sin.sin_port = inet->dport; + + return gr_search_connectbind(GR_CONNECT, sk, &sin, SOCK_DGRAM); + } +} + +int +gr_search_udp_recvmsg(const struct sock *sk, const struct sk_buff *skb) +{ + struct sockaddr_in sin; + + if (unlikely(skb->len < sizeof (struct udphdr))) + return 1; // skip this packet + + sin.sin_addr.s_addr = ip_hdr(skb)->saddr; + sin.sin_port = udp_hdr(skb)->source; + + return gr_search_connectbind(GR_CONNECT, sk, &sin, SOCK_DGRAM); +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl_learn.c linux-2.6.27.15-g-v/grsecurity/gracl_learn.c --- linux-2.6.27.15/grsecurity/gracl_learn.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl_learn.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,211 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +extern ssize_t write_grsec_handler(struct file * file, const char __user * buf, + size_t count, loff_t *ppos); +extern int gr_acl_is_enabled(void); + +static DECLARE_WAIT_QUEUE_HEAD(learn_wait); +static int gr_learn_attached; + +/* use a 512k buffer */ +#define LEARN_BUFFER_SIZE (512 * 1024) + +static DEFINE_SPINLOCK(gr_learn_lock); +static DECLARE_MUTEX(gr_learn_user_sem); + +/* we need to maintain two buffers, so that the kernel context of grlearn + uses a semaphore around the userspace copying, and the other kernel contexts + use a spinlock when copying into the buffer, since they cannot sleep +*/ +static char *learn_buffer; +static char *learn_buffer_user; +static int learn_buffer_len; +static int learn_buffer_user_len; + +static ssize_t +read_learn(struct file *file, char __user * buf, size_t count, loff_t * ppos) +{ + DECLARE_WAITQUEUE(wait, current); + ssize_t retval = 0; + + add_wait_queue(&learn_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + do { + down(&gr_learn_user_sem); + spin_lock(&gr_learn_lock); + if (learn_buffer_len) + break; + spin_unlock(&gr_learn_lock); + up(&gr_learn_user_sem); + if (file->f_flags & O_NONBLOCK) { + retval = -EAGAIN; + goto out; + } + if (signal_pending(current)) { + retval = -ERESTARTSYS; + goto out; + } + + schedule(); + } while (1); + + memcpy(learn_buffer_user, learn_buffer, learn_buffer_len); + learn_buffer_user_len = learn_buffer_len; + retval = learn_buffer_len; + learn_buffer_len = 0; + + spin_unlock(&gr_learn_lock); + + if (copy_to_user(buf, learn_buffer_user, learn_buffer_user_len)) + retval = -EFAULT; + + up(&gr_learn_user_sem); +out: + set_current_state(TASK_RUNNING); + remove_wait_queue(&learn_wait, &wait); + return retval; +} + +static unsigned int +poll_learn(struct file * file, poll_table * wait) +{ + poll_wait(file, &learn_wait, wait); + + if (learn_buffer_len) + return (POLLIN | POLLRDNORM); + + return 0; +} + +void +gr_clear_learn_entries(void) +{ + char *tmp; + + down(&gr_learn_user_sem); + if (learn_buffer != NULL) { + spin_lock(&gr_learn_lock); + tmp = learn_buffer; + learn_buffer = NULL; + spin_unlock(&gr_learn_lock); + vfree(learn_buffer); + } + if (learn_buffer_user != NULL) { + vfree(learn_buffer_user); + learn_buffer_user = NULL; + } + learn_buffer_len = 0; + up(&gr_learn_user_sem); + + return; +} + +void +gr_add_learn_entry(const char *fmt, ...) +{ + va_list args; + unsigned int len; + + if (!gr_learn_attached) + return; + + spin_lock(&gr_learn_lock); + + /* leave a gap at the end so we know when it's "full" but don't have to + compute the exact length of the string we're trying to append + */ + if (learn_buffer_len > LEARN_BUFFER_SIZE - 16384) { + spin_unlock(&gr_learn_lock); + wake_up_interruptible(&learn_wait); + return; + } + if (learn_buffer == NULL) { + spin_unlock(&gr_learn_lock); + return; + } + + va_start(args, fmt); + len = vsnprintf(learn_buffer + learn_buffer_len, LEARN_BUFFER_SIZE - learn_buffer_len, fmt, args); + va_end(args); + + learn_buffer_len += len + 1; + + spin_unlock(&gr_learn_lock); + wake_up_interruptible(&learn_wait); + + return; +} + +static int +open_learn(struct inode *inode, struct file *file) +{ + if (file->f_mode & FMODE_READ && gr_learn_attached) + return -EBUSY; + if (file->f_mode & FMODE_READ) { + int retval = 0; + down(&gr_learn_user_sem); + if (learn_buffer == NULL) + learn_buffer = vmalloc(LEARN_BUFFER_SIZE); + if (learn_buffer_user == NULL) + learn_buffer_user = vmalloc(LEARN_BUFFER_SIZE); + if (learn_buffer == NULL) { + retval = -ENOMEM; + goto out_error; + } + if (learn_buffer_user == NULL) { + retval = -ENOMEM; + goto out_error; + } + learn_buffer_len = 0; + learn_buffer_user_len = 0; + gr_learn_attached = 1; +out_error: + up(&gr_learn_user_sem); + return retval; + } + return 0; +} + +static int +close_learn(struct inode *inode, struct file *file) +{ + char *tmp; + + if (file->f_mode & FMODE_READ) { + down(&gr_learn_user_sem); + if (learn_buffer != NULL) { + spin_lock(&gr_learn_lock); + tmp = learn_buffer; + learn_buffer = NULL; + spin_unlock(&gr_learn_lock); + vfree(tmp); + } + if (learn_buffer_user != NULL) { + vfree(learn_buffer_user); + learn_buffer_user = NULL; + } + learn_buffer_len = 0; + learn_buffer_user_len = 0; + gr_learn_attached = 0; + up(&gr_learn_user_sem); + } + + return 0; +} + +struct file_operations grsec_fops = { + .read = read_learn, + .write = write_grsec_handler, + .open = open_learn, + .release = close_learn, + .poll = poll_learn, +}; diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl_res.c linux-2.6.27.15-g-v/grsecurity/gracl_res.c --- linux-2.6.27.15/grsecurity/gracl_res.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl_res.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,45 @@ +#include +#include +#include +#include + +static const char *restab_log[] = { + [RLIMIT_CPU] = "RLIMIT_CPU", + [RLIMIT_FSIZE] = "RLIMIT_FSIZE", + [RLIMIT_DATA] = "RLIMIT_DATA", + [RLIMIT_STACK] = "RLIMIT_STACK", + [RLIMIT_CORE] = "RLIMIT_CORE", + [RLIMIT_RSS] = "RLIMIT_RSS", + [RLIMIT_NPROC] = "RLIMIT_NPROC", + [RLIMIT_NOFILE] = "RLIMIT_NOFILE", + [RLIMIT_MEMLOCK] = "RLIMIT_MEMLOCK", + [RLIMIT_AS] = "RLIMIT_AS", + [RLIMIT_LOCKS] = "RLIMIT_LOCKS", + [RLIMIT_LOCKS + 1] = "RLIMIT_CRASH" +}; + +void +gr_log_resource(const struct task_struct *task, + const int res, const unsigned long wanted, const int gt) +{ + if (res == RLIMIT_NPROC && + (cap_raised(task->cap_effective, CAP_SYS_ADMIN) || + cap_raised(task->cap_effective, CAP_SYS_RESOURCE))) + return; + else if (res == RLIMIT_MEMLOCK && + cap_raised(task->cap_effective, CAP_IPC_LOCK)) + return; + + if (!gr_acl_is_enabled() && !grsec_resource_logging) + return; + + preempt_disable(); + + if (unlikely(((gt && wanted > task->signal->rlim[res].rlim_cur) || + (!gt && wanted >= task->signal->rlim[res].rlim_cur)) && + task->signal->rlim[res].rlim_cur != RLIM_INFINITY)) + gr_log_res_ulong2_str(GR_DONT_AUDIT, GR_RESOURCE_MSG, task, wanted, restab_log[res], task->signal->rlim[res].rlim_cur); + preempt_enable_no_resched(); + + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl_segv.c linux-2.6.27.15-g-v/grsecurity/gracl_segv.c --- linux-2.6.27.15/grsecurity/gracl_segv.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl_segv.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,304 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +static struct crash_uid *uid_set; +static unsigned short uid_used; +static DEFINE_SPINLOCK(gr_uid_lock); +extern rwlock_t gr_inode_lock; +extern struct acl_subject_label * + lookup_acl_subj_label(const ino_t inode, const dev_t dev, + struct acl_role_label *role); +extern int specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t); + +int +gr_init_uidset(void) +{ + uid_set = + kmalloc(GR_UIDTABLE_MAX * sizeof (struct crash_uid), GFP_KERNEL); + uid_used = 0; + + return uid_set ? 1 : 0; +} + +void +gr_free_uidset(void) +{ + if (uid_set) + kfree(uid_set); + + return; +} + +int +gr_find_uid(const uid_t uid) +{ + struct crash_uid *tmp = uid_set; + uid_t buid; + int low = 0, high = uid_used - 1, mid; + + while (high >= low) { + mid = (low + high) >> 1; + buid = tmp[mid].uid; + if (buid == uid) + return mid; + if (buid > uid) + high = mid - 1; + if (buid < uid) + low = mid + 1; + } + + return -1; +} + +static __inline__ void +gr_insertsort(void) +{ + unsigned short i, j; + struct crash_uid index; + + for (i = 1; i < uid_used; i++) { + index = uid_set[i]; + j = i; + while ((j > 0) && uid_set[j - 1].uid > index.uid) { + uid_set[j] = uid_set[j - 1]; + j--; + } + uid_set[j] = index; + } + + return; +} + +static __inline__ void +gr_insert_uid(const uid_t uid, const unsigned long expires) +{ + int loc; + + if (uid_used == GR_UIDTABLE_MAX) + return; + + loc = gr_find_uid(uid); + + if (loc >= 0) { + uid_set[loc].expires = expires; + return; + } + + uid_set[uid_used].uid = uid; + uid_set[uid_used].expires = expires; + uid_used++; + + gr_insertsort(); + + return; +} + +void +gr_remove_uid(const unsigned short loc) +{ + unsigned short i; + + for (i = loc + 1; i < uid_used; i++) + uid_set[i - 1] = uid_set[i]; + + uid_used--; + + return; +} + +int +gr_check_crash_uid(const uid_t uid) +{ + int loc; + int ret = 0; + + if (unlikely(!gr_acl_is_enabled())) + return 0; + + spin_lock(&gr_uid_lock); + loc = gr_find_uid(uid); + + if (loc < 0) + goto out_unlock; + + if (time_before_eq(uid_set[loc].expires, get_seconds())) + gr_remove_uid(loc); + else + ret = 1; + +out_unlock: + spin_unlock(&gr_uid_lock); + return ret; +} + +static __inline__ int +proc_is_setxid(const struct task_struct *task) +{ + if (task->uid != task->euid || task->uid != task->suid || + task->uid != task->fsuid) + return 1; + if (task->gid != task->egid || task->gid != task->sgid || + task->gid != task->fsgid) + return 1; + + return 0; +} +static __inline__ int +gr_fake_force_sig(int sig, struct task_struct *t) +{ + unsigned long int flags; + int ret, blocked, ignored; + struct k_sigaction *action; + + spin_lock_irqsave(&t->sighand->siglock, flags); + action = &t->sighand->action[sig-1]; + ignored = action->sa.sa_handler == SIG_IGN; + blocked = sigismember(&t->blocked, sig); + if (blocked || ignored) { + action->sa.sa_handler = SIG_DFL; + if (blocked) { + sigdelset(&t->blocked, sig); + recalc_sigpending_and_wake(t); + } + } + if (action->sa.sa_handler == SIG_DFL) + t->signal->flags &= ~SIGNAL_UNKILLABLE; + ret = specific_send_sig_info(sig, SEND_SIG_PRIV, t); + + spin_unlock_irqrestore(&t->sighand->siglock, flags); + + return ret; +} + +void +gr_handle_crash(struct task_struct *task, const int sig) +{ + struct acl_subject_label *curr; + struct acl_subject_label *curr2; + struct task_struct *tsk, *tsk2; + + if (sig != SIGSEGV && sig != SIGKILL && sig != SIGBUS && sig != SIGILL) + return; + + if (unlikely(!gr_acl_is_enabled())) + return; + + curr = task->acl; + + if (!(curr->resmask & (1 << GR_CRASH_RES))) + return; + + if (time_before_eq(curr->expires, get_seconds())) { + curr->expires = 0; + curr->crashes = 0; + } + + curr->crashes++; + + if (!curr->expires) + curr->expires = get_seconds() + curr->res[GR_CRASH_RES].rlim_max; + + if ((curr->crashes >= curr->res[GR_CRASH_RES].rlim_cur) && + time_after(curr->expires, get_seconds())) { + if (task->uid && proc_is_setxid(task)) { + gr_log_crash1(GR_DONT_AUDIT, GR_SEGVSTART_ACL_MSG, task, curr->res[GR_CRASH_RES].rlim_max); + spin_lock(&gr_uid_lock); + gr_insert_uid(task->uid, curr->expires); + spin_unlock(&gr_uid_lock); + curr->expires = 0; + curr->crashes = 0; + read_lock(&tasklist_lock); + do_each_thread(tsk2, tsk) { + if (tsk != task && tsk->uid == task->uid) + gr_fake_force_sig(SIGKILL, tsk); + } while_each_thread(tsk2, tsk); + read_unlock(&tasklist_lock); + } else { + gr_log_crash2(GR_DONT_AUDIT, GR_SEGVNOSUID_ACL_MSG, task, curr->res[GR_CRASH_RES].rlim_max); + read_lock(&tasklist_lock); + do_each_thread(tsk2, tsk) { + if (likely(tsk != task)) { + curr2 = tsk->acl; + + if (curr2->device == curr->device && + curr2->inode == curr->inode) + gr_fake_force_sig(SIGKILL, tsk); + } + } while_each_thread(tsk2, tsk); + read_unlock(&tasklist_lock); + } + } + + return; +} + +int +gr_check_crash_exec(const struct file *filp) +{ + struct acl_subject_label *curr; + + if (unlikely(!gr_acl_is_enabled())) + return 0; + + read_lock(&gr_inode_lock); + curr = lookup_acl_subj_label(filp->f_path.dentry->d_inode->i_ino, + filp->f_path.dentry->d_inode->i_sb->s_dev, + current->role); + read_unlock(&gr_inode_lock); + + if (!curr || !(curr->resmask & (1 << GR_CRASH_RES)) || + (!curr->crashes && !curr->expires)) + return 0; + + if ((curr->crashes >= curr->res[GR_CRASH_RES].rlim_cur) && + time_after(curr->expires, get_seconds())) + return 1; + else if (time_before_eq(curr->expires, get_seconds())) { + curr->crashes = 0; + curr->expires = 0; + } + + return 0; +} + +void +gr_handle_alertkill(struct task_struct *task) +{ + struct acl_subject_label *curracl; + __u32 curr_ip; + struct task_struct *p, *p2; + + if (unlikely(!gr_acl_is_enabled())) + return; + + curracl = task->acl; + curr_ip = task->signal->curr_ip; + + if ((curracl->mode & GR_KILLIPPROC) && curr_ip) { + read_lock(&tasklist_lock); + do_each_thread(p2, p) { + if (p->signal->curr_ip == curr_ip) + gr_fake_force_sig(SIGKILL, p); + } while_each_thread(p2, p); + read_unlock(&tasklist_lock); + } else if (curracl->mode & GR_KILLPROC) + gr_fake_force_sig(SIGKILL, task); + + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/gracl_shm.c linux-2.6.27.15-g-v/grsecurity/gracl_shm.c --- linux-2.6.27.15/grsecurity/gracl_shm.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/gracl_shm.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,33 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int +gr_handle_shmat(const pid_t shm_cprid, const pid_t shm_lapid, + const time_t shm_createtime, const uid_t cuid, const int shmid) +{ + struct task_struct *task; + + if (!gr_acl_is_enabled()) + return 1; + + task = find_task_by_vpid(shm_cprid); + + if (unlikely(!task)) + task = find_task_by_vpid(shm_lapid); + + if (unlikely(task && (time_before_eq((unsigned long)task->start_time.tv_sec, (unsigned long)shm_createtime) || + (task->pid == shm_lapid)) && + (task->acl->mode & GR_PROTSHM) && + (task->acl != current->acl))) { + gr_log_int3(GR_DONT_AUDIT, GR_SHMAT_ACL_MSG, cuid, shm_cprid, shmid); + return 0; + } + + return 1; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_chdir.c linux-2.6.27.15-g-v/grsecurity/grsec_chdir.c --- linux-2.6.27.15/grsecurity/grsec_chdir.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_chdir.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,19 @@ +#include +#include +#include +#include +#include +#include + +void +gr_log_chdir(const struct dentry *dentry, const struct vfsmount *mnt) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_CHDIR + if ((grsec_enable_chdir && grsec_enable_group && + in_group_p(grsec_audit_gid)) || (grsec_enable_chdir && + !grsec_enable_group)) { + gr_log_fs_generic(GR_DO_AUDIT, GR_CHDIR_AUDIT_MSG, dentry, mnt); + } +#endif + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_chroot.c linux-2.6.27.15-g-v/grsecurity/grsec_chroot.c --- linux-2.6.27.15/grsecurity/grsec_chroot.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_chroot.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,336 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +int +gr_handle_chroot_unix(const pid_t pid) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_UNIX + struct pid *spid = NULL; + + if (unlikely(!grsec_enable_chroot_unix)) + return 1; + + if (likely(!proc_is_chrooted(current))) + return 1; + + read_lock(&tasklist_lock); + + spid = find_vpid(pid); + if (spid) { + struct task_struct *p; + p = pid_task(spid, PIDTYPE_PID); + task_lock(p); + if (unlikely(!have_same_root(current, p))) { + task_unlock(p); + read_unlock(&tasklist_lock); + gr_log_noargs(GR_DONT_AUDIT, GR_UNIX_CHROOT_MSG); + return 0; + } + task_unlock(p); + } + read_unlock(&tasklist_lock); +#endif + return 1; +} + +int +gr_handle_chroot_nice(void) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_NICE + if (grsec_enable_chroot_nice && proc_is_chrooted(current)) { + gr_log_noargs(GR_DONT_AUDIT, GR_NICE_CHROOT_MSG); + return -EPERM; + } +#endif + return 0; +} + +int +gr_handle_chroot_setpriority(struct task_struct *p, const int niceval) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_NICE + if (grsec_enable_chroot_nice && (niceval < task_nice(p)) + && proc_is_chrooted(current)) { + gr_log_str_int(GR_DONT_AUDIT, GR_PRIORITY_CHROOT_MSG, p->comm, p->pid); + return -EACCES; + } +#endif + return 0; +} + +int +gr_handle_chroot_rawio(const struct inode *inode) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_CAPS + if (grsec_enable_chroot_caps && proc_is_chrooted(current) && + inode && S_ISBLK(inode->i_mode) && !capable(CAP_SYS_RAWIO)) + return 1; +#endif + return 0; +} + +int +gr_pid_is_chrooted(struct task_struct *p) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_FINDTASK + if (!grsec_enable_chroot_findtask || !proc_is_chrooted(current) || p == NULL) + return 0; + + task_lock(p); + if ((p->exit_state & (EXIT_ZOMBIE | EXIT_DEAD)) || + !have_same_root(current, p)) { + task_unlock(p); + return 1; + } + task_unlock(p); +#endif + return 0; +} + +EXPORT_SYMBOL(gr_pid_is_chrooted); + +#if defined(CONFIG_GRKERNSEC_CHROOT_DOUBLE) || defined(CONFIG_GRKERNSEC_CHROOT_FCHDIR) +int gr_is_outside_chroot(const struct dentry *u_dentry, const struct vfsmount *u_mnt) +{ + struct dentry *dentry = (struct dentry *)u_dentry; + struct vfsmount *mnt = (struct vfsmount *)u_mnt; + struct dentry *realroot; + struct vfsmount *realrootmnt; + struct dentry *currentroot; + struct vfsmount *currentmnt; + struct task_struct *reaper = current->nsproxy->pid_ns->child_reaper; + int ret = 1; + + read_lock(&reaper->fs->lock); + realrootmnt = mntget(reaper->fs->root.mnt); + realroot = dget(reaper->fs->root.dentry); + read_unlock(&reaper->fs->lock); + + read_lock(¤t->fs->lock); + currentmnt = mntget(current->fs->root.mnt); + currentroot = dget(current->fs->root.dentry); + read_unlock(¤t->fs->lock); + + spin_lock(&dcache_lock); + for (;;) { + if (unlikely((dentry == realroot && mnt == realrootmnt) + || (dentry == currentroot && mnt == currentmnt))) + break; + if (unlikely(dentry == mnt->mnt_root || IS_ROOT(dentry))) { + if (mnt->mnt_parent == mnt) + break; + dentry = mnt->mnt_mountpoint; + mnt = mnt->mnt_parent; + continue; + } + dentry = dentry->d_parent; + } + spin_unlock(&dcache_lock); + + dput(currentroot); + mntput(currentmnt); + + /* access is outside of chroot */ + if (dentry == realroot && mnt == realrootmnt) + ret = 0; + + dput(realroot); + mntput(realrootmnt); + return ret; +} +#endif + +int +gr_chroot_fchdir(struct dentry *u_dentry, struct vfsmount *u_mnt) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_FCHDIR + if (!grsec_enable_chroot_fchdir) + return 1; + + if (!proc_is_chrooted(current)) + return 1; + else if (!gr_is_outside_chroot(u_dentry, u_mnt)) { + gr_log_fs_generic(GR_DONT_AUDIT, GR_CHROOT_FCHDIR_MSG, u_dentry, u_mnt); + return 0; + } +#endif + return 1; +} + +int +gr_chroot_shmat(const pid_t shm_cprid, const pid_t shm_lapid, + const time_t shm_createtime) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_SHMAT + struct pid *pid = NULL; + time_t starttime; + + if (unlikely(!grsec_enable_chroot_shmat)) + return 1; + + if (likely(!proc_is_chrooted(current))) + return 1; + + read_lock(&tasklist_lock); + + pid = find_vpid(shm_cprid); + if (pid) { + struct task_struct *p; + p = pid_task(pid, PIDTYPE_PID); + task_lock(p); + starttime = p->start_time.tv_sec; + if (unlikely(!have_same_root(current, p) && + time_before_eq((unsigned long)starttime, (unsigned long)shm_createtime))) { + task_unlock(p); + read_unlock(&tasklist_lock); + gr_log_noargs(GR_DONT_AUDIT, GR_SHMAT_CHROOT_MSG); + return 0; + } + task_unlock(p); + } else { + pid = find_vpid(shm_lapid); + if (pid) { + struct task_struct *p; + p = pid_task(pid, PIDTYPE_PID); + task_lock(p); + if (unlikely(!have_same_root(current, p))) { + task_unlock(p); + read_unlock(&tasklist_lock); + gr_log_noargs(GR_DONT_AUDIT, GR_SHMAT_CHROOT_MSG); + return 0; + } + task_unlock(p); + } + } + + read_unlock(&tasklist_lock); +#endif + return 1; +} + +void +gr_log_chroot_exec(const struct dentry *dentry, const struct vfsmount *mnt) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_EXECLOG + if (grsec_enable_chroot_execlog && proc_is_chrooted(current)) + gr_log_fs_generic(GR_DO_AUDIT, GR_EXEC_CHROOT_MSG, dentry, mnt); +#endif + return; +} + +int +gr_handle_chroot_mknod(const struct dentry *dentry, + const struct vfsmount *mnt, const int mode) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_MKNOD + if (grsec_enable_chroot_mknod && !S_ISFIFO(mode) && !S_ISREG(mode) && + proc_is_chrooted(current)) { + gr_log_fs_generic(GR_DONT_AUDIT, GR_MKNOD_CHROOT_MSG, dentry, mnt); + return -EPERM; + } +#endif + return 0; +} + +int +gr_handle_chroot_mount(const struct dentry *dentry, + const struct vfsmount *mnt, const char *dev_name) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_MOUNT + if (grsec_enable_chroot_mount && proc_is_chrooted(current)) { + gr_log_str_fs(GR_DONT_AUDIT, GR_MOUNT_CHROOT_MSG, dev_name, dentry, mnt); + return -EPERM; + } +#endif + return 0; +} + +int +gr_handle_chroot_pivot(void) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_PIVOT + if (grsec_enable_chroot_pivot && proc_is_chrooted(current)) { + gr_log_noargs(GR_DONT_AUDIT, GR_PIVOT_CHROOT_MSG); + return -EPERM; + } +#endif + return 0; +} + +int +gr_handle_chroot_chroot(const struct dentry *dentry, const struct vfsmount *mnt) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_DOUBLE + if (grsec_enable_chroot_double && proc_is_chrooted(current) && + !gr_is_outside_chroot(dentry, mnt)) { + gr_log_fs_generic(GR_DONT_AUDIT, GR_CHROOT_CHROOT_MSG, dentry, mnt); + return -EPERM; + } +#endif + return 0; +} + +void +gr_handle_chroot_caps(struct task_struct *task) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_CAPS + if (grsec_enable_chroot_caps && proc_is_chrooted(task)) { + kernel_cap_t chroot_caps = GR_CHROOT_CAPS; + task->cap_permitted = + cap_drop(task->cap_permitted, chroot_caps); + task->cap_inheritable = + cap_drop(task->cap_inheritable, chroot_caps); + task->cap_effective = + cap_drop(task->cap_effective, chroot_caps); + } +#endif + return; +} + +int +gr_handle_chroot_sysctl(const int op) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_SYSCTL + if (grsec_enable_chroot_sysctl && proc_is_chrooted(current) + && (op & MAY_WRITE)) + return -EACCES; +#endif + return 0; +} + +void +gr_handle_chroot_chdir(struct path *path) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_CHDIR + if (grsec_enable_chroot_chdir) + set_fs_pwd(current->fs, path); +#endif + return; +} + +int +gr_handle_chroot_chmod(const struct dentry *dentry, + const struct vfsmount *mnt, const int mode) +{ +#ifdef CONFIG_GRKERNSEC_CHROOT_CHMOD + if (grsec_enable_chroot_chmod && + ((mode & S_ISUID) || ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP))) && + proc_is_chrooted(current)) { + gr_log_fs_generic(GR_DONT_AUDIT, GR_CHMOD_CHROOT_MSG, dentry, mnt); + return -EPERM; + } +#endif + return 0; +} + +#ifdef CONFIG_SECURITY +EXPORT_SYMBOL(gr_handle_chroot_caps); +#endif diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_disabled.c linux-2.6.27.15-g-v/grsecurity/grsec_disabled.c --- linux-2.6.27.15/grsecurity/grsec_disabled.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_disabled.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,418 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_PAX_HAVE_ACL_FLAGS +void +pax_set_initial_flags(struct linux_binprm *bprm) +{ + return; +} +#endif + +#ifdef CONFIG_SYSCTL +__u32 +gr_handle_sysctl(const struct ctl_table * table, const int op) +{ + return 0; +} +#endif + +int +gr_acl_is_enabled(void) +{ + return 0; +} + +int +gr_handle_rawio(const struct inode *inode) +{ + return 0; +} + +void +gr_acl_handle_psacct(struct task_struct *task, const long code) +{ + return; +} + +int +gr_handle_ptrace(struct task_struct *task, const long request) +{ + return 0; +} + +int +gr_handle_proc_ptrace(struct task_struct *task) +{ + return 0; +} + +void +gr_learn_resource(const struct task_struct *task, + const int res, const unsigned long wanted, const int gt) +{ + return; +} + +int +gr_set_acls(const int type) +{ + return 0; +} + +int +gr_check_hidden_task(const struct task_struct *tsk) +{ + return 0; +} + +int +gr_check_protected_task(const struct task_struct *task) +{ + return 0; +} + +void +gr_copy_label(struct task_struct *tsk) +{ + return; +} + +void +gr_set_pax_flags(struct task_struct *task) +{ + return; +} + +int +gr_set_proc_label(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return 0; +} + +void +gr_handle_delete(const ino_t ino, const dev_t dev) +{ + return; +} + +void +gr_handle_create(const struct dentry *dentry, const struct vfsmount *mnt) +{ + return; +} + +void +gr_handle_crash(struct task_struct *task, const int sig) +{ + return; +} + +int +gr_check_crash_exec(const struct file *filp) +{ + return 0; +} + +int +gr_check_crash_uid(const uid_t uid) +{ + return 0; +} + +void +gr_handle_rename(struct inode *old_dir, struct inode *new_dir, + struct dentry *old_dentry, + struct dentry *new_dentry, + struct vfsmount *mnt, const __u8 replace) +{ + return; +} + +int +gr_search_socket(const int family, const int type, const int protocol) +{ + return 1; +} + +int +gr_search_connectbind(const int mode, const struct socket *sock, + const struct sockaddr_in *addr) +{ + return 1; +} + +int +gr_task_is_capable(struct task_struct *task, const int cap) +{ + return 1; +} + +int +gr_is_capable_nolog(const int cap) +{ + return 1; +} + +void +gr_handle_alertkill(struct task_struct *task) +{ + return; +} + +__u32 +gr_acl_handle_execve(const struct dentry * dentry, const struct vfsmount * mnt) +{ + return 1; +} + +__u32 +gr_acl_handle_hidden_file(const struct dentry * dentry, + const struct vfsmount * mnt) +{ + return 1; +} + +__u32 +gr_acl_handle_open(const struct dentry * dentry, const struct vfsmount * mnt, + const int fmode) +{ + return 1; +} + +__u32 +gr_acl_handle_rmdir(const struct dentry * dentry, const struct vfsmount * mnt) +{ + return 1; +} + +__u32 +gr_acl_handle_unlink(const struct dentry * dentry, const struct vfsmount * mnt) +{ + return 1; +} + +int +gr_acl_handle_mmap(const struct file *file, const unsigned long prot, + unsigned int *vm_flags) +{ + return 1; +} + +__u32 +gr_acl_handle_truncate(const struct dentry * dentry, + const struct vfsmount * mnt) +{ + return 1; +} + +__u32 +gr_acl_handle_utime(const struct dentry * dentry, const struct vfsmount * mnt) +{ + return 1; +} + +__u32 +gr_acl_handle_access(const struct dentry * dentry, + const struct vfsmount * mnt, const int fmode) +{ + return 1; +} + +__u32 +gr_acl_handle_fchmod(const struct dentry * dentry, const struct vfsmount * mnt, + mode_t mode) +{ + return 1; +} + +__u32 +gr_acl_handle_chmod(const struct dentry * dentry, const struct vfsmount * mnt, + mode_t mode) +{ + return 1; +} + +__u32 +gr_acl_handle_chown(const struct dentry * dentry, const struct vfsmount * mnt) +{ + return 1; +} + +void +grsecurity_init(void) +{ + return; +} + +__u32 +gr_acl_handle_mknod(const struct dentry * new_dentry, + const struct dentry * parent_dentry, + const struct vfsmount * parent_mnt, + const int mode) +{ + return 1; +} + +__u32 +gr_acl_handle_mkdir(const struct dentry * new_dentry, + const struct dentry * parent_dentry, + const struct vfsmount * parent_mnt) +{ + return 1; +} + +__u32 +gr_acl_handle_symlink(const struct dentry * new_dentry, + const struct dentry * parent_dentry, + const struct vfsmount * parent_mnt, const char *from) +{ + return 1; +} + +__u32 +gr_acl_handle_link(const struct dentry * new_dentry, + const struct dentry * parent_dentry, + const struct vfsmount * parent_mnt, + const struct dentry * old_dentry, + const struct vfsmount * old_mnt, const char *to) +{ + return 1; +} + +int +gr_acl_handle_rename(const struct dentry *new_dentry, + const struct dentry *parent_dentry, + const struct vfsmount *parent_mnt, + const struct dentry *old_dentry, + const struct inode *old_parent_inode, + const struct vfsmount *old_mnt, const char *newname) +{ + return 0; +} + +int +gr_acl_handle_filldir(const struct file *file, const char *name, + const int namelen, const ino_t ino) +{ + return 1; +} + +int +gr_handle_shmat(const pid_t shm_cprid, const pid_t shm_lapid, + const time_t shm_createtime, const uid_t cuid, const int shmid) +{ + return 1; +} + +int +gr_search_bind(const struct socket *sock, const struct sockaddr_in *addr) +{ + return 1; +} + +int +gr_search_accept(const struct socket *sock) +{ + return 1; +} + +int +gr_search_listen(const struct socket *sock) +{ + return 1; +} + +int +gr_search_connect(const struct socket *sock, const struct sockaddr_in *addr) +{ + return 1; +} + +__u32 +gr_acl_handle_unix(const struct dentry * dentry, const struct vfsmount * mnt) +{ + return 1; +} + +__u32 +gr_acl_handle_creat(const struct dentry * dentry, + const struct dentry * p_dentry, + const struct vfsmount * p_mnt, const int fmode, + const int imode) +{ + return 1; +} + +void +gr_acl_handle_exit(void) +{ + return; +} + +int +gr_acl_handle_mprotect(const struct file *file, const unsigned long prot) +{ + return 1; +} + +void +gr_set_role_label(const uid_t uid, const gid_t gid) +{ + return; +} + +int +gr_acl_handle_procpidmem(const struct task_struct *task) +{ + return 0; +} + +int +gr_search_udp_recvmsg(const struct sock *sk, const struct sk_buff *skb) +{ + return 1; +} + +int +gr_search_udp_sendmsg(const struct sock *sk, const struct sockaddr_in *addr) +{ + return 1; +} + +void +gr_set_kernel_label(struct task_struct *task) +{ + return; +} + +int +gr_check_user_change(int real, int effective, int fs) +{ + return 0; +} + +int +gr_check_group_change(int real, int effective, int fs) +{ + return 0; +} + + +EXPORT_SYMBOL(gr_task_is_capable); +EXPORT_SYMBOL(gr_is_capable_nolog); +EXPORT_SYMBOL(gr_learn_resource); +EXPORT_SYMBOL(gr_set_kernel_label); +#ifdef CONFIG_SECURITY +EXPORT_SYMBOL(gr_check_user_change); +EXPORT_SYMBOL(gr_check_group_change); +#endif diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_exec.c linux-2.6.27.15-g-v/grsecurity/grsec_exec.c --- linux-2.6.27.15/grsecurity/grsec_exec.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_exec.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,88 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#ifdef CONFIG_GRKERNSEC_EXECLOG +static char gr_exec_arg_buf[132]; +static DECLARE_MUTEX(gr_exec_arg_sem); +#endif + +int +gr_handle_nproc(void) +{ +#ifdef CONFIG_GRKERNSEC_EXECVE + if (grsec_enable_execve && current->user && + (atomic_read(¤t->user->processes) > + current->signal->rlim[RLIMIT_NPROC].rlim_cur) && + !capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE)) { + gr_log_noargs(GR_DONT_AUDIT, GR_NPROC_MSG); + return -EAGAIN; + } +#endif + return 0; +} + +void +gr_handle_exec_args(struct linux_binprm *bprm, const char __user *__user *argv) +{ +#ifdef CONFIG_GRKERNSEC_EXECLOG + char *grarg = gr_exec_arg_buf; + unsigned int i, x, execlen = 0; + char c; + + if (!((grsec_enable_execlog && grsec_enable_group && + in_group_p(grsec_audit_gid)) + || (grsec_enable_execlog && !grsec_enable_group))) + return; + + down(&gr_exec_arg_sem); + memset(grarg, 0, sizeof(gr_exec_arg_buf)); + + if (unlikely(argv == NULL)) + goto log; + + for (i = 0; i < bprm->argc && execlen < 128; i++) { + const char __user *p; + unsigned int len; + + if (copy_from_user(&p, argv + i, sizeof(p))) + goto log; + if (!p) + goto log; + len = strnlen_user(p, 128 - execlen); + if (len > 128 - execlen) + len = 128 - execlen; + else if (len > 0) + len--; + if (copy_from_user(grarg + execlen, p, len)) + goto log; + + /* rewrite unprintable characters */ + for (x = 0; x < len; x++) { + c = *(grarg + execlen + x); + if (c < 32 || c > 126) + *(grarg + execlen + x) = ' '; + } + + execlen += len; + *(grarg + execlen) = ' '; + *(grarg + execlen + 1) = '\0'; + execlen++; + } + + log: + gr_log_fs_str(GR_DO_AUDIT, GR_EXEC_AUDIT_MSG, bprm->file->f_path.dentry, + bprm->file->f_path.mnt, grarg); + up(&gr_exec_arg_sem); +#endif + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_fifo.c linux-2.6.27.15-g-v/grsecurity/grsec_fifo.c --- linux-2.6.27.15/grsecurity/grsec_fifo.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_fifo.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,22 @@ +#include +#include +#include +#include +#include + +int +gr_handle_fifo(const struct dentry *dentry, const struct vfsmount *mnt, + const struct dentry *dir, const int flag, const int acc_mode) +{ +#ifdef CONFIG_GRKERNSEC_FIFO + if (grsec_enable_fifo && S_ISFIFO(dentry->d_inode->i_mode) && + !(flag & O_EXCL) && (dir->d_inode->i_mode & S_ISVTX) && + (dentry->d_inode->i_uid != dir->d_inode->i_uid) && + (current->fsuid != dentry->d_inode->i_uid)) { + if (!generic_permission(dentry->d_inode, acc_mode, NULL)) + gr_log_fs_int2(GR_DONT_AUDIT, GR_FIFO_MSG, dentry, mnt, dentry->d_inode->i_uid, dentry->d_inode->i_gid); + return -EACCES; + } +#endif + return 0; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_fork.c linux-2.6.27.15-g-v/grsecurity/grsec_fork.c --- linux-2.6.27.15/grsecurity/grsec_fork.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_fork.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,15 @@ +#include +#include +#include +#include +#include + +void +gr_log_forkfail(const int retval) +{ +#ifdef CONFIG_GRKERNSEC_FORKFAIL + if (grsec_enable_forkfail && retval != -ERESTARTNOINTR) + gr_log_int(GR_DONT_AUDIT, GR_FAILFORK_MSG, retval); +#endif + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_init.c linux-2.6.27.15-g-v/grsecurity/grsec_init.c --- linux-2.6.27.15/grsecurity/grsec_init.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_init.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,230 @@ +#include +#include +#include +#include +#include +#include +#include +#include + +int grsec_enable_link; +int grsec_enable_dmesg; +int grsec_enable_fifo; +int grsec_enable_execve; +int grsec_enable_execlog; +int grsec_enable_signal; +int grsec_enable_forkfail; +int grsec_enable_time; +int grsec_enable_audit_textrel; +int grsec_enable_group; +int grsec_audit_gid; +int grsec_enable_chdir; +int grsec_enable_audit_ipc; +int grsec_enable_mount; +int grsec_enable_chroot_findtask; +int grsec_enable_chroot_mount; +int grsec_enable_chroot_shmat; +int grsec_enable_chroot_fchdir; +int grsec_enable_chroot_double; +int grsec_enable_chroot_pivot; +int grsec_enable_chroot_chdir; +int grsec_enable_chroot_chmod; +int grsec_enable_chroot_mknod; +int grsec_enable_chroot_nice; +int grsec_enable_chroot_execlog; +int grsec_enable_chroot_caps; +int grsec_enable_chroot_sysctl; +int grsec_enable_chroot_unix; +int grsec_enable_tpe; +int grsec_tpe_gid; +int grsec_enable_tpe_all; +int grsec_enable_socket_all; +int grsec_socket_all_gid; +int grsec_enable_socket_client; +int grsec_socket_client_gid; +int grsec_enable_socket_server; +int grsec_socket_server_gid; +int grsec_resource_logging; +int grsec_lock; + +DEFINE_SPINLOCK(grsec_alert_lock); +unsigned long grsec_alert_wtime = 0; +unsigned long grsec_alert_fyet = 0; + +DEFINE_SPINLOCK(grsec_audit_lock); + +DEFINE_RWLOCK(grsec_exec_file_lock); + +char *gr_shared_page[4]; + +char *gr_alert_log_fmt; +char *gr_audit_log_fmt; +char *gr_alert_log_buf; +char *gr_audit_log_buf; + +extern struct gr_arg *gr_usermode; +extern unsigned char *gr_system_salt; +extern unsigned char *gr_system_sum; + +void +grsecurity_init(void) +{ + int j; + /* create the per-cpu shared pages */ + +#ifdef CONFIG_X86 + memset((char *)(0x41a + PAGE_OFFSET), 0, 36); +#endif + + for (j = 0; j < 4; j++) { + gr_shared_page[j] = (char *)__alloc_percpu(PAGE_SIZE); + if (gr_shared_page[j] == NULL) { + panic("Unable to allocate grsecurity shared page"); + return; + } + } + + /* allocate log buffers */ + gr_alert_log_fmt = kmalloc(512, GFP_KERNEL); + if (!gr_alert_log_fmt) { + panic("Unable to allocate grsecurity alert log format buffer"); + return; + } + gr_audit_log_fmt = kmalloc(512, GFP_KERNEL); + if (!gr_audit_log_fmt) { + panic("Unable to allocate grsecurity audit log format buffer"); + return; + } + gr_alert_log_buf = (char *) get_zeroed_page(GFP_KERNEL); + if (!gr_alert_log_buf) { + panic("Unable to allocate grsecurity alert log buffer"); + return; + } + gr_audit_log_buf = (char *) get_zeroed_page(GFP_KERNEL); + if (!gr_audit_log_buf) { + panic("Unable to allocate grsecurity audit log buffer"); + return; + } + + /* allocate memory for authentication structure */ + gr_usermode = kmalloc(sizeof(struct gr_arg), GFP_KERNEL); + gr_system_salt = kmalloc(GR_SALT_LEN, GFP_KERNEL); + gr_system_sum = kmalloc(GR_SHA_LEN, GFP_KERNEL); + + if (!gr_usermode || !gr_system_salt || !gr_system_sum) { + panic("Unable to allocate grsecurity authentication structure"); + return; + } + +#if !defined(CONFIG_GRKERNSEC_SYSCTL) || defined(CONFIG_GRKERNSEC_SYSCTL_ON) +#ifndef CONFIG_GRKERNSEC_SYSCTL + grsec_lock = 1; +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_TEXTREL + grsec_enable_audit_textrel = 1; +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_GROUP + grsec_enable_group = 1; + grsec_audit_gid = CONFIG_GRKERNSEC_AUDIT_GID; +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_CHDIR + grsec_enable_chdir = 1; +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_IPC + grsec_enable_audit_ipc = 1; +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT + grsec_enable_mount = 1; +#endif +#ifdef CONFIG_GRKERNSEC_LINK + grsec_enable_link = 1; +#endif +#ifdef CONFIG_GRKERNSEC_DMESG + grsec_enable_dmesg = 1; +#endif +#ifdef CONFIG_GRKERNSEC_FIFO + grsec_enable_fifo = 1; +#endif +#ifdef CONFIG_GRKERNSEC_EXECVE + grsec_enable_execve = 1; +#endif +#ifdef CONFIG_GRKERNSEC_EXECLOG + grsec_enable_execlog = 1; +#endif +#ifdef CONFIG_GRKERNSEC_SIGNAL + grsec_enable_signal = 1; +#endif +#ifdef CONFIG_GRKERNSEC_FORKFAIL + grsec_enable_forkfail = 1; +#endif +#ifdef CONFIG_GRKERNSEC_TIME + grsec_enable_time = 1; +#endif +#ifdef CONFIG_GRKERNSEC_RESLOG + grsec_resource_logging = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_FINDTASK + grsec_enable_chroot_findtask = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_UNIX + grsec_enable_chroot_unix = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_MOUNT + grsec_enable_chroot_mount = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_FCHDIR + grsec_enable_chroot_fchdir = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_SHMAT + grsec_enable_chroot_shmat = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_DOUBLE + grsec_enable_chroot_double = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_PIVOT + grsec_enable_chroot_pivot = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_CHDIR + grsec_enable_chroot_chdir = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_CHMOD + grsec_enable_chroot_chmod = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_MKNOD + grsec_enable_chroot_mknod = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_NICE + grsec_enable_chroot_nice = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_EXECLOG + grsec_enable_chroot_execlog = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_CAPS + grsec_enable_chroot_caps = 1; +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_SYSCTL + grsec_enable_chroot_sysctl = 1; +#endif +#ifdef CONFIG_GRKERNSEC_TPE + grsec_enable_tpe = 1; + grsec_tpe_gid = CONFIG_GRKERNSEC_TPE_GID; +#ifdef CONFIG_GRKERNSEC_TPE_ALL + grsec_enable_tpe_all = 1; +#endif +#endif +#ifdef CONFIG_GRKERNSEC_SOCKET_ALL + grsec_enable_socket_all = 1; + grsec_socket_all_gid = CONFIG_GRKERNSEC_SOCKET_ALL_GID; +#endif +#ifdef CONFIG_GRKERNSEC_SOCKET_CLIENT + grsec_enable_socket_client = 1; + grsec_socket_client_gid = CONFIG_GRKERNSEC_SOCKET_CLIENT_GID; +#endif +#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER + grsec_enable_socket_server = 1; + grsec_socket_server_gid = CONFIG_GRKERNSEC_SOCKET_SERVER_GID; +#endif +#endif + + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_ipc.c linux-2.6.27.15-g-v/grsecurity/grsec_ipc.c --- linux-2.6.27.15/grsecurity/grsec_ipc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_ipc.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,81 @@ +#include +#include +#include +#include +#include +#include + +void +gr_log_msgget(const int ret, const int msgflg) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_IPC + if (((grsec_enable_group && in_group_p(grsec_audit_gid) && + grsec_enable_audit_ipc) || (grsec_enable_audit_ipc && + !grsec_enable_group)) && (ret >= 0) + && (msgflg & IPC_CREAT)) + gr_log_noargs(GR_DO_AUDIT, GR_MSGQ_AUDIT_MSG); +#endif + return; +} + +void +gr_log_msgrm(const uid_t uid, const uid_t cuid) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_IPC + if ((grsec_enable_group && in_group_p(grsec_audit_gid) && + grsec_enable_audit_ipc) || + (grsec_enable_audit_ipc && !grsec_enable_group)) + gr_log_int_int(GR_DO_AUDIT, GR_MSGQR_AUDIT_MSG, uid, cuid); +#endif + return; +} + +void +gr_log_semget(const int err, const int semflg) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_IPC + if (((grsec_enable_group && in_group_p(grsec_audit_gid) && + grsec_enable_audit_ipc) || (grsec_enable_audit_ipc && + !grsec_enable_group)) && (err >= 0) + && (semflg & IPC_CREAT)) + gr_log_noargs(GR_DO_AUDIT, GR_SEM_AUDIT_MSG); +#endif + return; +} + +void +gr_log_semrm(const uid_t uid, const uid_t cuid) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_IPC + if ((grsec_enable_group && in_group_p(grsec_audit_gid) && + grsec_enable_audit_ipc) || + (grsec_enable_audit_ipc && !grsec_enable_group)) + gr_log_int_int(GR_DO_AUDIT, GR_SEMR_AUDIT_MSG, uid, cuid); +#endif + return; +} + +void +gr_log_shmget(const int err, const int shmflg, const size_t size) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_IPC + if (((grsec_enable_group && in_group_p(grsec_audit_gid) && + grsec_enable_audit_ipc) || (grsec_enable_audit_ipc && + !grsec_enable_group)) && (err >= 0) + && (shmflg & IPC_CREAT)) + gr_log_int(GR_DO_AUDIT, GR_SHM_AUDIT_MSG, size); +#endif + return; +} + +void +gr_log_shmrm(const uid_t uid, const uid_t cuid) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_IPC + if ((grsec_enable_group && in_group_p(grsec_audit_gid) && + grsec_enable_audit_ipc) || + (grsec_enable_audit_ipc && !grsec_enable_group)) + gr_log_int_int(GR_DO_AUDIT, GR_SHMR_AUDIT_MSG, uid, cuid); +#endif + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_link.c linux-2.6.27.15-g-v/grsecurity/grsec_link.c --- linux-2.6.27.15/grsecurity/grsec_link.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_link.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,39 @@ +#include +#include +#include +#include +#include + +int +gr_handle_follow_link(const struct inode *parent, + const struct inode *inode, + const struct dentry *dentry, const struct vfsmount *mnt) +{ +#ifdef CONFIG_GRKERNSEC_LINK + if (grsec_enable_link && S_ISLNK(inode->i_mode) && + (parent->i_mode & S_ISVTX) && (parent->i_uid != inode->i_uid) && + (parent->i_mode & S_IWOTH) && (current->fsuid != inode->i_uid)) { + gr_log_fs_int2(GR_DONT_AUDIT, GR_SYMLINK_MSG, dentry, mnt, inode->i_uid, inode->i_gid); + return -EACCES; + } +#endif + return 0; +} + +int +gr_handle_hardlink(const struct dentry *dentry, + const struct vfsmount *mnt, + struct inode *inode, const int mode, const char *to) +{ +#ifdef CONFIG_GRKERNSEC_LINK + if (grsec_enable_link && current->fsuid != inode->i_uid && + (!S_ISREG(mode) || (mode & S_ISUID) || + ((mode & (S_ISGID | S_IXGRP)) == (S_ISGID | S_IXGRP)) || + (generic_permission(inode, MAY_READ | MAY_WRITE, NULL))) && + !capable(CAP_FOWNER) && current->uid) { + gr_log_fs_int2_str(GR_DONT_AUDIT, GR_HARDLINK_MSG, dentry, mnt, inode->i_uid, inode->i_gid, to); + return -EPERM; + } +#endif + return 0; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_log.c linux-2.6.27.15-g-v/grsecurity/grsec_log.c --- linux-2.6.27.15/grsecurity/grsec_log.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_log.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,269 @@ +#include +#include +#include +#include +#include +#include + +#define BEGIN_LOCKS(x) \ + read_lock(&tasklist_lock); \ + read_lock(&grsec_exec_file_lock); \ + if (x != GR_DO_AUDIT) \ + spin_lock(&grsec_alert_lock); \ + else \ + spin_lock(&grsec_audit_lock) + +#define END_LOCKS(x) \ + if (x != GR_DO_AUDIT) \ + spin_unlock(&grsec_alert_lock); \ + else \ + spin_unlock(&grsec_audit_lock); \ + read_unlock(&grsec_exec_file_lock); \ + read_unlock(&tasklist_lock); \ + if (x == GR_DONT_AUDIT) \ + gr_handle_alertkill(current) + +enum { + FLOODING, + NO_FLOODING +}; + +extern char *gr_alert_log_fmt; +extern char *gr_audit_log_fmt; +extern char *gr_alert_log_buf; +extern char *gr_audit_log_buf; + +static int gr_log_start(int audit) +{ + char *loglevel = (audit == GR_DO_AUDIT) ? KERN_INFO : KERN_ALERT; + char *fmt = (audit == GR_DO_AUDIT) ? gr_audit_log_fmt : gr_alert_log_fmt; + char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; + + if (audit == GR_DO_AUDIT) + goto set_fmt; + + if (!grsec_alert_wtime || jiffies - grsec_alert_wtime > CONFIG_GRKERNSEC_FLOODTIME * HZ) { + grsec_alert_wtime = jiffies; + grsec_alert_fyet = 0; + } else if ((jiffies - grsec_alert_wtime < CONFIG_GRKERNSEC_FLOODTIME * HZ) && (grsec_alert_fyet < CONFIG_GRKERNSEC_FLOODBURST)) { + grsec_alert_fyet++; + } else if (grsec_alert_fyet == CONFIG_GRKERNSEC_FLOODBURST) { + grsec_alert_wtime = jiffies; + grsec_alert_fyet++; + printk(KERN_ALERT "grsec: more alerts, logging disabled for %d seconds\n", CONFIG_GRKERNSEC_FLOODTIME); + return FLOODING; + } else return FLOODING; + +set_fmt: + memset(buf, 0, PAGE_SIZE); + if (current->signal->curr_ip && gr_acl_is_enabled()) { + sprintf(fmt, "%s%s", loglevel, "grsec: From %u.%u.%u.%u: (%.64s:%c:%.950s) "); + snprintf(buf, PAGE_SIZE - 1, fmt, NIPQUAD(current->signal->curr_ip), current->role->rolename, gr_roletype_to_char(), current->acl->filename); + } else if (current->signal->curr_ip) { + sprintf(fmt, "%s%s", loglevel, "grsec: From %u.%u.%u.%u: "); + snprintf(buf, PAGE_SIZE - 1, fmt, NIPQUAD(current->signal->curr_ip)); + } else if (gr_acl_is_enabled()) { + sprintf(fmt, "%s%s", loglevel, "grsec: (%.64s:%c:%.950s) "); + snprintf(buf, PAGE_SIZE - 1, fmt, current->role->rolename, gr_roletype_to_char(), current->acl->filename); + } else { + sprintf(fmt, "%s%s", loglevel, "grsec: "); + strcpy(buf, fmt); + } + + return NO_FLOODING; +} + +static void gr_log_middle(int audit, const char *msg, va_list ap) +{ + char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; + unsigned int len = strlen(buf); + + vsnprintf(buf + len, PAGE_SIZE - len - 1, msg, ap); + + return; +} + +static void gr_log_middle_varargs(int audit, const char *msg, ...) +{ + char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; + unsigned int len = strlen(buf); + va_list ap; + + va_start(ap, msg); + vsnprintf(buf + len, PAGE_SIZE - len - 1, msg, ap); + va_end(ap); + + return; +} + +static void gr_log_end(int audit) +{ + char *buf = (audit == GR_DO_AUDIT) ? gr_audit_log_buf : gr_alert_log_buf; + unsigned int len = strlen(buf); + + snprintf(buf + len, PAGE_SIZE - len - 1, DEFAULTSECMSG, DEFAULTSECARGS(current)); + printk("%s\n", buf); + + return; +} + +void gr_log_varargs(int audit, const char *msg, int argtypes, ...) +{ + int logtype; + char *result = (audit == GR_DO_AUDIT) ? "successful" : "denied"; + char *str1, *str2, *str3; + int num1, num2; + unsigned long ulong1, ulong2; + struct dentry *dentry; + struct vfsmount *mnt; + struct file *file; + struct task_struct *task; + va_list ap; + + BEGIN_LOCKS(audit); + logtype = gr_log_start(audit); + if (logtype == FLOODING) { + END_LOCKS(audit); + return; + } + va_start(ap, argtypes); + switch (argtypes) { + case GR_TTYSNIFF: + task = va_arg(ap, struct task_struct *); + gr_log_middle_varargs(audit, msg, NIPQUAD(task->signal->curr_ip), gr_task_fullpath0(task), task->comm, task->pid, gr_parent_task_fullpath0(task), task->parent->comm, task->parent->pid); + break; + case GR_SYSCTL_HIDDEN: + str1 = va_arg(ap, char *); + gr_log_middle_varargs(audit, msg, result, str1); + break; + case GR_RBAC: + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + gr_log_middle_varargs(audit, msg, result, gr_to_filename(dentry, mnt)); + break; + case GR_RBAC_STR: + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + str1 = va_arg(ap, char *); + gr_log_middle_varargs(audit, msg, result, gr_to_filename(dentry, mnt), str1); + break; + case GR_STR_RBAC: + str1 = va_arg(ap, char *); + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + gr_log_middle_varargs(audit, msg, result, str1, gr_to_filename(dentry, mnt)); + break; + case GR_RBAC_MODE2: + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + str1 = va_arg(ap, char *); + str2 = va_arg(ap, char *); + gr_log_middle_varargs(audit, msg, result, gr_to_filename(dentry, mnt), str1, str2); + break; + case GR_RBAC_MODE3: + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + str1 = va_arg(ap, char *); + str2 = va_arg(ap, char *); + str3 = va_arg(ap, char *); + gr_log_middle_varargs(audit, msg, result, gr_to_filename(dentry, mnt), str1, str2, str3); + break; + case GR_FILENAME: + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt)); + break; + case GR_STR_FILENAME: + str1 = va_arg(ap, char *); + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + gr_log_middle_varargs(audit, msg, str1, gr_to_filename(dentry, mnt)); + break; + case GR_FILENAME_STR: + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + str1 = va_arg(ap, char *); + gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt), str1); + break; + case GR_FILENAME_TWO_INT: + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + num1 = va_arg(ap, int); + num2 = va_arg(ap, int); + gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt), num1, num2); + break; + case GR_FILENAME_TWO_INT_STR: + dentry = va_arg(ap, struct dentry *); + mnt = va_arg(ap, struct vfsmount *); + num1 = va_arg(ap, int); + num2 = va_arg(ap, int); + str1 = va_arg(ap, char *); + gr_log_middle_varargs(audit, msg, gr_to_filename(dentry, mnt), num1, num2, str1); + break; + case GR_TEXTREL: + file = va_arg(ap, struct file *); + ulong1 = va_arg(ap, unsigned long); + ulong2 = va_arg(ap, unsigned long); + gr_log_middle_varargs(audit, msg, file ? gr_to_filename(file->f_path.dentry, file->f_path.mnt) : "", ulong1, ulong2); + break; + case GR_PTRACE: + task = va_arg(ap, struct task_struct *); + gr_log_middle_varargs(audit, msg, task->exec_file ? gr_to_filename(task->exec_file->f_path.dentry, task->exec_file->f_path.mnt) : "(none)", task->comm, task->pid); + break; + case GR_RESOURCE: + task = va_arg(ap, struct task_struct *); + ulong1 = va_arg(ap, unsigned long); + str1 = va_arg(ap, char *); + ulong2 = va_arg(ap, unsigned long); + gr_log_middle_varargs(audit, msg, ulong1, str1, ulong2, gr_task_fullpath(task), task->comm, task->pid, task->uid, task->euid, task->gid, task->egid, gr_parent_task_fullpath(task), task->parent->comm, task->parent->pid, task->parent->uid, task->parent->euid, task->parent->gid, task->parent->egid); + break; + case GR_CAP: + task = va_arg(ap, struct task_struct *); + str1 = va_arg(ap, char *); + gr_log_middle_varargs(audit, msg, str1, gr_task_fullpath(task), task->comm, task->pid, task->uid, task->euid, task->gid, task->egid, gr_parent_task_fullpath(task), task->parent->comm, task->parent->pid, task->parent->uid, task->parent->euid, task->parent->gid, task->parent->egid); + break; + case GR_SIG: + task = va_arg(ap, struct task_struct *); + num1 = va_arg(ap, int); + gr_log_middle_varargs(audit, msg, num1, gr_task_fullpath0(task), task->comm, task->pid, task->uid, task->euid, task->gid, task->egid, gr_parent_task_fullpath0(task), task->parent->comm, task->parent->pid, task->parent->uid, task->parent->euid, task->parent->gid, task->parent->egid); + break; + case GR_CRASH1: + task = va_arg(ap, struct task_struct *); + ulong1 = va_arg(ap, unsigned long); + gr_log_middle_varargs(audit, msg, gr_task_fullpath(task), task->comm, task->pid, task->uid, task->euid, task->gid, task->egid, gr_parent_task_fullpath(task), task->parent->comm, task->parent->pid, task->parent->uid, task->parent->euid, task->parent->gid, task->parent->egid, task->uid, ulong1); + break; + case GR_CRASH2: + task = va_arg(ap, struct task_struct *); + ulong1 = va_arg(ap, unsigned long); + gr_log_middle_varargs(audit, msg, gr_task_fullpath(task), task->comm, task->pid, task->uid, task->euid, task->gid, task->egid, gr_parent_task_fullpath(task), task->parent->comm, task->parent->pid, task->parent->uid, task->parent->euid, task->parent->gid, task->parent->egid, ulong1); + break; + case GR_PSACCT: + { + unsigned int wday, cday; + __u8 whr, chr; + __u8 wmin, cmin; + __u8 wsec, csec; + char cur_tty[64] = { 0 }; + char parent_tty[64] = { 0 }; + + task = va_arg(ap, struct task_struct *); + wday = va_arg(ap, unsigned int); + cday = va_arg(ap, unsigned int); + whr = va_arg(ap, int); + chr = va_arg(ap, int); + wmin = va_arg(ap, int); + cmin = va_arg(ap, int); + wsec = va_arg(ap, int); + csec = va_arg(ap, int); + ulong1 = va_arg(ap, unsigned long); + + gr_log_middle_varargs(audit, msg, gr_task_fullpath(task), task->comm, task->pid, NIPQUAD(task->signal->curr_ip), tty_name(task->signal->tty, cur_tty), task->uid, task->euid, task->gid, task->egid, wday, whr, wmin, wsec, cday, chr, cmin, csec, (task->flags & PF_SIGNALED) ? "killed by signal" : "exited", ulong1, gr_parent_task_fullpath(task), task->parent->comm, task->parent->pid, NIPQUAD(task->parent->signal->curr_ip), tty_name(task->parent->signal->tty, parent_tty), task->parent->uid, task->parent->euid, task->parent->gid, task->parent->egid); + } + break; + default: + gr_log_middle(audit, msg, ap); + } + va_end(ap); + gr_log_end(audit); + END_LOCKS(audit); +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_mem.c linux-2.6.27.15-g-v/grsecurity/grsec_mem.c --- linux-2.6.27.15/grsecurity/grsec_mem.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_mem.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,71 @@ +#include +#include +#include +#include +#include + +void +gr_handle_ioperm(void) +{ + gr_log_noargs(GR_DONT_AUDIT, GR_IOPERM_MSG); + return; +} + +void +gr_handle_iopl(void) +{ + gr_log_noargs(GR_DONT_AUDIT, GR_IOPL_MSG); + return; +} + +void +gr_handle_mem_write(void) +{ + gr_log_noargs(GR_DONT_AUDIT, GR_MEM_WRITE_MSG); + return; +} + +void +gr_handle_kmem_write(void) +{ + gr_log_noargs(GR_DONT_AUDIT, GR_KMEM_MSG); + return; +} + +void +gr_handle_open_port(void) +{ + gr_log_noargs(GR_DONT_AUDIT, GR_PORT_OPEN_MSG); + return; +} + +int +gr_handle_mem_mmap(const unsigned long offset, struct vm_area_struct *vma) +{ + unsigned long start, end; + + start = offset; + end = start + vma->vm_end - vma->vm_start; + + if (start > end) { + gr_log_noargs(GR_DONT_AUDIT, GR_MEM_MMAP_MSG); + return -EPERM; + } + + /* allowed ranges : ISA I/O BIOS */ + if ((start >= __pa(high_memory)) +#ifdef CONFIG_X86 + || (start >= 0x000a0000 && end <= 0x00100000) + || (start >= 0x00000000 && end <= 0x00001000) +#endif + ) + return 0; + + if (vma->vm_flags & VM_WRITE) { + gr_log_noargs(GR_DONT_AUDIT, GR_MEM_MMAP_MSG); + return -EPERM; + } else + vma->vm_flags &= ~VM_MAYWRITE; + + return 0; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_mount.c linux-2.6.27.15-g-v/grsecurity/grsec_mount.c --- linux-2.6.27.15/grsecurity/grsec_mount.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_mount.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,34 @@ +#include +#include +#include +#include + +void +gr_log_remount(const char *devname, const int retval) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT + if (grsec_enable_mount && (retval >= 0)) + gr_log_str(GR_DO_AUDIT, GR_REMOUNT_AUDIT_MSG, devname ? devname : "none"); +#endif + return; +} + +void +gr_log_unmount(const char *devname, const int retval) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT + if (grsec_enable_mount && (retval >= 0)) + gr_log_str(GR_DO_AUDIT, GR_UNMOUNT_AUDIT_MSG, devname ? devname : "none"); +#endif + return; +} + +void +gr_log_mount(const char *from, const char *to, const int retval) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT + if (grsec_enable_mount && (retval >= 0)) + gr_log_str_str(GR_DO_AUDIT, GR_MOUNT_AUDIT_MSG, from, to); +#endif + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_sig.c linux-2.6.27.15-g-v/grsecurity/grsec_sig.c --- linux-2.6.27.15/grsecurity/grsec_sig.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_sig.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,58 @@ +#include +#include +#include +#include +#include + +void +gr_log_signal(const int sig, const struct task_struct *t) +{ +#ifdef CONFIG_GRKERNSEC_SIGNAL + if (grsec_enable_signal && ((sig == SIGSEGV) || (sig == SIGILL) || + (sig == SIGABRT) || (sig == SIGBUS))) { + if (t->pid == current->pid) { + gr_log_int(GR_DONT_AUDIT_GOOD, GR_UNISIGLOG_MSG, sig); + } else { + gr_log_sig(GR_DONT_AUDIT_GOOD, GR_DUALSIGLOG_MSG, t, sig); + } + } +#endif + return; +} + +int +gr_handle_signal(const struct task_struct *p, const int sig) +{ +#ifdef CONFIG_GRKERNSEC + if (current->pid > 1 && gr_check_protected_task(p)) { + gr_log_sig(GR_DONT_AUDIT, GR_SIG_ACL_MSG, p, sig); + return -EPERM; + } else if (gr_pid_is_chrooted((struct task_struct *)p)) { + return -EPERM; + } +#endif + return 0; +} + +void gr_handle_brute_attach(struct task_struct *p) +{ +#ifdef CONFIG_GRKERNSEC_BRUTE + read_lock(&tasklist_lock); + read_lock(&grsec_exec_file_lock); + if (p->parent && p->parent->exec_file == p->exec_file) + p->parent->brute = 1; + read_unlock(&grsec_exec_file_lock); + read_unlock(&tasklist_lock); +#endif + return; +} + +void gr_handle_brute_check(void) +{ +#ifdef CONFIG_GRKERNSEC_BRUTE + if (current->brute) + msleep(30 * 1000); +#endif + return; +} + diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_sock.c linux-2.6.27.15-g-v/grsecurity/grsec_sock.c --- linux-2.6.27.15/grsecurity/grsec_sock.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_sock.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,274 @@ +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#if defined(CONFIG_IP_NF_MATCH_STEALTH_MODULE) +extern struct sock *udp_v4_lookup(u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); +EXPORT_SYMBOL(udp_v4_lookup); +#endif + +kernel_cap_t gr_cap_rtnetlink(struct sock *sock); +EXPORT_SYMBOL(gr_cap_rtnetlink); + +extern int gr_search_udp_recvmsg(const struct sock *sk, const struct sk_buff *skb); +extern int gr_search_udp_sendmsg(const struct sock *sk, const struct sockaddr_in *addr); + +EXPORT_SYMBOL(gr_search_udp_recvmsg); +EXPORT_SYMBOL(gr_search_udp_sendmsg); + +#ifdef CONFIG_UNIX_MODULE +EXPORT_SYMBOL(gr_acl_handle_unix); +EXPORT_SYMBOL(gr_acl_handle_mknod); +EXPORT_SYMBOL(gr_handle_chroot_unix); +EXPORT_SYMBOL(gr_handle_create); +#endif + +#ifdef CONFIG_GRKERNSEC +#define gr_conn_table_size 32749 +struct conn_table_entry { + struct conn_table_entry *next; + struct signal_struct *sig; +}; + +struct conn_table_entry *gr_conn_table[gr_conn_table_size]; +DEFINE_SPINLOCK(gr_conn_table_lock); + +extern const char * gr_socktype_to_name(unsigned char type); +extern const char * gr_proto_to_name(unsigned char proto); + +static __inline__ int +conn_hash(__u32 saddr, __u32 daddr, __u16 sport, __u16 dport, unsigned int size) +{ + return ((daddr + saddr + (sport << 8) + (dport << 16)) % size); +} + +static __inline__ int +conn_match(const struct signal_struct *sig, __u32 saddr, __u32 daddr, + __u16 sport, __u16 dport) +{ + if (unlikely(sig->gr_saddr == saddr && sig->gr_daddr == daddr && + sig->gr_sport == sport && sig->gr_dport == dport)) + return 1; + else + return 0; +} + +static void gr_add_to_task_ip_table_nolock(struct signal_struct *sig, struct conn_table_entry *newent) +{ + struct conn_table_entry **match; + unsigned int index; + + index = conn_hash(sig->gr_saddr, sig->gr_daddr, + sig->gr_sport, sig->gr_dport, + gr_conn_table_size); + + newent->sig = sig; + + match = &gr_conn_table[index]; + newent->next = *match; + *match = newent; + + return; +} + +static void gr_del_task_from_ip_table_nolock(struct signal_struct *sig) +{ + struct conn_table_entry *match, *last = NULL; + unsigned int index; + + index = conn_hash(sig->gr_saddr, sig->gr_daddr, + sig->gr_sport, sig->gr_dport, + gr_conn_table_size); + + match = gr_conn_table[index]; + while (match && !conn_match(match->sig, + sig->gr_saddr, sig->gr_daddr, sig->gr_sport, + sig->gr_dport)) { + last = match; + match = match->next; + } + + if (match) { + if (last) + last->next = match->next; + else + gr_conn_table[index] = NULL; + kfree(match); + } + + return; +} + +static struct signal_struct * gr_lookup_task_ip_table(__u32 saddr, __u32 daddr, + __u16 sport, __u16 dport) +{ + struct conn_table_entry *match; + unsigned int index; + + index = conn_hash(saddr, daddr, sport, dport, gr_conn_table_size); + + match = gr_conn_table[index]; + while (match && !conn_match(match->sig, saddr, daddr, sport, dport)) + match = match->next; + + if (match) + return match->sig; + else + return NULL; +} + +#endif + +void gr_update_task_in_ip_table(struct task_struct *task, const struct inet_sock *inet) +{ +#ifdef CONFIG_GRKERNSEC + struct signal_struct *sig = task->signal; + struct conn_table_entry *newent; + + newent = kmalloc(sizeof(struct conn_table_entry), GFP_ATOMIC); + if (newent == NULL) + return; + /* no bh lock needed since we are called with bh disabled */ + spin_lock(&gr_conn_table_lock); + gr_del_task_from_ip_table_nolock(sig); + sig->gr_saddr = inet->rcv_saddr; + sig->gr_daddr = inet->daddr; + sig->gr_sport = inet->sport; + sig->gr_dport = inet->dport; + gr_add_to_task_ip_table_nolock(sig, newent); + spin_unlock(&gr_conn_table_lock); +#endif + return; +} + +void gr_del_task_from_ip_table(struct task_struct *task) +{ +#ifdef CONFIG_GRKERNSEC + spin_lock_bh(&gr_conn_table_lock); + gr_del_task_from_ip_table_nolock(task->signal); + spin_unlock_bh(&gr_conn_table_lock); +#endif + return; +} + +void +gr_attach_curr_ip(const struct sock *sk) +{ +#ifdef CONFIG_GRKERNSEC + struct signal_struct *p, *set; + const struct inet_sock *inet = inet_sk(sk); + + if (unlikely(sk->sk_protocol != IPPROTO_TCP)) + return; + + set = current->signal; + + spin_lock_bh(&gr_conn_table_lock); + p = gr_lookup_task_ip_table(inet->daddr, inet->rcv_saddr, + inet->dport, inet->sport); + if (unlikely(p != NULL)) { + set->curr_ip = p->curr_ip; + set->used_accept = 1; + gr_del_task_from_ip_table_nolock(p); + spin_unlock_bh(&gr_conn_table_lock); + return; + } + spin_unlock_bh(&gr_conn_table_lock); + + set->curr_ip = inet->daddr; + set->used_accept = 1; +#endif + return; +} + +int +gr_handle_sock_all(const int family, const int type, const int protocol) +{ +#ifdef CONFIG_GRKERNSEC_SOCKET_ALL + if (grsec_enable_socket_all && in_group_p(grsec_socket_all_gid) && + (family != AF_UNIX) && (family != AF_LOCAL)) { + gr_log_int_str2(GR_DONT_AUDIT, GR_SOCK2_MSG, family, gr_socktype_to_name(type), gr_proto_to_name(protocol)); + return -EACCES; + } +#endif + return 0; +} + +int +gr_handle_sock_server(const struct sockaddr *sck) +{ +#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER + if (grsec_enable_socket_server && + in_group_p(grsec_socket_server_gid) && + sck && (sck->sa_family != AF_UNIX) && + (sck->sa_family != AF_LOCAL)) { + gr_log_noargs(GR_DONT_AUDIT, GR_BIND_MSG); + return -EACCES; + } +#endif + return 0; +} + +int +gr_handle_sock_server_other(const struct sock *sck) +{ +#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER + if (grsec_enable_socket_server && + in_group_p(grsec_socket_server_gid) && + sck && (sck->sk_family != AF_UNIX) && + (sck->sk_family != AF_LOCAL)) { + gr_log_noargs(GR_DONT_AUDIT, GR_BIND_MSG); + return -EACCES; + } +#endif + return 0; +} + +int +gr_handle_sock_client(const struct sockaddr *sck) +{ +#ifdef CONFIG_GRKERNSEC_SOCKET_CLIENT + if (grsec_enable_socket_client && in_group_p(grsec_socket_client_gid) && + sck && (sck->sa_family != AF_UNIX) && + (sck->sa_family != AF_LOCAL)) { + gr_log_noargs(GR_DONT_AUDIT, GR_CONNECT_MSG); + return -EACCES; + } +#endif + return 0; +} + +kernel_cap_t +gr_cap_rtnetlink(struct sock *sock) +{ +#ifdef CONFIG_GRKERNSEC + if (!gr_acl_is_enabled()) + return current->cap_effective; + else if (sock->sk_protocol == NETLINK_ISCSI && + cap_raised(current->cap_effective, CAP_SYS_ADMIN) && + gr_task_is_capable(current, CAP_SYS_ADMIN)) + return current->cap_effective; + else if (sock->sk_protocol == NETLINK_AUDIT && + cap_raised(current->cap_effective, CAP_AUDIT_WRITE) && + gr_task_is_capable(current, CAP_AUDIT_WRITE) && + cap_raised(current->cap_effective, CAP_AUDIT_CONTROL) && + gr_task_is_capable(current, CAP_AUDIT_CONTROL)) + return current->cap_effective; + else if (cap_raised(current->cap_effective, CAP_NET_ADMIN) && + gr_task_is_capable(current, CAP_NET_ADMIN)) + return current->cap_effective; + else + return __cap_empty_set; +#else + return current->cap_effective; +#endif +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_sysctl.c linux-2.6.27.15-g-v/grsecurity/grsec_sysctl.c --- linux-2.6.27.15/grsecurity/grsec_sysctl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_sysctl.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,435 @@ +#include +#include +#include +#include +#include + +#ifdef CONFIG_GRKERNSEC_MODSTOP +int grsec_modstop; +#endif + +int +gr_handle_sysctl_mod(const char *dirname, const char *name, const int op) +{ +#ifdef CONFIG_GRKERNSEC_SYSCTL + if (!strcmp(dirname, "grsecurity") && grsec_lock && (op & MAY_WRITE)) { + gr_log_str(GR_DONT_AUDIT, GR_SYSCTL_MSG, name); + return -EACCES; + } +#endif +#ifdef CONFIG_GRKERNSEC_MODSTOP + if (!strcmp(dirname, "grsecurity") && !strcmp(name, "disable_modules") && + grsec_modstop && (op & MAY_WRITE)) { + gr_log_str(GR_DONT_AUDIT, GR_SYSCTL_MSG, name); + return -EACCES; + } +#endif + return 0; +} + +#if defined(CONFIG_GRKERNSEC_SYSCTL) || defined(CONFIG_GRKERNSEC_MODSTOP) +ctl_table grsecurity_table[] = { +#ifdef CONFIG_GRKERNSEC_SYSCTL +#ifdef CONFIG_GRKERNSEC_LINK + { + .ctl_name = CTL_UNNUMBERED, + .procname = "linking_restrictions", + .data = &grsec_enable_link, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_FIFO + { + .ctl_name = CTL_UNNUMBERED, + .procname = "fifo_restrictions", + .data = &grsec_enable_fifo, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_EXECVE + { + .ctl_name = CTL_UNNUMBERED, + .procname = "execve_limiting", + .data = &grsec_enable_execve, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_EXECLOG + { + .ctl_name = CTL_UNNUMBERED, + .procname = "exec_logging", + .data = &grsec_enable_execlog, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_SIGNAL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "signal_logging", + .data = &grsec_enable_signal, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_FORKFAIL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "forkfail_logging", + .data = &grsec_enable_forkfail, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_TIME + { + .ctl_name = CTL_UNNUMBERED, + .procname = "timechange_logging", + .data = &grsec_enable_time, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_SHMAT + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_shmat", + .data = &grsec_enable_chroot_shmat, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_UNIX + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_unix", + .data = &grsec_enable_chroot_unix, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_MOUNT + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_mount", + .data = &grsec_enable_chroot_mount, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_FCHDIR + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_fchdir", + .data = &grsec_enable_chroot_fchdir, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_DOUBLE + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_chroot", + .data = &grsec_enable_chroot_double, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_PIVOT + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_pivot", + .data = &grsec_enable_chroot_pivot, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_CHDIR + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_enforce_chdir", + .data = &grsec_enable_chroot_chdir, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_CHMOD + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_chmod", + .data = &grsec_enable_chroot_chmod, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_MKNOD + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_mknod", + .data = &grsec_enable_chroot_mknod, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_NICE + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_restrict_nice", + .data = &grsec_enable_chroot_nice, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_EXECLOG + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_execlog", + .data = &grsec_enable_chroot_execlog, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_CAPS + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_caps", + .data = &grsec_enable_chroot_caps, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_SYSCTL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_deny_sysctl", + .data = &grsec_enable_chroot_sysctl, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_TPE + { + .ctl_name = CTL_UNNUMBERED, + .procname = "tpe", + .data = &grsec_enable_tpe, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "tpe_gid", + .data = &grsec_tpe_gid, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_TPE_ALL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "tpe_restrict_all", + .data = &grsec_enable_tpe_all, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_SOCKET_ALL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "socket_all", + .data = &grsec_enable_socket_all, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "socket_all_gid", + .data = &grsec_socket_all_gid, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_SOCKET_CLIENT + { + .ctl_name = CTL_UNNUMBERED, + .procname = "socket_client", + .data = &grsec_enable_socket_client, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "socket_client_gid", + .data = &grsec_socket_client_gid, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_SOCKET_SERVER + { + .ctl_name = CTL_UNNUMBERED, + .procname = "socket_server", + .data = &grsec_enable_socket_server, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "socket_server_gid", + .data = &grsec_socket_server_gid, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_GROUP + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_group", + .data = &grsec_enable_group, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_gid", + .data = &grsec_audit_gid, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_CHDIR + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_chdir", + .data = &grsec_enable_chdir, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_MOUNT + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_mount", + .data = &grsec_enable_mount, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_IPC + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_ipc", + .data = &grsec_enable_audit_ipc, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_AUDIT_TEXTREL + { + .ctl_name = CTL_UNNUMBERED, + .procname = "audit_textrel", + .data = &grsec_enable_audit_textrel, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_DMESG + { + .ctl_name = CTL_UNNUMBERED, + .procname = "dmesg", + .data = &grsec_enable_dmesg, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_CHROOT_FINDTASK + { + .ctl_name = CTL_UNNUMBERED, + .procname = "chroot_findtask", + .data = &grsec_enable_chroot_findtask, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_RESLOG + { + .ctl_name = CTL_UNNUMBERED, + .procname = "resource_logging", + .data = &grsec_resource_logging, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif + { + .ctl_name = CTL_UNNUMBERED, + .procname = "grsec_lock", + .data = &grsec_lock, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif +#ifdef CONFIG_GRKERNSEC_MODSTOP + { + .ctl_name = CTL_UNNUMBERED, + .procname = "disable_modules", + .data = &grsec_modstop, + .maxlen = sizeof(int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, +#endif + { .ctl_name = 0 } +}; +#endif + +int gr_check_modstop(void) +{ +#ifdef CONFIG_GRKERNSEC_MODSTOP + if (grsec_modstop == 1) { + gr_log_noargs(GR_DONT_AUDIT, GR_STOPMOD_MSG); + return 1; + } +#endif + return 0; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_textrel.c linux-2.6.27.15-g-v/grsecurity/grsec_textrel.c --- linux-2.6.27.15/grsecurity/grsec_textrel.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_textrel.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,16 @@ +#include +#include +#include +#include +#include +#include + +void +gr_log_textrel(struct vm_area_struct * vma) +{ +#ifdef CONFIG_GRKERNSEC_AUDIT_TEXTREL + if (grsec_enable_audit_textrel) + gr_log_textrel_ulong_ulong(GR_DO_AUDIT, GR_TEXTREL_AUDIT_MSG, vma->vm_file, vma->vm_start, vma->vm_pgoff); +#endif + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_time.c linux-2.6.27.15-g-v/grsecurity/grsec_time.c --- linux-2.6.27.15/grsecurity/grsec_time.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_time.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,13 @@ +#include +#include +#include + +void +gr_log_timechange(void) +{ +#ifdef CONFIG_GRKERNSEC_TIME + if (grsec_enable_time) + gr_log_noargs(GR_DONT_AUDIT_GOOD, GR_TIME_MSG); +#endif + return; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsec_tpe.c linux-2.6.27.15-g-v/grsecurity/grsec_tpe.c --- linux-2.6.27.15/grsecurity/grsec_tpe.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsec_tpe.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,37 @@ +#include +#include +#include +#include +#include + +extern int gr_acl_tpe_check(void); + +int +gr_tpe_allow(const struct file *file) +{ +#ifdef CONFIG_GRKERNSEC + struct inode *inode = file->f_path.dentry->d_parent->d_inode; + + if (current->uid && ((grsec_enable_tpe && +#ifdef CONFIG_GRKERNSEC_TPE_INVERT + !in_group_p(grsec_tpe_gid) +#else + in_group_p(grsec_tpe_gid) +#endif + ) || gr_acl_tpe_check()) && + (inode->i_uid || (!inode->i_uid && ((inode->i_mode & S_IWGRP) || + (inode->i_mode & S_IWOTH))))) { + gr_log_fs_generic(GR_DONT_AUDIT, GR_EXEC_TPE_MSG, file->f_path.dentry, file->f_path.mnt); + return 0; + } +#ifdef CONFIG_GRKERNSEC_TPE_ALL + if (current->uid && grsec_enable_tpe && grsec_enable_tpe_all && + ((inode->i_uid && (inode->i_uid != current->uid)) || + (inode->i_mode & S_IWGRP) || (inode->i_mode & S_IWOTH))) { + gr_log_fs_generic(GR_DONT_AUDIT, GR_EXEC_TPE_MSG, file->f_path.dentry, file->f_path.mnt); + return 0; + } +#endif +#endif + return 1; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/grsum.c linux-2.6.27.15-g-v/grsecurity/grsum.c --- linux-2.6.27.15/grsecurity/grsum.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/grsum.c 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,59 @@ +#include +#include +#include +#include +#include +#include +#include + + +#if !defined(CONFIG_CRYPTO) || defined(CONFIG_CRYPTO_MODULE) || !defined(CONFIG_CRYPTO_SHA256) || defined(CONFIG_CRYPTO_SHA256_MODULE) +#error "crypto and sha256 must be built into the kernel" +#endif + +int +chkpw(struct gr_arg *entry, unsigned char *salt, unsigned char *sum) +{ + char *p; + struct crypto_hash *tfm; + struct hash_desc desc; + struct scatterlist sg; + unsigned char temp_sum[GR_SHA_LEN]; + volatile int retval = 0; + volatile int dummy = 0; + unsigned int i; + + tfm = crypto_alloc_hash("sha256", 0, CRYPTO_ALG_ASYNC); + if (IS_ERR(tfm)) { + /* should never happen, since sha256 should be built in */ + return 1; + } + + desc.tfm = tfm; + desc.flags = 0; + + crypto_hash_init(&desc); + + p = salt; + sg_set_buf(&sg, p, GR_SALT_LEN); + crypto_hash_update(&desc, &sg, sg.length); + + p = entry->pw; + sg_set_buf(&sg, p, strlen(p)); + + crypto_hash_update(&desc, &sg, sg.length); + + crypto_hash_final(&desc, temp_sum); + + memset(entry->pw, 0, GR_PW_LEN); + + for (i = 0; i < GR_SHA_LEN; i++) + if (sum[i] != temp_sum[i]) + retval = 1; + else + dummy = 1; // waste a cycle + + crypto_free_hash(tfm); + + return retval; +} diff -NurpP --minimal linux-2.6.27.15/grsecurity/Kconfig linux-2.6.27.15-g-v/grsecurity/Kconfig --- linux-2.6.27.15/grsecurity/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/Kconfig 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,863 @@ +# +# grecurity configuration +# + +menu "Grsecurity" + +config GRKERNSEC + bool "Grsecurity" + select CRYPTO + select CRYPTO_SHA256 + select SECURITY + select SECURITY_CAPABILITIES + help + If you say Y here, you will be able to configure many features + that will enhance the security of your system. It is highly + recommended that you say Y here and read through the help + for each option so that you fully understand the features and + can evaluate their usefulness for your machine. + +choice + prompt "Security Level" + depends on GRKERNSEC + default GRKERNSEC_CUSTOM + +config GRKERNSEC_LOW + bool "Low" + select GRKERNSEC_LINK + select GRKERNSEC_FIFO + select GRKERNSEC_EXECVE + select GRKERNSEC_RANDNET + select GRKERNSEC_DMESG + select GRKERNSEC_CHROOT_CHDIR + select GRKERNSEC_MODSTOP if (MODULES) + + help + If you choose this option, several of the grsecurity options will + be enabled that will give you greater protection against a number + of attacks, while assuring that none of your software will have any + conflicts with the additional security measures. If you run a lot + of unusual software, or you are having problems with the higher + security levels, you should say Y here. With this option, the + following features are enabled: + + - Linking restrictions + - FIFO restrictions + - Enforcing RLIMIT_NPROC on execve + - Restricted dmesg + - Enforced chdir("/") on chroot + - Runtime module disabling + +config GRKERNSEC_MEDIUM + bool "Medium" + select PAX + select PAX_EI_PAX + select PAX_PT_PAX_FLAGS + select PAX_HAVE_ACL_FLAGS + select GRKERNSEC_PROC_MEMMAP if (PAX_NOEXEC || PAX_ASLR) + select GRKERNSEC_CHROOT_SYSCTL + select GRKERNSEC_LINK + select GRKERNSEC_FIFO + select GRKERNSEC_EXECVE + select GRKERNSEC_DMESG + select GRKERNSEC_RANDNET + select GRKERNSEC_FORKFAIL + select GRKERNSEC_TIME + select GRKERNSEC_SIGNAL + select GRKERNSEC_CHROOT + select GRKERNSEC_CHROOT_UNIX + select GRKERNSEC_CHROOT_MOUNT + select GRKERNSEC_CHROOT_PIVOT + select GRKERNSEC_CHROOT_DOUBLE + select GRKERNSEC_CHROOT_CHDIR + select GRKERNSEC_CHROOT_MKNOD + select GRKERNSEC_PROC + select GRKERNSEC_PROC_USERGROUP + select GRKERNSEC_MODSTOP if (MODULES) + select PAX_RANDUSTACK + select PAX_ASLR + select PAX_RANDMMAP + select PAX_REFCOUNT if (X86) + + help + If you say Y here, several features in addition to those included + in the low additional security level will be enabled. These + features provide even more security to your system, though in rare + cases they may be incompatible with very old or poorly written + software. If you enable this option, make sure that your auth + service (identd) is running as gid 1001. With this option, + the following features (in addition to those provided in the + low additional security level) will be enabled: + + - Failed fork logging + - Time change logging + - Signal logging + - Deny mounts in chroot + - Deny double chrooting + - Deny sysctl writes in chroot + - Deny mknod in chroot + - Deny access to abstract AF_UNIX sockets out of chroot + - Deny pivot_root in chroot + - Denied writes of /dev/kmem, /dev/mem, and /dev/port + - /proc restrictions with special GID set to 10 (usually wheel) + - Address Space Layout Randomization (ASLR) + +config GRKERNSEC_HIGH + bool "High" + select GRKERNSEC_LINK + select GRKERNSEC_FIFO + select GRKERNSEC_EXECVE + select GRKERNSEC_DMESG + select GRKERNSEC_FORKFAIL + select GRKERNSEC_TIME + select GRKERNSEC_SIGNAL + select GRKERNSEC_CHROOT_SHMAT + select GRKERNSEC_CHROOT_UNIX + select GRKERNSEC_CHROOT_MOUNT + select GRKERNSEC_CHROOT_FCHDIR + select GRKERNSEC_CHROOT_PIVOT + select GRKERNSEC_CHROOT_DOUBLE + select GRKERNSEC_CHROOT_CHDIR + select GRKERNSEC_CHROOT_MKNOD + select GRKERNSEC_CHROOT_CAPS + select GRKERNSEC_CHROOT_SYSCTL + select GRKERNSEC_CHROOT_FINDTASK + select GRKERNSEC_PROC + select GRKERNSEC_PROC_MEMMAP if (PAX_NOEXEC || PAX_ASLR) + select GRKERNSEC_HIDESYM + select GRKERNSEC_BRUTE + select GRKERNSEC_PROC_USERGROUP + select GRKERNSEC_KMEM + select GRKERNSEC_RESLOG + select GRKERNSEC_RANDNET + select GRKERNSEC_PROC_ADD + select GRKERNSEC_CHROOT_CHMOD + select GRKERNSEC_CHROOT_NICE + select GRKERNSEC_AUDIT_MOUNT + select GRKERNSEC_MODSTOP if (MODULES) + select PAX + select PAX_RANDUSTACK + select PAX_ASLR + select PAX_RANDMMAP + select PAX_NOEXEC + select PAX_MPROTECT + select PAX_EI_PAX + select PAX_PT_PAX_FLAGS + select PAX_HAVE_ACL_FLAGS + select PAX_KERNEXEC if (X86 && !EFI && !COMPAT_VDSO && !PARAVIRT && (!X86_32 || X86_WP_WORKS_OK)) + select PAX_MEMORY_UDEREF if (!X86_64 && !COMPAT_VDSO) + select PAX_RANDKSTACK if (X86_TSC && !X86_64) + select PAX_SEGMEXEC if (X86 && !X86_64) + select PAX_PAGEEXEC if (!X86) + select PAX_EMUPLT if (ALPHA || PARISC || PPC32 || SPARC32 || SPARC64) + select PAX_DLRESOLVE if (SPARC32 || SPARC64) + select PAX_SYSCALL if (PPC32) + select PAX_EMUTRAMP if (PARISC) + select PAX_EMUSIGRT if (PARISC) + select PAX_ETEXECRELOCS if (ALPHA || IA64 || PARISC) + select PAX_REFCOUNT if (X86) + help + If you say Y here, many of the features of grsecurity will be + enabled, which will protect you against many kinds of attacks + against your system. The heightened security comes at a cost + of an increased chance of incompatibilities with rare software + on your machine. Since this security level enables PaX, you should + view and read about the PaX + project. While you are there, download chpax and run it on + binaries that cause problems with PaX. Also remember that + since the /proc restrictions are enabled, you must run your + identd as gid 1001. This security level enables the following + features in addition to those listed in the low and medium + security levels: + + - Additional /proc restrictions + - Chmod restrictions in chroot + - No signals, ptrace, or viewing of processes outside of chroot + - Capability restrictions in chroot + - Deny fchdir out of chroot + - Priority restrictions in chroot + - Segmentation-based implementation of PaX + - Mprotect restrictions + - Removal of addresses from /proc//[smaps|maps|stat] + - Kernel stack randomization + - Mount/unmount/remount logging + - Kernel symbol hiding + - Prevention of memory exhaustion-based exploits +config GRKERNSEC_CUSTOM + bool "Custom" + help + If you say Y here, you will be able to configure every grsecurity + option, which allows you to enable many more features that aren't + covered in the basic security levels. These additional features + include TPE, socket restrictions, and the sysctl system for + grsecurity. It is advised that you read through the help for + each option to determine its usefulness in your situation. + +endchoice + +menu "Address Space Protection" +depends on GRKERNSEC + +config GRKERNSEC_KMEM + bool "Deny writing to /dev/kmem, /dev/mem, and /dev/port" + help + If you say Y here, /dev/kmem and /dev/mem won't be allowed to + be written to via mmap or otherwise to modify the running kernel. + /dev/port will also not be allowed to be opened. If you have module + support disabled, enabling this will close up four ways that are + currently used to insert malicious code into the running kernel. + Even with all these features enabled, we still highly recommend that + you use the RBAC system, as it is still possible for an attacker to + modify the running kernel through privileged I/O granted by ioperm/iopl. + If you are not using XFree86, you may be able to stop this additional + case by enabling the 'Disable privileged I/O' option. Though nothing + legitimately writes to /dev/kmem, XFree86 does need to write to /dev/mem, + but only to video memory, which is the only writing we allow in this + case. If /dev/kmem or /dev/mem are mmaped without PROT_WRITE, they will + not be allowed to mprotect it with PROT_WRITE later. + It is highly recommended that you say Y here if you meet all the + conditions above. + +config GRKERNSEC_IO + bool "Disable privileged I/O" + depends on X86 + select RTC + help + If you say Y here, all ioperm and iopl calls will return an error. + Ioperm and iopl can be used to modify the running kernel. + Unfortunately, some programs need this access to operate properly, + the most notable of which are XFree86 and hwclock. hwclock can be + remedied by having RTC support in the kernel, so CONFIG_RTC is + enabled if this option is enabled, to ensure that hwclock operates + correctly. XFree86 still will not operate correctly with this option + enabled, so DO NOT CHOOSE Y IF YOU USE XFree86. If you use XFree86 + and you still want to protect your kernel against modification, + use the RBAC system. + +config GRKERNSEC_PROC_MEMMAP + bool "Remove addresses from /proc//[smaps|maps|stat]" + depends on PAX_NOEXEC || PAX_ASLR + help + If you say Y here, the /proc//maps and /proc//stat files will + give no information about the addresses of its mappings if + PaX features that rely on random addresses are enabled on the task. + If you use PaX it is greatly recommended that you say Y here as it + closes up a hole that makes the full ASLR useless for suid + binaries. + +config GRKERNSEC_BRUTE + bool "Deter exploit bruteforcing" + help + If you say Y here, attempts to bruteforce exploits against forking + daemons such as apache or sshd will be deterred. When a child of a + forking daemon is killed by PaX or crashes due to an illegal + instruction, the parent process will be delayed 30 seconds upon every + subsequent fork until the administrator is able to assess the + situation and restart the daemon. It is recommended that you also + enable signal logging in the auditing section so that logs are + generated when a process performs an illegal instruction. + +config GRKERNSEC_MODSTOP + bool "Runtime module disabling" + depends on MODULES + help + If you say Y here, you will be able to disable the ability to (un)load + modules at runtime. This feature is useful if you need the ability + to load kernel modules at boot time, but do not want to allow an + attacker to load a rootkit kernel module into the system, or to remove + a loaded kernel module important to system functioning. You should + enable the /dev/mem protection feature as well, since rootkits can be + inserted into the kernel via other methods than kernel modules. Since + an untrusted module could still be loaded by modifying init scripts and + rebooting the system, it is also recommended that you enable the RBAC + system. If you enable this option, a sysctl option with name + "disable_modules" will be created. Setting this option to "1" disables + module loading. After this option is set, no further writes to it are + allowed until the system is rebooted. + +config GRKERNSEC_HIDESYM + bool "Hide kernel symbols" + help + If you say Y here, getting information on loaded modules, and + displaying all kernel symbols through a syscall will be restricted + to users with CAP_SYS_MODULE. This option is only effective + provided the following conditions are met: + 1) The kernel using grsecurity is not precompiled by some distribution + 2) You are using the RBAC system and hiding other files such as your + kernel image and System.map + 3) You have the additional /proc restrictions enabled, which removes + /proc/kcore + If the above conditions are met, this option will aid to provide a + useful protection against local and remote kernel exploitation of + overflows and arbitrary read/write vulnerabilities. + +endmenu +menu "Role Based Access Control Options" +depends on GRKERNSEC + +config GRKERNSEC_ACL_HIDEKERN + bool "Hide kernel processes" + help + If you say Y here, all kernel threads will be hidden to all + processes but those whose subject has the "view hidden processes" + flag. + +config GRKERNSEC_ACL_MAXTRIES + int "Maximum tries before password lockout" + default 3 + help + This option enforces the maximum number of times a user can attempt + to authorize themselves with the grsecurity RBAC system before being + denied the ability to attempt authorization again for a specified time. + The lower the number, the harder it will be to brute-force a password. + +config GRKERNSEC_ACL_TIMEOUT + int "Time to wait after max password tries, in seconds" + default 30 + help + This option specifies the time the user must wait after attempting to + authorize to the RBAC system with the maximum number of invalid + passwords. The higher the number, the harder it will be to brute-force + a password. + +endmenu +menu "Filesystem Protections" +depends on GRKERNSEC + +config GRKERNSEC_PROC + bool "Proc restrictions" + help + If you say Y here, the permissions of the /proc filesystem + will be altered to enhance system security and privacy. You MUST + choose either a user only restriction or a user and group restriction. + Depending upon the option you choose, you can either restrict users to + see only the processes they themselves run, or choose a group that can + view all processes and files normally restricted to root if you choose + the "restrict to user only" option. NOTE: If you're running identd as + a non-root user, you will have to run it as the group you specify here. + +config GRKERNSEC_PROC_USER + bool "Restrict /proc to user only" + depends on GRKERNSEC_PROC + help + If you say Y here, non-root users will only be able to view their own + processes, and restricts them from viewing network-related information, + and viewing kernel symbol and module information. + +config GRKERNSEC_PROC_USERGROUP + bool "Allow special group" + depends on GRKERNSEC_PROC && !GRKERNSEC_PROC_USER + help + If you say Y here, you will be able to select a group that will be + able to view all processes, network-related information, and + kernel and symbol information. This option is useful if you want + to run identd as a non-root user. + +config GRKERNSEC_PROC_GID + int "GID for special group" + depends on GRKERNSEC_PROC_USERGROUP + default 1001 + +config GRKERNSEC_PROC_ADD + bool "Additional restrictions" + depends on GRKERNSEC_PROC_USER || GRKERNSEC_PROC_USERGROUP + help + If you say Y here, additional restrictions will be placed on + /proc that keep normal users from viewing device information and + slabinfo information that could be useful for exploits. + +config GRKERNSEC_LINK + bool "Linking restrictions" + help + If you say Y here, /tmp race exploits will be prevented, since users + will no longer be able to follow symlinks owned by other users in + world-writable +t directories (i.e. /tmp), unless the owner of the + symlink is the owner of the directory. users will also not be + able to hardlink to files they do not own. If the sysctl option is + enabled, a sysctl option with name "linking_restrictions" is created. + +config GRKERNSEC_FIFO + bool "FIFO restrictions" + help + If you say Y here, users will not be able to write to FIFOs they don't + own in world-writable +t directories (i.e. /tmp), unless the owner of + the FIFO is the same owner of the directory it's held in. If the sysctl + option is enabled, a sysctl option with name "fifo_restrictions" is + created. + +config GRKERNSEC_CHROOT + bool "Chroot jail restrictions" + help + If you say Y here, you will be able to choose several options that will + make breaking out of a chrooted jail much more difficult. If you + encounter no software incompatibilities with the following options, it + is recommended that you enable each one. + +config GRKERNSEC_CHROOT_MOUNT + bool "Deny mounts" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be able to + mount or remount filesystems. If the sysctl option is enabled, a + sysctl option with name "chroot_deny_mount" is created. + +config GRKERNSEC_CHROOT_DOUBLE + bool "Deny double-chroots" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be able to chroot + again outside the chroot. This is a widely used method of breaking + out of a chroot jail and should not be allowed. If the sysctl + option is enabled, a sysctl option with name + "chroot_deny_chroot" is created. + +config GRKERNSEC_CHROOT_PIVOT + bool "Deny pivot_root in chroot" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be able to use + a function called pivot_root() that was introduced in Linux 2.3.41. It + works similar to chroot in that it changes the root filesystem. This + function could be misused in a chrooted process to attempt to break out + of the chroot, and therefore should not be allowed. If the sysctl + option is enabled, a sysctl option with name "chroot_deny_pivot" is + created. + +config GRKERNSEC_CHROOT_CHDIR + bool "Enforce chdir(\"/\") on all chroots" + depends on GRKERNSEC_CHROOT + help + If you say Y here, the current working directory of all newly-chrooted + applications will be set to the the root directory of the chroot. + The man page on chroot(2) states: + Note that this call does not change the current working + directory, so that `.' can be outside the tree rooted at + `/'. In particular, the super-user can escape from a + `chroot jail' by doing `mkdir foo; chroot foo; cd ..'. + + It is recommended that you say Y here, since it's not known to break + any software. If the sysctl option is enabled, a sysctl option with + name "chroot_enforce_chdir" is created. + +config GRKERNSEC_CHROOT_CHMOD + bool "Deny (f)chmod +s" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be able to chmod + or fchmod files to make them have suid or sgid bits. This protects + against another published method of breaking a chroot. If the sysctl + option is enabled, a sysctl option with name "chroot_deny_chmod" is + created. + +config GRKERNSEC_CHROOT_FCHDIR + bool "Deny fchdir out of chroot" + depends on GRKERNSEC_CHROOT + help + If you say Y here, a well-known method of breaking chroots by fchdir'ing + to a file descriptor of the chrooting process that points to a directory + outside the filesystem will be stopped. If the sysctl option + is enabled, a sysctl option with name "chroot_deny_fchdir" is created. + +config GRKERNSEC_CHROOT_MKNOD + bool "Deny mknod" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be allowed to + mknod. The problem with using mknod inside a chroot is that it + would allow an attacker to create a device entry that is the same + as one on the physical root of your system, which could range from + anything from the console device to a device for your harddrive (which + they could then use to wipe the drive or steal data). It is recommended + that you say Y here, unless you run into software incompatibilities. + If the sysctl option is enabled, a sysctl option with name + "chroot_deny_mknod" is created. + +config GRKERNSEC_CHROOT_SHMAT + bool "Deny shmat() out of chroot" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be able to attach + to shared memory segments that were created outside of the chroot jail. + It is recommended that you say Y here. If the sysctl option is enabled, + a sysctl option with name "chroot_deny_shmat" is created. + +config GRKERNSEC_CHROOT_UNIX + bool "Deny access to abstract AF_UNIX sockets out of chroot" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be able to + connect to abstract (meaning not belonging to a filesystem) Unix + domain sockets that were bound outside of a chroot. It is recommended + that you say Y here. If the sysctl option is enabled, a sysctl option + with name "chroot_deny_unix" is created. + +config GRKERNSEC_CHROOT_FINDTASK + bool "Protect outside processes" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be able to + kill, send signals with fcntl, ptrace, capget, getpgid, getsid, + or view any process outside of the chroot. If the sysctl + option is enabled, a sysctl option with name "chroot_findtask" is + created. + +config GRKERNSEC_CHROOT_NICE + bool "Restrict priority changes" + depends on GRKERNSEC_CHROOT + help + If you say Y here, processes inside a chroot will not be able to raise + the priority of processes in the chroot, or alter the priority of + processes outside the chroot. This provides more security than simply + removing CAP_SYS_NICE from the process' capability set. If the + sysctl option is enabled, a sysctl option with name "chroot_restrict_nice" + is created. + +config GRKERNSEC_CHROOT_SYSCTL + bool "Deny sysctl writes" + depends on GRKERNSEC_CHROOT + help + If you say Y here, an attacker in a chroot will not be able to + write to sysctl entries, either by sysctl(2) or through a /proc + interface. It is strongly recommended that you say Y here. If the + sysctl option is enabled, a sysctl option with name + "chroot_deny_sysctl" is created. + +config GRKERNSEC_CHROOT_CAPS + bool "Capability restrictions" + depends on GRKERNSEC_CHROOT + help + If you say Y here, the capabilities on all root processes within a + chroot jail will be lowered to stop module insertion, raw i/o, + system and net admin tasks, rebooting the system, modifying immutable + files, modifying IPC owned by another, and changing the system time. + This is left an option because it can break some apps. Disable this + if your chrooted apps are having problems performing those kinds of + tasks. If the sysctl option is enabled, a sysctl option with + name "chroot_caps" is created. + +endmenu +menu "Kernel Auditing" +depends on GRKERNSEC + +config GRKERNSEC_AUDIT_GROUP + bool "Single group for auditing" + help + If you say Y here, the exec, chdir, (un)mount, and ipc logging features + will only operate on a group you specify. This option is recommended + if you only want to watch certain users instead of having a large + amount of logs from the entire system. If the sysctl option is enabled, + a sysctl option with name "audit_group" is created. + +config GRKERNSEC_AUDIT_GID + int "GID for auditing" + depends on GRKERNSEC_AUDIT_GROUP + default 1007 + +config GRKERNSEC_EXECLOG + bool "Exec logging" + help + If you say Y here, all execve() calls will be logged (since the + other exec*() calls are frontends to execve(), all execution + will be logged). Useful for shell-servers that like to keep track + of their users. If the sysctl option is enabled, a sysctl option with + name "exec_logging" is created. + WARNING: This option when enabled will produce a LOT of logs, especially + on an active system. + +config GRKERNSEC_RESLOG + bool "Resource logging" + help + If you say Y here, all attempts to overstep resource limits will + be logged with the resource name, the requested size, and the current + limit. It is highly recommended that you say Y here. If the sysctl + option is enabled, a sysctl option with name "resource_logging" is + created. If the RBAC system is enabled, the sysctl value is ignored. + +config GRKERNSEC_CHROOT_EXECLOG + bool "Log execs within chroot" + help + If you say Y here, all executions inside a chroot jail will be logged + to syslog. This can cause a large amount of logs if certain + applications (eg. djb's daemontools) are installed on the system, and + is therefore left as an option. If the sysctl option is enabled, a + sysctl option with name "chroot_execlog" is created. + +config GRKERNSEC_AUDIT_CHDIR + bool "Chdir logging" + help + If you say Y here, all chdir() calls will be logged. If the sysctl + option is enabled, a sysctl option with name "audit_chdir" is created. + +config GRKERNSEC_AUDIT_MOUNT + bool "(Un)Mount logging" + help + If you say Y here, all mounts and unmounts will be logged. If the + sysctl option is enabled, a sysctl option with name "audit_mount" is + created. + +config GRKERNSEC_AUDIT_IPC + bool "IPC logging" + help + If you say Y here, creation and removal of message queues, semaphores, + and shared memory will be logged. If the sysctl option is enabled, a + sysctl option with name "audit_ipc" is created. + +config GRKERNSEC_SIGNAL + bool "Signal logging" + help + If you say Y here, certain important signals will be logged, such as + SIGSEGV, which will as a result inform you of when a error in a program + occurred, which in some cases could mean a possible exploit attempt. + If the sysctl option is enabled, a sysctl option with name + "signal_logging" is created. + +config GRKERNSEC_FORKFAIL + bool "Fork failure logging" + help + If you say Y here, all failed fork() attempts will be logged. + This could suggest a fork bomb, or someone attempting to overstep + their process limit. If the sysctl option is enabled, a sysctl option + with name "forkfail_logging" is created. + +config GRKERNSEC_TIME + bool "Time change logging" + help + If you say Y here, any changes of the system clock will be logged. + If the sysctl option is enabled, a sysctl option with name + "timechange_logging" is created. + +config GRKERNSEC_PROC_IPADDR + bool "/proc//ipaddr support" + help + If you say Y here, a new entry will be added to each /proc/ + directory that contains the IP address of the person using the task. + The IP is carried across local TCP and AF_UNIX stream sockets. + This information can be useful for IDS/IPSes to perform remote response + to a local attack. The entry is readable by only the owner of the + process (and root if he has CAP_DAC_OVERRIDE, which can be removed via + the RBAC system), and thus does not create privacy concerns. + +config GRKERNSEC_AUDIT_TEXTREL + bool 'ELF text relocations logging (READ HELP)' + depends on PAX_MPROTECT + help + If you say Y here, text relocations will be logged with the filename + of the offending library or binary. The purpose of the feature is + to help Linux distribution developers get rid of libraries and + binaries that need text relocations which hinder the future progress + of PaX. Only Linux distribution developers should say Y here, and + never on a production machine, as this option creates an information + leak that could aid an attacker in defeating the randomization of + a single memory region. If the sysctl option is enabled, a sysctl + option with name "audit_textrel" is created. + +endmenu + +menu "Executable Protections" +depends on GRKERNSEC + +config GRKERNSEC_EXECVE + bool "Enforce RLIMIT_NPROC on execs" + help + If you say Y here, users with a resource limit on processes will + have the value checked during execve() calls. The current system + only checks the system limit during fork() calls. If the sysctl option + is enabled, a sysctl option with name "execve_limiting" is created. + +config GRKERNSEC_DMESG + bool "Dmesg(8) restriction" + help + If you say Y here, non-root users will not be able to use dmesg(8) + to view up to the last 4kb of messages in the kernel's log buffer. + If the sysctl option is enabled, a sysctl option with name "dmesg" is + created. + +config GRKERNSEC_TPE + bool "Trusted Path Execution (TPE)" + help + If you say Y here, you will be able to choose a gid to add to the + supplementary groups of users you want to mark as "untrusted." + These users will not be able to execute any files that are not in + root-owned directories writable only by root. If the sysctl option + is enabled, a sysctl option with name "tpe" is created. + +config GRKERNSEC_TPE_ALL + bool "Partially restrict non-root users" + depends on GRKERNSEC_TPE + help + If you say Y here, All non-root users other than the ones in the + group specified in the main TPE option will only be allowed to + execute files in directories they own that are not group or + world-writable, or in directories owned by root and writable only by + root. If the sysctl option is enabled, a sysctl option with name + "tpe_restrict_all" is created. + +config GRKERNSEC_TPE_INVERT + bool "Invert GID option" + depends on GRKERNSEC_TPE + help + If you say Y here, the group you specify in the TPE configuration will + decide what group TPE restrictions will be *disabled* for. This + option is useful if you want TPE restrictions to be applied to most + users on the system. + +config GRKERNSEC_TPE_GID + int "GID for untrusted users" + depends on GRKERNSEC_TPE && !GRKERNSEC_TPE_INVERT + default 1005 + help + If you have selected the "Invert GID option" above, setting this + GID determines what group TPE restrictions will be *disabled* for. + If you have not selected the "Invert GID option" above, setting this + GID determines what group TPE restrictions will be *enabled* for. + If the sysctl option is enabled, a sysctl option with name "tpe_gid" + is created. + +config GRKERNSEC_TPE_GID + int "GID for trusted users" + depends on GRKERNSEC_TPE && GRKERNSEC_TPE_INVERT + default 1005 + help + If you have selected the "Invert GID option" above, setting this + GID determines what group TPE restrictions will be *disabled* for. + If you have not selected the "Invert GID option" above, setting this + GID determines what group TPE restrictions will be *enabled* for. + If the sysctl option is enabled, a sysctl option with name "tpe_gid" + is created. + +endmenu +menu "Network Protections" +depends on GRKERNSEC + +config GRKERNSEC_RANDNET + bool "Larger entropy pools" + help + If you say Y here, the entropy pools used for many features of Linux + and grsecurity will be doubled in size. Since several grsecurity + features use additional randomness, it is recommended that you say Y + here. Saying Y here has a similar effect as modifying + /proc/sys/kernel/random/poolsize. + +config GRKERNSEC_SOCKET + bool "Socket restrictions" + help + If you say Y here, you will be able to choose from several options. + If you assign a GID on your system and add it to the supplementary + groups of users you want to restrict socket access to, this patch + will perform up to three things, based on the option(s) you choose. + +config GRKERNSEC_SOCKET_ALL + bool "Deny any sockets to group" + depends on GRKERNSEC_SOCKET + help + If you say Y here, you will be able to choose a GID of whose users will + be unable to connect to other hosts from your machine or run server + applications from your machine. If the sysctl option is enabled, a + sysctl option with name "socket_all" is created. + +config GRKERNSEC_SOCKET_ALL_GID + int "GID to deny all sockets for" + depends on GRKERNSEC_SOCKET_ALL + default 1004 + help + Here you can choose the GID to disable socket access for. Remember to + add the users you want socket access disabled for to the GID + specified here. If the sysctl option is enabled, a sysctl option + with name "socket_all_gid" is created. + +config GRKERNSEC_SOCKET_CLIENT + bool "Deny client sockets to group" + depends on GRKERNSEC_SOCKET + help + If you say Y here, you will be able to choose a GID of whose users will + be unable to connect to other hosts from your machine, but will be + able to run servers. If this option is enabled, all users in the group + you specify will have to use passive mode when initiating ftp transfers + from the shell on your machine. If the sysctl option is enabled, a + sysctl option with name "socket_client" is created. + +config GRKERNSEC_SOCKET_CLIENT_GID + int "GID to deny client sockets for" + depends on GRKERNSEC_SOCKET_CLIENT + default 1003 + help + Here you can choose the GID to disable client socket access for. + Remember to add the users you want client socket access disabled for to + the GID specified here. If the sysctl option is enabled, a sysctl + option with name "socket_client_gid" is created. + +config GRKERNSEC_SOCKET_SERVER + bool "Deny server sockets to group" + depends on GRKERNSEC_SOCKET + help + If you say Y here, you will be able to choose a GID of whose users will + be unable to run server applications from your machine. If the sysctl + option is enabled, a sysctl option with name "socket_server" is created. + +config GRKERNSEC_SOCKET_SERVER_GID + int "GID to deny server sockets for" + depends on GRKERNSEC_SOCKET_SERVER + default 1002 + help + Here you can choose the GID to disable server socket access for. + Remember to add the users you want server socket access disabled for to + the GID specified here. If the sysctl option is enabled, a sysctl + option with name "socket_server_gid" is created. + +endmenu +menu "Sysctl support" +depends on GRKERNSEC && SYSCTL + +config GRKERNSEC_SYSCTL + bool "Sysctl support" + help + If you say Y here, you will be able to change the options that + grsecurity runs with at bootup, without having to recompile your + kernel. You can echo values to files in /proc/sys/kernel/grsecurity + to enable (1) or disable (0) various features. All the sysctl entries + are mutable until the "grsec_lock" entry is set to a non-zero value. + All features enabled in the kernel configuration are disabled at boot + if you do not say Y to the "Turn on features by default" option. + All options should be set at startup, and the grsec_lock entry should + be set to a non-zero value after all the options are set. + *THIS IS EXTREMELY IMPORTANT* + +config GRKERNSEC_SYSCTL_ON + bool "Turn on features by default" + depends on GRKERNSEC_SYSCTL + help + If you say Y here, instead of having all features enabled in the + kernel configuration disabled at boot time, the features will be + enabled at boot time. It is recommended you say Y here unless + there is some reason you would want all sysctl-tunable features to + be disabled by default. As mentioned elsewhere, it is important + to enable the grsec_lock entry once you have finished modifying + the sysctl entries. + +endmenu +menu "Logging Options" +depends on GRKERNSEC + +config GRKERNSEC_FLOODTIME + int "Seconds in between log messages (minimum)" + default 10 + help + This option allows you to enforce the number of seconds between + grsecurity log messages. The default should be suitable for most + people, however, if you choose to change it, choose a value small enough + to allow informative logs to be produced, but large enough to + prevent flooding. + +config GRKERNSEC_FLOODBURST + int "Number of messages in a burst (maximum)" + default 4 + help + This option allows you to choose the maximum number of messages allowed + within the flood time interval you chose in a separate option. The + default should be suitable for most people, however if you find that + many of your logs are being interpreted as flooding, you may want to + raise this value. + +endmenu + +endmenu diff -NurpP --minimal linux-2.6.27.15/grsecurity/Makefile linux-2.6.27.15-g-v/grsecurity/Makefile --- linux-2.6.27.15/grsecurity/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/grsecurity/Makefile 2009-02-10 20:32:14.000000000 +0100 @@ -0,0 +1,20 @@ +# grsecurity's ACL system was originally written in 2001 by Michael Dalton +# during 2001-2005 it has been completely redesigned by Brad Spengler +# into an RBAC system +# +# All code in this directory and various hooks inserted throughout the kernel +# are copyright Brad Spengler, and released under the GPL v2 or higher + +obj-y = grsec_chdir.o grsec_chroot.o grsec_exec.o grsec_fifo.o grsec_fork.o \ + grsec_mount.o grsec_sig.o grsec_sock.o grsec_sysctl.o \ + grsec_time.o grsec_tpe.o grsec_ipc.o grsec_link.o grsec_textrel.o + +obj-$(CONFIG_GRKERNSEC) += grsec_init.o grsum.o gracl.o gracl_ip.o gracl_segv.o \ + gracl_cap.o gracl_alloc.o gracl_shm.o grsec_mem.o gracl_fs.o \ + gracl_learn.o grsec_log.o +obj-$(CONFIG_GRKERNSEC_RESLOG) += gracl_res.o + +ifndef CONFIG_GRKERNSEC +obj-y += grsec_disabled.o +endif + diff -NurpP --minimal linux-2.6.27.15/include/asm-cris/kmap_types.h linux-2.6.27.15-g-v/include/asm-cris/kmap_types.h --- linux-2.6.27.15/include/asm-cris/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-cris/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -19,6 +19,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/include/asm-frv/kmap_types.h linux-2.6.27.15-g-v/include/asm-frv/kmap_types.h --- linux-2.6.27.15/include/asm-frv/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-frv/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -23,6 +23,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/include/asm-generic/futex.h linux-2.6.27.15-g-v/include/asm-generic/futex.h --- linux-2.6.27.15/include/asm-generic/futex.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-generic/futex.h 2009-02-10 20:32:15.000000000 +0100 @@ -6,7 +6,7 @@ #include static inline int -futex_atomic_op_inuser (int encoded_op, int __user *uaddr) +futex_atomic_op_inuser (int encoded_op, u32 __user *uaddr) { int op = (encoded_op >> 28) & 7; int cmp = (encoded_op >> 24) & 15; @@ -48,7 +48,7 @@ futex_atomic_op_inuser (int encoded_op, } static inline int -futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, int newval) +futex_atomic_cmpxchg_inatomic(u32 __user *uaddr, int oldval, int newval) { return -ENOSYS; } diff -NurpP --minimal linux-2.6.27.15/include/asm-generic/tlb.h linux-2.6.27.15-g-v/include/asm-generic/tlb.h --- linux-2.6.27.15/include/asm-generic/tlb.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-generic/tlb.h 2009-02-10 20:32:15.000000000 +0100 @@ -14,6 +14,7 @@ #define _ASM_GENERIC__TLB_H #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/include/asm-generic/vmlinux.lds.h linux-2.6.27.15-g-v/include/asm-generic/vmlinux.lds.h --- linux-2.6.27.15/include/asm-generic/vmlinux.lds.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-generic/vmlinux.lds.h 2009-02-10 20:32:15.000000000 +0100 @@ -59,6 +59,7 @@ .rodata : AT(ADDR(.rodata) - LOAD_OFFSET) { \ VMLINUX_SYMBOL(__start_rodata) = .; \ *(.rodata) *(.rodata.*) \ + *(.data.read_only) \ *(__vermagic) /* Kernel version magic */ \ *(__markers_strings) /* Markers: strings */ \ } \ diff -NurpP --minimal linux-2.6.27.15/include/asm-m32r/kmap_types.h linux-2.6.27.15-g-v/include/asm-m32r/kmap_types.h --- linux-2.6.27.15/include/asm-m32r/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-m32r/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -21,7 +21,8 @@ D(9) KM_IRQ0, D(10) KM_IRQ1, D(11) KM_SOFTIRQ0, D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR +D(13) KM_CLEARPAGE, +D(14) KM_TYPE_NR }; #undef D diff -NurpP --minimal linux-2.6.27.15/include/asm-m68k/kmap_types.h linux-2.6.27.15-g-v/include/asm-m68k/kmap_types.h --- linux-2.6.27.15/include/asm-m68k/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-m68k/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -15,6 +15,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/include/asm-mips/elf.h linux-2.6.27.15-g-v/include/asm-mips/elf.h --- linux-2.6.27.15/include/asm-mips/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-mips/elf.h 2009-02-10 20:32:15.000000000 +0100 @@ -368,4 +368,11 @@ extern int dump_task_fpu(struct task_str #define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) #endif +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE (test_thread_flag(TIF_32BIT_ADDR) ? 0x00400000UL : 0x00400000UL) + +#define PAX_DELTA_MMAP_LEN (test_thread_flag(TIF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#define PAX_DELTA_STACK_LEN (test_thread_flag(TIF_32BIT_ADDR) ? 27-PAGE_SHIFT : 36-PAGE_SHIFT) +#endif + #endif /* _ASM_ELF_H */ diff -NurpP --minimal linux-2.6.27.15/include/asm-mips/kmap_types.h linux-2.6.27.15-g-v/include/asm-mips/kmap_types.h --- linux-2.6.27.15/include/asm-mips/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-mips/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -22,7 +22,8 @@ D(9) KM_IRQ0, D(10) KM_IRQ1, D(11) KM_SOFTIRQ0, D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR +D(13) KM_CLEARPAGE, +D(14) KM_TYPE_NR }; #undef D diff -NurpP --minimal linux-2.6.27.15/include/asm-mips/page.h linux-2.6.27.15-g-v/include/asm-mips/page.h --- linux-2.6.27.15/include/asm-mips/page.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-mips/page.h 2009-02-10 20:32:15.000000000 +0100 @@ -82,7 +82,7 @@ extern void copy_user_highpage(struct pa #ifdef CONFIG_CPU_MIPS32 typedef struct { unsigned long pte_low, pte_high; } pte_t; #define pte_val(x) ((x).pte_low | ((unsigned long long)(x).pte_high << 32)) - #define __pte(x) ({ pte_t __pte = {(x), ((unsigned long long)(x)) >> 32}; __pte; }) + #define __pte(x) ({ pte_t __pte = {(x), (x) >> 32}; __pte; }) #else typedef struct { unsigned long long pte; } pte_t; #define pte_val(x) ((x).pte) diff -NurpP --minimal linux-2.6.27.15/include/asm-mips/system.h linux-2.6.27.15-g-v/include/asm-mips/system.h --- linux-2.6.27.15/include/asm-mips/system.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-mips/system.h 2009-02-10 20:32:15.000000000 +0100 @@ -215,6 +215,6 @@ extern void per_cpu_trap_init(void); */ #define __ARCH_WANT_UNLOCKED_CTXSW -extern unsigned long arch_align_stack(unsigned long sp); +#define arch_align_stack(x) ((x) & ALMASK) #endif /* _ASM_SYSTEM_H */ diff -NurpP --minimal linux-2.6.27.15/include/asm-mn10300/kmap_types.h linux-2.6.27.15-g-v/include/asm-mn10300/kmap_types.h --- linux-2.6.27.15/include/asm-mn10300/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-mn10300/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -25,6 +25,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/include/asm-parisc/elf.h linux-2.6.27.15-g-v/include/asm-parisc/elf.h --- linux-2.6.27.15/include/asm-parisc/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-parisc/elf.h 2009-02-10 20:32:15.000000000 +0100 @@ -333,6 +333,13 @@ struct pt_regs; /* forward declaration.. #define ELF_ET_DYN_BASE (TASK_UNMAPPED_BASE + 0x01000000) +#ifdef CONFIG_PAX_ASLR +#define PAX_ELF_ET_DYN_BASE 0x10000UL + +#define PAX_DELTA_MMAP_LEN 16 +#define PAX_DELTA_STACK_LEN 16 +#endif + /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, but it's not easy, and we've already done it here. */ diff -NurpP --minimal linux-2.6.27.15/include/asm-parisc/kmap_types.h linux-2.6.27.15-g-v/include/asm-parisc/kmap_types.h --- linux-2.6.27.15/include/asm-parisc/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-parisc/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -22,7 +22,8 @@ D(9) KM_IRQ0, D(10) KM_IRQ1, D(11) KM_SOFTIRQ0, D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR +D(13) KM_CLEARPAGE, +D(14) KM_TYPE_NR }; #undef D diff -NurpP --minimal linux-2.6.27.15/include/asm-parisc/pgtable.h linux-2.6.27.15-g-v/include/asm-parisc/pgtable.h --- linux-2.6.27.15/include/asm-parisc/pgtable.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-parisc/pgtable.h 2009-02-10 20:32:15.000000000 +0100 @@ -202,6 +202,17 @@ #define PAGE_EXECREAD __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_EXEC |_PAGE_ACCESSED) #define PAGE_COPY PAGE_EXECREAD #define PAGE_RWX __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_EXEC |_PAGE_ACCESSED) + +#ifdef CONFIG_PAX_PAGEEXEC +# define PAGE_SHARED_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_WRITE | _PAGE_ACCESSED) +# define PAGE_COPY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_ACCESSED) +# define PAGE_READONLY_NOEXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | _PAGE_READ | _PAGE_ACCESSED) +#else +# define PAGE_SHARED_NOEXEC PAGE_SHARED +# define PAGE_COPY_NOEXEC PAGE_COPY +# define PAGE_READONLY_NOEXEC PAGE_READONLY +#endif + #define PAGE_KERNEL __pgprot(_PAGE_KERNEL) #define PAGE_KERNEL_RO __pgprot(_PAGE_KERNEL & ~_PAGE_WRITE) #define PAGE_KERNEL_UNC __pgprot(_PAGE_KERNEL | _PAGE_NO_CACHE) diff -NurpP --minimal linux-2.6.27.15/include/asm-um/kmap_types.h linux-2.6.27.15-g-v/include/asm-um/kmap_types.h --- linux-2.6.27.15/include/asm-um/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-um/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -23,6 +23,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/include/asm-um/page.h linux-2.6.27.15-g-v/include/asm-um/page.h --- linux-2.6.27.15/include/asm-um/page.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-um/page.h 2009-02-10 20:32:15.000000000 +0100 @@ -14,6 +14,9 @@ #define PAGE_SIZE (_AC(1, UL) << PAGE_SHIFT) #define PAGE_MASK (~(PAGE_SIZE-1)) +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) + #ifndef __ASSEMBLY__ struct page; diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/alternative.h linux-2.6.27.15-g-v/include/asm-x86/alternative.h --- linux-2.6.27.15/include/asm-x86/alternative.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/alternative.h 2009-02-10 20:32:15.000000000 +0100 @@ -96,7 +96,7 @@ const unsigned char *const *find_nop_tab " .byte 662b-661b\n" /* sourcelen */ \ " .byte 664f-663f\n" /* replacementlen */ \ ".previous\n" \ - ".section .altinstr_replacement,\"ax\"\n" \ + ".section .altinstr_replacement,\"a\"\n" \ "663:\n\t" newinstr "\n664:\n" /* replacement */ \ ".previous" :: "i" (feature) : "memory") @@ -120,7 +120,7 @@ const unsigned char *const *find_nop_tab " .byte 662b-661b\n" /* sourcelen */ \ " .byte 664f-663f\n" /* replacementlen */ \ ".previous\n" \ - ".section .altinstr_replacement,\"ax\"\n" \ + ".section .altinstr_replacement,\"a\"\n" \ "663:\n\t" newinstr "\n664:\n" /* replacement */ \ ".previous" :: "i" (feature), ##input) @@ -135,7 +135,7 @@ const unsigned char *const *find_nop_tab " .byte 662b-661b\n" /* sourcelen */ \ " .byte 664f-663f\n" /* replacementlen */ \ ".previous\n" \ - ".section .altinstr_replacement,\"ax\"\n" \ + ".section .altinstr_replacement,\"a\"\n" \ "663:\n\t" newinstr "\n664:\n" /* replacement */ \ ".previous" : output : [feat] "i" (feature), ##input) diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/atomic_32.h linux-2.6.27.15-g-v/include/asm-x86/atomic_32.h --- linux-2.6.27.15/include/asm-x86/atomic_32.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/atomic_32.h 2009-02-10 20:32:15.000000000 +0100 @@ -47,7 +47,15 @@ typedef struct { */ static inline void atomic_add(int i, atomic_t *v) { - asm volatile(LOCK_PREFIX "addl %1,%0" + asm volatile(LOCK_PREFIX "addl %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "subl %1,%0\n" + "into\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "+m" (v->counter) : "ir" (i)); } @@ -61,7 +69,15 @@ static inline void atomic_add(int i, ato */ static inline void atomic_sub(int i, atomic_t *v) { - asm volatile(LOCK_PREFIX "subl %1,%0" + asm volatile(LOCK_PREFIX "subl %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "addl %1,%0\n" + "into\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "+m" (v->counter) : "ir" (i)); } @@ -79,7 +95,16 @@ static inline int atomic_sub_and_test(in { unsigned char c; - asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" + asm volatile(LOCK_PREFIX "subl %2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "addl %2,%0\n" + "into\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + "sete %1\n" : "+m" (v->counter), "=qm" (c) : "ir" (i) : "memory"); return c; @@ -93,7 +118,18 @@ static inline int atomic_sub_and_test(in */ static inline void atomic_inc(atomic_t *v) { - asm volatile(LOCK_PREFIX "incl %0" + asm volatile(LOCK_PREFIX "incl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "into\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1:\n" + LOCK_PREFIX "decl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+m" (v->counter)); } @@ -105,7 +141,18 @@ static inline void atomic_inc(atomic_t * */ static inline void atomic_dec(atomic_t *v) { - asm volatile(LOCK_PREFIX "decl %0" + asm volatile(LOCK_PREFIX "decl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "into\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "incl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+m" (v->counter)); } @@ -121,7 +168,19 @@ static inline int atomic_dec_and_test(at { unsigned char c; - asm volatile(LOCK_PREFIX "decl %0; sete %1" + asm volatile(LOCK_PREFIX "decl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "into\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "incl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "+m" (v->counter), "=qm" (c) : : "memory"); return c != 0; @@ -139,7 +198,19 @@ static inline int atomic_inc_and_test(at { unsigned char c; - asm volatile(LOCK_PREFIX "incl %0; sete %1" + asm volatile(LOCK_PREFIX "incl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "into\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "decl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "+m" (v->counter), "=qm" (c) : : "memory"); return c != 0; @@ -158,7 +229,16 @@ static inline int atomic_add_negative(in { unsigned char c; - asm volatile(LOCK_PREFIX "addl %2,%0; sets %1" + asm volatile(LOCK_PREFIX "addl %2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "subl %2,%0\n" + "into\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + "sets %1\n" : "+m" (v->counter), "=qm" (c) : "ir" (i) : "memory"); return c; @@ -181,7 +261,15 @@ static inline int atomic_add_return(int #endif /* Modern 486+ processor */ __i = i; - asm volatile(LOCK_PREFIX "xaddl %0, %1" + asm volatile(LOCK_PREFIX "xaddl %0, %1\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "movl %0, %1\n" + "into\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "+r" (i), "+m" (v->counter) : : "memory"); return i + __i; diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/atomic_64.h linux-2.6.27.15-g-v/include/asm-x86/atomic_64.h --- linux-2.6.27.15/include/asm-x86/atomic_64.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/atomic_64.h 2009-02-10 20:32:15.000000000 +0100 @@ -48,7 +48,15 @@ typedef struct { */ static inline void atomic_add(int i, atomic_t *v) { - asm volatile(LOCK_PREFIX "addl %1,%0" + asm volatile(LOCK_PREFIX "addl %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "subl %1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "=m" (v->counter) : "ir" (i), "m" (v->counter)); } @@ -62,7 +70,15 @@ static inline void atomic_add(int i, ato */ static inline void atomic_sub(int i, atomic_t *v) { - asm volatile(LOCK_PREFIX "subl %1,%0" + asm volatile(LOCK_PREFIX "subl %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "addl %1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "=m" (v->counter) : "ir" (i), "m" (v->counter)); } @@ -80,7 +96,16 @@ static inline int atomic_sub_and_test(in { unsigned char c; - asm volatile(LOCK_PREFIX "subl %2,%0; sete %1" + asm volatile(LOCK_PREFIX "subl %2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "addl %2,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + "sete %1\n" : "=m" (v->counter), "=qm" (c) : "ir" (i), "m" (v->counter) : "memory"); return c; @@ -94,7 +119,19 @@ static inline int atomic_sub_and_test(in */ static inline void atomic_inc(atomic_t *v) { - asm volatile(LOCK_PREFIX "incl %0" + asm volatile(LOCK_PREFIX "incl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "int $4\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1:\n" + LOCK_PREFIX "decl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "=m" (v->counter) : "m" (v->counter)); } @@ -107,7 +144,19 @@ static inline void atomic_inc(atomic_t * */ static inline void atomic_dec(atomic_t *v) { - asm volatile(LOCK_PREFIX "decl %0" + asm volatile(LOCK_PREFIX "decl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "int $4\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "incl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "=m" (v->counter) : "m" (v->counter)); } @@ -124,7 +173,20 @@ static inline int atomic_dec_and_test(at { unsigned char c; - asm volatile(LOCK_PREFIX "decl %0; sete %1" + asm volatile(LOCK_PREFIX "decl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "int $4\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "incl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "=m" (v->counter), "=qm" (c) : "m" (v->counter) : "memory"); return c != 0; @@ -142,7 +204,20 @@ static inline int atomic_inc_and_test(at { unsigned char c; - asm volatile(LOCK_PREFIX "incl %0; sete %1" + asm volatile(LOCK_PREFIX "incl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "int $4\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "decl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "=m" (v->counter), "=qm" (c) : "m" (v->counter) : "memory"); return c != 0; @@ -161,7 +236,16 @@ static inline int atomic_add_negative(in { unsigned char c; - asm volatile(LOCK_PREFIX "addl %2,%0; sets %1" + asm volatile(LOCK_PREFIX "addl %2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "subl %2,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + "sets %1\n" : "=m" (v->counter), "=qm" (c) : "ir" (i), "m" (v->counter) : "memory"); return c; @@ -177,7 +261,15 @@ static inline int atomic_add_negative(in static inline int atomic_add_return(int i, atomic_t *v) { int __i = i; - asm volatile(LOCK_PREFIX "xaddl %0, %1" + asm volatile(LOCK_PREFIX "xaddl %0, %1\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "movl %0, %1\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "+r" (i), "+m" (v->counter) : : "memory"); return i + __i; @@ -226,7 +318,15 @@ typedef struct { */ static inline void atomic64_add(long i, atomic64_t *v) { - asm volatile(LOCK_PREFIX "addq %1,%0" + asm volatile(LOCK_PREFIX "addq %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "subq %1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "=m" (v->counter) : "er" (i), "m" (v->counter)); } @@ -240,7 +340,15 @@ static inline void atomic64_add(long i, */ static inline void atomic64_sub(long i, atomic64_t *v) { - asm volatile(LOCK_PREFIX "subq %1,%0" + asm volatile(LOCK_PREFIX "subq %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "addq %1,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "=m" (v->counter) : "er" (i), "m" (v->counter)); } @@ -258,7 +366,16 @@ static inline int atomic64_sub_and_test( { unsigned char c; - asm volatile(LOCK_PREFIX "subq %2,%0; sete %1" + asm volatile(LOCK_PREFIX "subq %2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "addq %2,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + "sete %1\n" : "=m" (v->counter), "=qm" (c) : "er" (i), "m" (v->counter) : "memory"); return c; @@ -272,7 +389,19 @@ static inline int atomic64_sub_and_test( */ static inline void atomic64_inc(atomic64_t *v) { - asm volatile(LOCK_PREFIX "incq %0" + asm volatile(LOCK_PREFIX "incq %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "int $4\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1:\n" + LOCK_PREFIX "decq %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "=m" (v->counter) : "m" (v->counter)); } @@ -285,7 +414,19 @@ static inline void atomic64_inc(atomic64 */ static inline void atomic64_dec(atomic64_t *v) { - asm volatile(LOCK_PREFIX "decq %0" + asm volatile(LOCK_PREFIX "decq %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "int $4\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "incq %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "=m" (v->counter) : "m" (v->counter)); } @@ -302,7 +443,20 @@ static inline int atomic64_dec_and_test( { unsigned char c; - asm volatile(LOCK_PREFIX "decq %0; sete %1" + asm volatile(LOCK_PREFIX "decq %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "int $4\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "incq %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "=m" (v->counter), "=qm" (c) : "m" (v->counter) : "memory"); return c != 0; @@ -320,7 +474,20 @@ static inline int atomic64_inc_and_test( { unsigned char c; - asm volatile(LOCK_PREFIX "incq %0; sete %1" + asm volatile(LOCK_PREFIX "incq %0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "int $4\n0:\n" + ".pushsection .fixup,\"ax\"\n" + "1: \n" + LOCK_PREFIX "decq %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "=m" (v->counter), "=qm" (c) : "m" (v->counter) : "memory"); return c != 0; @@ -339,7 +506,16 @@ static inline int atomic64_add_negative( { unsigned char c; - asm volatile(LOCK_PREFIX "addq %2,%0; sets %1" + asm volatile(LOCK_PREFIX "addq %2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + LOCK_PREFIX "subq %2,%0\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + + "sets %1\n" : "=m" (v->counter), "=qm" (c) : "er" (i), "m" (v->counter) : "memory"); return c; @@ -355,7 +531,15 @@ static inline int atomic64_add_negative( static inline long atomic64_add_return(long i, atomic64_t *v) { long __i = i; - asm volatile(LOCK_PREFIX "xaddq %0, %1;" + asm volatile(LOCK_PREFIX "xaddq %0, %1\n" + +#ifdef CONFIG_PAX_REFCOUNT + "jno 0f\n" + "movq %0, %1\n" + "int $4\n0:\n" + _ASM_EXTABLE(0b, 0b) +#endif + : "+r" (i), "+m" (v->counter) : : "memory"); return i + __i; diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/boot.h linux-2.6.27.15-g-v/include/asm-x86/boot.h --- linux-2.6.27.15/include/asm-x86/boot.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/boot.h 2009-02-10 20:32:15.000000000 +0100 @@ -13,10 +13,15 @@ #define ASK_VGA 0xfffd /* ask for it at bootup */ /* Physical address where kernel should be loaded. */ -#define LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \ +#define ____LOAD_PHYSICAL_ADDR ((CONFIG_PHYSICAL_START \ + (CONFIG_PHYSICAL_ALIGN - 1)) \ & ~(CONFIG_PHYSICAL_ALIGN - 1)) +#ifndef __ASSEMBLY__ +extern unsigned char __LOAD_PHYSICAL_ADDR[]; +#define LOAD_PHYSICAL_ADDR ((unsigned long)__LOAD_PHYSICAL_ADDR) +#endif + #ifdef CONFIG_X86_64 #define BOOT_HEAP_SIZE 0x7000 #define BOOT_STACK_SIZE 0x4000 diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/cache.h linux-2.6.27.15-g-v/include/asm-x86/cache.h --- linux-2.6.27.15/include/asm-x86/cache.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/cache.h 2009-02-10 20:32:15.000000000 +0100 @@ -6,6 +6,7 @@ #define L1_CACHE_BYTES (1 << L1_CACHE_SHIFT) #define __read_mostly __attribute__((__section__(".data.read_mostly"))) +#define __read_only __attribute__((__section__(".data.read_only"))) #ifdef CONFIG_X86_VSMP /* vSMP Internode cacheline shift */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/checksum_32.h linux-2.6.27.15-g-v/include/asm-x86/checksum_32.h --- linux-2.6.27.15/include/asm-x86/checksum_32.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/checksum_32.h 2009-02-10 20:32:15.000000000 +0100 @@ -31,6 +31,14 @@ asmlinkage __wsum csum_partial_copy_gene int len, __wsum sum, int *src_err_ptr, int *dst_err_ptr); +asmlinkage __wsum csum_partial_copy_generic_to_user(const void *src, void *dst, + int len, __wsum sum, + int *src_err_ptr, int *dst_err_ptr); + +asmlinkage __wsum csum_partial_copy_generic_from_user(const void *src, void *dst, + int len, __wsum sum, + int *src_err_ptr, int *dst_err_ptr); + /* * Note: when you get a NULL pointer exception here this means someone * passed in an incorrect kernel address to one of these functions. @@ -50,7 +58,7 @@ static inline __wsum csum_partial_copy_f int *err_ptr) { might_sleep(); - return csum_partial_copy_generic((__force void *)src, dst, + return csum_partial_copy_generic_from_user((__force void *)src, dst, len, sum, err_ptr, NULL); } @@ -177,7 +185,7 @@ static inline __wsum csum_and_copy_to_us { might_sleep(); if (access_ok(VERIFY_WRITE, dst, len)) - return csum_partial_copy_generic(src, (__force void *)dst, + return csum_partial_copy_generic_to_user(src, (__force void *)dst, len, sum, NULL, err_ptr); if (len) diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/desc.h linux-2.6.27.15-g-v/include/asm-x86/desc.h --- linux-2.6.27.15/include/asm-x86/desc.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/desc.h 2009-02-10 20:32:15.000000000 +0100 @@ -16,6 +16,7 @@ static inline void fill_ldt(struct desc_ desc->base1 = (info->base_addr & 0x00ff0000) >> 16; desc->type = (info->read_exec_only ^ 1) << 1; desc->type |= info->contents << 2; + desc->type |= info->seg_not_present ^ 1; desc->s = 1; desc->dpl = 0x3; desc->p = info->seg_not_present ^ 1; @@ -27,16 +28,12 @@ static inline void fill_ldt(struct desc_ } extern struct desc_ptr idt_descr; -extern gate_desc idt_table[]; - -struct gdt_page { - struct desc_struct gdt[GDT_ENTRIES]; -} __attribute__((aligned(PAGE_SIZE))); -DECLARE_PER_CPU(struct gdt_page, gdt_page); +extern gate_desc idt_table[256]; +extern struct desc_struct cpu_gdt_table[NR_CPUS][PAGE_SIZE / sizeof(struct desc_struct)]; static inline struct desc_struct *get_cpu_gdt_table(unsigned int cpu) { - return per_cpu(gdt_page, cpu).gdt; + return cpu_gdt_table[cpu]; } #ifdef CONFIG_X86_64 @@ -65,7 +62,6 @@ static inline void pack_gate(gate_desc * gate->b = (base & 0xffff0000) | (((0x80 | type | (dpl << 5)) & 0xff) << 8); } - #endif static inline int desc_empty(const void *ptr) @@ -102,19 +98,48 @@ static inline int desc_empty(const void static inline void native_write_idt_entry(gate_desc *idt, int entry, const gate_desc *gate) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + memcpy(&idt[entry], gate, sizeof(*gate)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static inline void native_write_ldt_entry(struct desc_struct *ldt, int entry, const void *desc) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + memcpy(&ldt[entry], desc, 8); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static inline void native_write_gdt_entry(struct desc_struct *gdt, int entry, const void *desc, int type) { unsigned int size; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + switch (type) { case DESC_TSS: size = sizeof(tss_desc); @@ -126,7 +151,17 @@ static inline void native_write_gdt_entr size = sizeof(struct desc_struct); break; } + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + memcpy(&gdt[entry], desc, size); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static inline void pack_descriptor(struct desc_struct *desc, unsigned long base, @@ -198,7 +233,19 @@ static inline void native_set_ldt(const static inline void native_load_tr_desc(void) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + asm volatile("ltr %w0"::"q" (GDT_ENTRY_TSS*8)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static inline void native_load_gdt(const struct desc_ptr *dtr) @@ -233,8 +280,19 @@ static inline void native_load_tls(struc unsigned int i; struct desc_struct *gdt = get_cpu_gdt_table(cpu); +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + for (i = 0; i < GDT_ENTRY_TLS_ENTRIES; i++) gdt[GDT_ENTRY_TLS_MIN + i] = t->tls_array[i]; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } #define _LDT_empty(info) \ @@ -372,6 +430,18 @@ static inline void set_system_gate_ist(i _set_gate(n, GATE_INTERRUPT, addr, 0x3, ist, __KERNEL_CS); } +#ifdef CONFIG_X86_32 +static inline void set_user_cs(unsigned long base, unsigned long limit, int cpu) +{ + struct desc_struct d; + + if (likely(limit)) + limit = (limit - 1UL) >> PAGE_SHIFT; + pack_descriptor(&d, base, limit, 0xFB, 0xC); + write_gdt_entry(get_cpu_gdt_table(cpu), GDT_ENTRY_DEFAULT_USER_CS, &d, DESCTYPE_S); +} +#endif + #else /* * GET_DESC_BASE reads the descriptor base of the specified segment. diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/e820.h linux-2.6.27.15-g-v/include/asm-x86/e820.h --- linux-2.6.27.15/include/asm-x86/e820.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/e820.h 2009-02-10 20:32:15.000000000 +0100 @@ -131,7 +131,7 @@ extern char *memory_setup(void); #define ISA_END_ADDRESS 0x100000 #define is_ISA_range(s, e) ((s) >= ISA_START_ADDRESS && (e) < ISA_END_ADDRESS) -#define BIOS_BEGIN 0x000a0000 +#define BIOS_BEGIN 0x000c0000 #define BIOS_END 0x00100000 #ifdef __KERNEL__ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/elf.h linux-2.6.27.15-g-v/include/asm-x86/elf.h --- linux-2.6.27.15/include/asm-x86/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/elf.h 2009-02-10 20:32:15.000000000 +0100 @@ -251,7 +251,25 @@ extern int force_personality32; the loader. We need to make sure that it is out of the way of the program that it will "exec", and that there is sufficient room for the brk. */ +#ifdef CONFIG_PAX_SEGMEXEC +#define ELF_ET_DYN_BASE ((current->mm->pax_flags & MF_PAX_SEGMEXEC) ? SEGMEXEC_TASK_SIZE/3*2 : TASK_SIZE/3*2) +#else #define ELF_ET_DYN_BASE (TASK_SIZE / 3 * 2) +#endif + +#ifdef CONFIG_PAX_ASLR +#ifdef CONFIG_X86_32 +#define PAX_ELF_ET_DYN_BASE 0x10000000UL + +#define PAX_DELTA_MMAP_LEN (current->mm->pax_flags & MF_PAX_SEGMEXEC ? 15 : 16) +#define PAX_DELTA_STACK_LEN (current->mm->pax_flags & MF_PAX_SEGMEXEC ? 15 : 16) +#else +#define PAX_ELF_ET_DYN_BASE 0x400000UL + +#define PAX_DELTA_MMAP_LEN ((test_thread_flag(TIF_IA32)) ? 16 : 32) +#define PAX_DELTA_STACK_LEN ((test_thread_flag(TIF_IA32)) ? 16 : 32) +#endif +#endif /* This yields a mask that user programs can use to figure out what instruction set this CPU supports. This could be done in user space, @@ -303,8 +321,7 @@ do { \ #define ARCH_DLINFO \ do { \ if (vdso_enabled) \ - NEW_AUX_ENT(AT_SYSINFO_EHDR, \ - (unsigned long)current->mm->context.vdso); \ + NEW_AUX_ENT(AT_SYSINFO_EHDR, current->mm->context.vdso);\ } while (0) #define AT_SYSINFO 32 @@ -315,7 +332,7 @@ do { \ #endif /* !CONFIG_X86_32 */ -#define VDSO_CURRENT_BASE ((unsigned long)current->mm->context.vdso) +#define VDSO_CURRENT_BASE (current->mm->context.vdso) #define VDSO_ENTRY \ ((unsigned long)VDSO32_SYMBOL(VDSO_CURRENT_BASE, vsyscall)) @@ -329,7 +346,4 @@ extern int arch_setup_additional_pages(s extern int syscall32_setup_pages(struct linux_binprm *, int exstack); #define compat_arch_setup_additional_pages syscall32_setup_pages -extern unsigned long arch_randomize_brk(struct mm_struct *mm); -#define arch_randomize_brk arch_randomize_brk - #endif diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/futex.h linux-2.6.27.15-g-v/include/asm-x86/futex.h --- linux-2.6.27.15/include/asm-x86/futex.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/futex.h 2009-02-10 20:32:15.000000000 +0100 @@ -11,6 +11,40 @@ #include #include +#ifdef CONFIG_X86_32 +#define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \ + asm volatile( \ + "movw\t%w6, %%ds\n" \ + "1:\t" insn "\n" \ + "2:\tpushl\t%%ss\n" \ + "\tpopl\t%%ds\n" \ + "\t.section .fixup,\"ax\"\n" \ + "3:\tmov\t%3, %1\n" \ + "\tjmp\t2b\n" \ + "\t.previous\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=r" (oldval), "=r" (ret), "+m" (*uaddr) \ + : "i" (-EFAULT), "0" (oparg), "1" (0), "r" (__USER_DS)) + +#define __futex_atomic_op2(insn, ret, oldval, uaddr, oparg) \ + asm volatile("movw\t%w7, %%es\n" \ + "1:\tmovl\t%%es:%2, %0\n" \ + "\tmovl\t%0, %3\n" \ + "\t" insn "\n" \ + "2:\tlock; cmpxchgl %3, %%es:%2\n" \ + "\tjnz\t1b\n" \ + "3:\tpushl\t%%ss\n" \ + "\tpopl\t%%es\n" \ + "\t.section .fixup,\"ax\"\n" \ + "4:\tmov\t%5, %1\n" \ + "\tjmp\t3b\n" \ + "\t.previous\n" \ + _ASM_EXTABLE(1b, 4b) \ + _ASM_EXTABLE(2b, 4b) \ + : "=&a" (oldval), "=&r" (ret), \ + "+m" (*uaddr), "=&r" (tem) \ + : "r" (oparg), "i" (-EFAULT), "1" (0), "r" (__USER_DS)) +#else #define __futex_atomic_op1(insn, ret, oldval, uaddr, oparg) \ asm volatile("1:\t" insn "\n" \ "2:\t.section .fixup,\"ax\"\n" \ @@ -36,8 +70,9 @@ : "=&a" (oldval), "=&r" (ret), \ "+m" (*uaddr), "=&r" (tem) \ : "r" (oparg), "i" (-EFAULT), "1" (0)) +#endif -static inline int futex_atomic_op_inuser(int encoded_op, int __user *uaddr) +static inline int futex_atomic_op_inuser(int encoded_op, u32 __user *uaddr) { int op = (encoded_op >> 28) & 7; int cmp = (encoded_op >> 24) & 15; @@ -61,11 +96,20 @@ static inline int futex_atomic_op_inuser switch (op) { case FUTEX_OP_SET: +#ifdef CONFIG_X86_32 + __futex_atomic_op1("xchgl %0, %%ds:%2", ret, oldval, uaddr, oparg); +#else __futex_atomic_op1("xchgl %0, %2", ret, oldval, uaddr, oparg); +#endif break; case FUTEX_OP_ADD: +#ifdef CONFIG_X86_32 + __futex_atomic_op1("lock ; xaddl %0, %%ds:%2", ret, oldval, + uaddr, oparg); +#else __futex_atomic_op1("lock; xaddl %0, %2", ret, oldval, uaddr, oparg); +#endif break; case FUTEX_OP_OR: __futex_atomic_op2("orl %4, %3", ret, oldval, uaddr, oparg); @@ -109,7 +153,7 @@ static inline int futex_atomic_op_inuser return ret; } -static inline int futex_atomic_cmpxchg_inatomic(int __user *uaddr, int oldval, +static inline int futex_atomic_cmpxchg_inatomic(u32 __user *uaddr, int oldval, int newval) { @@ -122,14 +166,27 @@ static inline int futex_atomic_cmpxchg_i if (!access_ok(VERIFY_WRITE, uaddr, sizeof(int))) return -EFAULT; - asm volatile("1:\tlock; cmpxchgl %3, %1\n" + asm volatile( +#ifdef CONFIG_X86_32 + "\tmovw %w5, %%ds\n" + "1:\tlock; cmpxchgl %3, %1\n" + "2:\tpushl %%ss\n" + "\tpopl %%ds\n" + "\t.section .fixup, \"ax\"\n" +#else + "1:\tlock; cmpxchgl %3, %1\n" "2:\t.section .fixup, \"ax\"\n" +#endif "3:\tmov %2, %0\n" "\tjmp 2b\n" "\t.previous\n" _ASM_EXTABLE(1b, 3b) : "=a" (oldval), "+m" (*uaddr) +#ifdef CONFIG_X86_32 + : "i" (-EFAULT), "r" (newval), "0" (oldval), "r" (__USER_DS) +#else : "i" (-EFAULT), "r" (newval), "0" (oldval) +#endif : "memory" ); diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/i387.h linux-2.6.27.15-g-v/include/asm-x86/i387.h --- linux-2.6.27.15/include/asm-x86/i387.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/i387.h 2009-02-10 20:32:15.000000000 +0100 @@ -159,13 +159,8 @@ static inline void restore_fpu(struct ta } /* We need a safe address that is cheap to find and that is already - in L1 during context switch. The best choices are unfortunately - different for UP and SMP */ -#ifdef CONFIG_SMP -#define safe_address (__per_cpu_offset[0]) -#else -#define safe_address (kstat_cpu(0).cpustat.user) -#endif + in L1 during context switch. */ +#define safe_address (init_tss[smp_processor_id()].x86_tss.sp0) /* * These must be called with preempt disabled diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/io_64.h linux-2.6.27.15-g-v/include/asm-x86/io_64.h --- linux-2.6.27.15/include/asm-x86/io_64.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/io_64.h 2009-02-10 20:32:15.000000000 +0100 @@ -158,6 +158,17 @@ static inline void *phys_to_virt(unsigne } #endif +#define ARCH_HAS_VALID_PHYS_ADDR_RANGE +static inline int valid_phys_addr_range (unsigned long addr, size_t count) +{ + return ((addr + count + PAGE_SIZE - 1) >> PAGE_SHIFT) < (1 << (boot_cpu_data.x86_phys_bits - PAGE_SHIFT)) ? 1 : 0; +} + +static inline int valid_mmap_phys_addr_range (unsigned long pfn, size_t count) +{ + return (pfn + (count >> PAGE_SHIFT)) < (1 << (boot_cpu_data.x86_phys_bits - PAGE_SHIFT)) ? 1 : 0; +} + /* * Change "struct page" to physical address. */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/irqflags.h linux-2.6.27.15-g-v/include/asm-x86/irqflags.h --- linux-2.6.27.15/include/asm-x86/irqflags.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/irqflags.h 2009-02-10 20:32:15.000000000 +0100 @@ -141,6 +141,8 @@ static inline unsigned long __raw_local_ #define INTERRUPT_RETURN iret #define ENABLE_INTERRUPTS_SYSEXIT sti; sysexit #define GET_CR0_INTO_EAX movl %cr0, %eax +#define GET_CR0_INTO_EDX movl %cr0, %edx +#define SET_CR0_FROM_EDX movl %edx, %cr0 #endif diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/kmap_types.h linux-2.6.27.15-g-v/include/asm-x86/kmap_types.h --- linux-2.6.27.15/include/asm-x86/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -21,7 +21,8 @@ D(9) KM_IRQ0, D(10) KM_IRQ1, D(11) KM_SOFTIRQ0, D(12) KM_SOFTIRQ1, -D(13) KM_TYPE_NR +D(13) KM_CLEARPAGE, +D(14) KM_TYPE_NR }; #undef D diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/linkage.h linux-2.6.27.15-g-v/include/asm-x86/linkage.h --- linux-2.6.27.15/include/asm-x86/linkage.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/linkage.h 2009-02-10 20:32:15.000000000 +0100 @@ -7,6 +7,11 @@ #ifdef CONFIG_X86_64 #define __ALIGN .p2align 4,,15 #define __ALIGN_STR ".p2align 4,,15" +#else +#ifdef CONFIG_X86_ALIGNMENT_16 +#define __ALIGN .align 16,0x90 +#define __ALIGN_STR ".align 16,0x90" +#endif #endif #ifdef CONFIG_X86_32 @@ -52,10 +57,5 @@ #endif -#ifdef CONFIG_X86_ALIGNMENT_16 -#define __ALIGN .align 16,0x90 -#define __ALIGN_STR ".align 16,0x90" -#endif - #endif diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/local.h linux-2.6.27.15-g-v/include/asm-x86/local.h --- linux-2.6.27.15/include/asm-x86/local.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/local.h 2009-02-10 20:32:15.000000000 +0100 @@ -18,26 +18,90 @@ typedef struct { static inline void local_inc(local_t *l) { - asm volatile(_ASM_INC "%0" + asm volatile(_ASM_INC "%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_DEC "%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+m" (l->a.counter)); } static inline void local_dec(local_t *l) { - asm volatile(_ASM_DEC "%0" + asm volatile(_ASM_DEC "%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_INC "%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+m" (l->a.counter)); } static inline void local_add(long i, local_t *l) { - asm volatile(_ASM_ADD "%1,%0" + asm volatile(_ASM_ADD "%1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_SUB "%1,%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+m" (l->a.counter) : "ir" (i)); } static inline void local_sub(long i, local_t *l) { - asm volatile(_ASM_SUB "%1,%0" + asm volatile(_ASM_SUB "%1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_ADD "%1,%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+m" (l->a.counter) : "ir" (i)); } @@ -55,7 +119,24 @@ static inline int local_sub_and_test(lon { unsigned char c; - asm volatile(_ASM_SUB "%2,%0; sete %1" + asm volatile(_ASM_SUB "%2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_ADD "%2,%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "+m" (l->a.counter), "=qm" (c) : "ir" (i) : "memory"); return c; @@ -73,7 +154,24 @@ static inline int local_dec_and_test(loc { unsigned char c; - asm volatile(_ASM_DEC "%0; sete %1" + asm volatile(_ASM_DEC "%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_INC "%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "+m" (l->a.counter), "=qm" (c) : : "memory"); return c != 0; @@ -91,7 +189,24 @@ static inline int local_inc_and_test(loc { unsigned char c; - asm volatile(_ASM_INC "%0; sete %1" + asm volatile(_ASM_INC "%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_DEC "%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sete %1\n" : "+m" (l->a.counter), "=qm" (c) : : "memory"); return c != 0; @@ -110,7 +225,24 @@ static inline int local_add_negative(lon { unsigned char c; - asm volatile(_ASM_ADD "%2,%0; sets %1" + asm volatile(_ASM_ADD "%2,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_SUB "%2,%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "sets %1\n" : "+m" (l->a.counter), "=qm" (c) : "ir" (i) : "memory"); return c; @@ -133,7 +265,23 @@ static inline long local_add_return(long #endif /* Modern 486+ processor */ __i = i; - asm volatile(_ASM_XADD "%0, %1;" + asm volatile(_ASM_XADD "%0, %1\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + _ASM_MOV_UL "%0,%1\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+r" (i), "+m" (l->a.counter) : : "memory"); return i + __i; diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/mach-default/apm.h linux-2.6.27.15-g-v/include/asm-x86/mach-default/apm.h --- linux-2.6.27.15/include/asm-x86/mach-default/apm.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/mach-default/apm.h 2009-02-10 20:32:15.000000000 +0100 @@ -34,7 +34,7 @@ static inline void apm_bios_call_asm(u32 __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall *%%cs:apm_bios_entry\n\t" + "lcall *%%ss:apm_bios_entry\n\t" "setc %%al\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" @@ -58,7 +58,7 @@ static inline u8 apm_bios_call_simple_as __asm__ __volatile__(APM_DO_ZERO_SEGS "pushl %%edi\n\t" "pushl %%ebp\n\t" - "lcall *%%cs:apm_bios_entry\n\t" + "lcall *%%ss:apm_bios_entry\n\t" "setc %%bl\n\t" "popl %%ebp\n\t" "popl %%edi\n\t" diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/mman.h linux-2.6.27.15-g-v/include/asm-x86/mman.h --- linux-2.6.27.15/include/asm-x86/mman.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/mman.h 2009-02-10 20:32:15.000000000 +0100 @@ -17,4 +17,14 @@ #define MCL_CURRENT 1 /* lock all current mappings */ #define MCL_FUTURE 2 /* lock all future mappings */ +#ifdef __KERNEL__ +#ifndef __ASSEMBLY__ +#ifdef CONFIG_X86_32 +#define arch_mmap_check i386_mmap_check +int i386_mmap_check(unsigned long addr, unsigned long len, + unsigned long flags); +#endif +#endif +#endif + #endif /* _ASM_X86_MMAN_H */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/mmu_context_32.h linux-2.6.27.15-g-v/include/asm-x86/mmu_context_32.h --- linux-2.6.27.15/include/asm-x86/mmu_context_32.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/mmu_context_32.h 2009-02-10 20:32:15.000000000 +0100 @@ -33,6 +33,22 @@ static inline void switch_mm(struct mm_s */ if (unlikely(prev->context.ldt != next->context.ldt)) load_LDT_nolock(&next->context); + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_SMP) + if (!nx_enabled) { + smp_mb__before_clear_bit(); + cpu_clear(cpu, prev->context.cpu_user_cs_mask); + smp_mb__after_clear_bit(); + cpu_set(cpu, next->context.cpu_user_cs_mask); + } +#endif + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (unlikely(prev->context.user_cs_base != next->context.user_cs_base || + prev->context.user_cs_limit != next->context.user_cs_limit)) + set_user_cs(next->context.user_cs_base, next->context.user_cs_limit, cpu); +#endif + } #ifdef CONFIG_SMP else { @@ -45,6 +61,19 @@ static inline void switch_mm(struct mm_s */ load_cr3(next->pgd); load_LDT_nolock(&next->context); + +#ifdef CONFIG_PAX_PAGEEXEC + if (!nx_enabled) + cpu_set(cpu, next->context.cpu_user_cs_mask); +#endif + +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) +#ifdef CONFIG_PAX_PAGEEXEC + if (!((next->pax_flags & MF_PAX_PAGEEXEC) && nx_enabled)) +#endif + set_user_cs(next->context.user_cs_base, next->context.user_cs_limit, cpu); +#endif + } } #endif diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/mmu.h linux-2.6.27.15-g-v/include/asm-x86/mmu.h --- linux-2.6.27.15/include/asm-x86/mmu.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/mmu.h 2009-02-10 20:32:15.000000000 +0100 @@ -11,13 +11,26 @@ * cpu_vm_mask is used to optimize ldt flushing. */ typedef struct { - void *ldt; + struct desc_struct *ldt; #ifdef CONFIG_X86_64 rwlock_t ldtlock; #endif int size; struct mutex lock; - void *vdso; + unsigned long vdso; + +#ifdef CONFIG_X86_32 +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + unsigned long user_cs_base; + unsigned long user_cs_limit; + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_SMP) + cpumask_t cpu_user_cs_mask; +#endif + +#endif +#endif + } mm_context_t; #ifdef CONFIG_SMP diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/module.h linux-2.6.27.15-g-v/include/asm-x86/module.h --- linux-2.6.27.15/include/asm-x86/module.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/module.h 2009-02-10 20:32:15.000000000 +0100 @@ -76,7 +76,12 @@ struct mod_arch_specific {}; # else # define MODULE_STACKSIZE "" # endif -# define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_STACKSIZE +# ifdef CONFIG_GRKERNSEC +# define MODULE_GRSEC "GRSECURITY " +# else +# define MODULE_GRSEC "" +# endif +# define MODULE_ARCH_VERMAGIC MODULE_PROC_FAMILY MODULE_STACKSIZE MODULE_GRSEC #endif #endif /* _ASM_MODULE_H */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/page_32.h linux-2.6.27.15-g-v/include/asm-x86/page_32.h --- linux-2.6.27.15/include/asm-x86/page_32.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/page_32.h 2009-02-10 20:32:15.000000000 +0100 @@ -13,6 +13,23 @@ */ #define __PAGE_OFFSET _AC(CONFIG_PAGE_OFFSET, UL) +#ifdef CONFIG_PAX_KERNEXEC +#ifndef __ASSEMBLY__ +extern unsigned char MODULES_VADDR[]; +extern unsigned char MODULES_END[]; +extern unsigned char KERNEL_TEXT_OFFSET[]; +#define ktla_ktva(addr) (addr + (unsigned long)KERNEL_TEXT_OFFSET) +#define ktva_ktla(addr) (addr - (unsigned long)KERNEL_TEXT_OFFSET) +#endif +#else +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) +#endif + +#ifdef CONFIG_PAX_PAGEEXEC +#define CONFIG_ARCH_TRACK_EXEC_LIMIT 1 +#endif + #ifdef CONFIG_4KSTACKS #define THREAD_ORDER 0 #else diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/page_64.h linux-2.6.27.15-g-v/include/asm-x86/page_64.h --- linux-2.6.27.15/include/asm-x86/page_64.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/page_64.h 2009-02-10 20:32:15.000000000 +0100 @@ -49,6 +49,9 @@ #define __START_KERNEL (__START_KERNEL_map + __PHYSICAL_START) #define __START_KERNEL_map _AC(0xffffffff80000000, UL) +#define ktla_ktva(addr) (addr) +#define ktva_ktla(addr) (addr) + /* See Documentation/x86_64/mm.txt for a description of the memory map. */ #define __PHYSICAL_MASK_SHIFT 46 #define __VIRTUAL_MASK_SHIFT 48 @@ -101,5 +104,6 @@ extern void init_extra_mapping_wb(unsign #define pfn_valid(pfn) ((pfn) < max_pfn) #endif +#define nx_enabled (1) #endif /* _X86_64_PAGE_H */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/paravirt.h linux-2.6.27.15-g-v/include/asm-x86/paravirt.h --- linux-2.6.27.15/include/asm-x86/paravirt.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/paravirt.h 2009-02-10 20:32:15.000000000 +0100 @@ -1557,7 +1557,7 @@ static inline unsigned long __raw_local_ #define PV_RESTORE_REGS popl %edx; popl %ecx; popl %edi; popl %eax #define PARA_PATCH(struct, off) ((PARAVIRT_PATCH_##struct + (off)) / 4) #define PARA_SITE(ptype, clobbers, ops) _PVSITE(ptype, clobbers, ops, .long, 4) -#define PARA_INDIRECT(addr) *%cs:addr +#define PARA_INDIRECT(addr) *%ss:addr #endif #define INTERRUPT_RETURN \ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/pda.h linux-2.6.27.15-g-v/include/asm-x86/pda.h --- linux-2.6.27.15/include/asm-x86/pda.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/pda.h 2009-02-10 20:32:15.000000000 +0100 @@ -16,11 +16,9 @@ struct x8664_pda { unsigned long oldrsp; /* 24 user rsp for system call */ int irqcount; /* 32 Irq nesting counter. Starts -1 */ unsigned int cpunumber; /* 36 Logical CPU number */ -#ifdef CONFIG_CC_STACKPROTECTOR unsigned long stack_canary; /* 40 stack canary value */ /* gcc-ABI: this canary MUST be at offset 40!!! */ -#endif char *irqstackptr; short nodenumber; /* number of current node (32k max) */ short in_bootmem; /* pda lives in bootmem */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/percpu.h linux-2.6.27.15-g-v/include/asm-x86/percpu.h --- linux-2.6.27.15/include/asm-x86/percpu.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/percpu.h 2009-02-10 20:32:15.000000000 +0100 @@ -93,6 +93,12 @@ DECLARE_PER_CPU(struct x8664_pda, pda); #define __my_cpu_offset x86_read_percpu(this_cpu_off) +#include +#include +#define __per_cpu_offset __per_cpu_offset +extern unsigned long __per_cpu_offset[NR_CPUS]; +#define per_cpu_offset(x) (__per_cpu_offset[x] + (unsigned long)__per_cpu_start) + /* fs segment starts at (positive) offset == __per_cpu_offset[cpu] */ #define __percpu_seg "%%fs:" diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/pgalloc.h linux-2.6.27.15-g-v/include/asm-x86/pgalloc.h --- linux-2.6.27.15/include/asm-x86/pgalloc.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/pgalloc.h 2009-02-10 20:32:15.000000000 +0100 @@ -52,7 +52,7 @@ static inline void pmd_populate_kernel(s pmd_t *pmd, pte_t *pte) { paravirt_alloc_pte(mm, __pa(pte) >> PAGE_SHIFT); - set_pmd(pmd, __pmd(__pa(pte) | _PAGE_TABLE)); + set_pmd(pmd, __pmd(__pa(pte) | _KERNPG_TABLE)); } static inline void pmd_populate(struct mm_struct *mm, pmd_t *pmd, diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/pgtable-2level.h linux-2.6.27.15-g-v/include/asm-x86/pgtable-2level.h --- linux-2.6.27.15/include/asm-x86/pgtable-2level.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/pgtable-2level.h 2009-02-10 20:32:15.000000000 +0100 @@ -18,7 +18,19 @@ static inline void native_set_pte(pte_t static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + *pmdp = pmd; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static inline void native_set_pte_atomic(pte_t *ptep, pte_t pte) diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/pgtable_32.h linux-2.6.27.15-g-v/include/asm-x86/pgtable_32.h --- linux-2.6.27.15/include/asm-x86/pgtable_32.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/pgtable_32.h 2009-02-10 20:32:15.000000000 +0100 @@ -25,8 +25,6 @@ struct mm_struct; struct vm_area_struct; -extern pgd_t swapper_pg_dir[1024]; - static inline void pgtable_cache_init(void) { } static inline void check_pgt_cache(void) { } void paging_init(void); @@ -45,6 +43,11 @@ void paging_init(void); # include #endif +extern pgd_t swapper_pg_dir[PTRS_PER_PGD]; +#ifdef CONFIG_X86_PAE +extern pmd_t swapper_pm_dir[PTRS_PER_PGD][PTRS_PER_PMD]; +#endif + #define PGDIR_SIZE (1UL << PGDIR_SHIFT) #define PGDIR_MASK (~(PGDIR_SIZE - 1)) @@ -81,7 +84,7 @@ void paging_init(void); #undef TEST_ACCESS_OK /* The boot page tables (all created as a single array) */ -extern unsigned long pg0[]; +extern pte_t pg0[]; #define pte_present(x) ((x).pte_low & (_PAGE_PRESENT | _PAGE_PROTNONE)) @@ -173,6 +176,9 @@ do { \ #endif /* !__ASSEMBLY__ */ +#define HAVE_ARCH_UNMAPPED_AREA +#define HAVE_ARCH_UNMAPPED_AREA_TOPDOWN + /* * kern_addr_valid() is (1) for FLATMEM and (0) for * SPARSEMEM and DISCONTIGMEM diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/pgtable-3level.h linux-2.6.27.15-g-v/include/asm-x86/pgtable-3level.h --- linux-2.6.27.15/include/asm-x86/pgtable-3level.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/pgtable-3level.h 2009-02-10 20:32:15.000000000 +0100 @@ -70,12 +70,36 @@ static inline void native_set_pte_atomic static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + set_64bit((unsigned long long *)(pmdp), native_pmd_val(pmd)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static inline void native_set_pud(pud_t *pudp, pud_t pud) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + set_64bit((unsigned long long *)(pudp), native_pud_val(pud)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } /* diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/pgtable_64.h linux-2.6.27.15-g-v/include/asm-x86/pgtable_64.h --- linux-2.6.27.15/include/asm-x86/pgtable_64.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/pgtable_64.h 2009-02-10 20:32:15.000000000 +0100 @@ -15,9 +15,12 @@ extern pud_t level3_kernel_pgt[512]; extern pud_t level3_ident_pgt[512]; +extern pud_t level3_vmalloc_pgt[512]; +extern pud_t level3_vmemmap_pgt[512]; extern pmd_t level2_kernel_pgt[512]; extern pmd_t level2_fixmap_pgt[512]; extern pmd_t level2_ident_pgt[512]; +extern pte_t level1_fixmap_pgt[512]; extern pgd_t init_level4_pgt[]; #define swapper_pg_dir init_level4_pgt @@ -106,7 +109,19 @@ static inline pte_t native_ptep_get_and_ static inline void native_set_pmd(pmd_t *pmdp, pmd_t pmd) { + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + *pmdp = pmd; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } static inline void native_pmd_clear(pmd_t *pmd) @@ -158,17 +173,17 @@ static inline void native_pgd_clear(pgd_ static inline int pgd_bad(pgd_t pgd) { - return (pgd_val(pgd) & ~(PTE_PFN_MASK | _PAGE_USER)) != _KERNPG_TABLE; + return (pgd_val(pgd) & ~(PTE_PFN_MASK | _PAGE_USER | _PAGE_NX)) != _KERNPG_TABLE; } static inline int pud_bad(pud_t pud) { - return (pud_val(pud) & ~(PTE_PFN_MASK | _PAGE_USER)) != _KERNPG_TABLE; + return (pud_val(pud) & ~(PTE_PFN_MASK | _PAGE_USER | _PAGE_NX)) != _KERNPG_TABLE; } static inline int pmd_bad(pmd_t pmd) { - return (pmd_val(pmd) & ~(PTE_PFN_MASK | _PAGE_USER)) != _KERNPG_TABLE; + return (pmd_val(pmd) & ~(PTE_PFN_MASK | _PAGE_USER | _PAGE_NX)) != _KERNPG_TABLE; } #define pte_none(x) (!pte_val((x))) diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/pgtable.h linux-2.6.27.15-g-v/include/asm-x86/pgtable.h --- linux-2.6.27.15/include/asm-x86/pgtable.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/pgtable.h 2009-02-10 20:32:15.000000000 +0100 @@ -41,7 +41,7 @@ #if defined(CONFIG_X86_64) || defined(CONFIG_X86_PAE) #define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_NX) #else -#define _PAGE_NX (_AT(pteval_t, 0)) +#define _PAGE_NX (_AT(pteval_t, 1) << _PAGE_BIT_UNUSED3) #endif /* If _PAGE_PRESENT is clear, we use these: */ @@ -81,6 +81,9 @@ #define PAGE_READONLY_EXEC __pgprot(_PAGE_PRESENT | _PAGE_USER | \ _PAGE_ACCESSED) +#define PAGE_READONLY_NOEXEC PAGE_READONLY +#define PAGE_SHARED_NOEXEC PAGE_SHARED + #define __PAGE_KERNEL_EXEC \ (_PAGE_PRESENT | _PAGE_RW | _PAGE_DIRTY | _PAGE_ACCESSED | _PAGE_GLOBAL) #define __PAGE_KERNEL (__PAGE_KERNEL_EXEC | _PAGE_NX) @@ -92,7 +95,7 @@ #define __PAGE_KERNEL_NOCACHE (__PAGE_KERNEL | _PAGE_PCD | _PAGE_PWT) #define __PAGE_KERNEL_UC_MINUS (__PAGE_KERNEL | _PAGE_PCD) #define __PAGE_KERNEL_VSYSCALL (__PAGE_KERNEL_RX | _PAGE_USER) -#define __PAGE_KERNEL_VSYSCALL_NOCACHE (__PAGE_KERNEL_VSYSCALL | _PAGE_PCD | _PAGE_PWT) +#define __PAGE_KERNEL_VSYSCALL_NOCACHE (__PAGE_KERNEL_RO | _PAGE_PCD | _PAGE_PWT | _PAGE_USER) #define __PAGE_KERNEL_LARGE (__PAGE_KERNEL | _PAGE_PSE) #define __PAGE_KERNEL_LARGE_NOCACHE (__PAGE_KERNEL | _PAGE_CACHE_UC | _PAGE_PSE) #define __PAGE_KERNEL_LARGE_EXEC (__PAGE_KERNEL_EXEC | _PAGE_PSE) @@ -142,10 +145,17 @@ extern unsigned long empty_zero_page[PAG extern spinlock_t pgd_lock; extern struct list_head pgd_list; +extern pteval_t __supported_pte_mask; + /* * The following only work if pte_present() is true. * Undefined behaviour if not.. */ +static inline int pte_user(pte_t pte) +{ + return pte_val(pte) & _PAGE_USER; +} + static inline int pte_dirty(pte_t pte) { return pte_flags(pte) & _PAGE_DIRTY; @@ -207,9 +217,29 @@ static inline pte_t pte_wrprotect(pte_t return __pte(pte_val(pte) & ~_PAGE_RW); } +static inline pte_t pte_mkread(pte_t pte) +{ + return __pte(pte_val(pte) | _PAGE_USER); +} + static inline pte_t pte_mkexec(pte_t pte) { - return __pte(pte_val(pte) & ~_PAGE_NX); +#ifdef CONFIG_X86_PAE + if (__supported_pte_mask & _PAGE_NX) + return __pte(pte_val(pte) & ~(pteval_t)_PAGE_NX); + else +#endif + return __pte(pte_val(pte) | _PAGE_USER); +} + +static inline pte_t pte_exprotect(pte_t pte) +{ +#ifdef CONFIG_X86_PAE + if (__supported_pte_mask & _PAGE_NX) + return __pte(pte_val(pte) | _PAGE_NX); + else +#endif + return __pte(pte_val(pte) & ~_PAGE_USER); } static inline pte_t pte_mkdirty(pte_t pte) @@ -252,8 +282,6 @@ static inline pte_t pte_mkspecial(pte_t return __pte(pte_val(pte) | _PAGE_SPECIAL); } -extern pteval_t __supported_pte_mask; - static inline pte_t pfn_pte(unsigned long page_nr, pgprot_t pgprot) { return __pte((((phys_addr_t)page_nr << PAGE_SHIFT) | @@ -514,7 +542,19 @@ static inline void ptep_set_wrprotect(st */ static inline void clone_pgd_range(pgd_t *dst, pgd_t *src, int count) { - memcpy(dst, src, count * sizeof(pgd_t)); + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + + memcpy(dst, src, count * sizeof(pgd_t)); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + } diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/processor.h linux-2.6.27.15-g-v/include/asm-x86/processor.h --- linux-2.6.27.15/include/asm-x86/processor.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/processor.h 2009-02-10 20:32:15.000000000 +0100 @@ -269,7 +269,7 @@ struct tss_struct { } ____cacheline_aligned; -DECLARE_PER_CPU(struct tss_struct, init_tss); +extern struct tss_struct init_tss[NR_CPUS]; /* * Save the original ist values for checking stack pointers during debugging @@ -832,11 +832,20 @@ static inline void spin_lock_prefetch(co * User space process size: 3GB (default). */ #define TASK_SIZE PAGE_OFFSET + +#ifdef CONFIG_PAX_SEGMEXEC +#define SEGMEXEC_TASK_SIZE (TASK_SIZE / 2) +#endif + +#ifdef CONFIG_PAX_SEGMEXEC +#define STACK_TOP ((current->mm->pax_flags & MF_PAX_SEGMEXEC)?SEGMEXEC_TASK_SIZE:TASK_SIZE) +#else #define STACK_TOP TASK_SIZE -#define STACK_TOP_MAX STACK_TOP +#endif +#define STACK_TOP_MAX TASK_SIZE #define INIT_THREAD { \ - .sp0 = sizeof(init_stack) + (long)&init_stack, \ + .sp0 = sizeof(init_stack) + (long)&init_stack - 8, \ .vm86_info = NULL, \ .sysenter_cs = __KERNEL_CS, \ .io_bitmap_ptr = NULL, \ @@ -851,7 +860,7 @@ static inline void spin_lock_prefetch(co */ #define INIT_TSS { \ .x86_tss = { \ - .sp0 = sizeof(init_stack) + (long)&init_stack, \ + .sp0 = sizeof(init_stack) + (long)&init_stack - 8, \ .ss0 = __KERNEL_DS, \ .ss1 = __KERNEL_CS, \ .io_bitmap_base = INVALID_IO_BITMAP_OFFSET, \ @@ -862,11 +871,7 @@ static inline void spin_lock_prefetch(co extern unsigned long thread_saved_pc(struct task_struct *tsk); #define THREAD_SIZE_LONGS (THREAD_SIZE/sizeof(unsigned long)) -#define KSTK_TOP(info) \ -({ \ - unsigned long *__ptr = (unsigned long *)(info); \ - (unsigned long)(&__ptr[THREAD_SIZE_LONGS]); \ -}) +#define KSTK_TOP(info) ((info)->task.thread.sp0) /* * The below -8 is to reserve 8 bytes on top of the ring0 stack. @@ -881,7 +886,7 @@ extern unsigned long thread_saved_pc(str #define task_pt_regs(task) \ ({ \ struct pt_regs *__regs__; \ - __regs__ = (struct pt_regs *)(KSTK_TOP(task_stack_page(task))-8); \ + __regs__ = (struct pt_regs *)((task)->thread.sp0); \ __regs__ - 1; \ }) @@ -897,7 +902,7 @@ extern unsigned long thread_saved_pc(str * space during mmap's. */ #define IA32_PAGE_OFFSET ((current->personality & ADDR_LIMIT_3GB) ? \ - 0xc0000000 : 0xFFFFe000) + 0xc0000000 : 0xFFFFf000) #define TASK_SIZE (test_thread_flag(TIF_IA32) ? \ IA32_PAGE_OFFSET : TASK_SIZE64) @@ -934,6 +939,10 @@ extern void start_thread(struct pt_regs */ #define TASK_UNMAPPED_BASE (PAGE_ALIGN(TASK_SIZE / 3)) +#ifdef CONFIG_PAX_SEGMEXEC +#define SEGMEXEC_TASK_UNMAPPED_BASE (PAGE_ALIGN(SEGMEXEC_TASK_SIZE / 3)) +#endif + #define KSTK_EIP(task) (task_pt_regs(task)->ip) /* Get/set a process' ability to use the timestamp counter instruction */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/ptrace.h linux-2.6.27.15-g-v/include/asm-x86/ptrace.h --- linux-2.6.27.15/include/asm-x86/ptrace.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/ptrace.h 2009-02-10 20:32:15.000000000 +0100 @@ -131,6 +131,7 @@ struct pt_regs { /* the DS BTS struct is used for ptrace as well */ #include +#include struct task_struct; @@ -154,28 +155,29 @@ static inline unsigned long regs_return_ } /* - * user_mode_vm(regs) determines whether a register set came from user mode. + * user_mode(regs) determines whether a register set came from user mode. * This is true if V8086 mode was enabled OR if the register set was from * protected mode with RPL-3 CS value. This tricky test checks that with * one comparison. Many places in the kernel can bypass this full check - * if they have already ruled out V8086 mode, so user_mode(regs) can be used. + * if they have already ruled out V8086 mode, so user_mode_novm(regs) can + * be used. */ -static inline int user_mode(struct pt_regs *regs) +static inline int user_mode_novm(struct pt_regs *regs) { #ifdef CONFIG_X86_32 return (regs->cs & SEGMENT_RPL_MASK) == USER_RPL; #else - return !!(regs->cs & 3); + return !!(regs->cs & SEGMENT_RPL_MASK); #endif } -static inline int user_mode_vm(struct pt_regs *regs) +static inline int user_mode(struct pt_regs *regs) { #ifdef CONFIG_X86_32 return ((regs->cs & SEGMENT_RPL_MASK) | (regs->flags & X86_VM_MASK)) >= USER_RPL; #else - return user_mode(regs); + return user_mode_novm(regs); #endif } diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/reboot.h linux-2.6.27.15-g-v/include/asm-x86/reboot.h --- linux-2.6.27.15/include/asm-x86/reboot.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/reboot.h 2009-02-10 20:32:15.000000000 +0100 @@ -16,6 +16,6 @@ extern struct machine_ops machine_ops; void native_machine_crash_shutdown(struct pt_regs *regs); void native_machine_shutdown(void); -void machine_real_restart(const unsigned char *code, int length); +void machine_real_restart(const unsigned char *code, unsigned int length); #endif /* _ASM_REBOOT_H */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/rwsem.h linux-2.6.27.15-g-v/include/asm-x86/rwsem.h --- linux-2.6.27.15/include/asm-x86/rwsem.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/rwsem.h 2009-02-10 20:32:15.000000000 +0100 @@ -106,10 +106,26 @@ static inline void __down_read(struct rw { asm volatile("# beginning down_read\n\t" LOCK_PREFIX " incl (%%eax)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + LOCK_PREFIX "decl (%%eax)\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + /* adds 0x00000001, returns the old value */ - " jns 1f\n" + " jns 2f\n" " call call_rwsem_down_read_failed\n" - "1:\n\t" + "2:\n\t" "# ending down_read\n\t" : "+m" (sem->count) : "a" (sem) @@ -124,13 +140,29 @@ static inline int __down_read_trylock(st __s32 result, tmp; asm volatile("# beginning __down_read_trylock\n\t" " movl %0,%1\n\t" - "1:\n\t" + "2:\n\t" " movl %1,%2\n\t" " addl %3,%2\n\t" - " jle 2f\n\t" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + "subl %3,%2\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + " jle 3f\n\t" LOCK_PREFIX " cmpxchgl %2,%0\n\t" - " jnz 1b\n\t" - "2:\n\t" + " jnz 2b\n\t" + "3:\n\t" "# ending __down_read_trylock\n\t" : "+m" (sem->count), "=&a" (result), "=&r" (tmp) : "i" (RWSEM_ACTIVE_READ_BIAS) @@ -148,12 +180,28 @@ static inline void __down_write_nested(s tmp = RWSEM_ACTIVE_WRITE_BIAS; asm volatile("# beginning down_write\n\t" LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + "movl %%edx,(%%eax)\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + /* subtract 0x0000ffff, returns the old value */ " testl %%edx,%%edx\n\t" /* was the count 0 before? */ - " jz 1f\n" + " jz 2f\n" " call call_rwsem_down_write_failed\n" - "1:\n" + "2:\n" "# ending down_write" : "+m" (sem->count), "=d" (tmp) : "a" (sem), "1" (tmp) @@ -186,10 +234,26 @@ static inline void __up_read(struct rw_s __s32 tmp = -RWSEM_ACTIVE_READ_BIAS; asm volatile("# beginning __up_read\n\t" LOCK_PREFIX " xadd %%edx,(%%eax)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + "movl %%edx,(%%eax)\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + /* subtracts 1, returns the old value */ - " jns 1f\n\t" + " jns 2f\n\t" " call call_rwsem_wake\n" - "1:\n" + "2:\n" "# ending __up_read\n" : "+m" (sem->count), "=d" (tmp) : "a" (sem), "1" (tmp) @@ -204,11 +268,27 @@ static inline void __up_write(struct rw_ asm volatile("# beginning __up_write\n\t" " movl %2,%%edx\n\t" LOCK_PREFIX " xaddl %%edx,(%%eax)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + "movl %%edx,(%%eax)\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + /* tries to transition 0xffff0001 -> 0x00000000 */ - " jz 1f\n" + " jz 2f\n" " call call_rwsem_wake\n" - "1:\n\t" + "2:\n\t" "# ending __up_write\n" : "+m" (sem->count) : "a" (sem), "i" (-RWSEM_ACTIVE_WRITE_BIAS) @@ -222,10 +302,26 @@ static inline void __downgrade_write(str { asm volatile("# beginning __downgrade_write\n\t" LOCK_PREFIX " addl %2,(%%eax)\n\t" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + LOCK_PREFIX "subl %2,(%%eax)\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + /* transitions 0xZZZZ0001 -> 0xYYYY0001 */ - " jns 1f\n\t" + " jns 2f\n\t" " call call_rwsem_downgrade_wake\n" - "1:\n\t" + "2:\n\t" "# ending __downgrade_write\n" : "+m" (sem->count) : "a" (sem), "i" (-RWSEM_WAITING_BIAS) @@ -237,7 +333,23 @@ static inline void __downgrade_write(str */ static inline void rwsem_atomic_add(int delta, struct rw_semaphore *sem) { - asm volatile(LOCK_PREFIX "addl %1,%0" + asm volatile(LOCK_PREFIX "addl %1,%0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + LOCK_PREFIX "subl %1,%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+m" (sem->count) : "ir" (delta)); } @@ -249,7 +361,23 @@ static inline int rwsem_atomic_update(in { int tmp = delta; - asm volatile(LOCK_PREFIX "xadd %0,%1" + asm volatile(LOCK_PREFIX "xadd %0,%1\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + "movl %0,%1\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+r" (tmp), "+m" (sem->count) : : "memory"); diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/segment.h linux-2.6.27.15-g-v/include/asm-x86/segment.h --- linux-2.6.27.15/include/asm-x86/segment.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/segment.h 2009-02-10 20:32:15.000000000 +0100 @@ -88,13 +88,19 @@ #define GDT_ENTRY_ESPFIX_SS (GDT_ENTRY_KERNEL_BASE + 14) #define __ESPFIX_SS (GDT_ENTRY_ESPFIX_SS * 8) -#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15) +#define GDT_ENTRY_PERCPU (GDT_ENTRY_KERNEL_BASE + 15) #ifdef CONFIG_SMP #define __KERNEL_PERCPU (GDT_ENTRY_PERCPU * 8) #else #define __KERNEL_PERCPU 0 #endif +#define GDT_ENTRY_PCIBIOS_CS (GDT_ENTRY_KERNEL_BASE + 16) +#define __PCIBIOS_CS (GDT_ENTRY_PCIBIOS_CS * 8) + +#define GDT_ENTRY_PCIBIOS_DS (GDT_ENTRY_KERNEL_BASE + 17) +#define __PCIBIOS_DS (GDT_ENTRY_PCIBIOS_DS * 8) + #define GDT_ENTRY_DOUBLEFAULT_TSS 31 /* @@ -135,10 +141,10 @@ #define SEGMENT_IS_KERNEL_CODE(x) (((x) & 0xfc) == GDT_ENTRY_KERNEL_CS * 8) /* Matches __KERNEL_CS and __USER_CS (they must be 2 entries apart) */ -#define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xec) == GDT_ENTRY_KERNEL_CS * 8) +#define SEGMENT_IS_FLAT_CODE(x) (((x) & 0xFFFCU) == __KERNEL_CS || ((x) & 0xFFFCU) == __USER_CS) /* Matches PNP_CS32 and PNP_CS16 (they must be consecutive) */ -#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xf4) == GDT_ENTRY_PNPBIOS_BASE * 8) +#define SEGMENT_IS_PNP_CODE(x) (((x) & 0xFFFCU) == PNP_CS32 || ((x) & 0xFFFCU) == PNP_CS16) #else diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/spinlock.h linux-2.6.27.15-g-v/include/asm-x86/spinlock.h --- linux-2.6.27.15/include/asm-x86/spinlock.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/spinlock.h 2009-02-10 20:32:15.000000000 +0100 @@ -315,18 +315,50 @@ static inline int __raw_write_can_lock(r static inline void __raw_read_lock(raw_rwlock_t *rw) { asm volatile(LOCK_PREFIX " subl $1,(%0)\n\t" - "jns 1f\n" - "call __read_lock_failed\n\t" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" "1:\n" + LOCK_PREFIX " addl $1,(%0)\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "jns 2f\n" + "call __read_lock_failed\n\t" + "2:\n" ::LOCK_PTR_REG (rw) : "memory"); } static inline void __raw_write_lock(raw_rwlock_t *rw) { asm volatile(LOCK_PREFIX " subl %1,(%0)\n\t" - "jz 1f\n" - "call __write_lock_failed\n\t" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" "1:\n" + LOCK_PREFIX " addl %1,(%0)\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + "jz 2f\n" + "call __write_lock_failed\n\t" + "2:\n" ::LOCK_PTR_REG (rw), "i" (RW_LOCK_BIAS) : "memory"); } @@ -353,12 +385,45 @@ static inline int __raw_write_trylock(ra static inline void __raw_read_unlock(raw_rwlock_t *rw) { - asm volatile(LOCK_PREFIX "incl %0" :"+m" (rw->lock) : : "memory"); + asm volatile(LOCK_PREFIX "incl %0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + LOCK_PREFIX "decl %0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + + :"+m" (rw->lock) : : "memory"); } static inline void __raw_write_unlock(raw_rwlock_t *rw) { - asm volatile(LOCK_PREFIX "addl %1, %0" + asm volatile(LOCK_PREFIX "addl %1, %0\n" + +#ifdef CONFIG_PAX_REFCOUNT +#ifdef CONFIG_X86_32 + "into\n0:\n" +#else + "jno 0f\n" + "int $4\n0:\n" +#endif + ".pushsection .fixup,\"ax\"\n" + "1:\n" + LOCK_PREFIX "subl %1,%0\n" + "jmp 0b\n" + ".popsection\n" + _ASM_EXTABLE(0b, 1b) +#endif + : "+m" (rw->lock) : "i" (RW_LOCK_BIAS) : "memory"); } diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/system.h linux-2.6.27.15-g-v/include/asm-x86/system.h --- linux-2.6.27.15/include/asm-x86/system.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/system.h 2009-02-10 20:32:15.000000000 +0100 @@ -92,6 +92,8 @@ do { \ ".globl thread_return\n" \ "thread_return:\n\t" \ "movq %%gs:%P[pda_pcurrent],%%rsi\n\t" \ + "movq %P[task_canary](%%rsi),%%r8\n\t" \ + "movq %%r8,%%gs:%P[pda_canary]\n\t" \ "movq %P[thread_info](%%rsi),%%r8\n\t" \ LOCK_PREFIX "btr %[tif_fork],%P[ti_flags](%%r8)\n\t" \ "movq %%rax,%%rdi\n\t" \ @@ -103,7 +105,9 @@ do { \ [ti_flags] "i" (offsetof(struct thread_info, flags)), \ [tif_fork] "i" (TIF_FORK), \ [thread_info] "i" (offsetof(struct task_struct, stack)), \ - [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent)) \ + [task_canary] "i" (offsetof(struct task_struct, stack_canary)), \ + [pda_pcurrent] "i" (offsetof(struct x8664_pda, pcurrent)), \ + [pda_canary] "i" (offsetof(struct x8664_pda, stack_canary))\ : "memory", "cc" __EXTRA_CLOBBER) #endif @@ -166,7 +170,7 @@ static inline unsigned long get_limit(un { unsigned long __limit; asm("lsll %1,%0" : "=r" (__limit) : "r" (segment)); - return __limit + 1; + return __limit; } static inline void native_clts(void) @@ -292,6 +296,21 @@ static inline void native_wbinvd(void) #define stts() write_cr0(read_cr0() | X86_CR0_TS) +#define pax_open_kernel(cr0) \ +do { \ + typecheck(unsigned long, cr0); \ + preempt_disable(); \ + cr0 = read_cr0(); \ + write_cr0(cr0 & ~X86_CR0_WP); \ +} while (0) + +#define pax_close_kernel(cr0) \ +do { \ + typecheck(unsigned long, cr0); \ + write_cr0(cr0); \ + preempt_enable_no_resched(); \ +} while (0) + #endif /* __KERNEL__ */ static inline void clflush(volatile void *__p) @@ -306,7 +325,7 @@ void enable_hlt(void); void cpu_idle_wait(void); -extern unsigned long arch_align_stack(unsigned long sp); +#define arch_align_stack(x) ((x) & ~0xfUL) extern void free_init_pages(char *what, unsigned long begin, unsigned long end); void default_idle(void); diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/uaccess_64.h linux-2.6.27.15-g-v/include/asm-x86/uaccess_64.h --- linux-2.6.27.15/include/asm-x86/uaccess_64.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/uaccess_64.h 2009-02-10 20:32:15.000000000 +0100 @@ -10,6 +10,8 @@ #include #include +#define set_fs(x) (current_thread_info()->addr_limit = (x)) + /* * Copy To/From Userspace */ diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/uaccess.h linux-2.6.27.15-g-v/include/asm-x86/uaccess.h --- linux-2.6.27.15/include/asm-x86/uaccess.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/uaccess.h 2009-02-10 20:32:15.000000000 +0100 @@ -10,6 +10,7 @@ #include #include #include +#include #define VERIFY_READ 0 #define VERIFY_WRITE 1 @@ -29,7 +30,12 @@ #define get_ds() (KERNEL_DS) #define get_fs() (current_thread_info()->addr_limit) +#ifdef CONFIG_X86_32 +void __set_fs(mm_segment_t x, int cpu); +void set_fs(mm_segment_t x); +#else #define set_fs(x) (current_thread_info()->addr_limit = (x)) +#endif #define segment_eq(a, b) ((a).seg == (b).seg) @@ -97,6 +103,7 @@ struct exception_table_entry { }; extern int fixup_exception(struct pt_regs *regs); +#define ARCH_HAS_SORT_EXTABLE /* * These are the main single-value transfer routines. They automatically @@ -186,9 +193,12 @@ extern int __get_user_bad(void); #ifdef CONFIG_X86_32 #define __put_user_u64(x, addr, err) \ - asm volatile("1: movl %%eax,0(%2)\n" \ - "2: movl %%edx,4(%2)\n" \ + asm volatile(" movw %w5,%%ds\n" \ + "1: movl %%eax,%%ds:0(%2)\n" \ + "2: movl %%edx,%%ds:4(%2)\n" \ "3:\n" \ + " pushl %%ss\n" \ + " popl %%ds\n" \ ".section .fixup,\"ax\"\n" \ "4: movl %3,%0\n" \ " jmp 3b\n" \ @@ -196,7 +206,8 @@ extern int __get_user_bad(void); _ASM_EXTABLE(1b, 4b) \ _ASM_EXTABLE(2b, 4b) \ : "=r" (err) \ - : "A" (x), "r" (addr), "i" (-EFAULT), "0" (err)) + : "A" (x), "r" (addr), "i" (-EFAULT), "0" (err), \ + "r"(__USER_DS)) #define __put_user_x8(x, ptr, __ret_pu) \ asm volatile("call __put_user_8" : "=a" (__ret_pu) \ @@ -336,6 +347,22 @@ do { \ } \ } while (0) +#ifdef CONFIG_X86_32 +#define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \ + asm volatile(" movw %w5,%%ds\n" \ + "1: mov"itype" %%ds:%2,%"rtype"1\n" \ + "2:\n" \ + " pushl %%ss\n" \ + " popl %%ds\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %3,%0\n" \ + " xor"itype" %"rtype"1,%"rtype"1\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=r" (err), ltype (x) \ + : "m" (__m(addr)), "i" (errret), "0" (err), "r"(__USER_DS)) +#else #define __get_user_asm(x, addr, err, itype, rtype, ltype, errret) \ asm volatile("1: mov"itype" %2,%"rtype"1\n" \ "2:\n" \ @@ -347,6 +374,7 @@ do { \ _ASM_EXTABLE(1b, 3b) \ : "=r" (err), ltype(x) \ : "m" (__m(addr)), "i" (errret), "0" (err)) +#endif #define __put_user_nocheck(x, ptr, size) \ ({ \ @@ -373,6 +401,22 @@ struct __large_struct { unsigned long bu * we do not write to any memory gcc knows about, so there are no * aliasing issues. */ +#ifdef CONFIG_X86_32 +#define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \ + asm volatile(" movw %w5,%%ds\n" \ + "1: mov"itype" %"rtype"1,%%ds:%2\n" \ + "2:\n" \ + " pushl %%ss\n" \ + " popl %%ds\n" \ + ".section .fixup,\"ax\"\n" \ + "3: movl %3,%0\n" \ + " jmp 2b\n" \ + ".previous\n" \ + _ASM_EXTABLE(1b, 3b) \ + : "=r"(err) \ + : ltype (x), "m" (__m(addr)), "i" (errret), "0" (err),\ + "r"(__USER_DS)) +#else #define __put_user_asm(x, addr, err, itype, rtype, ltype, errret) \ asm volatile("1: mov"itype" %"rtype"1,%2\n" \ "2:\n" \ @@ -383,6 +427,7 @@ struct __large_struct { unsigned long bu _ASM_EXTABLE(1b, 3b) \ : "=r"(err) \ : ltype(x), "m" (__m(addr)), "i" (errret), "0" (err)) +#endif /** * __get_user: - Get a simple variable from user space, with less checking. * @x: Variable to store result. @@ -447,6 +492,7 @@ extern struct movsl_mask { # include "uaccess_32.h" #else # define ARCH_HAS_SEARCH_EXTABLE +# define ARCH_HAS_SORT_EXTABLE # include "uaccess_64.h" #endif diff -NurpP --minimal linux-2.6.27.15/include/asm-x86/unistd_64.h linux-2.6.27.15-g-v/include/asm-x86/unistd_64.h --- linux-2.6.27.15/include/asm-x86/unistd_64.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-x86/unistd_64.h 2009-02-10 20:32:15.000000000 +0100 @@ -535,7 +535,7 @@ __SYSCALL(__NR_tgkill, sys_tgkill) #define __NR_utimes 235 __SYSCALL(__NR_utimes, sys_utimes) #define __NR_vserver 236 -__SYSCALL(__NR_vserver, sys_ni_syscall) +__SYSCALL(__NR_vserver, sys_vserver) #define __NR_mbind 237 __SYSCALL(__NR_mbind, sys_mbind) #define __NR_set_mempolicy 238 diff -NurpP --minimal linux-2.6.27.15/include/asm-xtensa/kmap_types.h linux-2.6.27.15-g-v/include/asm-xtensa/kmap_types.h --- linux-2.6.27.15/include/asm-xtensa/kmap_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/asm-xtensa/kmap_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -25,6 +25,7 @@ enum km_type { KM_IRQ1, KM_SOFTIRQ0, KM_SOFTIRQ1, + KM_CLEARPAGE, KM_TYPE_NR }; diff -NurpP --minimal linux-2.6.27.15/include/drm/drm_pciids.h linux-2.6.27.15-g-v/include/drm/drm_pciids.h --- linux-2.6.27.15/include/drm/drm_pciids.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/drm/drm_pciids.h 2009-02-10 20:32:15.000000000 +0100 @@ -237,7 +237,7 @@ {0x1002, 0x7835, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS300|RADEON_IS_IGP|RADEON_IS_MOBILITY|RADEON_NEW_MEMMAP}, \ {0x1002, 0x791e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ {0x1002, 0x791f, PCI_ANY_ID, PCI_ANY_ID, 0, 0, CHIP_RS690|RADEON_IS_IGP|RADEON_NEW_MEMMAP|RADEON_IS_IGPGART}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define r128_PCI_IDS \ {0x1002, 0x4c45, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ @@ -277,14 +277,14 @@ {0x1002, 0x5446, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1002, 0x544C, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1002, 0x5452, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define mga_PCI_IDS \ {0x102b, 0x0520, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \ {0x102b, 0x0521, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G200}, \ {0x102b, 0x0525, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G400}, \ {0x102b, 0x2527, PCI_ANY_ID, PCI_ANY_ID, 0, 0, MGA_CARD_TYPE_G550}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define mach64_PCI_IDS \ {0x1002, 0x4749, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ @@ -307,7 +307,7 @@ {0x1002, 0x4c53, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1002, 0x4c4d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1002, 0x4c4e, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define sisdrv_PCI_IDS \ {0x1039, 0x0300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ @@ -318,7 +318,7 @@ {0x1039, 0x7300, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x18CA, 0x0040, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ {0x18CA, 0x0042, PCI_ANY_ID, PCI_ANY_ID, 0, 0, SIS_CHIP_315}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define tdfx_PCI_IDS \ {0x121a, 0x0003, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ @@ -327,7 +327,7 @@ {0x121a, 0x0007, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x121a, 0x0009, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x121a, 0x000b, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define viadrv_PCI_IDS \ {0x1106, 0x3022, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ @@ -339,25 +339,25 @@ {0x1106, 0x3343, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x1106, 0x3230, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_DX9_0}, \ {0x1106, 0x3157, PCI_ANY_ID, PCI_ANY_ID, 0, 0, VIA_PRO_GROUP_A}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define i810_PCI_IDS \ {0x8086, 0x7121, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x7123, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x7125, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x1132, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define i830_PCI_IDS \ {0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2562, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x3582, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2572, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define gamma_PCI_IDS \ {0x3d3d, 0x0008, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define savage_PCI_IDS \ {0x5333, 0x8a20, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_SAVAGE3D}, \ @@ -383,10 +383,10 @@ {0x5333, 0x8d02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_TWISTER}, \ {0x5333, 0x8d03, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \ {0x5333, 0x8d04, PCI_ANY_ID, PCI_ANY_ID, 0, 0, S3_PROSAVAGEDDR}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define ffb_PCI_IDS \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} #define i915_PCI_IDS \ {0x8086, 0x3577, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ @@ -412,4 +412,4 @@ {0x8086, 0x2e02, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2e12, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ {0x8086, 0x2e22, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0}, \ - {0, 0, 0} + {0, 0, 0, 0, 0, 0} diff -NurpP --minimal linux-2.6.27.15/include/linux/a.out.h linux-2.6.27.15-g-v/include/linux/a.out.h --- linux-2.6.27.15/include/linux/a.out.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/a.out.h 2009-02-10 20:32:15.000000000 +0100 @@ -39,6 +39,14 @@ enum machine_type { M_MIPS2 = 152 /* MIPS R6000/R4000 binary */ }; +/* Constants for the N_FLAGS field */ +#define F_PAX_PAGEEXEC 1 /* Paging based non-executable pages */ +#define F_PAX_EMUTRAMP 2 /* Emulate trampolines */ +#define F_PAX_MPROTECT 4 /* Restrict mprotect() */ +#define F_PAX_RANDMMAP 8 /* Randomize mmap() base */ +/*#define F_PAX_RANDEXEC 16*/ /* Randomize ET_EXEC base */ +#define F_PAX_SEGMEXEC 32 /* Segmentation based non-executable pages */ + #if !defined (N_MAGIC) #define N_MAGIC(exec) ((exec).a_info & 0xffff) #endif diff -NurpP --minimal linux-2.6.27.15/include/linux/binfmts.h linux-2.6.27.15-g-v/include/linux/binfmts.h --- linux-2.6.27.15/include/linux/binfmts.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/binfmts.h 2009-02-10 20:32:15.000000000 +0100 @@ -71,6 +71,7 @@ struct linux_binfmt { int (*load_binary)(struct linux_binprm *, struct pt_regs * regs); int (*load_shlib)(struct file *); int (*core_dump)(long signr, struct pt_regs *regs, struct file *file, unsigned long limit); + void (*handle_mprotect)(struct vm_area_struct *vma, unsigned long newflags); unsigned long min_coredump; /* minimal dump size */ int hasvdso; }; diff -NurpP --minimal linux-2.6.27.15/include/linux/cache.h linux-2.6.27.15-g-v/include/linux/cache.h --- linux-2.6.27.15/include/linux/cache.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/cache.h 2009-02-10 20:32:15.000000000 +0100 @@ -16,6 +16,10 @@ #define __read_mostly #endif +#ifndef __read_only +#define __read_only __read_mostly +#endif + #ifndef ____cacheline_aligned #define ____cacheline_aligned __attribute__((__aligned__(SMP_CACHE_BYTES))) #endif diff -NurpP --minimal linux-2.6.27.15/include/linux/capability.h linux-2.6.27.15-g-v/include/linux/capability.h --- linux-2.6.27.15/include/linux/capability.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/capability.h 2009-02-10 20:32:15.000000000 +0100 @@ -274,6 +274,7 @@ typedef struct kernel_cap_struct { arbitrary SCSI commands */ /* Allow setting encryption key on loopback filesystem */ /* Allow setting zone reclaim policy */ +/* Allow the selection of a security context */ #define CAP_SYS_ADMIN 21 @@ -346,7 +347,13 @@ typedef struct kernel_cap_struct { #define CAP_MAC_ADMIN 33 -#define CAP_LAST_CAP CAP_MAC_ADMIN +/* Allow context manipulations */ +/* Allow changing context info on files */ + +#define CAP_CONTEXT 34 + + +#define CAP_LAST_CAP CAP_CONTEXT #define cap_valid(x) ((x) >= 0 && (x) <= CAP_LAST_CAP) @@ -516,6 +523,7 @@ kernel_cap_t cap_set_effective(const ker #define has_capability(t, cap) (security_capable((t), (cap)) == 0) extern int capable(int cap); +int capable_nolog(int cap); #endif /* __KERNEL__ */ diff -NurpP --minimal linux-2.6.27.15/include/linux/cpumask.h linux-2.6.27.15-g-v/include/linux/cpumask.h --- linux-2.6.27.15/include/linux/cpumask.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/cpumask.h 2009-02-10 20:32:15.000000000 +0100 @@ -139,7 +139,6 @@ #include typedef struct { DECLARE_BITMAP(bits, NR_CPUS); } cpumask_t; -extern cpumask_t _unused_cpumask_arg_; #define cpu_set(cpu, dst) __cpu_set((cpu), &(dst)) static inline void __cpu_set(int cpu, volatile cpumask_t *dstp) diff -NurpP --minimal linux-2.6.27.15/include/linux/devpts_fs.h linux-2.6.27.15-g-v/include/linux/devpts_fs.h --- linux-2.6.27.15/include/linux/devpts_fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/devpts_fs.h 2009-02-10 20:32:15.000000000 +0100 @@ -34,5 +34,4 @@ static inline void devpts_pty_kill(int n #endif - #endif /* _LINUX_DEVPTS_FS_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/elf.h linux-2.6.27.15-g-v/include/linux/elf.h --- linux-2.6.27.15/include/linux/elf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/elf.h 2009-02-10 20:32:15.000000000 +0100 @@ -49,6 +49,17 @@ typedef __s64 Elf64_Sxword; #define PT_GNU_EH_FRAME 0x6474e550 #define PT_GNU_STACK (PT_LOOS + 0x474e551) +#define PT_GNU_RELRO (PT_LOOS + 0x474e552) + +#define PT_PAX_FLAGS (PT_LOOS + 0x5041580) + +/* Constants for the e_flags field */ +#define EF_PAX_PAGEEXEC 1 /* Paging based non-executable pages */ +#define EF_PAX_EMUTRAMP 2 /* Emulate trampolines */ +#define EF_PAX_MPROTECT 4 /* Restrict mprotect() */ +#define EF_PAX_RANDMMAP 8 /* Randomize mmap() base */ +/*#define EF_PAX_RANDEXEC 16*/ /* Randomize ET_EXEC base */ +#define EF_PAX_SEGMEXEC 32 /* Segmentation based non-executable pages */ /* These constants define the different elf file types */ #define ET_NONE 0 @@ -84,6 +95,8 @@ typedef __s64 Elf64_Sxword; #define DT_DEBUG 21 #define DT_TEXTREL 22 #define DT_JMPREL 23 +#define DT_FLAGS 30 + #define DF_TEXTREL 0x00000004 #define DT_ENCODING 32 #define OLD_DT_LOOS 0x60000000 #define DT_LOOS 0x6000000d @@ -230,6 +243,19 @@ typedef struct elf64_hdr { #define PF_W 0x2 #define PF_X 0x1 +#define PF_PAGEEXEC (1U << 4) /* Enable PAGEEXEC */ +#define PF_NOPAGEEXEC (1U << 5) /* Disable PAGEEXEC */ +#define PF_SEGMEXEC (1U << 6) /* Enable SEGMEXEC */ +#define PF_NOSEGMEXEC (1U << 7) /* Disable SEGMEXEC */ +#define PF_MPROTECT (1U << 8) /* Enable MPROTECT */ +#define PF_NOMPROTECT (1U << 9) /* Disable MPROTECT */ +/*#define PF_RANDEXEC (1U << 10)*/ /* Enable RANDEXEC */ +/*#define PF_NORANDEXEC (1U << 11)*/ /* Disable RANDEXEC */ +#define PF_EMUTRAMP (1U << 12) /* Enable EMUTRAMP */ +#define PF_NOEMUTRAMP (1U << 13) /* Disable EMUTRAMP */ +#define PF_RANDMMAP (1U << 14) /* Enable RANDMMAP */ +#define PF_NORANDMMAP (1U << 15) /* Disable RANDMMAP */ + typedef struct elf32_phdr{ Elf32_Word p_type; Elf32_Off p_offset; @@ -322,6 +348,8 @@ typedef struct elf64_shdr { #define EI_OSABI 7 #define EI_PAD 8 +#define EI_PAX 14 + #define ELFMAG0 0x7f /* EI_MAG */ #define ELFMAG1 'E' #define ELFMAG2 'L' @@ -383,6 +411,7 @@ extern Elf32_Dyn _DYNAMIC []; #define elf_phdr elf32_phdr #define elf_note elf32_note #define elf_addr_t Elf32_Off +#define elf_dyn Elf32_Dyn #else @@ -391,6 +420,7 @@ extern Elf64_Dyn _DYNAMIC []; #define elf_phdr elf64_phdr #define elf_note elf64_note #define elf_addr_t Elf64_Off +#define elf_dyn Elf64_Dyn #endif diff -NurpP --minimal linux-2.6.27.15/include/linux/ext2_fs.h linux-2.6.27.15-g-v/include/linux/ext2_fs.h --- linux-2.6.27.15/include/linux/ext2_fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/ext2_fs.h 2009-02-10 20:32:15.000000000 +0100 @@ -189,8 +189,12 @@ struct ext2_group_desc #define EXT2_NOTAIL_FL FS_NOTAIL_FL /* file tail should not be merged */ #define EXT2_DIRSYNC_FL FS_DIRSYNC_FL /* dirsync behaviour (directories only) */ #define EXT2_TOPDIR_FL FS_TOPDIR_FL /* Top of directory hierarchies*/ +#define EXT2_IXUNLINK_FL FS_IXUNLINK_FL /* Immutable invert on unlink */ #define EXT2_RESERVED_FL FS_RESERVED_FL /* reserved for ext2 lib */ +#define EXT2_BARRIER_FL FS_BARRIER_FL /* Barrier for chroot() */ +#define EXT2_COW_FL FS_COW_FL /* Copy on Write marker */ + #define EXT2_FL_USER_VISIBLE FS_FL_USER_VISIBLE /* User visible flags */ #define EXT2_FL_USER_MODIFIABLE FS_FL_USER_MODIFIABLE /* User modifiable flags */ @@ -247,7 +251,7 @@ struct ext2_inode { struct { __u8 l_i_frag; /* Fragment number */ __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; + __u16 l_i_tag; /* Context Tag */ __le16 l_i_uid_high; /* these 2 fields */ __le16 l_i_gid_high; /* were reserved2[0] */ __u32 l_i_reserved2; @@ -279,6 +283,7 @@ struct ext2_inode { #define i_gid_low i_gid #define i_uid_high osd2.linux2.l_i_uid_high #define i_gid_high osd2.linux2.l_i_gid_high +#define i_raw_tag osd2.linux2.l_i_tag #define i_reserved2 osd2.linux2.l_i_reserved2 #endif @@ -323,6 +328,7 @@ struct ext2_inode { #define EXT2_MOUNT_USRQUOTA 0x020000 /* user quota */ #define EXT2_MOUNT_GRPQUOTA 0x040000 /* group quota */ #define EXT2_MOUNT_RESERVATION 0x080000 /* Preallocation */ +#define EXT2_MOUNT_TAGGED (1<<24) /* Enable Context Tags */ #define clear_opt(o, opt) o &= ~EXT2_MOUNT_##opt diff -NurpP --minimal linux-2.6.27.15/include/linux/ext3_fs.h linux-2.6.27.15-g-v/include/linux/ext3_fs.h --- linux-2.6.27.15/include/linux/ext3_fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/ext3_fs.h 2009-02-10 20:32:15.000000000 +0100 @@ -173,10 +173,14 @@ struct ext3_group_desc #define EXT3_NOTAIL_FL 0x00008000 /* file tail should not be merged */ #define EXT3_DIRSYNC_FL 0x00010000 /* dirsync behaviour (directories only) */ #define EXT3_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ +#define EXT3_IXUNLINK_FL 0x08000000 /* Immutable invert on unlink */ #define EXT3_RESERVED_FL 0x80000000 /* reserved for ext3 lib */ -#define EXT3_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ -#define EXT3_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ +#define EXT3_BARRIER_FL 0x04000000 /* Barrier for chroot() */ +#define EXT3_COW_FL 0x20000000 /* Copy on Write marker */ + +#define EXT3_FL_USER_VISIBLE 0x0103DFFF /* User visible flags */ +#define EXT3_FL_USER_MODIFIABLE 0x010380FF /* User modifiable flags */ /* * Inode dynamic state flags @@ -292,7 +296,7 @@ struct ext3_inode { struct { __u8 l_i_frag; /* Fragment number */ __u8 l_i_fsize; /* Fragment size */ - __u16 i_pad1; + __u16 l_i_tag; /* Context Tag */ __le16 l_i_uid_high; /* these 2 fields */ __le16 l_i_gid_high; /* were reserved2[0] */ __u32 l_i_reserved2; @@ -326,6 +330,7 @@ struct ext3_inode { #define i_gid_low i_gid #define i_uid_high osd2.linux2.l_i_uid_high #define i_gid_high osd2.linux2.l_i_gid_high +#define i_raw_tag osd2.linux2.l_i_tag #define i_reserved2 osd2.linux2.l_i_reserved2 #elif defined(__GNU__) @@ -380,6 +385,7 @@ struct ext3_inode { #define EXT3_MOUNT_QUOTA 0x80000 /* Some quota option set */ #define EXT3_MOUNT_USRQUOTA 0x100000 /* "old" user quota */ #define EXT3_MOUNT_GRPQUOTA 0x200000 /* "old" group quota */ +#define EXT3_MOUNT_TAGGED (1<<24) /* Enable Context Tags */ /* Compatibility, for having both ext2_fs.h and ext3_fs.h included at once */ #ifndef _LINUX_EXT2_FS_H @@ -822,6 +828,7 @@ struct buffer_head * ext3_bread (handle_ int ext3_get_blocks_handle(handle_t *handle, struct inode *inode, sector_t iblock, unsigned long maxblocks, struct buffer_head *bh_result, int create, int extend_disksize); +extern int ext3_sync_flags(struct inode *inode); extern struct inode *ext3_iget(struct super_block *, unsigned long); extern int ext3_write_inode (struct inode *, int); diff -NurpP --minimal linux-2.6.27.15/include/linux/fs.h linux-2.6.27.15-g-v/include/linux/fs.h --- linux-2.6.27.15/include/linux/fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/fs.h 2009-02-10 20:32:15.000000000 +0100 @@ -128,6 +128,9 @@ extern int dir_notify_enable; #define MS_RELATIME (1<<21) /* Update atime relative to mtime/ctime. */ #define MS_KERNMOUNT (1<<22) /* this is a kern_mount call */ #define MS_I_VERSION (1<<23) /* Update inode I_version field */ +#define MS_TAGGED (1<<24) /* use generic inode tagging */ +#define MS_TAGID (1<<25) /* use specific tag for this mount */ +#define MS_NOTAGCHECK (1<<26) /* don't check tags */ #define MS_ACTIVE (1<<30) #define MS_NOUSER (1<<31) @@ -154,6 +157,14 @@ extern int dir_notify_enable; #define S_NOCMTIME 128 /* Do not update file c/mtime */ #define S_SWAPFILE 256 /* Do not truncate: swapon got its bmaps */ #define S_PRIVATE 512 /* Inode is fs-internal */ +#define S_IXUNLINK 1024 /* Immutable Invert on unlink */ + +/* Linux-VServer related Inode flags */ + +#define V_VALID 1 +#define V_XATTR 2 +#define V_BARRIER 4 /* Barrier for chroot() */ +#define V_COW 8 /* Copy on Write */ /* * Note that nosuid etc flags are inode-specific: setting some file-system @@ -176,12 +187,15 @@ extern int dir_notify_enable; #define IS_DIRSYNC(inode) (__IS_FLG(inode, MS_SYNCHRONOUS|MS_DIRSYNC) || \ ((inode)->i_flags & (S_SYNC|S_DIRSYNC))) #define IS_MANDLOCK(inode) __IS_FLG(inode, MS_MANDLOCK) -#define IS_NOATIME(inode) __IS_FLG(inode, MS_RDONLY|MS_NOATIME) -#define IS_I_VERSION(inode) __IS_FLG(inode, MS_I_VERSION) +#define IS_NOATIME(inode) __IS_FLG(inode, MS_RDONLY|MS_NOATIME) +#define IS_I_VERSION(inode) __IS_FLG(inode, MS_I_VERSION) +#define IS_TAGGED(inode) __IS_FLG(inode, MS_TAGGED) #define IS_NOQUOTA(inode) ((inode)->i_flags & S_NOQUOTA) #define IS_APPEND(inode) ((inode)->i_flags & S_APPEND) #define IS_IMMUTABLE(inode) ((inode)->i_flags & S_IMMUTABLE) +#define IS_IXUNLINK(inode) ((inode)->i_flags & S_IXUNLINK) +#define IS_IXORUNLINK(inode) ((IS_IXUNLINK(inode) ? S_IMMUTABLE : 0) ^ IS_IMMUTABLE(inode)) #define IS_POSIXACL(inode) __IS_FLG(inode, MS_POSIXACL) #define IS_DEADDIR(inode) ((inode)->i_flags & S_DEAD) @@ -189,6 +203,16 @@ extern int dir_notify_enable; #define IS_SWAPFILE(inode) ((inode)->i_flags & S_SWAPFILE) #define IS_PRIVATE(inode) ((inode)->i_flags & S_PRIVATE) +#define IS_BARRIER(inode) (S_ISDIR((inode)->i_mode) && ((inode)->i_vflags & V_BARRIER)) + +#ifdef CONFIG_VSERVER_COWBL +# define IS_COW(inode) (IS_IXUNLINK(inode) && IS_IMMUTABLE(inode)) +# define IS_COW_LINK(inode) (S_ISREG((inode)->i_mode) && ((inode)->i_nlink > 1)) +#else +# define IS_COW(inode) (0) +# define IS_COW_LINK(inode) (0) +#endif + /* the read-only stuff doesn't really belong here, but any other place is probably as bad and I don't want to create yet another include file. */ @@ -262,11 +286,14 @@ extern int dir_notify_enable; #define FS_TOPDIR_FL 0x00020000 /* Top of directory hierarchies*/ #define FS_EXTENT_FL 0x00080000 /* Extents */ #define FS_DIRECTIO_FL 0x00100000 /* Use direct i/o */ +#define FS_IXUNLINK_FL 0x08000000 /* Immutable invert on unlink */ #define FS_RESERVED_FL 0x80000000 /* reserved for ext2 lib */ -#define FS_FL_USER_VISIBLE 0x0003DFFF /* User visible flags */ -#define FS_FL_USER_MODIFIABLE 0x000380FF /* User modifiable flags */ +#define FS_BARRIER_FL 0x04000000 /* Barrier for chroot() */ +#define FS_COW_FL 0x20000000 /* Copy on Write marker */ +#define FS_FL_USER_VISIBLE 0x0103DFFF /* User visible flags */ +#define FS_FL_USER_MODIFIABLE 0x010380FF /* User modifiable flags */ #define SYNC_FILE_RANGE_WAIT_BEFORE 1 #define SYNC_FILE_RANGE_WRITE 2 @@ -337,6 +364,7 @@ typedef void (dio_iodone_t)(struct kiocb #define ATTR_KILL_PRIV (1 << 14) #define ATTR_OPEN (1 << 15) /* Truncating from open(O_TRUNC) */ #define ATTR_TIMES_SET (1 << 16) +#define ATTR_TAG (1 << 17) /* * This is the Inode Attributes structure, used for notify_change(). It @@ -352,6 +380,7 @@ struct iattr { umode_t ia_mode; uid_t ia_uid; gid_t ia_gid; + tag_t ia_tag; loff_t ia_size; struct timespec ia_atime; struct timespec ia_mtime; @@ -365,6 +394,9 @@ struct iattr { struct file *ia_file; }; +#define ATTR_FLAG_BARRIER 512 /* Barrier for chroot() */ +#define ATTR_FLAG_IXUNLINK 1024 /* Immutable invert on unlink */ + /* * Includes for diskquotas. */ @@ -629,7 +661,9 @@ struct inode { unsigned int i_nlink; uid_t i_uid; gid_t i_gid; + tag_t i_tag; dev_t i_rdev; + dev_t i_mdev; u64 i_version; loff_t i_size; #ifdef __NEED_I_SIZE_ORDERED @@ -677,7 +711,8 @@ struct inode { unsigned long i_state; unsigned long dirtied_when; /* jiffies of first dirtying */ - unsigned int i_flags; + unsigned short i_flags; + unsigned short i_vflags; atomic_t i_writecount; #ifdef CONFIG_SECURITY @@ -764,12 +799,12 @@ static inline void i_size_write(struct i static inline unsigned iminor(const struct inode *inode) { - return MINOR(inode->i_rdev); + return MINOR(inode->i_mdev); } static inline unsigned imajor(const struct inode *inode) { - return MAJOR(inode->i_rdev); + return MAJOR(inode->i_mdev); } extern struct block_device *I_BDEV(struct inode *inode); @@ -827,6 +862,7 @@ struct file { loff_t f_pos; struct fown_struct f_owner; unsigned int f_uid, f_gid; + xid_t f_xid; struct file_ra_state f_ra; u64 f_version; @@ -961,6 +997,7 @@ struct file_lock { struct file *fl_file; loff_t fl_start; loff_t fl_end; + xid_t fl_xid; struct fasync_struct * fl_fasync; /* for lease break notifications */ unsigned long fl_break_time; /* for nonblocking lease breaks */ @@ -1289,6 +1326,7 @@ struct inode_operations { void (*truncate_range)(struct inode *, loff_t, loff_t); long (*fallocate)(struct inode *inode, int mode, loff_t offset, loff_t len); + int (*sync_flags) (struct inode *); }; struct seq_file; @@ -1304,6 +1342,7 @@ extern ssize_t vfs_readv(struct file *, unsigned long, loff_t *); extern ssize_t vfs_writev(struct file *, const struct iovec __user *, unsigned long, loff_t *); +ssize_t vfs_sendfile(struct file *, struct file *, loff_t *, size_t, loff_t); struct super_operations { struct inode *(*alloc_inode)(struct super_block *sb); @@ -1994,6 +2033,7 @@ extern int dcache_dir_open(struct inode extern int dcache_dir_close(struct inode *, struct file *); extern loff_t dcache_dir_lseek(struct file *, loff_t, int); extern int dcache_readdir(struct file *, void *, filldir_t); +extern int dcache_readdir_filter(struct file *, void *, filldir_t, int (*)(struct dentry *)); extern int simple_getattr(struct vfsmount *, struct dentry *, struct kstat *); extern int simple_statfs(struct dentry *, struct kstatfs *); extern int simple_link(struct dentry *, struct inode *, struct dentry *); diff -NurpP --minimal linux-2.6.27.15/include/linux/gracl.h linux-2.6.27.15-g-v/include/linux/gracl.h --- linux-2.6.27.15/include/linux/gracl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/gracl.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,318 @@ +#ifndef GR_ACL_H +#define GR_ACL_H + +#include +#include +#include +#include +#include + +/* Major status information */ + +#define GR_VERSION "grsecurity 2.1.12" +#define GRSECURITY_VERSION 0x2112 + +enum { + + SHUTDOWN = 0, + ENABLE = 1, + SPROLE = 2, + RELOAD = 3, + SEGVMOD = 4, + STATUS = 5, + UNSPROLE = 6, + PASSSET = 7, + SPROLEPAM = 8 +}; + +/* Password setup definitions + * kernel/grhash.c */ +enum { + GR_PW_LEN = 128, + GR_SALT_LEN = 16, + GR_SHA_LEN = 32, +}; + +enum { + GR_SPROLE_LEN = 64, +}; + +#define GR_NLIMITS (RLIMIT_LOCKS + 2) + +/* Begin Data Structures */ + +struct sprole_pw { + unsigned char *rolename; + unsigned char salt[GR_SALT_LEN]; + unsigned char sum[GR_SHA_LEN]; /* 256-bit SHA hash of the password */ +}; + +struct name_entry { + __u32 key; + ino_t inode; + dev_t device; + char *name; + __u16 len; + __u8 deleted; + struct name_entry *prev; + struct name_entry *next; +}; + +struct inodev_entry { + struct name_entry *nentry; + struct inodev_entry *prev; + struct inodev_entry *next; +}; + +struct acl_role_db { + struct acl_role_label **r_hash; + __u32 r_size; +}; + +struct inodev_db { + struct inodev_entry **i_hash; + __u32 i_size; +}; + +struct name_db { + struct name_entry **n_hash; + __u32 n_size; +}; + +struct crash_uid { + uid_t uid; + unsigned long expires; +}; + +struct gr_hash_struct { + void **table; + void **nametable; + void *first; + __u32 table_size; + __u32 used_size; + int type; +}; + +/* Userspace Grsecurity ACL data structures */ + +struct acl_subject_label { + char *filename; + ino_t inode; + dev_t device; + __u32 mode; + kernel_cap_t cap_mask; + kernel_cap_t cap_lower; + + struct rlimit res[GR_NLIMITS]; + __u16 resmask; + + __u8 user_trans_type; + __u8 group_trans_type; + uid_t *user_transitions; + gid_t *group_transitions; + __u16 user_trans_num; + __u16 group_trans_num; + + __u32 ip_proto[8]; + __u32 ip_type; + struct acl_ip_label **ips; + __u32 ip_num; + + __u32 crashes; + unsigned long expires; + + struct acl_subject_label *parent_subject; + struct gr_hash_struct *hash; + struct acl_subject_label *prev; + struct acl_subject_label *next; + + struct acl_object_label **obj_hash; + __u32 obj_hash_size; + __u16 pax_flags; +}; + +struct role_allowed_ip { + __u32 addr; + __u32 netmask; + + struct role_allowed_ip *prev; + struct role_allowed_ip *next; +}; + +struct role_transition { + char *rolename; + + struct role_transition *prev; + struct role_transition *next; +}; + +struct acl_role_label { + char *rolename; + uid_t uidgid; + __u16 roletype; + + __u16 auth_attempts; + unsigned long expires; + + struct acl_subject_label *root_label; + struct gr_hash_struct *hash; + + struct acl_role_label *prev; + struct acl_role_label *next; + + struct role_transition *transitions; + struct role_allowed_ip *allowed_ips; + uid_t *domain_children; + __u16 domain_child_num; + + struct acl_subject_label **subj_hash; + __u32 subj_hash_size; +}; + +struct user_acl_role_db { + struct acl_role_label **r_table; + __u32 num_pointers; /* Number of allocations to track */ + __u32 num_roles; /* Number of roles */ + __u32 num_domain_children; /* Number of domain children */ + __u32 num_subjects; /* Number of subjects */ + __u32 num_objects; /* Number of objects */ +}; + +struct acl_object_label { + char *filename; + ino_t inode; + dev_t device; + __u32 mode; + + struct acl_subject_label *nested; + struct acl_object_label *globbed; + + /* next two structures not used */ + + struct acl_object_label *prev; + struct acl_object_label *next; +}; + +struct acl_ip_label { + char *iface; + __u32 addr; + __u32 netmask; + __u16 low, high; + __u8 mode; + __u32 type; + __u32 proto[8]; + + /* next two structures not used */ + + struct acl_ip_label *prev; + struct acl_ip_label *next; +}; + +struct gr_arg { + struct user_acl_role_db role_db; + unsigned char pw[GR_PW_LEN]; + unsigned char salt[GR_SALT_LEN]; + unsigned char sum[GR_SHA_LEN]; + unsigned char sp_role[GR_SPROLE_LEN]; + struct sprole_pw *sprole_pws; + dev_t segv_device; + ino_t segv_inode; + uid_t segv_uid; + __u16 num_sprole_pws; + __u16 mode; +}; + +struct gr_arg_wrapper { + struct gr_arg *arg; + __u32 version; + __u32 size; +}; + +struct subject_map { + struct acl_subject_label *user; + struct acl_subject_label *kernel; + struct subject_map *prev; + struct subject_map *next; +}; + +struct acl_subj_map_db { + struct subject_map **s_hash; + __u32 s_size; +}; + +/* End Data Structures Section */ + +/* Hash functions generated by empirical testing by Brad Spengler + Makes good use of the low bits of the inode. Generally 0-1 times + in loop for successful match. 0-3 for unsuccessful match. + Shift/add algorithm with modulus of table size and an XOR*/ + +static __inline__ unsigned int +rhash(const uid_t uid, const __u16 type, const unsigned int sz) +{ + return (((uid << type) + (uid ^ type)) % sz); +} + + static __inline__ unsigned int +shash(const struct acl_subject_label *userp, const unsigned int sz) +{ + return ((const unsigned long)userp % sz); +} + +static __inline__ unsigned int +fhash(const ino_t ino, const dev_t dev, const unsigned int sz) +{ + return (((ino + dev) ^ ((ino << 13) + (ino << 23) + (dev << 9))) % sz); +} + +static __inline__ unsigned int +nhash(const char *name, const __u16 len, const unsigned int sz) +{ + return full_name_hash(name, len) % sz; +} + +#define FOR_EACH_ROLE_START(role,iter) \ + role = NULL; \ + iter = 0; \ + while (iter < acl_role_set.r_size) { \ + if (role == NULL) \ + role = acl_role_set.r_hash[iter]; \ + if (role == NULL) { \ + iter++; \ + continue; \ + } + +#define FOR_EACH_ROLE_END(role,iter) \ + role = role->next; \ + if (role == NULL) \ + iter++; \ + } + +#define FOR_EACH_SUBJECT_START(role,subj,iter) \ + subj = NULL; \ + iter = 0; \ + while (iter < role->subj_hash_size) { \ + if (subj == NULL) \ + subj = role->subj_hash[iter]; \ + if (subj == NULL) { \ + iter++; \ + continue; \ + } + +#define FOR_EACH_SUBJECT_END(subj,iter) \ + subj = subj->next; \ + if (subj == NULL) \ + iter++; \ + } + + +#define FOR_EACH_NESTED_SUBJECT_START(role,subj) \ + subj = role->hash->first; \ + while (subj != NULL) { + +#define FOR_EACH_NESTED_SUBJECT_END(subj) \ + subj = subj->next; \ + } + +#endif + diff -NurpP --minimal linux-2.6.27.15/include/linux/gralloc.h linux-2.6.27.15-g-v/include/linux/gralloc.h --- linux-2.6.27.15/include/linux/gralloc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/gralloc.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,8 @@ +#ifndef __GRALLOC_H +#define __GRALLOC_H + +void acl_free_all(void); +int acl_alloc_stack_init(unsigned long size); +void *acl_alloc(unsigned long len); + +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/grdefs.h linux-2.6.27.15-g-v/include/linux/grdefs.h --- linux-2.6.27.15/include/linux/grdefs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/grdefs.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,131 @@ +#ifndef GRDEFS_H +#define GRDEFS_H + +/* Begin grsecurity status declarations */ + +enum { + GR_READY = 0x01, + GR_STATUS_INIT = 0x00 // disabled state +}; + +/* Begin ACL declarations */ + +/* Role flags */ + +enum { + GR_ROLE_USER = 0x0001, + GR_ROLE_GROUP = 0x0002, + GR_ROLE_DEFAULT = 0x0004, + GR_ROLE_SPECIAL = 0x0008, + GR_ROLE_AUTH = 0x0010, + GR_ROLE_NOPW = 0x0020, + GR_ROLE_GOD = 0x0040, + GR_ROLE_LEARN = 0x0080, + GR_ROLE_TPE = 0x0100, + GR_ROLE_DOMAIN = 0x0200, + GR_ROLE_PAM = 0x0400 +}; + +/* ACL Subject and Object mode flags */ +enum { + GR_DELETED = 0x80000000 +}; + +/* ACL Object-only mode flags */ +enum { + GR_READ = 0x00000001, + GR_APPEND = 0x00000002, + GR_WRITE = 0x00000004, + GR_EXEC = 0x00000008, + GR_FIND = 0x00000010, + GR_INHERIT = 0x00000020, + GR_SETID = 0x00000040, + GR_CREATE = 0x00000080, + GR_DELETE = 0x00000100, + GR_LINK = 0x00000200, + GR_AUDIT_READ = 0x00000400, + GR_AUDIT_APPEND = 0x00000800, + GR_AUDIT_WRITE = 0x00001000, + GR_AUDIT_EXEC = 0x00002000, + GR_AUDIT_FIND = 0x00004000, + GR_AUDIT_INHERIT= 0x00008000, + GR_AUDIT_SETID = 0x00010000, + GR_AUDIT_CREATE = 0x00020000, + GR_AUDIT_DELETE = 0x00040000, + GR_AUDIT_LINK = 0x00080000, + GR_PTRACERD = 0x00100000, + GR_NOPTRACE = 0x00200000, + GR_SUPPRESS = 0x00400000, + GR_NOLEARN = 0x00800000 +}; + +#define GR_AUDITS (GR_AUDIT_READ | GR_AUDIT_WRITE | GR_AUDIT_APPEND | GR_AUDIT_EXEC | \ + GR_AUDIT_FIND | GR_AUDIT_INHERIT | GR_AUDIT_SETID | \ + GR_AUDIT_CREATE | GR_AUDIT_DELETE | GR_AUDIT_LINK) + +/* ACL subject-only mode flags */ +enum { + GR_KILL = 0x00000001, + GR_VIEW = 0x00000002, + GR_PROTECTED = 0x00000004, + GR_LEARN = 0x00000008, + GR_OVERRIDE = 0x00000010, + /* just a placeholder, this mode is only used in userspace */ + GR_DUMMY = 0x00000020, + GR_PROTSHM = 0x00000040, + GR_KILLPROC = 0x00000080, + GR_KILLIPPROC = 0x00000100, + /* just a placeholder, this mode is only used in userspace */ + GR_NOTROJAN = 0x00000200, + GR_PROTPROCFD = 0x00000400, + GR_PROCACCT = 0x00000800, + GR_RELAXPTRACE = 0x00001000, + GR_NESTED = 0x00002000, + GR_INHERITLEARN = 0x00004000, + GR_PROCFIND = 0x00008000, + GR_POVERRIDE = 0x00010000, + GR_KERNELAUTH = 0x00020000, +}; + +enum { + GR_PAX_ENABLE_SEGMEXEC = 0x0001, + GR_PAX_ENABLE_PAGEEXEC = 0x0002, + GR_PAX_ENABLE_MPROTECT = 0x0004, + GR_PAX_ENABLE_RANDMMAP = 0x0008, + GR_PAX_ENABLE_EMUTRAMP = 0x0010, + GR_PAX_DISABLE_SEGMEXEC = 0x0100, + GR_PAX_DISABLE_PAGEEXEC = 0x0200, + GR_PAX_DISABLE_MPROTECT = 0x0400, + GR_PAX_DISABLE_RANDMMAP = 0x0800, + GR_PAX_DISABLE_EMUTRAMP = 0x1000, +}; + +enum { + GR_ID_USER = 0x01, + GR_ID_GROUP = 0x02, +}; + +enum { + GR_ID_ALLOW = 0x01, + GR_ID_DENY = 0x02, +}; + +#define GR_CRASH_RES 11 +#define GR_UIDTABLE_MAX 500 + +/* begin resource learning section */ +enum { + GR_RLIM_CPU_BUMP = 60, + GR_RLIM_FSIZE_BUMP = 50000, + GR_RLIM_DATA_BUMP = 10000, + GR_RLIM_STACK_BUMP = 1000, + GR_RLIM_CORE_BUMP = 10000, + GR_RLIM_RSS_BUMP = 500000, + GR_RLIM_NPROC_BUMP = 1, + GR_RLIM_NOFILE_BUMP = 5, + GR_RLIM_MEMLOCK_BUMP = 50000, + GR_RLIM_AS_BUMP = 500000, + GR_RLIM_LOCKS_BUMP = 2 +}; + +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/grinternal.h linux-2.6.27.15-g-v/include/linux/grinternal.h --- linux-2.6.27.15/include/linux/grinternal.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/grinternal.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,210 @@ +#ifndef __GRINTERNAL_H +#define __GRINTERNAL_H + +#ifdef CONFIG_GRKERNSEC + +#include +#include +#include +#include + +void gr_add_learn_entry(const char *fmt, ...); +__u32 gr_search_file(const struct dentry *dentry, const __u32 mode, + const struct vfsmount *mnt); +__u32 gr_check_create(const struct dentry *new_dentry, + const struct dentry *parent, + const struct vfsmount *mnt, const __u32 mode); +int gr_check_protected_task(const struct task_struct *task); +__u32 to_gr_audit(const __u32 reqmode); +int gr_set_acls(const int type); + +int gr_acl_is_enabled(void); +char gr_roletype_to_char(void); + +void gr_handle_alertkill(struct task_struct *task); +char *gr_to_filename(const struct dentry *dentry, + const struct vfsmount *mnt); +char *gr_to_filename1(const struct dentry *dentry, + const struct vfsmount *mnt); +char *gr_to_filename2(const struct dentry *dentry, + const struct vfsmount *mnt); +char *gr_to_filename3(const struct dentry *dentry, + const struct vfsmount *mnt); + +extern int grsec_enable_link; +extern int grsec_enable_fifo; +extern int grsec_enable_execve; +extern int grsec_enable_shm; +extern int grsec_enable_execlog; +extern int grsec_enable_signal; +extern int grsec_enable_forkfail; +extern int grsec_enable_time; +extern int grsec_enable_chroot_shmat; +extern int grsec_enable_chroot_findtask; +extern int grsec_enable_chroot_mount; +extern int grsec_enable_chroot_double; +extern int grsec_enable_chroot_pivot; +extern int grsec_enable_chroot_chdir; +extern int grsec_enable_chroot_chmod; +extern int grsec_enable_chroot_mknod; +extern int grsec_enable_chroot_fchdir; +extern int grsec_enable_chroot_nice; +extern int grsec_enable_chroot_execlog; +extern int grsec_enable_chroot_caps; +extern int grsec_enable_chroot_sysctl; +extern int grsec_enable_chroot_unix; +extern int grsec_enable_tpe; +extern int grsec_tpe_gid; +extern int grsec_enable_tpe_all; +extern int grsec_enable_sidcaps; +extern int grsec_enable_socket_all; +extern int grsec_socket_all_gid; +extern int grsec_enable_socket_client; +extern int grsec_socket_client_gid; +extern int grsec_enable_socket_server; +extern int grsec_socket_server_gid; +extern int grsec_audit_gid; +extern int grsec_enable_group; +extern int grsec_enable_audit_ipc; +extern int grsec_enable_audit_textrel; +extern int grsec_enable_mount; +extern int grsec_enable_chdir; +extern int grsec_resource_logging; +extern int grsec_lock; + +extern spinlock_t grsec_alert_lock; +extern unsigned long grsec_alert_wtime; +extern unsigned long grsec_alert_fyet; + +extern spinlock_t grsec_audit_lock; + +extern rwlock_t grsec_exec_file_lock; + +#define gr_task_fullpath(tsk) (tsk->exec_file ? \ + gr_to_filename2(tsk->exec_file->f_path.dentry, \ + tsk->exec_file->f_vfsmnt) : "/") + +#define gr_parent_task_fullpath(tsk) (tsk->parent->exec_file ? \ + gr_to_filename3(tsk->parent->exec_file->f_path.dentry, \ + tsk->parent->exec_file->f_vfsmnt) : "/") + +#define gr_task_fullpath0(tsk) (tsk->exec_file ? \ + gr_to_filename(tsk->exec_file->f_path.dentry, \ + tsk->exec_file->f_vfsmnt) : "/") + +#define gr_parent_task_fullpath0(tsk) (tsk->parent->exec_file ? \ + gr_to_filename1(tsk->parent->exec_file->f_path.dentry, \ + tsk->parent->exec_file->f_vfsmnt) : "/") + +#define proc_is_chrooted(tsk_a) ((tsk_a->pid > 1) && (tsk_a->fs != NULL) && \ + ((tsk_a->fs->root.dentry->d_inode->i_sb->s_dev != \ + tsk_a->nsproxy->pid_ns->child_reaper->fs->root.dentry->d_inode->i_sb->s_dev) || \ + (tsk_a->fs->root.dentry->d_inode->i_ino != \ + tsk_a->nsproxy->pid_ns->child_reaper->fs->root.dentry->d_inode->i_ino))) + +#define have_same_root(tsk_a,tsk_b) ((tsk_a->fs != NULL) && (tsk_b->fs != NULL) && \ + (tsk_a->fs->root.dentry->d_inode->i_sb->s_dev == \ + tsk_b->fs->root.dentry->d_inode->i_sb->s_dev) && \ + (tsk_a->fs->root.dentry->d_inode->i_ino == \ + tsk_b->fs->root.dentry->d_inode->i_ino)) + +#define DEFAULTSECARGS(task) gr_task_fullpath(task), task->comm, \ + task->pid, task->uid, \ + task->euid, task->gid, task->egid, \ + gr_parent_task_fullpath(task), \ + task->parent->comm, task->parent->pid, \ + task->parent->uid, task->parent->euid, \ + task->parent->gid, task->parent->egid + +#define GR_CHROOT_CAPS Template:\ + CAP TO MASK(CAP LINUX IMMUTABLE) + +#define security_learn(normal_msg,args...) \ +({ \ + read_lock(&grsec_exec_file_lock); \ + gr_add_learn_entry(normal_msg "\n", ## args); \ + read_unlock(&grsec_exec_file_lock); \ +}) + +enum { + GR_DO_AUDIT, + GR_DONT_AUDIT, + GR_DONT_AUDIT_GOOD +}; + +enum { + GR_TTYSNIFF, + GR_RBAC, + GR_RBAC_STR, + GR_STR_RBAC, + GR_RBAC_MODE2, + GR_RBAC_MODE3, + GR_FILENAME, + GR_SYSCTL_HIDDEN, + GR_NOARGS, + GR_ONE_INT, + GR_ONE_INT_TWO_STR, + GR_ONE_STR, + GR_STR_INT, + GR_TWO_INT, + GR_THREE_INT, + GR_FIVE_INT_TWO_STR, + GR_TWO_STR, + GR_THREE_STR, + GR_FOUR_STR, + GR_STR_FILENAME, + GR_FILENAME_STR, + GR_FILENAME_TWO_INT, + GR_FILENAME_TWO_INT_STR, + GR_TEXTREL, + GR_PTRACE, + GR_RESOURCE, + GR_CAP, + GR_SIG, + GR_CRASH1, + GR_CRASH2, + GR_PSACCT +}; + +#define gr_log_hidden_sysctl(audit, msg, str) gr_log_varargs(audit, msg, GR_SYSCTL_HIDDEN, str) +#define gr_log_ttysniff(audit, msg, task) gr_log_varargs(audit, msg, GR_TTYSNIFF, task) +#define gr_log_fs_rbac_generic(audit, msg, dentry, mnt) gr_log_varargs(audit, msg, GR_RBAC, dentry, mnt) +#define gr_log_fs_rbac_str(audit, msg, dentry, mnt, str) gr_log_varargs(audit, msg, GR_RBAC_STR, dentry, mnt, str) +#define gr_log_fs_str_rbac(audit, msg, str, dentry, mnt) gr_log_varargs(audit, msg, GR_STR_RBAC, str, dentry, mnt) +#define gr_log_fs_rbac_mode2(audit, msg, dentry, mnt, str1, str2) gr_log_varargs(audit, msg, GR_RBAC_MODE2, dentry, mnt, str1, str2) +#define gr_log_fs_rbac_mode3(audit, msg, dentry, mnt, str1, str2, str3) gr_log_varargs(audit, msg, GR_RBAC_MODE3, dentry, mnt, str1, str2, str3) +#define gr_log_fs_generic(audit, msg, dentry, mnt) gr_log_varargs(audit, msg, GR_FILENAME, dentry, mnt) +#define gr_log_noargs(audit, msg) gr_log_varargs(audit, msg, GR_NOARGS) +#define gr_log_int(audit, msg, num) gr_log_varargs(audit, msg, GR_ONE_INT, num) +#define gr_log_int_str2(audit, msg, num, str1, str2) gr_log_varargs(audit, msg, GR_ONE_INT_TWO_STR, num, str1, str2) +#define gr_log_str(audit, msg, str) gr_log_varargs(audit, msg, GR_ONE_STR, str) +#define gr_log_str_int(audit, msg, str, num) gr_log_varargs(audit, msg, GR_STR_INT, str, num) +#define gr_log_int_int(audit, msg, num1, num2) gr_log_varargs(audit, msg, GR_TWO_INT, num1, num2) +#define gr_log_int3(audit, msg, num1, num2, num3) gr_log_varargs(audit, msg, GR_THREE_INT, num1, num2, num3) +#define gr_log_int5_str2(audit, msg, num1, num2, str1, str2) gr_log_varargs(audit, msg, GR_FIVE_INT_TWO_STR, num1, num2, str1, str2) +#define gr_log_str_str(audit, msg, str1, str2) gr_log_varargs(audit, msg, GR_TWO_STR, str1, str2) +#define gr_log_str3(audit, msg, str1, str2, str3) gr_log_varargs(audit, msg, GR_THREE_STR, str1, str2, str3) +#define gr_log_str4(audit, msg, str1, str2, str3, str4) gr_log_varargs(audit, msg, GR_FOUR_STR, str1, str2, str3, str4) +#define gr_log_str_fs(audit, msg, str, dentry, mnt) gr_log_varargs(audit, msg, GR_STR_FILENAME, str, dentry, mnt) +#define gr_log_fs_str(audit, msg, dentry, mnt, str) gr_log_varargs(audit, msg, GR_FILENAME_STR, dentry, mnt, str) +#define gr_log_fs_int2(audit, msg, dentry, mnt, num1, num2) gr_log_varargs(audit, msg, GR_FILENAME_TWO_INT, dentry, mnt, num1, num2) +#define gr_log_fs_int2_str(audit, msg, dentry, mnt, num1, num2, str) gr_log_varargs(audit, msg, GR_FILENAME_TWO_INT_STR, dentry, mnt, num1, num2, str) +#define gr_log_textrel_ulong_ulong(audit, msg, file, ulong1, ulong2) gr_log_varargs(audit, msg, GR_TEXTREL, file, ulong1, ulong2) +#define gr_log_ptrace(audit, msg, task) gr_log_varargs(audit, msg, GR_PTRACE, task) +#define gr_log_res_ulong2_str(audit, msg, task, ulong1, str, ulong2) gr_log_varargs(audit, msg, GR_RESOURCE, task, ulong1, str, ulong2) +#define gr_log_cap(audit, msg, task, str) gr_log_varargs(audit, msg, GR_CAP, task, str) +#define gr_log_sig(audit, msg, task, num) gr_log_varargs(audit, msg, GR_SIG, task, num) +#define gr_log_crash1(audit, msg, task, ulong) gr_log_varargs(audit, msg, GR_CRASH1, task, ulong) +#define gr_log_crash2(audit, msg, task, ulong1) gr_log_varargs(audit, msg, GR_CRASH2, task, ulong1) +#define gr_log_procacct(audit, msg, task, num1, num2, num3, num4, num5, num6, num7, num8, num9) gr_log_varargs(audit, msg, GR_PSACCT, task, num1, num2, num3, num4, num5, num6, num7, num8, num9) + +void gr_log_varargs(int audit, const char *msg, int argtypes, ...); + +#endif + +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/grmsg.h linux-2.6.27.15-g-v/include/linux/grmsg.h --- linux-2.6.27.15/include/linux/grmsg.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/grmsg.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,108 @@ +#define DEFAULTSECMSG "%.256s[%.16s:%d] uid/euid:%u/%u gid/egid:%u/%u, parent %.256s[%.16s:%d] uid/euid:%u/%u gid/egid:%u/%u" +#define GR_ACL_PROCACCT_MSG "%.256s[%.16s:%d] IP:%u.%u.%u.%u TTY:%.64s uid/euid:%u/%u gid/egid:%u/%u run time:[%ud %uh %um %us] cpu time:[%ud %uh %um %us] %s with exit code %ld, parent %.256s[%.16s:%d] IP:%u.%u.%u.%u TTY:%.64s uid/euid:%u/%u gid/egid:%u/%u" +#define GR_PTRACE_ACL_MSG "denied ptrace of %.950s(%.16s:%d) by " +#define GR_STOPMOD_MSG "denied modification of module state by " +#define GR_IOPERM_MSG "denied use of ioperm() by " +#define GR_IOPL_MSG "denied use of iopl() by " +#define GR_SHMAT_ACL_MSG "denied attach of shared memory of UID %u, PID %d, ID %u by " +#define GR_UNIX_CHROOT_MSG "denied connect() to abstract AF_UNIX socket outside of chroot by " +#define GR_SHMAT_CHROOT_MSG "denied attach of shared memory outside of chroot by " +#define GR_KMEM_MSG "denied write of /dev/kmem by " +#define GR_PORT_OPEN_MSG "denied open of /dev/port by " +#define GR_MEM_WRITE_MSG "denied write of /dev/mem by " +#define GR_MEM_MMAP_MSG "denied mmap write of /dev/[k]mem by " +#define GR_SYMLINK_MSG "not following symlink %.950s owned by %d.%d by " +#define GR_LEARN_AUDIT_MSG "%s\t%u\t%u\t%u\t%.4095s\t%.4095s\t%lu\t%lu\t%.4095s\t%lu\t%u.%u.%u.%u" +#define GR_ID_LEARN_MSG "%s\t%u\t%u\t%u\t%.4095s\t%.4095s\t%c\t%d\t%d\t%d\t%u.%u.%u.%u" +#define GR_HIDDEN_ACL_MSG "%s access to hidden file %.950s by " +#define GR_OPEN_ACL_MSG "%s open of %.950s for%s%s by " +#define GR_CREATE_ACL_MSG "%s create of %.950s for%s%s by " +#define GR_FIFO_MSG "denied writing FIFO %.950s of %d.%d by " +#define GR_MKNOD_CHROOT_MSG "denied mknod of %.950s from chroot by " +#define GR_MKNOD_ACL_MSG "%s mknod of %.950s by " +#define GR_UNIXCONNECT_ACL_MSG "%s connect() to the unix domain socket %.950s by " +#define GR_TTYSNIFF_ACL_MSG "terminal being sniffed by IP:%u.%u.%u.%u %.480s[%.16s:%d], parent %.480s[%.16s:%d] against " +#define GR_MKDIR_ACL_MSG "%s mkdir of %.950s by " +#define GR_RMDIR_ACL_MSG "%s rmdir of %.950s by " +#define GR_UNLINK_ACL_MSG "%s unlink of %.950s by " +#define GR_SYMLINK_ACL_MSG "%s symlink from %.480s to %.480s by " +#define GR_HARDLINK_MSG "denied hardlink of %.930s (owned by %d.%d) to %.30s for " +#define GR_LINK_ACL_MSG "%s link of %.480s to %.480s by " +#define GR_INHERIT_ACL_MSG "successful inherit of %.480s's ACL for %.480s by " +#define GR_RENAME_ACL_MSG "%s rename of %.480s to %.480s by " +#define GR_PTRACE_EXEC_ACL_MSG "denied ptrace of %.950s by " +#define GR_NPROC_MSG "denied overstep of process limit by " +#define GR_EXEC_ACL_MSG "%s execution of %.950s by " +#define GR_EXEC_TPE_MSG "denied untrusted exec of %.950s by " +#define GR_SEGVSTART_ACL_MSG "possible exploit bruteforcing on " DEFAULTSECMSG " banning uid %u from login for %lu seconds" +#define GR_SEGVNOSUID_ACL_MSG "possible exploit bruteforcing on " DEFAULTSECMSG " banning execution for %lu seconds" +#define GR_MOUNT_CHROOT_MSG "denied mount of %.256s as %.930s from chroot by " +#define GR_PIVOT_CHROOT_MSG "denied pivot_root from chroot by " +#define GR_TRUNCATE_ACL_MSG "%s truncate of %.950s by " +#define GR_ATIME_ACL_MSG "%s access time change of %.950s by " +#define GR_ACCESS_ACL_MSG "%s access of %.950s for%s%s%s by " +#define GR_CHROOT_CHROOT_MSG "denied double chroot to %.950s by " +#define GR_FCHMOD_ACL_MSG "%s fchmod of %.950s by " +#define GR_CHMOD_CHROOT_MSG "denied chmod +s of %.950s by " +#define GR_CHMOD_ACL_MSG "%s chmod of %.950s by " +#define GR_CHROOT_FCHDIR_MSG "denied fchdir outside of chroot to %.950s by " +#define GR_CHOWN_ACL_MSG "%s chown of %.950s by " +#define GR_WRITLIB_ACL_MSG "denied load of writable library %.950s by " +#define GR_INITF_ACL_MSG "init_variables() failed %s by " +#define GR_DISABLED_ACL_MSG "Error loading %s, trying to run kernel with acls disabled. To disable acls at startup use gracl=off from your boot loader" +#define GR_DEV_ACL_MSG "/dev/grsec: %d bytes sent %d required, being fed garbaged by " +#define GR_SHUTS_ACL_MSG "shutdown auth success for " +#define GR_SHUTF_ACL_MSG "shutdown auth failure for " +#define GR_SHUTI_ACL_MSG "ignoring shutdown for disabled RBAC system for " +#define GR_SEGVMODS_ACL_MSG "segvmod auth success for " +#define GR_SEGVMODF_ACL_MSG "segvmod auth failure for " +#define GR_SEGVMODI_ACL_MSG "ignoring segvmod for disabled RBAC system for " +#define GR_ENABLE_ACL_MSG "%s RBAC system loaded by " +#define GR_ENABLEF_ACL_MSG "unable to load %s for " +#define GR_RELOADI_ACL_MSG "ignoring reload request for disabled RBAC system" +#define GR_RELOAD_ACL_MSG "%s RBAC system reloaded by " +#define GR_RELOADF_ACL_MSG "failed reload of %s for " +#define GR_SPROLEI_ACL_MSG "ignoring change to special role for disabled RBAC system for " +#define GR_SPROLES_ACL_MSG "successful change to special role %s (id %d) by " +#define GR_SPROLEL_ACL_MSG "special role %s (id %d) exited by " +#define GR_SPROLEF_ACL_MSG "special role %s failure for " +#define GR_UNSPROLEI_ACL_MSG "ignoring unauth of special role for disabled RBAC system for " +#define GR_UNSPROLES_ACL_MSG "successful unauth of special role %s (id %d) by " +#define GR_UNSPROLEF_ACL_MSG "special role unauth of %s failure for " +#define GR_INVMODE_ACL_MSG "invalid mode %d by " +#define GR_PRIORITY_CHROOT_MSG "denied priority change of process (%.16s:%d) by " +#define GR_FAILFORK_MSG "failed fork with errno %d by " +#define GR_NICE_CHROOT_MSG "denied priority change by " +#define GR_UNISIGLOG_MSG "signal %d sent to " +#define GR_DUALSIGLOG_MSG "signal %d sent to " DEFAULTSECMSG " by " +#define GR_SIG_ACL_MSG "denied send of signal %d to protected task " DEFAULTSECMSG " by " +#define GR_SYSCTL_MSG "denied modification of grsecurity sysctl value : %.32s by " +#define GR_SYSCTL_ACL_MSG "%s sysctl of %.950s for%s%s by " +#define GR_TIME_MSG "time set by " +#define GR_DEFACL_MSG "fatal: unable to find subject for (%.16s:%d), loaded by " +#define GR_MMAP_ACL_MSG "%s executable mmap of %.950s by " +#define GR_MPROTECT_ACL_MSG "%s executable mprotect of %.950s by " +#define GR_SOCK_MSG "denied socket(%.16s,%.16s,%.16s) by " +#define GR_SOCK2_MSG "denied socket(%d,%.16s,%.16s) by " +#define GR_BIND_MSG "denied bind() by " +#define GR_CONNECT_MSG "denied connect() by " +#define GR_BIND_ACL_MSG "denied bind() to %u.%u.%u.%u port %u sock type %.16s protocol %.16s by " +#define GR_CONNECT_ACL_MSG "denied connect() to %u.%u.%u.%u port %u sock type %.16s protocol %.16s by " +#define GR_IP_LEARN_MSG "%s\t%u\t%u\t%u\t%.4095s\t%.4095s\t%u.%u.%u.%u\t%u\t%u\t%u\t%u\t%u.%u.%u.%u" +#define GR_EXEC_CHROOT_MSG "exec of %.980s within chroot by process " +#define GR_CAP_ACL_MSG "use of %s denied for " +#define GR_USRCHANGE_ACL_MSG "change to uid %u denied for " +#define GR_GRPCHANGE_ACL_MSG "change to gid %u denied for " +#define GR_REMOUNT_AUDIT_MSG "remount of %.256s by " +#define GR_UNMOUNT_AUDIT_MSG "unmount of %.256s by " +#define GR_MOUNT_AUDIT_MSG "mount of %.256s to %.256s by " +#define GR_CHDIR_AUDIT_MSG "chdir to %.980s by " +#define GR_EXEC_AUDIT_MSG "exec of %.930s (%.128s) by " +#define GR_MSGQ_AUDIT_MSG "message queue created by " +#define GR_MSGQR_AUDIT_MSG "message queue of uid:%u euid:%u removed by " +#define GR_SEM_AUDIT_MSG "semaphore created by " +#define GR_SEMR_AUDIT_MSG "semaphore of uid:%u euid:%u removed by " +#define GR_SHM_AUDIT_MSG "shared memory of size %d created by " +#define GR_SHMR_AUDIT_MSG "shared memory of uid:%u euid:%u removed by " +#define GR_RESOURCE_MSG "denied resource overstep by requesting %lu for %.16s against limit %lu for " +#define GR_TEXTREL_AUDIT_MSG "text relocation in %s, VMA:0x%08lx 0x%08lx by " diff -NurpP --minimal linux-2.6.27.15/include/linux/grsecurity.h linux-2.6.27.15-g-v/include/linux/grsecurity.h --- linux-2.6.27.15/include/linux/grsecurity.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/grsecurity.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,200 @@ +#ifndef GR_SECURITY_H +#define GR_SECURITY_H +#include +#include +#include + +/* notify of brain-dead configs */ +#if defined(CONFIG_PAX_NOEXEC) && !defined(CONFIG_PAX_PAGEEXEC) && !defined(CONFIG_PAX_SEGMEXEC) && !defined(CONFIG_PAX_KERNEXEC) +#error "CONFIG_PAX_NOEXEC enabled, but PAGEEXEC, SEGMEXEC, and KERNEXEC are disabled." +#endif +#if defined(CONFIG_PAX_NOEXEC) && !defined(CONFIG_PAX_EI_PAX) && !defined(CONFIG_PAX_PT_PAX_FLAGS) +#error "CONFIG_PAX_NOEXEC enabled, but neither CONFIG_PAX_EI_PAX nor CONFIG_PAX_PT_PAX_FLAGS are enabled." +#endif +#if defined(CONFIG_PAX_ASLR) && (defined(CONFIG_PAX_RANDMMAP) || defined(CONFIG_PAX_RANDUSTACK)) && !defined(CONFIG_PAX_EI_PAX) && !defined(CONFIG_PAX_PT_PAX_FLAGS) +#error "CONFIG_PAX_ASLR enabled, but neither CONFIG_PAX_EI_PAX nor CONFIG_PAX_PT_PAX_FLAGS are enabled." +#endif +#if defined(CONFIG_PAX_ASLR) && !defined(CONFIG_PAX_RANDKSTACK) && !defined(CONFIG_PAX_RANDUSTACK) && !defined(CONFIG_PAX_RANDMMAP) +#error "CONFIG_PAX_ASLR enabled, but RANDKSTACK, RANDUSTACK, and RANDMMAP are disabled." +#endif +#if defined(CONFIG_PAX) && !defined(CONFIG_PAX_NOEXEC) && !defined(CONFIG_PAX_ASLR) +#error "CONFIG_PAX enabled, but no PaX options are enabled." +#endif + +void gr_handle_brute_attach(struct task_struct *p); +void gr_handle_brute_check(void); + +char gr_roletype_to_char(void); + +int gr_check_user_change(int real, int effective, int fs); +int gr_check_group_change(int real, int effective, int fs); + +void gr_del_task_from_ip_table(struct task_struct *p); + +int gr_pid_is_chrooted(struct task_struct *p); +int gr_handle_chroot_nice(void); +int gr_handle_chroot_sysctl(const int op); +int gr_handle_chroot_setpriority(struct task_struct *p, + const int niceval); +int gr_chroot_fchdir(struct dentry *u_dentry, struct vfsmount *u_mnt); +int gr_handle_chroot_chroot(const struct dentry *dentry, + const struct vfsmount *mnt); +void gr_handle_chroot_caps(struct task_struct *task); +void gr_handle_chroot_chdir(struct path *path); +int gr_handle_chroot_chmod(const struct dentry *dentry, + const struct vfsmount *mnt, const int mode); +int gr_handle_chroot_mknod(const struct dentry *dentry, + const struct vfsmount *mnt, const int mode); +int gr_handle_chroot_mount(const struct dentry *dentry, + const struct vfsmount *mnt, + const char *dev_name); +int gr_handle_chroot_pivot(void); +int gr_handle_chroot_unix(const pid_t pid); + +int gr_handle_rawio(const struct inode *inode); +int gr_handle_nproc(void); + +void gr_handle_ioperm(void); +void gr_handle_iopl(void); + +int gr_tpe_allow(const struct file *file); + +int gr_random_pid(void); + +void gr_log_forkfail(const int retval); +void gr_log_timechange(void); +void gr_log_signal(const int sig, const struct task_struct *t); +void gr_log_chdir(const struct dentry *dentry, + const struct vfsmount *mnt); +void gr_log_chroot_exec(const struct dentry *dentry, + const struct vfsmount *mnt); +void gr_handle_exec_args(struct linux_binprm *bprm, char **argv); +void gr_log_remount(const char *devname, const int retval); +void gr_log_unmount(const char *devname, const int retval); +void gr_log_mount(const char *from, const char *to, const int retval); +void gr_log_msgget(const int ret, const int msgflg); +void gr_log_msgrm(const uid_t uid, const uid_t cuid); +void gr_log_semget(const int err, const int semflg); +void gr_log_semrm(const uid_t uid, const uid_t cuid); +void gr_log_shmget(const int err, const int shmflg, const size_t size); +void gr_log_shmrm(const uid_t uid, const uid_t cuid); +void gr_log_textrel(struct vm_area_struct *vma); + +int gr_handle_follow_link(const struct inode *parent, + const struct inode *inode, + const struct dentry *dentry, + const struct vfsmount *mnt); +int gr_handle_fifo(const struct dentry *dentry, + const struct vfsmount *mnt, + const struct dentry *dir, const int flag, + const int acc_mode); +int gr_handle_hardlink(const struct dentry *dentry, + const struct vfsmount *mnt, + struct inode *inode, + const int mode, const char *to); + +int gr_task_is_capable(struct task_struct *task, const int cap); +int gr_is_capable_nolog(const int cap); +void gr_learn_resource(const struct task_struct *task, const int limit, + const unsigned long wanted, const int gt); +void gr_copy_label(struct task_struct *tsk); +void gr_handle_crash(struct task_struct *task, const int sig); +int gr_handle_signal(const struct task_struct *p, const int sig); +int gr_check_crash_uid(const uid_t uid); +int gr_check_protected_task(const struct task_struct *task); +int gr_acl_handle_mmap(const struct file *file, + const unsigned long prot); +int gr_acl_handle_mprotect(const struct file *file, + const unsigned long prot); +int gr_check_hidden_task(const struct task_struct *tsk); +__u32 gr_acl_handle_truncate(const struct dentry *dentry, + const struct vfsmount *mnt); +__u32 gr_acl_handle_utime(const struct dentry *dentry, + const struct vfsmount *mnt); +__u32 gr_acl_handle_access(const struct dentry *dentry, + const struct vfsmount *mnt, const int fmode); +__u32 gr_acl_handle_fchmod(const struct dentry *dentry, + const struct vfsmount *mnt, mode_t mode); +__u32 gr_acl_handle_chmod(const struct dentry *dentry, + const struct vfsmount *mnt, mode_t mode); +__u32 gr_acl_handle_chown(const struct dentry *dentry, + const struct vfsmount *mnt); +int gr_handle_ptrace(struct task_struct *task, const long request); +int gr_handle_proc_ptrace(struct task_struct *task); +__u32 gr_acl_handle_execve(const struct dentry *dentry, + const struct vfsmount *mnt); +int gr_check_crash_exec(const struct file *filp); +int gr_acl_is_enabled(void); +void gr_set_kernel_label(struct task_struct *task); +void gr_set_role_label(struct task_struct *task, const uid_t uid, + const gid_t gid); +int gr_set_proc_label(const struct dentry *dentry, + const struct vfsmount *mnt); +__u32 gr_acl_handle_hidden_file(const struct dentry *dentry, + const struct vfsmount *mnt); +__u32 gr_acl_handle_open(const struct dentry *dentry, + const struct vfsmount *mnt, const int fmode); +__u32 gr_acl_handle_creat(const struct dentry *dentry, + const struct dentry *p_dentry, + const struct vfsmount *p_mnt, const int fmode, + const int imode); +void gr_handle_create(const struct dentry *dentry, + const struct vfsmount *mnt); +__u32 gr_acl_handle_mknod(const struct dentry *new_dentry, + const struct dentry *parent_dentry, + const struct vfsmount *parent_mnt, + const int mode); +__u32 gr_acl_handle_mkdir(const struct dentry *new_dentry, + const struct dentry *parent_dentry, + const struct vfsmount *parent_mnt); +__u32 gr_acl_handle_rmdir(const struct dentry *dentry, + const struct vfsmount *mnt); +void gr_handle_delete(const ino_t ino, const dev_t dev); +__u32 gr_acl_handle_unlink(const struct dentry *dentry, + const struct vfsmount *mnt); +__u32 gr_acl_handle_symlink(const struct dentry *new_dentry, + const struct dentry *parent_dentry, + const struct vfsmount *parent_mnt, + const char *from); +__u32 gr_acl_handle_link(const struct dentry *new_dentry, + const struct dentry *parent_dentry, + const struct vfsmount *parent_mnt, + const struct dentry *old_dentry, + const struct vfsmount *old_mnt, const char *to); +int gr_acl_handle_rename(struct dentry *new_dentry, + struct dentry *parent_dentry, + const struct vfsmount *parent_mnt, + struct dentry *old_dentry, + struct inode *old_parent_inode, + struct vfsmount *old_mnt, const char *newname); +void gr_handle_rename(struct inode *old_dir, struct inode *new_dir, + struct dentry *old_dentry, + struct dentry *new_dentry, + struct vfsmount *mnt, const __u8 replace); +__u32 gr_check_link(const struct dentry *new_dentry, + const struct dentry *parent_dentry, + const struct vfsmount *parent_mnt, + const struct dentry *old_dentry, + const struct vfsmount *old_mnt); +int gr_acl_handle_filldir(const struct file *file, const char *name, + const unsigned int namelen, const ino_t ino); + +__u32 gr_acl_handle_unix(const struct dentry *dentry, + const struct vfsmount *mnt); +void gr_acl_handle_exit(void); +void gr_acl_handle_psacct(struct task_struct *task, const long code); +int gr_acl_handle_procpidmem(const struct task_struct *task); + +#ifdef CONFIG_GRKERNSEC +void gr_handle_mem_write(void); +void gr_handle_kmem_write(void); +void gr_handle_open_port(void); +int gr_handle_mem_mmap(const unsigned long offset, + struct vm_area_struct *vma); + +extern int grsec_enable_dmesg; +extern int grsec_enable_randsrc; +extern int grsec_enable_shm; +#endif + +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/highmem.h linux-2.6.27.15-g-v/include/linux/highmem.h --- linux-2.6.27.15/include/linux/highmem.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/highmem.h 2009-02-10 20:32:15.000000000 +0100 @@ -122,6 +122,13 @@ static inline void clear_highpage(struct kunmap_atomic(kaddr, KM_USER0); } +static inline void sanitize_highpage(struct page *page) +{ + void *kaddr = kmap_atomic(page, KM_CLEARPAGE); + clear_page(kaddr); + kunmap_atomic(kaddr, KM_CLEARPAGE); +} + static inline void zero_user_segments(struct page *page, unsigned start1, unsigned end1, unsigned start2, unsigned end2) diff -NurpP --minimal linux-2.6.27.15/include/linux/if_tun.h linux-2.6.27.15-g-v/include/linux/if_tun.h --- linux-2.6.27.15/include/linux/if_tun.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/if_tun.h 2009-02-10 20:32:15.000000000 +0100 @@ -46,6 +46,7 @@ #define TUNSETOFFLOAD _IOW('T', 208, unsigned int) #define TUNSETTXFILTER _IOW('T', 209, unsigned int) #define TUNGETIFF _IOR('T', 210, unsigned int) +#define TUNSETNID _IOW('T', 215, int) /* TUNSETIFF ifr flags */ #define IFF_TUN 0x0001 diff -NurpP --minimal linux-2.6.27.15/include/linux/init_task.h linux-2.6.27.15-g-v/include/linux/init_task.h --- linux-2.6.27.15/include/linux/init_task.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/init_task.h 2009-02-10 20:32:15.000000000 +0100 @@ -179,6 +179,10 @@ extern struct group_info init_groups; INIT_IDS \ INIT_TRACE_IRQFLAGS \ INIT_LOCKDEP \ + .xid = 0, \ + .vx_info = NULL, \ + .nid = 0, \ + .nx_info = NULL, \ } diff -NurpP --minimal linux-2.6.27.15/include/linux/interrupt.h linux-2.6.27.15-g-v/include/linux/interrupt.h --- linux-2.6.27.15/include/linux/interrupt.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/interrupt.h 2009-02-10 20:32:15.000000000 +0100 @@ -8,8 +8,8 @@ #include #include #include -#include #include +#include #include #include #include diff -NurpP --minimal linux-2.6.27.15/include/linux/ipc.h linux-2.6.27.15-g-v/include/linux/ipc.h --- linux-2.6.27.15/include/linux/ipc.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/ipc.h 2009-02-10 20:32:15.000000000 +0100 @@ -93,6 +93,7 @@ struct kern_ipc_perm key_t key; uid_t uid; gid_t gid; + xid_t xid; uid_t cuid; gid_t cgid; mode_t mode; diff -NurpP --minimal linux-2.6.27.15/include/linux/jbd2.h linux-2.6.27.15-g-v/include/linux/jbd2.h --- linux-2.6.27.15/include/linux/jbd2.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/jbd2.h 2009-02-10 20:32:15.000000000 +0100 @@ -66,7 +66,7 @@ extern u8 jbd2_journal_enable_debug; } \ } while (0) #else -#define jbd_debug(f, a...) /**/ +#define jbd_debug(f, a...) do {} while (0) #endif static inline void *jbd2_alloc(size_t size, gfp_t flags) diff -NurpP --minimal linux-2.6.27.15/include/linux/jbd.h linux-2.6.27.15-g-v/include/linux/jbd.h --- linux-2.6.27.15/include/linux/jbd.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/jbd.h 2009-02-10 20:32:15.000000000 +0100 @@ -66,7 +66,7 @@ extern u8 journal_enable_debug; } \ } while (0) #else -#define jbd_debug(f, a...) /**/ +#define jbd_debug(f, a...) do {} while (0) #endif static inline void *jbd_alloc(size_t size, gfp_t flags) diff -NurpP --minimal linux-2.6.27.15/include/linux/Kbuild linux-2.6.27.15-g-v/include/linux/Kbuild --- linux-2.6.27.15/include/linux/Kbuild 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/Kbuild 2009-02-10 20:32:15.000000000 +0100 @@ -370,3 +370,6 @@ unifdef-y += xattr.h unifdef-y += xfrm.h objhdr-y += version.h + +header-y += vserver/ + diff -NurpP --minimal linux-2.6.27.15/include/linux/libata.h linux-2.6.27.15-g-v/include/linux/libata.h --- linux-2.6.27.15/include/linux/libata.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/libata.h 2009-02-10 20:32:15.000000000 +0100 @@ -64,11 +64,11 @@ #ifdef ATA_VERBOSE_DEBUG #define VPRINTK(fmt, args...) printk(KERN_ERR "%s: " fmt, __func__, ## args) #else -#define VPRINTK(fmt, args...) +#define VPRINTK(fmt, args...) do {} while (0) #endif /* ATA_VERBOSE_DEBUG */ #else -#define DPRINTK(fmt, args...) -#define VPRINTK(fmt, args...) +#define DPRINTK(fmt, args...) do {} while (0) +#define VPRINTK(fmt, args...) do {} while (0) #endif /* ATA_DEBUG */ #define BPRINTK(fmt, args...) if (ap->flags & ATA_FLAG_DEBUGMSG) printk(KERN_ERR "%s: " fmt, __func__, ## args) diff -NurpP --minimal linux-2.6.27.15/include/linux/loop.h linux-2.6.27.15-g-v/include/linux/loop.h --- linux-2.6.27.15/include/linux/loop.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/loop.h 2009-02-10 20:32:15.000000000 +0100 @@ -45,6 +45,7 @@ struct loop_device { struct loop_func_table *lo_encryption; __u32 lo_init[2]; uid_t lo_key_owner; /* Who set the key */ + xid_t lo_xid; int (*ioctl)(struct loop_device *, int cmd, unsigned long arg); diff -NurpP --minimal linux-2.6.27.15/include/linux/magic.h linux-2.6.27.15-g-v/include/linux/magic.h --- linux-2.6.27.15/include/linux/magic.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/magic.h 2009-02-10 20:32:15.000000000 +0100 @@ -3,7 +3,7 @@ #define ADFS_SUPER_MAGIC 0xadf5 #define AFFS_SUPER_MAGIC 0xadff -#define AFS_SUPER_MAGIC 0x5346414F +#define AFS_SUPER_MAGIC 0x5346414F #define AUTOFS_SUPER_MAGIC 0x0187 #define CODA_SUPER_MAGIC 0x73757245 #define EFS_SUPER_MAGIC 0x414A53 @@ -26,6 +26,7 @@ #define NFS_SUPER_MAGIC 0x6969 #define OPENPROM_SUPER_MAGIC 0x9fa1 #define PROC_SUPER_MAGIC 0x9fa0 +#define DEVPTS_SUPER_MAGIC 0x1cd1 #define QNX4_SUPER_MAGIC 0x002f /* qnx4 fs detection */ #define REISERFS_SUPER_MAGIC 0x52654973 /* used by gcc */ diff -NurpP --minimal linux-2.6.27.15/include/linux/major.h linux-2.6.27.15-g-v/include/linux/major.h --- linux-2.6.27.15/include/linux/major.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/major.h 2009-02-10 20:32:15.000000000 +0100 @@ -15,6 +15,7 @@ #define HD_MAJOR IDE0_MAJOR #define PTY_SLAVE_MAJOR 3 #define TTY_MAJOR 4 +#define VROOT_MAJOR 4 #define TTYAUX_MAJOR 5 #define LP_MAJOR 6 #define VCS_MAJOR 7 diff -NurpP --minimal linux-2.6.27.15/include/linux/mm.h linux-2.6.27.15-g-v/include/linux/mm.h --- linux-2.6.27.15/include/linux/mm.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/mm.h 2009-02-10 20:32:15.000000000 +0100 @@ -38,6 +38,7 @@ extern unsigned long mmap_min_addr; #include #include #include +#include #define nth_page(page,n) pfn_to_page(page_to_pfn((page)) + (n)) @@ -114,6 +115,10 @@ extern unsigned int kobjsize(const void #define VM_MIXEDMAP 0x10000000 /* Can contain "struct page" and pure PFN pages */ #define VM_SAO 0x20000000 /* Strong Access Ordering (powerpc) */ +#ifdef CONFIG_PAX_PAGEEXEC +#define VM_PAGEEXEC 0x40000000 /* vma->vm_page_prot needs special handling */ +#endif + #ifndef VM_STACK_DEFAULT_FLAGS /* arch can override this */ #define VM_STACK_DEFAULT_FLAGS VM_DATA_DEFAULT_FLAGS #endif @@ -873,6 +878,8 @@ struct shrinker { extern void register_shrinker(struct shrinker *); extern void unregister_shrinker(struct shrinker *); +pgprot_t vm_get_page_prot(unsigned long vm_flags); + int vma_wants_writenotify(struct vm_area_struct *vma); extern pte_t *get_locked_pte(struct mm_struct *mm, unsigned long addr, spinlock_t **ptl); @@ -1128,6 +1135,7 @@ out: } extern int do_munmap(struct mm_struct *, unsigned long, size_t); +extern int __do_munmap(struct mm_struct *, unsigned long, size_t); extern unsigned long do_brk(unsigned long, unsigned long); @@ -1180,6 +1188,10 @@ extern struct vm_area_struct * find_vma( extern struct vm_area_struct * find_vma_prev(struct mm_struct * mm, unsigned long addr, struct vm_area_struct **pprev); +extern struct vm_area_struct *pax_find_mirror_vma(struct vm_area_struct *vma); +extern void pax_mirror_vma(struct vm_area_struct *vma_m, struct vm_area_struct *vma); +extern void pax_mirror_file_pte(struct vm_area_struct *vma, unsigned long address, struct page *page_m, spinlock_t *ptl); + /* Look up the first VMA which intersects the interval start_addr..end_addr-1, NULL if none. Assume start_addr < end_addr. */ static inline struct vm_area_struct * find_vma_intersection(struct mm_struct * mm, unsigned long start_addr, unsigned long end_addr) @@ -1196,7 +1208,6 @@ static inline unsigned long vma_pages(st return (vma->vm_end - vma->vm_start) >> PAGE_SHIFT; } -pgprot_t vm_get_page_prot(unsigned long vm_flags); struct vm_area_struct *find_extend_vma(struct mm_struct *, unsigned long addr); int remap_pfn_range(struct vm_area_struct *, unsigned long addr, unsigned long pfn, unsigned long size, pgprot_t); @@ -1285,5 +1296,11 @@ int vmemmap_populate_basepages(struct pa int vmemmap_populate(struct page *start_page, unsigned long pages, int node); void vmemmap_populate_print_last(void); +#ifdef CONFIG_ARCH_TRACK_EXEC_LIMIT +extern void track_exec_limit(struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long prot); +#else +static inline void track_exec_limit(struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long prot) {} +#endif + #endif /* __KERNEL__ */ #endif /* _LINUX_MM_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/mm_types.h linux-2.6.27.15-g-v/include/linux/mm_types.h --- linux-2.6.27.15/include/linux/mm_types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/mm_types.h 2009-02-10 20:32:15.000000000 +0100 @@ -158,6 +158,8 @@ struct vm_area_struct { #ifdef CONFIG_NUMA struct mempolicy *vm_policy; /* NUMA policy for the VMA */ #endif + + struct vm_area_struct *vm_mirror;/* PaX: mirror vma or NULL */ }; struct core_thread { @@ -216,6 +218,7 @@ struct mm_struct { /* Architecture-specific MM context */ mm_context_t context; + struct vx_info *mm_vx_info; /* Swap token stuff */ /* @@ -257,6 +260,24 @@ struct mm_struct { #ifdef CONFIG_MMU_NOTIFIER struct mmu_notifier_mm *mmu_notifier_mm; #endif + +#if defined(CONFIG_PAX_EI_PAX) || defined(CONFIG_PAX_PT_PAX_FLAGS) || defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) + unsigned long pax_flags; +#endif + +#ifdef CONFIG_PAX_DLRESOLVE + unsigned long call_dl_resolve; +#endif + +#if defined(CONFIG_PPC32) && defined(CONFIG_PAX_EMUSIGRT) + unsigned long call_syscall; +#endif + +#ifdef CONFIG_PAX_ASLR + unsigned long delta_mmap; /* randomized offset */ + unsigned long delta_stack; /* randomized offset */ +#endif + }; #endif /* _LINUX_MM_TYPES_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/module.h linux-2.6.27.15-g-v/include/linux/module.h --- linux-2.6.27.15/include/linux/module.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/module.h 2009-02-10 20:32:15.000000000 +0100 @@ -282,16 +282,16 @@ struct module int (*init)(void); /* If this is non-NULL, vfree after init() returns */ - void *module_init; + void *module_init_rx, *module_init_rw; /* Here is the actual code + data, vfree'd on unload. */ - void *module_core; + void *module_core_rx, *module_core_rw; /* Here are the sizes of the init and core sections */ - unsigned int init_size, core_size; + unsigned int init_size_rw, core_size_rw; /* The size of the executable code in each section. */ - unsigned int init_text_size, core_text_size; + unsigned int init_size_rx, core_size_rx; /* The handle returned from unwind_add_table. */ void *unwind_info; diff -NurpP --minimal linux-2.6.27.15/include/linux/moduleloader.h linux-2.6.27.15-g-v/include/linux/moduleloader.h --- linux-2.6.27.15/include/linux/moduleloader.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/moduleloader.h 2009-02-10 20:32:15.000000000 +0100 @@ -17,9 +17,21 @@ int module_frob_arch_sections(Elf_Ehdr * sections. Returns NULL on failure. */ void *module_alloc(unsigned long size); +#ifdef CONFIG_PAX_KERNEXEC +void *module_alloc_exec(unsigned long size); +#else +#define module_alloc_exec(x) module_alloc(x) +#endif + /* Free memory returned from module_alloc. */ void module_free(struct module *mod, void *module_region); +#ifdef CONFIG_PAX_KERNEXEC +void module_free_exec(struct module *mod, void *module_region); +#else +#define module_free_exec(x, y) module_free(x, y) +#endif + /* Apply the given relocation to the (simplified) ELF. Return -error or 0. */ int apply_relocate(Elf_Shdr *sechdrs, diff -NurpP --minimal linux-2.6.27.15/include/linux/mount.h linux-2.6.27.15-g-v/include/linux/mount.h --- linux-2.6.27.15/include/linux/mount.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/mount.h 2009-02-10 20:32:15.000000000 +0100 @@ -37,6 +37,9 @@ struct mnt_namespace; #define MNT_UNBINDABLE 0x2000 /* if the vfsmount is a unbindable mount */ #define MNT_PNODE_MASK 0x3000 /* propagation flag mask */ +#define MNT_TAGID 0x10000 +#define MNT_NOTAG 0x20000 + struct vfsmount { struct list_head mnt_hash; struct vfsmount *mnt_parent; /* fs we are mounted on */ @@ -71,6 +74,7 @@ struct vfsmount { * are held, and all mnt_writer[]s on this mount have 0 as their ->count */ atomic_t __mnt_writers; + tag_t mnt_tag; /* tagging used for vfsmount */ }; static inline struct vfsmount *mntget(struct vfsmount *mnt) diff -NurpP --minimal linux-2.6.27.15/include/linux/namei.h linux-2.6.27.15-g-v/include/linux/namei.h --- linux-2.6.27.15/include/linux/namei.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/namei.h 2009-02-10 20:32:15.000000000 +0100 @@ -21,7 +21,7 @@ struct nameidata { unsigned int flags; int last_type; unsigned depth; - char *saved_names[MAX_NESTED_LINKS + 1]; + const char *saved_names[MAX_NESTED_LINKS + 1]; /* Intent data */ union { @@ -80,12 +80,12 @@ extern int follow_up(struct vfsmount **, extern struct dentry *lock_rename(struct dentry *, struct dentry *); extern void unlock_rename(struct dentry *, struct dentry *); -static inline void nd_set_link(struct nameidata *nd, char *path) +static inline void nd_set_link(struct nameidata *nd, const char *path) { nd->saved_names[nd->depth] = path; } -static inline char *nd_get_link(struct nameidata *nd) +static inline const char *nd_get_link(struct nameidata *nd) { return nd->saved_names[nd->depth]; } diff -NurpP --minimal linux-2.6.27.15/include/linux/net.h linux-2.6.27.15-g-v/include/linux/net.h --- linux-2.6.27.15/include/linux/net.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/net.h 2009-02-10 20:32:15.000000000 +0100 @@ -68,6 +68,7 @@ struct net; #define SOCK_NOSPACE 2 #define SOCK_PASSCRED 3 #define SOCK_PASSSEC 4 +#define SOCK_USER_SOCKET 5 #ifndef ARCH_HAS_SOCKET_TYPES /** diff -NurpP --minimal linux-2.6.27.15/include/linux/nfs_mount.h linux-2.6.27.15-g-v/include/linux/nfs_mount.h --- linux-2.6.27.15/include/linux/nfs_mount.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/nfs_mount.h 2009-02-10 20:32:15.000000000 +0100 @@ -63,6 +63,7 @@ struct nfs_mount_data { #define NFS_MOUNT_SECFLAVOUR 0x2000 /* 5 */ #define NFS_MOUNT_NORDIRPLUS 0x4000 /* 5 */ #define NFS_MOUNT_UNSHARED 0x8000 /* 5 */ -#define NFS_MOUNT_FLAGMASK 0xFFFF +#define NFS_MOUNT_TAGGED 0x10000 /* context tagging */ +#define NFS_MOUNT_FLAGMASK 0x1FFFF #endif diff -NurpP --minimal linux-2.6.27.15/include/linux/nodemask.h linux-2.6.27.15-g-v/include/linux/nodemask.h --- linux-2.6.27.15/include/linux/nodemask.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/nodemask.h 2009-02-10 20:32:15.000000000 +0100 @@ -442,11 +442,11 @@ static inline int num_node_state(enum no #define any_online_node(mask) \ ({ \ - int node; \ - for_each_node_mask(node, (mask)) \ - if (node_online(node)) \ + int __node; \ + for_each_node_mask(__node, (mask)) \ + if (node_online(__node)) \ break; \ - node; \ + __node; \ }) #define num_online_nodes() num_node_state(N_ONLINE) diff -NurpP --minimal linux-2.6.27.15/include/linux/nsproxy.h linux-2.6.27.15-g-v/include/linux/nsproxy.h --- linux-2.6.27.15/include/linux/nsproxy.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/nsproxy.h 2009-02-10 20:32:15.000000000 +0100 @@ -3,6 +3,7 @@ #include #include +#include struct mnt_namespace; struct uts_namespace; @@ -63,22 +64,33 @@ static inline struct nsproxy *task_nspro } int copy_namespaces(unsigned long flags, struct task_struct *tsk); +struct nsproxy *copy_nsproxy(struct nsproxy *orig); void exit_task_namespaces(struct task_struct *tsk); void switch_task_namespaces(struct task_struct *tsk, struct nsproxy *new); void free_nsproxy(struct nsproxy *ns); int unshare_nsproxy_namespaces(unsigned long, struct nsproxy **, struct fs_struct *); -static inline void put_nsproxy(struct nsproxy *ns) +#define get_nsproxy(n) __get_nsproxy(n, __FILE__, __LINE__) + +static inline void __get_nsproxy(struct nsproxy *ns, + const char *_file, int _line) { - if (atomic_dec_and_test(&ns->count)) { - free_nsproxy(ns); - } + vxlprintk(VXD_CBIT(space, 0), "get_nsproxy(%p[%u])", + ns, atomic_read(&ns->count), _file, _line); + atomic_inc(&ns->count); } -static inline void get_nsproxy(struct nsproxy *ns) +#define put_nsproxy(n) __put_nsproxy(n, __FILE__, __LINE__) + +static inline void __put_nsproxy(struct nsproxy *ns, + const char *_file, int _line) { - atomic_inc(&ns->count); + vxlprintk(VXD_CBIT(space, 0), "put_nsproxy(%p[%u])", + ns, atomic_read(&ns->count), _file, _line); + if (atomic_dec_and_test(&ns->count)) { + free_nsproxy(ns); + } } #ifdef CONFIG_CGROUP_NS diff -NurpP --minimal linux-2.6.27.15/include/linux/percpu.h linux-2.6.27.15-g-v/include/linux/percpu.h --- linux-2.6.27.15/include/linux/percpu.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/percpu.h 2009-02-10 20:32:15.000000000 +0100 @@ -43,7 +43,7 @@ #endif #define PERCPU_ENOUGH_ROOM \ - (__per_cpu_end - __per_cpu_start + PERCPU_MODULE_RESERVE) + ((unsigned long)(__per_cpu_end - __per_cpu_start + PERCPU_MODULE_RESERVE)) #endif /* PERCPU_ENOUGH_ROOM */ /* diff -NurpP --minimal linux-2.6.27.15/include/linux/pid.h linux-2.6.27.15-g-v/include/linux/pid.h --- linux-2.6.27.15/include/linux/pid.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/pid.h 2009-02-10 20:32:15.000000000 +0100 @@ -8,7 +8,8 @@ enum pid_type PIDTYPE_PID, PIDTYPE_PGID, PIDTYPE_SID, - PIDTYPE_MAX + PIDTYPE_MAX, + PIDTYPE_REALPID }; /* @@ -142,6 +143,7 @@ static inline pid_t pid_nr(struct pid *p } pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns); +pid_t pid_unmapped_nr_ns(struct pid *pid, struct pid_namespace *ns); pid_t pid_vnr(struct pid *pid); #define do_each_pid_task(pid, type, task) \ diff -NurpP --minimal linux-2.6.27.15/include/linux/poison.h linux-2.6.27.15-g-v/include/linux/poison.h --- linux-2.6.27.15/include/linux/poison.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/poison.h 2009-02-10 20:32:15.000000000 +0100 @@ -7,8 +7,8 @@ * under normal circumstances, used to verify that nobody uses * non-initialized list entries. */ -#define LIST_POISON1 ((void *) 0x00100100) -#define LIST_POISON2 ((void *) 0x00200200) +#define LIST_POISON1 ((void *) 0xFF1001FFFF1001FFULL) +#define LIST_POISON2 ((void *) 0xFF2002FFFF2002FFULL) /********** include/linux/timer.h **********/ /* diff -NurpP --minimal linux-2.6.27.15/include/linux/proc_fs.h linux-2.6.27.15-g-v/include/linux/proc_fs.h --- linux-2.6.27.15/include/linux/proc_fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/proc_fs.h 2009-02-10 20:32:15.000000000 +0100 @@ -59,6 +59,7 @@ struct proc_dir_entry { nlink_t nlink; uid_t uid; gid_t gid; + int vx_flags; loff_t size; const struct inode_operations *proc_iops; /* @@ -274,12 +275,18 @@ static inline void kclist_add(struct kco extern void kclist_add(struct kcore_list *, void *, size_t); #endif +struct vx_info; +struct nx_info; + union proc_op { int (*proc_get_link)(struct inode *, struct path *); int (*proc_read)(struct task_struct *task, char *page); int (*proc_show)(struct seq_file *m, struct pid_namespace *ns, struct pid *pid, struct task_struct *task); + int (*proc_vs_read)(char *page); + int (*proc_vxi_read)(struct vx_info *vxi, char *page); + int (*proc_nxi_read)(struct nx_info *nxi, char *page); }; struct ctl_table_header; @@ -287,6 +294,7 @@ struct ctl_table; struct proc_inode { struct pid *pid; + int vx_flags; int fd; union proc_op op; struct proc_dir_entry *pde; diff -NurpP --minimal linux-2.6.27.15/include/linux/random.h linux-2.6.27.15-g-v/include/linux/random.h --- linux-2.6.27.15/include/linux/random.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/random.h 2009-02-10 20:32:15.000000000 +0100 @@ -72,6 +72,11 @@ unsigned long randomize_range(unsigned l u32 random32(void); void srandom32(u32 seed); +static inline unsigned long pax_get_random_long(void) +{ + return random32() + (sizeof(long) > 4 ? (unsigned long)random32() << 32 : 0); +} + #endif /* __KERNEL___ */ #endif /* _LINUX_RANDOM_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/reiserfs_fs.h linux-2.6.27.15-g-v/include/linux/reiserfs_fs.h --- linux-2.6.27.15/include/linux/reiserfs_fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/reiserfs_fs.h 2009-02-10 20:32:15.000000000 +0100 @@ -837,6 +837,11 @@ struct stat_data_v1 { #define REISERFS_COMPR_FL FS_COMPR_FL #define REISERFS_NOTAIL_FL FS_NOTAIL_FL +/* unfortunately reiserfs sdattr is only 16 bit */ +#define REISERFS_IXUNLINK_FL (FS_IXUNLINK_FL >> 16) +#define REISERFS_BARRIER_FL (FS_BARRIER_FL >> 16) +#define REISERFS_COW_FL (FS_COW_FL >> 16) + /* persistent flags that file inherits from the parent directory */ #define REISERFS_INHERIT_MASK ( REISERFS_IMMUTABLE_FL | \ REISERFS_SYNC_FL | \ @@ -846,6 +851,9 @@ struct stat_data_v1 { REISERFS_COMPR_FL | \ REISERFS_NOTAIL_FL ) +#define REISERFS_FL_USER_VISIBLE 0x80FF +#define REISERFS_FL_USER_MODIFIABLE 0x80FF + /* Stat Data on disk (reiserfs version of UFS disk inode minus the address blocks) */ struct stat_data { @@ -1911,6 +1919,7 @@ static inline void reiserfs_update_sd(st void sd_attrs_to_i_attrs(__u16 sd_attrs, struct inode *inode); void i_attrs_to_sd_attrs(struct inode *inode, __u16 * sd_attrs); int reiserfs_setattr(struct dentry *dentry, struct iattr *attr); +int reiserfs_sync_flags(struct inode *inode); /* namei.c */ void set_de_name_and_namelen(struct reiserfs_dir_entry *de); diff -NurpP --minimal linux-2.6.27.15/include/linux/reiserfs_fs_sb.h linux-2.6.27.15-g-v/include/linux/reiserfs_fs_sb.h --- linux-2.6.27.15/include/linux/reiserfs_fs_sb.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/reiserfs_fs_sb.h 2009-02-10 20:32:15.000000000 +0100 @@ -455,6 +455,7 @@ enum reiserfs_mount_options { REISERFS_POSIXACL, REISERFS_BARRIER_NONE, REISERFS_BARRIER_FLUSH, + REISERFS_TAGGED, /* Actions on error */ REISERFS_ERROR_PANIC, diff -NurpP --minimal linux-2.6.27.15/include/linux/sched.h linux-2.6.27.15-g-v/include/linux/sched.h --- linux-2.6.27.15/include/linux/sched.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/sched.h 2009-02-10 20:32:15.000000000 +0100 @@ -71,7 +71,6 @@ struct sched_param { #include #include #include -#include #include #include #include @@ -88,6 +87,7 @@ struct sched_param { #include #include #include +#include #include @@ -96,6 +96,7 @@ struct exec_domain; struct futex_pi_state; struct robust_list_head; struct bio; +struct linux_binprm; /* * List of flags we want to share for kernel threads, @@ -357,25 +358,27 @@ extern void arch_unmap_area_topdown(stru * The mm counters are not protected by its page_table_lock, * so must be incremented atomically. */ -#define set_mm_counter(mm, member, value) atomic_long_set(&(mm)->_##member, value) -#define get_mm_counter(mm, member) ((unsigned long)atomic_long_read(&(mm)->_##member)) -#define add_mm_counter(mm, member, value) atomic_long_add(value, &(mm)->_##member) -#define inc_mm_counter(mm, member) atomic_long_inc(&(mm)->_##member) -#define dec_mm_counter(mm, member) atomic_long_dec(&(mm)->_##member) - +#define __set_mm_counter(mm, member, value) \ + atomic_long_set(&(mm)->_##member, value) +#define get_mm_counter(mm, member) \ + ((unsigned long)atomic_long_read(&(mm)->_##member)) #else /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */ /* * The mm counters are protected by its page_table_lock, * so can be incremented directly. */ -#define set_mm_counter(mm, member, value) (mm)->_##member = (value) +#define __set_mm_counter(mm, member, value) (mm)->_##member = (value) #define get_mm_counter(mm, member) ((mm)->_##member) -#define add_mm_counter(mm, member, value) (mm)->_##member += (value) -#define inc_mm_counter(mm, member) (mm)->_##member++ -#define dec_mm_counter(mm, member) (mm)->_##member-- #endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */ +#define set_mm_counter(mm, member, value) \ + vx_ ## member ## pages_sub((mm), (get_mm_counter(mm, member) - value)) +#define add_mm_counter(mm, member, value) \ + vx_ ## member ## pages_add((mm), (value)) +#define inc_mm_counter(mm, member) vx_ ## member ## pages_inc((mm)) +#define dec_mm_counter(mm, member) vx_ ## member ## pages_dec((mm)) + #define get_mm_rss(mm) \ (get_mm_counter(mm, file_rss) + get_mm_counter(mm, anon_rss)) #define update_hiwater_rss(mm) do { \ @@ -545,6 +548,15 @@ struct signal_struct { unsigned audit_tty; struct tty_audit_buf *tty_audit_buf; #endif + +#ifdef CONFIG_GRKERNSEC + u32 curr_ip; + u32 gr_saddr; + u32 gr_daddr; + u16 gr_sport; + u16 gr_dport; + u8 used_accept:1; +#endif }; /* Context switch must be unlocked if interrupts are to be enabled */ @@ -1029,7 +1041,7 @@ struct sched_rt_entity { struct task_struct { volatile long state; /* -1 unrunnable, 0 runnable, >0 stopped */ - void *stack; + struct thread_info *stack; atomic_t usage; unsigned int flags; /* per process flags, defined below */ unsigned int ptrace; @@ -1094,10 +1106,9 @@ struct task_struct { pid_t pid; pid_t tgid; -#ifdef CONFIG_CC_STACKPROTECTOR /* Canary value for the -fstack-protector gcc feature */ unsigned long stack_canary; -#endif + /* * pointers to (original) parent process, youngest child, younger sibling, * older sibling, respectively. (p->father can be replaced with @@ -1125,8 +1136,8 @@ struct task_struct { struct list_head thread_group; struct completion *vfork_done; /* for vfork() */ - int __user *set_child_tid; /* CLONE_CHILD_SETTID */ - int __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ + pid_t __user *set_child_tid; /* CLONE_CHILD_SETTID */ + pid_t __user *clear_child_tid; /* CLONE_CHILD_CLEARTID */ cputime_t utime, stime, utimescaled, stimescaled; cputime_t gtime; @@ -1199,6 +1210,14 @@ struct task_struct { #endif seccomp_t seccomp; +/* vserver context data */ + struct vx_info *vx_info; + struct nx_info *nx_info; + + xid_t xid; + nid_t nid; + tag_t tag; + /* Thread group tracking */ u32 parent_exec_id; u32 self_exec_id; @@ -1306,8 +1325,64 @@ struct task_struct { int latency_record_count; struct latency_record latency_record[LT_SAVECOUNT]; #endif + +#ifdef CONFIG_GRKERNSEC + /* grsecurity */ + struct acl_subject_label *acl; + struct acl_role_label *role; + struct file *exec_file; + u16 acl_role_id; + u8 acl_sp_role; + u8 is_writable; + u8 brute; +#endif + }; +#define MF_PAX_PAGEEXEC 0x01000000 /* Paging based non-executable pages */ +#define MF_PAX_EMUTRAMP 0x02000000 /* Emulate trampolines */ +#define MF_PAX_MPROTECT 0x04000000 /* Restrict mprotect() */ +#define MF_PAX_RANDMMAP 0x08000000 /* Randomize mmap() base */ +/*#define MF_PAX_RANDEXEC 0x10000000*/ /* Randomize ET_EXEC base */ +#define MF_PAX_SEGMEXEC 0x20000000 /* Segmentation based non-executable pages */ + +#ifdef CONFIG_PAX_SOFTMODE +extern unsigned int pax_softmode; +#endif + +extern int pax_check_flags(unsigned long *); + +/* if tsk != current then task_lock must be held on it */ +#if defined(CONFIG_PAX_NOEXEC) || defined(CONFIG_PAX_ASLR) +static inline unsigned long pax_get_flags(struct task_struct *tsk) +{ + if (likely(tsk->mm)) + return tsk->mm->pax_flags; + else + return 0UL; +} + +/* if tsk != current then task_lock must be held on it */ +static inline long pax_set_flags(struct task_struct *tsk, unsigned long flags) +{ + if (likely(tsk->mm)) { + tsk->mm->pax_flags = flags; + return 0; + } + return -EINVAL; +} +#endif + +#ifdef CONFIG_PAX_HAVE_ACL_FLAGS +extern void pax_set_initial_flags(struct linux_binprm *bprm); +#elif defined(CONFIG_PAX_HOOK_ACL_FLAGS) +extern void (*pax_set_initial_flags_func)(struct linux_binprm *bprm); +#endif + +void pax_report_fault(struct pt_regs *regs, void *pc, void *sp); +void pax_report_insns(void *pc, void *sp); +void pax_report_refcount_overflow(struct pt_regs *regs); + /* * Priority of a process goes from 0..MAX_PRIO-1, valid RT * priority is 0..MAX_RT_PRIO-1, and SCHED_NORMAL/SCHED_BATCH @@ -1385,6 +1460,11 @@ struct pid_namespace; * see also pid_nr() etc in include/linux/pid.h */ +#include +#include +#include +#include + static inline pid_t task_pid_nr(struct task_struct *tsk) { return tsk->pid; @@ -1394,7 +1474,7 @@ pid_t task_pid_nr_ns(struct task_struct static inline pid_t task_pid_vnr(struct task_struct *tsk) { - return pid_vnr(task_pid(tsk)); + return vx_map_pid(pid_vnr(task_pid(tsk))); } @@ -1407,7 +1487,7 @@ pid_t task_tgid_nr_ns(struct task_struct static inline pid_t task_tgid_vnr(struct task_struct *tsk) { - return pid_vnr(task_tgid(tsk)); + return vx_map_tgid(pid_vnr(task_tgid(tsk))); } @@ -1848,7 +1928,7 @@ extern void __cleanup_sighand(struct sig extern void exit_itimers(struct signal_struct *); extern void flush_itimer_signals(void); -extern NORET_TYPE void do_group_exit(int); +extern NORET_TYPE void do_group_exit(int) ATTRIB_NORET; extern void daemonize(const char *, ...); extern int allow_signal(int); @@ -1951,8 +2031,8 @@ static inline void unlock_task_sighand(s #ifndef __HAVE_THREAD_FUNCTIONS -#define task_thread_info(task) ((struct thread_info *)(task)->stack) -#define task_stack_page(task) ((task)->stack) +#define task_thread_info(task) ((task)->stack) +#define task_stack_page(task) ((void *)(task)->stack) static inline void setup_thread_stack(struct task_struct *p, struct task_struct *org) { diff -NurpP --minimal linux-2.6.27.15/include/linux/screen_info.h linux-2.6.27.15-g-v/include/linux/screen_info.h --- linux-2.6.27.15/include/linux/screen_info.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/screen_info.h 2009-02-10 20:32:15.000000000 +0100 @@ -42,7 +42,8 @@ struct screen_info { __u16 pages; /* 0x32 */ __u16 vesa_attributes; /* 0x34 */ __u32 capabilities; /* 0x36 */ - __u8 _reserved[6]; /* 0x3a */ + __u16 vesapm_size; /* 0x3a */ + __u8 _reserved[4]; /* 0x3c */ } __attribute__((packed)); #define VIDEO_TYPE_MDA 0x10 /* Monochrome Text Display */ diff -NurpP --minimal linux-2.6.27.15/include/linux/shmem_fs.h linux-2.6.27.15-g-v/include/linux/shmem_fs.h --- linux-2.6.27.15/include/linux/shmem_fs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/shmem_fs.h 2009-02-10 20:32:15.000000000 +0100 @@ -8,6 +8,9 @@ #define SHMEM_NR_DIRECT 16 +#define TMPFS_SUPER_MAGIC 0x01021994 + + struct shmem_inode_info { spinlock_t lock; unsigned long flags; diff -NurpP --minimal linux-2.6.27.15/include/linux/shm.h linux-2.6.27.15-g-v/include/linux/shm.h --- linux-2.6.27.15/include/linux/shm.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/shm.h 2009-02-10 20:32:15.000000000 +0100 @@ -95,6 +95,10 @@ struct shmid_kernel /* private to the ke pid_t shm_cprid; pid_t shm_lprid; struct user_struct *mlock_user; +#ifdef CONFIG_GRKERNSEC + time_t shm_createtime; + pid_t shm_lapid; +#endif }; /* shm_mode upper byte flags */ diff -NurpP --minimal linux-2.6.27.15/include/linux/slab.h linux-2.6.27.15-g-v/include/linux/slab.h --- linux-2.6.27.15/include/linux/slab.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/slab.h 2009-02-10 20:32:15.000000000 +0100 @@ -45,10 +45,9 @@ * ZERO_SIZE_PTR can be passed to kfree though in the same way that NULL can. * Both make kfree a no-op. */ -#define ZERO_SIZE_PTR ((void *)16) +#define ZERO_SIZE_PTR ((void *)-1024L) -#define ZERO_OR_NULL_PTR(x) ((unsigned long)(x) <= \ - (unsigned long)ZERO_SIZE_PTR) +#define ZERO_OR_NULL_PTR(x) (!(x) || (x) == ZERO_SIZE_PTR) /* * struct kmem_cache related prototypes diff -NurpP --minimal linux-2.6.27.15/include/linux/stat.h linux-2.6.27.15-g-v/include/linux/stat.h --- linux-2.6.27.15/include/linux/stat.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/stat.h 2009-02-10 20:32:15.000000000 +0100 @@ -66,6 +66,7 @@ struct kstat { unsigned int nlink; uid_t uid; gid_t gid; + tag_t tag; dev_t rdev; loff_t size; struct timespec atime; diff -NurpP --minimal linux-2.6.27.15/include/linux/sunrpc/auth.h linux-2.6.27.15-g-v/include/linux/sunrpc/auth.h --- linux-2.6.27.15/include/linux/sunrpc/auth.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/sunrpc/auth.h 2009-02-10 20:32:15.000000000 +0100 @@ -25,6 +25,7 @@ struct auth_cred { uid_t uid; gid_t gid; + tag_t tag; struct group_info *group_info; unsigned char machine_cred : 1; }; diff -NurpP --minimal linux-2.6.27.15/include/linux/sunrpc/clnt.h linux-2.6.27.15-g-v/include/linux/sunrpc/clnt.h --- linux-2.6.27.15/include/linux/sunrpc/clnt.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/sunrpc/clnt.h 2009-02-10 20:32:15.000000000 +0100 @@ -43,7 +43,8 @@ struct rpc_clnt { unsigned int cl_softrtry : 1,/* soft timeouts */ cl_discrtry : 1,/* disconnect before retry */ cl_autobind : 1,/* use getport() */ - cl_chatty : 1;/* be verbose */ + cl_chatty : 1,/* be verbose */ + cl_tag : 1;/* context tagging */ struct rpc_rtt * cl_rtt; /* RTO estimator data */ const struct rpc_timeout *cl_timeout; /* Timeout strategy */ diff -NurpP --minimal linux-2.6.27.15/include/linux/syscalls.h linux-2.6.27.15-g-v/include/linux/syscalls.h --- linux-2.6.27.15/include/linux/syscalls.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/syscalls.h 2009-02-10 20:32:15.000000000 +0100 @@ -364,6 +364,8 @@ asmlinkage long sys_symlink(const char _ asmlinkage long sys_unlink(const char __user *pathname); asmlinkage long sys_rename(const char __user *oldname, const char __user *newname); +asmlinkage long sys_copyfile(const char __user *from, const char __user *to, + umode_t mode); asmlinkage long sys_chmod(const char __user *filename, mode_t mode); asmlinkage long sys_fchmod(unsigned int fd, mode_t mode); diff -NurpP --minimal linux-2.6.27.15/include/linux/sysctl.h linux-2.6.27.15-g-v/include/linux/sysctl.h --- linux-2.6.27.15/include/linux/sysctl.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/sysctl.h 2009-02-10 20:32:15.000000000 +0100 @@ -70,6 +70,7 @@ enum CTL_ABI=9, /* Binary emulation */ CTL_CPU=10, /* CPU stuff (speed scaling, etc) */ CTL_ARLAN=254, /* arlan wireless driver */ + CTL_VSERVER=4242, /* Linux-VServer debug */ CTL_S390DBF=5677, /* s390 debug */ CTL_SUNRPC=7249, /* sunrpc debug */ CTL_PM=9899, /* frv power management */ @@ -104,6 +105,7 @@ enum KERN_PANIC=15, /* int: panic timeout */ KERN_REALROOTDEV=16, /* real root device to mount after initrd */ + KERN_VSHELPER=17, /* string: path to vshelper policy agent */ KERN_SPARC_REBOOT=21, /* reboot command on Sparc */ KERN_CTLALTDEL=22, /* int: allow ctl-alt-del to reboot */ @@ -165,7 +167,11 @@ enum KERN_PANIC_ON_NMI=76, /* int: whether we will panic on an unrecovered */ }; - +#ifdef CONFIG_PAX_SOFTMODE +enum { + PAX_SOFTMODE=1 /* PaX: disable/enable soft mode */ +}; +#endif /* CTL_VM names: */ enum diff -NurpP --minimal linux-2.6.27.15/include/linux/sysfs.h linux-2.6.27.15-g-v/include/linux/sysfs.h --- linux-2.6.27.15/include/linux/sysfs.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/sysfs.h 2009-02-10 20:32:15.000000000 +0100 @@ -17,6 +17,8 @@ #include #include +#define SYSFS_SUPER_MAGIC 0x62656572 + struct kobject; struct module; diff -NurpP --minimal linux-2.6.27.15/include/linux/thread_info.h linux-2.6.27.15-g-v/include/linux/thread_info.h --- linux-2.6.27.15/include/linux/thread_info.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/thread_info.h 2009-02-10 20:32:15.000000000 +0100 @@ -23,7 +23,7 @@ struct restart_block { }; /* For futex_wait */ struct { - u32 *uaddr; + u32 __user *uaddr; u32 val; u32 flags; u32 bitset; diff -NurpP --minimal linux-2.6.27.15/include/linux/time.h linux-2.6.27.15-g-v/include/linux/time.h --- linux-2.6.27.15/include/linux/time.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/time.h 2009-02-10 20:32:15.000000000 +0100 @@ -180,6 +180,9 @@ static __always_inline void timespec_add a->tv_sec += __iter_div_u64_rem(a->tv_nsec + ns, NSEC_PER_SEC, &ns); a->tv_nsec = ns; } + +#include + #endif /* __KERNEL__ */ #define NFDBITS __NFDBITS diff -NurpP --minimal linux-2.6.27.15/include/linux/types.h linux-2.6.27.15-g-v/include/linux/types.h --- linux-2.6.27.15/include/linux/types.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/types.h 2009-02-10 20:32:15.000000000 +0100 @@ -36,6 +36,9 @@ typedef __kernel_uid32_t uid_t; typedef __kernel_gid32_t gid_t; typedef __kernel_uid16_t uid16_t; typedef __kernel_gid16_t gid16_t; +typedef unsigned int xid_t; +typedef unsigned int nid_t; +typedef unsigned int tag_t; typedef unsigned long uintptr_t; diff -NurpP --minimal linux-2.6.27.15/include/linux/uaccess.h linux-2.6.27.15-g-v/include/linux/uaccess.h --- linux-2.6.27.15/include/linux/uaccess.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/uaccess.h 2009-02-10 20:32:15.000000000 +0100 @@ -76,11 +76,11 @@ static inline unsigned long __copy_from_ long ret; \ mm_segment_t old_fs = get_fs(); \ \ - set_fs(KERNEL_DS); \ pagefault_disable(); \ + set_fs(KERNEL_DS); \ ret = __get_user(retval, (__force typeof(retval) __user *)(addr)); \ - pagefault_enable(); \ set_fs(old_fs); \ + pagefault_enable(); \ ret; \ }) diff -NurpP --minimal linux-2.6.27.15/include/linux/vmalloc.h linux-2.6.27.15-g-v/include/linux/vmalloc.h --- linux-2.6.27.15/include/linux/vmalloc.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vmalloc.h 2009-02-10 20:32:15.000000000 +0100 @@ -12,6 +12,11 @@ struct vm_area_struct; /* vma defining #define VM_MAP 0x00000004 /* vmap()ed pages */ #define VM_USERMAP 0x00000008 /* suitable for remap_vmalloc_range */ #define VM_VPAGES 0x00000010 /* buffer for pages was vmalloc'ed */ + +#if defined(CONFIG_MODULES) && defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) +#define VM_KERNEXEC 0x00000020 /* allocate from executable kernel memory range */ +#endif + /* bits [20..32] reserved for arch specific ioremap internals */ /* diff -NurpP --minimal linux-2.6.27.15/include/linux/vroot.h linux-2.6.27.15-g-v/include/linux/vroot.h --- linux-2.6.27.15/include/linux/vroot.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vroot.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,51 @@ + +/* + * include/linux/vroot.h + * + * written by Herbert Pötzl, 9/11/2002 + * ported to 2.6 by Herbert Pötzl, 30/12/2004 + * + * Copyright (C) 2002-2007 by Herbert Pötzl. + * Redistribution of this file is permitted under the + * GNU General Public License. + */ + +#ifndef _LINUX_VROOT_H +#define _LINUX_VROOT_H + + +#ifdef __KERNEL__ + +/* Possible states of device */ +enum { + Vr_unbound, + Vr_bound, +}; + +struct vroot_device { + int vr_number; + int vr_refcnt; + + struct semaphore vr_ctl_mutex; + struct block_device *vr_device; + int vr_state; +}; + + +typedef struct block_device *(vroot_grb_func)(struct block_device *); + +extern int register_vroot_grb(vroot_grb_func *); +extern int unregister_vroot_grb(vroot_grb_func *); + +#endif /* __KERNEL__ */ + +#define MAX_VROOT_DEFAULT 8 + +/* + * IOCTL commands --- we will commandeer 0x56 ('V') + */ + +#define VROOT_SET_DEV 0x5600 +#define VROOT_CLR_DEV 0x5601 + +#endif /* _LINUX_VROOT_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_base.h linux-2.6.27.15-g-v/include/linux/vs_base.h --- linux-2.6.27.15/include/linux/vs_base.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_base.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,10 @@ +#ifndef _VS_BASE_H +#define _VS_BASE_H + +#include "vserver/base.h" +#include "vserver/check.h" +#include "vserver/debug.h" + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_context.h linux-2.6.27.15-g-v/include/linux/vs_context.h --- linux-2.6.27.15/include/linux/vs_context.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_context.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,227 @@ +#ifndef _VS_CONTEXT_H +#define _VS_CONTEXT_H + +#include "vserver/base.h" +#include "vserver/check.h" +#include "vserver/context.h" +#include "vserver/history.h" +#include "vserver/debug.h" + +#include + + +#define get_vx_info(i) __get_vx_info(i, __FILE__, __LINE__, __HERE__) + +static inline struct vx_info *__get_vx_info(struct vx_info *vxi, + const char *_file, int _line, void *_here) +{ + if (!vxi) + return NULL; + + vxlprintk(VXD_CBIT(xid, 2), "get_vx_info(%p[#%d.%d])", + vxi, vxi ? vxi->vx_id : 0, + vxi ? atomic_read(&vxi->vx_usecnt) : 0, + _file, _line); + __vxh_get_vx_info(vxi, _here); + + atomic_inc(&vxi->vx_usecnt); + return vxi; +} + + +extern void free_vx_info(struct vx_info *); + +#define put_vx_info(i) __put_vx_info(i, __FILE__, __LINE__, __HERE__) + +static inline void __put_vx_info(struct vx_info *vxi, + const char *_file, int _line, void *_here) +{ + if (!vxi) + return; + + vxlprintk(VXD_CBIT(xid, 2), "put_vx_info(%p[#%d.%d])", + vxi, vxi ? vxi->vx_id : 0, + vxi ? atomic_read(&vxi->vx_usecnt) : 0, + _file, _line); + __vxh_put_vx_info(vxi, _here); + + if (atomic_dec_and_test(&vxi->vx_usecnt)) + free_vx_info(vxi); +} + + +#define init_vx_info(p, i) \ + __init_vx_info(p, i, __FILE__, __LINE__, __HERE__) + +static inline void __init_vx_info(struct vx_info **vxp, struct vx_info *vxi, + const char *_file, int _line, void *_here) +{ + if (vxi) { + vxlprintk(VXD_CBIT(xid, 3), + "init_vx_info(%p[#%d.%d])", + vxi, vxi ? vxi->vx_id : 0, + vxi ? atomic_read(&vxi->vx_usecnt) : 0, + _file, _line); + __vxh_init_vx_info(vxi, vxp, _here); + + atomic_inc(&vxi->vx_usecnt); + } + *vxp = vxi; +} + + +#define set_vx_info(p, i) \ + __set_vx_info(p, i, __FILE__, __LINE__, __HERE__) + +static inline void __set_vx_info(struct vx_info **vxp, struct vx_info *vxi, + const char *_file, int _line, void *_here) +{ + struct vx_info *vxo; + + if (!vxi) + return; + + vxlprintk(VXD_CBIT(xid, 3), "set_vx_info(%p[#%d.%d])", + vxi, vxi ? vxi->vx_id : 0, + vxi ? atomic_read(&vxi->vx_usecnt) : 0, + _file, _line); + __vxh_set_vx_info(vxi, vxp, _here); + + atomic_inc(&vxi->vx_usecnt); + vxo = xchg(vxp, vxi); + BUG_ON(vxo); +} + + +#define clr_vx_info(p) __clr_vx_info(p, __FILE__, __LINE__, __HERE__) + +static inline void __clr_vx_info(struct vx_info **vxp, + const char *_file, int _line, void *_here) +{ + struct vx_info *vxo; + + vxo = xchg(vxp, NULL); + if (!vxo) + return; + + vxlprintk(VXD_CBIT(xid, 3), "clr_vx_info(%p[#%d.%d])", + vxo, vxo ? vxo->vx_id : 0, + vxo ? atomic_read(&vxo->vx_usecnt) : 0, + _file, _line); + __vxh_clr_vx_info(vxo, vxp, _here); + + if (atomic_dec_and_test(&vxo->vx_usecnt)) + free_vx_info(vxo); +} + + +#define claim_vx_info(v, p) \ + __claim_vx_info(v, p, __FILE__, __LINE__, __HERE__) + +static inline void __claim_vx_info(struct vx_info *vxi, + struct task_struct *task, + const char *_file, int _line, void *_here) +{ + vxlprintk(VXD_CBIT(xid, 3), "claim_vx_info(%p[#%d.%d.%d]) %p", + vxi, vxi ? vxi->vx_id : 0, + vxi ? atomic_read(&vxi->vx_usecnt) : 0, + vxi ? atomic_read(&vxi->vx_tasks) : 0, + task, _file, _line); + __vxh_claim_vx_info(vxi, task, _here); + + atomic_inc(&vxi->vx_tasks); +} + + +extern void unhash_vx_info(struct vx_info *); + +#define release_vx_info(v, p) \ + __release_vx_info(v, p, __FILE__, __LINE__, __HERE__) + +static inline void __release_vx_info(struct vx_info *vxi, + struct task_struct *task, + const char *_file, int _line, void *_here) +{ + vxlprintk(VXD_CBIT(xid, 3), "release_vx_info(%p[#%d.%d.%d]) %p", + vxi, vxi ? vxi->vx_id : 0, + vxi ? atomic_read(&vxi->vx_usecnt) : 0, + vxi ? atomic_read(&vxi->vx_tasks) : 0, + task, _file, _line); + __vxh_release_vx_info(vxi, task, _here); + + might_sleep(); + + if (atomic_dec_and_test(&vxi->vx_tasks)) + unhash_vx_info(vxi); +} + + +#define task_get_vx_info(p) \ + __task_get_vx_info(p, __FILE__, __LINE__, __HERE__) + +static inline struct vx_info *__task_get_vx_info(struct task_struct *p, + const char *_file, int _line, void *_here) +{ + struct vx_info *vxi; + + task_lock(p); + vxlprintk(VXD_CBIT(xid, 5), "task_get_vx_info(%p)", + p, _file, _line); + vxi = __get_vx_info(p->vx_info, _file, _line, _here); + task_unlock(p); + return vxi; +} + + +static inline void __wakeup_vx_info(struct vx_info *vxi) +{ + if (waitqueue_active(&vxi->vx_wait)) + wake_up_interruptible(&vxi->vx_wait); +} + + +#define enter_vx_info(v, s) __enter_vx_info(v, s, __FILE__, __LINE__) + +static inline void __enter_vx_info(struct vx_info *vxi, + struct vx_info_save *vxis, const char *_file, int _line) +{ + vxlprintk(VXD_CBIT(xid, 5), "enter_vx_info(%p[#%d],%p) %p[#%d,%p]", + vxi, vxi ? vxi->vx_id : 0, vxis, current, + current->xid, current->vx_info, _file, _line); + vxis->vxi = xchg(¤t->vx_info, vxi); + vxis->xid = current->xid; + current->xid = vxi ? vxi->vx_id : 0; +} + +#define leave_vx_info(s) __leave_vx_info(s, __FILE__, __LINE__) + +static inline void __leave_vx_info(struct vx_info_save *vxis, + const char *_file, int _line) +{ + vxlprintk(VXD_CBIT(xid, 5), "leave_vx_info(%p[#%d,%p]) %p[#%d,%p]", + vxis, vxis->xid, vxis->vxi, current, + current->xid, current->vx_info, _file, _line); + (void)xchg(¤t->vx_info, vxis->vxi); + current->xid = vxis->xid; +} + + +static inline void __enter_vx_admin(struct vx_info_save *vxis) +{ + vxis->vxi = xchg(¤t->vx_info, NULL); + vxis->xid = xchg(¤t->xid, (xid_t)0); +} + +static inline void __leave_vx_admin(struct vx_info_save *vxis) +{ + (void)xchg(¤t->xid, vxis->xid); + (void)xchg(¤t->vx_info, vxis->vxi); +} + +extern void exit_vx_info(struct task_struct *, int); +extern void exit_vx_info_early(struct task_struct *, int); + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_cowbl.h linux-2.6.27.15-g-v/include/linux/vs_cowbl.h --- linux-2.6.27.15/include/linux/vs_cowbl.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_cowbl.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,47 @@ +#ifndef _VS_COWBL_H +#define _VS_COWBL_H + +#include +#include +#include + +extern struct dentry *cow_break_link(const char *pathname); + +static inline int cow_check_and_break(struct path *path) +{ + struct inode *inode = path->dentry->d_inode; + int error = 0; + + /* do we need this check? */ + if (IS_RDONLY(inode)) + return -EROFS; + + if (IS_COW(inode)) { + if (IS_COW_LINK(inode)) { + struct dentry *new_dentry, *old_dentry = path->dentry; + char *pp, *buf; + + buf = kmalloc(PATH_MAX, GFP_KERNEL); + if (!buf) { + return -ENOMEM; + } + pp = d_path(path, buf, PATH_MAX); + new_dentry = cow_break_link(pp); + kfree(buf); + if (!IS_ERR(new_dentry)) { + path->dentry = new_dentry; + dput(old_dentry); + } else + error = PTR_ERR(new_dentry); + } else { + inode->i_flags &= ~(S_IXUNLINK | S_IMMUTABLE); + inode->i_ctime = CURRENT_TIME; + mark_inode_dirty(inode); + } + } + return error; +} + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_cvirt.h linux-2.6.27.15-g-v/include/linux/vs_cvirt.h --- linux-2.6.27.15/include/linux/vs_cvirt.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_cvirt.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,50 @@ +#ifndef _VS_CVIRT_H +#define _VS_CVIRT_H + +#include "vserver/cvirt.h" +#include "vserver/context.h" +#include "vserver/base.h" +#include "vserver/check.h" +#include "vserver/debug.h" + + +static inline void vx_activate_task(struct task_struct *p) +{ + struct vx_info *vxi; + + if ((vxi = p->vx_info)) { + vx_update_load(vxi); + atomic_inc(&vxi->cvirt.nr_running); + } +} + +static inline void vx_deactivate_task(struct task_struct *p) +{ + struct vx_info *vxi; + + if ((vxi = p->vx_info)) { + vx_update_load(vxi); + atomic_dec(&vxi->cvirt.nr_running); + } +} + +static inline void vx_uninterruptible_inc(struct task_struct *p) +{ + struct vx_info *vxi; + + if ((vxi = p->vx_info)) + atomic_inc(&vxi->cvirt.nr_uninterruptible); +} + +static inline void vx_uninterruptible_dec(struct task_struct *p) +{ + struct vx_info *vxi; + + if ((vxi = p->vx_info)) + atomic_dec(&vxi->cvirt.nr_uninterruptible); +} + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_device.h linux-2.6.27.15-g-v/include/linux/vs_device.h --- linux-2.6.27.15/include/linux/vs_device.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_device.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,45 @@ +#ifndef _VS_DEVICE_H +#define _VS_DEVICE_H + +#include "vserver/base.h" +#include "vserver/device.h" +#include "vserver/debug.h" + + +#ifdef CONFIG_VSERVER_DEVICE + +int vs_map_device(struct vx_info *, dev_t, dev_t *, umode_t); + +#define vs_device_perm(v, d, m, p) \ + ((vs_map_device(current_vx_info(), d, NULL, m) & (p)) == (p)) + +#else + +static inline +int vs_map_device(struct vx_info *vxi, + dev_t device, dev_t *target, umode_t mode) +{ + if (target) + *target = device; + return ~0; +} + +#define vs_device_perm(v, d, m, p) ((p) == (p)) + +#endif + + +#define vs_map_chrdev(d, t, p) \ + ((vs_map_device(current_vx_info(), d, t, S_IFCHR) & (p)) == (p)) +#define vs_map_blkdev(d, t, p) \ + ((vs_map_device(current_vx_info(), d, t, S_IFBLK) & (p)) == (p)) + +#define vs_chrdev_perm(d, p) \ + vs_device_perm(current_vx_info(), d, S_IFCHR, p) +#define vs_blkdev_perm(d, p) \ + vs_device_perm(current_vx_info(), d, S_IFBLK, p) + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_dlimit.h linux-2.6.27.15-g-v/include/linux/vs_dlimit.h --- linux-2.6.27.15/include/linux/vs_dlimit.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_dlimit.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,211 @@ +#ifndef _VS_DLIMIT_H +#define _VS_DLIMIT_H + +#include + +#include "vserver/dlimit.h" +#include "vserver/base.h" +#include "vserver/debug.h" + + +#define get_dl_info(i) __get_dl_info(i, __FILE__, __LINE__) + +static inline struct dl_info *__get_dl_info(struct dl_info *dli, + const char *_file, int _line) +{ + if (!dli) + return NULL; + vxlprintk(VXD_CBIT(dlim, 4), "get_dl_info(%p[#%d.%d])", + dli, dli ? dli->dl_tag : 0, + dli ? atomic_read(&dli->dl_usecnt) : 0, + _file, _line); + atomic_inc(&dli->dl_usecnt); + return dli; +} + + +#define free_dl_info(i) \ + call_rcu(&(i)->dl_rcu, rcu_free_dl_info) + +#define put_dl_info(i) __put_dl_info(i, __FILE__, __LINE__) + +static inline void __put_dl_info(struct dl_info *dli, + const char *_file, int _line) +{ + if (!dli) + return; + vxlprintk(VXD_CBIT(dlim, 4), "put_dl_info(%p[#%d.%d])", + dli, dli ? dli->dl_tag : 0, + dli ? atomic_read(&dli->dl_usecnt) : 0, + _file, _line); + if (atomic_dec_and_test(&dli->dl_usecnt)) + free_dl_info(dli); +} + + +#define __dlimit_char(d) ((d) ? '*' : ' ') + +static inline int __dl_alloc_space(struct super_block *sb, + tag_t tag, dlsize_t nr, const char *file, int line) +{ + struct dl_info *dli = NULL; + int ret = 0; + + if (nr == 0) + goto out; + dli = locate_dl_info(sb, tag); + if (!dli) + goto out; + + spin_lock(&dli->dl_lock); + ret = (dli->dl_space_used + nr > dli->dl_space_total); + if (!ret) + dli->dl_space_used += nr; + spin_unlock(&dli->dl_lock); + put_dl_info(dli); +out: + vxlprintk(VXD_CBIT(dlim, 1), + "ALLOC (%p,#%d)%c %lld bytes (%d)", + sb, tag, __dlimit_char(dli), (long long)nr, + ret, file, line); + return ret; +} + +static inline void __dl_free_space(struct super_block *sb, + tag_t tag, dlsize_t nr, const char *_file, int _line) +{ + struct dl_info *dli = NULL; + + if (nr == 0) + goto out; + dli = locate_dl_info(sb, tag); + if (!dli) + goto out; + + spin_lock(&dli->dl_lock); + if (dli->dl_space_used > nr) + dli->dl_space_used -= nr; + else + dli->dl_space_used = 0; + spin_unlock(&dli->dl_lock); + put_dl_info(dli); +out: + vxlprintk(VXD_CBIT(dlim, 1), + "FREE (%p,#%d)%c %lld bytes", + sb, tag, __dlimit_char(dli), (long long)nr, + _file, _line); +} + +static inline int __dl_alloc_inode(struct super_block *sb, + tag_t tag, const char *_file, int _line) +{ + struct dl_info *dli; + int ret = 0; + + dli = locate_dl_info(sb, tag); + if (!dli) + goto out; + + spin_lock(&dli->dl_lock); + ret = (dli->dl_inodes_used >= dli->dl_inodes_total); + if (!ret) + dli->dl_inodes_used++; + spin_unlock(&dli->dl_lock); + put_dl_info(dli); +out: + vxlprintk(VXD_CBIT(dlim, 0), + "ALLOC (%p,#%d)%c inode (%d)", + sb, tag, __dlimit_char(dli), ret, _file, _line); + return ret; +} + +static inline void __dl_free_inode(struct super_block *sb, + tag_t tag, const char *_file, int _line) +{ + struct dl_info *dli; + + dli = locate_dl_info(sb, tag); + if (!dli) + goto out; + + spin_lock(&dli->dl_lock); + if (dli->dl_inodes_used > 1) + dli->dl_inodes_used--; + else + dli->dl_inodes_used = 0; + spin_unlock(&dli->dl_lock); + put_dl_info(dli); +out: + vxlprintk(VXD_CBIT(dlim, 0), + "FREE (%p,#%d)%c inode", + sb, tag, __dlimit_char(dli), _file, _line); +} + +static inline void __dl_adjust_block(struct super_block *sb, tag_t tag, + unsigned long long *free_blocks, unsigned long long *root_blocks, + const char *_file, int _line) +{ + struct dl_info *dli; + uint64_t broot, bfree; + + dli = locate_dl_info(sb, tag); + if (!dli) + return; + + spin_lock(&dli->dl_lock); + broot = (dli->dl_space_total - + (dli->dl_space_total >> 10) * dli->dl_nrlmult) + >> sb->s_blocksize_bits; + bfree = (dli->dl_space_total - dli->dl_space_used) + >> sb->s_blocksize_bits; + spin_unlock(&dli->dl_lock); + + vxlprintk(VXD_CBIT(dlim, 2), + "ADJUST: %lld,%lld on %lld,%lld [mult=%d]", + (long long)bfree, (long long)broot, + *free_blocks, *root_blocks, dli->dl_nrlmult, + _file, _line); + if (free_blocks) { + if (*free_blocks > bfree) + *free_blocks = bfree; + } + if (root_blocks) { + if (*root_blocks > broot) + *root_blocks = broot; + } + put_dl_info(dli); +} + +#define DLIMIT_ALLOC_SPACE(in, bytes) \ + __dl_alloc_space((in)->i_sb, (in)->i_tag, (dlsize_t)(bytes), \ + __FILE__, __LINE__ ) + +#define DLIMIT_FREE_SPACE(in, bytes) \ + __dl_free_space((in)->i_sb, (in)->i_tag, (dlsize_t)(bytes), \ + __FILE__, __LINE__ ) + +#define DLIMIT_ALLOC_BLOCK(in, nr) \ + __dl_alloc_space((in)->i_sb, (in)->i_tag, \ + ((dlsize_t)(nr)) << (in)->i_sb->s_blocksize_bits, \ + __FILE__, __LINE__ ) + +#define DLIMIT_FREE_BLOCK(in, nr) \ + __dl_free_space((in)->i_sb, (in)->i_tag, \ + ((dlsize_t)(nr)) << (in)->i_sb->s_blocksize_bits, \ + __FILE__, __LINE__ ) + + +#define DLIMIT_ALLOC_INODE(in) \ + __dl_alloc_inode((in)->i_sb, (in)->i_tag, __FILE__, __LINE__ ) + +#define DLIMIT_FREE_INODE(in) \ + __dl_free_inode((in)->i_sb, (in)->i_tag, __FILE__, __LINE__ ) + + +#define DLIMIT_ADJUST_BLOCK(sb, tag, fb, rb) \ + __dl_adjust_block(sb, tag, fb, rb, __FILE__, __LINE__ ) + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/base.h linux-2.6.27.15-g-v/include/linux/vserver/base.h --- linux-2.6.27.15/include/linux/vserver/base.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/base.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,157 @@ +#ifndef _VX_BASE_H +#define _VX_BASE_H + + +/* context state changes */ + +enum { + VSC_STARTUP = 1, + VSC_SHUTDOWN, + + VSC_NETUP, + VSC_NETDOWN, +}; + + + +#define vx_task_xid(t) ((t)->xid) + +#define vx_current_xid() vx_task_xid(current) + +#define current_vx_info() (current->vx_info) + + +#define nx_task_nid(t) ((t)->nid) + +#define nx_current_nid() nx_task_nid(current) + +#define current_nx_info() (current->nx_info) + + +/* generic flag merging */ + +#define vs_check_flags(v, m, f) (((v) & (m)) ^ (f)) + +#define vs_mask_flags(v, f, m) (((v) & ~(m)) | ((f) & (m))) + +#define vs_mask_mask(v, f, m) (((v) & ~(m)) | ((v) & (f) & (m))) + +#define vs_check_bit(v, n) ((v) & (1LL << (n))) + + +/* context flags */ + +#define __vx_flags(v) ((v) ? (v)->vx_flags : 0) + +#define vx_current_flags() __vx_flags(current->vx_info) + +#define vx_info_flags(v, m, f) \ + vs_check_flags(__vx_flags(v), m, f) + +#define task_vx_flags(t, m, f) \ + ((t) && vx_info_flags((t)->vx_info, m, f)) + +#define vx_flags(m, f) vx_info_flags(current->vx_info, m, f) + + +/* context caps */ + +#define __vx_ccaps(v) ((v) ? (v)->vx_ccaps : 0) + +#define vx_current_ccaps() __vx_ccaps(current->vx_info) + +#define vx_info_ccaps(v, c) (__vx_ccaps(v) & (c)) + +#define vx_ccaps(c) vx_info_ccaps(current->vx_info, (c)) + + + +/* network flags */ + +#define __nx_flags(n) ((n) ? (n)->nx_flags : 0) + +#define nx_current_flags() __nx_flags(current->nx_info) + +#define nx_info_flags(n, m, f) \ + vs_check_flags(__nx_flags(n), m, f) + +#define task_nx_flags(t, m, f) \ + ((t) && nx_info_flags((t)->nx_info, m, f)) + +#define nx_flags(m, f) nx_info_flags(current->nx_info, m, f) + + +/* network caps */ + +#define __nx_ncaps(n) ((n) ? (n)->nx_ncaps : 0) + +#define nx_current_ncaps() __nx_ncaps(current->nx_info) + +#define nx_info_ncaps(n, c) (__nx_ncaps(n) & (c)) + +#define nx_ncaps(c) nx_info_ncaps(current->nx_info, c) + + +/* context mask capabilities */ + +#define __vx_mcaps(v) ((v) ? (v)->vx_ccaps >> 32UL : ~0 ) + +#define vx_info_mcaps(v, c) (__vx_mcaps(v) & (c)) + +#define vx_mcaps(c) vx_info_mcaps(current->vx_info, c) + + +/* context bcap mask */ + +#define __vx_bcaps(v) ((v)->vx_bcaps) + +#define vx_current_bcaps() __vx_bcaps(current->vx_info) + + +/* mask given bcaps */ + +#define vx_info_mbcaps(v, c) ((v) ? cap_intersect(__vx_bcaps(v), c) : c) + +#define vx_mbcaps(c) vx_info_mbcaps(current->vx_info, c) + + +/* masked cap_bset */ + +#define vx_info_cap_bset(v) vx_info_mbcaps(v, current->cap_bset) + +#define vx_current_cap_bset() vx_info_cap_bset(current->vx_info) + +#if 0 +#define vx_info_mbcap(v, b) \ + (!vx_info_flags(v, VXF_STATE_SETUP, 0) ? \ + vx_info_bcaps(v, b) : (b)) + +#define task_vx_mbcap(t, b) \ + vx_info_mbcap((t)->vx_info, (t)->b) + +#define vx_mbcap(b) task_vx_mbcap(current, b) +#endif + +#define vx_cap_raised(v, c, f) cap_raised(vx_info_mbcaps(v, c), f) + +#define vx_capable(b, c) (capable(b) || \ + (cap_raised(current->cap_effective, b) && vx_ccaps(c))) + +#define nx_capable(b, c) (capable(b) || \ + (cap_raised(current->cap_effective, b) && nx_ncaps(c))) + +#define vx_current_initpid(n) \ + (current->vx_info && \ + (current->vx_info->vx_initpid == (n))) + + +#define __vx_state(v) ((v) ? ((v)->vx_state) : 0) + +#define vx_info_state(v, m) (__vx_state(v) & (m)) + + +#define __nx_state(n) ((n) ? ((n)->nx_state) : 0) + +#define nx_info_state(n, m) (__nx_state(n) & (m)) + +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/cacct_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/cacct_cmd.h --- linux-2.6.27.15/include/linux/vserver/cacct_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/cacct_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,23 @@ +#ifndef _VX_CACCT_CMD_H +#define _VX_CACCT_CMD_H + + +/* virtual host info name commands */ + +#define VCMD_sock_stat VC_CMD(VSTAT, 5, 0) + +struct vcmd_sock_stat_v0 { + uint32_t field; + uint32_t count[3]; + uint64_t total[3]; +}; + + +#ifdef __KERNEL__ + +#include + +extern int vc_sock_stat(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_CACCT_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/cacct_def.h linux-2.6.27.15-g-v/include/linux/vserver/cacct_def.h --- linux-2.6.27.15/include/linux/vserver/cacct_def.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/cacct_def.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,43 @@ +#ifndef _VX_CACCT_DEF_H +#define _VX_CACCT_DEF_H + +#include +#include + + +struct _vx_sock_acc { + atomic_long_t count; + atomic_long_t total; +}; + +/* context sub struct */ + +struct _vx_cacct { + struct _vx_sock_acc sock[VXA_SOCK_SIZE][3]; + atomic_t slab[8]; + atomic_t page[6][8]; +}; + +#ifdef CONFIG_VSERVER_DEBUG + +static inline void __dump_vx_cacct(struct _vx_cacct *cacct) +{ + int i, j; + + printk("\t_vx_cacct:"); + for (i = 0; i < 6; i++) { + struct _vx_sock_acc *ptr = cacct->sock[i]; + + printk("\t [%d] =", i); + for (j = 0; j < 3; j++) { + printk(" [%d] = %8lu, %8lu", j, + atomic_long_read(&ptr[j].count), + atomic_long_read(&ptr[j].total)); + } + printk("\n"); + } +} + +#endif + +#endif /* _VX_CACCT_DEF_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/cacct.h linux-2.6.27.15-g-v/include/linux/vserver/cacct.h --- linux-2.6.27.15/include/linux/vserver/cacct.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/cacct.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,15 @@ +#ifndef _VX_CACCT_H +#define _VX_CACCT_H + + +enum sock_acc_field { + VXA_SOCK_UNSPEC = 0, + VXA_SOCK_UNIX, + VXA_SOCK_INET, + VXA_SOCK_INET6, + VXA_SOCK_PACKET, + VXA_SOCK_OTHER, + VXA_SOCK_SIZE /* array size */ +}; + +#endif /* _VX_CACCT_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/cacct_int.h linux-2.6.27.15-g-v/include/linux/vserver/cacct_int.h --- linux-2.6.27.15/include/linux/vserver/cacct_int.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/cacct_int.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,21 @@ +#ifndef _VX_CACCT_INT_H +#define _VX_CACCT_INT_H + + +#ifdef __KERNEL__ + +static inline +unsigned long vx_sock_count(struct _vx_cacct *cacct, int type, int pos) +{ + return atomic_long_read(&cacct->sock[type][pos].count); +} + + +static inline +unsigned long vx_sock_total(struct _vx_cacct *cacct, int type, int pos) +{ + return atomic_long_read(&cacct->sock[type][pos].total); +} + +#endif /* __KERNEL__ */ +#endif /* _VX_CACCT_INT_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/check.h linux-2.6.27.15-g-v/include/linux/vserver/check.h --- linux-2.6.27.15/include/linux/vserver/check.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/check.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,89 @@ +#ifndef _VS_CHECK_H +#define _VS_CHECK_H + + +#define MAX_S_CONTEXT 65535 /* Arbitrary limit */ + +#ifdef CONFIG_VSERVER_DYNAMIC_IDS +#define MIN_D_CONTEXT 49152 /* dynamic contexts start here */ +#else +#define MIN_D_CONTEXT 65536 +#endif + +/* check conditions */ + +#define VS_ADMIN 0x0001 +#define VS_WATCH 0x0002 +#define VS_HIDE 0x0004 +#define VS_HOSTID 0x0008 + +#define VS_IDENT 0x0010 +#define VS_EQUIV 0x0020 +#define VS_PARENT 0x0040 +#define VS_CHILD 0x0080 + +#define VS_ARG_MASK 0x00F0 + +#define VS_DYNAMIC 0x0100 +#define VS_STATIC 0x0200 + +#define VS_ATR_MASK 0x0F00 + +#ifdef CONFIG_VSERVER_PRIVACY +#define VS_ADMIN_P (0) +#define VS_WATCH_P (0) +#else +#define VS_ADMIN_P VS_ADMIN +#define VS_WATCH_P VS_WATCH +#endif + +#define VS_HARDIRQ 0x1000 +#define VS_SOFTIRQ 0x2000 +#define VS_IRQ 0x4000 + +#define VS_IRQ_MASK 0xF000 + +#include + +/* + * check current context for ADMIN/WATCH and + * optionally against supplied argument + */ +static inline int __vs_check(int cid, int id, unsigned int mode) +{ + if (mode & VS_ARG_MASK) { + if ((mode & VS_IDENT) && (id == cid)) + return 1; + } + if (mode & VS_ATR_MASK) { + if ((mode & VS_DYNAMIC) && + (id >= MIN_D_CONTEXT) && + (id <= MAX_S_CONTEXT)) + return 1; + if ((mode & VS_STATIC) && + (id > 1) && (id < MIN_D_CONTEXT)) + return 1; + } + if (mode & VS_IRQ_MASK) { + if ((mode & VS_IRQ) && unlikely(in_interrupt())) + return 1; + if ((mode & VS_HARDIRQ) && unlikely(in_irq())) + return 1; + if ((mode & VS_SOFTIRQ) && unlikely(in_softirq())) + return 1; + } + return (((mode & VS_ADMIN) && (cid == 0)) || + ((mode & VS_WATCH) && (cid == 1)) || + ((mode & VS_HOSTID) && (id == 0))); +} + +#define vx_check(c, m) __vs_check(vx_current_xid(), c, (m) | VS_IRQ) + +#define vx_weak_check(c, m) ((m) ? vx_check(c, m) : 1) + + +#define nx_check(c, m) __vs_check(nx_current_nid(), c, m) + +#define nx_weak_check(c, m) ((m) ? nx_check(c, m) : 1) + +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/context_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/context_cmd.h --- linux-2.6.27.15/include/linux/vserver/context_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/context_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,128 @@ +#ifndef _VX_CONTEXT_CMD_H +#define _VX_CONTEXT_CMD_H + + +/* vinfo commands */ + +#define VCMD_task_xid VC_CMD(VINFO, 1, 0) + +#ifdef __KERNEL__ +extern int vc_task_xid(uint32_t); + +#endif /* __KERNEL__ */ + +#define VCMD_vx_info VC_CMD(VINFO, 5, 0) + +struct vcmd_vx_info_v0 { + uint32_t xid; + uint32_t initpid; + /* more to come */ +}; + +#ifdef __KERNEL__ +extern int vc_vx_info(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_ctx_stat VC_CMD(VSTAT, 0, 0) + +struct vcmd_ctx_stat_v0 { + uint32_t usecnt; + uint32_t tasks; + /* more to come */ +}; + +#ifdef __KERNEL__ +extern int vc_ctx_stat(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + +/* context commands */ + +#define VCMD_ctx_create_v0 VC_CMD(VPROC, 1, 0) +#define VCMD_ctx_create VC_CMD(VPROC, 1, 1) + +struct vcmd_ctx_create { + uint64_t flagword; +}; + +#define VCMD_ctx_migrate_v0 VC_CMD(PROCMIG, 1, 0) +#define VCMD_ctx_migrate VC_CMD(PROCMIG, 1, 1) + +struct vcmd_ctx_migrate { + uint64_t flagword; +}; + +#ifdef __KERNEL__ +extern int vc_ctx_create(uint32_t, void __user *); +extern int vc_ctx_migrate(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + + +/* flag commands */ + +#define VCMD_get_cflags VC_CMD(FLAGS, 1, 0) +#define VCMD_set_cflags VC_CMD(FLAGS, 2, 0) + +struct vcmd_ctx_flags_v0 { + uint64_t flagword; + uint64_t mask; +}; + +#ifdef __KERNEL__ +extern int vc_get_cflags(struct vx_info *, void __user *); +extern int vc_set_cflags(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + + +/* context caps commands */ + +#define VCMD_get_ccaps VC_CMD(FLAGS, 3, 1) +#define VCMD_set_ccaps VC_CMD(FLAGS, 4, 1) + +struct vcmd_ctx_caps_v1 { + uint64_t ccaps; + uint64_t cmask; +}; + +#ifdef __KERNEL__ +extern int vc_get_ccaps(struct vx_info *, void __user *); +extern int vc_set_ccaps(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + + +/* bcaps commands */ + +#define VCMD_get_bcaps VC_CMD(FLAGS, 9, 0) +#define VCMD_set_bcaps VC_CMD(FLAGS, 10, 0) + +struct vcmd_bcaps { + uint64_t bcaps; + uint64_t bmask; +}; + +#ifdef __KERNEL__ +extern int vc_get_bcaps(struct vx_info *, void __user *); +extern int vc_set_bcaps(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + + +/* OOM badness */ + +#define VCMD_get_badness VC_CMD(MEMCTRL, 5, 0) +#define VCMD_set_badness VC_CMD(MEMCTRL, 6, 0) + +struct vcmd_badness_v0 { + int64_t bias; +}; + +#ifdef __KERNEL__ +extern int vc_get_badness(struct vx_info *, void __user *); +extern int vc_set_badness(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_CONTEXT_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/context.h linux-2.6.27.15-g-v/include/linux/vserver/context.h --- linux-2.6.27.15/include/linux/vserver/context.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/context.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,178 @@ +#ifndef _VX_CONTEXT_H +#define _VX_CONTEXT_H + +#include +#include + + +/* context flags */ + +#define VXF_INFO_SCHED 0x00000002 +#define VXF_INFO_NPROC 0x00000004 +#define VXF_INFO_PRIVATE 0x00000008 + +#define VXF_INFO_INIT 0x00000010 +#define VXF_INFO_HIDE 0x00000020 +#define VXF_INFO_ULIMIT 0x00000040 +#define VXF_INFO_NSPACE 0x00000080 + +#define VXF_SCHED_HARD 0x00000100 +#define VXF_SCHED_PRIO 0x00000200 +#define VXF_SCHED_PAUSE 0x00000400 + +#define VXF_VIRT_MEM 0x00010000 +#define VXF_VIRT_UPTIME 0x00020000 +#define VXF_VIRT_CPU 0x00040000 +#define VXF_VIRT_LOAD 0x00080000 +#define VXF_VIRT_TIME 0x00100000 + +#define VXF_HIDE_MOUNT 0x01000000 +/* was VXF_HIDE_NETIF 0x02000000 */ +#define VXF_HIDE_VINFO 0x04000000 + +#define VXF_STATE_SETUP (1ULL << 32) +#define VXF_STATE_INIT (1ULL << 33) +#define VXF_STATE_ADMIN (1ULL << 34) + +#define VXF_SC_HELPER (1ULL << 36) +#define VXF_REBOOT_KILL (1ULL << 37) +#define VXF_PERSISTENT (1ULL << 38) + +#define VXF_FORK_RSS (1ULL << 48) +#define VXF_PROLIFIC (1ULL << 49) + +#define VXF_IGNEG_NICE (1ULL << 52) + +#define VXF_ONE_TIME (0x0007ULL << 32) + +#define VXF_INIT_SET (VXF_STATE_SETUP | VXF_STATE_INIT | VXF_STATE_ADMIN) + + +/* context migration */ + +#define VXM_SET_INIT 0x00000001 +#define VXM_SET_REAPER 0x00000002 + +/* context caps */ + +#define VXC_CAP_MASK 0x00000000 + +#define VXC_SET_UTSNAME 0x00000001 +#define VXC_SET_RLIMIT 0x00000002 + +/* was VXC_RAW_ICMP 0x00000100 */ +#define VXC_SYSLOG 0x00001000 + +#define VXC_SECURE_MOUNT 0x00010000 +#define VXC_SECURE_REMOUNT 0x00020000 +#define VXC_BINARY_MOUNT 0x00040000 + +#define VXC_QUOTA_CTL 0x00100000 +#define VXC_ADMIN_MAPPER 0x00200000 +#define VXC_ADMIN_CLOOP 0x00400000 + +#define VXC_KTHREAD 0x01000000 + + +#ifdef __KERNEL__ + +#include +#include +#include + +#include "limit_def.h" +#include "sched_def.h" +#include "cvirt_def.h" +#include "cacct_def.h" +#include "device_def.h" + +#define VX_SPACES 2 + +struct _vx_info_pc { + struct _vx_sched_pc sched_pc; + struct _vx_cvirt_pc cvirt_pc; +}; + +struct vx_info { + struct hlist_node vx_hlist; /* linked list of contexts */ + xid_t vx_id; /* context id */ + atomic_t vx_usecnt; /* usage count */ + atomic_t vx_tasks; /* tasks count */ + struct vx_info *vx_parent; /* parent context */ + int vx_state; /* context state */ + + unsigned long vx_nsmask[VX_SPACES]; /* assignment mask */ + struct nsproxy *vx_nsproxy[VX_SPACES]; /* private namespaces */ + struct fs_struct *vx_fs[VX_SPACES]; /* private namespace fs */ + + uint64_t vx_flags; /* context flags */ + uint64_t vx_ccaps; /* context caps (vserver) */ + kernel_cap_t vx_bcaps; /* bounding caps (system) */ + // kernel_cap_t vx_cap_bset; /* the guest's bset */ + + struct task_struct *vx_reaper; /* guest reaper process */ + pid_t vx_initpid; /* PID of guest init */ + int64_t vx_badness_bias; /* OOM points bias */ + + struct _vx_limit limit; /* vserver limits */ + struct _vx_sched sched; /* vserver scheduler */ + struct _vx_cvirt cvirt; /* virtual/bias stuff */ + struct _vx_cacct cacct; /* context accounting */ + + struct _vx_device dmap; /* default device map targets */ + +#ifndef CONFIG_SMP + struct _vx_info_pc info_pc; /* per cpu data */ +#else + struct _vx_info_pc *ptr_pc; /* per cpu array */ +#endif + + wait_queue_head_t vx_wait; /* context exit waitqueue */ + int reboot_cmd; /* last sys_reboot() cmd */ + int exit_code; /* last process exit code */ + + char vx_name[65]; /* vserver name */ +}; + +#ifndef CONFIG_SMP +#define vx_ptr_pc(vxi) (&(vxi)->info_pc) +#define vx_per_cpu(vxi, v, id) vx_ptr_pc(vxi)->v +#else +#define vx_ptr_pc(vxi) ((vxi)->ptr_pc) +#define vx_per_cpu(vxi, v, id) per_cpu_ptr(vx_ptr_pc(vxi), id)->v +#endif + +#define vx_cpu(vxi, v) vx_per_cpu(vxi, v, smp_processor_id()) + + +struct vx_info_save { + struct vx_info *vxi; + xid_t xid; +}; + + +/* status flags */ + +#define VXS_HASHED 0x0001 +#define VXS_PAUSED 0x0010 +#define VXS_SHUTDOWN 0x0100 +#define VXS_HELPER 0x1000 +#define VXS_RELEASED 0x8000 + + +extern void claim_vx_info(struct vx_info *, struct task_struct *); +extern void release_vx_info(struct vx_info *, struct task_struct *); + +extern struct vx_info *lookup_vx_info(int); +extern struct vx_info *lookup_or_create_vx_info(int); + +extern int get_xid_list(int, unsigned int *, int); +extern int xid_is_hashed(xid_t); + +extern int vx_migrate_task(struct task_struct *, struct vx_info *, int); + +extern long vs_state_change(struct vx_info *, unsigned int); + + +#endif /* __KERNEL__ */ +#endif /* _VX_CONTEXT_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/cvirt_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/cvirt_cmd.h --- linux-2.6.27.15/include/linux/vserver/cvirt_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/cvirt_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,53 @@ +#ifndef _VX_CVIRT_CMD_H +#define _VX_CVIRT_CMD_H + + +/* virtual host info name commands */ + +#define VCMD_set_vhi_name VC_CMD(VHOST, 1, 0) +#define VCMD_get_vhi_name VC_CMD(VHOST, 2, 0) + +struct vcmd_vhi_name_v0 { + uint32_t field; + char name[65]; +}; + + +enum vhi_name_field { + VHIN_CONTEXT = 0, + VHIN_SYSNAME, + VHIN_NODENAME, + VHIN_RELEASE, + VHIN_VERSION, + VHIN_MACHINE, + VHIN_DOMAINNAME, +}; + + +#ifdef __KERNEL__ + +#include + +extern int vc_set_vhi_name(struct vx_info *, void __user *); +extern int vc_get_vhi_name(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_virt_stat VC_CMD(VSTAT, 3, 0) + +struct vcmd_virt_stat_v0 { + uint64_t offset; + uint64_t uptime; + uint32_t nr_threads; + uint32_t nr_running; + uint32_t nr_uninterruptible; + uint32_t nr_onhold; + uint32_t nr_forks; + uint32_t load[3]; +}; + +#ifdef __KERNEL__ +extern int vc_virt_stat(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_CVIRT_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/cvirt_def.h linux-2.6.27.15-g-v/include/linux/vserver/cvirt_def.h --- linux-2.6.27.15/include/linux/vserver/cvirt_def.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/cvirt_def.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,80 @@ +#ifndef _VX_CVIRT_DEF_H +#define _VX_CVIRT_DEF_H + +#include +#include +#include +#include +#include + + +struct _vx_usage_stat { + uint64_t user; + uint64_t nice; + uint64_t system; + uint64_t softirq; + uint64_t irq; + uint64_t idle; + uint64_t iowait; +}; + +struct _vx_syslog { + wait_queue_head_t log_wait; + spinlock_t logbuf_lock; /* lock for the log buffer */ + + unsigned long log_start; /* next char to be read by syslog() */ + unsigned long con_start; /* next char to be sent to consoles */ + unsigned long log_end; /* most-recently-written-char + 1 */ + unsigned long logged_chars; /* #chars since last read+clear operation */ + + char log_buf[1024]; +}; + + +/* context sub struct */ + +struct _vx_cvirt { + atomic_t nr_threads; /* number of current threads */ + atomic_t nr_running; /* number of running threads */ + atomic_t nr_uninterruptible; /* number of uninterruptible threads */ + + atomic_t nr_onhold; /* processes on hold */ + uint32_t onhold_last; /* jiffies when put on hold */ + + struct timeval bias_tv; /* time offset to the host */ + struct timespec bias_idle; + struct timespec bias_uptime; /* context creation point */ + uint64_t bias_clock; /* offset in clock_t */ + + spinlock_t load_lock; /* lock for the load averages */ + atomic_t load_updates; /* nr of load updates done so far */ + uint32_t load_last; /* last time load was calculated */ + uint32_t load[3]; /* load averages 1,5,15 */ + + atomic_t total_forks; /* number of forks so far */ + + struct _vx_syslog syslog; +}; + +struct _vx_cvirt_pc { + struct _vx_usage_stat cpustat; +}; + + +#ifdef CONFIG_VSERVER_DEBUG + +static inline void __dump_vx_cvirt(struct _vx_cvirt *cvirt) +{ + printk("\t_vx_cvirt:\n"); + printk("\t threads: %4d, %4d, %4d, %4d\n", + atomic_read(&cvirt->nr_threads), + atomic_read(&cvirt->nr_running), + atomic_read(&cvirt->nr_uninterruptible), + atomic_read(&cvirt->nr_onhold)); + /* add rest here */ + printk("\t total_forks = %d\n", atomic_read(&cvirt->total_forks)); +} + +#endif + +#endif /* _VX_CVIRT_DEF_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/cvirt.h linux-2.6.27.15-g-v/include/linux/vserver/cvirt.h --- linux-2.6.27.15/include/linux/vserver/cvirt.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/cvirt.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,20 @@ +#ifndef _VX_CVIRT_H +#define _VX_CVIRT_H + + +#ifdef __KERNEL__ + +struct timespec; + +void vx_vsi_uptime(struct timespec *, struct timespec *); + + +struct vx_info; + +void vx_update_load(struct vx_info *); + + +int vx_do_syslog(int, char __user *, int); + +#endif /* __KERNEL__ */ +#endif /* _VX_CVIRT_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/debug_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/debug_cmd.h --- linux-2.6.27.15/include/linux/vserver/debug_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/debug_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,58 @@ +#ifndef _VX_DEBUG_CMD_H +#define _VX_DEBUG_CMD_H + + +/* debug commands */ + +#define VCMD_dump_history VC_CMD(DEBUG, 1, 0) + +#define VCMD_read_history VC_CMD(DEBUG, 5, 0) +#define VCMD_read_monitor VC_CMD(DEBUG, 6, 0) + +struct vcmd_read_history_v0 { + uint32_t index; + uint32_t count; + char __user *data; +}; + +struct vcmd_read_monitor_v0 { + uint32_t index; + uint32_t count; + char __user *data; +}; + + +#ifdef __KERNEL__ + +#ifdef CONFIG_COMPAT + +#include + +struct vcmd_read_history_v0_x32 { + uint32_t index; + uint32_t count; + compat_uptr_t data_ptr; +}; + +struct vcmd_read_monitor_v0_x32 { + uint32_t index; + uint32_t count; + compat_uptr_t data_ptr; +}; + +#endif /* CONFIG_COMPAT */ + +extern int vc_dump_history(uint32_t); + +extern int vc_read_history(uint32_t, void __user *); +extern int vc_read_monitor(uint32_t, void __user *); + +#ifdef CONFIG_COMPAT + +extern int vc_read_history_x32(uint32_t, void __user *); +extern int vc_read_monitor_x32(uint32_t, void __user *); + +#endif /* CONFIG_COMPAT */ + +#endif /* __KERNEL__ */ +#endif /* _VX_DEBUG_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/debug.h linux-2.6.27.15-g-v/include/linux/vserver/debug.h --- linux-2.6.27.15/include/linux/vserver/debug.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/debug.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,127 @@ +#ifndef _VX_DEBUG_H +#define _VX_DEBUG_H + + +#define VXD_CBIT(n, m) (vx_debug_ ## n & (1 << (m))) +#define VXD_CMIN(n, m) (vx_debug_ ## n > (m)) +#define VXD_MASK(n, m) (vx_debug_ ## n & (m)) + +#define VXD_DEV(d) (d), (d)->bd_inode->i_ino, \ + imajor((d)->bd_inode), iminor((d)->bd_inode) +#define VXF_DEV "%p[%lu,%d:%d]" + + +#define vxd_path(p) \ + ({ static char _buffer[PATH_MAX]; \ + d_path(p, _buffer, sizeof(_buffer)); }) + +#define vxd_cond_path(n) \ + ((n) ? vxd_path(&(n)->path) : "" ) + + +#ifdef CONFIG_VSERVER_DEBUG + +extern unsigned int vx_debug_switch; +extern unsigned int vx_debug_xid; +extern unsigned int vx_debug_nid; +extern unsigned int vx_debug_tag; +extern unsigned int vx_debug_net; +extern unsigned int vx_debug_limit; +extern unsigned int vx_debug_cres; +extern unsigned int vx_debug_dlim; +extern unsigned int vx_debug_quota; +extern unsigned int vx_debug_cvirt; +extern unsigned int vx_debug_space; +extern unsigned int vx_debug_misc; + + +#define VX_LOGLEVEL "vxD: " +#define VX_PROC_FMT "%p: " +#define VX_PROCESS current + +#define vxdprintk(c, f, x...) \ + do { \ + if (c) \ + printk(VX_LOGLEVEL VX_PROC_FMT f "\n", \ + VX_PROCESS , ##x); \ + } while (0) + +#define vxlprintk(c, f, x...) \ + do { \ + if (c) \ + printk(VX_LOGLEVEL f " @%s:%d\n", x); \ + } while (0) + +#define vxfprintk(c, f, x...) \ + do { \ + if (c) \ + printk(VX_LOGLEVEL f " %s@%s:%d\n", x); \ + } while (0) + + +struct vx_info; + +void dump_vx_info(struct vx_info *, int); +void dump_vx_info_inactive(int); + +#else /* CONFIG_VSERVER_DEBUG */ + +#define vx_debug_switch 0 +#define vx_debug_xid 0 +#define vx_debug_nid 0 +#define vx_debug_tag 0 +#define vx_debug_net 0 +#define vx_debug_limit 0 +#define vx_debug_cres 0 +#define vx_debug_dlim 0 +#define vx_debug_cvirt 0 + +#define vxdprintk(x...) do { } while (0) +#define vxlprintk(x...) do { } while (0) +#define vxfprintk(x...) do { } while (0) + +#endif /* CONFIG_VSERVER_DEBUG */ + + +#ifdef CONFIG_VSERVER_WARN + +#define VX_WARNLEVEL KERN_WARNING "vxW: " +#define VX_WARN_TASK "[»%s«,%u:#%u|%u|%u] " +#define VX_WARN_XID "[xid #%u] " +#define VX_WARN_NID "[nid #%u] " +#define VX_WARN_TAG "[tag #%u] " + +#define vxwprintk(c, f, x...) \ + do { \ + if (c) \ + printk(VX_WARNLEVEL f "\n", ##x); \ + } while (0) + +#else /* CONFIG_VSERVER_WARN */ + +#define vxwprintk(x...) do { } while (0) + +#endif /* CONFIG_VSERVER_WARN */ + +#define vxwprintk_task(c, f, x...) \ + vxwprintk(c, VX_WARN_TASK f, \ + current->comm, current->pid, \ + current->xid, current->nid, current->tag, ##x) +#define vxwprintk_xid(c, f, x...) \ + vxwprintk(c, VX_WARN_XID f, current->xid, x) +#define vxwprintk_nid(c, f, x...) \ + vxwprintk(c, VX_WARN_NID f, current->nid, x) +#define vxwprintk_tag(c, f, x...) \ + vxwprintk(c, VX_WARN_TAG f, current->tag, x) + +#ifdef CONFIG_VSERVER_DEBUG +#define vxd_assert_lock(l) assert_spin_locked(l) +#define vxd_assert(c, f, x...) vxlprintk(!(c), \ + "assertion [" f "] failed.", ##x, __FILE__, __LINE__) +#else +#define vxd_assert_lock(l) do { } while (0) +#define vxd_assert(c, f, x...) do { } while (0) +#endif + + +#endif /* _VX_DEBUG_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/device_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/device_cmd.h --- linux-2.6.27.15/include/linux/vserver/device_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/device_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,44 @@ +#ifndef _VX_DEVICE_CMD_H +#define _VX_DEVICE_CMD_H + + +/* device vserver commands */ + +#define VCMD_set_mapping VC_CMD(DEVICE, 1, 0) +#define VCMD_unset_mapping VC_CMD(DEVICE, 2, 0) + +struct vcmd_set_mapping_v0 { + const char __user *device; + const char __user *target; + uint32_t flags; +}; + + +#ifdef __KERNEL__ + +#ifdef CONFIG_COMPAT + +#include + +struct vcmd_set_mapping_v0_x32 { + compat_uptr_t device_ptr; + compat_uptr_t target_ptr; + uint32_t flags; +}; + +#endif /* CONFIG_COMPAT */ + +#include + +extern int vc_set_mapping(struct vx_info *, void __user *); +extern int vc_unset_mapping(struct vx_info *, void __user *); + +#ifdef CONFIG_COMPAT + +extern int vc_set_mapping_x32(struct vx_info *, void __user *); +extern int vc_unset_mapping_x32(struct vx_info *, void __user *); + +#endif /* CONFIG_COMPAT */ + +#endif /* __KERNEL__ */ +#endif /* _VX_DEVICE_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/device_def.h linux-2.6.27.15-g-v/include/linux/vserver/device_def.h --- linux-2.6.27.15/include/linux/vserver/device_def.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/device_def.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,17 @@ +#ifndef _VX_DEVICE_DEF_H +#define _VX_DEVICE_DEF_H + +#include + +struct vx_dmap_target { + dev_t target; + uint32_t flags; +}; + +struct _vx_device { +#ifdef CONFIG_VSERVER_DEVICE + struct vx_dmap_target targets[2]; +#endif +}; + +#endif /* _VX_DEVICE_DEF_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/device.h linux-2.6.27.15-g-v/include/linux/vserver/device.h --- linux-2.6.27.15/include/linux/vserver/device.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/device.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,15 @@ +#ifndef _VX_DEVICE_H +#define _VX_DEVICE_H + + +#define DATTR_CREATE 0x00000001 +#define DATTR_OPEN 0x00000002 + +#define DATTR_REMAP 0x00000010 + +#define DATTR_MASK 0x00000013 + + +#else /* _VX_DEVICE_H */ +#warning duplicate inclusion +#endif /* _VX_DEVICE_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/dlimit_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/dlimit_cmd.h --- linux-2.6.27.15/include/linux/vserver/dlimit_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/dlimit_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,74 @@ +#ifndef _VX_DLIMIT_CMD_H +#define _VX_DLIMIT_CMD_H + + +/* dlimit vserver commands */ + +#define VCMD_add_dlimit VC_CMD(DLIMIT, 1, 0) +#define VCMD_rem_dlimit VC_CMD(DLIMIT, 2, 0) + +#define VCMD_set_dlimit VC_CMD(DLIMIT, 5, 0) +#define VCMD_get_dlimit VC_CMD(DLIMIT, 6, 0) + +struct vcmd_ctx_dlimit_base_v0 { + const char __user *name; + uint32_t flags; +}; + +struct vcmd_ctx_dlimit_v0 { + const char __user *name; + uint32_t space_used; /* used space in kbytes */ + uint32_t space_total; /* maximum space in kbytes */ + uint32_t inodes_used; /* used inodes */ + uint32_t inodes_total; /* maximum inodes */ + uint32_t reserved; /* reserved for root in % */ + uint32_t flags; +}; + +#define CDLIM_UNSET ((uint32_t)0UL) +#define CDLIM_INFINITY ((uint32_t)~0UL) +#define CDLIM_KEEP ((uint32_t)~1UL) + +#ifdef __KERNEL__ + +#ifdef CONFIG_COMPAT + +#include + +struct vcmd_ctx_dlimit_base_v0_x32 { + compat_uptr_t name_ptr; + uint32_t flags; +}; + +struct vcmd_ctx_dlimit_v0_x32 { + compat_uptr_t name_ptr; + uint32_t space_used; /* used space in kbytes */ + uint32_t space_total; /* maximum space in kbytes */ + uint32_t inodes_used; /* used inodes */ + uint32_t inodes_total; /* maximum inodes */ + uint32_t reserved; /* reserved for root in % */ + uint32_t flags; +}; + +#endif /* CONFIG_COMPAT */ + +#include + +extern int vc_add_dlimit(uint32_t, void __user *); +extern int vc_rem_dlimit(uint32_t, void __user *); + +extern int vc_set_dlimit(uint32_t, void __user *); +extern int vc_get_dlimit(uint32_t, void __user *); + +#ifdef CONFIG_COMPAT + +extern int vc_add_dlimit_x32(uint32_t, void __user *); +extern int vc_rem_dlimit_x32(uint32_t, void __user *); + +extern int vc_set_dlimit_x32(uint32_t, void __user *); +extern int vc_get_dlimit_x32(uint32_t, void __user *); + +#endif /* CONFIG_COMPAT */ + +#endif /* __KERNEL__ */ +#endif /* _VX_DLIMIT_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/dlimit.h linux-2.6.27.15-g-v/include/linux/vserver/dlimit.h --- linux-2.6.27.15/include/linux/vserver/dlimit.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/dlimit.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,54 @@ +#ifndef _VX_DLIMIT_H +#define _VX_DLIMIT_H + +#include "switch.h" + + +#ifdef __KERNEL__ + +/* keep in sync with CDLIM_INFINITY */ + +#define DLIM_INFINITY (~0ULL) + +#include +#include + +struct super_block; + +struct dl_info { + struct hlist_node dl_hlist; /* linked list of contexts */ + struct rcu_head dl_rcu; /* the rcu head */ + tag_t dl_tag; /* context tag */ + atomic_t dl_usecnt; /* usage count */ + atomic_t dl_refcnt; /* reference count */ + + struct super_block *dl_sb; /* associated superblock */ + + spinlock_t dl_lock; /* protect the values */ + + unsigned long long dl_space_used; /* used space in bytes */ + unsigned long long dl_space_total; /* maximum space in bytes */ + unsigned long dl_inodes_used; /* used inodes */ + unsigned long dl_inodes_total; /* maximum inodes */ + + unsigned int dl_nrlmult; /* non root limit mult */ +}; + +struct rcu_head; + +extern void rcu_free_dl_info(struct rcu_head *); +extern void unhash_dl_info(struct dl_info *); + +extern struct dl_info *locate_dl_info(struct super_block *, tag_t); + + +struct kstatfs; + +extern void vx_vsi_statfs(struct super_block *, struct kstatfs *); + +typedef uint64_t dlsize_t; + +#endif /* __KERNEL__ */ +#else /* _VX_DLIMIT_H */ +#warning duplicate inclusion +#endif /* _VX_DLIMIT_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/global.h linux-2.6.27.15-g-v/include/linux/vserver/global.h --- linux-2.6.27.15/include/linux/vserver/global.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/global.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,20 @@ +#ifndef _VX_GLOBAL_H +#define _VX_GLOBAL_H + + +extern atomic_t vx_global_ctotal; +extern atomic_t vx_global_cactive; + +extern atomic_t nx_global_ctotal; +extern atomic_t nx_global_cactive; + +extern atomic_t vs_global_nsproxy; +extern atomic_t vs_global_fs; +extern atomic_t vs_global_mnt_ns; +extern atomic_t vs_global_uts_ns; +extern atomic_t vs_global_ipc_ns; +extern atomic_t vs_global_user_ns; +extern atomic_t vs_global_pid_ns; + + +#endif /* _VX_GLOBAL_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/history.h linux-2.6.27.15-g-v/include/linux/vserver/history.h --- linux-2.6.27.15/include/linux/vserver/history.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/history.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,197 @@ +#ifndef _VX_HISTORY_H +#define _VX_HISTORY_H + + +enum { + VXH_UNUSED = 0, + VXH_THROW_OOPS = 1, + + VXH_GET_VX_INFO, + VXH_PUT_VX_INFO, + VXH_INIT_VX_INFO, + VXH_SET_VX_INFO, + VXH_CLR_VX_INFO, + VXH_CLAIM_VX_INFO, + VXH_RELEASE_VX_INFO, + VXH_ALLOC_VX_INFO, + VXH_DEALLOC_VX_INFO, + VXH_HASH_VX_INFO, + VXH_UNHASH_VX_INFO, + VXH_LOC_VX_INFO, + VXH_LOOKUP_VX_INFO, + VXH_CREATE_VX_INFO, +}; + +struct _vxhe_vxi { + struct vx_info *ptr; + unsigned xid; + unsigned usecnt; + unsigned tasks; +}; + +struct _vxhe_set_clr { + void *data; +}; + +struct _vxhe_loc_lookup { + unsigned arg; +}; + +struct _vx_hist_entry { + void *loc; + unsigned short seq; + unsigned short type; + struct _vxhe_vxi vxi; + union { + struct _vxhe_set_clr sc; + struct _vxhe_loc_lookup ll; + }; +}; + +#ifdef CONFIG_VSERVER_HISTORY + +extern unsigned volatile int vxh_active; + +struct _vx_hist_entry *vxh_advance(void *loc); + + +static inline +void __vxh_copy_vxi(struct _vx_hist_entry *entry, struct vx_info *vxi) +{ + entry->vxi.ptr = vxi; + if (vxi) { + entry->vxi.usecnt = atomic_read(&vxi->vx_usecnt); + entry->vxi.tasks = atomic_read(&vxi->vx_tasks); + entry->vxi.xid = vxi->vx_id; + } +} + + +#define __HERE__ current_text_addr() + +#define __VXH_BODY(__type, __data, __here) \ + struct _vx_hist_entry *entry; \ + \ + preempt_disable(); \ + entry = vxh_advance(__here); \ + __data; \ + entry->type = __type; \ + preempt_enable(); + + + /* pass vxi only */ + +#define __VXH_SMPL \ + __vxh_copy_vxi(entry, vxi) + +static inline +void __vxh_smpl(struct vx_info *vxi, int __type, void *__here) +{ + __VXH_BODY(__type, __VXH_SMPL, __here) +} + + /* pass vxi and data (void *) */ + +#define __VXH_DATA \ + __vxh_copy_vxi(entry, vxi); \ + entry->sc.data = data + +static inline +void __vxh_data(struct vx_info *vxi, void *data, + int __type, void *__here) +{ + __VXH_BODY(__type, __VXH_DATA, __here) +} + + /* pass vxi and arg (long) */ + +#define __VXH_LONG \ + __vxh_copy_vxi(entry, vxi); \ + entry->ll.arg = arg + +static inline +void __vxh_long(struct vx_info *vxi, long arg, + int __type, void *__here) +{ + __VXH_BODY(__type, __VXH_LONG, __here) +} + + +static inline +void __vxh_throw_oops(void *__here) +{ + __VXH_BODY(VXH_THROW_OOPS, {}, __here); + /* prevent further acquisition */ + vxh_active = 0; +} + + +#define vxh_throw_oops() __vxh_throw_oops(__HERE__); + +#define __vxh_get_vx_info(v, h) __vxh_smpl(v, VXH_GET_VX_INFO, h); +#define __vxh_put_vx_info(v, h) __vxh_smpl(v, VXH_PUT_VX_INFO, h); + +#define __vxh_init_vx_info(v, d, h) \ + __vxh_data(v, d, VXH_INIT_VX_INFO, h); +#define __vxh_set_vx_info(v, d, h) \ + __vxh_data(v, d, VXH_SET_VX_INFO, h); +#define __vxh_clr_vx_info(v, d, h) \ + __vxh_data(v, d, VXH_CLR_VX_INFO, h); + +#define __vxh_claim_vx_info(v, d, h) \ + __vxh_data(v, d, VXH_CLAIM_VX_INFO, h); +#define __vxh_release_vx_info(v, d, h) \ + __vxh_data(v, d, VXH_RELEASE_VX_INFO, h); + +#define vxh_alloc_vx_info(v) \ + __vxh_smpl(v, VXH_ALLOC_VX_INFO, __HERE__); +#define vxh_dealloc_vx_info(v) \ + __vxh_smpl(v, VXH_DEALLOC_VX_INFO, __HERE__); + +#define vxh_hash_vx_info(v) \ + __vxh_smpl(v, VXH_HASH_VX_INFO, __HERE__); +#define vxh_unhash_vx_info(v) \ + __vxh_smpl(v, VXH_UNHASH_VX_INFO, __HERE__); + +#define vxh_loc_vx_info(v, l) \ + __vxh_long(v, l, VXH_LOC_VX_INFO, __HERE__); +#define vxh_lookup_vx_info(v, l) \ + __vxh_long(v, l, VXH_LOOKUP_VX_INFO, __HERE__); +#define vxh_create_vx_info(v, l) \ + __vxh_long(v, l, VXH_CREATE_VX_INFO, __HERE__); + +extern void vxh_dump_history(void); + + +#else /* CONFIG_VSERVER_HISTORY */ + +#define __HERE__ 0 + +#define vxh_throw_oops() do { } while (0) + +#define __vxh_get_vx_info(v, h) do { } while (0) +#define __vxh_put_vx_info(v, h) do { } while (0) + +#define __vxh_init_vx_info(v, d, h) do { } while (0) +#define __vxh_set_vx_info(v, d, h) do { } while (0) +#define __vxh_clr_vx_info(v, d, h) do { } while (0) + +#define __vxh_claim_vx_info(v, d, h) do { } while (0) +#define __vxh_release_vx_info(v, d, h) do { } while (0) + +#define vxh_alloc_vx_info(v) do { } while (0) +#define vxh_dealloc_vx_info(v) do { } while (0) + +#define vxh_hash_vx_info(v) do { } while (0) +#define vxh_unhash_vx_info(v) do { } while (0) + +#define vxh_loc_vx_info(v, l) do { } while (0) +#define vxh_lookup_vx_info(v, l) do { } while (0) +#define vxh_create_vx_info(v, l) do { } while (0) + +#define vxh_dump_history() do { } while (0) + + +#endif /* CONFIG_VSERVER_HISTORY */ + +#endif /* _VX_HISTORY_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/inode_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/inode_cmd.h --- linux-2.6.27.15/include/linux/vserver/inode_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/inode_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,59 @@ +#ifndef _VX_INODE_CMD_H +#define _VX_INODE_CMD_H + + +/* inode vserver commands */ + +#define VCMD_get_iattr VC_CMD(INODE, 1, 1) +#define VCMD_set_iattr VC_CMD(INODE, 2, 1) + +#define VCMD_fget_iattr VC_CMD(INODE, 3, 0) +#define VCMD_fset_iattr VC_CMD(INODE, 4, 0) + +struct vcmd_ctx_iattr_v1 { + const char __user *name; + uint32_t tag; + uint32_t flags; + uint32_t mask; +}; + +struct vcmd_ctx_fiattr_v0 { + uint32_t tag; + uint32_t flags; + uint32_t mask; +}; + + +#ifdef __KERNEL__ + + +#ifdef CONFIG_COMPAT + +#include + +struct vcmd_ctx_iattr_v1_x32 { + compat_uptr_t name_ptr; + uint32_t tag; + uint32_t flags; + uint32_t mask; +}; + +#endif /* CONFIG_COMPAT */ + +#include + +extern int vc_get_iattr(void __user *); +extern int vc_set_iattr(void __user *); + +extern int vc_fget_iattr(uint32_t, void __user *); +extern int vc_fset_iattr(uint32_t, void __user *); + +#ifdef CONFIG_COMPAT + +extern int vc_get_iattr_x32(void __user *); +extern int vc_set_iattr_x32(void __user *); + +#endif /* CONFIG_COMPAT */ + +#endif /* __KERNEL__ */ +#endif /* _VX_INODE_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/inode.h linux-2.6.27.15-g-v/include/linux/vserver/inode.h --- linux-2.6.27.15/include/linux/vserver/inode.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/inode.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,38 @@ +#ifndef _VX_INODE_H +#define _VX_INODE_H + + +#define IATTR_TAG 0x01000000 + +#define IATTR_ADMIN 0x00000001 +#define IATTR_WATCH 0x00000002 +#define IATTR_HIDE 0x00000004 +#define IATTR_FLAGS 0x00000007 + +#define IATTR_BARRIER 0x00010000 +#define IATTR_IXUNLINK 0x00020000 +#define IATTR_IMMUTABLE 0x00040000 + +#ifdef __KERNEL__ + + +#ifdef CONFIG_VSERVER_PROC_SECURE +#define IATTR_PROC_DEFAULT ( IATTR_ADMIN | IATTR_HIDE ) +#define IATTR_PROC_SYMLINK ( IATTR_ADMIN ) +#else +#define IATTR_PROC_DEFAULT ( IATTR_ADMIN ) +#define IATTR_PROC_SYMLINK ( IATTR_ADMIN ) +#endif + +#define vx_hide_check(c, m) (((m) & IATTR_HIDE) ? vx_check(c, m) : 1) + +#endif /* __KERNEL__ */ + +/* inode ioctls */ + +#define FIOC_GETXFLG _IOR('x', 5, long) +#define FIOC_SETXFLG _IOW('x', 6, long) + +#else /* _VX_INODE_H */ +#warning duplicate inclusion +#endif /* _VX_INODE_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/Kbuild linux-2.6.27.15-g-v/include/linux/vserver/Kbuild --- linux-2.6.27.15/include/linux/vserver/Kbuild 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/Kbuild 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,8 @@ + +unifdef-y += context_cmd.h network_cmd.h space_cmd.h \ + cacct_cmd.h cvirt_cmd.h limit_cmd.h dlimit_cmd.h \ + inode_cmd.h tag_cmd.h sched_cmd.h signal_cmd.h \ + debug_cmd.h device_cmd.h + +unifdef-y += switch.h network.h monitor.h inode.h device.h + diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/limit_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/limit_cmd.h --- linux-2.6.27.15/include/linux/vserver/limit_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/limit_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,69 @@ +#ifndef _VX_LIMIT_CMD_H +#define _VX_LIMIT_CMD_H + + +/* rlimit vserver commands */ + +#define VCMD_get_rlimit VC_CMD(RLIMIT, 1, 0) +#define VCMD_set_rlimit VC_CMD(RLIMIT, 2, 0) +#define VCMD_get_rlimit_mask VC_CMD(RLIMIT, 3, 0) +#define VCMD_reset_minmax VC_CMD(RLIMIT, 9, 0) + +struct vcmd_ctx_rlimit_v0 { + uint32_t id; + uint64_t minimum; + uint64_t softlimit; + uint64_t maximum; +}; + +struct vcmd_ctx_rlimit_mask_v0 { + uint32_t minimum; + uint32_t softlimit; + uint32_t maximum; +}; + +#define VCMD_rlimit_stat VC_CMD(VSTAT, 1, 0) + +struct vcmd_rlimit_stat_v0 { + uint32_t id; + uint32_t hits; + uint64_t value; + uint64_t minimum; + uint64_t maximum; +}; + +#define CRLIM_UNSET (0ULL) +#define CRLIM_INFINITY (~0ULL) +#define CRLIM_KEEP (~1ULL) + +#ifdef __KERNEL__ + +#ifdef CONFIG_IA32_EMULATION + +struct vcmd_ctx_rlimit_v0_x32 { + uint32_t id; + uint64_t minimum; + uint64_t softlimit; + uint64_t maximum; +} __attribute__ ((packed)); + +#endif /* CONFIG_IA32_EMULATION */ + +#include + +extern int vc_get_rlimit_mask(uint32_t, void __user *); +extern int vc_get_rlimit(struct vx_info *, void __user *); +extern int vc_set_rlimit(struct vx_info *, void __user *); +extern int vc_reset_minmax(struct vx_info *, void __user *); + +extern int vc_rlimit_stat(struct vx_info *, void __user *); + +#ifdef CONFIG_IA32_EMULATION + +extern int vc_get_rlimit_x32(struct vx_info *, void __user *); +extern int vc_set_rlimit_x32(struct vx_info *, void __user *); + +#endif /* CONFIG_IA32_EMULATION */ + +#endif /* __KERNEL__ */ +#endif /* _VX_LIMIT_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/limit_def.h linux-2.6.27.15-g-v/include/linux/vserver/limit_def.h --- linux-2.6.27.15/include/linux/vserver/limit_def.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/limit_def.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,47 @@ +#ifndef _VX_LIMIT_DEF_H +#define _VX_LIMIT_DEF_H + +#include +#include + +#include "limit.h" + + +struct _vx_res_limit { + rlim_t soft; /* Context soft limit */ + rlim_t hard; /* Context hard limit */ + + rlim_atomic_t rcur; /* Current value */ + rlim_t rmin; /* Context minimum */ + rlim_t rmax; /* Context maximum */ + + atomic_t lhit; /* Limit hits */ +}; + +/* context sub struct */ + +struct _vx_limit { + struct _vx_res_limit res[NUM_LIMITS]; +}; + +#ifdef CONFIG_VSERVER_DEBUG + +static inline void __dump_vx_limit(struct _vx_limit *limit) +{ + int i; + + printk("\t_vx_limit:"); + for (i = 0; i < NUM_LIMITS; i++) { + printk("\t [%2d] = %8lu %8lu/%8lu, %8ld/%8ld, %8d\n", + i, (unsigned long)__rlim_get(limit, i), + (unsigned long)__rlim_rmin(limit, i), + (unsigned long)__rlim_rmax(limit, i), + (long)__rlim_soft(limit, i), + (long)__rlim_hard(limit, i), + atomic_read(&__rlim_lhit(limit, i))); + } +} + +#endif + +#endif /* _VX_LIMIT_DEF_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/limit.h linux-2.6.27.15-g-v/include/linux/vserver/limit.h --- linux-2.6.27.15/include/linux/vserver/limit.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/limit.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,70 @@ +#ifndef _VX_LIMIT_H +#define _VX_LIMIT_H + +#define VLIMIT_NSOCK 16 +#define VLIMIT_OPENFD 17 +#define VLIMIT_ANON 18 +#define VLIMIT_SHMEM 19 +#define VLIMIT_SEMARY 20 +#define VLIMIT_NSEMS 21 +#define VLIMIT_DENTRY 22 +#define VLIMIT_MAPPED 23 + + +#ifdef __KERNEL__ + +#define VLIM_NOCHECK ((1L << VLIMIT_DENTRY) | (1L << RLIMIT_RSS)) + +/* keep in sync with CRLIM_INFINITY */ + +#define VLIM_INFINITY (~0ULL) + +#include +#include + +#ifndef RLIM_INFINITY +#warning RLIM_INFINITY is undefined +#endif + +#define __rlim_val(l, r, v) ((l)->res[r].v) + +#define __rlim_soft(l, r) __rlim_val(l, r, soft) +#define __rlim_hard(l, r) __rlim_val(l, r, hard) + +#define __rlim_rcur(l, r) __rlim_val(l, r, rcur) +#define __rlim_rmin(l, r) __rlim_val(l, r, rmin) +#define __rlim_rmax(l, r) __rlim_val(l, r, rmax) + +#define __rlim_lhit(l, r) __rlim_val(l, r, lhit) +#define __rlim_hit(l, r) atomic_inc(&__rlim_lhit(l, r)) + +typedef atomic_long_t rlim_atomic_t; +typedef unsigned long rlim_t; + +#define __rlim_get(l, r) atomic_long_read(&__rlim_rcur(l, r)) +#define __rlim_set(l, r, v) atomic_long_set(&__rlim_rcur(l, r), v) +#define __rlim_inc(l, r) atomic_long_inc(&__rlim_rcur(l, r)) +#define __rlim_dec(l, r) atomic_long_dec(&__rlim_rcur(l, r)) +#define __rlim_add(l, r, v) atomic_long_add(v, &__rlim_rcur(l, r)) +#define __rlim_sub(l, r, v) atomic_long_sub(v, &__rlim_rcur(l, r)) + + +#if (RLIM_INFINITY == VLIM_INFINITY) +#define VX_VLIM(r) ((long long)(long)(r)) +#define VX_RLIM(v) ((rlim_t)(v)) +#else +#define VX_VLIM(r) (((r) == RLIM_INFINITY) \ + ? VLIM_INFINITY : (long long)(r)) +#define VX_RLIM(v) (((v) == VLIM_INFINITY) \ + ? RLIM_INFINITY : (rlim_t)(v)) +#endif + +struct sysinfo; + +void vx_vsi_meminfo(struct sysinfo *); +void vx_vsi_swapinfo(struct sysinfo *); + +#define NUM_LIMITS 24 + +#endif /* __KERNEL__ */ +#endif /* _VX_LIMIT_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/limit_int.h linux-2.6.27.15-g-v/include/linux/vserver/limit_int.h --- linux-2.6.27.15/include/linux/vserver/limit_int.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/limit_int.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,198 @@ +#ifndef _VX_LIMIT_INT_H +#define _VX_LIMIT_INT_H + +#include "context.h" + +#ifdef __KERNEL__ + +#define VXD_RCRES_COND(r) VXD_CBIT(cres, r) +#define VXD_RLIMIT_COND(r) VXD_CBIT(limit, r) + +extern const char *vlimit_name[NUM_LIMITS]; + +static inline void __vx_acc_cres(struct vx_info *vxi, + int res, int dir, void *_data, char *_file, int _line) +{ + if (VXD_RCRES_COND(res)) + vxlprintk(1, "vx_acc_cres[%5d,%s,%2d]: %5ld%s (%p)", + (vxi ? vxi->vx_id : -1), vlimit_name[res], res, + (vxi ? (long)__rlim_get(&vxi->limit, res) : 0), + (dir > 0) ? "++" : "--", _data, _file, _line); + if (!vxi) + return; + + if (dir > 0) + __rlim_inc(&vxi->limit, res); + else + __rlim_dec(&vxi->limit, res); +} + +static inline void __vx_add_cres(struct vx_info *vxi, + int res, int amount, void *_data, char *_file, int _line) +{ + if (VXD_RCRES_COND(res)) + vxlprintk(1, "vx_add_cres[%5d,%s,%2d]: %5ld += %5d (%p)", + (vxi ? vxi->vx_id : -1), vlimit_name[res], res, + (vxi ? (long)__rlim_get(&vxi->limit, res) : 0), + amount, _data, _file, _line); + if (amount == 0) + return; + if (!vxi) + return; + __rlim_add(&vxi->limit, res, amount); +} + +static inline +int __vx_cres_adjust_max(struct _vx_limit *limit, int res, rlim_t value) +{ + int cond = (value > __rlim_rmax(limit, res)); + + if (cond) + __rlim_rmax(limit, res) = value; + return cond; +} + +static inline +int __vx_cres_adjust_min(struct _vx_limit *limit, int res, rlim_t value) +{ + int cond = (value < __rlim_rmin(limit, res)); + + if (cond) + __rlim_rmin(limit, res) = value; + return cond; +} + +static inline +void __vx_cres_fixup(struct _vx_limit *limit, int res, rlim_t value) +{ + if (!__vx_cres_adjust_max(limit, res, value)) + __vx_cres_adjust_min(limit, res, value); +} + + +/* return values: + +1 ... no limit hit + -1 ... over soft limit + 0 ... over hard limit */ + +static inline int __vx_cres_avail(struct vx_info *vxi, + int res, int num, char *_file, int _line) +{ + struct _vx_limit *limit; + rlim_t value; + + if (VXD_RLIMIT_COND(res)) + vxlprintk(1, "vx_cres_avail[%5d,%s,%2d]: %5ld/%5ld > %5ld + %5d", + (vxi ? vxi->vx_id : -1), vlimit_name[res], res, + (vxi ? (long)__rlim_soft(&vxi->limit, res) : -1), + (vxi ? (long)__rlim_hard(&vxi->limit, res) : -1), + (vxi ? (long)__rlim_get(&vxi->limit, res) : 0), + num, _file, _line); + if (!vxi) + return 1; + + limit = &vxi->limit; + value = __rlim_get(limit, res); + + if (!__vx_cres_adjust_max(limit, res, value)) + __vx_cres_adjust_min(limit, res, value); + + if (num == 0) + return 1; + + if (__rlim_soft(limit, res) == RLIM_INFINITY) + return -1; + if (value + num <= __rlim_soft(limit, res)) + return -1; + + if (__rlim_hard(limit, res) == RLIM_INFINITY) + return 1; + if (value + num <= __rlim_hard(limit, res)) + return 1; + + __rlim_hit(limit, res); + return 0; +} + + +static const int VLA_RSS[] = { RLIMIT_RSS, VLIMIT_ANON, VLIMIT_MAPPED, 0 }; + +static inline +rlim_t __vx_cres_array_sum(struct _vx_limit *limit, const int *array) +{ + rlim_t value, sum = 0; + int res; + + while ((res = *array++)) { + value = __rlim_get(limit, res); + __vx_cres_fixup(limit, res, value); + sum += value; + } + return sum; +} + +static inline +rlim_t __vx_cres_array_fixup(struct _vx_limit *limit, const int *array) +{ + rlim_t value = __vx_cres_array_sum(limit, array + 1); + int res = *array; + + if (value == __rlim_get(limit, res)) + return value; + + __rlim_set(limit, res, value); + /* now adjust min/max */ + if (!__vx_cres_adjust_max(limit, res, value)) + __vx_cres_adjust_min(limit, res, value); + + return value; +} + +static inline int __vx_cres_array_avail(struct vx_info *vxi, + const int *array, int num, char *_file, int _line) +{ + struct _vx_limit *limit; + rlim_t value = 0; + int res; + + if (num == 0) + return 1; + if (!vxi) + return 1; + + limit = &vxi->limit; + res = *array; + value = __vx_cres_array_sum(limit, array + 1); + + __rlim_set(limit, res, value); + __vx_cres_fixup(limit, res, value); + + return __vx_cres_avail(vxi, res, num, _file, _line); +} + + +static inline void vx_limit_fixup(struct _vx_limit *limit, int id) +{ + rlim_t value; + int res; + + /* complex resources first */ + if ((id < 0) || (id == RLIMIT_RSS)) + __vx_cres_array_fixup(limit, VLA_RSS); + + for (res = 0; res < NUM_LIMITS; res++) { + if ((id > 0) && (res != id)) + continue; + + value = __rlim_get(limit, res); + __vx_cres_fixup(limit, res, value); + + /* not supposed to happen, maybe warn? */ + if (__rlim_rmax(limit, res) > __rlim_hard(limit, res)) + __rlim_rmax(limit, res) = __rlim_hard(limit, res); + } +} + + +#endif /* __KERNEL__ */ +#endif /* _VX_LIMIT_INT_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/monitor.h linux-2.6.27.15-g-v/include/linux/vserver/monitor.h --- linux-2.6.27.15/include/linux/vserver/monitor.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/monitor.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,96 @@ +#ifndef _VX_MONITOR_H +#define _VX_MONITOR_H + +#include + +enum { + VXM_UNUSED = 0, + + VXM_SYNC = 0x10, + + VXM_UPDATE = 0x20, + VXM_UPDATE_1, + VXM_UPDATE_2, + + VXM_RQINFO_1 = 0x24, + VXM_RQINFO_2, + + VXM_ACTIVATE = 0x40, + VXM_DEACTIVATE, + VXM_IDLE, + + VXM_HOLD = 0x44, + VXM_UNHOLD, + + VXM_MIGRATE = 0x48, + VXM_RESCHED, + + /* all other bits are flags */ + VXM_SCHED = 0x80, +}; + +struct _vxm_update_1 { + uint32_t tokens_max; + uint32_t fill_rate; + uint32_t interval; +}; + +struct _vxm_update_2 { + uint32_t tokens_min; + uint32_t fill_rate; + uint32_t interval; +}; + +struct _vxm_rqinfo_1 { + uint16_t running; + uint16_t onhold; + uint16_t iowait; + uint16_t uintr; + uint32_t idle_tokens; +}; + +struct _vxm_rqinfo_2 { + uint32_t norm_time; + uint32_t idle_time; + uint32_t idle_skip; +}; + +struct _vxm_sched { + uint32_t tokens; + uint32_t norm_time; + uint32_t idle_time; +}; + +struct _vxm_task { + uint16_t pid; + uint16_t state; +}; + +struct _vxm_event { + uint32_t jif; + union { + uint32_t seq; + uint32_t sec; + }; + union { + uint32_t tokens; + uint32_t nsec; + struct _vxm_task tsk; + }; +}; + +struct _vx_mon_entry { + uint16_t type; + uint16_t xid; + union { + struct _vxm_event ev; + struct _vxm_sched sd; + struct _vxm_update_1 u1; + struct _vxm_update_2 u2; + struct _vxm_rqinfo_1 q1; + struct _vxm_rqinfo_2 q2; + }; +}; + + +#endif /* _VX_MONITOR_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/network_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/network_cmd.h --- linux-2.6.27.15/include/linux/vserver/network_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/network_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,150 @@ +#ifndef _VX_NETWORK_CMD_H +#define _VX_NETWORK_CMD_H + + +/* vinfo commands */ + +#define VCMD_task_nid VC_CMD(VINFO, 2, 0) + +#ifdef __KERNEL__ +extern int vc_task_nid(uint32_t); + +#endif /* __KERNEL__ */ + +#define VCMD_nx_info VC_CMD(VINFO, 6, 0) + +struct vcmd_nx_info_v0 { + uint32_t nid; + /* more to come */ +}; + +#ifdef __KERNEL__ +extern int vc_nx_info(struct nx_info *, void __user *); + +#endif /* __KERNEL__ */ + +#include +#include + +#define VCMD_net_create_v0 VC_CMD(VNET, 1, 0) +#define VCMD_net_create VC_CMD(VNET, 1, 1) + +struct vcmd_net_create { + uint64_t flagword; +}; + +#define VCMD_net_migrate VC_CMD(NETMIG, 1, 0) + +#define VCMD_net_add VC_CMD(NETALT, 1, 0) +#define VCMD_net_remove VC_CMD(NETALT, 2, 0) + +struct vcmd_net_addr_v0 { + uint16_t type; + uint16_t count; + struct in_addr ip[4]; + struct in_addr mask[4]; +}; + +#define VCMD_net_add_ipv4 VC_CMD(NETALT, 1, 1) +#define VCMD_net_remove_ipv4 VC_CMD(NETALT, 2, 1) + +struct vcmd_net_addr_ipv4_v1 { + uint16_t type; + uint16_t flags; + struct in_addr ip; + struct in_addr mask; +}; + +#define VCMD_net_add_ipv6 VC_CMD(NETALT, 3, 1) +#define VCMD_net_remove_ipv6 VC_CMD(NETALT, 4, 1) + +struct vcmd_net_addr_ipv6_v1 { + uint16_t type; + uint16_t flags; + uint32_t prefix; + struct in6_addr ip; + struct in6_addr mask; +}; + +#define VCMD_add_match_ipv4 VC_CMD(NETALT, 5, 0) +#define VCMD_get_match_ipv4 VC_CMD(NETALT, 6, 0) + +struct vcmd_match_ipv4_v0 { + uint16_t type; + uint16_t flags; + uint16_t parent; + uint16_t prefix; + struct in_addr ip; + struct in_addr ip2; + struct in_addr mask; +}; + +#define VCMD_add_match_ipv6 VC_CMD(NETALT, 7, 0) +#define VCMD_get_match_ipv6 VC_CMD(NETALT, 8, 0) + +struct vcmd_match_ipv6_v0 { + uint16_t type; + uint16_t flags; + uint16_t parent; + uint16_t prefix; + struct in6_addr ip; + struct in6_addr ip2; + struct in6_addr mask; +}; + + +#ifdef __KERNEL__ +extern int vc_net_create(uint32_t, void __user *); +extern int vc_net_migrate(struct nx_info *, void __user *); + +extern int vc_net_add(struct nx_info *, void __user *); +extern int vc_net_remove(struct nx_info *, void __user *); + +extern int vc_net_add_ipv4(struct nx_info *, void __user *); +extern int vc_net_remove_ipv4(struct nx_info *, void __user *); + +extern int vc_net_add_ipv6(struct nx_info *, void __user *); +extern int vc_net_remove_ipv6(struct nx_info *, void __user *); + +extern int vc_add_match_ipv4(struct nx_info *, void __user *); +extern int vc_get_match_ipv4(struct nx_info *, void __user *); + +extern int vc_add_match_ipv6(struct nx_info *, void __user *); +extern int vc_get_match_ipv6(struct nx_info *, void __user *); + +#endif /* __KERNEL__ */ + + +/* flag commands */ + +#define VCMD_get_nflags VC_CMD(FLAGS, 5, 0) +#define VCMD_set_nflags VC_CMD(FLAGS, 6, 0) + +struct vcmd_net_flags_v0 { + uint64_t flagword; + uint64_t mask; +}; + +#ifdef __KERNEL__ +extern int vc_get_nflags(struct nx_info *, void __user *); +extern int vc_set_nflags(struct nx_info *, void __user *); + +#endif /* __KERNEL__ */ + + +/* network caps commands */ + +#define VCMD_get_ncaps VC_CMD(FLAGS, 7, 0) +#define VCMD_set_ncaps VC_CMD(FLAGS, 8, 0) + +struct vcmd_net_caps_v0 { + uint64_t ncaps; + uint64_t cmask; +}; + +#ifdef __KERNEL__ +extern int vc_get_ncaps(struct nx_info *, void __user *); +extern int vc_set_ncaps(struct nx_info *, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_CONTEXT_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/network.h linux-2.6.27.15-g-v/include/linux/vserver/network.h --- linux-2.6.27.15/include/linux/vserver/network.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/network.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,146 @@ +#ifndef _VX_NETWORK_H +#define _VX_NETWORK_H + +#include + + +#define MAX_N_CONTEXT 65535 /* Arbitrary limit */ + + +/* network flags */ + +#define NXF_INFO_PRIVATE 0x00000008 + +#define NXF_SINGLE_IP 0x00000100 +#define NXF_LBACK_REMAP 0x00000200 +#define NXF_LBACK_ALLOW 0x00000400 + +#define NXF_HIDE_NETIF 0x02000000 +#define NXF_HIDE_LBACK 0x04000000 + +#define NXF_STATE_SETUP (1ULL << 32) +#define NXF_STATE_ADMIN (1ULL << 34) + +#define NXF_SC_HELPER (1ULL << 36) +#define NXF_PERSISTENT (1ULL << 38) + +#define NXF_ONE_TIME (0x0005ULL << 32) + + +#define NXF_INIT_SET (__nxf_init_set()) + +static inline uint64_t __nxf_init_set(void) { + return NXF_STATE_ADMIN +#ifdef CONFIG_VSERVER_AUTO_LBACK + | NXF_LBACK_REMAP + | NXF_HIDE_LBACK +#endif +#ifdef CONFIG_VSERVER_AUTO_SINGLE + | NXF_SINGLE_IP +#endif + | NXF_HIDE_NETIF; +} + + +/* network caps */ + +#define NXC_TUN_CREATE 0x00000001 + +#define NXC_RAW_ICMP 0x00000100 + + +/* address types */ + +#define NXA_TYPE_IPV4 0x0001 +#define NXA_TYPE_IPV6 0x0002 + +#define NXA_TYPE_NONE 0x0000 +#define NXA_TYPE_ANY 0x00FF + +#define NXA_TYPE_ADDR 0x0010 +#define NXA_TYPE_MASK 0x0020 +#define NXA_TYPE_RANGE 0x0040 + +#define NXA_MASK_ALL (NXA_TYPE_ADDR | NXA_TYPE_MASK | NXA_TYPE_RANGE) + +#define NXA_MOD_BCAST 0x0100 +#define NXA_MOD_LBACK 0x0200 + +#define NXA_LOOPBACK 0x1000 + +#define NXA_MASK_BIND (NXA_MASK_ALL | NXA_MOD_BCAST | NXA_MOD_LBACK) +#define NXA_MASK_SHOW (NXA_MASK_ALL | NXA_LOOPBACK) + +#ifdef __KERNEL__ + +#include +#include +#include +#include +#include +#include + +struct nx_addr_v4 { + struct nx_addr_v4 *next; + struct in_addr ip[2]; + struct in_addr mask; + uint16_t type; + uint16_t flags; +}; + +struct nx_addr_v6 { + struct nx_addr_v6 *next; + struct in6_addr ip; + struct in6_addr mask; + uint32_t prefix; + uint16_t type; + uint16_t flags; +}; + +struct nx_info { + struct hlist_node nx_hlist; /* linked list of nxinfos */ + nid_t nx_id; /* vnet id */ + atomic_t nx_usecnt; /* usage count */ + atomic_t nx_tasks; /* tasks count */ + int nx_state; /* context state */ + + uint64_t nx_flags; /* network flag word */ + uint64_t nx_ncaps; /* network capabilities */ + + struct in_addr v4_lback; /* Loopback address */ + struct in_addr v4_bcast; /* Broadcast address */ + struct nx_addr_v4 v4; /* First/Single ipv4 address */ +#ifdef CONFIG_IPV6 + struct nx_addr_v6 v6; /* First/Single ipv6 address */ +#endif + char nx_name[65]; /* network context name */ +}; + + +/* status flags */ + +#define NXS_HASHED 0x0001 +#define NXS_SHUTDOWN 0x0100 +#define NXS_RELEASED 0x8000 + +extern struct nx_info *lookup_nx_info(int); + +extern int get_nid_list(int, unsigned int *, int); +extern int nid_is_hashed(nid_t); + +extern int nx_migrate_task(struct task_struct *, struct nx_info *); + +extern long vs_net_change(struct nx_info *, unsigned int); + +struct sock; + + +#define NX_IPV4(n) ((n)->v4.type != NXA_TYPE_NONE) +#ifdef CONFIG_IPV6 +#define NX_IPV6(n) ((n)->v6.type != NXA_TYPE_NONE) +#else +#define NX_IPV6(n) (0) +#endif + +#endif /* __KERNEL__ */ +#endif /* _VX_NETWORK_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/percpu.h linux-2.6.27.15-g-v/include/linux/vserver/percpu.h --- linux-2.6.27.15/include/linux/vserver/percpu.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/percpu.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,14 @@ +#ifndef _VX_PERCPU_H +#define _VX_PERCPU_H + +#include "cvirt_def.h" +#include "sched_def.h" + +struct _vx_percpu { + struct _vx_cvirt_pc cvirt; + struct _vx_sched_pc sched; +}; + +#define PERCPU_PERCTX (sizeof(struct _vx_percpu)) + +#endif /* _VX_PERCPU_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/pid.h linux-2.6.27.15-g-v/include/linux/vserver/pid.h --- linux-2.6.27.15/include/linux/vserver/pid.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/pid.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,51 @@ +#ifndef _VSERVER_PID_H +#define _VSERVER_PID_H + +/* pid faking stuff */ + +#define vx_info_map_pid(v, p) \ + __vx_info_map_pid((v), (p), __func__, __FILE__, __LINE__) +#define vx_info_map_tgid(v,p) vx_info_map_pid(v,p) +#define vx_map_pid(p) vx_info_map_pid(current->vx_info, p) +#define vx_map_tgid(p) vx_map_pid(p) + +static inline int __vx_info_map_pid(struct vx_info *vxi, int pid, + const char *func, const char *file, int line) +{ + if (vx_info_flags(vxi, VXF_INFO_INIT, 0)) { + vxfprintk(VXD_CBIT(cvirt, 2), + "vx_map_tgid: %p/%llx: %d -> %d", + vxi, (long long)vxi->vx_flags, pid, + (pid && pid == vxi->vx_initpid) ? 1 : pid, + func, file, line); + if (pid == 0) + return 0; + if (pid == vxi->vx_initpid) + return 1; + } + return pid; +} + +#define vx_info_rmap_pid(v, p) \ + __vx_info_rmap_pid((v), (p), __func__, __FILE__, __LINE__) +#define vx_rmap_pid(p) vx_info_rmap_pid(current->vx_info, p) +#define vx_rmap_tgid(p) vx_rmap_pid(p) + +static inline int __vx_info_rmap_pid(struct vx_info *vxi, int pid, + const char *func, const char *file, int line) +{ + if (vx_info_flags(vxi, VXF_INFO_INIT, 0)) { + vxfprintk(VXD_CBIT(cvirt, 2), + "vx_rmap_tgid: %p/%llx: %d -> %d", + vxi, (long long)vxi->vx_flags, pid, + (pid == 1) ? vxi->vx_initpid : pid, + func, file, line); + if ((pid == 1) && vxi->vx_initpid) + return vxi->vx_initpid; + if (pid == vxi->vx_initpid) + return ~0U; + } + return pid; +} + +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/sched_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/sched_cmd.h --- linux-2.6.27.15/include/linux/vserver/sched_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/sched_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,108 @@ +#ifndef _VX_SCHED_CMD_H +#define _VX_SCHED_CMD_H + + +/* sched vserver commands */ + +#define VCMD_set_sched_v2 VC_CMD(SCHED, 1, 2) +#define VCMD_set_sched_v3 VC_CMD(SCHED, 1, 3) +#define VCMD_set_sched_v4 VC_CMD(SCHED, 1, 4) + +struct vcmd_set_sched_v2 { + int32_t fill_rate; + int32_t interval; + int32_t tokens; + int32_t tokens_min; + int32_t tokens_max; + uint64_t cpu_mask; +}; + +struct vcmd_set_sched_v3 { + uint32_t set_mask; + int32_t fill_rate; + int32_t interval; + int32_t tokens; + int32_t tokens_min; + int32_t tokens_max; + int32_t priority_bias; +}; + +struct vcmd_set_sched_v4 { + uint32_t set_mask; + int32_t fill_rate; + int32_t interval; + int32_t tokens; + int32_t tokens_min; + int32_t tokens_max; + int32_t prio_bias; + int32_t cpu_id; + int32_t bucket_id; +}; + +#define VCMD_set_sched VC_CMD(SCHED, 1, 5) +#define VCMD_get_sched VC_CMD(SCHED, 2, 5) + +struct vcmd_sched_v5 { + uint32_t mask; + int32_t cpu_id; + int32_t bucket_id; + int32_t fill_rate[2]; + int32_t interval[2]; + int32_t tokens; + int32_t tokens_min; + int32_t tokens_max; + int32_t prio_bias; +}; + +#define VXSM_FILL_RATE 0x0001 +#define VXSM_INTERVAL 0x0002 +#define VXSM_FILL_RATE2 0x0004 +#define VXSM_INTERVAL2 0x0008 +#define VXSM_TOKENS 0x0010 +#define VXSM_TOKENS_MIN 0x0020 +#define VXSM_TOKENS_MAX 0x0040 +#define VXSM_PRIO_BIAS 0x0100 + +#define VXSM_IDLE_TIME 0x0200 +#define VXSM_FORCE 0x0400 + +#define VXSM_V3_MASK 0x0173 +#define VXSM_SET_MASK 0x01FF + +#define VXSM_CPU_ID 0x1000 +#define VXSM_BUCKET_ID 0x2000 + +#define VXSM_MSEC 0x4000 + +#define SCHED_KEEP (-2) /* only for v2 */ + +#ifdef __KERNEL__ + +#include + +extern int vc_set_sched_v2(struct vx_info *, void __user *); +extern int vc_set_sched_v3(struct vx_info *, void __user *); +extern int vc_set_sched_v4(struct vx_info *, void __user *); +extern int vc_set_sched(struct vx_info *, void __user *); +extern int vc_get_sched(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + +#define VCMD_sched_info VC_CMD(SCHED, 3, 0) + +struct vcmd_sched_info { + int32_t cpu_id; + int32_t bucket_id; + uint64_t user_msec; + uint64_t sys_msec; + uint64_t hold_msec; + uint32_t token_usec; + int32_t vavavoom; +}; + +#ifdef __KERNEL__ + +extern int vc_sched_info(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_SCHED_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/sched_def.h linux-2.6.27.15-g-v/include/linux/vserver/sched_def.h --- linux-2.6.27.15/include/linux/vserver/sched_def.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/sched_def.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,68 @@ +#ifndef _VX_SCHED_DEF_H +#define _VX_SCHED_DEF_H + +#include +#include +#include +#include +#include + + +/* context sub struct */ + +struct _vx_sched { + spinlock_t tokens_lock; /* lock for token bucket */ + + int tokens; /* number of CPU tokens */ + int fill_rate[2]; /* Fill rate: add X tokens... */ + int interval[2]; /* Divisor: per Y jiffies */ + int tokens_min; /* Limit: minimum for unhold */ + int tokens_max; /* Limit: no more than N tokens */ + + int prio_bias; /* bias offset for priority */ + + unsigned update_mask; /* which features should be updated */ + cpumask_t update; /* CPUs which should update */ +}; + +struct _vx_sched_pc { + int tokens; /* number of CPU tokens */ + int flags; /* bucket flags */ + + int fill_rate[2]; /* Fill rate: add X tokens... */ + int interval[2]; /* Divisor: per Y jiffies */ + int tokens_min; /* Limit: minimum for unhold */ + int tokens_max; /* Limit: no more than N tokens */ + + int prio_bias; /* bias offset for priority */ + int vavavoom; /* last calculated vavavoom */ + + unsigned long norm_time; /* last time accounted */ + unsigned long idle_time; /* non linear time for fair sched */ + unsigned long token_time; /* token time for accounting */ + unsigned long onhold; /* jiffies when put on hold */ + + uint64_t user_ticks; /* token tick events */ + uint64_t sys_ticks; /* token tick events */ + uint64_t hold_ticks; /* token ticks paused */ +}; + + +#define VXSF_ONHOLD 0x0001 +#define VXSF_IDLE_TIME 0x0100 + +#ifdef CONFIG_VSERVER_DEBUG + +static inline void __dump_vx_sched(struct _vx_sched *sched) +{ + printk("\t_vx_sched:\n"); + printk("\t tokens: %4d/%4d, %4d/%4d, %4d, %4d\n", + sched->fill_rate[0], sched->interval[0], + sched->fill_rate[1], sched->interval[1], + sched->tokens_min, sched->tokens_max); + printk("\t priority = %4d\n", sched->prio_bias); +} + +#endif + +#endif /* _VX_SCHED_DEF_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/sched.h linux-2.6.27.15-g-v/include/linux/vserver/sched.h --- linux-2.6.27.15/include/linux/vserver/sched.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/sched.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,26 @@ +#ifndef _VX_SCHED_H +#define _VX_SCHED_H + + +#ifdef __KERNEL__ + +struct timespec; + +void vx_vsi_uptime(struct timespec *, struct timespec *); + + +struct vx_info; + +void vx_update_load(struct vx_info *); + + +int vx_tokens_recalc(struct _vx_sched_pc *, + unsigned long *, unsigned long *, int [2]); + +void vx_update_sched_param(struct _vx_sched *sched, + struct _vx_sched_pc *sched_pc); + +#endif /* __KERNEL__ */ +#else /* _VX_SCHED_H */ +#warning duplicate inclusion +#endif /* _VX_SCHED_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/signal_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/signal_cmd.h --- linux-2.6.27.15/include/linux/vserver/signal_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/signal_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,43 @@ +#ifndef _VX_SIGNAL_CMD_H +#define _VX_SIGNAL_CMD_H + + +/* signalling vserver commands */ + +#define VCMD_ctx_kill VC_CMD(PROCTRL, 1, 0) +#define VCMD_wait_exit VC_CMD(EVENT, 99, 0) + +struct vcmd_ctx_kill_v0 { + int32_t pid; + int32_t sig; +}; + +struct vcmd_wait_exit_v0 { + int32_t reboot_cmd; + int32_t exit_code; +}; + +#ifdef __KERNEL__ + +extern int vc_ctx_kill(struct vx_info *, void __user *); +extern int vc_wait_exit(struct vx_info *, void __user *); + +#endif /* __KERNEL__ */ + +/* process alteration commands */ + +#define VCMD_get_pflags VC_CMD(PROCALT, 5, 0) +#define VCMD_set_pflags VC_CMD(PROCALT, 6, 0) + +struct vcmd_pflags_v0 { + uint32_t flagword; + uint32_t mask; +}; + +#ifdef __KERNEL__ + +extern int vc_get_pflags(uint32_t pid, void __user *); +extern int vc_set_pflags(uint32_t pid, void __user *); + +#endif /* __KERNEL__ */ +#endif /* _VX_SIGNAL_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/signal.h linux-2.6.27.15-g-v/include/linux/vserver/signal.h --- linux-2.6.27.15/include/linux/vserver/signal.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/signal.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,14 @@ +#ifndef _VX_SIGNAL_H +#define _VX_SIGNAL_H + + +#ifdef __KERNEL__ + +struct vx_info; + +int vx_info_kill(struct vx_info *, int, int); + +#endif /* __KERNEL__ */ +#else /* _VX_SIGNAL_H */ +#warning duplicate inclusion +#endif /* _VX_SIGNAL_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/space_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/space_cmd.h --- linux-2.6.27.15/include/linux/vserver/space_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/space_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,38 @@ +#ifndef _VX_SPACE_CMD_H +#define _VX_SPACE_CMD_H + + +#define VCMD_enter_space_v0 VC_CMD(PROCALT, 1, 0) +#define VCMD_enter_space_v1 VC_CMD(PROCALT, 1, 1) +#define VCMD_enter_space VC_CMD(PROCALT, 1, 2) + +#define VCMD_set_space_v0 VC_CMD(PROCALT, 3, 0) +#define VCMD_set_space_v1 VC_CMD(PROCALT, 3, 1) +#define VCMD_set_space VC_CMD(PROCALT, 3, 2) + +#define VCMD_get_space_mask_v0 VC_CMD(PROCALT, 4, 0) + +#define VCMD_get_space_mask VC_CMD(VSPACE, 0, 1) +#define VCMD_get_space_default VC_CMD(VSPACE, 1, 0) + + +struct vcmd_space_mask_v1 { + uint64_t mask; +}; + +struct vcmd_space_mask_v2 { + uint64_t mask; + uint32_t index; +}; + + +#ifdef __KERNEL__ + +extern int vc_enter_space_v1(struct vx_info *, void __user *); +extern int vc_set_space_v1(struct vx_info *, void __user *); +extern int vc_enter_space(struct vx_info *, void __user *); +extern int vc_set_space(struct vx_info *, void __user *); +extern int vc_get_space_mask(void __user *, int); + +#endif /* __KERNEL__ */ +#endif /* _VX_SPACE_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/space.h linux-2.6.27.15-g-v/include/linux/vserver/space.h --- linux-2.6.27.15/include/linux/vserver/space.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/space.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,12 @@ +#ifndef _VX_SPACE_H +#define _VX_SPACE_H + +#include + +struct vx_info; + +int vx_set_space(struct vx_info *vxi, unsigned long mask, unsigned index); + +#else /* _VX_SPACE_H */ +#warning duplicate inclusion +#endif /* _VX_SPACE_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/switch.h linux-2.6.27.15-g-v/include/linux/vserver/switch.h --- linux-2.6.27.15/include/linux/vserver/switch.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/switch.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,98 @@ +#ifndef _VX_SWITCH_H +#define _VX_SWITCH_H + +#include + + +#define VC_CATEGORY(c) (((c) >> 24) & 0x3F) +#define VC_COMMAND(c) (((c) >> 16) & 0xFF) +#define VC_VERSION(c) ((c) & 0xFFF) + +#define VC_CMD(c, i, v) ((((VC_CAT_ ## c) & 0x3F) << 24) \ + | (((i) & 0xFF) << 16) | ((v) & 0xFFF)) + +/* + + Syscall Matrix V2.8 + + |VERSION|CREATE |MODIFY |MIGRATE|CONTROL|EXPERIM| |SPECIAL|SPECIAL| + |STATS |DESTROY|ALTER |CHANGE |LIMIT |TEST | | | | + |INFO |SETUP | |MOVE | | | | | | + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + SYSTEM |VERSION|VSETUP |VHOST | | | | |DEVICE | | + HOST | 00| 01| 02| 03| 04| 05| | 06| 07| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + CPU | |VPROC |PROCALT|PROCMIG|PROCTRL| | |SCHED. | | + PROCESS| 08| 09| 10| 11| 12| 13| | 14| 15| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + MEMORY | | | | |MEMCTRL| | |SWAP | | + | 16| 17| 18| 19| 20| 21| | 22| 23| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + NETWORK| |VNET |NETALT |NETMIG |NETCTL | | |SERIAL | | + | 24| 25| 26| 27| 28| 29| | 30| 31| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + DISK | | | |TAGMIG |DLIMIT | | |INODE | | + VFS | 32| 33| 34| 35| 36| 37| | 38| 39| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + OTHER |VSTAT | | | | | | |VINFO | | + | 40| 41| 42| 43| 44| 45| | 46| 47| + =======+=======+=======+=======+=======+=======+=======+ +=======+=======+ + SPECIAL|EVENT | | | |FLAGS | | |VSPACE | | + | 48| 49| 50| 51| 52| 53| | 54| 55| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + SPECIAL|DEBUG | | | |RLIMIT |SYSCALL| | |COMPAT | + | 56| 57| 58| 59| 60|TEST 61| | 62| 63| + -------+-------+-------+-------+-------+-------+-------+ +-------+-------+ + +*/ + +#define VC_CAT_VERSION 0 + +#define VC_CAT_VSETUP 1 +#define VC_CAT_VHOST 2 + +#define VC_CAT_DEVICE 6 + +#define VC_CAT_VPROC 9 +#define VC_CAT_PROCALT 10 +#define VC_CAT_PROCMIG 11 +#define VC_CAT_PROCTRL 12 + +#define VC_CAT_SCHED 14 +#define VC_CAT_MEMCTRL 20 + +#define VC_CAT_VNET 25 +#define VC_CAT_NETALT 26 +#define VC_CAT_NETMIG 27 +#define VC_CAT_NETCTRL 28 + +#define VC_CAT_TAGMIG 35 +#define VC_CAT_DLIMIT 36 +#define VC_CAT_INODE 38 + +#define VC_CAT_VSTAT 40 +#define VC_CAT_VINFO 46 +#define VC_CAT_EVENT 48 + +#define VC_CAT_FLAGS 52 +#define VC_CAT_VSPACE 54 +#define VC_CAT_DEBUG 56 +#define VC_CAT_RLIMIT 60 + +#define VC_CAT_SYSTEST 61 +#define VC_CAT_COMPAT 63 + +/* query version */ + +#define VCMD_get_version VC_CMD(VERSION, 0, 0) +#define VCMD_get_vci VC_CMD(VERSION, 1, 0) + + +#ifdef __KERNEL__ + +#include + +#endif /* __KERNEL__ */ + +#endif /* _VX_SWITCH_H */ + diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/tag_cmd.h linux-2.6.27.15-g-v/include/linux/vserver/tag_cmd.h --- linux-2.6.27.15/include/linux/vserver/tag_cmd.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/tag_cmd.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,22 @@ +#ifndef _VX_TAG_CMD_H +#define _VX_TAG_CMD_H + + +/* vinfo commands */ + +#define VCMD_task_tag VC_CMD(VINFO, 3, 0) + +#ifdef __KERNEL__ +extern int vc_task_tag(uint32_t); + +#endif /* __KERNEL__ */ + +/* context commands */ + +#define VCMD_tag_migrate VC_CMD(TAGMIG, 1, 0) + +#ifdef __KERNEL__ +extern int vc_tag_migrate(uint32_t); + +#endif /* __KERNEL__ */ +#endif /* _VX_TAG_CMD_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vserver/tag.h linux-2.6.27.15-g-v/include/linux/vserver/tag.h --- linux-2.6.27.15/include/linux/vserver/tag.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vserver/tag.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,143 @@ +#ifndef _DX_TAG_H +#define _DX_TAG_H + +#include + + +#define DX_TAG(in) (IS_TAGGED(in)) + + +#ifdef CONFIG_TAG_NFSD +#define DX_TAG_NFSD 1 +#else +#define DX_TAG_NFSD 0 +#endif + + +#ifdef CONFIG_TAGGING_NONE + +#define MAX_UID 0xFFFFFFFF +#define MAX_GID 0xFFFFFFFF + +#define INOTAG_TAG(cond, uid, gid, tag) (0) + +#define TAGINO_UID(cond, uid, tag) (uid) +#define TAGINO_GID(cond, gid, tag) (gid) + +#endif + + +#ifdef CONFIG_TAGGING_GID16 + +#define MAX_UID 0xFFFFFFFF +#define MAX_GID 0x0000FFFF + +#define INOTAG_TAG(cond, uid, gid, tag) \ + ((cond) ? (((gid) >> 16) & 0xFFFF) : 0) + +#define TAGINO_UID(cond, uid, tag) (uid) +#define TAGINO_GID(cond, gid, tag) \ + ((cond) ? (((gid) & 0xFFFF) | ((tag) << 16)) : (gid)) + +#endif + + +#ifdef CONFIG_TAGGING_ID24 + +#define MAX_UID 0x00FFFFFF +#define MAX_GID 0x00FFFFFF + +#define INOTAG_TAG(cond, uid, gid, tag) \ + ((cond) ? ((((uid) >> 16) & 0xFF00) | (((gid) >> 24) & 0xFF)) : 0) + +#define TAGINO_UID(cond, uid, tag) \ + ((cond) ? (((uid) & 0xFFFFFF) | (((tag) & 0xFF00) << 16)) : (uid)) +#define TAGINO_GID(cond, gid, tag) \ + ((cond) ? (((gid) & 0xFFFFFF) | (((tag) & 0x00FF) << 24)) : (gid)) + +#endif + + +#ifdef CONFIG_TAGGING_UID16 + +#define MAX_UID 0x0000FFFF +#define MAX_GID 0xFFFFFFFF + +#define INOTAG_TAG(cond, uid, gid, tag) \ + ((cond) ? (((uid) >> 16) & 0xFFFF) : 0) + +#define TAGINO_UID(cond, uid, tag) \ + ((cond) ? (((uid) & 0xFFFF) | ((tag) << 16)) : (uid)) +#define TAGINO_GID(cond, gid, tag) (gid) + +#endif + + +#ifdef CONFIG_TAGGING_INTERN + +#define MAX_UID 0xFFFFFFFF +#define MAX_GID 0xFFFFFFFF + +#define INOTAG_TAG(cond, uid, gid, tag) \ + ((cond) ? (tag) : 0) + +#define TAGINO_UID(cond, uid, tag) (uid) +#define TAGINO_GID(cond, gid, tag) (gid) + +#endif + + +#ifndef CONFIG_TAGGING_NONE +#define dx_current_fstag(sb) \ + ((sb)->s_flags & MS_TAGGED ? dx_current_tag() : 0) +#else +#define dx_current_fstag(sb) (0) +#endif + +#ifndef CONFIG_TAGGING_INTERN +#define TAGINO_TAG(cond, tag) (0) +#else +#define TAGINO_TAG(cond, tag) ((cond) ? (tag) : 0) +#endif + +#define INOTAG_UID(cond, uid, gid) \ + ((cond) ? ((uid) & MAX_UID) : (uid)) +#define INOTAG_GID(cond, uid, gid) \ + ((cond) ? ((gid) & MAX_GID) : (gid)) + + +static inline uid_t dx_map_uid(uid_t uid) +{ + if ((uid > MAX_UID) && (uid != -1)) + uid = -2; + return (uid & MAX_UID); +} + +static inline gid_t dx_map_gid(gid_t gid) +{ + if ((gid > MAX_GID) && (gid != -1)) + gid = -2; + return (gid & MAX_GID); +} + +struct peer_tag { + int32_t xid; + int32_t nid; +}; + +#define dx_notagcheck(sb) ((sb) && ((sb)->s_flags & MS_NOTAGCHECK)) + +int dx_parse_tag(char *string, tag_t *tag, int remove, int *mnt_flags, + unsigned long *flags); + +#ifdef CONFIG_PROPAGATE + +void __dx_propagate_tag(struct nameidata *nd, struct inode *inode); + +#define dx_propagate_tag(n, i) __dx_propagate_tag(n, i) + +#else +#define dx_propagate_tag(n, i) do { } while (0) +#endif + +#endif /* _DX_TAG_H */ diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_inet6.h linux-2.6.27.15-g-v/include/linux/vs_inet6.h --- linux-2.6.27.15/include/linux/vs_inet6.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_inet6.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,246 @@ +#ifndef _VS_INET6_H +#define _VS_INET6_H + +#include "vserver/base.h" +#include "vserver/network.h" +#include "vserver/debug.h" + +#include + +#define NXAV6(a) NIP6((a)->ip), NIP6((a)->mask), (a)->prefix, (a)->type +#define NXAV6_FMT "[" NIP6_FMT "/" NIP6_FMT "/%d:%04x]" + + +#ifdef CONFIG_IPV6 + +static inline +int v6_addr_match(struct nx_addr_v6 *nxa, + const struct in6_addr *addr, uint16_t mask) +{ + int ret = 0; + + switch (nxa->type & mask) { + case NXA_TYPE_MASK: + ret = ipv6_masked_addr_cmp(&nxa->ip, &nxa->mask, addr); + break; + case NXA_TYPE_ADDR: + ret = ipv6_addr_equal(&nxa->ip, addr); + break; + case NXA_TYPE_ANY: + ret = 1; + break; + } + vxdprintk(VXD_CBIT(net, 0), + "v6_addr_match(%p" NXAV6_FMT ", " NIP6_FMT ", %04x) = %d", + nxa, NXAV6(nxa), NIP6(*addr), mask, ret); + return ret; +} + +static inline +int v6_addr_in_nx_info(struct nx_info *nxi, + const struct in6_addr *addr, uint16_t mask) +{ + struct nx_addr_v6 *nxa; + int ret = 1; + + if (!nxi) + goto out; + for (nxa = &nxi->v6; nxa; nxa = nxa->next) + if (v6_addr_match(nxa, addr, mask)) + goto out; + ret = 0; +out: + vxdprintk(VXD_CBIT(net, 0), + "v6_addr_in_nx_info(%p[#%u]," NIP6_FMT ",%04x) = %d", + nxi, nxi ? nxi->nx_id : 0, NIP6(*addr), mask, ret); + return ret; +} + +static inline +int v6_nx_addr_match(struct nx_addr_v6 *nxa, struct nx_addr_v6 *addr, uint16_t mask) +{ + /* FIXME: needs full range checks */ + return v6_addr_match(nxa, &addr->ip, mask); +} + +static inline +int v6_nx_addr_in_nx_info(struct nx_info *nxi, struct nx_addr_v6 *nxa, uint16_t mask) +{ + struct nx_addr_v6 *ptr; + + for (ptr = &nxi->v6; ptr; ptr = ptr->next) + if (v6_nx_addr_match(ptr, nxa, mask)) + return 1; + return 0; +} + + +/* + * Check if a given address matches for a socket + * + * nxi: the socket's nx_info if any + * addr: to be verified address + */ +static inline +int v6_sock_addr_match ( + struct nx_info *nxi, + struct inet_sock *inet, + struct in6_addr *addr) +{ + struct sock *sk = &inet->sk; + struct in6_addr *saddr = inet6_rcv_saddr(sk); + + if (!ipv6_addr_any(addr) && + ipv6_addr_equal(saddr, addr)) + return 1; + if (ipv6_addr_any(saddr)) + return v6_addr_in_nx_info(nxi, addr, -1); + return 0; +} + +/* + * check if address is covered by socket + * + * sk: the socket to check against + * addr: the address in question (must be != 0) + */ + +static inline +int __v6_addr_match_socket(const struct sock *sk, struct nx_addr_v6 *nxa) +{ + struct nx_info *nxi = sk->sk_nx_info; + struct in6_addr *saddr = inet6_rcv_saddr(sk); + + vxdprintk(VXD_CBIT(net, 5), + "__v6_addr_in_socket(%p," NXAV6_FMT ") %p:" NIP6_FMT " %p;%lx", + sk, NXAV6(nxa), nxi, NIP6(*saddr), sk->sk_socket, + (sk->sk_socket?sk->sk_socket->flags:0)); + + if (!ipv6_addr_any(saddr)) { /* direct address match */ + return v6_addr_match(nxa, saddr, -1); + } else if (nxi) { /* match against nx_info */ + return v6_nx_addr_in_nx_info(nxi, nxa, -1); + } else { /* unrestricted any socket */ + return 1; + } +} + + +/* inet related checks and helpers */ + + +struct in_ifaddr; +struct net_device; +struct sock; + + +#include +#include +#include + + +int dev_in_nx_info(struct net_device *, struct nx_info *); +int v6_dev_in_nx_info(struct net_device *, struct nx_info *); +int nx_v6_addr_conflict(struct nx_info *, struct nx_info *); + + + +static inline +int v6_ifa_in_nx_info(struct inet6_ifaddr *ifa, struct nx_info *nxi) +{ + if (!nxi) + return 1; + if (!ifa) + return 0; + return v6_addr_in_nx_info(nxi, &ifa->addr, -1); +} + +static inline +int nx_v6_ifa_visible(struct nx_info *nxi, struct inet6_ifaddr *ifa) +{ + vxdprintk(VXD_CBIT(net, 1), "nx_v6_ifa_visible(%p[#%u],%p) %d", + nxi, nxi ? nxi->nx_id : 0, ifa, + nxi ? v6_ifa_in_nx_info(ifa, nxi) : 0); + + if (!nx_info_flags(nxi, NXF_HIDE_NETIF, 0)) + return 1; + if (v6_ifa_in_nx_info(ifa, nxi)) + return 1; + return 0; +} + + +struct nx_v6_sock_addr { + struct in6_addr saddr; /* Address used for validation */ + struct in6_addr baddr; /* Address used for socket bind */ +}; + +static inline +int v6_map_sock_addr(struct inet_sock *inet, struct sockaddr_in6 *addr, + struct nx_v6_sock_addr *nsa) +{ + // struct sock *sk = &inet->sk; + // struct nx_info *nxi = sk->sk_nx_info; + struct in6_addr saddr = addr->sin6_addr; + struct in6_addr baddr = saddr; + + nsa->saddr = saddr; + nsa->baddr = baddr; + return 0; +} + +static inline +void v6_set_sock_addr(struct inet_sock *inet, struct nx_v6_sock_addr *nsa) +{ + // struct sock *sk = &inet->sk; + // struct in6_addr *saddr = inet6_rcv_saddr(sk); + + // *saddr = nsa->baddr; + // inet->saddr = nsa->baddr; +} + +static inline +int nx_info_has_v6(struct nx_info *nxi) +{ + if (!nxi) + return 1; + if (NX_IPV6(nxi)) + return 1; + return 0; +} + +#else /* CONFIG_IPV6 */ + +static inline +int nx_v6_dev_visible(struct nx_info *n, struct net_device *d) +{ + return 1; +} + + +static inline +int nx_v6_addr_conflict(struct nx_info *n, uint32_t a, const struct sock *s) +{ + return 1; +} + +static inline +int v6_ifa_in_nx_info(struct in_ifaddr *a, struct nx_info *n) +{ + return 1; +} + +static inline +int nx_info_has_v6(struct nx_info *nxi) +{ + return 0; +} + +#endif /* CONFIG_IPV6 */ + +#define current_nx_info_has_v6() \ + nx_info_has_v6(current_nx_info()) + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_inet.h linux-2.6.27.15-g-v/include/linux/vs_inet.h --- linux-2.6.27.15/include/linux/vs_inet.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_inet.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,342 @@ +#ifndef _VS_INET_H +#define _VS_INET_H + +#include "vserver/base.h" +#include "vserver/network.h" +#include "vserver/debug.h" + +#define IPI_LOOPBACK htonl(INADDR_LOOPBACK) + +#define NXAV4(a) NIPQUAD((a)->ip[0]), NIPQUAD((a)->ip[1]), \ + NIPQUAD((a)->mask), (a)->type +#define NXAV4_FMT "[" NIPQUAD_FMT "-" NIPQUAD_FMT "/" NIPQUAD_FMT ":%04x]" + + +static inline +int v4_addr_match(struct nx_addr_v4 *nxa, __be32 addr, uint16_t tmask) +{ + __be32 ip = nxa->ip[0].s_addr; + __be32 mask = nxa->mask.s_addr; + __be32 bcast = ip | ~mask; + int ret = 0; + + switch (nxa->type & tmask) { + case NXA_TYPE_MASK: + ret = (ip == (addr & mask)); + break; + case NXA_TYPE_ADDR: + ret = 3; + if (addr == ip) + break; + /* fall through to broadcast */ + case NXA_MOD_BCAST: + ret = ((tmask & NXA_MOD_BCAST) && (addr == bcast)); + break; + case NXA_TYPE_RANGE: + ret = ((nxa->ip[0].s_addr <= addr) && + (nxa->ip[1].s_addr > addr)); + break; + case NXA_TYPE_ANY: + ret = 2; + break; + } + + vxdprintk(VXD_CBIT(net, 0), + "v4_addr_match(%p" NXAV4_FMT "," NIPQUAD_FMT ",%04x) = %d", + nxa, NXAV4(nxa), NIPQUAD(addr), tmask, ret); + return ret; +} + +static inline +int v4_addr_in_nx_info(struct nx_info *nxi, __be32 addr, uint16_t tmask) +{ + struct nx_addr_v4 *nxa; + int ret = 1; + + if (!nxi) + goto out; + + ret = 2; + /* allow 127.0.0.1 when remapping lback */ + if ((tmask & NXA_LOOPBACK) && + (addr == IPI_LOOPBACK) && + nx_info_flags(nxi, NXF_LBACK_REMAP, 0)) + goto out; + ret = 3; + /* check for lback address */ + if ((tmask & NXA_MOD_LBACK) && + (nxi->v4_lback.s_addr == addr)) + goto out; + ret = 4; + /* check for broadcast address */ + if ((tmask & NXA_MOD_BCAST) && + (nxi->v4_bcast.s_addr == addr)) + goto out; + ret = 5; + /* check for v4 addresses */ + for (nxa = &nxi->v4; nxa; nxa = nxa->next) + if (v4_addr_match(nxa, addr, tmask)) + goto out; + ret = 0; +out: + vxdprintk(VXD_CBIT(net, 0), + "v4_addr_in_nx_info(%p[#%u]," NIPQUAD_FMT ",%04x) = %d", + nxi, nxi ? nxi->nx_id : 0, NIPQUAD(addr), tmask, ret); + return ret; +} + +static inline +int v4_nx_addr_match(struct nx_addr_v4 *nxa, struct nx_addr_v4 *addr, uint16_t mask) +{ + /* FIXME: needs full range checks */ + return v4_addr_match(nxa, addr->ip[0].s_addr, mask); +} + +static inline +int v4_nx_addr_in_nx_info(struct nx_info *nxi, struct nx_addr_v4 *nxa, uint16_t mask) +{ + struct nx_addr_v4 *ptr; + + for (ptr = &nxi->v4; ptr; ptr = ptr->next) + if (v4_nx_addr_match(ptr, nxa, mask)) + return 1; + return 0; +} + +#include + +/* + * Check if a given address matches for a socket + * + * nxi: the socket's nx_info if any + * addr: to be verified address + */ +static inline +int v4_sock_addr_match ( + struct nx_info *nxi, + struct inet_sock *inet, + __be32 addr) +{ + __be32 saddr = inet->rcv_saddr; + __be32 bcast = nxi ? nxi->v4_bcast.s_addr : INADDR_BROADCAST; + + if (addr && (saddr == addr || bcast == addr)) + return 1; + if (!saddr) + return v4_addr_in_nx_info(nxi, addr, NXA_MASK_BIND); + return 0; +} + + +/* inet related checks and helpers */ + + +struct in_ifaddr; +struct net_device; +struct sock; + +#ifdef CONFIG_INET + +#include +#include +#include +#include + + +int dev_in_nx_info(struct net_device *, struct nx_info *); +int v4_dev_in_nx_info(struct net_device *, struct nx_info *); +int nx_v4_addr_conflict(struct nx_info *, struct nx_info *); + + +/* + * check if address is covered by socket + * + * sk: the socket to check against + * addr: the address in question (must be != 0) + */ + +static inline +int __v4_addr_match_socket(const struct sock *sk, struct nx_addr_v4 *nxa) +{ + struct nx_info *nxi = sk->sk_nx_info; + __be32 saddr = inet_rcv_saddr(sk); + + vxdprintk(VXD_CBIT(net, 5), + "__v4_addr_in_socket(%p," NXAV4_FMT ") %p:" NIPQUAD_FMT " %p;%lx", + sk, NXAV4(nxa), nxi, NIPQUAD(saddr), sk->sk_socket, + (sk->sk_socket?sk->sk_socket->flags:0)); + + if (saddr) { /* direct address match */ + return v4_addr_match(nxa, saddr, -1); + } else if (nxi) { /* match against nx_info */ + return v4_nx_addr_in_nx_info(nxi, nxa, -1); + } else { /* unrestricted any socket */ + return 1; + } +} + + + +static inline +int nx_dev_visible(struct nx_info *nxi, struct net_device *dev) +{ + vxdprintk(VXD_CBIT(net, 1), "nx_dev_visible(%p[#%u],%p »%s«) %d", + nxi, nxi ? nxi->nx_id : 0, dev, dev->name, + nxi ? dev_in_nx_info(dev, nxi) : 0); + + if (!nx_info_flags(nxi, NXF_HIDE_NETIF, 0)) + return 1; + if (dev_in_nx_info(dev, nxi)) + return 1; + return 0; +} + + +static inline +int v4_ifa_in_nx_info(struct in_ifaddr *ifa, struct nx_info *nxi) +{ + if (!nxi) + return 1; + if (!ifa) + return 0; + return v4_addr_in_nx_info(nxi, ifa->ifa_local, NXA_MASK_SHOW); +} + +static inline +int nx_v4_ifa_visible(struct nx_info *nxi, struct in_ifaddr *ifa) +{ + vxdprintk(VXD_CBIT(net, 1), "nx_v4_ifa_visible(%p[#%u],%p) %d", + nxi, nxi ? nxi->nx_id : 0, ifa, + nxi ? v4_ifa_in_nx_info(ifa, nxi) : 0); + + if (!nx_info_flags(nxi, NXF_HIDE_NETIF, 0)) + return 1; + if (v4_ifa_in_nx_info(ifa, nxi)) + return 1; + return 0; +} + + +struct nx_v4_sock_addr { + __be32 saddr; /* Address used for validation */ + __be32 baddr; /* Address used for socket bind */ +}; + +static inline +int v4_map_sock_addr(struct inet_sock *inet, struct sockaddr_in *addr, + struct nx_v4_sock_addr *nsa) +{ + struct sock *sk = &inet->sk; + struct nx_info *nxi = sk->sk_nx_info; + __be32 saddr = addr->sin_addr.s_addr; + __be32 baddr = saddr; + + vxdprintk(VXD_CBIT(net, 3), + "inet_bind(%p)* %p,%p;%lx " NIPQUAD_FMT, + sk, sk->sk_nx_info, sk->sk_socket, + (sk->sk_socket ? sk->sk_socket->flags : 0), + NIPQUAD(saddr)); + + if (nxi) { + if (saddr == INADDR_ANY) { + if (nx_info_flags(nxi, NXF_SINGLE_IP, 0)) + baddr = nxi->v4.ip[0].s_addr; + } else if (saddr == IPI_LOOPBACK) { + if (nx_info_flags(nxi, NXF_LBACK_REMAP, 0)) + baddr = nxi->v4_lback.s_addr; + } else { /* normal address bind */ + if (!v4_addr_in_nx_info(nxi, saddr, NXA_MASK_BIND)) + return -EADDRNOTAVAIL; + } + } + + vxdprintk(VXD_CBIT(net, 3), + "inet_bind(%p) " NIPQUAD_FMT ", " NIPQUAD_FMT, + sk, NIPQUAD(saddr), NIPQUAD(baddr)); + + nsa->saddr = saddr; + nsa->baddr = baddr; + return 0; +} + +static inline +void v4_set_sock_addr(struct inet_sock *inet, struct nx_v4_sock_addr *nsa) +{ + inet->saddr = nsa->baddr; + inet->rcv_saddr = nsa->baddr; +} + + +/* + * helper to simplify inet_lookup_listener + * + * nxi: the socket's nx_info if any + * addr: to be verified address + * saddr: socket address + */ +static inline int v4_inet_addr_match ( + struct nx_info *nxi, + __be32 addr, + __be32 saddr) +{ + if (addr && (saddr == addr)) + return 1; + if (!saddr) + return nxi ? v4_addr_in_nx_info(nxi, addr, NXA_MASK_BIND) : 1; + return 0; +} + +static inline __be32 nx_map_sock_lback(struct nx_info *nxi, __be32 addr) +{ + if (nx_info_flags(nxi, NXF_HIDE_LBACK, 0) && + (addr == nxi->v4_lback.s_addr)) + return IPI_LOOPBACK; + return addr; +} + +static inline +int nx_info_has_v4(struct nx_info *nxi) +{ + if (!nxi) + return 1; + if (NX_IPV4(nxi)) + return 1; + if (nx_info_flags(nxi, NXF_LBACK_REMAP, 0)) + return 1; + return 0; +} + +#else /* CONFIG_INET */ + +static inline +int nx_dev_visible(struct nx_info *n, struct net_device *d) +{ + return 1; +} + +static inline +int nx_v4_addr_conflict(struct nx_info *n, uint32_t a, const struct sock *s) +{ + return 1; +} + +static inline +int v4_ifa_in_nx_info(struct in_ifaddr *a, struct nx_info *n) +{ + return 1; +} + +static inline +int nx_info_has_v4(struct nx_info *nxi) +{ + return 0; +} + +#endif /* CONFIG_INET */ + +#define current_nx_info_has_v4() \ + nx_info_has_v4(current_nx_info()) + +#else +// #warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_limit.h linux-2.6.27.15-g-v/include/linux/vs_limit.h --- linux-2.6.27.15/include/linux/vs_limit.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_limit.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,140 @@ +#ifndef _VS_LIMIT_H +#define _VS_LIMIT_H + +#include "vserver/limit.h" +#include "vserver/base.h" +#include "vserver/context.h" +#include "vserver/debug.h" +#include "vserver/context.h" +#include "vserver/limit_int.h" + + +#define vx_acc_cres(v, d, p, r) \ + __vx_acc_cres(v, r, d, p, __FILE__, __LINE__) + +#define vx_acc_cres_cond(x, d, p, r) \ + __vx_acc_cres(((x) == vx_current_xid()) ? current->vx_info : 0, \ + r, d, p, __FILE__, __LINE__) + + +#define vx_add_cres(v, a, p, r) \ + __vx_add_cres(v, r, a, p, __FILE__, __LINE__) +#define vx_sub_cres(v, a, p, r) vx_add_cres(v, -(a), p, r) + +#define vx_add_cres_cond(x, a, p, r) \ + __vx_add_cres(((x) == vx_current_xid()) ? current->vx_info : 0, \ + r, a, p, __FILE__, __LINE__) +#define vx_sub_cres_cond(x, a, p, r) vx_add_cres_cond(x, -(a), p, r) + + +/* process and file limits */ + +#define vx_nproc_inc(p) \ + vx_acc_cres((p)->vx_info, 1, p, RLIMIT_NPROC) + +#define vx_nproc_dec(p) \ + vx_acc_cres((p)->vx_info,-1, p, RLIMIT_NPROC) + +#define vx_files_inc(f) \ + vx_acc_cres_cond((f)->f_xid, 1, f, RLIMIT_NOFILE) + +#define vx_files_dec(f) \ + vx_acc_cres_cond((f)->f_xid,-1, f, RLIMIT_NOFILE) + +#define vx_locks_inc(l) \ + vx_acc_cres_cond((l)->fl_xid, 1, l, RLIMIT_LOCKS) + +#define vx_locks_dec(l) \ + vx_acc_cres_cond((l)->fl_xid,-1, l, RLIMIT_LOCKS) + +#define vx_openfd_inc(f) \ + vx_acc_cres(current->vx_info, 1, (void *)(long)(f), VLIMIT_OPENFD) + +#define vx_openfd_dec(f) \ + vx_acc_cres(current->vx_info,-1, (void *)(long)(f), VLIMIT_OPENFD) + + +#define vx_cres_avail(v, n, r) \ + __vx_cres_avail(v, r, n, __FILE__, __LINE__) + + +#define vx_nproc_avail(n) \ + vx_cres_avail(current->vx_info, n, RLIMIT_NPROC) + +#define vx_files_avail(n) \ + vx_cres_avail(current->vx_info, n, RLIMIT_NOFILE) + +#define vx_locks_avail(n) \ + vx_cres_avail(current->vx_info, n, RLIMIT_LOCKS) + +#define vx_openfd_avail(n) \ + vx_cres_avail(current->vx_info, n, VLIMIT_OPENFD) + + +/* dentry limits */ + +#define vx_dentry_inc(d) do { \ + if (atomic_read(&d->d_count) == 1) \ + vx_acc_cres(current->vx_info, 1, d, VLIMIT_DENTRY); \ + } while (0) + +#define vx_dentry_dec(d) do { \ + if (atomic_read(&d->d_count) == 0) \ + vx_acc_cres(current->vx_info,-1, d, VLIMIT_DENTRY); \ + } while (0) + +#define vx_dentry_avail(n) \ + vx_cres_avail(current->vx_info, n, VLIMIT_DENTRY) + + +/* socket limits */ + +#define vx_sock_inc(s) \ + vx_acc_cres((s)->sk_vx_info, 1, s, VLIMIT_NSOCK) + +#define vx_sock_dec(s) \ + vx_acc_cres((s)->sk_vx_info,-1, s, VLIMIT_NSOCK) + +#define vx_sock_avail(n) \ + vx_cres_avail(current->vx_info, n, VLIMIT_NSOCK) + + +/* ipc resource limits */ + +#define vx_ipcmsg_add(v, u, a) \ + vx_add_cres(v, a, u, RLIMIT_MSGQUEUE) + +#define vx_ipcmsg_sub(v, u, a) \ + vx_sub_cres(v, a, u, RLIMIT_MSGQUEUE) + +#define vx_ipcmsg_avail(v, a) \ + vx_cres_avail(v, a, RLIMIT_MSGQUEUE) + + +#define vx_ipcshm_add(v, k, a) \ + vx_add_cres(v, a, (void *)(long)(k), VLIMIT_SHMEM) + +#define vx_ipcshm_sub(v, k, a) \ + vx_sub_cres(v, a, (void *)(long)(k), VLIMIT_SHMEM) + +#define vx_ipcshm_avail(v, a) \ + vx_cres_avail(v, a, VLIMIT_SHMEM) + + +#define vx_semary_inc(a) \ + vx_acc_cres(current->vx_info, 1, a, VLIMIT_SEMARY) + +#define vx_semary_dec(a) \ + vx_acc_cres(current->vx_info, -1, a, VLIMIT_SEMARY) + + +#define vx_nsems_add(a,n) \ + vx_add_cres(current->vx_info, n, a, VLIMIT_NSEMS) + +#define vx_nsems_sub(a,n) \ + vx_sub_cres(current->vx_info, n, a, VLIMIT_NSEMS) + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_memory.h linux-2.6.27.15-g-v/include/linux/vs_memory.h --- linux-2.6.27.15/include/linux/vs_memory.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_memory.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,159 @@ +#ifndef _VS_MEMORY_H +#define _VS_MEMORY_H + +#include "vserver/limit.h" +#include "vserver/base.h" +#include "vserver/context.h" +#include "vserver/debug.h" +#include "vserver/context.h" +#include "vserver/limit_int.h" + + +#define __acc_add_long(a, v) (*(v) += (a)) +#define __acc_inc_long(v) (++*(v)) +#define __acc_dec_long(v) (--*(v)) + +#if NR_CPUS >= CONFIG_SPLIT_PTLOCK_CPUS +#define __acc_add_atomic(a, v) atomic_long_add(a, v) +#define __acc_inc_atomic(v) atomic_long_inc(v) +#define __acc_dec_atomic(v) atomic_long_dec(v) +#else /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */ +#define __acc_add_atomic(a, v) __acc_add_long(a, v) +#define __acc_inc_atomic(v) __acc_inc_long(v) +#define __acc_dec_atomic(v) __acc_dec_long(v) +#endif /* NR_CPUS < CONFIG_SPLIT_PTLOCK_CPUS */ + + +#define vx_acc_page(m, d, v, r) do { \ + if ((d) > 0) \ + __acc_inc_long(&(m)->v); \ + else \ + __acc_dec_long(&(m)->v); \ + __vx_acc_cres(m->mm_vx_info, r, d, m, __FILE__, __LINE__); \ +} while (0) + +#define vx_acc_page_atomic(m, d, v, r) do { \ + if ((d) > 0) \ + __acc_inc_atomic(&(m)->v); \ + else \ + __acc_dec_atomic(&(m)->v); \ + __vx_acc_cres(m->mm_vx_info, r, d, m, __FILE__, __LINE__); \ +} while (0) + + +#define vx_acc_pages(m, p, v, r) do { \ + unsigned long __p = (p); \ + __acc_add_long(__p, &(m)->v); \ + __vx_add_cres(m->mm_vx_info, r, __p, m, __FILE__, __LINE__); \ +} while (0) + +#define vx_acc_pages_atomic(m, p, v, r) do { \ + unsigned long __p = (p); \ + __acc_add_atomic(__p, &(m)->v); \ + __vx_add_cres(m->mm_vx_info, r, __p, m, __FILE__, __LINE__); \ +} while (0) + + + +#define vx_acc_vmpage(m, d) \ + vx_acc_page(m, d, total_vm, RLIMIT_AS) +#define vx_acc_vmlpage(m, d) \ + vx_acc_page(m, d, locked_vm, RLIMIT_MEMLOCK) +#define vx_acc_file_rsspage(m, d) \ + vx_acc_page_atomic(m, d, _file_rss, VLIMIT_MAPPED) +#define vx_acc_anon_rsspage(m, d) \ + vx_acc_page_atomic(m, d, _anon_rss, VLIMIT_ANON) + +#define vx_acc_vmpages(m, p) \ + vx_acc_pages(m, p, total_vm, RLIMIT_AS) +#define vx_acc_vmlpages(m, p) \ + vx_acc_pages(m, p, locked_vm, RLIMIT_MEMLOCK) +#define vx_acc_file_rsspages(m, p) \ + vx_acc_pages_atomic(m, p, _file_rss, VLIMIT_MAPPED) +#define vx_acc_anon_rsspages(m, p) \ + vx_acc_pages_atomic(m, p, _anon_rss, VLIMIT_ANON) + +#define vx_pages_add(s, r, p) __vx_add_cres(s, r, p, 0, __FILE__, __LINE__) +#define vx_pages_sub(s, r, p) vx_pages_add(s, r, -(p)) + +#define vx_vmpages_inc(m) vx_acc_vmpage(m, 1) +#define vx_vmpages_dec(m) vx_acc_vmpage(m, -1) +#define vx_vmpages_add(m, p) vx_acc_vmpages(m, p) +#define vx_vmpages_sub(m, p) vx_acc_vmpages(m, -(p)) + +#define vx_vmlocked_inc(m) vx_acc_vmlpage(m, 1) +#define vx_vmlocked_dec(m) vx_acc_vmlpage(m, -1) +#define vx_vmlocked_add(m, p) vx_acc_vmlpages(m, p) +#define vx_vmlocked_sub(m, p) vx_acc_vmlpages(m, -(p)) + +#define vx_file_rsspages_inc(m) vx_acc_file_rsspage(m, 1) +#define vx_file_rsspages_dec(m) vx_acc_file_rsspage(m, -1) +#define vx_file_rsspages_add(m, p) vx_acc_file_rsspages(m, p) +#define vx_file_rsspages_sub(m, p) vx_acc_file_rsspages(m, -(p)) + +#define vx_anon_rsspages_inc(m) vx_acc_anon_rsspage(m, 1) +#define vx_anon_rsspages_dec(m) vx_acc_anon_rsspage(m, -1) +#define vx_anon_rsspages_add(m, p) vx_acc_anon_rsspages(m, p) +#define vx_anon_rsspages_sub(m, p) vx_acc_anon_rsspages(m, -(p)) + + +#define vx_pages_avail(m, p, r) \ + __vx_cres_avail((m)->mm_vx_info, r, p, __FILE__, __LINE__) + +#define vx_vmpages_avail(m, p) vx_pages_avail(m, p, RLIMIT_AS) +#define vx_vmlocked_avail(m, p) vx_pages_avail(m, p, RLIMIT_MEMLOCK) +#define vx_anon_avail(m, p) vx_pages_avail(m, p, VLIMIT_ANON) +#define vx_mapped_avail(m, p) vx_pages_avail(m, p, VLIMIT_MAPPED) + +#define vx_rss_avail(m, p) \ + __vx_cres_array_avail((m)->mm_vx_info, VLA_RSS, p, __FILE__, __LINE__) + + +enum { + VXPT_UNKNOWN = 0, + VXPT_ANON, + VXPT_NONE, + VXPT_FILE, + VXPT_SWAP, + VXPT_WRITE +}; + +#if 0 +#define vx_page_fault(mm, vma, type, ret) +#else + +static inline +void __vx_page_fault(struct mm_struct *mm, + struct vm_area_struct *vma, int type, int ret) +{ + struct vx_info *vxi = mm->mm_vx_info; + int what; +/* + static char *page_type[6] = + { "UNKNOWN", "ANON", "NONE", "FILE", "SWAP", "WRITE" }; + static char *page_what[4] = + { "FAULT_OOM", "FAULT_SIGBUS", "FAULT_MINOR", "FAULT_MAJOR" }; +*/ + + if (!vxi) + return; + + what = (ret & 0x3); + +/* printk("[%d] page[%d][%d] %2x %s %s\n", vxi->vx_id, + type, what, ret, page_type[type], page_what[what]); +*/ + if (ret & VM_FAULT_WRITE) + what |= 0x4; + atomic_inc(&vxi->cacct.page[type][what]); +} + +#define vx_page_fault(mm, vma, type, ret) __vx_page_fault(mm, vma, type, ret) +#endif + + +extern unsigned long vx_badness(struct task_struct *task, struct mm_struct *mm); + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_network.h linux-2.6.27.15-g-v/include/linux/vs_network.h --- linux-2.6.27.15/include/linux/vs_network.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_network.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,169 @@ +#ifndef _NX_VS_NETWORK_H +#define _NX_VS_NETWORK_H + +#include "vserver/context.h" +#include "vserver/network.h" +#include "vserver/base.h" +#include "vserver/check.h" +#include "vserver/debug.h" + +#include + + +#define get_nx_info(i) __get_nx_info(i, __FILE__, __LINE__) + +static inline struct nx_info *__get_nx_info(struct nx_info *nxi, + const char *_file, int _line) +{ + if (!nxi) + return NULL; + + vxlprintk(VXD_CBIT(nid, 2), "get_nx_info(%p[#%d.%d])", + nxi, nxi ? nxi->nx_id : 0, + nxi ? atomic_read(&nxi->nx_usecnt) : 0, + _file, _line); + + atomic_inc(&nxi->nx_usecnt); + return nxi; +} + + +extern void free_nx_info(struct nx_info *); + +#define put_nx_info(i) __put_nx_info(i, __FILE__, __LINE__) + +static inline void __put_nx_info(struct nx_info *nxi, const char *_file, int _line) +{ + if (!nxi) + return; + + vxlprintk(VXD_CBIT(nid, 2), "put_nx_info(%p[#%d.%d])", + nxi, nxi ? nxi->nx_id : 0, + nxi ? atomic_read(&nxi->nx_usecnt) : 0, + _file, _line); + + if (atomic_dec_and_test(&nxi->nx_usecnt)) + free_nx_info(nxi); +} + + +#define init_nx_info(p, i) __init_nx_info(p, i, __FILE__, __LINE__) + +static inline void __init_nx_info(struct nx_info **nxp, struct nx_info *nxi, + const char *_file, int _line) +{ + if (nxi) { + vxlprintk(VXD_CBIT(nid, 3), + "init_nx_info(%p[#%d.%d])", + nxi, nxi ? nxi->nx_id : 0, + nxi ? atomic_read(&nxi->nx_usecnt) : 0, + _file, _line); + + atomic_inc(&nxi->nx_usecnt); + } + *nxp = nxi; +} + + +#define set_nx_info(p, i) __set_nx_info(p, i, __FILE__, __LINE__) + +static inline void __set_nx_info(struct nx_info **nxp, struct nx_info *nxi, + const char *_file, int _line) +{ + struct nx_info *nxo; + + if (!nxi) + return; + + vxlprintk(VXD_CBIT(nid, 3), "set_nx_info(%p[#%d.%d])", + nxi, nxi ? nxi->nx_id : 0, + nxi ? atomic_read(&nxi->nx_usecnt) : 0, + _file, _line); + + atomic_inc(&nxi->nx_usecnt); + nxo = xchg(nxp, nxi); + BUG_ON(nxo); +} + +#define clr_nx_info(p) __clr_nx_info(p, __FILE__, __LINE__) + +static inline void __clr_nx_info(struct nx_info **nxp, + const char *_file, int _line) +{ + struct nx_info *nxo; + + nxo = xchg(nxp, NULL); + if (!nxo) + return; + + vxlprintk(VXD_CBIT(nid, 3), "clr_nx_info(%p[#%d.%d])", + nxo, nxo ? nxo->nx_id : 0, + nxo ? atomic_read(&nxo->nx_usecnt) : 0, + _file, _line); + + if (atomic_dec_and_test(&nxo->nx_usecnt)) + free_nx_info(nxo); +} + + +#define claim_nx_info(v, p) __claim_nx_info(v, p, __FILE__, __LINE__) + +static inline void __claim_nx_info(struct nx_info *nxi, + struct task_struct *task, const char *_file, int _line) +{ + vxlprintk(VXD_CBIT(nid, 3), "claim_nx_info(%p[#%d.%d.%d]) %p", + nxi, nxi ? nxi->nx_id : 0, + nxi?atomic_read(&nxi->nx_usecnt):0, + nxi?atomic_read(&nxi->nx_tasks):0, + task, _file, _line); + + atomic_inc(&nxi->nx_tasks); +} + + +extern void unhash_nx_info(struct nx_info *); + +#define release_nx_info(v, p) __release_nx_info(v, p, __FILE__, __LINE__) + +static inline void __release_nx_info(struct nx_info *nxi, + struct task_struct *task, const char *_file, int _line) +{ + vxlprintk(VXD_CBIT(nid, 3), "release_nx_info(%p[#%d.%d.%d]) %p", + nxi, nxi ? nxi->nx_id : 0, + nxi ? atomic_read(&nxi->nx_usecnt) : 0, + nxi ? atomic_read(&nxi->nx_tasks) : 0, + task, _file, _line); + + might_sleep(); + + if (atomic_dec_and_test(&nxi->nx_tasks)) + unhash_nx_info(nxi); +} + + +#define task_get_nx_info(i) __task_get_nx_info(i, __FILE__, __LINE__) + +static __inline__ struct nx_info *__task_get_nx_info(struct task_struct *p, + const char *_file, int _line) +{ + struct nx_info *nxi; + + task_lock(p); + vxlprintk(VXD_CBIT(nid, 5), "task_get_nx_info(%p)", + p, _file, _line); + nxi = __get_nx_info(p->nx_info, _file, _line); + task_unlock(p); + return nxi; +} + + +static inline void exit_nx_info(struct task_struct *p) +{ + if (p->nx_info) + release_nx_info(p->nx_info, p); +} + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_pid.h linux-2.6.27.15-g-v/include/linux/vs_pid.h --- linux-2.6.27.15/include/linux/vs_pid.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_pid.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,95 @@ +#ifndef _VS_PID_H +#define _VS_PID_H + +#include "vserver/base.h" +#include "vserver/check.h" +#include "vserver/context.h" +#include "vserver/debug.h" +#include "vserver/pid.h" +#include + + +#define VXF_FAKE_INIT (VXF_INFO_INIT | VXF_STATE_INIT) + +static inline +int vx_proc_task_visible(struct task_struct *task) +{ + if ((task->pid == 1) && + !vx_flags(VXF_FAKE_INIT, VXF_FAKE_INIT)) + /* show a blend through init */ + goto visible; + if (vx_check(vx_task_xid(task), VS_WATCH | VS_IDENT)) + goto visible; + return 0; +visible: + return 1; +} + +#define find_task_by_real_pid(pid) find_task_by_pid_ns(pid, &init_pid_ns) + +#if 0 + +static inline +struct task_struct *vx_find_proc_task_by_pid(int pid) +{ + struct task_struct *task = find_task_by_real_pid(pid); + + if (task && !vx_proc_task_visible(task)) { + vxdprintk(VXD_CBIT(misc, 6), + "dropping task (find) %p[#%u,%u] for %p[#%u,%u]", + task, task->xid, task->pid, + current, current->xid, current->pid); + task = NULL; + } + return task; +} + +#endif + +static inline +struct task_struct *vx_get_proc_task(struct inode *inode, struct pid *pid) +{ + struct task_struct *task = get_pid_task(pid, PIDTYPE_PID); + + if (task && !vx_proc_task_visible(task)) { + vxdprintk(VXD_CBIT(misc, 6), + "dropping task (get) %p[#%u,%u] for %p[#%u,%u]", + task, task->xid, task->pid, + current, current->xid, current->pid); + put_task_struct(task); + task = NULL; + } + return task; +} + +#if 0 + +static inline +struct task_struct *vx_child_reaper(struct task_struct *p) +{ + struct vx_info *vxi = p->vx_info; + struct task_struct *reaper = child_reaper(p); + + if (!vxi) + goto out; + + BUG_ON(!p->vx_info->vx_reaper); + + /* child reaper for the guest reaper */ + if (vxi->vx_reaper == p) + goto out; + + reaper = vxi->vx_reaper; +out: + vxdprintk(VXD_CBIT(xid, 7), + "vx_child_reaper(%p[#%u,%u]) = %p[#%u,%u]", + p, p->xid, p->pid, reaper, reaper->xid, reaper->pid); + return reaper; +} + +#endif + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_sched.h linux-2.6.27.15-g-v/include/linux/vs_sched.h --- linux-2.6.27.15/include/linux/vs_sched.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_sched.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,110 @@ +#ifndef _VS_SCHED_H +#define _VS_SCHED_H + +#include "vserver/base.h" +#include "vserver/context.h" +#include "vserver/sched.h" + + +#define VAVAVOOM_RATIO 50 + +#define MAX_PRIO_BIAS 20 +#define MIN_PRIO_BIAS -20 + + +#ifdef CONFIG_VSERVER_HARDCPU + +/* + * effective_prio - return the priority that is based on the static + * priority but is modified by bonuses/penalties. + * + * We scale the actual sleep average [0 .... MAX_SLEEP_AVG] + * into a -4 ... 0 ... +4 bonus/penalty range. + * + * Additionally, we scale another amount based on the number of + * CPU tokens currently held by the context, if the process is + * part of a context (and the appropriate SCHED flag is set). + * This ranges from -5 ... 0 ... +15, quadratically. + * + * So, the total bonus is -9 .. 0 .. +19 + * We use ~50% of the full 0...39 priority range so that: + * + * 1) nice +19 interactive tasks do not preempt nice 0 CPU hogs. + * 2) nice -20 CPU hogs do not get preempted by nice 0 tasks. + * unless that context is far exceeding its CPU allocation. + * + * Both properties are important to certain workloads. + */ +static inline +int vx_effective_vavavoom(struct _vx_sched_pc *sched_pc, int max_prio) +{ + int vavavoom, max; + + /* lots of tokens = lots of vavavoom + * no tokens = no vavavoom */ + if ((vavavoom = sched_pc->tokens) >= 0) { + max = sched_pc->tokens_max; + vavavoom = max - vavavoom; + max = max * max; + vavavoom = max_prio * VAVAVOOM_RATIO / 100 + * (vavavoom*vavavoom - (max >> 2)) / max; + return vavavoom; + } + return 0; +} + + +static inline +int vx_adjust_prio(struct task_struct *p, int prio, int max_user) +{ + struct vx_info *vxi = p->vx_info; + struct _vx_sched_pc *sched_pc; + + if (!vxi) + return prio; + + sched_pc = &vx_cpu(vxi, sched_pc); + if (vx_info_flags(vxi, VXF_SCHED_PRIO, 0)) { + int vavavoom = vx_effective_vavavoom(sched_pc, max_user); + + sched_pc->vavavoom = vavavoom; + prio += vavavoom; + } + prio += sched_pc->prio_bias; + return prio; +} + +#else /* !CONFIG_VSERVER_HARDCPU */ + +static inline +int vx_adjust_prio(struct task_struct *p, int prio, int max_user) +{ + struct vx_info *vxi = p->vx_info; + + if (vxi) + prio += vx_cpu(vxi, sched_pc).prio_bias; + return prio; +} + +#endif /* CONFIG_VSERVER_HARDCPU */ + + +static inline void vx_account_user(struct vx_info *vxi, + cputime_t cputime, int nice) +{ + if (!vxi) + return; + vx_cpu(vxi, sched_pc).user_ticks += cputime; +} + +static inline void vx_account_system(struct vx_info *vxi, + cputime_t cputime, int idle) +{ + if (!vxi) + return; + vx_cpu(vxi, sched_pc).sys_ticks += cputime; +} + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_socket.h linux-2.6.27.15-g-v/include/linux/vs_socket.h --- linux-2.6.27.15/include/linux/vs_socket.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_socket.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,67 @@ +#ifndef _VS_SOCKET_H +#define _VS_SOCKET_H + +#include "vserver/debug.h" +#include "vserver/base.h" +#include "vserver/cacct.h" +#include "vserver/context.h" +#include "vserver/tag.h" + + +/* socket accounting */ + +#include + +static inline int vx_sock_type(int family) +{ + switch (family) { + case PF_UNSPEC: + return VXA_SOCK_UNSPEC; + case PF_UNIX: + return VXA_SOCK_UNIX; + case PF_INET: + return VXA_SOCK_INET; + case PF_INET6: + return VXA_SOCK_INET6; + case PF_PACKET: + return VXA_SOCK_PACKET; + default: + return VXA_SOCK_OTHER; + } +} + +#define vx_acc_sock(v, f, p, s) \ + __vx_acc_sock(v, f, p, s, __FILE__, __LINE__) + +static inline void __vx_acc_sock(struct vx_info *vxi, + int family, int pos, int size, char *file, int line) +{ + if (vxi) { + int type = vx_sock_type(family); + + atomic_long_inc(&vxi->cacct.sock[type][pos].count); + atomic_long_add(size, &vxi->cacct.sock[type][pos].total); + } +} + +#define vx_sock_recv(sk, s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 0, s) +#define vx_sock_send(sk, s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 1, s) +#define vx_sock_fail(sk, s) \ + vx_acc_sock((sk)->sk_vx_info, (sk)->sk_family, 2, s) + + +#define sock_vx_init(s) do { \ + (s)->sk_xid = 0; \ + (s)->sk_vx_info = NULL; \ + } while (0) + +#define sock_nx_init(s) do { \ + (s)->sk_nid = 0; \ + (s)->sk_nx_info = NULL; \ + } while (0) + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_tag.h linux-2.6.27.15-g-v/include/linux/vs_tag.h --- linux-2.6.27.15/include/linux/vs_tag.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_tag.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,47 @@ +#ifndef _VS_TAG_H +#define _VS_TAG_H + +#include + +/* check conditions */ + +#define DX_ADMIN 0x0001 +#define DX_WATCH 0x0002 +#define DX_HOSTID 0x0008 + +#define DX_IDENT 0x0010 + +#define DX_ARG_MASK 0x0010 + + +#define dx_task_tag(t) ((t)->tag) + +#define dx_current_tag() dx_task_tag(current) + +#define dx_check(c, m) __dx_check(dx_current_tag(), c, m) + +#define dx_weak_check(c, m) ((m) ? dx_check(c, m) : 1) + + +/* + * check current context for ADMIN/WATCH and + * optionally against supplied argument + */ +static inline int __dx_check(tag_t cid, tag_t id, unsigned int mode) +{ + if (mode & DX_ARG_MASK) { + if ((mode & DX_IDENT) && (id == cid)) + return 1; + } + return (((mode & DX_ADMIN) && (cid == 0)) || + ((mode & DX_WATCH) && (cid == 1)) || + ((mode & DX_HOSTID) && (id == 0))); +} + +struct inode; +int dx_permission(struct inode *inode, int mask); + + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/linux/vs_time.h linux-2.6.27.15-g-v/include/linux/vs_time.h --- linux-2.6.27.15/include/linux/vs_time.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/include/linux/vs_time.h 2009-02-10 20:32:15.000000000 +0100 @@ -0,0 +1,19 @@ +#ifndef _VS_TIME_H +#define _VS_TIME_H + + +/* time faking stuff */ + +#ifdef CONFIG_VSERVER_VTIME + +extern void vx_gettimeofday(struct timeval *tv); +extern int vx_settimeofday(struct timespec *ts); + +#else +#define vx_gettimeofday(t) do_gettimeofday(t) +#define vx_settimeofday(t) do_settimeofday(t) +#endif + +#else +#warning duplicate inclusion +#endif diff -NurpP --minimal linux-2.6.27.15/include/net/addrconf.h linux-2.6.27.15-g-v/include/net/addrconf.h --- linux-2.6.27.15/include/net/addrconf.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/net/addrconf.h 2009-02-10 20:32:15.000000000 +0100 @@ -84,7 +84,8 @@ extern int ipv6_dev_get_saddr(struct n struct net_device *dev, const struct in6_addr *daddr, unsigned int srcprefs, - struct in6_addr *saddr); + struct in6_addr *saddr, + struct nx_info *nxi); extern int ipv6_get_lladdr(struct net_device *dev, struct in6_addr *addr, unsigned char banned_flags); diff -NurpP --minimal linux-2.6.27.15/include/net/af_unix.h linux-2.6.27.15-g-v/include/net/af_unix.h --- linux-2.6.27.15/include/net/af_unix.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/net/af_unix.h 2009-02-10 20:32:15.000000000 +0100 @@ -4,6 +4,7 @@ #include #include #include +#include #include extern void unix_inflight(struct file *fp); diff -NurpP --minimal linux-2.6.27.15/include/net/inet_sock.h linux-2.6.27.15-g-v/include/net/inet_sock.h --- linux-2.6.27.15/include/net/inet_sock.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/net/inet_sock.h 2009-02-10 20:32:15.000000000 +0100 @@ -24,7 +24,7 @@ #include #include #include -#include +// #include #include /** struct ip_options - IP Options @@ -195,11 +195,6 @@ static inline int inet_sk_ehashfn(const } -static inline int inet_iif(const struct sk_buff *skb) -{ - return skb->rtable->rt_iif; -} - static inline struct request_sock *inet_reqsk_alloc(struct request_sock_ops *ops) { struct request_sock *req = reqsk_alloc(ops); diff -NurpP --minimal linux-2.6.27.15/include/net/inet_timewait_sock.h linux-2.6.27.15-g-v/include/net/inet_timewait_sock.h --- linux-2.6.27.15/include/net/inet_timewait_sock.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/net/inet_timewait_sock.h 2009-02-10 20:32:15.000000000 +0100 @@ -15,15 +15,14 @@ #ifndef _INET_TIMEWAIT_SOCK_ #define _INET_TIMEWAIT_SOCK_ +// #include +#include #include #include #include #include #include - -#include -#include #include #include @@ -116,6 +115,10 @@ struct inet_timewait_sock { #define tw_hash __tw_common.skc_hash #define tw_prot __tw_common.skc_prot #define tw_net __tw_common.skc_net +#define tw_xid __tw_common.skc_xid +#define tw_vx_info __tw_common.skc_vx_info +#define tw_nid __tw_common.skc_nid +#define tw_nx_info __tw_common.skc_nx_info int tw_timeout; volatile unsigned char tw_substate; /* 3 bits hole, try to pack */ diff -NurpP --minimal linux-2.6.27.15/include/net/route.h linux-2.6.27.15-g-v/include/net/route.h --- linux-2.6.27.15/include/net/route.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/net/route.h 2009-02-10 20:32:15.000000000 +0100 @@ -28,6 +28,7 @@ #include #include #include +// #include #include #include #include @@ -85,6 +86,11 @@ struct ip_rt_acct __u32 i_packets; }; +static inline int inet_iif(const struct sk_buff *skb) +{ + return skb->rtable->rt_iif; +} + struct rt_cache_stat { unsigned int in_hit; @@ -135,6 +141,9 @@ static inline void ip_rt_put(struct rtab dst_release(&rt->u.dst); } +#include +#include + #define IPTOS_RT_MASK (IPTOS_TOS_MASK & ~3) extern const __u8 ip_tos2prio[16]; @@ -144,6 +153,9 @@ static inline char rt_tos2priority(u8 to return ip_tos2prio[IPTOS_TOS(tos)>>1]; } +extern int ip_v4_find_src(struct net *net, struct nx_info *, + struct rtable **, struct flowi *); + static inline int ip_route_connect(struct rtable **rp, __be32 dst, __be32 src, u32 tos, int oif, u8 protocol, __be16 sport, __be16 dport, struct sock *sk, @@ -161,7 +173,21 @@ static inline int ip_route_connect(struc int err; struct net *net = sock_net(sk); - if (!dst || !src) { + struct nx_info *nx_info = current->nx_info; + + if (sk) + nx_info = sk->sk_nx_info; + + vxdprintk(VXD_CBIT(net, 4), + "ip_route_connect(%p) %p,%p;%lx", + sk, nx_info, sk->sk_socket, + (sk->sk_socket?sk->sk_socket->flags:0)); + + err = ip_v4_find_src(net, nx_info, rp, &fl); + if (err) + return err; + + if (!fl.fl4_dst || !fl.fl4_src) { err = __ip_route_output_key(net, rp, &fl); if (err) return err; diff -NurpP --minimal linux-2.6.27.15/include/net/sctp/sctp.h linux-2.6.27.15-g-v/include/net/sctp/sctp.h --- linux-2.6.27.15/include/net/sctp/sctp.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/net/sctp/sctp.h 2009-02-10 20:32:15.000000000 +0100 @@ -309,8 +309,8 @@ extern int sctp_debug_flag; #else /* SCTP_DEBUG */ -#define SCTP_DEBUG_PRINTK(whatever...) -#define SCTP_DEBUG_PRINTK_IPADDR(whatever...) +#define SCTP_DEBUG_PRINTK(whatever...) do {} while (0) +#define SCTP_DEBUG_PRINTK_IPADDR(whatever...) do {} while (0) #define SCTP_ENABLE_DEBUG #define SCTP_DISABLE_DEBUG #define SCTP_ASSERT(expr, str, func) diff -NurpP --minimal linux-2.6.27.15/include/net/sock.h linux-2.6.27.15-g-v/include/net/sock.h --- linux-2.6.27.15/include/net/sock.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/net/sock.h 2009-02-10 20:32:15.000000000 +0100 @@ -128,6 +128,10 @@ struct sock_common { #ifdef CONFIG_NET_NS struct net *skc_net; #endif + xid_t skc_xid; + struct vx_info *skc_vx_info; + nid_t skc_nid; + struct nx_info *skc_nx_info; }; /** @@ -211,6 +215,10 @@ struct sock { #define sk_hash __sk_common.skc_hash #define sk_prot __sk_common.skc_prot #define sk_net __sk_common.skc_net +#define sk_xid __sk_common.skc_xid +#define sk_vx_info __sk_common.skc_vx_info +#define sk_nid __sk_common.skc_nid +#define sk_nx_info __sk_common.skc_nx_info unsigned char sk_shutdown : 2, sk_no_check : 2, sk_userlocks : 4; diff -NurpP --minimal linux-2.6.27.15/include/sound/core.h linux-2.6.27.15-g-v/include/sound/core.h --- linux-2.6.27.15/include/sound/core.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/sound/core.h 2009-02-10 20:32:15.000000000 +0100 @@ -406,9 +406,9 @@ void snd_verbose_printd(const char *file #else /* !CONFIG_SND_DEBUG */ -#define snd_printd(fmt, args...) /* nothing */ +#define snd_printd(fmt, args...) do {} while (0) #define snd_assert(expr, args...) (void)(expr) -#define snd_BUG() /* nothing */ +#define snd_BUG() do {} while (0) #endif /* CONFIG_SND_DEBUG */ @@ -422,7 +422,7 @@ void snd_verbose_printd(const char *file */ #define snd_printdd(format, args...) snd_printk(format, ##args) #else -#define snd_printdd(format, args...) /* nothing */ +#define snd_printdd(format, args...) do {} while (0) #endif diff -NurpP --minimal linux-2.6.27.15/include/video/uvesafb.h linux-2.6.27.15-g-v/include/video/uvesafb.h --- linux-2.6.27.15/include/video/uvesafb.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/include/video/uvesafb.h 2009-02-10 20:32:15.000000000 +0100 @@ -175,6 +175,7 @@ struct uvesafb_par { u8 ypan; /* 0 - nothing, 1 - ypan, 2 - ywrap */ u8 pmi_setpal; /* PMI for palette changes */ u16 *pmi_base; /* protected mode interface location */ + u8 *pmi_code; /* protected mode code location */ void *pmi_start; void *pmi_pal; u8 *vbe_state_orig; /* diff -NurpP --minimal linux-2.6.27.15/init/do_mounts.c linux-2.6.27.15-g-v/init/do_mounts.c --- linux-2.6.27.15/init/do_mounts.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/init/do_mounts.c 2009-02-10 20:32:16.000000000 +0100 @@ -214,11 +214,11 @@ static void __init get_fs_names(char *pa static int __init do_mount_root(char *name, char *fs, int flags, void *data) { - int err = sys_mount(name, "/root", fs, flags, data); + int err = sys_mount((char __user *)name, (char __user *)"/root", (char __user *)fs, flags, (void __user *)data); if (err) return err; - sys_chdir("/root"); + sys_chdir((char __user *)"/root"); ROOT_DEV = current->fs->pwd.mnt->mnt_sb->s_dev; printk("VFS: Mounted root (%s filesystem)%s.\n", current->fs->pwd.mnt->mnt_sb->s_type->name, @@ -304,18 +304,18 @@ void __init change_floppy(char *fmt, ... va_start(args, fmt); vsprintf(buf, fmt, args); va_end(args); - fd = sys_open("/dev/root", O_RDWR | O_NDELAY, 0); + fd = sys_open((char __user *)"/dev/root", O_RDWR | O_NDELAY, 0); if (fd >= 0) { sys_ioctl(fd, FDEJECT, 0); sys_close(fd); } printk(KERN_NOTICE "VFS: Insert %s and press ENTER\n", buf); - fd = sys_open("/dev/console", O_RDWR, 0); + fd = sys_open((char __user *)"/dev/console", O_RDWR, 0); if (fd >= 0) { sys_ioctl(fd, TCGETS, (long)&termios); termios.c_lflag &= ~ICANON; sys_ioctl(fd, TCSETSF, (long)&termios); - sys_read(fd, &c, 1); + sys_read(fd, (char __user *)&c, 1); termios.c_lflag |= ICANON; sys_ioctl(fd, TCSETSF, (long)&termios); sys_close(fd); @@ -402,7 +402,7 @@ void __init prepare_namespace(void) mount_root(); out: - sys_mount(".", "/", NULL, MS_MOVE, NULL); - sys_chroot("."); + sys_mount((char __user *)".", (char __user *)"/", NULL, MS_MOVE, NULL); + sys_chroot((char __user *)"."); } diff -NurpP --minimal linux-2.6.27.15/init/do_mounts.h linux-2.6.27.15-g-v/init/do_mounts.h --- linux-2.6.27.15/init/do_mounts.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/init/do_mounts.h 2009-02-10 20:32:16.000000000 +0100 @@ -14,15 +14,15 @@ extern int root_mountflags; static inline int create_dev(char *name, dev_t dev) { - sys_unlink(name); - return sys_mknod(name, S_IFBLK|0600, new_encode_dev(dev)); + sys_unlink((char __user *)name); + return sys_mknod((char __user *)name, S_IFBLK|0600, new_encode_dev(dev)); } #if BITS_PER_LONG == 32 static inline u32 bstat(char *name) { struct stat64 stat; - if (sys_stat64(name, &stat) != 0) + if (sys_stat64((char __user *)name, (struct stat64 __user *)&stat) != 0) return 0; if (!S_ISBLK(stat.st_mode)) return 0; diff -NurpP --minimal linux-2.6.27.15/init/do_mounts_initrd.c linux-2.6.27.15-g-v/init/do_mounts_initrd.c --- linux-2.6.27.15/init/do_mounts_initrd.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/init/do_mounts_initrd.c 2009-02-10 20:32:16.000000000 +0100 @@ -32,7 +32,7 @@ static int __init do_linuxrc(void * shel sys_close(old_fd);sys_close(root_fd); sys_close(0);sys_close(1);sys_close(2); sys_setsid(); - (void) sys_open("/dev/console",O_RDWR,0); + (void) sys_open((const char __user *)"/dev/console",O_RDWR,0); (void) sys_dup(0); (void) sys_dup(0); return kernel_execve(shell, argv, envp_init); @@ -47,13 +47,13 @@ static void __init handle_initrd(void) create_dev("/dev/root.old", Root_RAM0); /* mount initrd on rootfs' /root */ mount_block_root("/dev/root.old", root_mountflags & ~MS_RDONLY); - sys_mkdir("/old", 0700); - root_fd = sys_open("/", 0, 0); - old_fd = sys_open("/old", 0, 0); + sys_mkdir((const char __user *)"/old", 0700); + root_fd = sys_open((const char __user *)"/", 0, 0); + old_fd = sys_open((const char __user *)"/old", 0, 0); /* move initrd over / and chdir/chroot in initrd root */ - sys_chdir("/root"); - sys_mount(".", "/", NULL, MS_MOVE, NULL); - sys_chroot("."); + sys_chdir((const char __user *)"/root"); + sys_mount((char __user *)".", (char __user *)"/", NULL, MS_MOVE, NULL); + sys_chroot((const char __user *)"."); /* * In case that a resume from disk is carried out by linuxrc or one of @@ -70,15 +70,15 @@ static void __init handle_initrd(void) /* move initrd to rootfs' /old */ sys_fchdir(old_fd); - sys_mount("/", ".", NULL, MS_MOVE, NULL); + sys_mount((char __user *)"/", (char __user *)".", NULL, MS_MOVE, NULL); /* switch root and cwd back to / of rootfs */ sys_fchdir(root_fd); - sys_chroot("."); + sys_chroot((const char __user *)"."); sys_close(old_fd); sys_close(root_fd); if (new_decode_dev(real_root_dev) == Root_RAM0) { - sys_chdir("/old"); + sys_chdir((const char __user *)"/old"); return; } @@ -86,17 +86,17 @@ static void __init handle_initrd(void) mount_root(); printk(KERN_NOTICE "Trying to move old root to /initrd ... "); - error = sys_mount("/old", "/root/initrd", NULL, MS_MOVE, NULL); + error = sys_mount((char __user *)"/old", (char __user *)"/root/initrd", NULL, MS_MOVE, NULL); if (!error) printk("okay\n"); else { - int fd = sys_open("/dev/root.old", O_RDWR, 0); + int fd = sys_open((const char __user *)"/dev/root.old", O_RDWR, 0); if (error == -ENOENT) printk("/initrd does not exist. Ignored.\n"); else printk("failed\n"); printk(KERN_NOTICE "Unmounting old root\n"); - sys_umount("/old", MNT_DETACH); + sys_umount((char __user *)"/old", MNT_DETACH); printk(KERN_NOTICE "Trying to free ramdisk memory ... "); if (fd < 0) { error = fd; @@ -119,11 +119,11 @@ int __init initrd_load(void) * mounted in the normal path. */ if (rd_load_image("/initrd.image") && ROOT_DEV != Root_RAM0) { - sys_unlink("/initrd.image"); + sys_unlink((const char __user *)"/initrd.image"); handle_initrd(); return 1; } } - sys_unlink("/initrd.image"); + sys_unlink((const char __user *)"/initrd.image"); return 0; } diff -NurpP --minimal linux-2.6.27.15/init/do_mounts_md.c linux-2.6.27.15-g-v/init/do_mounts_md.c --- linux-2.6.27.15/init/do_mounts_md.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/init/do_mounts_md.c 2009-02-10 20:32:16.000000000 +0100 @@ -166,7 +166,7 @@ static void __init md_setup_drive(void) partitioned ? "_d" : "", minor, md_setup_args[ent].device_names); - fd = sys_open(name, 0, 0); + fd = sys_open((char __user *)name, 0, 0); if (fd < 0) { printk(KERN_ERR "md: open failed - cannot start " "array %s\n", name); @@ -229,7 +229,7 @@ static void __init md_setup_drive(void) * array without it */ sys_close(fd); - fd = sys_open(name, 0, 0); + fd = sys_open((char __user *)name, 0, 0); sys_ioctl(fd, BLKRRPART, 0); } sys_close(fd); @@ -270,7 +270,7 @@ void __init md_run_setup(void) if (raid_noautodetect) printk(KERN_INFO "md: Skipping autodetection of RAID arrays. (raid=noautodetect)\n"); else { - int fd = sys_open("/dev/md0", 0, 0); + int fd = sys_open((char __user *)"/dev/md0", 0, 0); if (fd >= 0) { sys_ioctl(fd, RAID_AUTORUN, raid_autopart); sys_close(fd); diff -NurpP --minimal linux-2.6.27.15/init/initramfs.c linux-2.6.27.15-g-v/init/initramfs.c --- linux-2.6.27.15/init/initramfs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/init/initramfs.c 2009-02-10 20:32:16.000000000 +0100 @@ -230,7 +230,7 @@ static int __init maybe_link(void) if (nlink >= 2) { char *old = find_link(major, minor, ino, mode, collected); if (old) - return (sys_link(old, collected) < 0) ? -1 : 1; + return (sys_link((char __user *)old, (char __user *)collected) < 0) ? -1 : 1; } return 0; } @@ -239,11 +239,11 @@ static void __init clean_path(char *path { struct stat st; - if (!sys_newlstat(path, &st) && (st.st_mode^mode) & S_IFMT) { + if (!sys_newlstat((char __user *)path, (struct stat __user *)&st) && (st.st_mode^mode) & S_IFMT) { if (S_ISDIR(st.st_mode)) - sys_rmdir(path); + sys_rmdir((char __user *)path); else - sys_unlink(path); + sys_unlink((char __user *)path); } } @@ -266,7 +266,7 @@ static int __init do_name(void) int openflags = O_WRONLY|O_CREAT; if (ml != 1) openflags |= O_TRUNC; - wfd = sys_open(collected, openflags, mode); + wfd = sys_open((char __user *)collected, openflags, mode); if (wfd >= 0) { sys_fchown(wfd, uid, gid); @@ -275,15 +275,15 @@ static int __init do_name(void) } } } else if (S_ISDIR(mode)) { - sys_mkdir(collected, mode); - sys_chown(collected, uid, gid); - sys_chmod(collected, mode); + sys_mkdir((char __user *)collected, mode); + sys_chown((char __user *)collected, uid, gid); + sys_chmod((char __user *)collected, mode); } else if (S_ISBLK(mode) || S_ISCHR(mode) || S_ISFIFO(mode) || S_ISSOCK(mode)) { if (maybe_link() == 0) { - sys_mknod(collected, mode, rdev); - sys_chown(collected, uid, gid); - sys_chmod(collected, mode); + sys_mknod((char __user *)collected, mode, rdev); + sys_chown((char __user *)collected, uid, gid); + sys_chmod((char __user *)collected, mode); } } return 0; @@ -292,13 +292,13 @@ static int __init do_name(void) static int __init do_copy(void) { if (count >= body_len) { - sys_write(wfd, victim, body_len); + sys_write(wfd, (char __user *)victim, body_len); sys_close(wfd); eat(body_len); state = SkipIt; return 0; } else { - sys_write(wfd, victim, count); + sys_write(wfd, (char __user *)victim, count); body_len -= count; eat(count); return 1; @@ -309,8 +309,8 @@ static int __init do_symlink(void) { collected[N_ALIGN(name_len) + body_len] = '\0'; clean_path(collected, 0); - sys_symlink(collected + N_ALIGN(name_len), collected); - sys_lchown(collected, uid, gid); + sys_symlink((char __user *)collected + N_ALIGN(name_len), (char __user *)collected); + sys_lchown((char __user *)collected, uid, gid); state = SkipIt; next_state = Reset; return 0; diff -NurpP --minimal linux-2.6.27.15/init/Kconfig linux-2.6.27.15-g-v/init/Kconfig --- linux-2.6.27.15/init/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/init/Kconfig 2009-02-10 20:32:16.000000000 +0100 @@ -561,6 +561,7 @@ config SYSCTL_SYSCALL config KALLSYMS bool "Load all symbols for debugging/ksymoops" if EMBEDDED default y + depends on !GRKERNSEC_HIDESYM help Say Y here to let the kernel print out symbolic crash information and symbolic stack backtraces. This increases the size of the kernel @@ -780,8 +781,8 @@ config MARKERS source "arch/Kconfig" config PROC_PAGE_MONITOR - default y - depends on PROC_FS && MMU + default n + depends on PROC_FS && MMU && !GRKERNSEC bool "Enable /proc page monitoring" if EMBEDDED help Various /proc files exist to monitor process memory utilization: @@ -797,9 +798,9 @@ config HAVE_GENERIC_DMA_COHERENT config SLABINFO bool - depends on PROC_FS + depends on PROC_FS && !GRKERNSEC_PROC_ADD depends on SLAB || SLUB_DEBUG - default y + default n config RT_MUTEXES boolean diff -NurpP --minimal linux-2.6.27.15/init/main.c linux-2.6.27.15-g-v/init/main.c --- linux-2.6.27.15/init/main.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/init/main.c 2009-02-10 20:32:16.000000000 +0100 @@ -60,6 +60,7 @@ #include #include #include +#include #include #include @@ -101,6 +102,7 @@ static inline void mark_rodata_ro(void) #ifdef CONFIG_TC extern void tc_init(void); #endif +extern void grsecurity_init(void); enum system_states system_state; EXPORT_SYMBOL(system_state); @@ -187,6 +189,40 @@ static int __init set_reset_devices(char __setup("reset_devices", set_reset_devices); +#if defined(CONFIG_PAX_MEMORY_UDEREF) && defined(CONFIG_X86_32) +static int __init setup_pax_nouderef(char *str) +{ + unsigned int cpu; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; + + pax_open_kernel(cr0); +#endif + + for (cpu = 0; cpu < NR_CPUS; cpu++) + get_cpu_gdt_table(cpu)[GDT_ENTRY_KERNEL_DS].b = 0x00cf9300; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + return 1; +} +__setup("pax_nouderef", setup_pax_nouderef); +#endif + +#ifdef CONFIG_PAX_SOFTMODE +unsigned int pax_softmode; + +static int __init setup_pax_softmode(char *str) +{ + get_option(&str, &pax_softmode); + return 1; +} +__setup("pax_softmode=", setup_pax_softmode); +#endif + static char * argv_init[MAX_INIT_ARGS+2] = { "init", NULL, }; char * envp_init[MAX_INIT_ENVS+2] = { "HOME=/", "TERM=linux", NULL, }; static const char *panic_later, *panic_param; @@ -385,18 +421,20 @@ static void __init setup_nr_cpu_ids(void } #ifndef CONFIG_HAVE_SETUP_PER_CPU_AREA -unsigned long __per_cpu_offset[NR_CPUS] __read_mostly; +unsigned long __per_cpu_offset[NR_CPUS] __read_only; EXPORT_SYMBOL(__per_cpu_offset); static void __init setup_per_cpu_areas(void) { - unsigned long size, i; + unsigned long size, vspc, i; char *ptr; unsigned long nr_possible_cpus = num_possible_cpus(); + vspc = PERCPU_PERCTX * CONFIG_VSERVER_CONTEXTS; + /* Copy section for each CPU (we discard the original) */ - size = ALIGN(PERCPU_ENOUGH_ROOM, PAGE_SIZE); + size = ALIGN(PERCPU_ENOUGH_ROOM + vspc, PAGE_SIZE); ptr = alloc_bootmem_pages(size * nr_possible_cpus); for_each_possible_cpu(i) { @@ -704,6 +742,7 @@ int do_one_initcall(initcall_t fn) { int count = preempt_count(); ktime_t t0, t1, delta; + const char *msg1 = "", *msg2 = ""; char msgbuf[64]; int result; @@ -729,15 +768,15 @@ int do_one_initcall(initcall_t fn) sprintf(msgbuf, "error code %d ", result); if (preempt_count() != count) { - strlcat(msgbuf, "preemption imbalance ", sizeof(msgbuf)); + msg1 = " preemption imbalance"; preempt_count() = count; } if (irqs_disabled()) { - strlcat(msgbuf, "disabled interrupts ", sizeof(msgbuf)); + msg2 = " disabled interrupts"; local_irq_enable(); } - if (msgbuf[0]) { - printk("initcall %pF returned with %s\n", fn, msgbuf); + if (msgbuf[0] || *msg1 || *msg2) { + printk("initcall %pF returned with %s%s%s\n", fn, msgbuf, msg1, msg2); } return result; @@ -876,6 +915,8 @@ static int __init kernel_init(void * unu prepare_namespace(); } + grsecurity_init(); + /* * Ok, we have completed the initial bootup, and * we're essentially up and running. Get rid of the diff -NurpP --minimal linux-2.6.27.15/init/noinitramfs.c linux-2.6.27.15-g-v/init/noinitramfs.c --- linux-2.6.27.15/init/noinitramfs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/init/noinitramfs.c 2009-02-10 20:32:16.000000000 +0100 @@ -29,7 +29,7 @@ static int __init default_rootfs(void) { int err; - err = sys_mkdir("/dev", 0755); + err = sys_mkdir((const char __user *)"/dev", 0755); if (err < 0) goto out; @@ -39,7 +39,7 @@ static int __init default_rootfs(void) if (err < 0) goto out; - err = sys_mkdir("/root", 0700); + err = sys_mkdir((const char __user *)"/root", 0700); if (err < 0) goto out; diff -NurpP --minimal linux-2.6.27.15/ipc/ipc_sysctl.c linux-2.6.27.15-g-v/ipc/ipc_sysctl.c --- linux-2.6.27.15/ipc/ipc_sysctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/ipc/ipc_sysctl.c 2009-02-10 20:32:16.000000000 +0100 @@ -268,7 +268,7 @@ static struct ctl_table ipc_kern_table[] .extra1 = &zero, .extra2 = &one, }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static struct ctl_table ipc_root_table[] = { @@ -278,7 +278,7 @@ static struct ctl_table ipc_root_table[] .mode = 0555, .child = ipc_kern_table, }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static int __init ipc_sysctl_init(void) diff -NurpP --minimal linux-2.6.27.15/ipc/mqueue.c linux-2.6.27.15-g-v/ipc/mqueue.c --- linux-2.6.27.15/ipc/mqueue.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/ipc/mqueue.c 2009-02-10 20:32:16.000000000 +0100 @@ -31,6 +31,8 @@ #include #include #include +#include +#include #include #include "util.h" @@ -71,6 +73,7 @@ struct mqueue_inode_info { struct sigevent notify; struct pid* notify_owner; struct user_struct *user; /* user who created, for accounting */ + struct vx_info *vxi; struct sock *notify_sock; struct sk_buff *notify_cookie; @@ -119,6 +122,7 @@ static struct inode *mqueue_get_inode(st struct mqueue_inode_info *info; struct task_struct *p = current; struct user_struct *u = p->user; + struct vx_info *vxi = p->vx_info; unsigned long mq_bytes, mq_msg_tblsz; inode->i_fop = &mqueue_file_operations; @@ -133,6 +137,7 @@ static struct inode *mqueue_get_inode(st info->notify_owner = NULL; info->qsize = 0; info->user = NULL; /* set when all is ok */ + info->vxi = NULL; memset(&info->attr, 0, sizeof(info->attr)); info->attr.mq_maxmsg = DFLT_MSGMAX; info->attr.mq_msgsize = DFLT_MSGSIZEMAX; @@ -147,22 +152,26 @@ static struct inode *mqueue_get_inode(st spin_lock(&mq_lock); if (u->mq_bytes + mq_bytes < u->mq_bytes || u->mq_bytes + mq_bytes > - p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur) { + p->signal->rlim[RLIMIT_MSGQUEUE].rlim_cur || + !vx_ipcmsg_avail(vxi, mq_bytes)) { spin_unlock(&mq_lock); goto out_inode; } u->mq_bytes += mq_bytes; + vx_ipcmsg_add(vxi, u, mq_bytes); spin_unlock(&mq_lock); info->messages = kmalloc(mq_msg_tblsz, GFP_KERNEL); if (!info->messages) { spin_lock(&mq_lock); u->mq_bytes -= mq_bytes; + vx_ipcmsg_sub(vxi, u, mq_bytes); spin_unlock(&mq_lock); goto out_inode; } /* all is ok */ info->user = get_uid(u); + info->vxi = get_vx_info(vxi); } else if (S_ISDIR(mode)) { inc_nlink(inode); /* Some things misbehave if size == 0 on a directory */ @@ -253,10 +262,14 @@ static void mqueue_delete_inode(struct i (info->attr.mq_maxmsg * info->attr.mq_msgsize)); user = info->user; if (user) { + struct vx_info *vxi = info->vxi; + spin_lock(&mq_lock); user->mq_bytes -= mq_bytes; + vx_ipcmsg_sub(vxi, user, mq_bytes); queues_count--; spin_unlock(&mq_lock); + put_vx_info(vxi); free_uid(user); } } diff -NurpP --minimal linux-2.6.27.15/ipc/msg.c linux-2.6.27.15-g-v/ipc/msg.c --- linux-2.6.27.15/ipc/msg.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/ipc/msg.c 2009-02-10 20:32:16.000000000 +0100 @@ -38,6 +38,8 @@ #include #include #include +#include +#include #include #include @@ -190,6 +192,7 @@ static int newque(struct ipc_namespace * msq->q_perm.mode = msgflg & S_IRWXUGO; msq->q_perm.key = key; + msq->q_perm.xid = vx_current_xid(); msq->q_perm.security = NULL; retval = security_msg_queue_alloc(msq); @@ -314,6 +317,7 @@ SYSCALL_DEFINE2(msgget, key_t, key, int, struct ipc_namespace *ns; struct ipc_ops msg_ops; struct ipc_params msg_params; + long err; ns = current->nsproxy->ipc_ns; @@ -324,7 +328,11 @@ SYSCALL_DEFINE2(msgget, key_t, key, int, msg_params.key = key; msg_params.flg = msgflg; - return ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params); + err = ipcget(ns, &msg_ids(ns), &msg_ops, &msg_params); + + gr_log_msgget(err, msgflg); + + return err; } static inline unsigned long @@ -434,6 +442,7 @@ static int msgctl_down(struct ipc_namesp switch (cmd) { case IPC_RMID: + gr_log_msgrm(ipcp->uid, ipcp->cuid); freeque(ns, ipcp); goto out_up; case IPC_SET: diff -NurpP --minimal linux-2.6.27.15/ipc/namespace.c linux-2.6.27.15-g-v/ipc/namespace.c --- linux-2.6.27.15/ipc/namespace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/ipc/namespace.c 2009-02-10 20:32:16.000000000 +0100 @@ -9,6 +9,8 @@ #include #include #include +#include +#include #include "util.h" @@ -35,6 +37,7 @@ static struct ipc_namespace *clone_ipc_n register_ipcns_notifier(ns); kref_init(&ns->kref); + atomic_inc(&vs_global_ipc_ns); return ns; } @@ -101,6 +104,7 @@ void free_ipc_ns(struct kref *kref) sem_exit_ns(ns); msg_exit_ns(ns); shm_exit_ns(ns); + atomic_dec(&vs_global_ipc_ns); kfree(ns); atomic_dec(&nr_ipc_ns); diff -NurpP --minimal linux-2.6.27.15/ipc/sem.c linux-2.6.27.15-g-v/ipc/sem.c --- linux-2.6.27.15/ipc/sem.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/ipc/sem.c 2009-02-10 20:32:16.000000000 +0100 @@ -83,6 +83,9 @@ #include #include #include +#include +#include +#include #include #include "util.h" @@ -255,6 +258,7 @@ static int newary(struct ipc_namespace * sma->sem_perm.mode = (semflg & S_IRWXUGO); sma->sem_perm.key = key; + sma->sem_perm.xid = vx_current_xid(); sma->sem_perm.security = NULL; retval = security_sem_alloc(sma); @@ -270,6 +274,9 @@ static int newary(struct ipc_namespace * return id; } ns->used_sems += nsems; + /* FIXME: obsoleted? */ + vx_semary_inc(sma); + vx_nsems_add(sma, nsems); sma->sem_base = (struct sem *) &sma[1]; INIT_LIST_HEAD(&sma->sem_pending); @@ -313,6 +320,7 @@ SYSCALL_DEFINE3(semget, key_t, key, int, struct ipc_namespace *ns; struct ipc_ops sem_ops; struct ipc_params sem_params; + long err; ns = current->nsproxy->ipc_ns; @@ -327,7 +335,11 @@ SYSCALL_DEFINE3(semget, key_t, key, int, sem_params.flg = semflg; sem_params.u.nsems = nsems; - return ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); + err = ipcget(ns, &sem_ids(ns), &sem_ops, &sem_params); + + gr_log_semget(err, semflg); + + return err; } /* @@ -870,6 +882,7 @@ static int semctl_down(struct ipc_namesp switch(cmd){ case IPC_RMID: + gr_log_semrm(ipcp->uid, ipcp->cuid); freeary(ns, ipcp); goto out_up; case IPC_SET: diff -NurpP --minimal linux-2.6.27.15/ipc/shm.c linux-2.6.27.15-g-v/ipc/shm.c --- linux-2.6.27.15/ipc/shm.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/ipc/shm.c 2009-02-10 20:32:16.000000000 +0100 @@ -39,6 +39,9 @@ #include #include #include +#include +#include +#include #include @@ -69,6 +72,14 @@ static void shm_destroy (struct ipc_name static int sysvipc_shm_proc_show(struct seq_file *s, void *it); #endif +#ifdef CONFIG_GRKERNSEC +extern int gr_handle_shmat(const pid_t shm_cprid, const pid_t shm_lapid, + const time_t shm_createtime, const uid_t cuid, + const int shmid); +extern int gr_chroot_shmat(const pid_t shm_cprid, const pid_t shm_lapid, + const time_t shm_createtime); +#endif + void shm_init_ns(struct ipc_namespace *ns) { ns->shm_ctlmax = SHMMAX; @@ -87,6 +98,8 @@ static void do_shm_rmid(struct ipc_names struct shmid_kernel *shp; shp = container_of(ipcp, struct shmid_kernel, shm_perm); + gr_log_shmrm(shp->shm_perm.uid, shp->shm_perm.cuid); + if (shp->shm_nattch){ shp->shm_perm.mode |= SHM_DEST; /* Do not find it any more */ @@ -168,7 +181,12 @@ static void shm_open(struct vm_area_stru */ static void shm_destroy(struct ipc_namespace *ns, struct shmid_kernel *shp) { - ns->shm_tot -= (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; + struct vx_info *vxi = lookup_vx_info(shp->shm_perm.xid); + int numpages = (shp->shm_segsz + PAGE_SIZE - 1) >> PAGE_SHIFT; + + vx_ipcshm_sub(vxi, shp, numpages); + ns->shm_tot -= numpages; + shm_rmid(ns, shp); shm_unlock(shp); if (!is_file_hugepages(shp->shm_file)) @@ -178,6 +196,7 @@ static void shm_destroy(struct ipc_names shp->mlock_user); fput (shp->shm_file); security_shm_free(shp); + put_vx_info(vxi); ipc_rcu_putref(shp); } @@ -347,11 +366,15 @@ static int newseg(struct ipc_namespace * if (ns->shm_tot + numpages > ns->shm_ctlall) return -ENOSPC; + if (!vx_ipcshm_avail(current->vx_info, numpages)) + return -ENOSPC; + shp = ipc_rcu_alloc(sizeof(*shp)); if (!shp) return -ENOMEM; shp->shm_perm.key = key; + shp->shm_perm.xid = vx_current_xid(); shp->shm_perm.mode = (shmflg & S_IRWXUGO); shp->mlock_user = NULL; @@ -392,6 +415,14 @@ static int newseg(struct ipc_namespace * shp->shm_lprid = 0; shp->shm_atim = shp->shm_dtim = 0; shp->shm_ctim = get_seconds(); +#ifdef CONFIG_GRKERNSEC + { + struct timespec timeval; + do_posix_clock_monotonic_gettime(&timeval); + + shp->shm_createtime = timeval.tv_sec; + } +#endif shp->shm_segsz = size; shp->shm_nattch = 0; shp->shm_file = file; @@ -404,6 +435,7 @@ static int newseg(struct ipc_namespace * ns->shm_tot += numpages; error = shp->shm_perm.id; shm_unlock(shp); + vx_ipcshm_add(current->vx_info, key, numpages); return error; no_id: @@ -445,6 +477,7 @@ SYSCALL_DEFINE3(shmget, key_t, key, size struct ipc_namespace *ns; struct ipc_ops shm_ops; struct ipc_params shm_params; + long err; ns = current->nsproxy->ipc_ns; @@ -456,7 +489,11 @@ SYSCALL_DEFINE3(shmget, key_t, key, size shm_params.flg = shmflg; shm_params.u.size = size; - return ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params); + err = ipcget(ns, &shm_ids(ns), &shm_ops, &shm_params); + + gr_log_shmget(err, shmflg, size); + + return err; } static inline unsigned long copy_shmid_to_user(void __user *buf, struct shmid64_ds *in, int version) @@ -869,9 +906,21 @@ long do_shmat(int shmid, char __user *sh if (err) goto out_unlock; +#ifdef CONFIG_GRKERNSEC + if (!gr_handle_shmat(shp->shm_cprid, shp->shm_lapid, shp->shm_createtime, + shp->shm_perm.cuid, shmid) || + !gr_chroot_shmat(shp->shm_cprid, shp->shm_lapid, shp->shm_createtime)) { + err = -EACCES; + goto out_unlock; + } +#endif + path.dentry = dget(shp->shm_file->f_path.dentry); path.mnt = shp->shm_file->f_path.mnt; shp->shm_nattch++; +#ifdef CONFIG_GRKERNSEC + shp->shm_lapid = current->pid; +#endif size = i_size_read(path.dentry->d_inode); shm_unlock(shp); diff -NurpP --minimal linux-2.6.27.15/kernel/acct.c linux-2.6.27.15-g-v/kernel/acct.c --- linux-2.6.27.15/kernel/acct.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/acct.c 2009-02-10 20:32:16.000000000 +0100 @@ -573,7 +573,7 @@ static void do_acct_process(struct bsd_a */ flim = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; current->signal->rlim[RLIMIT_FSIZE].rlim_cur = RLIM_INFINITY; - file->f_op->write(file, (char *)&ac, + file->f_op->write(file, (char __user *)&ac, sizeof(acct_t), &file->f_pos); current->signal->rlim[RLIMIT_FSIZE].rlim_cur = flim; set_fs(fs); diff -NurpP --minimal linux-2.6.27.15/kernel/capability.c linux-2.6.27.15-g-v/kernel/capability.c --- linux-2.6.27.15/kernel/capability.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/capability.c 2009-02-10 20:32:16.000000000 +0100 @@ -13,6 +13,8 @@ #include #include #include +#include +#include #include /* @@ -166,6 +168,8 @@ static inline int cap_set_pg(int pgrp_nr pgrp = find_vpid(pgrp_nr); do_each_pid_task(pgrp, PIDTYPE_PGID, g) { + if (!vx_check(g->xid, VS_ADMIN_P | VS_IDENT)) + continue; target = g; while_each_thread(g, target) { if (!security_capset_check(target, effective, @@ -486,6 +490,8 @@ SYSCALL_DEFINE2(capset, cap_user_header_ return ret; } +#include + /** * capable - Determine if the current task has a superior capability in effect * @cap: The capability to be tested for @@ -498,10 +504,27 @@ SYSCALL_DEFINE2(capset, cap_user_header_ */ int capable(int cap) { - if (has_capability(current, cap)) { + /* here for now so we don't require task locking */ + if (vs_check_bit(VXC_CAP_MASK, cap) && !vx_mcaps(1L << cap)) + return 0; + if (has_capability(current, cap) && gr_task_is_capable(current, cap)) { current->flags |= PF_SUPERPRIV; return 1; } return 0; } + +int capable_nolog(int cap) +{ + /* here for now so we don't require task locking */ + if (vs_check_bit(VXC_CAP_MASK, cap) && !vx_mcaps(1L << cap)) + return 0; + if (has_capability(current, cap) && gr_is_capable_nolog(cap)) { + current->flags |= PF_SUPERPRIV; + return 1; + } + return 0; +} + EXPORT_SYMBOL(capable); +EXPORT_SYMBOL(capable_nolog); diff -NurpP --minimal linux-2.6.27.15/kernel/compat.c linux-2.6.27.15-g-v/kernel/compat.c --- linux-2.6.27.15/kernel/compat.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/compat.c 2009-02-10 20:32:16.000000000 +0100 @@ -845,7 +845,7 @@ asmlinkage long compat_sys_time(compat_t compat_time_t i; struct timeval tv; - do_gettimeofday(&tv); + vx_gettimeofday(&tv); i = tv.tv_sec; if (tloc) { @@ -869,7 +869,7 @@ asmlinkage long compat_sys_stime(compat_ if (err) return err; - do_settimeofday(&tv); + vx_settimeofday(&tv); return 0; } diff -NurpP --minimal linux-2.6.27.15/kernel/configs.c linux-2.6.27.15-g-v/kernel/configs.c --- linux-2.6.27.15/kernel/configs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/configs.c 2009-02-10 20:32:16.000000000 +0100 @@ -79,8 +79,19 @@ static int __init ikconfig_init(void) struct proc_dir_entry *entry; /* create the current config file */ +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + entry = proc_create("config.gz", S_IFREG | S_IRUSR, NULL, + &ikconfig_file_ops); +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + entry = proc_create("config.gz", S_IFREG | S_IRUSR | S_IRGRP, NULL, + &ikconfig_file_ops); +#endif +#else entry = proc_create("config.gz", S_IFREG | S_IRUGO, NULL, &ikconfig_file_ops); +#endif + if (!entry) return -ENOMEM; diff -NurpP --minimal linux-2.6.27.15/kernel/cpu.c linux-2.6.27.15-g-v/kernel/cpu.c --- linux-2.6.27.15/kernel/cpu.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/cpu.c 2009-02-10 20:32:16.000000000 +0100 @@ -40,7 +40,7 @@ EXPORT_SYMBOL(cpu_possible_map); /* Serializes the updates to cpu_online_map, cpu_present_map */ static DEFINE_MUTEX(cpu_add_remove_lock); -static __cpuinitdata RAW_NOTIFIER_HEAD(cpu_chain); +static RAW_NOTIFIER_HEAD(cpu_chain); /* If set, cpu_up and cpu_down will return -EBUSY and do nothing. * Should always be manipulated under cpu_add_remove_lock diff -NurpP --minimal linux-2.6.27.15/kernel/exit.c linux-2.6.27.15-g-v/kernel/exit.c --- linux-2.6.27.15/kernel/exit.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/exit.c 2009-02-10 20:32:16.000000000 +0100 @@ -40,13 +40,22 @@ #include #include #include -#include #include #include /* for audit_free() */ #include #include #include #include +#include +#include +#include +#include +#include +#include + +#ifdef CONFIG_GRKERNSEC +extern rwlock_t grsec_exec_file_lock; +#endif #include #include @@ -133,7 +142,6 @@ static void __exit_signal(struct task_st * doing sigqueue_free() if we have SIGQUEUE_PREALLOC signals. */ flush_sigqueue(&tsk->pending); - tsk->signal = NULL; tsk->sighand = NULL; spin_unlock(&sighand->siglock); @@ -158,6 +166,8 @@ void release_task(struct task_struct * p struct task_struct *leader; int zap_leader; repeat: + gr_del_task_from_ip_table(p); + tracehook_prepare_release_task(p); atomic_dec(&p->user->processes); proc_flush_task(p); @@ -321,11 +331,22 @@ static void reparent_to_kthreadd(void) { write_lock_irq(&tasklist_lock); +#ifdef CONFIG_GRKERNSEC + write_lock(&grsec_exec_file_lock); + if (current->exec_file) { + fput(current->exec_file); + current->exec_file = NULL; + } + write_unlock(&grsec_exec_file_lock); +#endif + ptrace_unlink(current); /* Reparent to init */ current->real_parent = current->parent = kthreadd_task; list_move_tail(¤t->sibling, ¤t->real_parent->children); + gr_set_kernel_label(current); + /* Set the exit signal to SIGCHLD so we signal init on exit */ current->exit_signal = SIGCHLD; @@ -419,6 +440,17 @@ void daemonize(const char *name, ...) vsnprintf(current->comm, sizeof(current->comm), name, args); va_end(args); +#ifdef CONFIG_GRKERNSEC + write_lock(&grsec_exec_file_lock); + if (current->exec_file) { + fput(current->exec_file); + current->exec_file = NULL; + } + write_unlock(&grsec_exec_file_lock); +#endif + + gr_set_kernel_label(current); + /* * If we were started as result of loading a module, close all of the * user space pages. We don't need them, and if we didn't close them @@ -485,9 +517,11 @@ static void close_files(struct files_str filp_close(file, files); cond_resched(); } + vx_openfd_dec(i); } i++; set >>= 1; + cond_resched(); } } } @@ -554,6 +588,7 @@ void put_fs_struct(struct fs_struct *fs) if (atomic_dec_and_test(&fs->count)) { path_put(&fs->root); path_put(&fs->pwd); + atomic_dec(&vs_global_fs); kmem_cache_free(fs_cachep, fs); } } @@ -1054,14 +1089,6 @@ NORET_TYPE void do_exit(long code) exit_itimers(tsk->signal); } acct_collect(code, group_dead); -#ifdef CONFIG_FUTEX - if (unlikely(tsk->robust_list)) - exit_robust_list(tsk); -#ifdef CONFIG_COMPAT - if (unlikely(tsk->compat_robust_list)) - compat_exit_robust_list(tsk); -#endif -#endif if (group_dead) tty_audit_exit(); if (unlikely(tsk->audit_context)) @@ -1070,6 +1097,9 @@ NORET_TYPE void do_exit(long code) tsk->exit_code = code; taskstats_exit(tsk, group_dead); + gr_acl_handle_psacct(tsk, code); + gr_acl_handle_exit(); + exit_mm(tsk); if (group_dead) @@ -1122,6 +1152,10 @@ NORET_TYPE void do_exit(long code) if (tsk->splice_pipe) __free_pipe_info(tsk->splice_pipe); + /* needs to stay after exit_notify() */ + exit_vx_info(tsk, code); + exit_nx_info(tsk); + preempt_disable(); /* causes final put_task_struct in finish_task_switch(). */ tsk->state = TASK_DEAD; @@ -1274,7 +1308,7 @@ static int wait_task_zombie(struct task_ if (unlikely(options & WNOWAIT)) { uid_t uid = p->uid; int exit_code = p->exit_code; - int why, status; + int why; get_task_struct(p); read_unlock(&tasklist_lock); diff -NurpP --minimal linux-2.6.27.15/kernel/fork.c linux-2.6.27.15-g-v/kernel/fork.c --- linux-2.6.27.15/kernel/fork.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/fork.c 2009-02-10 20:32:16.000000000 +0100 @@ -40,6 +40,7 @@ #include #include #include +#include #include #include #include @@ -58,6 +59,12 @@ #include #include #include +#include +#include +#include +#include +#include +#include #include #include @@ -135,6 +142,8 @@ void free_task(struct task_struct *tsk) prop_local_destroy_single(&tsk->dirties); free_thread_info(tsk->stack); rt_mutex_debug_task_free(tsk); + clr_vx_info(&tsk->vx_info); + clr_nx_info(&tsk->nx_info); free_task_struct(tsk); } EXPORT_SYMBOL(free_task); @@ -234,7 +243,7 @@ static struct task_struct *dup_task_stru setup_thread_stack(tsk, orig); #ifdef CONFIG_CC_STACKPROTECTOR - tsk->stack_canary = get_random_int(); + tsk->stack_canary = pax_get_random_long(); #endif /* One for us, one for whoever does the "release_task()" (usually parent) */ @@ -271,9 +280,11 @@ static int dup_mmap(struct mm_struct *mm mm->locked_vm = 0; mm->mmap = NULL; mm->mmap_cache = NULL; - mm->free_area_cache = oldmm->mmap_base; - mm->cached_hole_size = ~0UL; + mm->free_area_cache = oldmm->free_area_cache; + mm->cached_hole_size = oldmm->cached_hole_size; mm->map_count = 0; + __set_mm_counter(mm, file_rss, 0); + __set_mm_counter(mm, anon_rss, 0); cpus_clear(mm->cpu_vm_mask); mm->mm_rb = RB_ROOT; rb_link = &mm->mm_rb.rb_node; @@ -285,7 +296,7 @@ static int dup_mmap(struct mm_struct *mm if (mpnt->vm_flags & VM_DONTCOPY) { long pages = vma_pages(mpnt); - mm->total_vm -= pages; + vx_vmpages_sub(mm, pages); vm_stat_account(mm, mpnt->vm_flags, mpnt->vm_file, -pages); continue; @@ -309,6 +320,7 @@ static int dup_mmap(struct mm_struct *mm tmp->vm_flags &= ~VM_LOCKED; tmp->vm_mm = mm; tmp->vm_next = NULL; + tmp->vm_mirror = NULL; anon_vma_link(tmp); file = tmp->vm_file; if (file) { @@ -356,6 +368,31 @@ static int dup_mmap(struct mm_struct *mm if (retval) goto out; } + +#ifdef CONFIG_PAX_SEGMEXEC + if (oldmm->pax_flags & MF_PAX_SEGMEXEC) { + struct vm_area_struct *mpnt_m; + + for (mpnt = oldmm->mmap, mpnt_m = mm->mmap; mpnt; mpnt = mpnt->vm_next, mpnt_m = mpnt_m->vm_next) { + BUG_ON(!mpnt_m || mpnt_m->vm_mirror || mpnt->vm_mm != oldmm || mpnt_m->vm_mm != mm); + + if (!mpnt->vm_mirror) + continue; + + if (mpnt->vm_end <= SEGMEXEC_TASK_SIZE) { + BUG_ON(mpnt->vm_mirror->vm_mirror != mpnt); + mpnt->vm_mirror = mpnt_m; + } else { + BUG_ON(mpnt->vm_mirror->vm_mirror == mpnt || mpnt->vm_mirror->vm_mirror->vm_mm != mm); + mpnt_m->vm_mirror = mpnt->vm_mirror->vm_mirror; + mpnt_m->vm_mirror->vm_mirror = mpnt_m; + mpnt->vm_mirror->vm_mirror = mpnt; + } + } + BUG_ON(mpnt_m); + } +#endif + /* a new mm has just been created */ arch_dup_mmap(oldmm, mm); retval = 0; @@ -407,8 +444,8 @@ static struct mm_struct * mm_init(struct : MMF_DUMP_FILTER_DEFAULT; mm->core_state = NULL; mm->nr_ptes = 0; - set_mm_counter(mm, file_rss, 0); - set_mm_counter(mm, anon_rss, 0); + __set_mm_counter(mm, file_rss, 0); + __set_mm_counter(mm, anon_rss, 0); spin_lock_init(&mm->page_table_lock); rwlock_init(&mm->ioctx_list_lock); mm->ioctx_list = NULL; @@ -419,6 +456,7 @@ static struct mm_struct * mm_init(struct if (likely(!mm_alloc_pgd(mm))) { mm->def_flags = 0; mmu_notifier_mm_init(mm); + set_vx_info(&mm->mm_vx_info, p->vx_info); return mm; } @@ -452,6 +490,7 @@ void __mmdrop(struct mm_struct *mm) mm_free_pgd(mm); destroy_context(mm); mmu_notifier_mm_destroy(mm); + clr_vx_info(&mm->mm_vx_info); free_mm(mm); } EXPORT_SYMBOL_GPL(__mmdrop); @@ -521,6 +560,18 @@ void mm_release(struct task_struct *tsk, { struct completion *vfork_done = tsk->vfork_done; + /* Get rid of any futexes when releasing the mm */ +#ifdef CONFIG_FUTEX + if (unlikely(tsk->robust_list)) + exit_robust_list(tsk); + tsk->robust_list = NULL; +#ifdef CONFIG_COMPAT + if (unlikely(tsk->compat_robust_list)) + compat_exit_robust_list(tsk); + tsk->compat_robust_list = NULL; +#endif +#endif + /* Get rid of any cached register state */ deactivate_mm(tsk, mm); @@ -539,7 +590,7 @@ void mm_release(struct task_struct *tsk, if (tsk->clear_child_tid && !(tsk->flags & PF_SIGNALED) && atomic_read(&mm->mm_users) > 1) { - u32 __user * tidptr = tsk->clear_child_tid; + pid_t __user * tidptr = tsk->clear_child_tid; tsk->clear_child_tid = NULL; /* @@ -547,7 +598,7 @@ void mm_release(struct task_struct *tsk, * not set up a proper pointer then tough luck. */ put_user(0, tidptr); - sys_futex(tidptr, FUTEX_WAKE, 1, NULL, NULL, 0); + sys_futex((u32 __user *)tidptr, FUTEX_WAKE, 1, NULL, NULL, 0); } } @@ -568,6 +619,7 @@ struct mm_struct *dup_mm(struct task_str goto fail_nomem; memcpy(mm, oldmm, sizeof(*mm)); + mm->mm_vx_info = NULL; /* Initializing for Swap token stuff */ mm->token_priority = 0; @@ -601,6 +653,7 @@ fail_nocontext: * If init_new_context() failed, we cannot use mmput() to free the mm * because it calls destroy_context() */ + clr_vx_info(&mm->mm_vx_info); mm_free_pgd(mm); free_mm(mm); return NULL; @@ -664,6 +717,7 @@ static struct fs_struct *__copy_fs_struc fs->pwd = old->pwd; path_get(&old->pwd); read_unlock(&old->lock); + atomic_inc(&vs_global_fs); } return fs; } @@ -907,6 +961,8 @@ static struct task_struct *copy_process( int retval; struct task_struct *p; int cgroup_callbacks_done = 0; + struct vx_info *vxi; + struct nx_info *nxi; if ((clone_flags & (CLONE_NEWNS|CLONE_FS)) == (CLONE_NEWNS|CLONE_FS)) return ERR_PTR(-EINVAL); @@ -941,12 +997,31 @@ static struct task_struct *copy_process( DEBUG_LOCKS_WARN_ON(!p->hardirqs_enabled); DEBUG_LOCKS_WARN_ON(!p->softirqs_enabled); #endif + init_vx_info(&p->vx_info, current->vx_info); + init_nx_info(&p->nx_info, current->nx_info); + + /* check vserver memory */ + if (p->mm && !(clone_flags & CLONE_VM)) { + if (vx_vmpages_avail(p->mm, p->mm->total_vm)) + vx_pages_add(p->vx_info, RLIMIT_AS, p->mm->total_vm); + else + goto bad_fork_free; + } + if (p->mm && vx_flags(VXF_FORK_RSS, 0)) { + if (!vx_rss_avail(p->mm, get_mm_counter(p->mm, file_rss))) + goto bad_fork_cleanup_vm; + } retval = -EAGAIN; + if (!vx_nproc_avail(1)) + goto bad_fork_cleanup_vm; + + gr_learn_resource(p, RLIMIT_NPROC, atomic_read(&p->user->processes), 0); + if (atomic_read(&p->user->processes) >= p->signal->rlim[RLIMIT_NPROC].rlim_cur) { if (!capable(CAP_SYS_ADMIN) && !capable(CAP_SYS_RESOURCE) && p->user != current->nsproxy->user_ns->root_user) - goto bad_fork_free; + goto bad_fork_cleanup_vm; } atomic_inc(&p->user->__count); @@ -1108,6 +1183,8 @@ static struct task_struct *copy_process( goto bad_fork_free_pid; } + gr_copy_label(p); + p->set_child_tid = (clone_flags & CLONE_CHILD_SETTID) ? child_tidptr : NULL; /* * Clear TID on mm_release()? @@ -1244,6 +1321,18 @@ static struct task_struct *copy_process( total_forks++; spin_unlock(¤t->sighand->siglock); + + /* p is copy of current */ + vxi = p->vx_info; + if (vxi) { + claim_vx_info(vxi, p); + atomic_inc(&vxi->cvirt.nr_threads); + atomic_inc(&vxi->cvirt.total_forks); + vx_nproc_inc(p); + } + nxi = p->nx_info; + if (nxi) + claim_nx_info(nxi, p); write_unlock_irq(&tasklist_lock); proc_fork_connector(p); cgroup_post_fork(p); @@ -1290,9 +1379,14 @@ bad_fork_cleanup_count: put_group_info(p->group_info); atomic_dec(&p->user->processes); free_uid(p->user); +bad_fork_cleanup_vm: + if (p->mm && !(clone_flags & CLONE_VM)) + vx_pages_sub(p->vx_info, RLIMIT_AS, p->mm->total_vm); bad_fork_free: free_task(p); fork_out: + gr_log_forkfail(retval); + return ERR_PTR(retval); } @@ -1369,6 +1463,8 @@ long do_fork(unsigned long clone_flags, if (clone_flags & CLONE_PARENT_SETTID) put_user(nr, parent_tidptr); + gr_handle_brute_check(); + if (clone_flags & CLONE_VFORK) { p->vfork_done = &vfork; init_completion(&vfork); diff -NurpP --minimal linux-2.6.27.15/kernel/futex.c linux-2.6.27.15-g-v/kernel/futex.c --- linux-2.6.27.15/kernel/futex.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/futex.c 2009-02-10 20:32:16.000000000 +0100 @@ -188,6 +188,11 @@ static int get_futex_key(u32 __user *uad struct page *page; int err; +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && address >= SEGMEXEC_TASK_SIZE) + return -EFAULT; +#endif + /* * The futex address must be "naturally" aligned. */ @@ -214,8 +219,8 @@ static int get_futex_key(u32 __user *uad * The futex is hashed differently depending on whether * it's in a shared or private mapping. So check vma first. */ - vma = find_extend_vma(mm, address); - if (unlikely(!vma)) + vma = find_vma(mm, address); + if (unlikely(!vma || address < vma->vm_start)) return -EFAULT; /* @@ -1345,7 +1350,7 @@ static int futex_wait(u32 __user *uaddr, struct restart_block *restart; restart = ¤t_thread_info()->restart_block; restart->fn = futex_wait_restart; - restart->futex.uaddr = (u32 *)uaddr; + restart->futex.uaddr = uaddr; restart->futex.val = val; restart->futex.time = abs_time->tv64; restart->futex.bitset = bitset; @@ -1905,7 +1910,7 @@ retry: */ static inline int fetch_robust_entry(struct robust_list __user **entry, struct robust_list __user * __user *head, - int *pi) + unsigned int *pi) { unsigned long uentry; diff -NurpP --minimal linux-2.6.27.15/kernel/irq/handle.c linux-2.6.27.15-g-v/kernel/irq/handle.c --- linux-2.6.27.15/kernel/irq/handle.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/irq/handle.c 2009-02-10 20:32:16.000000000 +0100 @@ -55,7 +55,8 @@ struct irq_desc irq_desc[NR_IRQS] __cach .depth = 1, .lock = __SPIN_LOCK_UNLOCKED(irq_desc->lock), #ifdef CONFIG_SMP - .affinity = CPU_MASK_ALL + .affinity = CPU_MASK_ALL, + .cpu = 0, #endif } }; diff -NurpP --minimal linux-2.6.27.15/kernel/kallsyms.c linux-2.6.27.15-g-v/kernel/kallsyms.c --- linux-2.6.27.15/kernel/kallsyms.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/kallsyms.c 2009-02-10 20:32:16.000000000 +0100 @@ -62,6 +62,19 @@ static inline int is_kernel_text(unsigne static inline int is_kernel(unsigned long addr) { + +#ifdef CONFIG_PAX_KERNEXEC + +#ifdef CONFIG_MODULES + if ((unsigned long)MODULES_VADDR <= ktla_ktva(addr) && + ktla_ktva(addr) < (unsigned long)MODULES_END) + return 0; +#endif + + if (is_kernel_inittext(addr)) + return 1; +#endif + if (addr >= (unsigned long)_stext && addr <= (unsigned long)_end) return 1; return in_gate_area_no_task(addr); @@ -366,7 +379,6 @@ static unsigned long get_ksymbol_core(st static void reset_iter(struct kallsym_iter *iter, loff_t new_pos) { - iter->name[0] = '\0'; iter->nameoff = get_symbol_offset(new_pos); iter->pos = new_pos; } @@ -450,7 +462,7 @@ static int kallsyms_open(struct inode *i struct kallsym_iter *iter; int ret; - iter = kmalloc(sizeof(*iter), GFP_KERNEL); + iter = kzalloc(sizeof(*iter), GFP_KERNEL); if (!iter) return -ENOMEM; reset_iter(iter, 0); @@ -472,7 +484,15 @@ static const struct file_operations kall static int __init kallsyms_init(void) { +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + proc_create("kallsyms", S_IFREG | S_IRUSR, NULL, &kallsyms_operations); +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + proc_create("kallsyms", S_IFREG | S_IRUSR | S_IRGRP, NULL, &kallsyms_operations); +#endif +#else proc_create("kallsyms", 0444, NULL, &kallsyms_operations); +#endif return 0; } __initcall(kallsyms_init); diff -NurpP --minimal linux-2.6.27.15/kernel/kmod.c linux-2.6.27.15-g-v/kernel/kmod.c --- linux-2.6.27.15/kernel/kmod.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/kmod.c 2009-02-10 20:32:16.000000000 +0100 @@ -108,7 +108,7 @@ int request_module(const char *fmt, ...) return -ENOMEM; } - ret = call_usermodehelper(modprobe_path, argv, envp, 1); + ret = call_usermodehelper(modprobe_path, argv, envp, UMH_WAIT_PROC); atomic_dec(&kmod_concurrent); return ret; } diff -NurpP --minimal linux-2.6.27.15/kernel/kprobes.c linux-2.6.27.15-g-v/kernel/kprobes.c --- linux-2.6.27.15/kernel/kprobes.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/kprobes.c 2009-02-10 20:32:16.000000000 +0100 @@ -182,7 +182,7 @@ kprobe_opcode_t __kprobes *get_insn_slot * kernel image and loaded module images reside. This is required * so x86_64 can correctly handle the %rip-relative fixups. */ - kip->insns = module_alloc(PAGE_SIZE); + kip->insns = module_alloc_exec(PAGE_SIZE); if (!kip->insns) { kfree(kip); return NULL; @@ -214,7 +214,7 @@ static int __kprobes collect_one_slot(st hlist_add_head(&kip->hlist, &kprobe_insn_pages); } else { - module_free(NULL, kip->insns); + module_free_exec(NULL, kip->insns); kfree(kip); } return 1; diff -NurpP --minimal linux-2.6.27.15/kernel/kthread.c linux-2.6.27.15-g-v/kernel/kthread.c --- linux-2.6.27.15/kernel/kthread.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/kthread.c 2009-02-10 20:32:16.000000000 +0100 @@ -13,6 +13,7 @@ #include #include #include +#include #define KTHREAD_NICE_LEVEL (-5) @@ -98,7 +99,7 @@ static void create_kthread(struct kthrea struct sched_param param = { .sched_priority = 0 }; wait_for_completion(&create->started); read_lock(&tasklist_lock); - create->result = find_task_by_pid_ns(pid, &init_pid_ns); + create->result = find_task_by_real_pid(pid); read_unlock(&tasklist_lock); /* * root may have changed our (kthreadd's) priority or CPU mask. diff -NurpP --minimal linux-2.6.27.15/kernel/lockdep.c linux-2.6.27.15-g-v/kernel/lockdep.c --- linux-2.6.27.15/kernel/lockdep.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/lockdep.c 2009-02-10 20:32:16.000000000 +0100 @@ -627,6 +627,10 @@ static int static_obj(void *obj) int i; #endif +#ifdef CONFIG_PAX_KERNEXEC + start = (unsigned long )&_data; +#endif + /* * static variable? */ @@ -638,9 +642,12 @@ static int static_obj(void *obj) * percpu var? */ for_each_possible_cpu(i) { +#ifdef CONFIG_X86_32 + start = per_cpu_offset(i); +#else start = (unsigned long) &__per_cpu_start + per_cpu_offset(i); - end = (unsigned long) &__per_cpu_start + PERCPU_ENOUGH_ROOM - + per_cpu_offset(i); +#endif + end = start + PERCPU_ENOUGH_ROOM; if ((addr >= start) && (addr < end)) return 1; diff -NurpP --minimal linux-2.6.27.15/kernel/Makefile linux-2.6.27.15-g-v/kernel/Makefile --- linux-2.6.27.15/kernel/Makefile 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/Makefile 2009-02-10 20:32:16.000000000 +0100 @@ -22,6 +22,7 @@ CFLAGS_REMOVE_sched_clock.o = -pg CFLAGS_REMOVE_sched.o = -pg endif +obj-y += vserver/ obj-$(CONFIG_PROFILING) += profile.o obj-$(CONFIG_SYSCTL_SYSCALL_CHECK) += sysctl_check.o obj-$(CONFIG_STACKTRACE) += stacktrace.o diff -NurpP --minimal linux-2.6.27.15/kernel/module.c linux-2.6.27.15-g-v/kernel/module.c --- linux-2.6.27.15/kernel/module.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/module.c 2009-02-10 20:32:16.000000000 +0100 @@ -44,6 +44,11 @@ #include #include #include + +#ifdef CONFIG_PAX_KERNEXEC +#include +#endif + #include #include @@ -71,7 +76,10 @@ static DECLARE_WAIT_QUEUE_HEAD(module_wq static BLOCKING_NOTIFIER_HEAD(module_notify_list); /* Bounds of module allocation, for speeding __module_text_address */ -static unsigned long module_addr_min = -1UL, module_addr_max = 0; +static unsigned long module_addr_min_rw = -1UL, module_addr_max_rw = 0; +static unsigned long module_addr_min_rx = -1UL, module_addr_max_rx = 0; + +extern int gr_check_modstop(void); int register_module_notifier(struct notifier_block * nb) { @@ -217,7 +225,7 @@ static bool each_symbol(bool (*fn)(const return true; list_for_each_entry(mod, &modules, list) { - struct symsearch arr[] = { + struct symsearch modarr[] = { { mod->syms, mod->syms + mod->num_syms, mod->crcs, NOT_GPL_ONLY, false }, { mod->gpl_syms, mod->gpl_syms + mod->num_gpl_syms, @@ -239,7 +247,7 @@ static bool each_symbol(bool (*fn)(const #endif }; - if (each_symbol_in_section(arr, ARRAY_SIZE(arr), mod, fn, data)) + if (each_symbol_in_section(modarr, ARRAY_SIZE(modarr), mod, fn, data)) return true; } return false; @@ -375,6 +383,8 @@ static inline unsigned int block_size(in return val; } +EXPORT_SYMBOL(__per_cpu_start); + static void *percpu_modalloc(unsigned long size, unsigned long align, const char *name) { @@ -382,7 +392,7 @@ static void *percpu_modalloc(unsigned lo unsigned int i; void *ptr; - if (align > PAGE_SIZE) { + if (align-1 >= PAGE_SIZE) { printk(KERN_WARNING "%s: per-cpu alignment %li > %li\n", name, align, PAGE_SIZE); align = PAGE_SIZE; @@ -464,7 +474,11 @@ static void percpu_modcopy(void *pcpudes int cpu; for_each_possible_cpu(cpu) +#ifdef CONFIG_X86_32 + memcpy(pcpudest + __per_cpu_offset[cpu], from, size); +#else memcpy(pcpudest + per_cpu_offset(cpu), from, size); +#endif } static int percpu_modinit(void) @@ -722,6 +736,9 @@ SYSCALL_DEFINE2(delete_module, const cha char name[MODULE_NAME_LEN]; int ret, forced = 0; + if (gr_check_modstop()) + return -EPERM; + if (!capable(CAP_SYS_MODULE)) return -EPERM; @@ -1430,16 +1447,19 @@ static void free_module(struct module *m module_unload_free(mod); /* This may be NULL, but that's OK */ - module_free(mod, mod->module_init); + module_free(mod, mod->module_init_rw); + module_free_exec(mod, mod->module_init_rx); kfree(mod->args); if (mod->percpu) percpu_modfree(mod->percpu); /* Free lock-classes: */ - lockdep_free_key_range(mod->module_core, mod->core_size); + lockdep_free_key_range(mod->module_core_rx, mod->core_size_rx); + lockdep_free_key_range(mod->module_core_rw, mod->core_size_rw); /* Finally, free the core (containing the module structure) */ - module_free(mod, mod->module_core); + module_free_exec(mod, mod->module_core_rx); + module_free(mod, mod->module_core_rw); } void *__symbol_get(const char *symbol) @@ -1505,10 +1525,14 @@ static int simplify_symbols(Elf_Shdr *se struct module *mod) { Elf_Sym *sym = (void *)sechdrs[symindex].sh_addr; - unsigned long secbase; + unsigned long secbase, symbol; unsigned int i, n = sechdrs[symindex].sh_size / sizeof(Elf_Sym); int ret = 0; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + for (i = 1; i < n; i++) { switch (sym[i].st_shndx) { case SHN_COMMON: @@ -1527,10 +1551,19 @@ static int simplify_symbols(Elf_Shdr *se break; case SHN_UNDEF: - sym[i].st_value - = resolve_symbol(sechdrs, versindex, + symbol = resolve_symbol(sechdrs, versindex, strtab + sym[i].st_name, mod); +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + sym[i].st_value = symbol; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + /* Ok if resolved. */ if (!IS_ERR_VALUE(sym[i].st_value)) break; @@ -1545,11 +1578,27 @@ static int simplify_symbols(Elf_Shdr *se default: /* Divert to percpu allocation if a percpu var. */ - if (sym[i].st_shndx == pcpuindex) + if (sym[i].st_shndx == pcpuindex) { + +#if defined(CONFIG_X86_32) && defined(CONFIG_SMP) + secbase = (unsigned long)mod->percpu - (unsigned long)__per_cpu_start; +#else secbase = (unsigned long)mod->percpu; - else +#endif + + } else secbase = sechdrs[sym[i].st_shndx].sh_addr; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + sym[i].st_value += secbase; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + break; } } @@ -1601,11 +1650,12 @@ static void layout_sections(struct modul || strncmp(secstrings + s->sh_name, ".init", 5) == 0) continue; - s->sh_entsize = get_offset(&mod->core_size, s); + if ((s->sh_flags & SHF_WRITE) || !(s->sh_flags & SHF_ALLOC)) + s->sh_entsize = get_offset(&mod->core_size_rw, s); + else + s->sh_entsize = get_offset(&mod->core_size_rx, s); DEBUGP("\t%s\n", secstrings + s->sh_name); } - if (m == 0) - mod->core_text_size = mod->core_size; } DEBUGP("Init section allocation order:\n"); @@ -1619,12 +1669,13 @@ static void layout_sections(struct modul || strncmp(secstrings + s->sh_name, ".init", 5) != 0) continue; - s->sh_entsize = (get_offset(&mod->init_size, s) - | INIT_OFFSET_MASK); + if ((s->sh_flags & SHF_WRITE) || !(s->sh_flags & SHF_ALLOC)) + s->sh_entsize = get_offset(&mod->init_size_rw, s); + else + s->sh_entsize = get_offset(&mod->init_size_rx, s); + s->sh_entsize |= INIT_OFFSET_MASK; DEBUGP("\t%s\n", secstrings + s->sh_name); } - if (m == 0) - mod->init_text_size = mod->init_size; } } @@ -1764,14 +1815,31 @@ static void add_kallsyms(struct module * { unsigned int i; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + mod->symtab = (void *)sechdrs[symindex].sh_addr; mod->num_symtab = sechdrs[symindex].sh_size / sizeof(Elf_Sym); mod->strtab = (void *)sechdrs[strindex].sh_addr; /* Set types up while we still have access to sections. */ - for (i = 0; i < mod->num_symtab; i++) - mod->symtab[i].st_info - = elf_type(&mod->symtab[i], sechdrs, secstrings, mod); + + for (i = 0; i < mod->num_symtab; i++) { + char type = elf_type(&mod->symtab[i], sechdrs, secstrings, mod); + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + mod->symtab[i].st_info = type; + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + } + } #else static inline void add_kallsyms(struct module *mod, @@ -1783,16 +1851,30 @@ static inline void add_kallsyms(struct m } #endif /* CONFIG_KALLSYMS */ -static void *module_alloc_update_bounds(unsigned long size) +static void *module_alloc_update_bounds_rw(unsigned long size) { void *ret = module_alloc(size); if (ret) { /* Update module bounds. */ - if ((unsigned long)ret < module_addr_min) - module_addr_min = (unsigned long)ret; - if ((unsigned long)ret + size > module_addr_max) - module_addr_max = (unsigned long)ret + size; + if ((unsigned long)ret < module_addr_min_rw) + module_addr_min_rw = (unsigned long)ret; + if ((unsigned long)ret + size > module_addr_max_rw) + module_addr_max_rw = (unsigned long)ret + size; + } + return ret; +} + +static void *module_alloc_update_bounds_rx(unsigned long size) +{ + void *ret = module_alloc_exec(size); + + if (ret) { + /* Update module bounds. */ + if ((unsigned long)ret < module_addr_min_rx) + module_addr_min_rx = (unsigned long)ret; + if ((unsigned long)ret + size > module_addr_max_rx) + module_addr_max_rx = (unsigned long)ret + size; } return ret; } @@ -1837,6 +1919,10 @@ static noinline struct module *load_modu struct exception_table_entry *extable; mm_segment_t old_fs; +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif + DEBUGP("load_module: umod=%p, len=%lu, uargs=%p\n", umod, len, uargs); if (len < sizeof(*hdr)) @@ -1998,22 +2084,57 @@ static noinline struct module *load_modu layout_sections(mod, hdr, sechdrs, secstrings); /* Do the allocs. */ - ptr = module_alloc_update_bounds(mod->core_size); + ptr = module_alloc_update_bounds_rw(mod->core_size_rw); if (!ptr) { err = -ENOMEM; goto free_percpu; } - memset(ptr, 0, mod->core_size); - mod->module_core = ptr; + memset(ptr, 0, mod->core_size_rw); + mod->module_core_rw = ptr; - ptr = module_alloc_update_bounds(mod->init_size); - if (!ptr && mod->init_size) { + ptr = module_alloc_update_bounds_rw(mod->init_size_rw); + if (!ptr && mod->init_size_rw) { err = -ENOMEM; - goto free_core; + goto free_core_rw; } - memset(ptr, 0, mod->init_size); - mod->module_init = ptr; + memset(ptr, 0, mod->init_size_rw); + mod->module_init_rw = ptr; + + ptr = module_alloc_update_bounds_rx(mod->core_size_rx); + if (!ptr) { + err = -ENOMEM; + goto free_init_rw; + } + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + memset(ptr, 0, mod->core_size_rx); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + mod->module_core_rx = ptr; + + ptr = module_alloc_update_bounds_rx(mod->init_size_rx); + if (!ptr && mod->init_size_rx) { + err = -ENOMEM; + goto free_core_rx; + } + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + + memset(ptr, 0, mod->init_size_rx); + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + mod->module_init_rx = ptr; /* Transfer each section which specifies SHF_ALLOC */ DEBUGP("final section addresses:\n"); for (i = 0; i < hdr->e_shnum; i++) { @@ -2022,17 +2143,41 @@ static noinline struct module *load_modu if (!(sechdrs[i].sh_flags & SHF_ALLOC)) continue; - if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK) - dest = mod->module_init - + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK); - else - dest = mod->module_core + sechdrs[i].sh_entsize; + if (sechdrs[i].sh_entsize & INIT_OFFSET_MASK) { + if ((sechdrs[i].sh_flags & SHF_WRITE) || !(sechdrs[i].sh_flags & SHF_ALLOC)) + dest = mod->module_init_rw + + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK); + else + dest = mod->module_init_rx + + (sechdrs[i].sh_entsize & ~INIT_OFFSET_MASK); + } else { + if ((sechdrs[i].sh_flags & SHF_WRITE) || !(sechdrs[i].sh_flags & SHF_ALLOC)) + dest = mod->module_core_rw + sechdrs[i].sh_entsize; + else + dest = mod->module_core_rx + sechdrs[i].sh_entsize; + } - if (sechdrs[i].sh_type != SHT_NOBITS) - memcpy(dest, (void *)sechdrs[i].sh_addr, - sechdrs[i].sh_size); + if (sechdrs[i].sh_type != SHT_NOBITS) { + +#ifdef CONFIG_PAX_KERNEXEC + if (!(sechdrs[i].sh_flags & SHF_WRITE) && (sechdrs[i].sh_flags & SHF_ALLOC)) { + pax_open_kernel(cr0); + memcpy(dest, (void *)sechdrs[i].sh_addr, sechdrs[i].sh_size); + pax_close_kernel(cr0); + } else +#endif + + memcpy(dest, (void *)sechdrs[i].sh_addr, sechdrs[i].sh_size); + } /* Update sh_addr to point to copy in image. */ - sechdrs[i].sh_addr = (unsigned long)dest; + +#ifdef CONFIG_PAX_KERNEXEC + if (sechdrs[i].sh_flags & SHF_EXECINSTR) + sechdrs[i].sh_addr = ktva_ktla((unsigned long)dest); + else +#endif + + sechdrs[i].sh_addr = (unsigned long)dest; DEBUGP("\t0x%lx %s\n", sechdrs[i].sh_addr, secstrings + sechdrs[i].sh_name); } /* Module has been moved. */ @@ -2120,8 +2265,8 @@ static noinline struct module *load_modu /* Now do relocations. */ for (i = 1; i < hdr->e_shnum; i++) { - const char *strtab = (char *)sechdrs[strindex].sh_addr; unsigned int info = sechdrs[i].sh_info; + strtab = (char *)sechdrs[strindex].sh_addr; /* Not a valid relocation section? */ if (info >= hdr->e_shnum) @@ -2180,12 +2325,12 @@ static noinline struct module *load_modu * Do it before processing of module parameters, so the module * can provide parameter accessor functions of its own. */ - if (mod->module_init) - flush_icache_range((unsigned long)mod->module_init, - (unsigned long)mod->module_init - + mod->init_size); - flush_icache_range((unsigned long)mod->module_core, - (unsigned long)mod->module_core + mod->core_size); + if (mod->module_init_rx) + flush_icache_range((unsigned long)mod->module_init_rx, + (unsigned long)mod->module_init_rx + + mod->init_size_rx); + flush_icache_range((unsigned long)mod->module_core_rx, + (unsigned long)mod->module_core_rx + mod->core_size_rx); set_fs(old_fs); @@ -2238,9 +2383,13 @@ static noinline struct module *load_modu kobject_put(&mod->mkobj.kobj); free_unload: module_unload_free(mod); - module_free(mod, mod->module_init); - free_core: - module_free(mod, mod->module_core); + module_free_exec(mod, mod->module_init_rx); + free_core_rx: + module_free_exec(mod, mod->module_core_rx); + free_init_rw: + module_free(mod, mod->module_init_rw); + free_core_rw: + module_free(mod, mod->module_core_rw); free_percpu: if (percpu) percpu_modfree(percpu); @@ -2263,6 +2412,9 @@ SYSCALL_DEFINE3(init_module, void __user struct module *mod; int ret = 0; + if (gr_check_modstop()) + return -EPERM; + /* Must have permission */ if (!capable(CAP_SYS_MODULE)) return -EPERM; @@ -2318,10 +2470,12 @@ SYSCALL_DEFINE3(init_module, void __user /* Drop initial reference. */ module_put(mod); unwind_remove_table(mod->unwind_info, 1); - module_free(mod, mod->module_init); - mod->module_init = NULL; - mod->init_size = 0; - mod->init_text_size = 0; + module_free(mod, mod->module_init_rw); + module_free_exec(mod, mod->module_init_rx); + mod->module_init_rw = NULL; + mod->module_init_rx = NULL; + mod->init_size_rw = 0; + mod->init_size_rx = 0; mutex_unlock(&module_mutex); return 0; @@ -2329,6 +2483,13 @@ SYSCALL_DEFINE3(init_module, void __user static inline int within(unsigned long addr, void *start, unsigned long size) { + +#ifdef CONFIG_PAX_KERNEXEC + if (ktla_ktva(addr) >= (unsigned long)start && + ktla_ktva(addr) < (unsigned long)start + size) + return 1; +#endif + return ((void *)addr >= start && (void *)addr < start + size); } @@ -2352,10 +2513,14 @@ static const char *get_ksymbol(struct mo unsigned long nextval; /* At worse, next value is at end of module */ - if (within(addr, mod->module_init, mod->init_size)) - nextval = (unsigned long)mod->module_init+mod->init_text_size; + if (within(addr, mod->module_init_rx, mod->init_size_rx)) + nextval = (unsigned long)mod->module_init_rx+mod->init_size_rx; + else if (within(addr, mod->module_init_rw, mod->init_size_rw)) + nextval = (unsigned long)mod->module_init_rw+mod->init_size_rw; + else if (within(addr, mod->module_core_rx, mod->core_size_rx)) + nextval = (unsigned long)mod->module_core_rx+mod->core_size_rx; else - nextval = (unsigned long)mod->module_core+mod->core_text_size; + nextval = (unsigned long)mod->module_core_rw+mod->core_size_rw; /* Scan for closest preceeding symbol, and next symbol. (ELF starts real symbols at 1). */ @@ -2400,8 +2565,10 @@ const char *module_address_lookup(unsign preempt_disable(); list_for_each_entry(mod, &modules, list) { - if (within(addr, mod->module_init, mod->init_size) - || within(addr, mod->module_core, mod->core_size)) { + if (within(addr, mod->module_init_rx, mod->init_size_rx) || + within(addr, mod->module_init_rw, mod->init_size_rw) || + within(addr, mod->module_core_rx, mod->core_size_rx) || + within(addr, mod->module_core_rw, mod->core_size_rw)) { if (modname) *modname = mod->name; ret = get_ksymbol(mod, addr, size, offset); @@ -2423,8 +2590,10 @@ int lookup_module_symbol_name(unsigned l preempt_disable(); list_for_each_entry(mod, &modules, list) { - if (within(addr, mod->module_init, mod->init_size) || - within(addr, mod->module_core, mod->core_size)) { + if (within(addr, mod->module_init_rx, mod->init_size_rx) || + within(addr, mod->module_init_rw, mod->init_size_rw) || + within(addr, mod->module_core_rx, mod->core_size_rx) || + within(addr, mod->module_core_rw, mod->core_size_rw)) { const char *sym; sym = get_ksymbol(mod, addr, NULL, NULL); @@ -2447,8 +2616,10 @@ int lookup_module_symbol_attrs(unsigned preempt_disable(); list_for_each_entry(mod, &modules, list) { - if (within(addr, mod->module_init, mod->init_size) || - within(addr, mod->module_core, mod->core_size)) { + if (within(addr, mod->module_init_rx, mod->init_size_rx) || + within(addr, mod->module_init_rw, mod->init_size_rw) || + within(addr, mod->module_core_rx, mod->core_size_rx) || + within(addr, mod->module_core_rw, mod->core_size_rw)) { const char *sym; sym = get_ksymbol(mod, addr, size, offset); @@ -2579,7 +2750,7 @@ static int m_show(struct seq_file *m, vo char buf[8]; seq_printf(m, "%s %u", - mod->name, mod->init_size + mod->core_size); + mod->name, mod->init_size_rx + mod->init_size_rw + mod->core_size_rx + mod->core_size_rw); print_unload_info(m, mod); /* Informative for users. */ @@ -2588,7 +2759,7 @@ static int m_show(struct seq_file *m, vo mod->state == MODULE_STATE_COMING ? "Loading": "Live"); /* Used by oprofile and other similar tools. */ - seq_printf(m, " 0x%p", mod->module_core); + seq_printf(m, " 0x%p 0x%p", mod->module_core_rx, mod->module_core_rw); /* Taints info */ if (mod->taints) @@ -2644,7 +2815,8 @@ int is_module_address(unsigned long addr preempt_disable(); list_for_each_entry(mod, &modules, list) { - if (within(addr, mod->module_core, mod->core_size)) { + if (within(addr, mod->module_core_rx, mod->core_size_rx) || + within(addr, mod->module_core_rw, mod->core_size_rw)) { preempt_enable(); return 1; } @@ -2661,12 +2833,16 @@ struct module *__module_text_address(uns { struct module *mod; - if (addr < module_addr_min || addr > module_addr_max) +#ifdef CONFIG_X86_32 + addr = ktla_ktva(addr); +#endif + + if (addr < module_addr_min_rx || addr > module_addr_max_rx) return NULL; list_for_each_entry(mod, &modules, list) - if (within(addr, mod->module_init, mod->init_text_size) - || within(addr, mod->module_core, mod->core_text_size)) + if (within(addr, mod->module_init_rx, mod->init_size_rx) + || within(addr, mod->module_core_rx, mod->core_size_rx)) return mod; return NULL; } diff -NurpP --minimal linux-2.6.27.15/kernel/mutex.c linux-2.6.27.15-g-v/kernel/mutex.c --- linux-2.6.27.15/kernel/mutex.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/mutex.c 2009-02-10 20:32:16.000000000 +0100 @@ -83,7 +83,7 @@ __mutex_lock_slowpath(atomic_t *lock_cou * * This function is similar to (but not equivalent to) down(). */ -void inline __sched mutex_lock(struct mutex *lock) +inline void __sched mutex_lock(struct mutex *lock) { might_sleep(); /* diff -NurpP --minimal linux-2.6.27.15/kernel/nsproxy.c linux-2.6.27.15-g-v/kernel/nsproxy.c --- linux-2.6.27.15/kernel/nsproxy.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/nsproxy.c 2009-02-10 20:32:16.000000000 +0100 @@ -19,6 +19,8 @@ #include #include #include +#include +#include #include #include @@ -37,6 +39,9 @@ static inline struct nsproxy *clone_nspr if (ns) { memcpy(ns, orig, sizeof(struct nsproxy)); atomic_set(&ns->count, 1); + vxdprintk(VXD_CBIT(space, 2), "clone_nsproxy(%p[%u] = %p[1]", + orig, atomic_read(&orig->count), ns); + atomic_inc(&vs_global_nsproxy); } return ns; } @@ -46,47 +51,51 @@ static inline struct nsproxy *clone_nspr * Return the newly created nsproxy. Do not attach this to the task, * leave it to the caller to do proper locking and attach it to task. */ -static struct nsproxy *create_new_namespaces(unsigned long flags, - struct task_struct *tsk, struct fs_struct *new_fs) +static struct nsproxy *unshare_namespaces(unsigned long flags, + struct nsproxy *orig, struct fs_struct *new_fs) { struct nsproxy *new_nsp; int err; - new_nsp = clone_nsproxy(tsk->nsproxy); + vxdprintk(VXD_CBIT(space, 4), + "unshare_namespaces(0x%08lx,%p,%p)", + flags, orig, new_fs); + + new_nsp = clone_nsproxy(orig); if (!new_nsp) return ERR_PTR(-ENOMEM); - new_nsp->mnt_ns = copy_mnt_ns(flags, tsk->nsproxy->mnt_ns, new_fs); + new_nsp->mnt_ns = copy_mnt_ns(flags, orig->mnt_ns, new_fs); if (IS_ERR(new_nsp->mnt_ns)) { err = PTR_ERR(new_nsp->mnt_ns); goto out_ns; } - new_nsp->uts_ns = copy_utsname(flags, tsk->nsproxy->uts_ns); + new_nsp->uts_ns = copy_utsname(flags, orig->uts_ns); if (IS_ERR(new_nsp->uts_ns)) { err = PTR_ERR(new_nsp->uts_ns); goto out_uts; } - new_nsp->ipc_ns = copy_ipcs(flags, tsk->nsproxy->ipc_ns); + new_nsp->ipc_ns = copy_ipcs(flags, orig->ipc_ns); if (IS_ERR(new_nsp->ipc_ns)) { err = PTR_ERR(new_nsp->ipc_ns); goto out_ipc; } - new_nsp->pid_ns = copy_pid_ns(flags, task_active_pid_ns(tsk)); + new_nsp->pid_ns = copy_pid_ns(flags, orig->pid_ns); if (IS_ERR(new_nsp->pid_ns)) { err = PTR_ERR(new_nsp->pid_ns); goto out_pid; } - new_nsp->user_ns = copy_user_ns(flags, tsk->nsproxy->user_ns); + new_nsp->user_ns = copy_user_ns(flags, orig->user_ns); if (IS_ERR(new_nsp->user_ns)) { err = PTR_ERR(new_nsp->user_ns); goto out_user; } - new_nsp->net_ns = copy_net_ns(flags, tsk->nsproxy->net_ns); + new_nsp->net_ns = copy_net_ns(flags, orig->net_ns); if (IS_ERR(new_nsp->net_ns)) { err = PTR_ERR(new_nsp->net_ns); goto out_net; @@ -114,6 +123,37 @@ out_ns: return ERR_PTR(err); } +static struct nsproxy *create_new_namespaces(int flags, struct task_struct *tsk, + struct fs_struct *new_fs) +{ + return unshare_namespaces(flags, tsk->nsproxy, new_fs); +} + +/* + * copies the nsproxy, setting refcount to 1, and grabbing a + * reference to all contained namespaces. + */ +struct nsproxy *copy_nsproxy(struct nsproxy *orig) +{ + struct nsproxy *ns = clone_nsproxy(orig); + + if (ns) { + if (ns->mnt_ns) + get_mnt_ns(ns->mnt_ns); + if (ns->uts_ns) + get_uts_ns(ns->uts_ns); + if (ns->ipc_ns) + get_ipc_ns(ns->ipc_ns); + if (ns->pid_ns) + get_pid_ns(ns->pid_ns); + if (ns->user_ns) + get_user_ns(ns->user_ns); + if (ns->net_ns) + get_net(ns->net_ns); + } + return ns; +} + /* * called from clone. This now handles copy for nsproxy and all * namespaces therein. @@ -121,9 +161,12 @@ out_ns: int copy_namespaces(unsigned long flags, struct task_struct *tsk) { struct nsproxy *old_ns = tsk->nsproxy; - struct nsproxy *new_ns; + struct nsproxy *new_ns = NULL; int err = 0; + vxdprintk(VXD_CBIT(space, 7), "copy_namespaces(0x%08lx,%p[%p])", + flags, tsk, old_ns); + if (!old_ns) return 0; @@ -160,6 +203,9 @@ int copy_namespaces(unsigned long flags, out: put_nsproxy(old_ns); + vxdprintk(VXD_CBIT(space, 3), + "copy_namespaces(0x%08lx,%p[%p]) = %d [%p]", + flags, tsk, old_ns, err, new_ns); return err; } @@ -175,7 +221,9 @@ void free_nsproxy(struct nsproxy *ns) put_pid_ns(ns->pid_ns); if (ns->user_ns) put_user_ns(ns->user_ns); - put_net(ns->net_ns); + if (ns->net_ns) + put_net(ns->net_ns); + atomic_dec(&vs_global_nsproxy); kmem_cache_free(nsproxy_cachep, ns); } @@ -188,6 +236,10 @@ int unshare_nsproxy_namespaces(unsigned { int err = 0; + vxdprintk(VXD_CBIT(space, 4), + "unshare_nsproxy_namespaces(0x%08lx,[%p])", + unshare_flags, current->nsproxy); + if (!(unshare_flags & (CLONE_NEWNS | CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER | CLONE_NEWNET))) return 0; diff -NurpP --minimal linux-2.6.27.15/kernel/panic.c linux-2.6.27.15-g-v/kernel/panic.c --- linux-2.6.27.15/kernel/panic.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/panic.c 2009-02-10 20:32:16.000000000 +0100 @@ -349,6 +349,8 @@ EXPORT_SYMBOL(warn_slowpath); */ void __stack_chk_fail(void) { + print_symbol("stack corrupted in: %s\n", (unsigned long)__builtin_return_address(0)); + dump_stack(); panic("stack-protector: Kernel stack is corrupted"); } EXPORT_SYMBOL(__stack_chk_fail); diff -NurpP --minimal linux-2.6.27.15/kernel/pid.c linux-2.6.27.15-g-v/kernel/pid.c --- linux-2.6.27.15/kernel/pid.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/pid.c 2009-02-10 20:32:16.000000000 +0100 @@ -36,6 +36,9 @@ #include #include #include +#include +#include +#include #define pid_hashfn(nr, ns) \ hash_long((unsigned long)nr + (unsigned long)ns, pidhash_shift) @@ -45,7 +48,7 @@ struct pid init_struct_pid = INIT_STRUCT int pid_max = PID_MAX_DEFAULT; -#define RESERVED_PIDS 300 +#define RESERVED_PIDS 500 int pid_max_min = RESERVED_PIDS + 1; int pid_max_max = PID_MAX_LIMIT; @@ -305,7 +308,7 @@ EXPORT_SYMBOL_GPL(find_pid_ns); struct pid *find_vpid(int nr) { - return find_pid_ns(nr, current->nsproxy->pid_ns); + return find_pid_ns(vx_rmap_pid(nr), current->nsproxy->pid_ns); } EXPORT_SYMBOL_GPL(find_vpid); @@ -365,6 +368,9 @@ void transfer_pid(struct task_struct *ol struct task_struct *pid_task(struct pid *pid, enum pid_type type) { struct task_struct *result = NULL; + + if (type == PIDTYPE_REALPID) + type = PIDTYPE_PID; if (pid) { struct hlist_node *first; first = rcu_dereference(pid->tasks[type].first); @@ -381,21 +387,28 @@ EXPORT_SYMBOL(pid_task); struct task_struct *find_task_by_pid_type_ns(int type, int nr, struct pid_namespace *ns) { - return pid_task(find_pid_ns(nr, ns), type); + struct task_struct *task; + + task = pid_task(find_pid_ns(nr, ns), type); + + if (gr_pid_is_chrooted(task)) + return NULL; + + return task; } EXPORT_SYMBOL(find_task_by_pid_type_ns); struct task_struct *find_task_by_vpid(pid_t vnr) { - return find_task_by_pid_type_ns(PIDTYPE_PID, vnr, + return find_task_by_pid_type_ns(PIDTYPE_PID, vx_rmap_pid(vnr), current->nsproxy->pid_ns); } EXPORT_SYMBOL(find_task_by_vpid); struct task_struct *find_task_by_pid_ns(pid_t nr, struct pid_namespace *ns) { - return find_task_by_pid_type_ns(PIDTYPE_PID, nr, ns); + return find_task_by_pid_type_ns(PIDTYPE_PID, vx_rmap_pid(nr), ns); } EXPORT_SYMBOL(find_task_by_pid_ns); @@ -431,7 +444,7 @@ struct pid *find_get_pid(pid_t nr) } EXPORT_SYMBOL_GPL(find_get_pid); -pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) +pid_t pid_unmapped_nr_ns(struct pid *pid, struct pid_namespace *ns) { struct upid *upid; pid_t nr = 0; @@ -444,6 +457,11 @@ pid_t pid_nr_ns(struct pid *pid, struct return nr; } +pid_t pid_nr_ns(struct pid *pid, struct pid_namespace *ns) +{ + return vx_map_pid(pid_unmapped_nr_ns(pid, ns)); +} + pid_t pid_vnr(struct pid *pid) { return pid_nr_ns(pid, current->nsproxy->pid_ns); diff -NurpP --minimal linux-2.6.27.15/kernel/pid_namespace.c linux-2.6.27.15-g-v/kernel/pid_namespace.c --- linux-2.6.27.15/kernel/pid_namespace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/pid_namespace.c 2009-02-10 20:32:16.000000000 +0100 @@ -13,6 +13,7 @@ #include #include #include +#include #define BITS_PER_PAGE (PAGE_SIZE*8) @@ -85,6 +86,7 @@ static struct pid_namespace *create_pid_ goto out_free_map; kref_init(&ns->kref); + atomic_inc(&vs_global_pid_ns); ns->level = level; set_bit(0, ns->pidmap[0].page); @@ -109,6 +111,7 @@ static void destroy_pid_namespace(struct for (i = 0; i < PIDMAP_ENTRIES; i++) kfree(ns->pidmap[i].page); + atomic_dec(&vs_global_pid_ns); kmem_cache_free(pid_ns_cachep, ns); } diff -NurpP --minimal linux-2.6.27.15/kernel/posix-cpu-timers.c linux-2.6.27.15-g-v/kernel/posix-cpu-timers.c --- linux-2.6.27.15/kernel/posix-cpu-timers.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/posix-cpu-timers.c 2009-02-10 20:32:16.000000000 +0100 @@ -6,6 +6,7 @@ #include #include #include +#include #include static int check_clock(const clockid_t which_clock) @@ -1176,6 +1177,7 @@ static void check_process_timers(struct __group_send_sig_info(SIGKILL, SEND_SIG_PRIV, tsk); return; } + gr_learn_resource(tsk, RLIMIT_CPU, psecs, 1); if (psecs >= sig->rlim[RLIMIT_CPU].rlim_cur) { /* * At the soft limit, send a SIGXCPU every second. @@ -1370,17 +1372,17 @@ void run_posix_cpu_timers(struct task_st * timer call will interfere. */ list_for_each_entry_safe(timer, next, &firing, it.cpu.entry) { - int firing; + int __firing; spin_lock(&timer->it_lock); list_del_init(&timer->it.cpu.entry); - firing = timer->it.cpu.firing; + __firing = timer->it.cpu.firing; timer->it.cpu.firing = 0; /* * The firing flag is -1 if we collided with a reset * of the timer, which already reported this * almost-firing as an overrun. So don't generate an event. */ - if (likely(firing >= 0)) { + if (likely(__firing >= 0)) { cpu_timer_fire(timer); } spin_unlock(&timer->it_lock); diff -NurpP --minimal linux-2.6.27.15/kernel/posix-timers.c linux-2.6.27.15-g-v/kernel/posix-timers.c --- linux-2.6.27.15/kernel/posix-timers.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/posix-timers.c 2009-02-10 20:32:16.000000000 +0100 @@ -46,6 +46,7 @@ #include #include #include +#include /* * Management arrays for POSIX timers. Timers are kept in slab memory @@ -298,6 +299,12 @@ void do_schedule_next_timer(struct sigin int posix_timer_event(struct k_itimer *timr, int si_private) { + struct vx_info_save vxis; + struct vx_info *vxi; + int ret; + + vxi = task_get_vx_info(timr->it_process); + enter_vx_info(vxi, &vxis); /* * FIXME: if ->sigq is queued we can race with * dequeue_signal()->do_schedule_next_timer(). @@ -318,10 +325,11 @@ int posix_timer_event(struct k_itimer *t if (timr->it_sigev_notify & SIGEV_THREAD_ID) { struct task_struct *leader; - int ret = send_sigqueue(timr->sigq, timr->it_process, 0); + + ret = send_sigqueue(timr->sigq, timr->it_process, 0); if (likely(ret >= 0)) - return ret; + goto out; timr->it_sigev_notify = SIGEV_SIGNAL; leader = timr->it_process->group_leader; @@ -329,7 +337,11 @@ int posix_timer_event(struct k_itimer *t timr->it_process = leader; } - return send_sigqueue(timr->sigq, timr->it_process, 1); + ret = send_sigqueue(timr->sigq, timr->it_process, 1); +out: + leave_vx_info(&vxis); + put_vx_info(vxi); + return ret; } EXPORT_SYMBOL_GPL(posix_timer_event); diff -NurpP --minimal linux-2.6.27.15/kernel/power/poweroff.c linux-2.6.27.15-g-v/kernel/power/poweroff.c --- linux-2.6.27.15/kernel/power/poweroff.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/power/poweroff.c 2009-02-10 20:32:16.000000000 +0100 @@ -37,7 +37,7 @@ static struct sysrq_key_op sysrq_powerof .enable_mask = SYSRQ_ENABLE_BOOT, }; -static int pm_sysrq_init(void) +static int __init pm_sysrq_init(void) { register_sysrq_key('o', &sysrq_poweroff_op); return 0; diff -NurpP --minimal linux-2.6.27.15/kernel/printk.c linux-2.6.27.15-g-v/kernel/printk.c --- linux-2.6.27.15/kernel/printk.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/printk.c 2009-02-10 20:32:16.000000000 +0100 @@ -32,6 +32,8 @@ #include #include #include +#include +#include #include @@ -291,18 +293,18 @@ int do_syslog(int type, char __user *buf unsigned i, j, limit, count; int do_clear = 0; char c; - int error = 0; + int error; + +#ifdef CONFIG_GRKERNSEC_DMESG + if (grsec_enable_dmesg && !capable(CAP_SYS_ADMIN)) + return -EPERM; +#endif error = security_syslog(type); if (error) return error; - switch (type) { - case 0: /* Close log */ - break; - case 1: /* Open log */ - break; - case 2: /* Read from log */ + if ((type >= 2) && (type <= 4)) { error = -EINVAL; if (!buf || len < 0) goto out; @@ -313,6 +315,16 @@ int do_syslog(int type, char __user *buf error = -EFAULT; goto out; } + } + if (!vx_check(0, VS_ADMIN|VS_WATCH)) + return vx_do_syslog(type, buf, len); + + switch (type) { + case 0: /* Close log */ + break; + case 1: /* Open log */ + break; + case 2: /* Read from log */ error = wait_event_interruptible(log_wait, (log_start - log_end)); if (error) @@ -337,16 +349,6 @@ int do_syslog(int type, char __user *buf do_clear = 1; /* FALL THRU */ case 3: /* Read last kernel messages */ - error = -EINVAL; - if (!buf || len < 0) - goto out; - error = 0; - if (!len) - goto out; - if (!access_ok(VERIFY_WRITE, buf, len)) { - error = -EFAULT; - goto out; - } count = len; if (count > log_buf_len) count = log_buf_len; diff -NurpP --minimal linux-2.6.27.15/kernel/ptrace.c linux-2.6.27.15-g-v/kernel/ptrace.c --- linux-2.6.27.15/kernel/ptrace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/ptrace.c 2009-02-10 20:32:16.000000000 +0100 @@ -21,6 +21,8 @@ #include #include #include +#include +#include #include #include @@ -132,13 +134,18 @@ int __ptrace_may_access(struct task_stru (current->uid != task->uid) || (current->gid != task->egid) || (current->gid != task->sgid) || - (current->gid != task->gid)) && !capable(CAP_SYS_PTRACE)) + (current->gid != task->gid)) && !capable_nolog(CAP_SYS_PTRACE)) return -EPERM; smp_rmb(); if (task->mm) dumpable = get_dumpable(task->mm); - if (!dumpable && !capable(CAP_SYS_PTRACE)) + if (!dumpable && !capable_nolog(CAP_SYS_PTRACE)) return -EPERM; + if (!vx_check(task->xid, VS_ADMIN_P|VS_IDENT)) + return -EPERM; + if (!vx_check(task->xid, VS_IDENT) && + !task_vx_flags(task, VXF_STATE_ADMIN, 0)) + return -EACCES; return security_ptrace_may_access(task, mode); } @@ -193,7 +200,7 @@ repeat: /* Go */ task->ptrace |= PT_PTRACED; - if (capable(CAP_SYS_PTRACE)) + if (capable_nolog(CAP_SYS_PTRACE)) task->ptrace |= PT_PTRACE_CAP; __ptrace_link(task, current); @@ -567,6 +574,10 @@ SYSCALL_DEFINE4(ptrace, long, request, l goto out; } + ret = -EPERM; + if (!vx_check(vx_task_xid(child), VS_WATCH_P | VS_IDENT)) + goto out_put_task_struct; + if (request == PTRACE_ATTACH) { ret = ptrace_attach(child); /* @@ -582,6 +593,11 @@ SYSCALL_DEFINE4(ptrace, long, request, l if (ret < 0) goto out_put_task_struct; + if (gr_handle_ptrace(child, request)) { + ret = -EPERM; + goto out_put_task_struct; + } + ret = arch_ptrace(child, request, addr, data); if (ret < 0) goto out_put_task_struct; diff -NurpP --minimal linux-2.6.27.15/kernel/relay.c linux-2.6.27.15-g-v/kernel/relay.c --- linux-2.6.27.15/kernel/relay.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/relay.c 2009-02-10 20:32:16.000000000 +0100 @@ -1293,7 +1293,7 @@ static int subbuf_splice_actor(struct fi return 0; ret = *nonpad_ret = splice_to_pipe(pipe, &spd); - if (ret < 0 || ret < total_len) + if ((int)ret < 0 || ret < total_len) return ret; if (read_start + ret == nonpad_end) diff -NurpP --minimal linux-2.6.27.15/kernel/resource.c linux-2.6.27.15-g-v/kernel/resource.c --- linux-2.6.27.15/kernel/resource.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/resource.c 2009-02-10 20:32:16.000000000 +0100 @@ -131,8 +131,18 @@ static const struct file_operations proc static int __init ioresources_init(void) { +#ifdef CONFIG_GRKERNSEC_PROC_ADD +#ifdef CONFIG_GRKERNSEC_PROC_USER + proc_create("ioports", S_IRUSR, NULL, &proc_ioports_operations); + proc_create("iomem", S_IRUSR, NULL, &proc_iomem_operations); +#elif defined(CONFIG_GRKERNSEC_PROC_USERGROUP) + proc_create("ioports", S_IRUSR | S_IRGRP, NULL, &proc_ioports_operations); + proc_create("iomem", S_IRUSR | S_IRGRP, NULL, &proc_iomem_operations); +#endif +#else proc_create("ioports", 0, NULL, &proc_ioports_operations); proc_create("iomem", 0, NULL, &proc_iomem_operations); +#endif return 0; } __initcall(ioresources_init); diff -NurpP --minimal linux-2.6.27.15/kernel/sched.c linux-2.6.27.15-g-v/kernel/sched.c --- linux-2.6.27.15/kernel/sched.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/sched.c 2009-02-10 20:32:16.000000000 +0100 @@ -71,6 +71,9 @@ #include #include #include +#include +#include +#include #include #include @@ -497,6 +500,16 @@ struct root_domain { static struct root_domain def_root_domain; #endif + unsigned long norm_time; + unsigned long idle_time; +#ifdef CONFIG_VSERVER_IDLETIME + int idle_skip; +#endif +#ifdef CONFIG_VSERVER_HARDCPU + struct list_head hold_queue; + unsigned long nr_onhold; + int idle_tokens; +#endif /* * This is the main, per-CPU runqueue data structure. @@ -1640,6 +1653,7 @@ static void update_avg(u64 *avg, u64 sam static void enqueue_task(struct rq *rq, struct task_struct *p, int wakeup) { + // BUG_ON(p->state & TASK_ONHOLD); sched_info_queued(p); p->sched_class->enqueue_task(rq, p, wakeup); p->se.on_rq = 1; @@ -1837,6 +1851,9 @@ struct migration_req { struct completion done; }; +#include "sched_mon.h" + + /* * The task's runqueue lock must be held. * Returns true if you have to wait for migration thread. @@ -1846,6 +1863,7 @@ migrate_task(struct task_struct *p, int { struct rq *rq = task_rq(p); + vxm_migrate_task(p, rq, dest_cpu); /* * If the task is not on a runqueue (and not running), then * it is sufficient to simply update the task's cpu field. @@ -2242,6 +2260,12 @@ static int try_to_wake_up(struct task_st /* might preempt at this point */ rq = task_rq_lock(p, &flags); old_state = p->state; + + /* we need to unhold suspended tasks + if (old_state & TASK_ONHOLD) { + vx_unhold_task(p, rq); + old_state = p->state; + } */ if (!(old_state & state)) goto out; if (p->se.on_rq) @@ -4067,13 +4091,16 @@ unsigned long long task_sched_runtime(st void account_user_time(struct task_struct *p, cputime_t cputime) { struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; + struct vx_info *vxi = p->vx_info; /* p is _always_ current */ cputime64_t tmp; + int nice = (TASK_NICE(p) > 0); p->utime = cputime_add(p->utime, cputime); + vx_account_user(vxi, cputime, nice); /* Add user time to cpustat. */ tmp = cputime_to_cputime64(cputime); - if (TASK_NICE(p) > 0) + if (nice) cpustat->nice = cputime64_add(cpustat->nice, tmp); else cpustat->user = cputime64_add(cpustat->user, tmp); @@ -4120,6 +4147,7 @@ void account_system_time(struct task_str cputime_t cputime) { struct cpu_usage_stat *cpustat = &kstat_this_cpu.cpustat; + struct vx_info *vxi = p->vx_info; /* p is _always_ current */ struct rq *rq = this_rq(); cputime64_t tmp; @@ -4129,6 +4157,7 @@ void account_system_time(struct task_str } p->stime = cputime_add(p->stime, cputime); + vx_account_system(vxi, cputime, (p == rq->idle)); /* Add system time to cpustat. */ tmp = cputime_to_cputime64(cputime); @@ -4962,8 +4991,9 @@ SYSCALL_DEFINE1(nice, int, increment) if (nice > 19) nice = 19; - if (increment < 0 && !can_nice(current, nice)) - return -EPERM; + if (increment < 0 && (!can_nice(current, nice) || + gr_handle_chroot_nice())) + return vx_flags(VXF_IGNEG_NICE, 0) ? 0 : -EPERM; retval = security_task_setnice(current, nice); if (retval) @@ -6225,7 +6255,7 @@ static struct ctl_table sd_ctl_dir[] = { .procname = "sched_domain", .mode = 0555, }, - {0, }, + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static struct ctl_table sd_ctl_root[] = { @@ -6235,7 +6265,7 @@ static struct ctl_table sd_ctl_root[] = .mode = 0555, .child = sd_ctl_dir, }, - {0, }, + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static struct ctl_table *sd_alloc_ctl_entry(int n) diff -NurpP --minimal linux-2.6.27.15/kernel/sched_fair.c linux-2.6.27.15-g-v/kernel/sched_fair.c --- linux-2.6.27.15/kernel/sched_fair.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/sched_fair.c 2009-02-10 20:32:16.000000000 +0100 @@ -724,6 +724,9 @@ enqueue_entity(struct cfs_rq *cfs_rq, st check_spread(cfs_rq, se); if (se != cfs_rq->curr) __enqueue_entity(cfs_rq, se); + + if (entity_is_task(se)) + vx_activate_task(task_of(se)); } static void @@ -750,6 +753,8 @@ dequeue_entity(struct cfs_rq *cfs_rq, st if (se != cfs_rq->curr) __dequeue_entity(cfs_rq, se); + if (entity_is_task(se)) + vx_deactivate_task(task_of(se)); account_entity_dequeue(cfs_rq, se); } diff -NurpP --minimal linux-2.6.27.15/kernel/sched_hard.h linux-2.6.27.15-g-v/kernel/sched_hard.h --- linux-2.6.27.15/kernel/sched_hard.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/sched_hard.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,324 @@ + +#ifdef CONFIG_VSERVER_IDLELIMIT + +/* + * vx_idle_resched - reschedule after maxidle + */ +static inline +void vx_idle_resched(struct rq *rq) +{ + /* maybe have a better criterion for paused */ + if (!--rq->idle_tokens && !list_empty(&rq->hold_queue)) + set_need_resched(); +} + +#else /* !CONFIG_VSERVER_IDLELIMIT */ + +#define vx_idle_resched(rq) + +#endif /* CONFIG_VSERVER_IDLELIMIT */ + + + +#ifdef CONFIG_VSERVER_IDLETIME + +#define vx_set_rq_min_skip(rq, min) \ + (rq)->idle_skip = (min) + +#define vx_save_min_skip(ret, min, val) \ + __vx_save_min_skip(ret, min, val) + +static inline +void __vx_save_min_skip(int ret, int *min, int val) +{ + if (ret > -2) + return; + if ((*min > val) || !*min) + *min = val; +} + +static inline +int vx_try_skip(struct rq *rq, int cpu) +{ + /* artificially advance time */ + if (rq->idle_skip > 0) { + vxdprintk(list_empty(&rq->hold_queue), + "hold queue empty on cpu %d", cpu); + rq->idle_time += rq->idle_skip; + vxm_idle_skip(rq, cpu); + return 1; + } + return 0; +} + +#else /* !CONFIG_VSERVER_IDLETIME */ + +#define vx_set_rq_min_skip(rq, min) \ + ({ int dummy = (min); dummy; }) + +#define vx_save_min_skip(ret, min, val) + +static inline +int vx_try_skip(struct rq *rq, int cpu) +{ + return 0; +} + +#endif /* CONFIG_VSERVER_IDLETIME */ + + + +#ifdef CONFIG_VSERVER_HARDCPU + +#define vx_set_rq_max_idle(rq, max) \ + (rq)->idle_tokens = (max) + +#define vx_save_max_idle(ret, min, val) \ + __vx_save_max_idle(ret, min, val) + +static inline +void __vx_save_max_idle(int ret, int *min, int val) +{ + if (*min > val) + *min = val; +} + + +/* + * vx_hold_task - put a task on the hold queue + */ +static inline +void vx_hold_task(struct task_struct *p, struct rq *rq) +{ + __deactivate_task(p, rq); + p->state |= TASK_ONHOLD; + /* a new one on hold */ + rq->nr_onhold++; + vxm_hold_task(p, rq); + list_add_tail(&p->run_list, &rq->hold_queue); +} + +/* + * vx_unhold_task - put a task back to the runqueue + */ +static inline +void vx_unhold_task(struct task_struct *p, struct rq *rq) +{ + list_del(&p->run_list); + /* one less waiting */ + rq->nr_onhold--; + p->state &= ~TASK_ONHOLD; + enqueue_task(p, rq->expired); + inc_nr_running(p, rq); + vxm_unhold_task(p, rq); + + if (p->static_prio < rq->best_expired_prio) + rq->best_expired_prio = p->static_prio; +} + +unsigned long nr_onhold(void) +{ + unsigned long i, sum = 0; + + for_each_online_cpu(i) + sum += cpu_rq(i)->nr_onhold; + + return sum; +} + + + +static inline +int __vx_tokens_avail(struct _vx_sched_pc *sched_pc) +{ + return sched_pc->tokens; +} + +static inline +void __vx_consume_token(struct _vx_sched_pc *sched_pc) +{ + sched_pc->tokens--; +} + +static inline +int vx_need_resched(struct task_struct *p, int slice, int cpu) +{ + struct vx_info *vxi = p->vx_info; + + if (vx_info_flags(vxi, VXF_SCHED_HARD|VXF_SCHED_PRIO, 0)) { + struct _vx_sched_pc *sched_pc = + &vx_per_cpu(vxi, sched_pc, cpu); + int tokens; + + /* maybe we can simplify that to decrement + the token counter unconditional? */ + + if ((tokens = __vx_tokens_avail(sched_pc)) > 0) + __vx_consume_token(sched_pc); + + /* for tokens > 0, one token was consumed */ + if (tokens < 2) + slice = 0; + } + vxm_need_resched(p, slice, cpu); + return (slice == 0); +} + + +#define vx_set_rq_time(rq, time) do { \ + rq->norm_time = time; \ +} while (0) + + +static inline +void vx_try_unhold(struct rq *rq, int cpu) +{ + struct vx_info *vxi = NULL; + struct list_head *l, *n; + int maxidle = HZ; + int minskip = 0; + + /* nothing to do? what about pause? */ + if (list_empty(&rq->hold_queue)) + return; + + list_for_each_safe(l, n, &rq->hold_queue) { + int ret, delta_min[2]; + struct _vx_sched_pc *sched_pc; + struct task_struct *p; + + p = list_entry(l, struct task_struct, run_list); + /* don't bother with same context */ + if (vxi == p->vx_info) + continue; + + vxi = p->vx_info; + /* ignore paused contexts */ + if (vx_info_flags(vxi, VXF_SCHED_PAUSE, 0)) + continue; + + sched_pc = &vx_per_cpu(vxi, sched_pc, cpu); + + /* recalc tokens */ + vxm_sched_info(sched_pc, vxi, cpu); + ret = vx_tokens_recalc(sched_pc, + &rq->norm_time, &rq->idle_time, delta_min); + vxm_tokens_recalc(sched_pc, rq, vxi, cpu); + + if (ret > 0) { + /* we found a runable context */ + vx_unhold_task(p, rq); + break; + } + vx_save_max_idle(ret, &maxidle, delta_min[0]); + vx_save_min_skip(ret, &minskip, delta_min[1]); + } + vx_set_rq_max_idle(rq, maxidle); + vx_set_rq_min_skip(rq, minskip); + vxm_rq_max_min(rq, cpu); +} + + +static inline +int vx_schedule(struct task_struct *next, struct rq *rq, int cpu) +{ + struct vx_info *vxi = next->vx_info; + struct _vx_sched_pc *sched_pc; + int delta_min[2]; + int flags, ret; + + if (!vxi) + return 1; + + flags = vxi->vx_flags; + + if (unlikely(vs_check_flags(flags, VXF_SCHED_PAUSE, 0))) + goto put_on_hold; + if (!vs_check_flags(flags, VXF_SCHED_HARD | VXF_SCHED_PRIO, 0)) + return 1; + + sched_pc = &vx_per_cpu(vxi, sched_pc, cpu); +#ifdef CONFIG_SMP + /* update scheduler params */ + if (cpu_isset(cpu, vxi->sched.update)) { + vx_update_sched_param(&vxi->sched, sched_pc); + vxm_update_sched(sched_pc, vxi, cpu); + cpu_clear(cpu, vxi->sched.update); + } +#endif + vxm_sched_info(sched_pc, vxi, cpu); + ret = vx_tokens_recalc(sched_pc, + &rq->norm_time, &rq->idle_time, delta_min); + vxm_tokens_recalc(sched_pc, rq, vxi, cpu); + + if (!vs_check_flags(flags, VXF_SCHED_HARD, 0)) + return 1; + + if (unlikely(ret < 0)) { + vx_save_max_idle(ret, &rq->idle_tokens, delta_min[0]); + vx_save_min_skip(ret, &rq->idle_skip, delta_min[1]); + vxm_rq_max_min(rq, cpu); + put_on_hold: + vx_hold_task(next, rq); + return 0; + } + return 1; +} + + +#else /* CONFIG_VSERVER_HARDCPU */ + +static inline +void vx_hold_task(struct task_struct *p, struct rq *rq) +{ + return; +} + +static inline +void vx_unhold_task(struct task_struct *p, struct rq *rq) +{ + return; +} + +unsigned long nr_onhold(void) +{ + return 0; +} + + +static inline +int vx_need_resched(struct task_struct *p, int slice, int cpu) +{ + return (slice == 0); +} + + +#define vx_set_rq_time(rq, time) + +static inline +void vx_try_unhold(struct rq *rq, int cpu) +{ + return; +} + +static inline +int vx_schedule(struct task_struct *next, struct rq *rq, int cpu) +{ + struct vx_info *vxi = next->vx_info; + struct _vx_sched_pc *sched_pc; + int delta_min[2]; + int ret; + + if (!vx_info_flags(vxi, VXF_SCHED_PRIO, 0)) + return 1; + + sched_pc = &vx_per_cpu(vxi, sched_pc, cpu); + vxm_sched_info(sched_pc, vxi, cpu); + ret = vx_tokens_recalc(sched_pc, + &rq->norm_time, &rq->idle_time, delta_min); + vxm_tokens_recalc(sched_pc, rq, vxi, cpu); + return 1; +} + +#endif /* CONFIG_VSERVER_HARDCPU */ + diff -NurpP --minimal linux-2.6.27.15/kernel/sched_mon.h linux-2.6.27.15-g-v/kernel/sched_mon.h --- linux-2.6.27.15/kernel/sched_mon.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/sched_mon.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,200 @@ + +#include + +#ifdef CONFIG_VSERVER_MONITOR + +#ifdef CONFIG_VSERVER_HARDCPU +#define HARDCPU(x) (x) +#else +#define HARDCPU(x) (0) +#endif + +#ifdef CONFIG_VSERVER_IDLETIME +#define IDLETIME(x) (x) +#else +#define IDLETIME(x) (0) +#endif + +struct _vx_mon_entry *vxm_advance(int cpu); + + +static inline +void __vxm_basic(struct _vx_mon_entry *entry, xid_t xid, int type) +{ + entry->type = type; + entry->xid = xid; +} + +static inline +void __vxm_sync(int cpu) +{ + struct _vx_mon_entry *entry = vxm_advance(cpu); + + __vxm_basic(entry, 0, VXM_SYNC); + entry->ev.sec = xtime.tv_sec; + entry->ev.nsec = xtime.tv_nsec; +} + +static inline +void __vxm_task(struct task_struct *p, int type) +{ + struct _vx_mon_entry *entry = vxm_advance(task_cpu(p)); + + __vxm_basic(entry, p->xid, type); + entry->ev.tsk.pid = p->pid; + entry->ev.tsk.state = p->state; +} + +static inline +void __vxm_sched(struct _vx_sched_pc *s, struct vx_info *vxi, int cpu) +{ + struct _vx_mon_entry *entry = vxm_advance(cpu); + + __vxm_basic(entry, vxi->vx_id, (VXM_SCHED | s->flags)); + entry->sd.tokens = s->tokens; + entry->sd.norm_time = s->norm_time; + entry->sd.idle_time = s->idle_time; +} + +static inline +void __vxm_rqinfo1(struct rq *q, int cpu) +{ + struct _vx_mon_entry *entry = vxm_advance(cpu); + + entry->type = VXM_RQINFO_1; + entry->xid = ((unsigned long)q >> 16) & 0xffff; + entry->q1.running = q->nr_running; + entry->q1.onhold = HARDCPU(q->nr_onhold); + entry->q1.iowait = atomic_read(&q->nr_iowait); + entry->q1.uintr = q->nr_uninterruptible; + entry->q1.idle_tokens = IDLETIME(q->idle_tokens); +} + +static inline +void __vxm_rqinfo2(struct rq *q, int cpu) +{ + struct _vx_mon_entry *entry = vxm_advance(cpu); + + entry->type = VXM_RQINFO_2; + entry->xid = (unsigned long)q & 0xffff; + entry->q2.norm_time = q->norm_time; + entry->q2.idle_time = q->idle_time; + entry->q2.idle_skip = IDLETIME(q->idle_skip); +} + +static inline +void __vxm_update(struct _vx_sched_pc *s, struct vx_info *vxi, int cpu) +{ + struct _vx_mon_entry *entry = vxm_advance(cpu); + + __vxm_basic(entry, vxi->vx_id, VXM_UPDATE); + entry->ev.tokens = s->tokens; +} + +static inline +void __vxm_update1(struct _vx_sched_pc *s, struct vx_info *vxi, int cpu) +{ + struct _vx_mon_entry *entry = vxm_advance(cpu); + + __vxm_basic(entry, vxi->vx_id, VXM_UPDATE_1); + entry->u1.tokens_max = s->tokens_max; + entry->u1.fill_rate = s->fill_rate[0]; + entry->u1.interval = s->interval[0]; +} + +static inline +void __vxm_update2(struct _vx_sched_pc *s, struct vx_info *vxi, int cpu) +{ + struct _vx_mon_entry *entry = vxm_advance(cpu); + + __vxm_basic(entry, vxi->vx_id, VXM_UPDATE_2); + entry->u2.tokens_min = s->tokens_min; + entry->u2.fill_rate = s->fill_rate[1]; + entry->u2.interval = s->interval[1]; +} + + +#define vxm_activate_task(p,q) __vxm_task(p, VXM_ACTIVATE) +#define vxm_activate_idle(p,q) __vxm_task(p, VXM_IDLE) +#define vxm_deactivate_task(p,q) __vxm_task(p, VXM_DEACTIVATE) +#define vxm_hold_task(p,q) __vxm_task(p, VXM_HOLD) +#define vxm_unhold_task(p,q) __vxm_task(p, VXM_UNHOLD) + +static inline +void vxm_migrate_task(struct task_struct *p, struct rq *rq, int dest) +{ + __vxm_task(p, VXM_MIGRATE); + __vxm_rqinfo1(rq, task_cpu(p)); + __vxm_rqinfo2(rq, task_cpu(p)); +} + +static inline +void vxm_idle_skip(struct rq *rq, int cpu) +{ + __vxm_rqinfo1(rq, cpu); + __vxm_rqinfo2(rq, cpu); +} + +static inline +void vxm_need_resched(struct task_struct *p, int slice, int cpu) +{ + if (slice) + return; + + __vxm_task(p, VXM_RESCHED); +} + +static inline +void vxm_sync(unsigned long now, int cpu) +{ + if (!CONFIG_VSERVER_MONITOR_SYNC || + (now % CONFIG_VSERVER_MONITOR_SYNC)) + return; + + __vxm_sync(cpu); +} + +#define vxm_sched_info(s,v,c) __vxm_sched(s,v,c) + +static inline +void vxm_tokens_recalc(struct _vx_sched_pc *s, struct rq *rq, + struct vx_info *vxi, int cpu) +{ + __vxm_sched(s, vxi, cpu); + __vxm_rqinfo2(rq, cpu); +} + +static inline +void vxm_update_sched(struct _vx_sched_pc *s, struct vx_info *vxi, int cpu) +{ + __vxm_sched(s, vxi, cpu); + __vxm_update(s, vxi, cpu); + __vxm_update1(s, vxi, cpu); + __vxm_update2(s, vxi, cpu); +} + +static inline +void vxm_rq_max_min(struct rq *rq, int cpu) +{ + __vxm_rqinfo1(rq, cpu); + __vxm_rqinfo2(rq, cpu); +} + +#else /* CONFIG_VSERVER_MONITOR */ + +#define vxm_activate_task(t,q) do { } while (0) +#define vxm_activate_idle(t,q) do { } while (0) +#define vxm_deactivate_task(t,q) do { } while (0) +#define vxm_hold_task(t,q) do { } while (0) +#define vxm_unhold_task(t,q) do { } while (0) +#define vxm_migrate_task(t,q,d) do { } while (0) +#define vxm_idle_skip(q,c) do { } while (0) +#define vxm_need_resched(t,s,c) do { } while (0) +#define vxm_sync(s,c) do { } while (0) +#define vxm_sched_info(s,v,c) do { } while (0) +#define vxm_tokens_recalc(s,q,v,c) do { } while (0) +#define vxm_update_sched(s,v,c) do { } while (0) +#define vxm_rq_max_min(q,c) do { } while (0) + +#endif /* CONFIG_VSERVER_MONITOR */ + diff -NurpP --minimal linux-2.6.27.15/kernel/signal.c linux-2.6.27.15-g-v/kernel/signal.c --- linux-2.6.27.15/kernel/signal.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/signal.c 2009-02-10 20:32:41.000000000 +0100 @@ -26,7 +26,10 @@ #include #include #include +#include #include +#include +#include #include #include @@ -571,6 +574,14 @@ static int check_kill_permission(int sig if (!valid_signal(sig)) return -EINVAL; + if ((info != SEND_SIG_NOINFO) && + (is_si_special(info) || !SI_FROMUSER(info))) + goto skip; + + vxdprintk(VXD_CBIT(misc, 7), + "check_kill_permission(%d,%p,%p[#%u,%u])", + sig, info, t, vx_task_xid(t), t->pid); + if (info != SEND_SIG_NOINFO && (is_si_special(info) || SI_FROMKERNEL(info))) return 0; @@ -595,6 +606,22 @@ static int check_kill_permission(int sig } } + error = -EPERM; + if (t->pid == 1 && current->xid) + return error; + + error = -ESRCH; + if (!vx_check(vx_task_xid(t), VS_WATCH_P | VS_IDENT)) { + vxdprintk(current->xid || VXD_CBIT(misc, 7), + "signal %d[%p] xid mismatch %p[#%u,%u] xid=#%u", + sig, info, t, vx_task_xid(t), t->pid, current->xid); + return error; + } +skip: + + if (gr_handle_signal(t, sig)) + return -EPERM; + return security_task_kill(t, info, sig, 0); } @@ -884,8 +911,8 @@ static void print_fatal_signal(struct pt for (i = 0; i < 16; i++) { unsigned char insn; - __get_user(insn, (unsigned char *)(regs->ip + i)); - printk("%02x ", insn); + if (!get_user(insn, (unsigned char __user *)(regs->ip + i))) + printk("%02x ", insn); } } #endif @@ -908,7 +935,7 @@ __group_send_sig_info(int sig, struct si return send_signal(sig, info, p, 1); } -static int +int specific_send_sig_info(int sig, struct siginfo *info, struct task_struct *t) { return send_signal(sig, info, t, 0); @@ -946,8 +973,12 @@ force_sig_info(int sig, struct siginfo * if (action->sa.sa_handler == SIG_DFL) t->signal->flags &= ~SIGNAL_UNKILLABLE; ret = specific_send_sig_info(sig, info, t); + spin_unlock_irqrestore(&t->sighand->siglock, flags); + gr_log_signal(sig, t); + gr_handle_crash(t, sig); + return ret; } @@ -1018,6 +1049,8 @@ int group_send_sig_info(int sig, struct ret = __group_send_sig_info(sig, info, p); unlock_task_sighand(p, &flags); } + if (!ret) + gr_log_signal(sig, p); } return ret; @@ -1051,7 +1084,7 @@ int kill_pid_info(int sig, struct siginf rcu_read_lock(); retry: p = pid_task(pid, PIDTYPE_PID); - if (p) { + if (p && vx_check(vx_task_xid(p), VS_ADMIN | VS_IDENT)) { error = group_send_sig_info(sig, info, p); if (unlikely(error == -ESRCH)) /* @@ -1089,7 +1122,7 @@ int kill_pid_info_as_uid(int sig, struct read_lock(&tasklist_lock); p = pid_task(pid, PIDTYPE_PID); - if (!p) { + if (!p || !vx_check(vx_task_xid(p), VS_IDENT)) { ret = -ESRCH; goto out_unlock; } @@ -1141,8 +1174,10 @@ static int kill_something_info(int sig, struct task_struct * p; for_each_process(p) { - if (task_pid_vnr(p) > 1 && - !same_thread_group(p, current)) { + if (vx_check(vx_task_xid(p), VS_ADMIN|VS_IDENT) && + task_pid_vnr(p) > 1 && + !same_thread_group(p, current) && + !vx_current_initpid(p->pid)) { int err = group_send_sig_info(sig, info, p); ++count; if (err != -EPERM) @@ -1815,6 +1850,11 @@ relock: !signal_group_exit(signal)) continue; + /* virtual init is protected against user signals */ + if ((info->si_code == SI_USER) && + vx_current_initpid(current->pid)) + continue; + if (sig_kernel_stop(signr)) { /* * The default action is to stop all threads in diff -NurpP --minimal linux-2.6.27.15/kernel/softirq.c linux-2.6.27.15-g-v/kernel/softirq.c --- linux-2.6.27.15/kernel/softirq.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/softirq.c 2009-02-10 20:32:16.000000000 +0100 @@ -21,6 +21,7 @@ #include #include #include +#include #include /* @@ -453,9 +454,9 @@ void tasklet_kill(struct tasklet_struct printk("Attempt to kill tasklet from interrupt\n"); while (test_and_set_bit(TASKLET_STATE_SCHED, &t->state)) { - do + do { yield(); - while (test_bit(TASKLET_STATE_SCHED, &t->state)); + } while (test_bit(TASKLET_STATE_SCHED, &t->state)); } tasklet_unlock_wait(t); clear_bit(TASKLET_STATE_SCHED, &t->state); diff -NurpP --minimal linux-2.6.27.15/kernel/sys.c linux-2.6.27.15-g-v/kernel/sys.c --- linux-2.6.27.15/kernel/sys.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/sys.c 2009-02-10 20:32:16.000000000 +0100 @@ -33,11 +33,13 @@ #include #include #include +#include #include #include #include #include +#include #include #include @@ -122,9 +124,18 @@ static int set_one_prio(struct task_stru goto out; } if (niceval < task_nice(p) && !can_nice(p, niceval)) { + if (vx_flags(VXF_IGNEG_NICE, 0)) + error = 0; + else + error = -EACCES; + goto out; + } + + if (gr_handle_chroot_setpriority(p, niceval)) { error = -EACCES; goto out; } + no_nice = security_task_setnice(p, niceval); if (no_nice) { error = no_nice; @@ -170,6 +181,8 @@ SYSCALL_DEFINE3(setpriority, int, which, else pgrp = task_pgrp(current); do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { + if (!vx_check(p->xid, VS_ADMIN_P | VS_IDENT)) + continue; error = set_one_prio(p, niceval, error); } while_each_pid_thread(pgrp, PIDTYPE_PGID, p); break; @@ -181,10 +194,10 @@ SYSCALL_DEFINE3(setpriority, int, which, if ((who != current->uid) && !(user = find_user(who))) goto out_unlock; /* No processes for this user */ - do_each_thread(g, p) + do_each_thread(g, p) { if (p->uid == who) error = set_one_prio(p, niceval, error); - while_each_thread(g, p); + } while_each_thread(g, p); if (who != current->uid) free_uid(user); /* For find_user() */ break; @@ -230,6 +243,8 @@ SYSCALL_DEFINE2(getpriority, int, which, else pgrp = task_pgrp(current); do_each_pid_thread(pgrp, PIDTYPE_PGID, p) { + if (!vx_check(p->xid, VS_ADMIN_P | VS_IDENT)) + continue; niceval = 20 - task_nice(p); if (niceval > retval) retval = niceval; @@ -243,13 +258,13 @@ SYSCALL_DEFINE2(getpriority, int, which, if ((who != current->uid) && !(user = find_user(who))) goto out_unlock; /* No processes for this user */ - do_each_thread(g, p) + do_each_thread(g, p) { if (p->uid == who) { niceval = 20 - task_nice(p); if (niceval > retval) retval = niceval; } - while_each_thread(g, p); + } while_each_thread(g, p); if (who != current->uid) free_uid(user); /* for find_user() */ break; @@ -339,6 +354,9 @@ void kernel_power_off(void) machine_power_off(); } EXPORT_SYMBOL_GPL(kernel_power_off); + +long vs_reboot(unsigned int, void __user *); + /* * Reboot system call: for obvious reasons only root may call it, * and even root needs to set up some magic numbers in the registers @@ -370,6 +388,9 @@ SYSCALL_DEFINE4(reboot, int, magic1, int if ((cmd == LINUX_REBOOT_CMD_POWER_OFF) && !pm_power_off) cmd = LINUX_REBOOT_CMD_HALT; + if (!vx_check(0, VS_ADMIN|VS_WATCH)) + return vs_reboot(cmd, arg); + lock_kernel(); switch (cmd) { case LINUX_REBOOT_CMD_RESTART: @@ -500,6 +521,10 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, g else return -EPERM; } + + if (gr_check_group_change(new_rgid, new_egid, -1)) + return -EPERM; + if (new_egid != old_egid) { set_dumpable(current->mm, suid_dumpable); smp_wmb(); @@ -507,6 +532,9 @@ SYSCALL_DEFINE2(setregid, gid_t, rgid, g if (rgid != (gid_t) -1 || (egid != (gid_t) -1 && egid != old_rgid)) current->sgid = new_egid; + + gr_set_role_label(current, current->uid, new_rgid); + current->fsgid = new_egid; current->egid = new_egid; current->gid = new_rgid; @@ -529,11 +557,17 @@ SYSCALL_DEFINE1(setgid, gid_t, gid) if (retval) return retval; + if (gr_check_group_change(gid, gid, gid)) + return -EPERM; + if (capable(CAP_SETGID)) { if (old_egid != gid) { set_dumpable(current->mm, suid_dumpable); smp_wmb(); } + + gr_set_role_label(current, current->uid, gid); + current->gid = current->egid = current->sgid = current->fsgid = gid; } else if ((gid == current->gid) || (gid == current->sgid)) { if (old_egid != gid) { @@ -571,6 +605,9 @@ static int set_user(uid_t new_ruid, int set_dumpable(current->mm, suid_dumpable); smp_wmb(); } + + gr_set_role_label(current, new_ruid, current->gid); + current->uid = new_ruid; return 0; } @@ -620,6 +657,9 @@ SYSCALL_DEFINE2(setreuid, uid_t, ruid, u return -EPERM; } + if (gr_check_user_change(new_ruid, new_euid, -1)) + return -EPERM; + if (new_ruid != old_ruid && set_user(new_ruid, new_euid != old_euid) < 0) return -EAGAIN; @@ -666,6 +706,12 @@ SYSCALL_DEFINE1(setuid, uid_t, uid) old_suid = current->suid; new_suid = old_suid; + if (gr_check_crash_uid(uid)) + return -EPERM; + + if (gr_check_user_change(uid, uid, uid)) + return -EPERM; + if (capable(CAP_SETUID)) { if (uid != old_ruid && set_user(uid, old_euid != uid) < 0) return -EAGAIN; @@ -713,6 +759,10 @@ SYSCALL_DEFINE3(setresuid, uid_t, ruid, (suid != current->euid) && (suid != current->suid)) return -EPERM; } + + if (gr_check_user_change(ruid, euid, -1)) + return -EPERM; + if (ruid != (uid_t) -1) { if (ruid != current->uid && set_user(ruid, euid != current->euid) < 0) return -EAGAIN; @@ -767,6 +817,10 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, (sgid != current->egid) && (sgid != current->sgid)) return -EPERM; } + + if (gr_check_group_change(rgid, egid, -1)) + return -EPERM; + if (egid != (gid_t) -1) { if (egid != current->egid) { set_dumpable(current->mm, suid_dumpable); @@ -775,8 +829,10 @@ SYSCALL_DEFINE3(setresgid, gid_t, rgid, current->egid = egid; } current->fsgid = current->egid; - if (rgid != (gid_t) -1) + if (rgid != (gid_t) -1) { + gr_set_role_label(current, current->uid, rgid); current->gid = rgid; + } if (sgid != (gid_t) -1) current->sgid = sgid; @@ -811,6 +867,9 @@ SYSCALL_DEFINE1(setfsuid, uid_t, uid) if (security_task_setuid(uid, (uid_t)-1, (uid_t)-1, LSM_SETID_FS)) return old_fsuid; + if (gr_check_user_change(-1, -1, uid)) + return old_fsuid; + if (uid == current->uid || uid == current->euid || uid == current->suid || uid == current->fsuid || capable(CAP_SETUID)) { @@ -843,6 +902,9 @@ SYSCALL_DEFINE1(setfsgid, gid_t, gid) if (gid == current->gid || gid == current->egid || gid == current->sgid || gid == current->fsgid || capable(CAP_SETGID)) { + if (gr_check_group_change(-1, -1, gid)) + return old_fsgid; + if (gid != old_fsgid) { set_dumpable(current->mm, suid_dumpable); smp_wmb(); @@ -924,7 +986,10 @@ SYSCALL_DEFINE2(setpgid, pid_t, pid, pid write_lock_irq(&tasklist_lock); err = -ESRCH; - p = find_task_by_vpid(pid); + /* grsec: replaced find_task_by_vpid with equivalent call which + lacks the chroot restriction + */ + p = pid_task(find_pid_ns(pid, current->nsproxy->pid_ns), PIDTYPE_PID); if (!p) goto out; @@ -1345,7 +1410,7 @@ SYSCALL_DEFINE2(sethostname, char __user int errno; char tmp[__NEW_UTS_LEN]; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SET_UTSNAME)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -1390,7 +1455,7 @@ SYSCALL_DEFINE2(setdomainname, char __us int errno; char tmp[__NEW_UTS_LEN]; - if (!capable(CAP_SYS_ADMIN)) + if (!vx_capable(CAP_SYS_ADMIN, VXC_SET_UTSNAME)) return -EPERM; if (len < 0 || len > __NEW_UTS_LEN) return -EINVAL; @@ -1458,7 +1523,7 @@ SYSCALL_DEFINE2(setrlimit, unsigned int, return -EINVAL; old_rlim = current->signal->rlim + resource; if ((new_rlim.rlim_max > old_rlim->rlim_max) && - !capable(CAP_SYS_RESOURCE)) + !vx_capable(CAP_SYS_RESOURCE, VXC_SET_RLIMIT)) return -EPERM; if (resource == RLIMIT_NOFILE && new_rlim.rlim_max > sysctl_nr_open) return -EPERM; @@ -1657,7 +1722,7 @@ SYSCALL_DEFINE5(prctl, int, option, unsi error = get_dumpable(current->mm); break; case PR_SET_DUMPABLE: - if (arg2 < 0 || arg2 > 1) { + if (arg2 > 1) { error = -EINVAL; break; } diff -NurpP --minimal linux-2.6.27.15/kernel/sysctl.c linux-2.6.27.15-g-v/kernel/sysctl.c --- linux-2.6.27.15/kernel/sysctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/sysctl.c 2009-02-10 20:32:16.000000000 +0100 @@ -61,6 +61,13 @@ static int deprecated_sysctl_warning(struct __sysctl_args *args); #if defined(CONFIG_SYSCTL) +#include +#include + +extern __u32 gr_handle_sysctl(const ctl_table *table, const int op); +extern int gr_handle_sysctl_mod(const char *dirname, const char *name, + const int op); +extern int gr_handle_chroot_sysctl(const int op); /* External variables not in a header file. */ extern int C_A_D; @@ -114,6 +121,7 @@ static int ngroups_max = NGROUPS_MAX; #ifdef CONFIG_MODULES extern char modprobe_path[]; #endif +extern char vshelper_path[]; #ifdef CONFIG_CHR_DEV_SG extern int sg_big_buff; #endif @@ -155,6 +163,7 @@ static int proc_do_cad_pid(struct ctl_ta static int proc_dointvec_taint(struct ctl_table *table, int write, struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos); #endif +extern ctl_table grsecurity_table[]; static struct ctl_table root_table[]; static struct ctl_table_root sysctl_table_root; @@ -187,6 +196,21 @@ extern struct ctl_table epoll_table[]; int sysctl_legacy_va_layout; #endif +#ifdef CONFIG_PAX_SOFTMODE +static ctl_table pax_table[] = { + { + .ctl_name = CTL_UNNUMBERED, + .procname = "softmode", + .data = &pax_softmode, + .maxlen = sizeof(unsigned int), + .mode = 0600, + .proc_handler = &proc_dointvec, + }, + + { .ctl_name = 0 } +}; +#endif + extern int prove_locking; extern int lock_stat; @@ -223,6 +247,7 @@ static struct ctl_table root_table[] = { .mode = 0555, .child = dev_table, }, + /* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt @@ -503,6 +528,15 @@ static struct ctl_table kern_table[] = { .strategy = &sysctl_string, }, #endif + { + .ctl_name = KERN_VSHELPER, + .procname = "vshelper", + .data = &vshelper_path, + .maxlen = 256, + .mode = 0644, + .proc_handler = &proc_dostring, + .strategy = &sysctl_string, + }, #ifdef CONFIG_CHR_DEV_SG { .ctl_name = KERN_SG_BIG_BUFF, @@ -850,6 +884,25 @@ static struct ctl_table kern_table[] = { .proc_handler = &proc_dointvec, }, #endif + +#if defined(CONFIG_GRKERNSEC_SYSCTL) || defined(CONFIG_GRKERNSEC_MODSTOP) + { + .ctl_name = CTL_UNNUMBERED, + .procname = "grsecurity", + .mode = 0500, + .child = grsecurity_table, + }, +#endif + +#ifdef CONFIG_PAX_SOFTMODE + { + .ctl_name = CTL_UNNUMBERED, + .procname = "pax", + .mode = 0500, + .child = pax_table, + }, +#endif + /* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt @@ -1179,6 +1232,7 @@ static struct ctl_table vm_table[] = { .extra2 = &one, }, #endif + /* * NOTE: do not add new entries to this table unless you have read * Documentation/sysctl/ctl_unnumbered.txt @@ -1553,6 +1607,8 @@ static int do_sysctl_strategy(struct ctl return 0; } +static int sysctl_perm_nochk(struct ctl_table_root *root, struct ctl_table *table, int op); + static int parse_table(int __user *name, int nlen, void __user *oldval, size_t __user *oldlenp, void __user *newval, size_t newlen, @@ -1571,7 +1627,7 @@ repeat: if (n == table->ctl_name) { int error; if (table->child) { - if (sysctl_perm(root, table, MAY_EXEC)) + if (sysctl_perm_nochk(root, table, MAY_EXEC)) return -EPERM; name++; nlen--; @@ -1656,6 +1712,33 @@ int sysctl_perm(struct ctl_table_root *r int error; int mode; + if (table->parent != NULL && table->parent->procname != NULL && + table->procname != NULL && + gr_handle_sysctl_mod(table->parent->procname, table->procname, op)) + return -EACCES; + if (gr_handle_chroot_sysctl(op)) + return -EACCES; + error = gr_handle_sysctl(table, op); + if (error) + return error; + + error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC)); + if (error) + return error; + + if (root->permissions) + mode = root->permissions(root, current->nsproxy, table); + else + mode = table->mode; + + return test_perm(mode, op); +} + +int sysctl_perm_nochk(struct ctl_table_root *root, struct ctl_table *table, int op) +{ + int error; + int mode; + error = security_sysctl(table, op & (MAY_READ | MAY_WRITE | MAY_EXEC)); if (error) return error; diff -NurpP --minimal linux-2.6.27.15/kernel/sysctl_check.c linux-2.6.27.15-g-v/kernel/sysctl_check.c --- linux-2.6.27.15/kernel/sysctl_check.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/sysctl_check.c 2009-02-10 20:32:16.000000000 +0100 @@ -39,6 +39,7 @@ static const struct trans_ctl_table tran { KERN_PANIC, "panic" }, { KERN_REALROOTDEV, "real-root-dev" }, + { KERN_VSHELPER, "vshelper", }, { KERN_SPARC_REBOOT, "reboot-cmd" }, { KERN_CTLALTDEL, "ctrl-alt-del" }, @@ -1217,6 +1218,22 @@ static const struct trans_ctl_table tran {} }; +static struct trans_ctl_table trans_vserver_table[] = { + { 1, "debug_switch" }, + { 2, "debug_xid" }, + { 3, "debug_nid" }, + { 4, "debug_tag" }, + { 5, "debug_net" }, + { 6, "debug_limit" }, + { 7, "debug_cres" }, + { 8, "debug_dlim" }, + { 9, "debug_quota" }, + { 10, "debug_cvirt" }, + { 11, "debug_space" }, + { 12, "debug_misc" }, + {} +}; + static const struct trans_ctl_table trans_root_table[] = { { CTL_KERN, "kernel", trans_kern_table }, { CTL_VM, "vm", trans_vm_table }, @@ -1233,6 +1250,7 @@ static const struct trans_ctl_table tran { CTL_SUNRPC, "sunrpc", trans_sunrpc_table }, { CTL_PM, "pm", trans_pm_table }, { CTL_FRV, "frv", trans_frv_table }, + { CTL_VSERVER, "vserver", trans_vserver_table }, {} }; diff -NurpP --minimal linux-2.6.27.15/kernel/time/tick-broadcast.c linux-2.6.27.15-g-v/kernel/time/tick-broadcast.c --- linux-2.6.27.15/kernel/time/tick-broadcast.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/time/tick-broadcast.c 2009-02-10 20:32:16.000000000 +0100 @@ -114,7 +114,7 @@ int tick_device_uses_broadcast(struct cl * then clear the broadcast bit. */ if (!(dev->features & CLOCK_EVT_FEAT_C3STOP)) { - int cpu = smp_processor_id(); + cpu = smp_processor_id(); cpu_clear(cpu, tick_broadcast_mask); tick_broadcast_clear_oneshot(cpu); diff -NurpP --minimal linux-2.6.27.15/kernel/time.c linux-2.6.27.15-g-v/kernel/time.c --- linux-2.6.27.15/kernel/time.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/time.c 2009-02-10 20:32:16.000000000 +0100 @@ -37,6 +37,7 @@ #include #include #include +#include #include #include @@ -62,6 +63,7 @@ EXPORT_SYMBOL(sys_tz); SYSCALL_DEFINE1(time, time_t __user *, tloc) { time_t i = get_seconds(); +/* FIXME: do_gettimeofday(&tv) -> vx_gettimeofday(&tv) */ if (tloc) { if (put_user(i,tloc)) @@ -91,7 +93,10 @@ SYSCALL_DEFINE1(stime, time_t __user *, if (err) return err; - do_settimeofday(&tv); + vx_settimeofday(&tv); + + gr_log_timechange(); + return 0; } @@ -102,7 +107,7 @@ SYSCALL_DEFINE2(gettimeofday, struct tim { if (likely(tv != NULL)) { struct timeval ktv; - do_gettimeofday(&ktv); + vx_gettimeofday(&ktv); if (copy_to_user(tv, &ktv, sizeof(ktv))) return -EFAULT; } @@ -177,7 +182,7 @@ int do_sys_settimeofday(struct timespec /* SMP safe, again the code in arch/foo/time.c should * globally block out interrupts when it runs. */ - return do_settimeofday(tv); + return vx_settimeofday(tv); } return 0; } @@ -200,6 +205,8 @@ SYSCALL_DEFINE2(settimeofday, struct tim return -EFAULT; } + gr_log_timechange(); + return do_sys_settimeofday(tv ? &new_ts : NULL, tz ? &new_tz : NULL); } @@ -238,7 +245,7 @@ EXPORT_SYMBOL(current_fs_time); * Avoid unnecessary multiplications/divisions in the * two most common HZ cases: */ -unsigned int inline jiffies_to_msecs(const unsigned long j) +inline unsigned int jiffies_to_msecs(const unsigned long j) { #if HZ <= MSEC_PER_SEC && !(MSEC_PER_SEC % HZ) return (MSEC_PER_SEC / HZ) * j; @@ -254,7 +261,7 @@ unsigned int inline jiffies_to_msecs(con } EXPORT_SYMBOL(jiffies_to_msecs); -unsigned int inline jiffies_to_usecs(const unsigned long j) +inline unsigned int jiffies_to_usecs(const unsigned long j) { #if HZ <= USEC_PER_SEC && !(USEC_PER_SEC % HZ) return (USEC_PER_SEC / HZ) * j; @@ -309,7 +316,7 @@ void getnstimeofday(struct timespec *tv) { struct timeval x; - do_gettimeofday(&x); + vx_gettimeofday(&x); tv->tv_sec = x.tv_sec; tv->tv_nsec = x.tv_usec * NSEC_PER_USEC; } diff -NurpP --minimal linux-2.6.27.15/kernel/timer.c linux-2.6.27.15-g-v/kernel/timer.c --- linux-2.6.27.15/kernel/timer.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/timer.c 2009-02-10 20:32:16.000000000 +0100 @@ -37,6 +37,10 @@ #include #include #include +#include +#include +#include +#include #include #include @@ -1081,12 +1085,6 @@ SYSCALL_DEFINE1(alarm, unsigned int, sec #endif -#ifndef __alpha__ - -/* - * The Alpha uses getxpid, getxuid, and getxgid instead. Maybe this - * should be moved into arch/i386 instead? - */ /** * sys_getpid - return the thread group id of the current process @@ -1115,10 +1113,23 @@ SYSCALL_DEFINE0(getppid) rcu_read_lock(); pid = task_tgid_vnr(current->real_parent); rcu_read_unlock(); + return vx_map_pid(pid); +} - return pid; +#ifdef __alpha__ + +/* + * The Alpha uses getxpid, getxuid, and getxgid instead. + */ + +asmlinkage long do_getxpid(long *ppid) +{ + *ppid = sys_getppid(); + return sys_getpid(); } +#else /* _alpha_ */ + SYSCALL_DEFINE0(getuid) { /* Only we change this so SMP safe */ @@ -1289,6 +1300,8 @@ int do_sysinfo(struct sysinfo *info) tp.tv_nsec = tp.tv_nsec - NSEC_PER_SEC; tp.tv_sec++; } + if (vx_flags(VXF_VIRT_UPTIME, 0)) + vx_vsi_uptime(&tp, NULL); info->uptime = tp.tv_sec + (tp.tv_nsec ? 1 : 0); info->loads[0] = avenrun[0] << (SI_LOAD_SHIFT - FSHIFT); diff -NurpP --minimal linux-2.6.27.15/kernel/user.c linux-2.6.27.15-g-v/kernel/user.c --- linux-2.6.27.15/kernel/user.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/user.c 2009-02-10 20:32:16.000000000 +0100 @@ -243,12 +243,15 @@ static struct kobj_type uids_ktype = { }; /* create /sys/kernel/uids//cpu_share file for this user */ -static int uids_user_create(struct user_struct *up) +static int uids_user_create(struct user_namespace *ns, struct user_struct *up) { struct kobject *kobj = &up->kobj; - int error; + int error = 0; memset(kobj, 0, sizeof(struct kobject)); + if (ns != &init_user_ns) + goto done; + kobj->kset = uids_kset; error = kobject_init_and_add(kobj, &uids_ktype, NULL, "%d", up->uid); if (error) { @@ -272,7 +275,7 @@ int __init uids_sysfs_init(void) if (!uids_kset) return -ENOMEM; - return uids_user_create(&root_user); + return uids_user_create(NULL, &root_user); } /* work function to remove sysfs directory for a user and free up @@ -302,9 +305,11 @@ static void remove_user_sysfs_dir(struct if (!remove_user) goto done; - kobject_uevent(&up->kobj, KOBJ_REMOVE); - kobject_del(&up->kobj); - kobject_put(&up->kobj); + if (up->kobj.name) { + kobject_uevent(&up->kobj, KOBJ_REMOVE); + kobject_del(&up->kobj); + kobject_put(&up->kobj); + } sched_destroy_user(up); key_put(up->uid_keyring); @@ -332,7 +337,8 @@ static inline void free_user(struct user #else /* CONFIG_USER_SCHED && CONFIG_SYSFS */ int uids_sysfs_init(void) { return 0; } -static inline int uids_user_create(struct user_struct *up) { return 0; } +static inline int uids_user_create(struct user_namespace *ns, + struct user_struct *up) { return 0; } static inline void uids_mutex_lock(void) { } static inline void uids_mutex_unlock(void) { } @@ -409,7 +415,7 @@ struct user_struct *alloc_uid(struct use if (sched_create_user(new) < 0) goto out_free_user; - if (uids_user_create(new)) + if (uids_user_create(ns, new)) goto out_destoy_sched; /* diff -NurpP --minimal linux-2.6.27.15/kernel/user_namespace.c linux-2.6.27.15-g-v/kernel/user_namespace.c --- linux-2.6.27.15/kernel/user_namespace.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/user_namespace.c 2009-02-10 20:32:16.000000000 +0100 @@ -9,6 +9,7 @@ #include #include #include +#include /* * Clone a new ns copying an original user ns, setting refcount to 1 @@ -26,6 +27,7 @@ static struct user_namespace *clone_user return ERR_PTR(-ENOMEM); kref_init(&ns->kref); + atomic_inc(&vs_global_user_ns); for (n = 0; n < UIDHASH_SZ; ++n) INIT_HLIST_HEAD(ns->uidhash_table + n); @@ -71,6 +73,7 @@ void free_user_ns(struct kref *kref) ns = container_of(kref, struct user_namespace, kref); release_uids(ns); + atomic_dec(&vs_global_user_ns); kfree(ns); } EXPORT_SYMBOL(free_user_ns); diff -NurpP --minimal linux-2.6.27.15/kernel/utsname.c linux-2.6.27.15-g-v/kernel/utsname.c --- linux-2.6.27.15/kernel/utsname.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/utsname.c 2009-02-10 20:32:16.000000000 +0100 @@ -14,6 +14,7 @@ #include #include #include +#include /* * Clone a new ns copying an original utsname, setting refcount to 1 @@ -32,6 +33,7 @@ static struct uts_namespace *clone_uts_n memcpy(&ns->name, &old_ns->name, sizeof(ns->name)); up_read(&uts_sem); kref_init(&ns->kref); + atomic_inc(&vs_global_uts_ns); return ns; } @@ -62,5 +64,6 @@ void free_uts_ns(struct kref *kref) struct uts_namespace *ns; ns = container_of(kref, struct uts_namespace, kref); + atomic_dec(&vs_global_uts_ns); kfree(ns); } diff -NurpP --minimal linux-2.6.27.15/kernel/utsname_sysctl.c linux-2.6.27.15-g-v/kernel/utsname_sysctl.c --- linux-2.6.27.15/kernel/utsname_sysctl.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/utsname_sysctl.c 2009-02-10 20:32:16.000000000 +0100 @@ -124,7 +124,7 @@ static struct ctl_table uts_kern_table[] .proc_handler = proc_do_uts_string, .strategy = sysctl_uts_string, }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static struct ctl_table uts_root_table[] = { @@ -134,7 +134,7 @@ static struct ctl_table uts_root_table[] .mode = 0555, .child = uts_kern_table, }, - {} + { 0, NULL, NULL, 0, 0, NULL, NULL, NULL, NULL, NULL, NULL } }; static int __init utsname_sysctl_init(void) diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/cacct.c linux-2.6.27.15-g-v/kernel/vserver/cacct.c --- linux-2.6.27.15/kernel/vserver/cacct.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/cacct.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,42 @@ +/* + * linux/kernel/vserver/cacct.c + * + * Virtual Server: Context Accounting + * + * Copyright (C) 2006-2007 Herbert Pötzl + * + * V0.01 added accounting stats + * + */ + +#include +#include +#include +#include + +#include +#include + + +int vc_sock_stat(struct vx_info *vxi, void __user *data) +{ + struct vcmd_sock_stat_v0 vc_data; + int j, field; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + field = vc_data.field; + if ((field < 0) || (field >= VXA_SOCK_SIZE)) + return -EINVAL; + + for (j = 0; j < 3; j++) { + vc_data.count[j] = vx_sock_count(&vxi->cacct, field, j); + vc_data.total[j] = vx_sock_total(&vxi->cacct, field, j); + } + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/cacct_init.h linux-2.6.27.15-g-v/kernel/vserver/cacct_init.h --- linux-2.6.27.15/kernel/vserver/cacct_init.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/cacct_init.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,25 @@ + + +static inline void vx_info_init_cacct(struct _vx_cacct *cacct) +{ + int i, j; + + + for (i = 0; i < VXA_SOCK_SIZE; i++) { + for (j = 0; j < 3; j++) { + atomic_set(&cacct->sock[i][j].count, 0); + atomic_set(&cacct->sock[i][j].total, 0); + } + } + for (i = 0; i < 8; i++) + atomic_set(&cacct->slab[i], 0); + for (i = 0; i < 5; i++) + for (j = 0; j < 4; j++) + atomic_set(&cacct->page[i][j], 0); +} + +static inline void vx_info_exit_cacct(struct _vx_cacct *cacct) +{ + return; +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/cacct_proc.h linux-2.6.27.15-g-v/kernel/vserver/cacct_proc.h --- linux-2.6.27.15/kernel/vserver/cacct_proc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/cacct_proc.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,53 @@ +#ifndef _VX_CACCT_PROC_H +#define _VX_CACCT_PROC_H + +#include + + +#define VX_SOCKA_TOP \ + "Type\t recv #/bytes\t\t send #/bytes\t\t fail #/bytes\n" + +static inline int vx_info_proc_cacct(struct _vx_cacct *cacct, char *buffer) +{ + int i, j, length = 0; + static char *type[VXA_SOCK_SIZE] = { + "UNSPEC", "UNIX", "INET", "INET6", "PACKET", "OTHER" + }; + + length += sprintf(buffer + length, VX_SOCKA_TOP); + for (i = 0; i < VXA_SOCK_SIZE; i++) { + length += sprintf(buffer + length, "%s:", type[i]); + for (j = 0; j < 3; j++) { + length += sprintf(buffer + length, + "\t%10lu/%-10lu", + vx_sock_count(cacct, i, j), + vx_sock_total(cacct, i, j)); + } + buffer[length++] = '\n'; + } + + length += sprintf(buffer + length, "\n"); + length += sprintf(buffer + length, + "slab:\t %8u %8u %8u %8u\n", + atomic_read(&cacct->slab[1]), + atomic_read(&cacct->slab[4]), + atomic_read(&cacct->slab[0]), + atomic_read(&cacct->slab[2])); + + length += sprintf(buffer + length, "\n"); + for (i = 0; i < 5; i++) { + length += sprintf(buffer + length, + "page[%d]: %8u %8u %8u %8u\t %8u %8u %8u %8u\n", i, + atomic_read(&cacct->page[i][0]), + atomic_read(&cacct->page[i][1]), + atomic_read(&cacct->page[i][2]), + atomic_read(&cacct->page[i][3]), + atomic_read(&cacct->page[i][4]), + atomic_read(&cacct->page[i][5]), + atomic_read(&cacct->page[i][6]), + atomic_read(&cacct->page[i][7])); + } + return length; +} + +#endif /* _VX_CACCT_PROC_H */ diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/context.c linux-2.6.27.15-g-v/kernel/vserver/context.c --- linux-2.6.27.15/kernel/vserver/context.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/context.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,1018 @@ +/* + * linux/kernel/vserver/context.c + * + * Virtual Server: Context Support + * + * Copyright (C) 2003-2007 Herbert Pötzl + * + * V0.01 context helper + * V0.02 vx_ctx_kill syscall command + * V0.03 replaced context_info calls + * V0.04 redesign of struct (de)alloc + * V0.05 rlimit basic implementation + * V0.06 task_xid and info commands + * V0.07 context flags and caps + * V0.08 switch to RCU based hash + * V0.09 revert to non RCU for now + * V0.10 and back to working RCU hash + * V0.11 and back to locking again + * V0.12 referenced context store + * V0.13 separate per cpu data + * V0.14 changed vcmds to vxi arg + * V0.15 added context stat + * V0.16 have __create claim() the vxi + * V0.17 removed older and legacy stuff + * + */ + +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "cvirt_init.h" +#include "cacct_init.h" +#include "limit_init.h" +#include "sched_init.h" + + +atomic_t vx_global_ctotal = ATOMIC_INIT(0); +atomic_t vx_global_cactive = ATOMIC_INIT(0); + + +/* now inactive context structures */ + +static struct hlist_head vx_info_inactive = HLIST_HEAD_INIT; + +static spinlock_t vx_info_inactive_lock = SPIN_LOCK_UNLOCKED; + + +/* __alloc_vx_info() + + * allocate an initialized vx_info struct + * doesn't make it visible (hash) */ + +static struct vx_info *__alloc_vx_info(xid_t xid) +{ + struct vx_info *new = NULL; + int cpu; + + vxdprintk(VXD_CBIT(xid, 0), "alloc_vx_info(%d)*", xid); + + /* would this benefit from a slab cache? */ + new = kmalloc(sizeof(struct vx_info), GFP_KERNEL); + if (!new) + return 0; + + memset(new, 0, sizeof(struct vx_info)); +#ifdef CONFIG_SMP + new->ptr_pc = alloc_percpu(struct _vx_info_pc); + if (!new->ptr_pc) + goto error; +#endif + new->vx_id = xid; + INIT_HLIST_NODE(&new->vx_hlist); + atomic_set(&new->vx_usecnt, 0); + atomic_set(&new->vx_tasks, 0); + new->vx_parent = NULL; + new->vx_state = 0; + init_waitqueue_head(&new->vx_wait); + + /* prepare reaper */ + get_task_struct(init_pid_ns.child_reaper); + new->vx_reaper = init_pid_ns.child_reaper; + new->vx_badness_bias = 0; + + /* rest of init goes here */ + vx_info_init_limit(&new->limit); + vx_info_init_sched(&new->sched); + vx_info_init_cvirt(&new->cvirt); + vx_info_init_cacct(&new->cacct); + + /* per cpu data structures */ + for_each_possible_cpu(cpu) { + vx_info_init_sched_pc( + &vx_per_cpu(new, sched_pc, cpu), cpu); + vx_info_init_cvirt_pc( + &vx_per_cpu(new, cvirt_pc, cpu), cpu); + } + + new->vx_flags = VXF_INIT_SET; + cap_set_init_eff(new->vx_bcaps); + new->vx_ccaps = 0; + // new->vx_cap_bset = current->cap_bset; + + new->reboot_cmd = 0; + new->exit_code = 0; + + vxdprintk(VXD_CBIT(xid, 0), + "alloc_vx_info(%d) = %p", xid, new); + vxh_alloc_vx_info(new); + atomic_inc(&vx_global_ctotal); + return new; +#ifdef CONFIG_SMP +error: + kfree(new); + return 0; +#endif +} + +/* __dealloc_vx_info() + + * final disposal of vx_info */ + +static void __dealloc_vx_info(struct vx_info *vxi) +{ + struct vx_info_save vxis; + int cpu; + + vxdprintk(VXD_CBIT(xid, 0), + "dealloc_vx_info(%p)", vxi); + vxh_dealloc_vx_info(vxi); + +#ifdef CONFIG_VSERVER_WARN + enter_vx_info(vxi, &vxis); + vx_info_exit_limit(&vxi->limit); + vx_info_exit_sched(&vxi->sched); + vx_info_exit_cvirt(&vxi->cvirt); + vx_info_exit_cacct(&vxi->cacct); + + for_each_possible_cpu(cpu) { + vx_info_exit_sched_pc( + &vx_per_cpu(vxi, sched_pc, cpu), cpu); + vx_info_exit_cvirt_pc( + &vx_per_cpu(vxi, cvirt_pc, cpu), cpu); + } + leave_vx_info(&vxis); +#endif + + vxi->vx_id = -1; + vxi->vx_state |= VXS_RELEASED; + +#ifdef CONFIG_SMP + free_percpu(vxi->ptr_pc); +#endif + kfree(vxi); + atomic_dec(&vx_global_ctotal); +} + +static void __shutdown_vx_info(struct vx_info *vxi) +{ + struct nsproxy *nsproxy; + struct fs_struct *fs; + int index; + + might_sleep(); + + vxi->vx_state |= VXS_SHUTDOWN; + vs_state_change(vxi, VSC_SHUTDOWN); + + for (index = 0; index < VX_SPACES; index++) { + nsproxy = xchg(&vxi->vx_nsproxy[index], NULL); + if (nsproxy) + put_nsproxy(nsproxy); + + fs = xchg(&vxi->vx_fs[index], NULL); + if (fs) + put_fs_struct(fs); + } +} + +/* exported stuff */ + +void free_vx_info(struct vx_info *vxi) +{ + unsigned long flags; + unsigned index; + + /* check for reference counts first */ + BUG_ON(atomic_read(&vxi->vx_usecnt)); + BUG_ON(atomic_read(&vxi->vx_tasks)); + + /* context must not be hashed */ + BUG_ON(vx_info_state(vxi, VXS_HASHED)); + + /* context shutdown is mandatory */ + BUG_ON(!vx_info_state(vxi, VXS_SHUTDOWN)); + + /* nsproxy and fs check */ + for (index = 0; index < VX_SPACES; index++) { + BUG_ON(vxi->vx_nsproxy[index]); + BUG_ON(vxi->vx_fs[index]); + } + + spin_lock_irqsave(&vx_info_inactive_lock, flags); + hlist_del(&vxi->vx_hlist); + spin_unlock_irqrestore(&vx_info_inactive_lock, flags); + + __dealloc_vx_info(vxi); +} + + +/* hash table for vx_info hash */ + +#define VX_HASH_SIZE 13 + +static struct hlist_head vx_info_hash[VX_HASH_SIZE] = + { [0 ... VX_HASH_SIZE-1] = HLIST_HEAD_INIT }; + +static spinlock_t vx_info_hash_lock = SPIN_LOCK_UNLOCKED; + + +static inline unsigned int __hashval(xid_t xid) +{ + return (xid % VX_HASH_SIZE); +} + + + +/* __hash_vx_info() + + * add the vxi to the global hash table + * requires the hash_lock to be held */ + +static inline void __hash_vx_info(struct vx_info *vxi) +{ + struct hlist_head *head; + + vxd_assert_lock(&vx_info_hash_lock); + vxdprintk(VXD_CBIT(xid, 4), + "__hash_vx_info: %p[#%d]", vxi, vxi->vx_id); + vxh_hash_vx_info(vxi); + + /* context must not be hashed */ + BUG_ON(vx_info_state(vxi, VXS_HASHED)); + + vxi->vx_state |= VXS_HASHED; + head = &vx_info_hash[__hashval(vxi->vx_id)]; + hlist_add_head(&vxi->vx_hlist, head); + atomic_inc(&vx_global_cactive); +} + +/* __unhash_vx_info() + + * remove the vxi from the global hash table + * requires the hash_lock to be held */ + +static inline void __unhash_vx_info(struct vx_info *vxi) +{ + unsigned long flags; + + vxd_assert_lock(&vx_info_hash_lock); + vxdprintk(VXD_CBIT(xid, 4), + "__unhash_vx_info: %p[#%d.%d.%d]", vxi, vxi->vx_id, + atomic_read(&vxi->vx_usecnt), atomic_read(&vxi->vx_tasks)); + vxh_unhash_vx_info(vxi); + + /* context must be hashed */ + BUG_ON(!vx_info_state(vxi, VXS_HASHED)); + /* but without tasks */ + BUG_ON(atomic_read(&vxi->vx_tasks)); + + vxi->vx_state &= ~VXS_HASHED; + hlist_del_init(&vxi->vx_hlist); + spin_lock_irqsave(&vx_info_inactive_lock, flags); + hlist_add_head(&vxi->vx_hlist, &vx_info_inactive); + spin_unlock_irqrestore(&vx_info_inactive_lock, flags); + atomic_dec(&vx_global_cactive); +} + + +/* __lookup_vx_info() + + * requires the hash_lock to be held + * doesn't increment the vx_refcnt */ + +static inline struct vx_info *__lookup_vx_info(xid_t xid) +{ + struct hlist_head *head = &vx_info_hash[__hashval(xid)]; + struct hlist_node *pos; + struct vx_info *vxi; + + vxd_assert_lock(&vx_info_hash_lock); + hlist_for_each(pos, head) { + vxi = hlist_entry(pos, struct vx_info, vx_hlist); + + if (vxi->vx_id == xid) + goto found; + } + vxi = NULL; +found: + vxdprintk(VXD_CBIT(xid, 0), + "__lookup_vx_info(#%u): %p[#%u]", + xid, vxi, vxi ? vxi->vx_id : 0); + vxh_lookup_vx_info(vxi, xid); + return vxi; +} + + +/* __create_vx_info() + + * create the requested context + * get(), claim() and hash it */ + +static struct vx_info *__create_vx_info(int id) +{ + struct vx_info *new, *vxi = NULL; + + vxdprintk(VXD_CBIT(xid, 1), "create_vx_info(%d)*", id); + + if (!(new = __alloc_vx_info(id))) + return ERR_PTR(-ENOMEM); + + /* required to make dynamic xids unique */ + spin_lock(&vx_info_hash_lock); + + /* static context requested */ + if ((vxi = __lookup_vx_info(id))) { + vxdprintk(VXD_CBIT(xid, 0), + "create_vx_info(%d) = %p (already there)", id, vxi); + if (vx_info_flags(vxi, VXF_STATE_SETUP, 0)) + vxi = ERR_PTR(-EBUSY); + else + vxi = ERR_PTR(-EEXIST); + goto out_unlock; + } + /* new context */ + vxdprintk(VXD_CBIT(xid, 0), + "create_vx_info(%d) = %p (new)", id, new); + claim_vx_info(new, NULL); + __hash_vx_info(get_vx_info(new)); + vxi = new, new = NULL; + +out_unlock: + spin_unlock(&vx_info_hash_lock); + vxh_create_vx_info(IS_ERR(vxi) ? NULL : vxi, id); + if (new) + __dealloc_vx_info(new); + return vxi; +} + + +/* exported stuff */ + + +void unhash_vx_info(struct vx_info *vxi) +{ + __shutdown_vx_info(vxi); + spin_lock(&vx_info_hash_lock); + __unhash_vx_info(vxi); + spin_unlock(&vx_info_hash_lock); + __wakeup_vx_info(vxi); +} + + +/* lookup_vx_info() + + * search for a vx_info and get() it + * negative id means current */ + +struct vx_info *lookup_vx_info(int id) +{ + struct vx_info *vxi = NULL; + + if (id < 0) { + vxi = get_vx_info(current->vx_info); + } else if (id > 1) { + spin_lock(&vx_info_hash_lock); + vxi = get_vx_info(__lookup_vx_info(id)); + spin_unlock(&vx_info_hash_lock); + } + return vxi; +} + +/* xid_is_hashed() + + * verify that xid is still hashed */ + +int xid_is_hashed(xid_t xid) +{ + int hashed; + + spin_lock(&vx_info_hash_lock); + hashed = (__lookup_vx_info(xid) != NULL); + spin_unlock(&vx_info_hash_lock); + return hashed; +} + +#ifdef CONFIG_PROC_FS + +/* get_xid_list() + + * get a subset of hashed xids for proc + * assumes size is at least one */ + +int get_xid_list(int index, unsigned int *xids, int size) +{ + int hindex, nr_xids = 0; + + /* only show current and children */ + if (!vx_check(0, VS_ADMIN | VS_WATCH)) { + if (index > 0) + return 0; + xids[nr_xids] = vx_current_xid(); + return 1; + } + + for (hindex = 0; hindex < VX_HASH_SIZE; hindex++) { + struct hlist_head *head = &vx_info_hash[hindex]; + struct hlist_node *pos; + + spin_lock(&vx_info_hash_lock); + hlist_for_each(pos, head) { + struct vx_info *vxi; + + if (--index > 0) + continue; + + vxi = hlist_entry(pos, struct vx_info, vx_hlist); + xids[nr_xids] = vxi->vx_id; + if (++nr_xids >= size) { + spin_unlock(&vx_info_hash_lock); + goto out; + } + } + /* keep the lock time short */ + spin_unlock(&vx_info_hash_lock); + } +out: + return nr_xids; +} +#endif + +#ifdef CONFIG_VSERVER_DEBUG + +void dump_vx_info_inactive(int level) +{ + struct hlist_node *entry, *next; + + hlist_for_each_safe(entry, next, &vx_info_inactive) { + struct vx_info *vxi = + list_entry(entry, struct vx_info, vx_hlist); + + dump_vx_info(vxi, level); + } +} + +#endif + +#if 0 +int vx_migrate_user(struct task_struct *p, struct vx_info *vxi) +{ + struct user_struct *new_user, *old_user; + + if (!p || !vxi) + BUG(); + + if (vx_info_flags(vxi, VXF_INFO_PRIVATE, 0)) + return -EACCES; + + new_user = alloc_uid(vxi->vx_id, p->uid); + if (!new_user) + return -ENOMEM; + + old_user = p->user; + if (new_user != old_user) { + atomic_inc(&new_user->processes); + atomic_dec(&old_user->processes); + p->user = new_user; + } + free_uid(old_user); + return 0; +} +#endif + +#if 0 +void vx_mask_cap_bset(struct vx_info *vxi, struct task_struct *p) +{ + // p->cap_effective &= vxi->vx_cap_bset; + p->cap_effective = + cap_intersect(p->cap_effective, vxi->cap_bset); + // p->cap_inheritable &= vxi->vx_cap_bset; + p->cap_inheritable = + cap_intersect(p->cap_inheritable, vxi->cap_bset); + // p->cap_permitted &= vxi->vx_cap_bset; + p->cap_permitted = + cap_intersect(p->cap_permitted, vxi->cap_bset); +} +#endif + + +#include +#include + +static int vx_openfd_task(struct task_struct *tsk) +{ + struct files_struct *files = tsk->files; + struct fdtable *fdt; + const unsigned long *bptr; + int count, total; + + /* no rcu_read_lock() because of spin_lock() */ + spin_lock(&files->file_lock); + fdt = files_fdtable(files); + bptr = fdt->open_fds->fds_bits; + count = fdt->max_fds / (sizeof(unsigned long) * 8); + for (total = 0; count > 0; count--) { + if (*bptr) + total += hweight_long(*bptr); + bptr++; + } + spin_unlock(&files->file_lock); + return total; +} + + +/* for *space compatibility */ + +asmlinkage long sys_unshare(unsigned long); + +/* + * migrate task to new context + * gets vxi, puts old_vxi on change + * optionally unshares namespaces (hack) + */ + +int vx_migrate_task(struct task_struct *p, struct vx_info *vxi, int unshare) +{ + struct vx_info *old_vxi; + int ret = 0; + + if (!p || !vxi) + BUG(); + + vxdprintk(VXD_CBIT(xid, 5), + "vx_migrate_task(%p,%p[#%d.%d])", p, vxi, + vxi->vx_id, atomic_read(&vxi->vx_usecnt)); + + if (vx_info_flags(vxi, VXF_INFO_PRIVATE, 0) && + !vx_info_flags(vxi, VXF_STATE_SETUP, 0)) + return -EACCES; + + if (vx_info_state(vxi, VXS_SHUTDOWN)) + return -EFAULT; + + old_vxi = task_get_vx_info(p); + if (old_vxi == vxi) + goto out; + +// if (!(ret = vx_migrate_user(p, vxi))) { + { + int openfd; + + task_lock(p); + openfd = vx_openfd_task(p); + + if (old_vxi) { + atomic_dec(&old_vxi->cvirt.nr_threads); + atomic_dec(&old_vxi->cvirt.nr_running); + __rlim_dec(&old_vxi->limit, RLIMIT_NPROC); + /* FIXME: what about the struct files here? */ + __rlim_sub(&old_vxi->limit, VLIMIT_OPENFD, openfd); + /* account for the executable */ + __rlim_dec(&old_vxi->limit, VLIMIT_DENTRY); + } + atomic_inc(&vxi->cvirt.nr_threads); + atomic_inc(&vxi->cvirt.nr_running); + __rlim_inc(&vxi->limit, RLIMIT_NPROC); + /* FIXME: what about the struct files here? */ + __rlim_add(&vxi->limit, VLIMIT_OPENFD, openfd); + /* account for the executable */ + __rlim_inc(&vxi->limit, VLIMIT_DENTRY); + + if (old_vxi) { + release_vx_info(old_vxi, p); + clr_vx_info(&p->vx_info); + } + claim_vx_info(vxi, p); + set_vx_info(&p->vx_info, vxi); + p->xid = vxi->vx_id; + + vxdprintk(VXD_CBIT(xid, 5), + "moved task %p into vxi:%p[#%d]", + p, vxi, vxi->vx_id); + + // vx_mask_cap_bset(vxi, p); + task_unlock(p); + + /* hack for *spaces to provide compatibility */ + if (unshare) { + struct nsproxy *old_nsp, *new_nsp; + + ret = unshare_nsproxy_namespaces( + CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER, + &new_nsp, NULL); + if (ret) + goto out; + + old_nsp = xchg(&p->nsproxy, new_nsp); + vx_set_space(vxi, + CLONE_NEWUTS | CLONE_NEWIPC | CLONE_NEWUSER, 0); + put_nsproxy(old_nsp); + } + } +out: + put_vx_info(old_vxi); + return ret; +} + +int vx_set_reaper(struct vx_info *vxi, struct task_struct *p) +{ + struct task_struct *old_reaper; + + if (!vxi) + return -EINVAL; + + vxdprintk(VXD_CBIT(xid, 6), + "vx_set_reaper(%p[#%d],%p[#%d,%d])", + vxi, vxi->vx_id, p, p->xid, p->pid); + + old_reaper = vxi->vx_reaper; + if (old_reaper == p) + return 0; + + /* set new child reaper */ + get_task_struct(p); + vxi->vx_reaper = p; + put_task_struct(old_reaper); + return 0; +} + +int vx_set_init(struct vx_info *vxi, struct task_struct *p) +{ + if (!vxi) + return -EINVAL; + + vxdprintk(VXD_CBIT(xid, 6), + "vx_set_init(%p[#%d],%p[#%d,%d,%d])", + vxi, vxi->vx_id, p, p->xid, p->pid, p->tgid); + + vxi->vx_flags &= ~VXF_STATE_INIT; + vxi->vx_initpid = p->tgid; + return 0; +} + +void vx_exit_init(struct vx_info *vxi, struct task_struct *p, int code) +{ + vxdprintk(VXD_CBIT(xid, 6), + "vx_exit_init(%p[#%d],%p[#%d,%d,%d])", + vxi, vxi->vx_id, p, p->xid, p->pid, p->tgid); + + vxi->exit_code = code; + vxi->vx_initpid = 0; +} + + +void vx_set_persistent(struct vx_info *vxi) +{ + vxdprintk(VXD_CBIT(xid, 6), + "vx_set_persistent(%p[#%d])", vxi, vxi->vx_id); + + get_vx_info(vxi); + claim_vx_info(vxi, NULL); +} + +void vx_clear_persistent(struct vx_info *vxi) +{ + vxdprintk(VXD_CBIT(xid, 6), + "vx_clear_persistent(%p[#%d])", vxi, vxi->vx_id); + + release_vx_info(vxi, NULL); + put_vx_info(vxi); +} + +void vx_update_persistent(struct vx_info *vxi) +{ + if (vx_info_flags(vxi, VXF_PERSISTENT, 0)) + vx_set_persistent(vxi); + else + vx_clear_persistent(vxi); +} + + +/* task must be current or locked */ + +void exit_vx_info(struct task_struct *p, int code) +{ + struct vx_info *vxi = p->vx_info; + + if (vxi) { + atomic_dec(&vxi->cvirt.nr_threads); + vx_nproc_dec(p); + + vxi->exit_code = code; + release_vx_info(vxi, p); + } +} + +void exit_vx_info_early(struct task_struct *p, int code) +{ + struct vx_info *vxi = p->vx_info; + + if (vxi) { + if (vxi->vx_initpid == p->tgid) + vx_exit_init(vxi, p, code); + if (vxi->vx_reaper == p) + vx_set_reaper(vxi, init_pid_ns.child_reaper); + } +} + + +/* vserver syscall commands below here */ + +/* taks xid and vx_info functions */ + +#include + + +int vc_task_xid(uint32_t id) +{ + xid_t xid; + + if (id) { + struct task_struct *tsk; + + read_lock(&tasklist_lock); + tsk = find_task_by_real_pid(id); + xid = (tsk) ? tsk->xid : -ESRCH; + read_unlock(&tasklist_lock); + } else + xid = vx_current_xid(); + return xid; +} + + +int vc_vx_info(struct vx_info *vxi, void __user *data) +{ + struct vcmd_vx_info_v0 vc_data; + + vc_data.xid = vxi->vx_id; + vc_data.initpid = vxi->vx_initpid; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +int vc_ctx_stat(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_stat_v0 vc_data; + + vc_data.usecnt = atomic_read(&vxi->vx_usecnt); + vc_data.tasks = atomic_read(&vxi->vx_tasks); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +/* context functions */ + +int vc_ctx_create(uint32_t xid, void __user *data) +{ + struct vcmd_ctx_create vc_data = { .flagword = VXF_INIT_SET }; + struct vx_info *new_vxi; + int ret; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + if ((xid > MAX_S_CONTEXT) || (xid < 2)) + return -EINVAL; + + new_vxi = __create_vx_info(xid); + if (IS_ERR(new_vxi)) + return PTR_ERR(new_vxi); + + /* initial flags */ + new_vxi->vx_flags = vc_data.flagword; + + ret = -ENOEXEC; + if (vs_state_change(new_vxi, VSC_STARTUP)) + goto out; + + ret = vx_migrate_task(current, new_vxi, (!data)); + if (ret) + goto out; + + /* return context id on success */ + ret = new_vxi->vx_id; + + /* get a reference for persistent contexts */ + if ((vc_data.flagword & VXF_PERSISTENT)) + vx_set_persistent(new_vxi); +out: + release_vx_info(new_vxi, NULL); + put_vx_info(new_vxi); + return ret; +} + + +int vc_ctx_migrate(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_migrate vc_data = { .flagword = 0 }; + int ret; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = vx_migrate_task(current, vxi, 0); + if (ret) + return ret; + if (vc_data.flagword & VXM_SET_INIT) + ret = vx_set_init(vxi, current); + if (ret) + return ret; + if (vc_data.flagword & VXM_SET_REAPER) + ret = vx_set_reaper(vxi, current); + return ret; +} + + +int vc_get_cflags(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_flags_v0 vc_data; + + vc_data.flagword = vxi->vx_flags; + + /* special STATE flag handling */ + vc_data.mask = vs_mask_flags(~0ULL, vxi->vx_flags, VXF_ONE_TIME); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_cflags(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_flags_v0 vc_data; + uint64_t mask, trigger; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + /* special STATE flag handling */ + mask = vs_mask_mask(vc_data.mask, vxi->vx_flags, VXF_ONE_TIME); + trigger = (mask & vxi->vx_flags) ^ (mask & vc_data.flagword); + + if (vxi == current->vx_info) { + /* if (trigger & VXF_STATE_SETUP) + vx_mask_cap_bset(vxi, current); */ + if (trigger & VXF_STATE_INIT) { + int ret; + + ret = vx_set_init(vxi, current); + if (ret) + return ret; + ret = vx_set_reaper(vxi, current); + if (ret) + return ret; + } + } + + vxi->vx_flags = vs_mask_flags(vxi->vx_flags, + vc_data.flagword, mask); + if (trigger & VXF_PERSISTENT) + vx_update_persistent(vxi); + + return 0; +} + + +static inline uint64_t caps_from_cap_t(kernel_cap_t c) +{ + uint64_t v = c.cap[0] | ((uint64_t)c.cap[1] << 32); + + // printk("caps_from_cap_t(%08x:%08x) = %016llx\n", c.cap[1], c.cap[0], v); + return v; +} + +static inline kernel_cap_t cap_t_from_caps(uint64_t v) +{ + kernel_cap_t c = __cap_empty_set; + + c.cap[0] = v & 0xFFFFFFFF; + c.cap[1] = (v >> 32) & 0xFFFFFFFF; + + // printk("cap_t_from_caps(%016llx) = %08x:%08x\n", v, c.cap[1], c.cap[0]); + return c; +} + + +static int do_get_caps(struct vx_info *vxi, uint64_t *bcaps, uint64_t *ccaps) +{ + if (bcaps) + *bcaps = caps_from_cap_t(vxi->vx_bcaps); + if (ccaps) + *ccaps = vxi->vx_ccaps; + + return 0; +} + +int vc_get_ccaps(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_caps_v1 vc_data; + int ret; + + ret = do_get_caps(vxi, NULL, &vc_data.ccaps); + if (ret) + return ret; + vc_data.cmask = ~0ULL; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +static int do_set_caps(struct vx_info *vxi, + uint64_t bcaps, uint64_t bmask, uint64_t ccaps, uint64_t cmask) +{ + uint64_t bcold = caps_from_cap_t(vxi->vx_bcaps); + +#if 0 + printk("do_set_caps(%16llx, %16llx, %16llx, %16llx)\n", + bcaps, bmask, ccaps, cmask); +#endif + vxi->vx_bcaps = cap_t_from_caps( + vs_mask_flags(bcold, bcaps, bmask)); + vxi->vx_ccaps = vs_mask_flags(vxi->vx_ccaps, ccaps, cmask); + + return 0; +} + +int vc_set_ccaps(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_caps_v1 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_caps(vxi, 0, 0, vc_data.ccaps, vc_data.cmask); +} + +int vc_get_bcaps(struct vx_info *vxi, void __user *data) +{ + struct vcmd_bcaps vc_data; + int ret; + + ret = do_get_caps(vxi, &vc_data.bcaps, NULL); + if (ret) + return ret; + vc_data.bmask = ~0ULL; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_bcaps(struct vx_info *vxi, void __user *data) +{ + struct vcmd_bcaps vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_caps(vxi, vc_data.bcaps, vc_data.bmask, 0, 0); +} + + +int vc_get_badness(struct vx_info *vxi, void __user *data) +{ + struct vcmd_badness_v0 vc_data; + + vc_data.bias = vxi->vx_badness_bias; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_badness(struct vx_info *vxi, void __user *data) +{ + struct vcmd_badness_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + vxi->vx_badness_bias = vc_data.bias; + return 0; +} + +#include + +EXPORT_SYMBOL_GPL(free_vx_info); + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/cvirt.c linux-2.6.27.15-g-v/kernel/vserver/cvirt.c --- linux-2.6.27.15/kernel/vserver/cvirt.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/cvirt.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,300 @@ +/* + * linux/kernel/vserver/cvirt.c + * + * Virtual Server: Context Virtualization + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 broken out from limit.c + * V0.02 added utsname stuff + * V0.03 changed vcmds to vxi arg + * + */ + +#include +#include +#include +#include +#include + +#include + + +void vx_vsi_uptime(struct timespec *uptime, struct timespec *idle) +{ + struct vx_info *vxi = current->vx_info; + + set_normalized_timespec(uptime, + uptime->tv_sec - vxi->cvirt.bias_uptime.tv_sec, + uptime->tv_nsec - vxi->cvirt.bias_uptime.tv_nsec); + if (!idle) + return; + set_normalized_timespec(idle, + idle->tv_sec - vxi->cvirt.bias_idle.tv_sec, + idle->tv_nsec - vxi->cvirt.bias_idle.tv_nsec); + return; +} + +uint64_t vx_idle_jiffies(void) +{ + return init_task.utime + init_task.stime; +} + + + +static inline uint32_t __update_loadavg(uint32_t load, + int wsize, int delta, int n) +{ + unsigned long long calc, prev; + + /* just set it to n */ + if (unlikely(delta >= wsize)) + return (n << FSHIFT); + + calc = delta * n; + calc <<= FSHIFT; + prev = (wsize - delta); + prev *= load; + calc += prev; + do_div(calc, wsize); + return calc; +} + + +void vx_update_load(struct vx_info *vxi) +{ + uint32_t now, last, delta; + unsigned int nr_running, nr_uninterruptible; + unsigned int total; + unsigned long flags; + + spin_lock_irqsave(&vxi->cvirt.load_lock, flags); + + now = jiffies; + last = vxi->cvirt.load_last; + delta = now - last; + + if (delta < 5*HZ) + goto out; + + nr_running = atomic_read(&vxi->cvirt.nr_running); + nr_uninterruptible = atomic_read(&vxi->cvirt.nr_uninterruptible); + total = nr_running + nr_uninterruptible; + + vxi->cvirt.load[0] = __update_loadavg(vxi->cvirt.load[0], + 60*HZ, delta, total); + vxi->cvirt.load[1] = __update_loadavg(vxi->cvirt.load[1], + 5*60*HZ, delta, total); + vxi->cvirt.load[2] = __update_loadavg(vxi->cvirt.load[2], + 15*60*HZ, delta, total); + + vxi->cvirt.load_last = now; +out: + atomic_inc(&vxi->cvirt.load_updates); + spin_unlock_irqrestore(&vxi->cvirt.load_lock, flags); +} + + +/* + * Commands to do_syslog: + * + * 0 -- Close the log. Currently a NOP. + * 1 -- Open the log. Currently a NOP. + * 2 -- Read from the log. + * 3 -- Read all messages remaining in the ring buffer. + * 4 -- Read and clear all messages remaining in the ring buffer + * 5 -- Clear ring buffer. + * 6 -- Disable printk's to console + * 7 -- Enable printk's to console + * 8 -- Set level of messages printed to console + * 9 -- Return number of unread characters in the log buffer + * 10 -- Return size of the log buffer + */ +int vx_do_syslog(int type, char __user *buf, int len) +{ + int error = 0; + int do_clear = 0; + struct vx_info *vxi = current->vx_info; + struct _vx_syslog *log; + + if (!vxi) + return -EINVAL; + log = &vxi->cvirt.syslog; + + switch (type) { + case 0: /* Close log */ + case 1: /* Open log */ + break; + case 2: /* Read from log */ + error = wait_event_interruptible(log->log_wait, + (log->log_start - log->log_end)); + if (error) + break; + spin_lock_irq(&log->logbuf_lock); + spin_unlock_irq(&log->logbuf_lock); + break; + case 4: /* Read/clear last kernel messages */ + do_clear = 1; + /* fall through */ + case 3: /* Read last kernel messages */ + return 0; + + case 5: /* Clear ring buffer */ + return 0; + + case 6: /* Disable logging to console */ + case 7: /* Enable logging to console */ + case 8: /* Set level of messages printed to console */ + break; + + case 9: /* Number of chars in the log buffer */ + return 0; + case 10: /* Size of the log buffer */ + return 0; + default: + error = -EINVAL; + break; + } + return error; +} + + +/* virtual host info names */ + +static char *vx_vhi_name(struct vx_info *vxi, int id) +{ + struct nsproxy *nsproxy; + struct uts_namespace *uts; + + if (id == VHIN_CONTEXT) + return vxi->vx_name; + + nsproxy = vxi->vx_nsproxy[0]; + if (!nsproxy) + return NULL; + + uts = nsproxy->uts_ns; + if (!uts) + return NULL; + + switch (id) { + case VHIN_SYSNAME: + return uts->name.sysname; + case VHIN_NODENAME: + return uts->name.nodename; + case VHIN_RELEASE: + return uts->name.release; + case VHIN_VERSION: + return uts->name.version; + case VHIN_MACHINE: + return uts->name.machine; + case VHIN_DOMAINNAME: + return uts->name.domainname; + default: + return NULL; + } + return NULL; +} + +int vc_set_vhi_name(struct vx_info *vxi, void __user *data) +{ + struct vcmd_vhi_name_v0 vc_data; + char *name; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + name = vx_vhi_name(vxi, vc_data.field); + if (!name) + return -EINVAL; + + memcpy(name, vc_data.name, 65); + return 0; +} + +int vc_get_vhi_name(struct vx_info *vxi, void __user *data) +{ + struct vcmd_vhi_name_v0 vc_data; + char *name; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + name = vx_vhi_name(vxi, vc_data.field); + if (!name) + return -EINVAL; + + memcpy(vc_data.name, name, 65); + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +int vc_virt_stat(struct vx_info *vxi, void __user *data) +{ + struct vcmd_virt_stat_v0 vc_data; + struct _vx_cvirt *cvirt = &vxi->cvirt; + struct timespec uptime; + + do_posix_clock_monotonic_gettime(&uptime); + set_normalized_timespec(&uptime, + uptime.tv_sec - cvirt->bias_uptime.tv_sec, + uptime.tv_nsec - cvirt->bias_uptime.tv_nsec); + + vc_data.offset = timeval_to_ns(&cvirt->bias_tv); + vc_data.uptime = timespec_to_ns(&uptime); + vc_data.nr_threads = atomic_read(&cvirt->nr_threads); + vc_data.nr_running = atomic_read(&cvirt->nr_running); + vc_data.nr_uninterruptible = atomic_read(&cvirt->nr_uninterruptible); + vc_data.nr_onhold = atomic_read(&cvirt->nr_onhold); + vc_data.nr_forks = atomic_read(&cvirt->total_forks); + vc_data.load[0] = cvirt->load[0]; + vc_data.load[1] = cvirt->load[1]; + vc_data.load[2] = cvirt->load[2]; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +#ifdef CONFIG_VSERVER_VTIME + +/* virtualized time base */ + +void vx_gettimeofday(struct timeval *tv) +{ + do_gettimeofday(tv); + if (!vx_flags(VXF_VIRT_TIME, 0)) + return; + + tv->tv_sec += current->vx_info->cvirt.bias_tv.tv_sec; + tv->tv_usec += current->vx_info->cvirt.bias_tv.tv_usec; + + if (tv->tv_usec >= USEC_PER_SEC) { + tv->tv_sec++; + tv->tv_usec -= USEC_PER_SEC; + } else if (tv->tv_usec < 0) { + tv->tv_sec--; + tv->tv_usec += USEC_PER_SEC; + } +} + +int vx_settimeofday(struct timespec *ts) +{ + struct timeval tv; + + if (!vx_flags(VXF_VIRT_TIME, 0)) + return do_settimeofday(ts); + + do_gettimeofday(&tv); + current->vx_info->cvirt.bias_tv.tv_sec = + ts->tv_sec - tv.tv_sec; + current->vx_info->cvirt.bias_tv.tv_usec = + (ts->tv_nsec/NSEC_PER_USEC) - tv.tv_usec; + return 0; +} + +#endif + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/cvirt_init.h linux-2.6.27.15-g-v/kernel/vserver/cvirt_init.h --- linux-2.6.27.15/kernel/vserver/cvirt_init.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/cvirt_init.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,69 @@ + + +extern uint64_t vx_idle_jiffies(void); + +static inline void vx_info_init_cvirt(struct _vx_cvirt *cvirt) +{ + uint64_t idle_jiffies = vx_idle_jiffies(); + uint64_t nsuptime; + + do_posix_clock_monotonic_gettime(&cvirt->bias_uptime); + nsuptime = (unsigned long long)cvirt->bias_uptime.tv_sec + * NSEC_PER_SEC + cvirt->bias_uptime.tv_nsec; + cvirt->bias_clock = nsec_to_clock_t(nsuptime); + cvirt->bias_tv.tv_sec = 0; + cvirt->bias_tv.tv_usec = 0; + + jiffies_to_timespec(idle_jiffies, &cvirt->bias_idle); + atomic_set(&cvirt->nr_threads, 0); + atomic_set(&cvirt->nr_running, 0); + atomic_set(&cvirt->nr_uninterruptible, 0); + atomic_set(&cvirt->nr_onhold, 0); + + spin_lock_init(&cvirt->load_lock); + cvirt->load_last = jiffies; + atomic_set(&cvirt->load_updates, 0); + cvirt->load[0] = 0; + cvirt->load[1] = 0; + cvirt->load[2] = 0; + atomic_set(&cvirt->total_forks, 0); + + spin_lock_init(&cvirt->syslog.logbuf_lock); + init_waitqueue_head(&cvirt->syslog.log_wait); + cvirt->syslog.log_start = 0; + cvirt->syslog.log_end = 0; + cvirt->syslog.con_start = 0; + cvirt->syslog.logged_chars = 0; +} + +static inline +void vx_info_init_cvirt_pc(struct _vx_cvirt_pc *cvirt_pc, int cpu) +{ + // cvirt_pc->cpustat = { 0 }; +} + +static inline void vx_info_exit_cvirt(struct _vx_cvirt *cvirt) +{ + int value; + + vxwprintk_xid((value = atomic_read(&cvirt->nr_threads)), + "!!! cvirt: %p[nr_threads] = %d on exit.", + cvirt, value); + vxwprintk_xid((value = atomic_read(&cvirt->nr_running)), + "!!! cvirt: %p[nr_running] = %d on exit.", + cvirt, value); + vxwprintk_xid((value = atomic_read(&cvirt->nr_uninterruptible)), + "!!! cvirt: %p[nr_uninterruptible] = %d on exit.", + cvirt, value); + vxwprintk_xid((value = atomic_read(&cvirt->nr_onhold)), + "!!! cvirt: %p[nr_onhold] = %d on exit.", + cvirt, value); + return; +} + +static inline +void vx_info_exit_cvirt_pc(struct _vx_cvirt_pc *cvirt_pc, int cpu) +{ + return; +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/cvirt_proc.h linux-2.6.27.15-g-v/kernel/vserver/cvirt_proc.h --- linux-2.6.27.15/kernel/vserver/cvirt_proc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/cvirt_proc.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,135 @@ +#ifndef _VX_CVIRT_PROC_H +#define _VX_CVIRT_PROC_H + +#include +#include +#include +#include +#include + + +static inline +int vx_info_proc_nsproxy(struct nsproxy *nsproxy, char *buffer) +{ + struct mnt_namespace *ns; + struct uts_namespace *uts; + struct ipc_namespace *ipc; + struct path path; + char *pstr, *root; + int length = 0; + + if (!nsproxy) + goto out; + + length += sprintf(buffer + length, + "NSProxy:\t%p [%p,%p,%p]\n", + nsproxy, nsproxy->mnt_ns, + nsproxy->uts_ns, nsproxy->ipc_ns); + + ns = nsproxy->mnt_ns; + if (!ns) + goto skip_ns; + + pstr = kmalloc(PATH_MAX, GFP_KERNEL); + if (!pstr) + goto skip_ns; + + path.mnt = ns->root; + path.dentry = ns->root->mnt_root; + root = d_path(&path, pstr, PATH_MAX - 2); + length += sprintf(buffer + length, + "Namespace:\t%p [#%u]\n" + "RootPath:\t%s\n", + ns, atomic_read(&ns->count), + root); + kfree(pstr); +skip_ns: + + uts = nsproxy->uts_ns; + if (!uts) + goto skip_uts; + + length += sprintf(buffer + length, + "SysName:\t%.*s\n" + "NodeName:\t%.*s\n" + "Release:\t%.*s\n" + "Version:\t%.*s\n" + "Machine:\t%.*s\n" + "DomainName:\t%.*s\n", + __NEW_UTS_LEN, uts->name.sysname, + __NEW_UTS_LEN, uts->name.nodename, + __NEW_UTS_LEN, uts->name.release, + __NEW_UTS_LEN, uts->name.version, + __NEW_UTS_LEN, uts->name.machine, + __NEW_UTS_LEN, uts->name.domainname); +skip_uts: + + ipc = nsproxy->ipc_ns; + if (!ipc) + goto skip_ipc; + + length += sprintf(buffer + length, + "SEMS:\t\t%d %d %d %d %d\n" + "MSG:\t\t%d %d %d\n" + "SHM:\t\t%lu %lu %d %d\n", + ipc->sem_ctls[0], ipc->sem_ctls[1], + ipc->sem_ctls[2], ipc->sem_ctls[3], + ipc->used_sems, + ipc->msg_ctlmax, ipc->msg_ctlmnb, ipc->msg_ctlmni, + (unsigned long)ipc->shm_ctlmax, + (unsigned long)ipc->shm_ctlall, + ipc->shm_ctlmni, ipc->shm_tot); +skip_ipc: +out: + return length; +} + + +#include + +#define LOAD_INT(x) ((x) >> FSHIFT) +#define LOAD_FRAC(x) LOAD_INT(((x) & (FIXED_1 - 1)) * 100) + +static inline +int vx_info_proc_cvirt(struct _vx_cvirt *cvirt, char *buffer) +{ + int length = 0; + int a, b, c; + + length += sprintf(buffer + length, + "BiasUptime:\t%lu.%02lu\n", + (unsigned long)cvirt->bias_uptime.tv_sec, + (cvirt->bias_uptime.tv_nsec / (NSEC_PER_SEC / 100))); + + a = cvirt->load[0] + (FIXED_1 / 200); + b = cvirt->load[1] + (FIXED_1 / 200); + c = cvirt->load[2] + (FIXED_1 / 200); + length += sprintf(buffer + length, + "nr_threads:\t%d\n" + "nr_running:\t%d\n" + "nr_unintr:\t%d\n" + "nr_onhold:\t%d\n" + "load_updates:\t%d\n" + "loadavg:\t%d.%02d %d.%02d %d.%02d\n" + "total_forks:\t%d\n", + atomic_read(&cvirt->nr_threads), + atomic_read(&cvirt->nr_running), + atomic_read(&cvirt->nr_uninterruptible), + atomic_read(&cvirt->nr_onhold), + atomic_read(&cvirt->load_updates), + LOAD_INT(a), LOAD_FRAC(a), + LOAD_INT(b), LOAD_FRAC(b), + LOAD_INT(c), LOAD_FRAC(c), + atomic_read(&cvirt->total_forks)); + return length; +} + +static inline +int vx_info_proc_cvirt_pc(struct _vx_cvirt_pc *cvirt_pc, + char *buffer, int cpu) +{ + int length = 0; + return length; +} + +#endif /* _VX_CVIRT_PROC_H */ diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/debug.c linux-2.6.27.15-g-v/kernel/vserver/debug.c --- linux-2.6.27.15/kernel/vserver/debug.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/debug.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,32 @@ +/* + * kernel/vserver/debug.c + * + * Copyright (C) 2005-2007 Herbert Pötzl + * + * V0.01 vx_info dump support + * + */ + +#include + +#include + + +void dump_vx_info(struct vx_info *vxi, int level) +{ + printk("vx_info %p[#%d, %d.%d, %4x]\n", vxi, vxi->vx_id, + atomic_read(&vxi->vx_usecnt), + atomic_read(&vxi->vx_tasks), + vxi->vx_state); + if (level > 0) { + __dump_vx_limit(&vxi->limit); + __dump_vx_sched(&vxi->sched); + __dump_vx_cvirt(&vxi->cvirt); + __dump_vx_cacct(&vxi->cacct); + } + printk("---\n"); +} + + +EXPORT_SYMBOL_GPL(dump_vx_info); + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/device.c linux-2.6.27.15-g-v/kernel/vserver/device.c --- linux-2.6.27.15/kernel/vserver/device.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/device.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,443 @@ +/* + * linux/kernel/vserver/device.c + * + * Linux-VServer: Device Support + * + * Copyright (C) 2006 Herbert Pötzl + * Copyright (C) 2007 Daniel Hokka Zakrisson + * + * V0.01 device mapping basics + * V0.02 added defaults + * + */ + +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include + + +#define DMAP_HASH_BITS 4 + + +struct vs_mapping { + union { + struct hlist_node hlist; + struct list_head list; + } u; +#define dm_hlist u.hlist +#define dm_list u.list + xid_t xid; + dev_t device; + struct vx_dmap_target target; +}; + + +static struct hlist_head dmap_main_hash[1 << DMAP_HASH_BITS]; + +static spinlock_t dmap_main_hash_lock = SPIN_LOCK_UNLOCKED; + +static struct vx_dmap_target dmap_defaults[2] = { + { .flags = DATTR_OPEN }, + { .flags = DATTR_OPEN }, +}; + + +struct kmem_cache *dmap_cachep __read_mostly; + +int __init dmap_cache_init(void) +{ + dmap_cachep = kmem_cache_create("dmap_cache", + sizeof(struct vs_mapping), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + return 0; +} + +__initcall(dmap_cache_init); + + +static inline unsigned int __hashval(dev_t dev, int bits) +{ + return hash_long((unsigned long)dev, bits); +} + + +/* __hash_mapping() + * add the mapping to the hash table + */ +static inline void __hash_mapping(struct vx_info *vxi, struct vs_mapping *vdm) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + struct hlist_head *head, *hash = dmap_main_hash; + int device = vdm->device; + + spin_lock(hash_lock); + vxdprintk(VXD_CBIT(misc, 8), "__hash_mapping: %p[#%d] %08x:%08x", + vxi, vxi ? vxi->vx_id : 0, device, vdm->target.target); + + head = &hash[__hashval(device, DMAP_HASH_BITS)]; + hlist_add_head(&vdm->dm_hlist, head); + spin_unlock(hash_lock); +} + + +static inline int __mode_to_default(umode_t mode) +{ + switch (mode) { + case S_IFBLK: + return 0; + case S_IFCHR: + return 1; + default: + BUG(); + } +} + + +/* __set_default() + * set a default + */ +static inline void __set_default(struct vx_info *vxi, umode_t mode, + struct vx_dmap_target *vdmt) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + spin_lock(hash_lock); + + if (vxi) + vxi->dmap.targets[__mode_to_default(mode)] = *vdmt; + else + dmap_defaults[__mode_to_default(mode)] = *vdmt; + + + spin_unlock(hash_lock); + + vxdprintk(VXD_CBIT(misc, 8), "__set_default: %p[#%u] %08x %04x", + vxi, vxi ? vxi->vx_id : 0, vdmt->target, vdmt->flags); +} + + +/* __remove_default() + * remove a default + */ +static inline int __remove_default(struct vx_info *vxi, umode_t mode) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + spin_lock(hash_lock); + + if (vxi) + vxi->dmap.targets[__mode_to_default(mode)].flags = 0; + else /* remove == reset */ + dmap_defaults[__mode_to_default(mode)].flags = DATTR_OPEN | mode; + + spin_unlock(hash_lock); + return 0; +} + + +/* __find_mapping() + * find a mapping in the hash table + * + * caller must hold hash_lock + */ +static inline int __find_mapping(xid_t xid, dev_t device, umode_t mode, + struct vs_mapping **local, struct vs_mapping **global) +{ + struct hlist_head *hash = dmap_main_hash; + struct hlist_head *head = &hash[__hashval(device, DMAP_HASH_BITS)]; + struct hlist_node *pos; + struct vs_mapping *vdm; + + *local = NULL; + if (global) + *global = NULL; + + hlist_for_each(pos, head) { + vdm = hlist_entry(pos, struct vs_mapping, dm_hlist); + + if ((vdm->device == device) && + !((vdm->target.flags ^ mode) & S_IFMT)) { + if (vdm->xid == xid) { + *local = vdm; + return 1; + } else if (global && vdm->xid == 0) + *global = vdm; + } + } + + if (global && *global) + return 0; + else + return -ENOENT; +} + + +/* __lookup_mapping() + * find a mapping and store the result in target and flags + */ +static inline int __lookup_mapping(struct vx_info *vxi, + dev_t device, dev_t *target, int *flags, umode_t mode) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + struct vs_mapping *vdm, *global; + struct vx_dmap_target *vdmt; + int ret = 0; + xid_t xid = vxi->vx_id; + int index; + + spin_lock(hash_lock); + if (__find_mapping(xid, device, mode, &vdm, &global) > 0) { + ret = 1; + vdmt = &vdm->target; + goto found; + } + + index = __mode_to_default(mode); + if (vxi && vxi->dmap.targets[index].flags) { + ret = 2; + vdmt = &vxi->dmap.targets[index]; + } else if (global) { + ret = 3; + vdmt = &global->target; + goto found; + } else { + ret = 4; + vdmt = &dmap_defaults[index]; + } + +found: + if (target && (vdmt->flags & DATTR_REMAP)) + *target = vdmt->target; + else if (target) + *target = device; + if (flags) + *flags = vdmt->flags; + + spin_unlock(hash_lock); + + return ret; +} + + +/* __remove_mapping() + * remove a mapping from the hash table + */ +static inline int __remove_mapping(struct vx_info *vxi, dev_t device, + umode_t mode) +{ + spinlock_t *hash_lock = &dmap_main_hash_lock; + struct vs_mapping *vdm = NULL; + int ret = 0; + + spin_lock(hash_lock); + + ret = __find_mapping((vxi ? vxi->vx_id : 0), device, mode, &vdm, + NULL); + vxdprintk(VXD_CBIT(misc, 8), "__remove_mapping: %p[#%d] %08x %04x", + vxi, vxi ? vxi->vx_id : 0, device, mode); + if (ret < 0) + goto out; + hlist_del(&vdm->dm_hlist); + +out: + spin_unlock(hash_lock); + if (vdm) + kmem_cache_free(dmap_cachep, vdm); + return ret; +} + + + +int vs_map_device(struct vx_info *vxi, + dev_t device, dev_t *target, umode_t mode) +{ + int ret, flags = DATTR_MASK; + + if (!vxi) { + if (target) + *target = device; + goto out; + } + ret = __lookup_mapping(vxi, device, target, &flags, mode); + vxdprintk(VXD_CBIT(misc, 8), "vs_map_device: %08x target: %08x flags: %04x mode: %04x mapped=%d", + device, target ? *target : 0, flags, mode, ret); +out: + return (flags & DATTR_MASK); +} + + + +static int do_set_mapping(struct vx_info *vxi, + dev_t device, dev_t target, int flags, umode_t mode) +{ + if (device) { + struct vs_mapping *new; + + new = kmem_cache_alloc(dmap_cachep, GFP_KERNEL); + if (!new) + return -ENOMEM; + + INIT_HLIST_NODE(&new->dm_hlist); + new->device = device; + new->target.target = target; + new->target.flags = flags | mode; + new->xid = (vxi ? vxi->vx_id : 0); + + vxdprintk(VXD_CBIT(misc, 8), "do_set_mapping: %08x target: %08x flags: %04x", device, target, flags); + __hash_mapping(vxi, new); + } else { + struct vx_dmap_target new = { + .target = target, + .flags = flags | mode, + }; + __set_default(vxi, mode, &new); + } + return 0; +} + + +static int do_unset_mapping(struct vx_info *vxi, + dev_t device, dev_t target, int flags, umode_t mode) +{ + int ret = -EINVAL; + + if (device) { + ret = __remove_mapping(vxi, device, mode); + if (ret < 0) + goto out; + } else { + ret = __remove_default(vxi, mode); + if (ret < 0) + goto out; + } + +out: + return ret; +} + + +static inline int __user_device(const char __user *name, dev_t *dev, + umode_t *mode) +{ + struct nameidata nd; + int ret; + + if (!name) { + *dev = 0; + return 0; + } + ret = user_lpath(name, &nd.path); + if (ret) + return ret; + if (nd.path.dentry->d_inode) { + *dev = nd.path.dentry->d_inode->i_rdev; + *mode = nd.path.dentry->d_inode->i_mode; + } + path_put(&nd.path); + return 0; +} + +static inline int __mapping_mode(dev_t device, dev_t target, + umode_t device_mode, umode_t target_mode, umode_t *mode) +{ + if (device) + *mode = device_mode & S_IFMT; + else if (target) + *mode = target_mode & S_IFMT; + else + return -EINVAL; + + /* if both given, device and target mode have to match */ + if (device && target && + ((device_mode ^ target_mode) & S_IFMT)) + return -EINVAL; + return 0; +} + + +static inline int do_mapping(struct vx_info *vxi, const char __user *device_path, + const char __user *target_path, int flags, int set) +{ + dev_t device = ~0, target = ~0; + umode_t device_mode = 0, target_mode = 0, mode; + int ret; + + ret = __user_device(device_path, &device, &device_mode); + if (ret) + return ret; + ret = __user_device(target_path, &target, &target_mode); + if (ret) + return ret; + + ret = __mapping_mode(device, target, + device_mode, target_mode, &mode); + if (ret) + return ret; + + if (set) + return do_set_mapping(vxi, device, target, + flags, mode); + else + return do_unset_mapping(vxi, device, target, + flags, mode); +} + + +int vc_set_mapping(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_mapping(vxi, vc_data.device, vc_data.target, + vc_data.flags, 1); +} + +int vc_unset_mapping(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_mapping(vxi, vc_data.device, vc_data.target, + vc_data.flags, 0); +} + + +#ifdef CONFIG_COMPAT + +int vc_set_mapping_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0_x32 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_mapping(vxi, compat_ptr(vc_data.device_ptr), + compat_ptr(vc_data.target_ptr), vc_data.flags, 1); +} + +int vc_unset_mapping_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_mapping_v0_x32 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_mapping(vxi, compat_ptr(vc_data.device_ptr), + compat_ptr(vc_data.target_ptr), vc_data.flags, 0); +} + +#endif /* CONFIG_COMPAT */ + + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/dlimit.c linux-2.6.27.15-g-v/kernel/vserver/dlimit.c --- linux-2.6.27.15/kernel/vserver/dlimit.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/dlimit.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,522 @@ +/* + * linux/kernel/vserver/dlimit.c + * + * Virtual Server: Context Disk Limits + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 initial version + * V0.02 compat32 splitup + * + */ + +#include +#include +#include +#include +#include +#include + +#include + +/* __alloc_dl_info() + + * allocate an initialized dl_info struct + * doesn't make it visible (hash) */ + +static struct dl_info *__alloc_dl_info(struct super_block *sb, tag_t tag) +{ + struct dl_info *new = NULL; + + vxdprintk(VXD_CBIT(dlim, 5), + "alloc_dl_info(%p,%d)*", sb, tag); + + /* would this benefit from a slab cache? */ + new = kmalloc(sizeof(struct dl_info), GFP_KERNEL); + if (!new) + return 0; + + memset(new, 0, sizeof(struct dl_info)); + new->dl_tag = tag; + new->dl_sb = sb; + INIT_RCU_HEAD(&new->dl_rcu); + INIT_HLIST_NODE(&new->dl_hlist); + spin_lock_init(&new->dl_lock); + atomic_set(&new->dl_refcnt, 0); + atomic_set(&new->dl_usecnt, 0); + + /* rest of init goes here */ + + vxdprintk(VXD_CBIT(dlim, 4), + "alloc_dl_info(%p,%d) = %p", sb, tag, new); + return new; +} + +/* __dealloc_dl_info() + + * final disposal of dl_info */ + +static void __dealloc_dl_info(struct dl_info *dli) +{ + vxdprintk(VXD_CBIT(dlim, 4), + "dealloc_dl_info(%p)", dli); + + dli->dl_hlist.next = LIST_POISON1; + dli->dl_tag = -1; + dli->dl_sb = 0; + + BUG_ON(atomic_read(&dli->dl_usecnt)); + BUG_ON(atomic_read(&dli->dl_refcnt)); + + kfree(dli); +} + + +/* hash table for dl_info hash */ + +#define DL_HASH_SIZE 13 + +struct hlist_head dl_info_hash[DL_HASH_SIZE]; + +static spinlock_t dl_info_hash_lock = SPIN_LOCK_UNLOCKED; + + +static inline unsigned int __hashval(struct super_block *sb, tag_t tag) +{ + return ((tag ^ (unsigned long)sb) % DL_HASH_SIZE); +} + + + +/* __hash_dl_info() + + * add the dli to the global hash table + * requires the hash_lock to be held */ + +static inline void __hash_dl_info(struct dl_info *dli) +{ + struct hlist_head *head; + + vxdprintk(VXD_CBIT(dlim, 6), + "__hash_dl_info: %p[#%d]", dli, dli->dl_tag); + get_dl_info(dli); + head = &dl_info_hash[__hashval(dli->dl_sb, dli->dl_tag)]; + hlist_add_head_rcu(&dli->dl_hlist, head); +} + +/* __unhash_dl_info() + + * remove the dli from the global hash table + * requires the hash_lock to be held */ + +static inline void __unhash_dl_info(struct dl_info *dli) +{ + vxdprintk(VXD_CBIT(dlim, 6), + "__unhash_dl_info: %p[#%d]", dli, dli->dl_tag); + hlist_del_rcu(&dli->dl_hlist); + put_dl_info(dli); +} + + +/* __lookup_dl_info() + + * requires the rcu_read_lock() + * doesn't increment the dl_refcnt */ + +static inline struct dl_info *__lookup_dl_info(struct super_block *sb, tag_t tag) +{ + struct hlist_head *head = &dl_info_hash[__hashval(sb, tag)]; + struct hlist_node *pos; + struct dl_info *dli; + + hlist_for_each_entry_rcu(dli, pos, head, dl_hlist) { + + if (dli->dl_tag == tag && dli->dl_sb == sb) { + return dli; + } + } + return NULL; +} + + +struct dl_info *locate_dl_info(struct super_block *sb, tag_t tag) +{ + struct dl_info *dli; + + rcu_read_lock(); + dli = get_dl_info(__lookup_dl_info(sb, tag)); + vxdprintk(VXD_CBIT(dlim, 7), + "locate_dl_info(%p,#%d) = %p", sb, tag, dli); + rcu_read_unlock(); + return dli; +} + +void rcu_free_dl_info(struct rcu_head *head) +{ + struct dl_info *dli = container_of(head, struct dl_info, dl_rcu); + int usecnt, refcnt; + + BUG_ON(!dli || !head); + + usecnt = atomic_read(&dli->dl_usecnt); + BUG_ON(usecnt < 0); + + refcnt = atomic_read(&dli->dl_refcnt); + BUG_ON(refcnt < 0); + + vxdprintk(VXD_CBIT(dlim, 3), + "rcu_free_dl_info(%p)", dli); + if (!usecnt) + __dealloc_dl_info(dli); + else + printk("!!! rcu didn't free\n"); +} + + + + +static int do_addrem_dlimit(uint32_t id, const char __user *name, + uint32_t flags, int add) +{ + struct path path; + int ret; + + ret = user_lpath(name, &path); + if (!ret) { + struct super_block *sb; + struct dl_info *dli; + + ret = -EINVAL; + if (!path.dentry->d_inode) + goto out_release; + if (!(sb = path.dentry->d_inode->i_sb)) + goto out_release; + + if (add) { + dli = __alloc_dl_info(sb, id); + spin_lock(&dl_info_hash_lock); + + ret = -EEXIST; + if (__lookup_dl_info(sb, id)) + goto out_unlock; + __hash_dl_info(dli); + dli = NULL; + } else { + spin_lock(&dl_info_hash_lock); + dli = __lookup_dl_info(sb, id); + + ret = -ESRCH; + if (!dli) + goto out_unlock; + __unhash_dl_info(dli); + } + ret = 0; + out_unlock: + spin_unlock(&dl_info_hash_lock); + if (add && dli) + __dealloc_dl_info(dli); + out_release: + path_put(&path); + } + return ret; +} + +int vc_add_dlimit(uint32_t id, void __user *data) +{ + struct vcmd_ctx_dlimit_base_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_addrem_dlimit(id, vc_data.name, vc_data.flags, 1); +} + +int vc_rem_dlimit(uint32_t id, void __user *data) +{ + struct vcmd_ctx_dlimit_base_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_addrem_dlimit(id, vc_data.name, vc_data.flags, 0); +} + +#ifdef CONFIG_COMPAT + +int vc_add_dlimit_x32(uint32_t id, void __user *data) +{ + struct vcmd_ctx_dlimit_base_v0_x32 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_addrem_dlimit(id, + compat_ptr(vc_data.name_ptr), vc_data.flags, 1); +} + +int vc_rem_dlimit_x32(uint32_t id, void __user *data) +{ + struct vcmd_ctx_dlimit_base_v0_x32 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_addrem_dlimit(id, + compat_ptr(vc_data.name_ptr), vc_data.flags, 0); +} + +#endif /* CONFIG_COMPAT */ + + +static inline +int do_set_dlimit(uint32_t id, const char __user *name, + uint32_t space_used, uint32_t space_total, + uint32_t inodes_used, uint32_t inodes_total, + uint32_t reserved, uint32_t flags) +{ + struct path path; + int ret; + + ret = user_lpath(name, &path); + if (!ret) { + struct super_block *sb; + struct dl_info *dli; + + ret = -EINVAL; + if (!path.dentry->d_inode) + goto out_release; + if (!(sb = path.dentry->d_inode->i_sb)) + goto out_release; + if ((reserved != CDLIM_KEEP && + reserved > 100) || + (inodes_used != CDLIM_KEEP && + inodes_used > inodes_total) || + (space_used != CDLIM_KEEP && + space_used > space_total)) + goto out_release; + + ret = -ESRCH; + dli = locate_dl_info(sb, id); + if (!dli) + goto out_release; + + spin_lock(&dli->dl_lock); + + if (inodes_used != CDLIM_KEEP) + dli->dl_inodes_used = inodes_used; + if (inodes_total != CDLIM_KEEP) + dli->dl_inodes_total = inodes_total; + if (space_used != CDLIM_KEEP) { + dli->dl_space_used = space_used; + dli->dl_space_used <<= 10; + } + if (space_total == CDLIM_INFINITY) + dli->dl_space_total = DLIM_INFINITY; + else if (space_total != CDLIM_KEEP) { + dli->dl_space_total = space_total; + dli->dl_space_total <<= 10; + } + if (reserved != CDLIM_KEEP) + dli->dl_nrlmult = (1 << 10) * (100 - reserved) / 100; + + spin_unlock(&dli->dl_lock); + + put_dl_info(dli); + ret = 0; + + out_release: + path_put(&path); + } + return ret; +} + +int vc_set_dlimit(uint32_t id, void __user *data) +{ + struct vcmd_ctx_dlimit_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_dlimit(id, vc_data.name, + vc_data.space_used, vc_data.space_total, + vc_data.inodes_used, vc_data.inodes_total, + vc_data.reserved, vc_data.flags); +} + +#ifdef CONFIG_COMPAT + +int vc_set_dlimit_x32(uint32_t id, void __user *data) +{ + struct vcmd_ctx_dlimit_v0_x32 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_dlimit(id, compat_ptr(vc_data.name_ptr), + vc_data.space_used, vc_data.space_total, + vc_data.inodes_used, vc_data.inodes_total, + vc_data.reserved, vc_data.flags); +} + +#endif /* CONFIG_COMPAT */ + + +static inline +int do_get_dlimit(uint32_t id, const char __user *name, + uint32_t *space_used, uint32_t *space_total, + uint32_t *inodes_used, uint32_t *inodes_total, + uint32_t *reserved, uint32_t *flags) +{ + struct path path; + int ret; + + ret = user_lpath(name, &path); + if (!ret) { + struct super_block *sb; + struct dl_info *dli; + + ret = -EINVAL; + if (!path.dentry->d_inode) + goto out_release; + if (!(sb = path.dentry->d_inode->i_sb)) + goto out_release; + + ret = -ESRCH; + dli = locate_dl_info(sb, id); + if (!dli) + goto out_release; + + spin_lock(&dli->dl_lock); + *inodes_used = dli->dl_inodes_used; + *inodes_total = dli->dl_inodes_total; + *space_used = dli->dl_space_used >> 10; + if (dli->dl_space_total == DLIM_INFINITY) + *space_total = CDLIM_INFINITY; + else + *space_total = dli->dl_space_total >> 10; + + *reserved = 100 - ((dli->dl_nrlmult * 100 + 512) >> 10); + spin_unlock(&dli->dl_lock); + + put_dl_info(dli); + ret = -EFAULT; + + ret = 0; + out_release: + path_put(&path); + } + return ret; +} + + +int vc_get_dlimit(uint32_t id, void __user *data) +{ + struct vcmd_ctx_dlimit_v0 vc_data; + int ret; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_get_dlimit(id, vc_data.name, + &vc_data.space_used, &vc_data.space_total, + &vc_data.inodes_used, &vc_data.inodes_total, + &vc_data.reserved, &vc_data.flags); + if (ret) + return ret; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +#ifdef CONFIG_COMPAT + +int vc_get_dlimit_x32(uint32_t id, void __user *data) +{ + struct vcmd_ctx_dlimit_v0_x32 vc_data; + int ret; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_get_dlimit(id, compat_ptr(vc_data.name_ptr), + &vc_data.space_used, &vc_data.space_total, + &vc_data.inodes_used, &vc_data.inodes_total, + &vc_data.reserved, &vc_data.flags); + if (ret) + return ret; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +#endif /* CONFIG_COMPAT */ + + +void vx_vsi_statfs(struct super_block *sb, struct kstatfs *buf) +{ + struct dl_info *dli; + __u64 blimit, bfree, bavail; + __u32 ifree; + + dli = locate_dl_info(sb, dx_current_tag()); + if (!dli) + return; + + spin_lock(&dli->dl_lock); + if (dli->dl_inodes_total == (unsigned long)DLIM_INFINITY) + goto no_ilim; + + /* reduce max inodes available to limit */ + if (buf->f_files > dli->dl_inodes_total) + buf->f_files = dli->dl_inodes_total; + + ifree = dli->dl_inodes_total - dli->dl_inodes_used; + /* reduce free inodes to min */ + if (ifree < buf->f_ffree) + buf->f_ffree = ifree; + +no_ilim: + if (dli->dl_space_total == DLIM_INFINITY) + goto no_blim; + + blimit = dli->dl_space_total >> sb->s_blocksize_bits; + + if (dli->dl_space_total < dli->dl_space_used) + bfree = 0; + else + bfree = (dli->dl_space_total - dli->dl_space_used) + >> sb->s_blocksize_bits; + + bavail = ((dli->dl_space_total >> 10) * dli->dl_nrlmult); + if (bavail < dli->dl_space_used) + bavail = 0; + else + bavail = (bavail - dli->dl_space_used) + >> sb->s_blocksize_bits; + + /* reduce max space available to limit */ + if (buf->f_blocks > blimit) + buf->f_blocks = blimit; + + /* reduce free space to min */ + if (bfree < buf->f_bfree) + buf->f_bfree = bfree; + + /* reduce avail space to min */ + if (bavail < buf->f_bavail) + buf->f_bavail = bavail; + +no_blim: + spin_unlock(&dli->dl_lock); + put_dl_info(dli); + + return; +} + +#include + +EXPORT_SYMBOL_GPL(locate_dl_info); +EXPORT_SYMBOL_GPL(rcu_free_dl_info); + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/helper.c linux-2.6.27.15-g-v/kernel/vserver/helper.c --- linux-2.6.27.15/kernel/vserver/helper.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/helper.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,199 @@ +/* + * linux/kernel/vserver/helper.c + * + * Virtual Context Support + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 basic helper + * + */ + +#include +#include +#include +#include +#include + + +char vshelper_path[255] = "/sbin/vshelper"; + + +static int do_vshelper(char *name, char *argv[], char *envp[], int sync) +{ + int ret; + + if ((ret = call_usermodehelper(name, argv, envp, sync))) { + printk( KERN_WARNING + "%s: (%s %s) returned %s with %d\n", + name, argv[1], argv[2], + sync ? "sync" : "async", ret); + } + vxdprintk(VXD_CBIT(switch, 4), + "%s: (%s %s) returned %s with %d", + name, argv[1], argv[2], sync ? "sync" : "async", ret); + return ret; +} + +/* + * vshelper path is set via /proc/sys + * invoked by vserver sys_reboot(), with + * the following arguments + * + * argv [0] = vshelper_path; + * argv [1] = action: "restart", "halt", "poweroff", ... + * argv [2] = context identifier + * + * envp [*] = type-specific parameters + */ + +long vs_reboot_helper(struct vx_info *vxi, int cmd, void __user *arg) +{ + char id_buf[8], cmd_buf[16]; + char uid_buf[16], pid_buf[16]; + int ret; + + char *argv[] = {vshelper_path, NULL, id_buf, 0}; + char *envp[] = {"HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", + uid_buf, pid_buf, cmd_buf, 0}; + + if (vx_info_state(vxi, VXS_HELPER)) + return -EAGAIN; + vxi->vx_state |= VXS_HELPER; + + snprintf(id_buf, sizeof(id_buf)-1, "%d", vxi->vx_id); + + snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd); + snprintf(uid_buf, sizeof(uid_buf)-1, "VS_UID=%d", current->uid); + snprintf(pid_buf, sizeof(pid_buf)-1, "VS_PID=%d", current->pid); + + switch (cmd) { + case LINUX_REBOOT_CMD_RESTART: + argv[1] = "restart"; + break; + + case LINUX_REBOOT_CMD_HALT: + argv[1] = "halt"; + break; + + case LINUX_REBOOT_CMD_POWER_OFF: + argv[1] = "poweroff"; + break; + + case LINUX_REBOOT_CMD_SW_SUSPEND: + argv[1] = "swsusp"; + break; + + default: + vxi->vx_state &= ~VXS_HELPER; + return 0; + } + + ret = do_vshelper(vshelper_path, argv, envp, 0); + vxi->vx_state &= ~VXS_HELPER; + __wakeup_vx_info(vxi); + return (ret) ? -EPERM : 0; +} + + +long vs_reboot(unsigned int cmd, void __user *arg) +{ + struct vx_info *vxi = current->vx_info; + long ret = 0; + + vxdprintk(VXD_CBIT(misc, 5), + "vs_reboot(%p[#%d],%d)", + vxi, vxi ? vxi->vx_id : 0, cmd); + + ret = vs_reboot_helper(vxi, cmd, arg); + if (ret) + return ret; + + vxi->reboot_cmd = cmd; + if (vx_info_flags(vxi, VXF_REBOOT_KILL, 0)) { + switch (cmd) { + case LINUX_REBOOT_CMD_RESTART: + case LINUX_REBOOT_CMD_HALT: + case LINUX_REBOOT_CMD_POWER_OFF: + vx_info_kill(vxi, 0, SIGKILL); + vx_info_kill(vxi, 1, SIGKILL); + default: + break; + } + } + return 0; +} + + +/* + * argv [0] = vshelper_path; + * argv [1] = action: "startup", "shutdown" + * argv [2] = context identifier + * + * envp [*] = type-specific parameters + */ + +long vs_state_change(struct vx_info *vxi, unsigned int cmd) +{ + char id_buf[8], cmd_buf[16]; + char *argv[] = {vshelper_path, NULL, id_buf, 0}; + char *envp[] = {"HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", cmd_buf, 0}; + + if (!vx_info_flags(vxi, VXF_SC_HELPER, 0)) + return 0; + + snprintf(id_buf, sizeof(id_buf)-1, "%d", vxi->vx_id); + snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd); + + switch (cmd) { + case VSC_STARTUP: + argv[1] = "startup"; + break; + case VSC_SHUTDOWN: + argv[1] = "shutdown"; + break; + default: + return 0; + } + + return do_vshelper(vshelper_path, argv, envp, 1); +} + + +/* + * argv [0] = vshelper_path; + * argv [1] = action: "netup", "netdown" + * argv [2] = context identifier + * + * envp [*] = type-specific parameters + */ + +long vs_net_change(struct nx_info *nxi, unsigned int cmd) +{ + char id_buf[8], cmd_buf[16]; + char *argv[] = {vshelper_path, NULL, id_buf, 0}; + char *envp[] = {"HOME=/", "TERM=linux", + "PATH=/sbin:/usr/sbin:/bin:/usr/bin", cmd_buf, 0}; + + if (!nx_info_flags(nxi, NXF_SC_HELPER, 0)) + return 0; + + snprintf(id_buf, sizeof(id_buf)-1, "%d", nxi->nx_id); + snprintf(cmd_buf, sizeof(cmd_buf)-1, "VS_CMD=%08x", cmd); + + switch (cmd) { + case VSC_NETUP: + argv[1] = "netup"; + break; + case VSC_NETDOWN: + argv[1] = "netdown"; + break; + default: + return 0; + } + + return do_vshelper(vshelper_path, argv, envp, 1); +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/history.c linux-2.6.27.15-g-v/kernel/vserver/history.c --- linux-2.6.27.15/kernel/vserver/history.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/history.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,258 @@ +/* + * kernel/vserver/history.c + * + * Virtual Context History Backtrace + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 basic structure + * V0.02 hash/unhash and trace + * V0.03 preemption fixes + * + */ + +#include +#include + +#include +#include +#include +#include + + +#ifdef CONFIG_VSERVER_HISTORY +#define VXH_SIZE CONFIG_VSERVER_HISTORY_SIZE +#else +#define VXH_SIZE 64 +#endif + +struct _vx_history { + unsigned int counter; + + struct _vx_hist_entry entry[VXH_SIZE + 1]; +}; + + +DEFINE_PER_CPU(struct _vx_history, vx_history_buffer); + +unsigned volatile int vxh_active = 1; + +static atomic_t sequence = ATOMIC_INIT(0); + + +/* vxh_advance() + + * requires disabled preemption */ + +struct _vx_hist_entry *vxh_advance(void *loc) +{ + unsigned int cpu = smp_processor_id(); + struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu); + struct _vx_hist_entry *entry; + unsigned int index; + + index = vxh_active ? (hist->counter++ % VXH_SIZE) : VXH_SIZE; + entry = &hist->entry[index]; + + entry->seq = atomic_inc_return(&sequence); + entry->loc = loc; + return entry; +} + +EXPORT_SYMBOL_GPL(vxh_advance); + + +#define VXH_LOC_FMTS "(#%04x,*%d):%p" + +#define VXH_LOC_ARGS(e) (e)->seq, cpu, (e)->loc + + +#define VXH_VXI_FMTS "%p[#%d,%d.%d]" + +#define VXH_VXI_ARGS(e) (e)->vxi.ptr, \ + (e)->vxi.ptr ? (e)->vxi.xid : 0, \ + (e)->vxi.ptr ? (e)->vxi.usecnt : 0, \ + (e)->vxi.ptr ? (e)->vxi.tasks : 0 + +void vxh_dump_entry(struct _vx_hist_entry *e, unsigned cpu) +{ + switch (e->type) { + case VXH_THROW_OOPS: + printk( VXH_LOC_FMTS " oops \n", VXH_LOC_ARGS(e)); + break; + + case VXH_GET_VX_INFO: + case VXH_PUT_VX_INFO: + printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n", + VXH_LOC_ARGS(e), + (e->type == VXH_GET_VX_INFO) ? "get" : "put", + VXH_VXI_ARGS(e)); + break; + + case VXH_INIT_VX_INFO: + case VXH_SET_VX_INFO: + case VXH_CLR_VX_INFO: + printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n", + VXH_LOC_ARGS(e), + (e->type == VXH_INIT_VX_INFO) ? "init" : + ((e->type == VXH_SET_VX_INFO) ? "set" : "clr"), + VXH_VXI_ARGS(e), e->sc.data); + break; + + case VXH_CLAIM_VX_INFO: + case VXH_RELEASE_VX_INFO: + printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS " @%p\n", + VXH_LOC_ARGS(e), + (e->type == VXH_CLAIM_VX_INFO) ? "claim" : "release", + VXH_VXI_ARGS(e), e->sc.data); + break; + + case VXH_ALLOC_VX_INFO: + case VXH_DEALLOC_VX_INFO: + printk( VXH_LOC_FMTS " %s_vx_info " VXH_VXI_FMTS "\n", + VXH_LOC_ARGS(e), + (e->type == VXH_ALLOC_VX_INFO) ? "alloc" : "dealloc", + VXH_VXI_ARGS(e)); + break; + + case VXH_HASH_VX_INFO: + case VXH_UNHASH_VX_INFO: + printk( VXH_LOC_FMTS " __%s_vx_info " VXH_VXI_FMTS "\n", + VXH_LOC_ARGS(e), + (e->type == VXH_HASH_VX_INFO) ? "hash" : "unhash", + VXH_VXI_ARGS(e)); + break; + + case VXH_LOC_VX_INFO: + case VXH_LOOKUP_VX_INFO: + case VXH_CREATE_VX_INFO: + printk( VXH_LOC_FMTS " __%s_vx_info [#%d] -> " VXH_VXI_FMTS "\n", + VXH_LOC_ARGS(e), + (e->type == VXH_CREATE_VX_INFO) ? "create" : + ((e->type == VXH_LOC_VX_INFO) ? "loc" : "lookup"), + e->ll.arg, VXH_VXI_ARGS(e)); + break; + } +} + +static void __vxh_dump_history(void) +{ + unsigned int i, cpu; + + printk("History:\tSEQ: %8x\tNR_CPUS: %d\n", + atomic_read(&sequence), NR_CPUS); + + for (i = 0; i < VXH_SIZE; i++) { + for_each_online_cpu(cpu) { + struct _vx_history *hist = + &per_cpu(vx_history_buffer, cpu); + unsigned int index = (hist->counter - i) % VXH_SIZE; + struct _vx_hist_entry *entry = &hist->entry[index]; + + vxh_dump_entry(entry, cpu); + } + } +} + +void vxh_dump_history(void) +{ + vxh_active = 0; +#ifdef CONFIG_SMP + local_irq_enable(); + smp_send_stop(); + local_irq_disable(); +#endif + __vxh_dump_history(); +} + + +/* vserver syscall commands below here */ + + +int vc_dump_history(uint32_t id) +{ + vxh_active = 0; + __vxh_dump_history(); + vxh_active = 1; + + return 0; +} + + +int do_read_history(struct __user _vx_hist_entry *data, + int cpu, uint32_t *index, uint32_t *count) +{ + int pos, ret = 0; + struct _vx_history *hist = &per_cpu(vx_history_buffer, cpu); + int end = hist->counter; + int start = end - VXH_SIZE + 2; + int idx = *index; + + /* special case: get current pos */ + if (!*count) { + *index = end; + return 0; + } + + /* have we lost some data? */ + if (idx < start) + idx = start; + + for (pos = 0; (pos < *count) && (idx < end); pos++, idx++) { + struct _vx_hist_entry *entry = + &hist->entry[idx % VXH_SIZE]; + + /* send entry to userspace */ + ret = copy_to_user(&data[pos], entry, sizeof(*entry)); + if (ret) + break; + } + /* save new index and count */ + *index = idx; + *count = pos; + return ret ? ret : (*index < end); +} + +int vc_read_history(uint32_t id, void __user *data) +{ + struct vcmd_read_history_v0 vc_data; + int ret; + + if (id >= NR_CPUS) + return -EINVAL; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_read_history((struct __user _vx_hist_entry *)vc_data.data, + id, &vc_data.index, &vc_data.count); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + +#ifdef CONFIG_COMPAT + +int vc_read_history_x32(uint32_t id, void __user *data) +{ + struct vcmd_read_history_v0_x32 vc_data; + int ret; + + if (id >= NR_CPUS) + return -EINVAL; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_read_history((struct __user _vx_hist_entry *) + compat_ptr(vc_data.data_ptr), + id, &vc_data.index, &vc_data.count); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + +#endif /* CONFIG_COMPAT */ + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/inet.c linux-2.6.27.15-g-v/kernel/vserver/inet.c --- linux-2.6.27.15/kernel/vserver/inet.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/inet.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,225 @@ + +#include +#include +#include +#include +#include +#include +#include + + +int nx_v4_addr_conflict(struct nx_info *nxi1, struct nx_info *nxi2) +{ + int ret = 0; + + if (!nxi1 || !nxi2 || nxi1 == nxi2) + ret = 1; + else { + struct nx_addr_v4 *ptr; + + for (ptr = &nxi1->v4; ptr; ptr = ptr->next) { + if (v4_nx_addr_in_nx_info(nxi2, ptr, -1)) { + ret = 1; + break; + } + } + } + + vxdprintk(VXD_CBIT(net, 2), + "nx_v4_addr_conflict(%p,%p): %d", + nxi1, nxi2, ret); + + return ret; +} + + +#ifdef CONFIG_IPV6 + +int nx_v6_addr_conflict(struct nx_info *nxi1, struct nx_info *nxi2) +{ + int ret = 0; + + if (!nxi1 || !nxi2 || nxi1 == nxi2) + ret = 1; + else { + struct nx_addr_v6 *ptr; + + for (ptr = &nxi1->v6; ptr; ptr = ptr->next) { + if (v6_nx_addr_in_nx_info(nxi2, ptr, -1)) { + ret = 1; + break; + } + } + } + + vxdprintk(VXD_CBIT(net, 2), + "nx_v6_addr_conflict(%p,%p): %d", + nxi1, nxi2, ret); + + return ret; +} + +#endif + +int v4_dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) +{ + struct in_device *in_dev; + struct in_ifaddr **ifap; + struct in_ifaddr *ifa; + int ret = 0; + + if (!dev) + goto out; + in_dev = in_dev_get(dev); + if (!in_dev) + goto out; + + for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; + ifap = &ifa->ifa_next) { + if (v4_addr_in_nx_info(nxi, ifa->ifa_local, NXA_MASK_SHOW)) { + ret = 1; + break; + } + } + in_dev_put(in_dev); +out: + return ret; +} + + +#ifdef CONFIG_IPV6 + +int v6_dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) +{ + struct inet6_dev *in_dev; + struct inet6_ifaddr **ifap; + struct inet6_ifaddr *ifa; + int ret = 0; + + if (!dev) + goto out; + in_dev = in6_dev_get(dev); + if (!in_dev) + goto out; + + for (ifap = &in_dev->addr_list; (ifa = *ifap) != NULL; + ifap = &ifa->if_next) { + if (v6_addr_in_nx_info(nxi, &ifa->addr, -1)) { + ret = 1; + break; + } + } + in6_dev_put(in_dev); +out: + return ret; +} + +#endif + +int dev_in_nx_info(struct net_device *dev, struct nx_info *nxi) +{ + int ret = 1; + + if (!nxi) + goto out; + if (nxi->v4.type && v4_dev_in_nx_info(dev, nxi)) + goto out; +#ifdef CONFIG_IPV6 + ret = 2; + if (nxi->v6.type && v6_dev_in_nx_info(dev, nxi)) + goto out; +#endif + ret = 0; +out: + vxdprintk(VXD_CBIT(net, 3), + "dev_in_nx_info(%p,%p[#%d]) = %d", + dev, nxi, nxi ? nxi->nx_id : 0, ret); + return ret; +} + +int ip_v4_find_src(struct net *net, struct nx_info *nxi, + struct rtable **rp, struct flowi *fl) +{ + if (!nxi) + return 0; + + /* FIXME: handle lback only case */ + if (!NX_IPV4(nxi)) + return -EPERM; + + vxdprintk(VXD_CBIT(net, 4), + "ip_v4_find_src(%p[#%u]) " NIPQUAD_FMT " -> " NIPQUAD_FMT, + nxi, nxi ? nxi->nx_id : 0, + NIPQUAD(fl->fl4_src), NIPQUAD(fl->fl4_dst)); + + /* single IP is unconditional */ + if (nx_info_flags(nxi, NXF_SINGLE_IP, 0) && + (fl->fl4_src == INADDR_ANY)) + fl->fl4_src = nxi->v4.ip[0].s_addr; + + if (fl->fl4_src == INADDR_ANY) { + struct nx_addr_v4 *ptr; + __be32 found = 0; + int err; + + err = __ip_route_output_key(net, rp, fl); + if (!err) { + found = (*rp)->rt_src; + ip_rt_put(*rp); + vxdprintk(VXD_CBIT(net, 4), + "ip_v4_find_src(%p[#%u]) rok[%u]: " NIPQUAD_FMT, + nxi, nxi ? nxi->nx_id : 0, fl->oif, NIPQUAD(found)); + if (v4_addr_in_nx_info(nxi, found, NXA_MASK_BIND)) + goto found; + } + + for (ptr = &nxi->v4; ptr; ptr = ptr->next) { + __be32 primary = ptr->ip[0].s_addr; + __be32 mask = ptr->mask.s_addr; + __be32 neta = primary & mask; + + vxdprintk(VXD_CBIT(net, 4), "ip_v4_find_src(%p[#%u]) chk: " + NIPQUAD_FMT "/" NIPQUAD_FMT "/" NIPQUAD_FMT, + nxi, nxi ? nxi->nx_id : 0, NIPQUAD(primary), + NIPQUAD(mask), NIPQUAD(neta)); + if ((found & mask) != neta) + continue; + + fl->fl4_src = primary; + err = __ip_route_output_key(net, rp, fl); + vxdprintk(VXD_CBIT(net, 4), + "ip_v4_find_src(%p[#%u]) rok[%u]: " NIPQUAD_FMT, + nxi, nxi ? nxi->nx_id : 0, fl->oif, NIPQUAD(primary)); + if (!err) { + found = (*rp)->rt_src; + ip_rt_put(*rp); + if (found == primary) + goto found; + } + } + /* still no source ip? */ + found = ipv4_is_loopback(fl->fl4_dst) + ? IPI_LOOPBACK : nxi->v4.ip[0].s_addr; + found: + /* assign src ip to flow */ + fl->fl4_src = found; + + } else { + if (!v4_addr_in_nx_info(nxi, fl->fl4_src, NXA_MASK_BIND)) + return -EPERM; + } + + if (nx_info_flags(nxi, NXF_LBACK_REMAP, 0)) { + if (ipv4_is_loopback(fl->fl4_dst)) + fl->fl4_dst = nxi->v4_lback.s_addr; + if (ipv4_is_loopback(fl->fl4_src)) + fl->fl4_src = nxi->v4_lback.s_addr; + } else if (ipv4_is_loopback(fl->fl4_dst) && + !nx_info_flags(nxi, NXF_LBACK_ALLOW, 0)) + return -EPERM; + + return 0; +} + +EXPORT_SYMBOL_GPL(ip_v4_find_src); + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/init.c linux-2.6.27.15-g-v/kernel/vserver/init.c --- linux-2.6.27.15/kernel/vserver/init.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/init.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,45 @@ +/* + * linux/kernel/init.c + * + * Virtual Server Init + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 basic structure + * + */ + +#include + +int vserver_register_sysctl(void); +void vserver_unregister_sysctl(void); + + +static int __init init_vserver(void) +{ + int ret = 0; + +#ifdef CONFIG_VSERVER_DEBUG + vserver_register_sysctl(); +#endif + return ret; +} + + +static void __exit exit_vserver(void) +{ + +#ifdef CONFIG_VSERVER_DEBUG + vserver_unregister_sysctl(); +#endif + return; +} + +/* FIXME: GFP_ZONETYPES gone +long vx_slab[GFP_ZONETYPES]; */ +long vx_area; + + +module_init(init_vserver); +module_exit(exit_vserver); + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/inode.c linux-2.6.27.15-g-v/kernel/vserver/inode.c --- linux-2.6.27.15/kernel/vserver/inode.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/inode.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,422 @@ +/* + * linux/kernel/vserver/inode.c + * + * Virtual Server: File System Support + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 separated from vcontext V0.05 + * V0.02 moved to tag (instead of xid) + * + */ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + + +static int __vc_get_iattr(struct inode *in, uint32_t *tag, uint32_t *flags, uint32_t *mask) +{ + struct proc_dir_entry *entry; + + if (!in || !in->i_sb) + return -ESRCH; + + *flags = IATTR_TAG + | (IS_BARRIER(in) ? IATTR_BARRIER : 0) + | (IS_IXUNLINK(in) ? IATTR_IXUNLINK : 0) + | (IS_IMMUTABLE(in) ? IATTR_IMMUTABLE : 0); + *mask = IATTR_IXUNLINK | IATTR_IMMUTABLE; + + if (S_ISDIR(in->i_mode)) + *mask |= IATTR_BARRIER; + + if (IS_TAGGED(in)) { + *tag = in->i_tag; + *mask |= IATTR_TAG; + } + + switch (in->i_sb->s_magic) { + case PROC_SUPER_MAGIC: + entry = PROC_I(in)->pde; + + /* check for specific inodes? */ + if (entry) + *mask |= IATTR_FLAGS; + if (entry) + *flags |= (entry->vx_flags & IATTR_FLAGS); + else + *flags |= (PROC_I(in)->vx_flags & IATTR_FLAGS); + break; + + case DEVPTS_SUPER_MAGIC: + *tag = in->i_tag; + *mask |= IATTR_TAG; + break; + + default: + break; + } + return 0; +} + +int vc_get_iattr(void __user *data) +{ + struct path path; + struct vcmd_ctx_iattr_v1 vc_data = { .tag = -1 }; + int ret; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_lpath(vc_data.name, &path); + if (!ret) { + ret = __vc_get_iattr(path.dentry->d_inode, + &vc_data.tag, &vc_data.flags, &vc_data.mask); + path_put(&path); + } + if (ret) + return ret; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + ret = -EFAULT; + return ret; +} + +#ifdef CONFIG_COMPAT + +int vc_get_iattr_x32(void __user *data) +{ + struct path path; + struct vcmd_ctx_iattr_v1_x32 vc_data = { .tag = -1 }; + int ret; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_lpath(compat_ptr(vc_data.name_ptr), &path); + if (!ret) { + ret = __vc_get_iattr(path.dentry->d_inode, + &vc_data.tag, &vc_data.flags, &vc_data.mask); + path_put(&path); + } + if (ret) + return ret; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + ret = -EFAULT; + return ret; +} + +#endif /* CONFIG_COMPAT */ + + +int vc_fget_iattr(uint32_t fd, void __user *data) +{ + struct file *filp; + struct vcmd_ctx_fiattr_v0 vc_data = { .tag = -1 }; + int ret; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + filp = fget(fd); + if (!filp || !filp->f_dentry || !filp->f_dentry->d_inode) + return -EBADF; + + ret = __vc_get_iattr(filp->f_dentry->d_inode, + &vc_data.tag, &vc_data.flags, &vc_data.mask); + + fput(filp); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + ret = -EFAULT; + return ret; +} + + +static int __vc_set_iattr(struct dentry *de, uint32_t *tag, uint32_t *flags, uint32_t *mask) +{ + struct inode *in = de->d_inode; + int error = 0, is_proc = 0, has_tag = 0; + struct iattr attr = { 0 }; + + if (!in || !in->i_sb) + return -ESRCH; + + is_proc = (in->i_sb->s_magic == PROC_SUPER_MAGIC); + if ((*mask & IATTR_FLAGS) && !is_proc) + return -EINVAL; + + has_tag = IS_TAGGED(in) || + (in->i_sb->s_magic == DEVPTS_SUPER_MAGIC); + if ((*mask & IATTR_TAG) && !has_tag) + return -EINVAL; + + mutex_lock(&in->i_mutex); + if (*mask & IATTR_TAG) { + attr.ia_tag = *tag; + attr.ia_valid |= ATTR_TAG; + } + + if (*mask & IATTR_FLAGS) { + struct proc_dir_entry *entry = PROC_I(in)->pde; + unsigned int iflags = PROC_I(in)->vx_flags; + + iflags = (iflags & ~(*mask & IATTR_FLAGS)) + | (*flags & IATTR_FLAGS); + PROC_I(in)->vx_flags = iflags; + if (entry) + entry->vx_flags = iflags; + } + + if (*mask & (IATTR_BARRIER | IATTR_IXUNLINK | IATTR_IMMUTABLE)) { + if (*mask & IATTR_IMMUTABLE) { + if (*flags & IATTR_IMMUTABLE) + in->i_flags |= S_IMMUTABLE; + else + in->i_flags &= ~S_IMMUTABLE; + } + if (*mask & IATTR_IXUNLINK) { + if (*flags & IATTR_IXUNLINK) + in->i_flags |= S_IXUNLINK; + else + in->i_flags &= ~S_IXUNLINK; + } + if (S_ISDIR(in->i_mode) && (*mask & IATTR_BARRIER)) { + if (*flags & IATTR_BARRIER) + in->i_vflags |= V_BARRIER; + else + in->i_vflags &= ~V_BARRIER; + } + if (in->i_op && in->i_op->sync_flags) { + error = in->i_op->sync_flags(in); + if (error) + goto out; + } + } + + if (attr.ia_valid) { + if (in->i_op && in->i_op->setattr) + error = in->i_op->setattr(de, &attr); + else { + error = inode_change_ok(in, &attr); + if (!error) + error = inode_setattr(in, &attr); + } + } + +out: + mutex_unlock(&in->i_mutex); + return error; +} + +int vc_set_iattr(void __user *data) +{ + struct path path; + struct vcmd_ctx_iattr_v1 vc_data; + int ret; + + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_lpath(vc_data.name, &path); + if (!ret) { + ret = __vc_set_iattr(path.dentry, + &vc_data.tag, &vc_data.flags, &vc_data.mask); + path_put(&path); + } + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + ret = -EFAULT; + return ret; +} + +#ifdef CONFIG_COMPAT + +int vc_set_iattr_x32(void __user *data) +{ + struct path path; + struct vcmd_ctx_iattr_v1_x32 vc_data; + int ret; + + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = user_lpath(compat_ptr(vc_data.name_ptr), &path); + if (!ret) { + ret = __vc_set_iattr(path.dentry, + &vc_data.tag, &vc_data.flags, &vc_data.mask); + path_put(&path); + } + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + ret = -EFAULT; + return ret; +} + +#endif /* CONFIG_COMPAT */ + +int vc_fset_iattr(uint32_t fd, void __user *data) +{ + struct file *filp; + struct vcmd_ctx_fiattr_v0 vc_data; + int ret; + + if (!capable(CAP_LINUX_IMMUTABLE)) + return -EPERM; + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + filp = fget(fd); + if (!filp || !filp->f_dentry || !filp->f_dentry->d_inode) + return -EBADF; + + ret = __vc_set_iattr(filp->f_dentry, &vc_data.tag, + &vc_data.flags, &vc_data.mask); + + fput(filp); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + + +enum { Opt_notagcheck, Opt_tag, Opt_notag, Opt_tagid, Opt_err }; + +static match_table_t tokens = { + {Opt_notagcheck, "notagcheck"}, +#ifdef CONFIG_PROPAGATE + {Opt_notag, "notag"}, + {Opt_tag, "tag"}, + {Opt_tagid, "tagid=%u"}, +#endif + {Opt_err, NULL} +}; + + +static void __dx_parse_remove(char *string, char *opt) +{ + char *p = strstr(string, opt); + char *q = p; + + if (p) { + while (*q != '\0' && *q != ',') + q++; + while (*q) + *p++ = *q++; + while (*p) + *p++ = '\0'; + } +} + +int dx_parse_tag(char *string, tag_t *tag, int remove, int *mnt_flags, + unsigned long *flags) +{ + int set = 0; + substring_t args[MAX_OPT_ARGS]; + int token, option = 0; + char *s, *p, *opts; + + if (!string) + return 0; + s = kstrdup(string, GFP_KERNEL | GFP_ATOMIC); + if (!s) + return 0; + + opts = s; + while ((p = strsep(&opts, ",")) != NULL) { + token = match_token(p, tokens, args); + + vxdprintk(VXD_CBIT(tag, 7), + "dx_parse_tag(»%s«): %d:#%d", + p, token, option); + + switch (token) { +#ifdef CONFIG_PROPAGATE + case Opt_tag: + if (tag) + *tag = 0; + if (remove) + __dx_parse_remove(s, "tag"); + *mnt_flags |= MNT_TAGID; + set |= MNT_TAGID; + break; + case Opt_notag: + if (remove) + __dx_parse_remove(s, "notag"); + *mnt_flags |= MNT_NOTAG; + set |= MNT_NOTAG; + break; + case Opt_tagid: + if (tag && !match_int(args, &option)) + *tag = option; + if (remove) + __dx_parse_remove(s, "tagid"); + *mnt_flags |= MNT_TAGID; + set |= MNT_TAGID; + break; +#endif + case Opt_notagcheck: + if (remove) + __dx_parse_remove(s, "notagcheck"); + *flags |= MS_NOTAGCHECK; + set |= MS_NOTAGCHECK; + break; + } + } + if (set) + strcpy(string, s); + kfree(s); + return set; +} + +#ifdef CONFIG_PROPAGATE + +void __dx_propagate_tag(struct nameidata *nd, struct inode *inode) +{ + tag_t new_tag = 0; + struct vfsmount *mnt; + int propagate; + + if (!nd) + return; + mnt = nd->path.mnt; + if (!mnt) + return; + + propagate = (mnt->mnt_flags & MNT_TAGID); + if (propagate) + new_tag = mnt->mnt_tag; + + vxdprintk(VXD_CBIT(tag, 7), + "dx_propagate_tag(%p[#%lu.%d]): %d,%d", + inode, inode->i_ino, inode->i_tag, + new_tag, (propagate) ? 1 : 0); + + if (propagate) + inode->i_tag = new_tag; +} + +#include + +EXPORT_SYMBOL_GPL(__dx_propagate_tag); + +#endif /* CONFIG_PROPAGATE */ + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/Kconfig linux-2.6.27.15-g-v/kernel/vserver/Kconfig --- linux-2.6.27.15/kernel/vserver/Kconfig 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/Kconfig 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,251 @@ +# +# Linux VServer configuration +# + +menu "Linux VServer" + +config VSERVER_AUTO_LBACK + bool "Automatically Assign Loopback IP" + default y + help + Automatically assign a guest specific loopback + IP and add it to the kernel network stack on + startup. + +config VSERVER_AUTO_SINGLE + bool "Automatic Single IP Special Casing" + depends on EXPERIMENTAL + default y + help + This allows network contexts with a single IP to + automatically remap 0.0.0.0 bindings to that IP, + avoiding further network checks and improving + performance. + + (note: such guests do not allow to change the ip + on the fly and do not show loopback addresses) + +config VSERVER_COWBL + bool "Enable COW Immutable Link Breaking" + default y + help + This enables the COW (Copy-On-Write) link break code. + It allows you to treat unified files like normal files + when writing to them (which will implicitely break the + link and create a copy of the unified file) + +config VSERVER_VTIME + bool "Enable Virtualized Guest Time" + depends on EXPERIMENTAL + default n + help + This enables per guest time offsets to allow for + adjusting the system clock individually per guest. + this adds some overhead to the time functions and + therefore should not be enabled without good reason. + +config VSERVER_DEVICE + bool "Enable Guest Device Mapping" + depends on EXPERIMENTAL + default n + help + This enables generic device remapping. + +config VSERVER_PROC_SECURE + bool "Enable Proc Security" + depends on PROC_FS + default y + help + This configures ProcFS security to initially hide + non-process entries for all contexts except the main and + spectator context (i.e. for all guests), which is a secure + default. + + (note: on 1.2x the entries were visible by default) + +config VSERVER_HARDCPU + bool "Enable Hard CPU Limits" + default y + help + Activate the Hard CPU Limits + + This will compile in code that allows the Token Bucket + Scheduler to put processes on hold when a context's + tokens are depleted (provided that its per-context + sched_hard flag is set). + + Processes belonging to that context will not be able + to consume CPU resources again until a per-context + configured minimum of tokens has been reached. + +config VSERVER_IDLETIME + bool "Avoid idle CPUs by skipping Time" + depends on VSERVER_HARDCPU + default y + help + This option allows the scheduler to artificially + advance time (per cpu) when otherwise the idle + task would be scheduled, thus keeping the cpu + busy and sharing the available resources among + certain contexts. + +config VSERVER_IDLELIMIT + bool "Limit the IDLE task" + depends on VSERVER_HARDCPU + default n + help + Limit the idle slices, so the the next context + will be scheduled as soon as possible. + + This might improve interactivity and latency, but + will also marginally increase scheduling overhead. + +choice + prompt "Persistent Inode Tagging" + default TAGGING_ID24 + help + This adds persistent context information to filesystems + mounted with the tagxid option. Tagging is a requirement + for per-context disk limits and per-context quota. + + +config TAGGING_NONE + bool "Disabled" + help + do not store per-context information in inodes. + +config TAGGING_UID16 + bool "UID16/GID32" + help + reduces UID to 16 bit, but leaves GID at 32 bit. + +config TAGGING_GID16 + bool "UID32/GID16" + help + reduces GID to 16 bit, but leaves UID at 32 bit. + +config TAGGING_ID24 + bool "UID24/GID24" + help + uses the upper 8bit from UID and GID for XID tagging + which leaves 24bit for UID/GID each, which should be + more than sufficient for normal use. + +config TAGGING_INTERN + bool "UID32/GID32" + help + this uses otherwise reserved inode fields in the on + disk representation, which limits the use to a few + filesystems (currently ext2 and ext3) + +endchoice + +config TAG_NFSD + bool "Tag NFSD User Auth and Files" + default n + help + Enable this if you do want the in-kernel NFS + Server to use the tagging specified above. + (will require patched clients too) + +config VSERVER_PRIVACY + bool "Honor Privacy Aspects of Guests" + default n + help + When enabled, most context checks will disallow + access to structures assigned to a specific context, + like ptys or loop devices. + +config VSERVER_CONTEXTS + int "Maximum number of Contexts (1-65533)" if EMBEDDED + range 1 65533 + default "768" if 64BIT + default "256" + help + This setting will optimize certain data structures + and memory allocations according to the expected + maximum. + + note: this is not a strict upper limit. + +config VSERVER_WARN + bool "VServer Warnings" + default y + help + This enables various runtime warnings, which will + notify about potential manipulation attempts or + resource shortage. It is generally considered to + be a good idea to have that enabled. + +config VSERVER_DEBUG + bool "VServer Debugging Code" + default n + help + Set this to yes if you want to be able to activate + debugging output at runtime. It adds a very small + overhead to all vserver related functions and + increases the kernel size by about 20k. + +config VSERVER_HISTORY + bool "VServer History Tracing" + depends on VSERVER_DEBUG + default n + help + Set this to yes if you want to record the history of + linux-vserver activities, so they can be replayed in + the event of a kernel panic or oops. + +config VSERVER_HISTORY_SIZE + int "Per-CPU History Size (32-65536)" + depends on VSERVER_HISTORY + range 32 65536 + default 64 + help + This allows you to specify the number of entries in + the per-CPU history buffer. + +config VSERVER_MONITOR + bool "VServer Scheduling Monitor" + depends on VSERVER_DISABLED + default n + help + Set this to yes if you want to record the scheduling + decisions, so that they can be relayed to userspace + for detailed analysis. + +config VSERVER_MONITOR_SIZE + int "Per-CPU Monitor Queue Size (32-65536)" + depends on VSERVER_MONITOR + range 32 65536 + default 1024 + help + This allows you to specify the number of entries in + the per-CPU scheduling monitor buffer. + +config VSERVER_MONITOR_SYNC + int "Per-CPU Monitor Sync Interval (0-65536)" + depends on VSERVER_MONITOR + range 0 65536 + default 256 + help + This allows you to specify the interval in ticks + when a time sync entry is inserted. + +endmenu + + +config VSERVER + bool + default y + select NAMESPACES + select UTS_NS + select IPC_NS + select USER_NS + select SYSVIPC + +config VSERVER_SECURITY + bool + depends on SECURITY + default y + select SECURITY_CAPABILITIES + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/limit.c linux-2.6.27.15-g-v/kernel/vserver/limit.c --- linux-2.6.27.15/kernel/vserver/limit.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/limit.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,319 @@ +/* + * linux/kernel/vserver/limit.c + * + * Virtual Server: Context Limits + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 broken out from vcontext V0.05 + * V0.02 changed vcmds to vxi arg + * + */ + +#include +#include +#include +#include +#include + +#include + + +const char *vlimit_name[NUM_LIMITS] = { + [RLIMIT_CPU] = "CPU", + [RLIMIT_RSS] = "RSS", + [RLIMIT_NPROC] = "NPROC", + [RLIMIT_NOFILE] = "NOFILE", + [RLIMIT_MEMLOCK] = "VML", + [RLIMIT_AS] = "VM", + [RLIMIT_LOCKS] = "LOCKS", + [RLIMIT_SIGPENDING] = "SIGP", + [RLIMIT_MSGQUEUE] = "MSGQ", + + [VLIMIT_NSOCK] = "NSOCK", + [VLIMIT_OPENFD] = "OPENFD", + [VLIMIT_ANON] = "ANON", + [VLIMIT_SHMEM] = "SHMEM", + [VLIMIT_DENTRY] = "DENTRY", +}; + +EXPORT_SYMBOL_GPL(vlimit_name); + +#define MASK_ENTRY(x) (1 << (x)) + +const struct vcmd_ctx_rlimit_mask_v0 vlimit_mask = { + /* minimum */ + 0 + , /* softlimit */ + MASK_ENTRY( RLIMIT_RSS ) | + MASK_ENTRY( VLIMIT_ANON ) | + 0 + , /* maximum */ + MASK_ENTRY( RLIMIT_RSS ) | + MASK_ENTRY( RLIMIT_NPROC ) | + MASK_ENTRY( RLIMIT_NOFILE ) | + MASK_ENTRY( RLIMIT_MEMLOCK ) | + MASK_ENTRY( RLIMIT_AS ) | + MASK_ENTRY( RLIMIT_LOCKS ) | + MASK_ENTRY( RLIMIT_MSGQUEUE ) | + + MASK_ENTRY( VLIMIT_NSOCK ) | + MASK_ENTRY( VLIMIT_OPENFD ) | + MASK_ENTRY( VLIMIT_ANON ) | + MASK_ENTRY( VLIMIT_SHMEM ) | + MASK_ENTRY( VLIMIT_DENTRY ) | + 0 +}; + /* accounting only */ +uint32_t account_mask = + MASK_ENTRY( VLIMIT_SEMARY ) | + MASK_ENTRY( VLIMIT_NSEMS ) | + MASK_ENTRY( VLIMIT_MAPPED ) | + 0; + + +static int is_valid_vlimit(int id) +{ + uint32_t mask = vlimit_mask.minimum | + vlimit_mask.softlimit | vlimit_mask.maximum; + return mask & (1 << id); +} + +static int is_accounted_vlimit(int id) +{ + if (is_valid_vlimit(id)) + return 1; + return account_mask & (1 << id); +} + + +static inline uint64_t vc_get_soft(struct vx_info *vxi, int id) +{ + rlim_t limit = __rlim_soft(&vxi->limit, id); + return VX_VLIM(limit); +} + +static inline uint64_t vc_get_hard(struct vx_info *vxi, int id) +{ + rlim_t limit = __rlim_hard(&vxi->limit, id); + return VX_VLIM(limit); +} + +static int do_get_rlimit(struct vx_info *vxi, uint32_t id, + uint64_t *minimum, uint64_t *softlimit, uint64_t *maximum) +{ + if (!is_valid_vlimit(id)) + return -EINVAL; + + if (minimum) + *minimum = CRLIM_UNSET; + if (softlimit) + *softlimit = vc_get_soft(vxi, id); + if (maximum) + *maximum = vc_get_hard(vxi, id); + return 0; +} + +int vc_get_rlimit(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_rlimit_v0 vc_data; + int ret; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_get_rlimit(vxi, vc_data.id, + &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum); + if (ret) + return ret; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +static int do_set_rlimit(struct vx_info *vxi, uint32_t id, + uint64_t minimum, uint64_t softlimit, uint64_t maximum) +{ + if (!is_valid_vlimit(id)) + return -EINVAL; + + if (maximum != CRLIM_KEEP) + __rlim_hard(&vxi->limit, id) = VX_RLIM(maximum); + if (softlimit != CRLIM_KEEP) + __rlim_soft(&vxi->limit, id) = VX_RLIM(softlimit); + + /* clamp soft limit */ + if (__rlim_soft(&vxi->limit, id) > __rlim_hard(&vxi->limit, id)) + __rlim_soft(&vxi->limit, id) = __rlim_hard(&vxi->limit, id); + + return 0; +} + +int vc_set_rlimit(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_rlimit_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_rlimit(vxi, vc_data.id, + vc_data.minimum, vc_data.softlimit, vc_data.maximum); +} + +#ifdef CONFIG_IA32_EMULATION + +int vc_set_rlimit_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_rlimit_v0_x32 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_rlimit(vxi, vc_data.id, + vc_data.minimum, vc_data.softlimit, vc_data.maximum); +} + +int vc_get_rlimit_x32(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_rlimit_v0_x32 vc_data; + int ret; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_get_rlimit(vxi, vc_data.id, + &vc_data.minimum, &vc_data.softlimit, &vc_data.maximum); + if (ret) + return ret; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +#endif /* CONFIG_IA32_EMULATION */ + + +int vc_get_rlimit_mask(uint32_t id, void __user *data) +{ + if (copy_to_user(data, &vlimit_mask, sizeof(vlimit_mask))) + return -EFAULT; + return 0; +} + + +static inline void vx_reset_minmax(struct _vx_limit *limit) +{ + rlim_t value; + int lim; + + for (lim = 0; lim < NUM_LIMITS; lim++) { + value = __rlim_get(limit, lim); + __rlim_rmax(limit, lim) = value; + __rlim_rmin(limit, lim) = value; + } +} + + +int vc_reset_minmax(struct vx_info *vxi, void __user *data) +{ + vx_reset_minmax(&vxi->limit); + return 0; +} + + +int vc_rlimit_stat(struct vx_info *vxi, void __user *data) +{ + struct vcmd_rlimit_stat_v0 vc_data; + struct _vx_limit *limit = &vxi->limit; + int id; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + id = vc_data.id; + if (!is_accounted_vlimit(id)) + return -EINVAL; + + vx_limit_fixup(limit, id); + vc_data.hits = atomic_read(&__rlim_lhit(limit, id)); + vc_data.value = __rlim_get(limit, id); + vc_data.minimum = __rlim_rmin(limit, id); + vc_data.maximum = __rlim_rmax(limit, id); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +void vx_vsi_meminfo(struct sysinfo *val) +{ + struct vx_info *vxi = current->vx_info; + unsigned long totalram, freeram; + rlim_t v; + + /* we blindly accept the max */ + v = __rlim_soft(&vxi->limit, RLIMIT_RSS); + totalram = (v != RLIM_INFINITY) ? v : val->totalram; + + /* total minus used equals free */ + v = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); + freeram = (v < totalram) ? totalram - v : 0; + + val->totalram = totalram; + val->freeram = freeram; + val->bufferram = 0; + val->totalhigh = 0; + val->freehigh = 0; + return; +} + +void vx_vsi_swapinfo(struct sysinfo *val) +{ + struct vx_info *vxi = current->vx_info; + unsigned long totalswap, freeswap; + rlim_t v, w; + + v = __rlim_soft(&vxi->limit, RLIMIT_RSS); + if (v == RLIM_INFINITY) { + val->freeswap = val->totalswap; + return; + } + + /* we blindly accept the max */ + w = __rlim_hard(&vxi->limit, RLIMIT_RSS); + totalswap = (w != RLIM_INFINITY) ? (w - v) : val->totalswap; + + /* currently 'used' swap */ + w = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); + w -= (w > v) ? v : w; + + /* total minus used equals free */ + freeswap = (w < totalswap) ? totalswap - w : 0; + + val->totalswap = totalswap; + val->freeswap = freeswap; + return; +} + + +unsigned long vx_badness(struct task_struct *task, struct mm_struct *mm) +{ + struct vx_info *vxi = mm->mm_vx_info; + unsigned long points; + rlim_t v, w; + + if (!vxi) + return 0; + + points = vxi->vx_badness_bias; + + v = __vx_cres_array_fixup(&vxi->limit, VLA_RSS); + w = __rlim_soft(&vxi->limit, RLIMIT_RSS); + points += (v > w) ? (v - w) : 0; + + return points; +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/limit_init.h linux-2.6.27.15-g-v/kernel/vserver/limit_init.h --- linux-2.6.27.15/kernel/vserver/limit_init.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/limit_init.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,31 @@ + + +static inline void vx_info_init_limit(struct _vx_limit *limit) +{ + int lim; + + for (lim = 0; lim < NUM_LIMITS; lim++) { + __rlim_soft(limit, lim) = RLIM_INFINITY; + __rlim_hard(limit, lim) = RLIM_INFINITY; + __rlim_set(limit, lim, 0); + atomic_set(&__rlim_lhit(limit, lim), 0); + __rlim_rmin(limit, lim) = 0; + __rlim_rmax(limit, lim) = 0; + } +} + +static inline void vx_info_exit_limit(struct _vx_limit *limit) +{ + rlim_t value; + int lim; + + for (lim = 0; lim < NUM_LIMITS; lim++) { + if ((1 << lim) & VLIM_NOCHECK) + continue; + value = __rlim_get(limit, lim); + vxwprintk_xid(value, + "!!! limit: %p[%s,%d] = %ld on exit.", + limit, vlimit_name[lim], lim, (long)value); + } +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/limit_proc.h linux-2.6.27.15-g-v/kernel/vserver/limit_proc.h --- linux-2.6.27.15/kernel/vserver/limit_proc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/limit_proc.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,57 @@ +#ifndef _VX_LIMIT_PROC_H +#define _VX_LIMIT_PROC_H + +#include + + +#define VX_LIMIT_FMT ":\t%8ld\t%8ld/%8ld\t%8lld/%8lld\t%6d\n" +#define VX_LIMIT_TOP \ + "Limit\t current\t min/max\t\t soft/hard\t\thits\n" + +#define VX_LIMIT_ARG(r) \ + (unsigned long)__rlim_get(limit, r), \ + (unsigned long)__rlim_rmin(limit, r), \ + (unsigned long)__rlim_rmax(limit, r), \ + VX_VLIM(__rlim_soft(limit, r)), \ + VX_VLIM(__rlim_hard(limit, r)), \ + atomic_read(&__rlim_lhit(limit, r)) + +static inline int vx_info_proc_limit(struct _vx_limit *limit, char *buffer) +{ + vx_limit_fixup(limit, -1); + return sprintf(buffer, VX_LIMIT_TOP + "PROC" VX_LIMIT_FMT + "VM" VX_LIMIT_FMT + "VML" VX_LIMIT_FMT + "RSS" VX_LIMIT_FMT + "ANON" VX_LIMIT_FMT + "RMAP" VX_LIMIT_FMT + "FILES" VX_LIMIT_FMT + "OFD" VX_LIMIT_FMT + "LOCKS" VX_LIMIT_FMT + "SOCK" VX_LIMIT_FMT + "MSGQ" VX_LIMIT_FMT + "SHM" VX_LIMIT_FMT + "SEMA" VX_LIMIT_FMT + "SEMS" VX_LIMIT_FMT + "DENT" VX_LIMIT_FMT, + VX_LIMIT_ARG(RLIMIT_NPROC), + VX_LIMIT_ARG(RLIMIT_AS), + VX_LIMIT_ARG(RLIMIT_MEMLOCK), + VX_LIMIT_ARG(RLIMIT_RSS), + VX_LIMIT_ARG(VLIMIT_ANON), + VX_LIMIT_ARG(VLIMIT_MAPPED), + VX_LIMIT_ARG(RLIMIT_NOFILE), + VX_LIMIT_ARG(VLIMIT_OPENFD), + VX_LIMIT_ARG(RLIMIT_LOCKS), + VX_LIMIT_ARG(VLIMIT_NSOCK), + VX_LIMIT_ARG(RLIMIT_MSGQUEUE), + VX_LIMIT_ARG(VLIMIT_SHMEM), + VX_LIMIT_ARG(VLIMIT_SEMARY), + VX_LIMIT_ARG(VLIMIT_NSEMS), + VX_LIMIT_ARG(VLIMIT_DENTRY)); +} + +#endif /* _VX_LIMIT_PROC_H */ + + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/Makefile linux-2.6.27.15-g-v/kernel/vserver/Makefile --- linux-2.6.27.15/kernel/vserver/Makefile 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/Makefile 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,18 @@ +# +# Makefile for the Linux vserver routines. +# + + +obj-y += vserver.o + +vserver-y := switch.o context.o space.o sched.o network.o inode.o \ + limit.o cvirt.o cacct.o signal.o helper.o init.o \ + dlimit.o tag.o + +vserver-$(CONFIG_INET) += inet.o +vserver-$(CONFIG_PROC_FS) += proc.o +vserver-$(CONFIG_VSERVER_DEBUG) += sysctl.o debug.o +vserver-$(CONFIG_VSERVER_HISTORY) += history.o +vserver-$(CONFIG_VSERVER_MONITOR) += monitor.o +vserver-$(CONFIG_VSERVER_DEVICE) += device.o + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/monitor.c linux-2.6.27.15-g-v/kernel/vserver/monitor.c --- linux-2.6.27.15/kernel/vserver/monitor.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/monitor.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,138 @@ +/* + * kernel/vserver/monitor.c + * + * Virtual Context Scheduler Monitor + * + * Copyright (C) 2006-2007 Herbert Pötzl + * + * V0.01 basic design + * + */ + +#include +#include +#include +#include + +#include +#include + + +#ifdef CONFIG_VSERVER_MONITOR +#define VXM_SIZE CONFIG_VSERVER_MONITOR_SIZE +#else +#define VXM_SIZE 64 +#endif + +struct _vx_monitor { + unsigned int counter; + + struct _vx_mon_entry entry[VXM_SIZE+1]; +}; + + +DEFINE_PER_CPU(struct _vx_monitor, vx_monitor_buffer); + +unsigned volatile int vxm_active = 1; + +static atomic_t sequence = ATOMIC_INIT(0); + + +/* vxm_advance() + + * requires disabled preemption */ + +struct _vx_mon_entry *vxm_advance(int cpu) +{ + struct _vx_monitor *mon = &per_cpu(vx_monitor_buffer, cpu); + struct _vx_mon_entry *entry; + unsigned int index; + + index = vxm_active ? (mon->counter++ % VXM_SIZE) : VXM_SIZE; + entry = &mon->entry[index]; + + entry->ev.seq = atomic_inc_return(&sequence); + entry->ev.jif = jiffies; + return entry; +} + +EXPORT_SYMBOL_GPL(vxm_advance); + + +int do_read_monitor(struct __user _vx_mon_entry *data, + int cpu, uint32_t *index, uint32_t *count) +{ + int pos, ret = 0; + struct _vx_monitor *mon = &per_cpu(vx_monitor_buffer, cpu); + int end = mon->counter; + int start = end - VXM_SIZE + 2; + int idx = *index; + + /* special case: get current pos */ + if (!*count) { + *index = end; + return 0; + } + + /* have we lost some data? */ + if (idx < start) + idx = start; + + for (pos = 0; (pos < *count) && (idx < end); pos++, idx++) { + struct _vx_mon_entry *entry = + &mon->entry[idx % VXM_SIZE]; + + /* send entry to userspace */ + ret = copy_to_user(&data[pos], entry, sizeof(*entry)); + if (ret) + break; + } + /* save new index and count */ + *index = idx; + *count = pos; + return ret ? ret : (*index < end); +} + +int vc_read_monitor(uint32_t id, void __user *data) +{ + struct vcmd_read_monitor_v0 vc_data; + int ret; + + if (id >= NR_CPUS) + return -EINVAL; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_read_monitor((struct __user _vx_mon_entry *)vc_data.data, + id, &vc_data.index, &vc_data.count); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + +#ifdef CONFIG_COMPAT + +int vc_read_monitor_x32(uint32_t id, void __user *data) +{ + struct vcmd_read_monitor_v0_x32 vc_data; + int ret; + + if (id >= NR_CPUS) + return -EINVAL; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + ret = do_read_monitor((struct __user _vx_mon_entry *) + compat_ptr(vc_data.data_ptr), + id, &vc_data.index, &vc_data.count); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return ret; +} + +#endif /* CONFIG_COMPAT */ + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/network.c linux-2.6.27.15-g-v/kernel/vserver/network.c --- linux-2.6.27.15/kernel/vserver/network.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/network.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,864 @@ +/* + * linux/kernel/vserver/network.c + * + * Virtual Server: Network Support + * + * Copyright (C) 2003-2007 Herbert Pötzl + * + * V0.01 broken out from vcontext V0.05 + * V0.02 cleaned up implementation + * V0.03 added equiv nx commands + * V0.04 switch to RCU based hash + * V0.05 and back to locking again + * V0.06 changed vcmds to nxi arg + * V0.07 have __create claim() the nxi + * + */ + +#include +#include +#include + +#include +#include +#include + + +atomic_t nx_global_ctotal = ATOMIC_INIT(0); +atomic_t nx_global_cactive = ATOMIC_INIT(0); + +static struct kmem_cache *nx_addr_v4_cachep = NULL; +static struct kmem_cache *nx_addr_v6_cachep = NULL; + + +static int __init init_network(void) +{ + nx_addr_v4_cachep = kmem_cache_create("nx_v4_addr_cache", + sizeof(struct nx_addr_v4), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + nx_addr_v6_cachep = kmem_cache_create("nx_v6_addr_cache", + sizeof(struct nx_addr_v6), 0, + SLAB_HWCACHE_ALIGN|SLAB_PANIC, NULL); + return 0; +} + + +/* __alloc_nx_addr_v4() */ + +static inline struct nx_addr_v4 *__alloc_nx_addr_v4(void) +{ + struct nx_addr_v4 *nxa = kmem_cache_alloc( + nx_addr_v4_cachep, GFP_KERNEL); + + if (!IS_ERR(nxa)) + memset(nxa, 0, sizeof(*nxa)); + return nxa; +} + +/* __dealloc_nx_addr_v4() */ + +static inline void __dealloc_nx_addr_v4(struct nx_addr_v4 *nxa) +{ + kmem_cache_free(nx_addr_v4_cachep, nxa); +} + +/* __dealloc_nx_addr_v4_all() */ + +static inline void __dealloc_nx_addr_v4_all(struct nx_addr_v4 *nxa) +{ + while (nxa) { + struct nx_addr_v4 *next = nxa->next; + + __dealloc_nx_addr_v4(nxa); + nxa = next; + } +} + + +#ifdef CONFIG_IPV6 + +/* __alloc_nx_addr_v6() */ + +static inline struct nx_addr_v6 *__alloc_nx_addr_v6(void) +{ + struct nx_addr_v6 *nxa = kmem_cache_alloc( + nx_addr_v6_cachep, GFP_KERNEL); + + if (!IS_ERR(nxa)) + memset(nxa, 0, sizeof(*nxa)); + return nxa; +} + +/* __dealloc_nx_addr_v6() */ + +static inline void __dealloc_nx_addr_v6(struct nx_addr_v6 *nxa) +{ + kmem_cache_free(nx_addr_v6_cachep, nxa); +} + +/* __dealloc_nx_addr_v6_all() */ + +static inline void __dealloc_nx_addr_v6_all(struct nx_addr_v6 *nxa) +{ + while (nxa) { + struct nx_addr_v6 *next = nxa->next; + + __dealloc_nx_addr_v6(nxa); + nxa = next; + } +} + +#endif /* CONFIG_IPV6 */ + +/* __alloc_nx_info() + + * allocate an initialized nx_info struct + * doesn't make it visible (hash) */ + +static struct nx_info *__alloc_nx_info(nid_t nid) +{ + struct nx_info *new = NULL; + + vxdprintk(VXD_CBIT(nid, 1), "alloc_nx_info(%d)*", nid); + + /* would this benefit from a slab cache? */ + new = kmalloc(sizeof(struct nx_info), GFP_KERNEL); + if (!new) + return 0; + + memset(new, 0, sizeof(struct nx_info)); + new->nx_id = nid; + INIT_HLIST_NODE(&new->nx_hlist); + atomic_set(&new->nx_usecnt, 0); + atomic_set(&new->nx_tasks, 0); + new->nx_state = 0; + + new->nx_flags = NXF_INIT_SET; + + /* rest of init goes here */ + + new->v4_lback.s_addr = htonl(INADDR_LOOPBACK); + new->v4_bcast.s_addr = htonl(INADDR_BROADCAST); + + vxdprintk(VXD_CBIT(nid, 0), + "alloc_nx_info(%d) = %p", nid, new); + atomic_inc(&nx_global_ctotal); + return new; +} + +/* __dealloc_nx_info() + + * final disposal of nx_info */ + +static void __dealloc_nx_info(struct nx_info *nxi) +{ + vxdprintk(VXD_CBIT(nid, 0), + "dealloc_nx_info(%p)", nxi); + + nxi->nx_hlist.next = LIST_POISON1; + nxi->nx_id = -1; + + BUG_ON(atomic_read(&nxi->nx_usecnt)); + BUG_ON(atomic_read(&nxi->nx_tasks)); + + __dealloc_nx_addr_v4_all(nxi->v4.next); + + nxi->nx_state |= NXS_RELEASED; + kfree(nxi); + atomic_dec(&nx_global_ctotal); +} + +static void __shutdown_nx_info(struct nx_info *nxi) +{ + nxi->nx_state |= NXS_SHUTDOWN; + vs_net_change(nxi, VSC_NETDOWN); +} + +/* exported stuff */ + +void free_nx_info(struct nx_info *nxi) +{ + /* context shutdown is mandatory */ + BUG_ON(nxi->nx_state != NXS_SHUTDOWN); + + /* context must not be hashed */ + BUG_ON(nxi->nx_state & NXS_HASHED); + + BUG_ON(atomic_read(&nxi->nx_usecnt)); + BUG_ON(atomic_read(&nxi->nx_tasks)); + + __dealloc_nx_info(nxi); +} + + +void __nx_set_lback(struct nx_info *nxi) +{ + int nid = nxi->nx_id; + __be32 lback = htonl(INADDR_LOOPBACK ^ ((nid & 0xFFFF) << 8)); + + nxi->v4_lback.s_addr = lback; +} + +extern int __nx_inet_add_lback(__be32 addr); +extern int __nx_inet_del_lback(__be32 addr); + + +/* hash table for nx_info hash */ + +#define NX_HASH_SIZE 13 + +struct hlist_head nx_info_hash[NX_HASH_SIZE]; + +static spinlock_t nx_info_hash_lock = SPIN_LOCK_UNLOCKED; + + +static inline unsigned int __hashval(nid_t nid) +{ + return (nid % NX_HASH_SIZE); +} + + + +/* __hash_nx_info() + + * add the nxi to the global hash table + * requires the hash_lock to be held */ + +static inline void __hash_nx_info(struct nx_info *nxi) +{ + struct hlist_head *head; + + vxd_assert_lock(&nx_info_hash_lock); + vxdprintk(VXD_CBIT(nid, 4), + "__hash_nx_info: %p[#%d]", nxi, nxi->nx_id); + + /* context must not be hashed */ + BUG_ON(nx_info_state(nxi, NXS_HASHED)); + + nxi->nx_state |= NXS_HASHED; + head = &nx_info_hash[__hashval(nxi->nx_id)]; + hlist_add_head(&nxi->nx_hlist, head); + atomic_inc(&nx_global_cactive); +} + +/* __unhash_nx_info() + + * remove the nxi from the global hash table + * requires the hash_lock to be held */ + +static inline void __unhash_nx_info(struct nx_info *nxi) +{ + vxd_assert_lock(&nx_info_hash_lock); + vxdprintk(VXD_CBIT(nid, 4), + "__unhash_nx_info: %p[#%d.%d.%d]", nxi, nxi->nx_id, + atomic_read(&nxi->nx_usecnt), atomic_read(&nxi->nx_tasks)); + + /* context must be hashed */ + BUG_ON(!nx_info_state(nxi, NXS_HASHED)); + /* but without tasks */ + BUG_ON(atomic_read(&nxi->nx_tasks)); + + nxi->nx_state &= ~NXS_HASHED; + hlist_del(&nxi->nx_hlist); + atomic_dec(&nx_global_cactive); +} + + +/* __lookup_nx_info() + + * requires the hash_lock to be held + * doesn't increment the nx_refcnt */ + +static inline struct nx_info *__lookup_nx_info(nid_t nid) +{ + struct hlist_head *head = &nx_info_hash[__hashval(nid)]; + struct hlist_node *pos; + struct nx_info *nxi; + + vxd_assert_lock(&nx_info_hash_lock); + hlist_for_each(pos, head) { + nxi = hlist_entry(pos, struct nx_info, nx_hlist); + + if (nxi->nx_id == nid) + goto found; + } + nxi = NULL; +found: + vxdprintk(VXD_CBIT(nid, 0), + "__lookup_nx_info(#%u): %p[#%u]", + nid, nxi, nxi ? nxi->nx_id : 0); + return nxi; +} + + +/* __create_nx_info() + + * create the requested context + * get(), claim() and hash it */ + +static struct nx_info *__create_nx_info(int id) +{ + struct nx_info *new, *nxi = NULL; + + vxdprintk(VXD_CBIT(nid, 1), "create_nx_info(%d)*", id); + + if (!(new = __alloc_nx_info(id))) + return ERR_PTR(-ENOMEM); + + /* required to make dynamic xids unique */ + spin_lock(&nx_info_hash_lock); + + /* static context requested */ + if ((nxi = __lookup_nx_info(id))) { + vxdprintk(VXD_CBIT(nid, 0), + "create_nx_info(%d) = %p (already there)", id, nxi); + if (nx_info_flags(nxi, NXF_STATE_SETUP, 0)) + nxi = ERR_PTR(-EBUSY); + else + nxi = ERR_PTR(-EEXIST); + goto out_unlock; + } + /* new context */ + vxdprintk(VXD_CBIT(nid, 0), + "create_nx_info(%d) = %p (new)", id, new); + claim_nx_info(new, NULL); + __nx_set_lback(new); + __hash_nx_info(get_nx_info(new)); + nxi = new, new = NULL; + +out_unlock: + spin_unlock(&nx_info_hash_lock); + if (new) + __dealloc_nx_info(new); + return nxi; +} + + + +/* exported stuff */ + + +void unhash_nx_info(struct nx_info *nxi) +{ + __shutdown_nx_info(nxi); + spin_lock(&nx_info_hash_lock); + __unhash_nx_info(nxi); + spin_unlock(&nx_info_hash_lock); +} + +/* lookup_nx_info() + + * search for a nx_info and get() it + * negative id means current */ + +struct nx_info *lookup_nx_info(int id) +{ + struct nx_info *nxi = NULL; + + if (id < 0) { + nxi = get_nx_info(current->nx_info); + } else if (id > 1) { + spin_lock(&nx_info_hash_lock); + nxi = get_nx_info(__lookup_nx_info(id)); + spin_unlock(&nx_info_hash_lock); + } + return nxi; +} + +/* nid_is_hashed() + + * verify that nid is still hashed */ + +int nid_is_hashed(nid_t nid) +{ + int hashed; + + spin_lock(&nx_info_hash_lock); + hashed = (__lookup_nx_info(nid) != NULL); + spin_unlock(&nx_info_hash_lock); + return hashed; +} + + +#ifdef CONFIG_PROC_FS + +/* get_nid_list() + + * get a subset of hashed nids for proc + * assumes size is at least one */ + +int get_nid_list(int index, unsigned int *nids, int size) +{ + int hindex, nr_nids = 0; + + /* only show current and children */ + if (!nx_check(0, VS_ADMIN | VS_WATCH)) { + if (index > 0) + return 0; + nids[nr_nids] = nx_current_nid(); + return 1; + } + + for (hindex = 0; hindex < NX_HASH_SIZE; hindex++) { + struct hlist_head *head = &nx_info_hash[hindex]; + struct hlist_node *pos; + + spin_lock(&nx_info_hash_lock); + hlist_for_each(pos, head) { + struct nx_info *nxi; + + if (--index > 0) + continue; + + nxi = hlist_entry(pos, struct nx_info, nx_hlist); + nids[nr_nids] = nxi->nx_id; + if (++nr_nids >= size) { + spin_unlock(&nx_info_hash_lock); + goto out; + } + } + /* keep the lock time short */ + spin_unlock(&nx_info_hash_lock); + } +out: + return nr_nids; +} +#endif + + +/* + * migrate task to new network + * gets nxi, puts old_nxi on change + */ + +int nx_migrate_task(struct task_struct *p, struct nx_info *nxi) +{ + struct nx_info *old_nxi; + int ret = 0; + + if (!p || !nxi) + BUG(); + + vxdprintk(VXD_CBIT(nid, 5), + "nx_migrate_task(%p,%p[#%d.%d.%d])", + p, nxi, nxi->nx_id, + atomic_read(&nxi->nx_usecnt), + atomic_read(&nxi->nx_tasks)); + + if (nx_info_flags(nxi, NXF_INFO_PRIVATE, 0) && + !nx_info_flags(nxi, NXF_STATE_SETUP, 0)) + return -EACCES; + + if (nx_info_state(nxi, NXS_SHUTDOWN)) + return -EFAULT; + + /* maybe disallow this completely? */ + old_nxi = task_get_nx_info(p); + if (old_nxi == nxi) + goto out; + + task_lock(p); + if (old_nxi) + clr_nx_info(&p->nx_info); + claim_nx_info(nxi, p); + set_nx_info(&p->nx_info, nxi); + p->nid = nxi->nx_id; + task_unlock(p); + + vxdprintk(VXD_CBIT(nid, 5), + "moved task %p into nxi:%p[#%d]", + p, nxi, nxi->nx_id); + + if (old_nxi) + release_nx_info(old_nxi, p); + ret = 0; +out: + put_nx_info(old_nxi); + return ret; +} + + +void nx_set_persistent(struct nx_info *nxi) +{ + vxdprintk(VXD_CBIT(nid, 6), + "nx_set_persistent(%p[#%d])", nxi, nxi->nx_id); + + get_nx_info(nxi); + claim_nx_info(nxi, NULL); +} + +void nx_clear_persistent(struct nx_info *nxi) +{ + vxdprintk(VXD_CBIT(nid, 6), + "nx_clear_persistent(%p[#%d])", nxi, nxi->nx_id); + + release_nx_info(nxi, NULL); + put_nx_info(nxi); +} + +void nx_update_persistent(struct nx_info *nxi) +{ + if (nx_info_flags(nxi, NXF_PERSISTENT, 0)) + nx_set_persistent(nxi); + else + nx_clear_persistent(nxi); +} + +/* vserver syscall commands below here */ + +/* taks nid and nx_info functions */ + +#include + + +int vc_task_nid(uint32_t id) +{ + nid_t nid; + + if (id) { + struct task_struct *tsk; + + read_lock(&tasklist_lock); + tsk = find_task_by_real_pid(id); + nid = (tsk) ? tsk->nid : -ESRCH; + read_unlock(&tasklist_lock); + } else + nid = nx_current_nid(); + return nid; +} + + +int vc_nx_info(struct nx_info *nxi, void __user *data) +{ + struct vcmd_nx_info_v0 vc_data; + + vc_data.nid = nxi->nx_id; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +/* network functions */ + +int vc_net_create(uint32_t nid, void __user *data) +{ + struct vcmd_net_create vc_data = { .flagword = NXF_INIT_SET }; + struct nx_info *new_nxi; + int ret; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + if ((nid > MAX_S_CONTEXT) || (nid < 2)) + return -EINVAL; + + new_nxi = __create_nx_info(nid); + if (IS_ERR(new_nxi)) + return PTR_ERR(new_nxi); + + /* initial flags */ + new_nxi->nx_flags = vc_data.flagword; + + ret = -ENOEXEC; + if (vs_net_change(new_nxi, VSC_NETUP)) + goto out; + + ret = nx_migrate_task(current, new_nxi); + if (ret) + goto out; + + /* return context id on success */ + ret = new_nxi->nx_id; + + /* get a reference for persistent contexts */ + if ((vc_data.flagword & NXF_PERSISTENT)) + nx_set_persistent(new_nxi); +out: + release_nx_info(new_nxi, NULL); + put_nx_info(new_nxi); + return ret; +} + + +int vc_net_migrate(struct nx_info *nxi, void __user *data) +{ + return nx_migrate_task(current, nxi); +} + + + +int do_add_v4_addr(struct nx_info *nxi, __be32 ip, __be32 ip2, __be32 mask, + uint16_t type, uint16_t flags) +{ + struct nx_addr_v4 *nxa = &nxi->v4; + + if (NX_IPV4(nxi)) { + /* locate last entry */ + for (; nxa->next; nxa = nxa->next); + nxa->next = __alloc_nx_addr_v4(); + nxa = nxa->next; + + if (IS_ERR(nxa)) + return PTR_ERR(nxa); + } + + if (nxi->v4.next) + /* remove single ip for ip list */ + nxi->nx_flags &= ~NXF_SINGLE_IP; + + nxa->ip[0].s_addr = ip; + nxa->ip[1].s_addr = ip2; + nxa->mask.s_addr = mask; + nxa->type = type; + nxa->flags = flags; + return 0; +} + + +int vc_net_add(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_addr_v0 vc_data; + int index, ret = 0; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + switch (vc_data.type) { + case NXA_TYPE_IPV4: + if ((vc_data.count < 1) || (vc_data.count > 4)) + return -EINVAL; + + index = 0; + while (index < vc_data.count) { + ret = do_add_v4_addr(nxi, vc_data.ip[index].s_addr, 0, + vc_data.mask[index].s_addr, NXA_TYPE_ADDR, 0); + if (ret) + return ret; + index++; + } + ret = index; + break; + + case NXA_TYPE_IPV4|NXA_MOD_BCAST: + nxi->v4_bcast = vc_data.ip[0]; + ret = 1; + break; + + case NXA_TYPE_IPV4|NXA_MOD_LBACK: + nxi->v4_lback = vc_data.ip[0]; + ret = 1; + break; + + default: + ret = -EINVAL; + break; + } + return ret; +} + +int vc_net_remove(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_addr_v0 vc_data; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + switch (vc_data.type) { + case NXA_TYPE_ANY: + __dealloc_nx_addr_v4_all(xchg(&nxi->v4.next, NULL)); + memset(&nxi->v4, 0, sizeof(nxi->v4)); + break; + + default: + return -EINVAL; + } + return 0; +} + + +int vc_net_add_ipv4(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_addr_ipv4_v1 vc_data; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + switch (vc_data.type) { + case NXA_TYPE_ADDR: + case NXA_TYPE_RANGE: + case NXA_TYPE_MASK: + return do_add_v4_addr(nxi, vc_data.ip.s_addr, 0, + vc_data.mask.s_addr, vc_data.type, vc_data.flags); + + case NXA_TYPE_ADDR | NXA_MOD_BCAST: + nxi->v4_bcast = vc_data.ip; + break; + + case NXA_TYPE_ADDR | NXA_MOD_LBACK: + nxi->v4_lback = vc_data.ip; + break; + + default: + return -EINVAL; + } + return 0; +} + +int vc_net_remove_ipv4(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_addr_ipv4_v1 vc_data; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + switch (vc_data.type) { +/* case NXA_TYPE_ADDR: + break; */ + + case NXA_TYPE_ANY: + __dealloc_nx_addr_v4_all(xchg(&nxi->v4.next, NULL)); + memset(&nxi->v4, 0, sizeof(nxi->v4)); + break; + + default: + return -EINVAL; + } + return 0; +} + + +#ifdef CONFIG_IPV6 + +int do_add_v6_addr(struct nx_info *nxi, + struct in6_addr *ip, struct in6_addr *mask, + uint32_t prefix, uint16_t type, uint16_t flags) +{ + struct nx_addr_v6 *nxa = &nxi->v6; + + if (NX_IPV6(nxi)) { + /* locate last entry */ + for (; nxa->next; nxa = nxa->next); + nxa->next = __alloc_nx_addr_v6(); + nxa = nxa->next; + + if (IS_ERR(nxa)) + return PTR_ERR(nxa); + } + + nxa->ip = *ip; + nxa->mask = *mask; + nxa->prefix = prefix; + nxa->type = type; + nxa->flags = flags; + return 0; +} + + +int vc_net_add_ipv6(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_addr_ipv6_v1 vc_data; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + switch (vc_data.type) { + case NXA_TYPE_ADDR: + case NXA_TYPE_MASK: + return do_add_v6_addr(nxi, &vc_data.ip, &vc_data.mask, + vc_data.prefix, vc_data.type, vc_data.flags); + default: + return -EINVAL; + } + return 0; +} + +int vc_net_remove_ipv6(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_addr_ipv6_v1 vc_data; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + switch (vc_data.type) { + case NXA_TYPE_ANY: + __dealloc_nx_addr_v6_all(xchg(&nxi->v6.next, NULL)); + memset(&nxi->v6, 0, sizeof(nxi->v6)); + break; + + default: + return -EINVAL; + } + return 0; +} + +#endif /* CONFIG_IPV6 */ + + +int vc_get_nflags(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_flags_v0 vc_data; + + vc_data.flagword = nxi->nx_flags; + + /* special STATE flag handling */ + vc_data.mask = vs_mask_flags(~0ULL, nxi->nx_flags, NXF_ONE_TIME); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_nflags(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_flags_v0 vc_data; + uint64_t mask, trigger; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + /* special STATE flag handling */ + mask = vs_mask_mask(vc_data.mask, nxi->nx_flags, NXF_ONE_TIME); + trigger = (mask & nxi->nx_flags) ^ (mask & vc_data.flagword); + + nxi->nx_flags = vs_mask_flags(nxi->nx_flags, + vc_data.flagword, mask); + if (trigger & NXF_PERSISTENT) + nx_update_persistent(nxi); + + return 0; +} + +int vc_get_ncaps(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_caps_v0 vc_data; + + vc_data.ncaps = nxi->nx_ncaps; + vc_data.cmask = ~0ULL; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + +int vc_set_ncaps(struct nx_info *nxi, void __user *data) +{ + struct vcmd_net_caps_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + nxi->nx_ncaps = vs_mask_flags(nxi->nx_ncaps, + vc_data.ncaps, vc_data.cmask); + return 0; +} + + +#include + +module_init(init_network); + +EXPORT_SYMBOL_GPL(free_nx_info); +EXPORT_SYMBOL_GPL(unhash_nx_info); + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/proc.c linux-2.6.27.15-g-v/kernel/vserver/proc.c --- linux-2.6.27.15/kernel/vserver/proc.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/proc.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,1092 @@ +/* + * linux/kernel/vserver/proc.c + * + * Virtual Context Support + * + * Copyright (C) 2003-2007 Herbert Pötzl + * + * V0.01 basic structure + * V0.02 adaptation vs1.3.0 + * V0.03 proc permissions + * V0.04 locking/generic + * V0.05 next generation procfs + * V0.06 inode validation + * V0.07 generic rewrite vid + * V0.08 remove inode type + * + */ + +#include +#include + +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "cvirt_proc.h" +#include "cacct_proc.h" +#include "limit_proc.h" +#include "sched_proc.h" +#include "vci_config.h" + + +static inline char *print_cap_t(char *buffer, kernel_cap_t *c) +{ + unsigned __capi; + + CAP_FOR_EACH_U32(__capi) { + buffer += sprintf(buffer, "%08x", + c->cap[(_KERNEL_CAPABILITY_U32S-1) - __capi]); + } + return buffer; +} + + +static struct proc_dir_entry *proc_virtual; + +static struct proc_dir_entry *proc_virtnet; + + +/* first the actual feeds */ + + +static int proc_vci(char *buffer) +{ + return sprintf(buffer, + "VCIVersion:\t%04x:%04x\n" + "VCISyscall:\t%d\n" + "VCIKernel:\t%08x\n", + VCI_VERSION >> 16, + VCI_VERSION & 0xFFFF, + __NR_vserver, + vci_kernel_config()); +} + +static int proc_virtual_info(char *buffer) +{ + return proc_vci(buffer); +} + +static int proc_virtual_status(char *buffer) +{ + return sprintf(buffer, + "#CTotal:\t%d\n" + "#CActive:\t%d\n" + "#NSProxy:\t%d\t%d %d %d %d %d %d\n", + atomic_read(&vx_global_ctotal), + atomic_read(&vx_global_cactive), + atomic_read(&vs_global_nsproxy), + atomic_read(&vs_global_fs), + atomic_read(&vs_global_mnt_ns), + atomic_read(&vs_global_uts_ns), + atomic_read(&vs_global_ipc_ns), + atomic_read(&vs_global_user_ns), + atomic_read(&vs_global_pid_ns)); +} + + +int proc_vxi_info(struct vx_info *vxi, char *buffer) +{ + int length; + + length = sprintf(buffer, + "ID:\t%d\n" + "Info:\t%p\n" + "Init:\t%d\n" + "OOM:\t%lld\n", + vxi->vx_id, + vxi, + vxi->vx_initpid, + vxi->vx_badness_bias); + return length; +} + +int proc_vxi_status(struct vx_info *vxi, char *buffer) +{ + char *orig = buffer; + + buffer += sprintf(buffer, + "UseCnt:\t%d\n" + "Tasks:\t%d\n" + "Flags:\t%016llx\n", + atomic_read(&vxi->vx_usecnt), + atomic_read(&vxi->vx_tasks), + (unsigned long long)vxi->vx_flags); + + buffer += sprintf(buffer, "BCaps:\t"); + buffer = print_cap_t(buffer, &vxi->vx_bcaps); + buffer += sprintf(buffer, "\n"); + + buffer += sprintf(buffer, + "CCaps:\t%016llx\n" + "Spaces:\t%08lx %08lx\n", + (unsigned long long)vxi->vx_ccaps, + vxi->vx_nsmask[0], vxi->vx_nsmask[1]); + return buffer - orig; +} + +int proc_vxi_limit(struct vx_info *vxi, char *buffer) +{ + return vx_info_proc_limit(&vxi->limit, buffer); +} + +int proc_vxi_sched(struct vx_info *vxi, char *buffer) +{ + int cpu, length; + + length = vx_info_proc_sched(&vxi->sched, buffer); + for_each_online_cpu(cpu) { + length += vx_info_proc_sched_pc( + &vx_per_cpu(vxi, sched_pc, cpu), + buffer + length, cpu); + } + return length; +} + +int proc_vxi_nsproxy0(struct vx_info *vxi, char *buffer) +{ + return vx_info_proc_nsproxy(vxi->vx_nsproxy[0], buffer); +} + +int proc_vxi_nsproxy1(struct vx_info *vxi, char *buffer) +{ + return vx_info_proc_nsproxy(vxi->vx_nsproxy[1], buffer); +} + +int proc_vxi_cvirt(struct vx_info *vxi, char *buffer) +{ + int cpu, length; + + vx_update_load(vxi); + length = vx_info_proc_cvirt(&vxi->cvirt, buffer); + for_each_online_cpu(cpu) { + length += vx_info_proc_cvirt_pc( + &vx_per_cpu(vxi, cvirt_pc, cpu), + buffer + length, cpu); + } + return length; +} + +int proc_vxi_cacct(struct vx_info *vxi, char *buffer) +{ + return vx_info_proc_cacct(&vxi->cacct, buffer); +} + + +static int proc_virtnet_info(char *buffer) +{ + return proc_vci(buffer); +} + +static int proc_virtnet_status(char *buffer) +{ + return sprintf(buffer, + "#CTotal:\t%d\n" + "#CActive:\t%d\n", + atomic_read(&nx_global_ctotal), + atomic_read(&nx_global_cactive)); +} + +int proc_nxi_info(struct nx_info *nxi, char *buffer) +{ + struct nx_addr_v4 *v4a; +#ifdef CONFIG_IPV6 + struct nx_addr_v6 *v6a; +#endif + int length, i; + + length = sprintf(buffer, + "ID:\t%d\n" + "Info:\t%p\n" + "Bcast:\t" NIPQUAD_FMT "\n" + "Lback:\t" NIPQUAD_FMT "\n", + nxi->nx_id, + nxi, + NIPQUAD(nxi->v4_bcast.s_addr), + NIPQUAD(nxi->v4_lback.s_addr)); + + if (!NX_IPV4(nxi)) + goto skip_v4; + for (i = 0, v4a = &nxi->v4; v4a; i++, v4a = v4a->next) + length += sprintf(buffer + length, "%d:\t" NXAV4_FMT "\n", + i, NXAV4(v4a)); +skip_v4: +#ifdef CONFIG_IPV6 + if (!NX_IPV6(nxi)) + goto skip_v6; + for (i = 0, v6a = &nxi->v6; v6a; i++, v6a = v6a->next) + length += sprintf(buffer + length, "%d:\t" NXAV6_FMT "\n", + i, NXAV6(v6a)); +skip_v6: +#endif + return length; +} + +int proc_nxi_status(struct nx_info *nxi, char *buffer) +{ + int length; + + length = sprintf(buffer, + "UseCnt:\t%d\n" + "Tasks:\t%d\n" + "Flags:\t%016llx\n" + "NCaps:\t%016llx\n", + atomic_read(&nxi->nx_usecnt), + atomic_read(&nxi->nx_tasks), + (unsigned long long)nxi->nx_flags, + (unsigned long long)nxi->nx_ncaps); + return length; +} + + + +/* here the inode helpers */ + +struct vs_entry { + int len; + char *name; + mode_t mode; + struct inode_operations *iop; + struct file_operations *fop; + union proc_op op; +}; + +static struct inode *vs_proc_make_inode(struct super_block *sb, struct vs_entry *p) +{ + struct inode *inode = new_inode(sb); + + if (!inode) + goto out; + + inode->i_mode = p->mode; + if (p->iop) + inode->i_op = p->iop; + if (p->fop) + inode->i_fop = p->fop; + + inode->i_nlink = (p->mode & S_IFDIR) ? 2 : 1; + inode->i_flags |= S_IMMUTABLE; + + inode->i_mtime = inode->i_atime = inode->i_ctime = CURRENT_TIME; + + inode->i_uid = 0; + inode->i_gid = 0; + inode->i_tag = 0; +out: + return inode; +} + +static struct dentry *vs_proc_instantiate(struct inode *dir, + struct dentry *dentry, int id, void *ptr) +{ + struct vs_entry *p = ptr; + struct inode *inode = vs_proc_make_inode(dir->i_sb, p); + struct dentry *error = ERR_PTR(-EINVAL); + + if (!inode) + goto out; + + PROC_I(inode)->op = p->op; + PROC_I(inode)->fd = id; + d_add(dentry, inode); + error = NULL; +out: + return error; +} + +/* Lookups */ + +typedef struct dentry *instantiate_t(struct inode *, struct dentry *, int, void *); + +/* + * Fill a directory entry. + * + * If possible create the dcache entry and derive our inode number and + * file type from dcache entry. + * + * Since all of the proc inode numbers are dynamically generated, the inode + * numbers do not exist until the inode is cache. This means creating the + * the dcache entry in readdir is necessary to keep the inode numbers + * reported by readdir in sync with the inode numbers reported + * by stat. + */ +static int proc_fill_cache(struct file *filp, void *dirent, filldir_t filldir, + char *name, int len, instantiate_t instantiate, int id, void *ptr) +{ + struct dentry *child, *dir = filp->f_dentry; + struct inode *inode; + struct qstr qname; + ino_t ino = 0; + unsigned type = DT_UNKNOWN; + + qname.name = name; + qname.len = len; + qname.hash = full_name_hash(name, len); + + child = d_lookup(dir, &qname); + if (!child) { + struct dentry *new; + new = d_alloc(dir, &qname); + if (new) { + child = instantiate(dir->d_inode, new, id, ptr); + if (child) + dput(new); + else + child = new; + } + } + if (!child || IS_ERR(child) || !child->d_inode) + goto end_instantiate; + inode = child->d_inode; + if (inode) { + ino = inode->i_ino; + type = inode->i_mode >> 12; + } + dput(child); +end_instantiate: + if (!ino) + ino = find_inode_number(dir, &qname); + if (!ino) + ino = 1; + return filldir(dirent, name, len, filp->f_pos, ino, type); +} + + + +/* get and revalidate vx_info/xid */ + +static inline +struct vx_info *get_proc_vx_info(struct inode *inode) +{ + return lookup_vx_info(PROC_I(inode)->fd); +} + +static int proc_xid_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode = dentry->d_inode; + xid_t xid = PROC_I(inode)->fd; + + if (!xid || xid_is_hashed(xid)) + return 1; + d_drop(dentry); + return 0; +} + + +/* get and revalidate nx_info/nid */ + +static int proc_nid_revalidate(struct dentry *dentry, struct nameidata *nd) +{ + struct inode *inode = dentry->d_inode; + nid_t nid = PROC_I(inode)->fd; + + if (!nid || nid_is_hashed(nid)) + return 1; + d_drop(dentry); + return 0; +} + + + +#define PROC_BLOCK_SIZE (PAGE_SIZE - 1024) + +static ssize_t proc_vs_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + unsigned long page; + ssize_t length = 0; + + if (count > PROC_BLOCK_SIZE) + count = PROC_BLOCK_SIZE; + + /* fade that out as soon as stable */ + WARN_ON(PROC_I(inode)->fd); + + if (!(page = __get_free_page(GFP_KERNEL))) + return -ENOMEM; + + BUG_ON(!PROC_I(inode)->op.proc_vs_read); + length = PROC_I(inode)->op.proc_vs_read((char *)page); + + if (length >= 0) + length = simple_read_from_buffer(buf, count, ppos, + (char *)page, length); + + free_page(page); + return length; +} + +static ssize_t proc_vx_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct vx_info *vxi = NULL; + xid_t xid = PROC_I(inode)->fd; + unsigned long page; + ssize_t length = 0; + + if (count > PROC_BLOCK_SIZE) + count = PROC_BLOCK_SIZE; + + /* fade that out as soon as stable */ + WARN_ON(!xid); + vxi = lookup_vx_info(xid); + if (!vxi) + goto out; + + length = -ENOMEM; + if (!(page = __get_free_page(GFP_KERNEL))) + goto out_put; + + BUG_ON(!PROC_I(inode)->op.proc_vxi_read); + length = PROC_I(inode)->op.proc_vxi_read(vxi, (char *)page); + + if (length >= 0) + length = simple_read_from_buffer(buf, count, ppos, + (char *)page, length); + + free_page(page); +out_put: + put_vx_info(vxi); +out: + return length; +} + +static ssize_t proc_nx_info_read(struct file *file, char __user *buf, + size_t count, loff_t *ppos) +{ + struct inode *inode = file->f_dentry->d_inode; + struct nx_info *nxi = NULL; + nid_t nid = PROC_I(inode)->fd; + unsigned long page; + ssize_t length = 0; + + if (count > PROC_BLOCK_SIZE) + count = PROC_BLOCK_SIZE; + + /* fade that out as soon as stable */ + WARN_ON(!nid); + nxi = lookup_nx_info(nid); + if (!nxi) + goto out; + + length = -ENOMEM; + if (!(page = __get_free_page(GFP_KERNEL))) + goto out_put; + + BUG_ON(!PROC_I(inode)->op.proc_nxi_read); + length = PROC_I(inode)->op.proc_nxi_read(nxi, (char *)page); + + if (length >= 0) + length = simple_read_from_buffer(buf, count, ppos, + (char *)page, length); + + free_page(page); +out_put: + put_nx_info(nxi); +out: + return length; +} + + + +/* here comes the lower level */ + + +#define NOD(NAME, MODE, IOP, FOP, OP) { \ + .len = sizeof(NAME) - 1, \ + .name = (NAME), \ + .mode = MODE, \ + .iop = IOP, \ + .fop = FOP, \ + .op = OP, \ +} + + +#define DIR(NAME, MODE, OTYPE) \ + NOD(NAME, (S_IFDIR | (MODE)), \ + &proc_ ## OTYPE ## _inode_operations, \ + &proc_ ## OTYPE ## _file_operations, { } ) + +#define INF(NAME, MODE, OTYPE) \ + NOD(NAME, (S_IFREG | (MODE)), NULL, \ + &proc_vs_info_file_operations, \ + { .proc_vs_read = &proc_##OTYPE } ) + +#define VINF(NAME, MODE, OTYPE) \ + NOD(NAME, (S_IFREG | (MODE)), NULL, \ + &proc_vx_info_file_operations, \ + { .proc_vxi_read = &proc_##OTYPE } ) + +#define NINF(NAME, MODE, OTYPE) \ + NOD(NAME, (S_IFREG | (MODE)), NULL, \ + &proc_nx_info_file_operations, \ + { .proc_nxi_read = &proc_##OTYPE } ) + + +static struct file_operations proc_vs_info_file_operations = { + .read = proc_vs_info_read, +}; + +static struct file_operations proc_vx_info_file_operations = { + .read = proc_vx_info_read, +}; + +static struct dentry_operations proc_xid_dentry_operations = { + .d_revalidate = proc_xid_revalidate, +}; + +static struct vs_entry vx_base_stuff[] = { + VINF("info", S_IRUGO, vxi_info), + VINF("status", S_IRUGO, vxi_status), + VINF("limit", S_IRUGO, vxi_limit), + VINF("sched", S_IRUGO, vxi_sched), + VINF("nsproxy", S_IRUGO, vxi_nsproxy0), + VINF("nsproxy1",S_IRUGO, vxi_nsproxy1), + VINF("cvirt", S_IRUGO, vxi_cvirt), + VINF("cacct", S_IRUGO, vxi_cacct), + {} +}; + + + + +static struct dentry *proc_xid_instantiate(struct inode *dir, + struct dentry *dentry, int id, void *ptr) +{ + dentry->d_op = &proc_xid_dentry_operations; + return vs_proc_instantiate(dir, dentry, id, ptr); +} + +static struct dentry *proc_xid_lookup(struct inode *dir, + struct dentry *dentry, struct nameidata *nd) +{ + struct vs_entry *p = vx_base_stuff; + struct dentry *error = ERR_PTR(-ENOENT); + + for (; p->name; p++) { + if (p->len != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, p->name, p->len)) + break; + } + if (!p->name) + goto out; + + error = proc_xid_instantiate(dir, dentry, PROC_I(dir)->fd, p); +out: + return error; +} + +static int proc_xid_readdir(struct file *filp, + void *dirent, filldir_t filldir) +{ + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + struct vs_entry *p = vx_base_stuff; + int size = sizeof(vx_base_stuff) / sizeof(struct vs_entry); + int pos, index; + u64 ino; + + pos = filp->f_pos; + switch (pos) { + case 0: + ino = inode->i_ino; + if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) + goto out; + pos++; + /* fall through */ + case 1: + ino = parent_ino(dentry); + if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) + goto out; + pos++; + /* fall through */ + default: + index = pos - 2; + if (index >= size) + goto out; + for (p += index; p->name; p++) { + if (proc_fill_cache(filp, dirent, filldir, p->name, p->len, + vs_proc_instantiate, PROC_I(inode)->fd, p)) + goto out; + pos++; + } + } +out: + filp->f_pos = pos; + return 1; +} + + + +static struct file_operations proc_nx_info_file_operations = { + .read = proc_nx_info_read, +}; + +static struct dentry_operations proc_nid_dentry_operations = { + .d_revalidate = proc_nid_revalidate, +}; + +static struct vs_entry nx_base_stuff[] = { + NINF("info", S_IRUGO, nxi_info), + NINF("status", S_IRUGO, nxi_status), + {} +}; + + +static struct dentry *proc_nid_instantiate(struct inode *dir, + struct dentry *dentry, int id, void *ptr) +{ + dentry->d_op = &proc_nid_dentry_operations; + return vs_proc_instantiate(dir, dentry, id, ptr); +} + +static struct dentry *proc_nid_lookup(struct inode *dir, + struct dentry *dentry, struct nameidata *nd) +{ + struct vs_entry *p = nx_base_stuff; + struct dentry *error = ERR_PTR(-ENOENT); + + for (; p->name; p++) { + if (p->len != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, p->name, p->len)) + break; + } + if (!p->name) + goto out; + + error = proc_nid_instantiate(dir, dentry, PROC_I(dir)->fd, p); +out: + return error; +} + +static int proc_nid_readdir(struct file *filp, + void *dirent, filldir_t filldir) +{ + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + struct vs_entry *p = nx_base_stuff; + int size = sizeof(nx_base_stuff) / sizeof(struct vs_entry); + int pos, index; + u64 ino; + + pos = filp->f_pos; + switch (pos) { + case 0: + ino = inode->i_ino; + if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) + goto out; + pos++; + /* fall through */ + case 1: + ino = parent_ino(dentry); + if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) + goto out; + pos++; + /* fall through */ + default: + index = pos - 2; + if (index >= size) + goto out; + for (p += index; p->name; p++) { + if (proc_fill_cache(filp, dirent, filldir, p->name, p->len, + vs_proc_instantiate, PROC_I(inode)->fd, p)) + goto out; + pos++; + } + } +out: + filp->f_pos = pos; + return 1; +} + + +#define MAX_MULBY10 ((~0U - 9) / 10) + +static inline int atovid(const char *str, int len) +{ + int vid, c; + + vid = 0; + while (len-- > 0) { + c = *str - '0'; + str++; + if (c > 9) + return -1; + if (vid >= MAX_MULBY10) + return -1; + vid *= 10; + vid += c; + if (!vid) + return -1; + } + return vid; +} + +/* now the upper level (virtual) */ + + +static struct file_operations proc_xid_file_operations = { + .read = generic_read_dir, + .readdir = proc_xid_readdir, +}; + +static struct inode_operations proc_xid_inode_operations = { + .lookup = proc_xid_lookup, +}; + +static struct vs_entry vx_virtual_stuff[] = { + INF("info", S_IRUGO, virtual_info), + INF("status", S_IRUGO, virtual_status), + DIR(NULL, S_IRUGO | S_IXUGO, xid), +}; + + +static struct dentry *proc_virtual_lookup(struct inode *dir, + struct dentry *dentry, struct nameidata *nd) +{ + struct vs_entry *p = vx_virtual_stuff; + struct dentry *error = ERR_PTR(-ENOENT); + int id = 0; + + for (; p->name; p++) { + if (p->len != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, p->name, p->len)) + break; + } + if (p->name) + goto instantiate; + + id = atovid(dentry->d_name.name, dentry->d_name.len); + if ((id < 0) || !xid_is_hashed(id)) + goto out; + +instantiate: + error = proc_xid_instantiate(dir, dentry, id, p); +out: + return error; +} + +static struct file_operations proc_nid_file_operations = { + .read = generic_read_dir, + .readdir = proc_nid_readdir, +}; + +static struct inode_operations proc_nid_inode_operations = { + .lookup = proc_nid_lookup, +}; + +static struct vs_entry nx_virtnet_stuff[] = { + INF("info", S_IRUGO, virtnet_info), + INF("status", S_IRUGO, virtnet_status), + DIR(NULL, S_IRUGO | S_IXUGO, nid), +}; + + +static struct dentry *proc_virtnet_lookup(struct inode *dir, + struct dentry *dentry, struct nameidata *nd) +{ + struct vs_entry *p = nx_virtnet_stuff; + struct dentry *error = ERR_PTR(-ENOENT); + int id = 0; + + for (; p->name; p++) { + if (p->len != dentry->d_name.len) + continue; + if (!memcmp(dentry->d_name.name, p->name, p->len)) + break; + } + if (p->name) + goto instantiate; + + id = atovid(dentry->d_name.name, dentry->d_name.len); + if ((id < 0) || !nid_is_hashed(id)) + goto out; + +instantiate: + error = proc_nid_instantiate(dir, dentry, id, p); +out: + return error; +} + + +#define PROC_MAXVIDS 32 + +int proc_virtual_readdir(struct file *filp, + void *dirent, filldir_t filldir) +{ + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + struct vs_entry *p = vx_virtual_stuff; + int size = sizeof(vx_virtual_stuff) / sizeof(struct vs_entry); + int pos, index; + unsigned int xid_array[PROC_MAXVIDS]; + char buf[PROC_NUMBUF]; + unsigned int nr_xids, i; + u64 ino; + + pos = filp->f_pos; + switch (pos) { + case 0: + ino = inode->i_ino; + if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) + goto out; + pos++; + /* fall through */ + case 1: + ino = parent_ino(dentry); + if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) + goto out; + pos++; + /* fall through */ + default: + index = pos - 2; + if (index >= size) + goto entries; + for (p += index; p->name; p++) { + if (proc_fill_cache(filp, dirent, filldir, p->name, p->len, + vs_proc_instantiate, 0, p)) + goto out; + pos++; + } + entries: + index = pos - size; + p = &vx_virtual_stuff[size - 1]; + nr_xids = get_xid_list(index, xid_array, PROC_MAXVIDS); + for (i = 0; i < nr_xids; i++) { + int n, xid = xid_array[i]; + unsigned int j = PROC_NUMBUF; + + n = xid; + do + buf[--j] = '0' + (n % 10); + while (n /= 10); + + if (proc_fill_cache(filp, dirent, filldir, + buf + j, PROC_NUMBUF - j, + vs_proc_instantiate, xid, p)) + goto out; + pos++; + } + } +out: + filp->f_pos = pos; + return 0; +} + +static int proc_virtual_getattr(struct vfsmount *mnt, + struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + + generic_fillattr(inode, stat); + stat->nlink = 2 + atomic_read(&vx_global_cactive); + return 0; +} + +static struct file_operations proc_virtual_dir_operations = { + .read = generic_read_dir, + .readdir = proc_virtual_readdir, +}; + +static struct inode_operations proc_virtual_dir_inode_operations = { + .getattr = proc_virtual_getattr, + .lookup = proc_virtual_lookup, +}; + + + + + +int proc_virtnet_readdir(struct file *filp, + void *dirent, filldir_t filldir) +{ + struct dentry *dentry = filp->f_dentry; + struct inode *inode = dentry->d_inode; + struct vs_entry *p = nx_virtnet_stuff; + int size = sizeof(nx_virtnet_stuff) / sizeof(struct vs_entry); + int pos, index; + unsigned int nid_array[PROC_MAXVIDS]; + char buf[PROC_NUMBUF]; + unsigned int nr_nids, i; + u64 ino; + + pos = filp->f_pos; + switch (pos) { + case 0: + ino = inode->i_ino; + if (filldir(dirent, ".", 1, pos, ino, DT_DIR) < 0) + goto out; + pos++; + /* fall through */ + case 1: + ino = parent_ino(dentry); + if (filldir(dirent, "..", 2, pos, ino, DT_DIR) < 0) + goto out; + pos++; + /* fall through */ + default: + index = pos - 2; + if (index >= size) + goto entries; + for (p += index; p->name; p++) { + if (proc_fill_cache(filp, dirent, filldir, p->name, p->len, + vs_proc_instantiate, 0, p)) + goto out; + pos++; + } + entries: + index = pos - size; + p = &nx_virtnet_stuff[size - 1]; + nr_nids = get_nid_list(index, nid_array, PROC_MAXVIDS); + for (i = 0; i < nr_nids; i++) { + int n, nid = nid_array[i]; + unsigned int j = PROC_NUMBUF; + + n = nid; + do + buf[--j] = '0' + (n % 10); + while (n /= 10); + + if (proc_fill_cache(filp, dirent, filldir, + buf + j, PROC_NUMBUF - j, + vs_proc_instantiate, nid, p)) + goto out; + pos++; + } + } +out: + filp->f_pos = pos; + return 0; +} + +static int proc_virtnet_getattr(struct vfsmount *mnt, + struct dentry *dentry, struct kstat *stat) +{ + struct inode *inode = dentry->d_inode; + + generic_fillattr(inode, stat); + stat->nlink = 2 + atomic_read(&nx_global_cactive); + return 0; +} + +static struct file_operations proc_virtnet_dir_operations = { + .read = generic_read_dir, + .readdir = proc_virtnet_readdir, +}; + +static struct inode_operations proc_virtnet_dir_inode_operations = { + .getattr = proc_virtnet_getattr, + .lookup = proc_virtnet_lookup, +}; + + + +void proc_vx_init(void) +{ + struct proc_dir_entry *ent; + + ent = proc_mkdir("virtual", 0); + if (ent) { + ent->proc_fops = &proc_virtual_dir_operations; + ent->proc_iops = &proc_virtual_dir_inode_operations; + } + proc_virtual = ent; + + ent = proc_mkdir("virtnet", 0); + if (ent) { + ent->proc_fops = &proc_virtnet_dir_operations; + ent->proc_iops = &proc_virtnet_dir_inode_operations; + } + proc_virtnet = ent; +} + + + + +/* per pid info */ + + +int proc_pid_vx_info(struct task_struct *p, char *buffer) +{ + struct vx_info *vxi; + char *orig = buffer; + + buffer += sprintf(buffer, "XID:\t%d\n", vx_task_xid(p)); + + vxi = task_get_vx_info(p); + if (!vxi) + goto out; + + buffer += sprintf(buffer, "BCaps:\t"); + buffer = print_cap_t(buffer, &vxi->vx_bcaps); + buffer += sprintf(buffer, "\n"); + buffer += sprintf(buffer, "CCaps:\t%016llx\n", + (unsigned long long)vxi->vx_ccaps); + buffer += sprintf(buffer, "CFlags:\t%016llx\n", + (unsigned long long)vxi->vx_flags); + buffer += sprintf(buffer, "CIPid:\t%d\n", vxi->vx_initpid); + + put_vx_info(vxi); +out: + return buffer - orig; +} + + +int proc_pid_nx_info(struct task_struct *p, char *buffer) +{ + struct nx_info *nxi; + struct nx_addr_v4 *v4a; +#ifdef CONFIG_IPV6 + struct nx_addr_v6 *v6a; +#endif + char *orig = buffer; + int i; + + buffer += sprintf(buffer, "NID:\t%d\n", nx_task_nid(p)); + + nxi = task_get_nx_info(p); + if (!nxi) + goto out; + + buffer += sprintf(buffer, "NCaps:\t%016llx\n", + (unsigned long long)nxi->nx_ncaps); + buffer += sprintf(buffer, "NFlags:\t%016llx\n", + (unsigned long long)nxi->nx_flags); + + buffer += sprintf(buffer, + "V4Root[bcast]:\t" NIPQUAD_FMT "\n", + NIPQUAD(nxi->v4_bcast.s_addr)); + buffer += sprintf (buffer, + "V4Root[lback]:\t" NIPQUAD_FMT "\n", + NIPQUAD(nxi->v4_lback.s_addr)); + if (!NX_IPV4(nxi)) + goto skip_v4; + for (i = 0, v4a = &nxi->v4; v4a; i++, v4a = v4a->next) + buffer += sprintf(buffer, "V4Root[%d]:\t" NXAV4_FMT "\n", + i, NXAV4(v4a)); +skip_v4: +#ifdef CONFIG_IPV6 + if (!NX_IPV6(nxi)) + goto skip_v6; + for (i = 0, v6a = &nxi->v6; v6a; i++, v6a = v6a->next) + buffer += sprintf(buffer, "V6Root[%d]:\t" NXAV6_FMT "\n", + i, NXAV6(v6a)); +skip_v6: +#endif + put_nx_info(nxi); +out: + return buffer - orig; +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/sched.c linux-2.6.27.15-g-v/kernel/vserver/sched.c --- linux-2.6.27.15/kernel/vserver/sched.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/sched.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,413 @@ +/* + * linux/kernel/vserver/sched.c + * + * Virtual Server: Scheduler Support + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 adapted Sam Vilains version to 2.6.3 + * V0.02 removed legacy interface + * V0.03 changed vcmds to vxi arg + * V0.04 removed older and legacy interfaces + * + */ + +#include +#include +#include + +#include + + +#define vxd_check_range(val, min, max) do { \ + vxlprintk((val < min) || (val > max), \ + "check_range(%ld,%ld,%ld)", \ + (long)val, (long)min, (long)max, \ + __FILE__, __LINE__); \ + } while (0) + + +void vx_update_sched_param(struct _vx_sched *sched, + struct _vx_sched_pc *sched_pc) +{ + unsigned int set_mask = sched->update_mask; + + if (set_mask & VXSM_FILL_RATE) + sched_pc->fill_rate[0] = sched->fill_rate[0]; + if (set_mask & VXSM_INTERVAL) + sched_pc->interval[0] = sched->interval[0]; + if (set_mask & VXSM_FILL_RATE2) + sched_pc->fill_rate[1] = sched->fill_rate[1]; + if (set_mask & VXSM_INTERVAL2) + sched_pc->interval[1] = sched->interval[1]; + if (set_mask & VXSM_TOKENS) + sched_pc->tokens = sched->tokens; + if (set_mask & VXSM_TOKENS_MIN) + sched_pc->tokens_min = sched->tokens_min; + if (set_mask & VXSM_TOKENS_MAX) + sched_pc->tokens_max = sched->tokens_max; + if (set_mask & VXSM_PRIO_BIAS) + sched_pc->prio_bias = sched->prio_bias; + + if (set_mask & VXSM_IDLE_TIME) + sched_pc->flags |= VXSF_IDLE_TIME; + else + sched_pc->flags &= ~VXSF_IDLE_TIME; + + /* reset time */ + sched_pc->norm_time = jiffies; +} + + +/* + * recalculate the context's scheduling tokens + * + * ret > 0 : number of tokens available + * ret < 0 : on hold, check delta_min[] + * -1 only jiffies + * -2 also idle time + * + */ +int vx_tokens_recalc(struct _vx_sched_pc *sched_pc, + unsigned long *norm_time, unsigned long *idle_time, int delta_min[2]) +{ + long delta; + long tokens = 0; + int flags = sched_pc->flags; + + /* how much time did pass? */ + delta = *norm_time - sched_pc->norm_time; + vxd_check_range(delta, 0, INT_MAX); + + if (delta >= sched_pc->interval[0]) { + long tokens, integral; + + /* calc integral token part */ + tokens = delta / sched_pc->interval[0]; + integral = tokens * sched_pc->interval[0]; + tokens *= sched_pc->fill_rate[0]; +#ifdef CONFIG_VSERVER_HARDCPU + delta_min[0] = delta - integral; + vxd_check_range(delta_min[0], 0, sched_pc->interval[0]); +#endif + /* advance time */ + sched_pc->norm_time += delta; + + /* add tokens */ + sched_pc->tokens += tokens; + sched_pc->token_time += tokens; + } else + delta_min[0] = delta; + +#ifdef CONFIG_VSERVER_IDLETIME + if (!(flags & VXSF_IDLE_TIME)) + goto skip_idle; + + /* how much was the idle skip? */ + delta = *idle_time - sched_pc->idle_time; + vxd_check_range(delta, 0, INT_MAX); + + if (delta >= sched_pc->interval[1]) { + long tokens, integral; + + /* calc fair share token part */ + tokens = delta / sched_pc->interval[1]; + integral = tokens * sched_pc->interval[1]; + tokens *= sched_pc->fill_rate[1]; + delta_min[1] = delta - integral; + vxd_check_range(delta_min[1], 0, sched_pc->interval[1]); + + /* advance idle time */ + sched_pc->idle_time += integral; + + /* add tokens */ + sched_pc->tokens += tokens; + sched_pc->token_time += tokens; + } else + delta_min[1] = delta; +skip_idle: +#endif + + /* clip at maximum */ + if (sched_pc->tokens > sched_pc->tokens_max) + sched_pc->tokens = sched_pc->tokens_max; + tokens = sched_pc->tokens; + + if ((flags & VXSF_ONHOLD)) { + /* can we unhold? */ + if (tokens >= sched_pc->tokens_min) { + flags &= ~VXSF_ONHOLD; + sched_pc->hold_ticks += + *norm_time - sched_pc->onhold; + } else + goto on_hold; + } else { + /* put on hold? */ + if (tokens <= 0) { + flags |= VXSF_ONHOLD; + sched_pc->onhold = *norm_time; + goto on_hold; + } + } + sched_pc->flags = flags; + return tokens; + +on_hold: + tokens = sched_pc->tokens_min - tokens; + sched_pc->flags = flags; + BUG_ON(tokens < 0); + +#ifdef CONFIG_VSERVER_HARDCPU + /* next interval? */ + if (!sched_pc->fill_rate[0]) + delta_min[0] = HZ; + else if (tokens > sched_pc->fill_rate[0]) + delta_min[0] += sched_pc->interval[0] * + tokens / sched_pc->fill_rate[0]; + else + delta_min[0] = sched_pc->interval[0] - delta_min[0]; + vxd_check_range(delta_min[0], 0, INT_MAX); + +#ifdef CONFIG_VSERVER_IDLETIME + if (!(flags & VXSF_IDLE_TIME)) + return -1; + + /* next interval? */ + if (!sched_pc->fill_rate[1]) + delta_min[1] = HZ; + else if (tokens > sched_pc->fill_rate[1]) + delta_min[1] += sched_pc->interval[1] * + tokens / sched_pc->fill_rate[1]; + else + delta_min[1] = sched_pc->interval[1] - delta_min[1]; + vxd_check_range(delta_min[1], 0, INT_MAX); + + return -2; +#else + return -1; +#endif /* CONFIG_VSERVER_IDLETIME */ +#else + return 0; +#endif /* CONFIG_VSERVER_HARDCPU */ +} + +static inline unsigned long msec_to_ticks(unsigned long msec) +{ + return msecs_to_jiffies(msec); +} + +static inline unsigned long ticks_to_msec(unsigned long ticks) +{ + return jiffies_to_msecs(ticks); +} + +static inline unsigned long ticks_to_usec(unsigned long ticks) +{ + return jiffies_to_usecs(ticks); +} + + +static int do_set_sched(struct vx_info *vxi, struct vcmd_sched_v5 *data) +{ + unsigned int set_mask = data->mask; + unsigned int update_mask; + int i, cpu; + + /* Sanity check data values */ + if (data->tokens_max <= 0) + data->tokens_max = HZ; + if (data->tokens_min < 0) + data->tokens_min = HZ / 3; + if (data->tokens_min >= data->tokens_max) + data->tokens_min = data->tokens_max; + + if (data->prio_bias > MAX_PRIO_BIAS) + data->prio_bias = MAX_PRIO_BIAS; + if (data->prio_bias < MIN_PRIO_BIAS) + data->prio_bias = MIN_PRIO_BIAS; + + spin_lock(&vxi->sched.tokens_lock); + + /* sync up on delayed updates */ + for_each_cpu_mask(cpu, vxi->sched.update) + vx_update_sched_param(&vxi->sched, + &vx_per_cpu(vxi, sched_pc, cpu)); + + if (set_mask & VXSM_FILL_RATE) + vxi->sched.fill_rate[0] = data->fill_rate[0]; + if (set_mask & VXSM_FILL_RATE2) + vxi->sched.fill_rate[1] = data->fill_rate[1]; + if (set_mask & VXSM_INTERVAL) + vxi->sched.interval[0] = (set_mask & VXSM_MSEC) ? + msec_to_ticks(data->interval[0]) : data->interval[0]; + if (set_mask & VXSM_INTERVAL2) + vxi->sched.interval[1] = (set_mask & VXSM_MSEC) ? + msec_to_ticks(data->interval[1]) : data->interval[1]; + if (set_mask & VXSM_TOKENS) + vxi->sched.tokens = data->tokens; + if (set_mask & VXSM_TOKENS_MIN) + vxi->sched.tokens_min = data->tokens_min; + if (set_mask & VXSM_TOKENS_MAX) + vxi->sched.tokens_max = data->tokens_max; + if (set_mask & VXSM_PRIO_BIAS) + vxi->sched.prio_bias = data->prio_bias; + + /* Sanity check rate/interval */ + for (i = 0; i < 2; i++) { + if (data->fill_rate[i] < 0) + data->fill_rate[i] = 0; + if (data->interval[i] <= 0) + data->interval[i] = HZ; + } + + update_mask = vxi->sched.update_mask & VXSM_SET_MASK; + update_mask |= (set_mask & (VXSM_SET_MASK | VXSM_IDLE_TIME)); + vxi->sched.update_mask = update_mask; + +#ifdef CONFIG_SMP + rmb(); + if (set_mask & VXSM_CPU_ID) { + vxi->sched.update = cpumask_of_cpu(data->cpu_id); + cpus_and(vxi->sched.update, cpu_online_map, + vxi->sched.update); + } else + vxi->sched.update = cpu_online_map; + + /* forced reload? */ + if (set_mask & VXSM_FORCE) { + for_each_cpu_mask(cpu, vxi->sched.update) + vx_update_sched_param(&vxi->sched, + &vx_per_cpu(vxi, sched_pc, cpu)); + vxi->sched.update = CPU_MASK_NONE; + } +#else + /* on UP we update immediately */ + vx_update_sched_param(&vxi->sched, + &vx_per_cpu(vxi, sched_pc, 0)); +#endif + + spin_unlock(&vxi->sched.tokens_lock); + return 0; +} + + +#define COPY_IDS(C) C(cpu_id); C(bucket_id) +#define COPY_PRI(C) C(prio_bias) +#define COPY_TOK(C) C(tokens); C(tokens_min); C(tokens_max) +#define COPY_FRI(C) C(fill_rate[0]); C(interval[0]); \ + C(fill_rate[1]); C(interval[1]); + +#define COPY_VALUE(name) vc_data.name = data->name + +static int do_set_sched_v4(struct vx_info *vxi, struct vcmd_set_sched_v4 *data) +{ + struct vcmd_sched_v5 vc_data; + + vc_data.mask = data->set_mask; + COPY_IDS(COPY_VALUE); + COPY_PRI(COPY_VALUE); + COPY_TOK(COPY_VALUE); + vc_data.fill_rate[0] = vc_data.fill_rate[1] = data->fill_rate; + vc_data.interval[0] = vc_data.interval[1] = data->interval; + return do_set_sched(vxi, &vc_data); +} + +int vc_set_sched_v4(struct vx_info *vxi, void __user *data) +{ + struct vcmd_set_sched_v4 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_sched_v4(vxi, &vc_data); +} + + /* latest interface is v5 */ + +int vc_set_sched(struct vx_info *vxi, void __user *data) +{ + struct vcmd_sched_v5 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return do_set_sched(vxi, &vc_data); +} + + +#define COPY_PRI(C) C(prio_bias) +#define COPY_TOK(C) C(tokens); C(tokens_min); C(tokens_max) +#define COPY_FRI(C) C(fill_rate[0]); C(interval[0]); \ + C(fill_rate[1]); C(interval[1]); + +#define COPY_VALUE(name) vc_data.name = data->name + + +int vc_get_sched(struct vx_info *vxi, void __user *data) +{ + struct vcmd_sched_v5 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + if (vc_data.mask & VXSM_CPU_ID) { + int cpu = vc_data.cpu_id; + struct _vx_sched_pc *data; + + if (!cpu_possible(cpu)) + return -EINVAL; + + data = &vx_per_cpu(vxi, sched_pc, cpu); + COPY_TOK(COPY_VALUE); + COPY_PRI(COPY_VALUE); + COPY_FRI(COPY_VALUE); + + if (data->flags & VXSF_IDLE_TIME) + vc_data.mask |= VXSM_IDLE_TIME; + } else { + struct _vx_sched *data = &vxi->sched; + + COPY_TOK(COPY_VALUE); + COPY_PRI(COPY_VALUE); + COPY_FRI(COPY_VALUE); + } + + if (vc_data.mask & VXSM_MSEC) { + vc_data.interval[0] = ticks_to_msec(vc_data.interval[0]); + vc_data.interval[1] = ticks_to_msec(vc_data.interval[1]); + } + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + + +int vc_sched_info(struct vx_info *vxi, void __user *data) +{ + struct vcmd_sched_info vc_data; + int cpu; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + cpu = vc_data.cpu_id; + if (!cpu_possible(cpu)) + return -EINVAL; + + if (vxi) { + struct _vx_sched_pc *sched_pc = + &vx_per_cpu(vxi, sched_pc, cpu); + + vc_data.user_msec = ticks_to_msec(sched_pc->user_ticks); + vc_data.sys_msec = ticks_to_msec(sched_pc->sys_ticks); + vc_data.hold_msec = ticks_to_msec(sched_pc->hold_ticks); + vc_data.vavavoom = sched_pc->vavavoom; + } + vc_data.token_usec = ticks_to_usec(1); + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + return -EFAULT; + return 0; +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/sched_init.h linux-2.6.27.15-g-v/kernel/vserver/sched_init.h --- linux-2.6.27.15/kernel/vserver/sched_init.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/sched_init.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,50 @@ + +static inline void vx_info_init_sched(struct _vx_sched *sched) +{ + static struct lock_class_key tokens_lock_key; + + /* scheduling; hard code starting values as constants */ + sched->fill_rate[0] = 1; + sched->interval[0] = 4; + sched->fill_rate[1] = 1; + sched->interval[1] = 8; + sched->tokens = HZ >> 2; + sched->tokens_min = HZ >> 4; + sched->tokens_max = HZ >> 1; + sched->tokens_lock = SPIN_LOCK_UNLOCKED; + sched->prio_bias = 0; + + lockdep_set_class(&sched->tokens_lock, &tokens_lock_key); +} + +static inline +void vx_info_init_sched_pc(struct _vx_sched_pc *sched_pc, int cpu) +{ + sched_pc->fill_rate[0] = 1; + sched_pc->interval[0] = 4; + sched_pc->fill_rate[1] = 1; + sched_pc->interval[1] = 8; + sched_pc->tokens = HZ >> 2; + sched_pc->tokens_min = HZ >> 4; + sched_pc->tokens_max = HZ >> 1; + sched_pc->prio_bias = 0; + sched_pc->vavavoom = 0; + sched_pc->token_time = 0; + sched_pc->idle_time = 0; + sched_pc->norm_time = jiffies; + + sched_pc->user_ticks = 0; + sched_pc->sys_ticks = 0; + sched_pc->hold_ticks = 0; +} + +static inline void vx_info_exit_sched(struct _vx_sched *sched) +{ + return; +} + +static inline +void vx_info_exit_sched_pc(struct _vx_sched_pc *sched_pc, int cpu) +{ + return; +} diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/sched_proc.h linux-2.6.27.15-g-v/kernel/vserver/sched_proc.h --- linux-2.6.27.15/kernel/vserver/sched_proc.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/sched_proc.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,57 @@ +#ifndef _VX_SCHED_PROC_H +#define _VX_SCHED_PROC_H + + +static inline +int vx_info_proc_sched(struct _vx_sched *sched, char *buffer) +{ + int length = 0; + + length += sprintf(buffer, + "FillRate:\t%8d,%d\n" + "Interval:\t%8d,%d\n" + "TokensMin:\t%8d\n" + "TokensMax:\t%8d\n" + "PrioBias:\t%8d\n", + sched->fill_rate[0], + sched->fill_rate[1], + sched->interval[0], + sched->interval[1], + sched->tokens_min, + sched->tokens_max, + sched->prio_bias); + return length; +} + +static inline +int vx_info_proc_sched_pc(struct _vx_sched_pc *sched_pc, + char *buffer, int cpu) +{ + int length = 0; + + length += sprintf(buffer + length, + "cpu %d: %lld %lld %lld %ld %ld", cpu, + (unsigned long long)sched_pc->user_ticks, + (unsigned long long)sched_pc->sys_ticks, + (unsigned long long)sched_pc->hold_ticks, + sched_pc->token_time, + sched_pc->idle_time); + length += sprintf(buffer + length, + " %c%c %d %d %d %d/%d %d/%d", + (sched_pc->flags & VXSF_ONHOLD) ? 'H' : 'R', + (sched_pc->flags & VXSF_IDLE_TIME) ? 'I' : '-', + sched_pc->tokens, + sched_pc->tokens_min, + sched_pc->tokens_max, + sched_pc->fill_rate[0], + sched_pc->interval[0], + sched_pc->fill_rate[1], + sched_pc->interval[1]); + length += sprintf(buffer + length, + " %d %d\n", + sched_pc->prio_bias, + sched_pc->vavavoom); + return length; +} + +#endif /* _VX_SCHED_PROC_H */ diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/signal.c linux-2.6.27.15-g-v/kernel/vserver/signal.c --- linux-2.6.27.15/kernel/vserver/signal.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/signal.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,132 @@ +/* + * linux/kernel/vserver/signal.c + * + * Virtual Server: Signal Support + * + * Copyright (C) 2003-2007 Herbert Pötzl + * + * V0.01 broken out from vcontext V0.05 + * V0.02 changed vcmds to vxi arg + * V0.03 adjusted siginfo for kill + * + */ + +#include + +#include +#include +#include + + +int vx_info_kill(struct vx_info *vxi, int pid, int sig) +{ + int retval, count = 0; + struct task_struct *p; + struct siginfo *sip = SEND_SIG_PRIV; + + retval = -ESRCH; + vxdprintk(VXD_CBIT(misc, 4), + "vx_info_kill(%p[#%d],%d,%d)*", + vxi, vxi->vx_id, pid, sig); + read_lock(&tasklist_lock); + switch (pid) { + case 0: + case -1: + for_each_process(p) { + int err = 0; + + if (vx_task_xid(p) != vxi->vx_id || p->pid <= 1 || + (pid && vxi->vx_initpid == p->pid)) + continue; + + err = group_send_sig_info(sig, sip, p); + ++count; + if (err != -EPERM) + retval = err; + } + break; + + case 1: + if (vxi->vx_initpid) { + pid = vxi->vx_initpid; + /* for now, only SIGINT to private init ... */ + if (!vx_info_flags(vxi, VXF_STATE_ADMIN, 0) && + /* ... as long as there are tasks left */ + (atomic_read(&vxi->vx_tasks) > 1)) + sig = SIGINT; + } + /* fallthrough */ + default: + p = find_task_by_real_pid(pid); + if (p) { + if (vx_task_xid(p) == vxi->vx_id) + retval = group_send_sig_info(sig, sip, p); + } + break; + } + read_unlock(&tasklist_lock); + vxdprintk(VXD_CBIT(misc, 4), + "vx_info_kill(%p[#%d],%d,%d,%ld) = %d", + vxi, vxi->vx_id, pid, sig, (long)sip, retval); + return retval; +} + +int vc_ctx_kill(struct vx_info *vxi, void __user *data) +{ + struct vcmd_ctx_kill_v0 vc_data; + + if (copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + /* special check to allow guest shutdown */ + if (!vx_info_flags(vxi, VXF_STATE_ADMIN, 0) && + /* forbid killall pid=0 when init is present */ + (((vc_data.pid < 1) && vxi->vx_initpid) || + (vc_data.pid > 1))) + return -EACCES; + + return vx_info_kill(vxi, vc_data.pid, vc_data.sig); +} + + +static int __wait_exit(struct vx_info *vxi) +{ + DECLARE_WAITQUEUE(wait, current); + int ret = 0; + + add_wait_queue(&vxi->vx_wait, &wait); + set_current_state(TASK_INTERRUPTIBLE); + +wait: + if (vx_info_state(vxi, + VXS_SHUTDOWN | VXS_HASHED | VXS_HELPER) == VXS_SHUTDOWN) + goto out; + if (signal_pending(current)) { + ret = -ERESTARTSYS; + goto out; + } + schedule(); + goto wait; + +out: + set_current_state(TASK_RUNNING); + remove_wait_queue(&vxi->vx_wait, &wait); + return ret; +} + + + +int vc_wait_exit(struct vx_info *vxi, void __user *data) +{ + struct vcmd_wait_exit_v0 vc_data; + int ret; + + ret = __wait_exit(vxi); + vc_data.reboot_cmd = vxi->reboot_cmd; + vc_data.exit_code = vxi->exit_code; + + if (copy_to_user(data, &vc_data, sizeof(vc_data))) + ret = -EFAULT; + return ret; +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/space.c linux-2.6.27.15-g-v/kernel/vserver/space.c --- linux-2.6.27.15/kernel/vserver/space.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/space.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,398 @@ +/* + * linux/kernel/vserver/space.c + * + * Virtual Server: Context Space Support + * + * Copyright (C) 2003-2007 Herbert Pötzl + * + * V0.01 broken out from context.c 0.07 + * V0.02 added task locking for namespace + * V0.03 broken out vx_enter_namespace + * V0.04 added *space support and commands + * + */ + +#include +#include +#include +#include + +#include +#include +#include + +atomic_t vs_global_nsproxy = ATOMIC_INIT(0); +atomic_t vs_global_fs = ATOMIC_INIT(0); +atomic_t vs_global_mnt_ns = ATOMIC_INIT(0); +atomic_t vs_global_uts_ns = ATOMIC_INIT(0); +atomic_t vs_global_ipc_ns = ATOMIC_INIT(0); +atomic_t vs_global_user_ns = ATOMIC_INIT(0); +atomic_t vs_global_pid_ns = ATOMIC_INIT(0); + + +/* namespace functions */ + +#include +#include +#include +#include +#include + + +static const struct vcmd_space_mask_v1 space_mask_v0 = { + .mask = CLONE_FS | + CLONE_NEWNS | + CLONE_NEWUTS | + CLONE_NEWIPC | + CLONE_NEWUSER | + 0 +}; + +static const struct vcmd_space_mask_v1 space_mask = { + .mask = CLONE_FS | + CLONE_NEWNS | + CLONE_NEWUTS | + CLONE_NEWIPC | + CLONE_NEWUSER | +#ifdef CONFIG_PID_NS + CLONE_NEWPID | +#endif +#ifdef CONFIG_NET_NS + CLONE_NEWNET | +#endif + 0 +}; + +static const struct vcmd_space_mask_v1 default_space_mask = { + .mask = CLONE_FS | + CLONE_NEWNS | + CLONE_NEWUTS | + CLONE_NEWIPC | + CLONE_NEWUSER | +#ifdef CONFIG_PID_NS +// CLONE_NEWPID | +#endif + 0 +}; + +/* + * build a new nsproxy mix + * assumes that both proxies are 'const' + * does not touch nsproxy refcounts + * will hold a reference on the result. + */ + +struct nsproxy *vs_mix_nsproxy(struct nsproxy *old_nsproxy, + struct nsproxy *new_nsproxy, unsigned long mask) +{ + struct mnt_namespace *old_ns; + struct uts_namespace *old_uts; + struct ipc_namespace *old_ipc; + struct user_namespace *old_user; +#ifdef CONFIG_PID_NS + struct pid_namespace *old_pid; +#endif +#ifdef CONFIG_NET_NS + struct net *old_net; +#endif + struct nsproxy *nsproxy; + + nsproxy = copy_nsproxy(old_nsproxy); + if (!nsproxy) + goto out; + + if (mask & CLONE_NEWNS) { + old_ns = nsproxy->mnt_ns; + nsproxy->mnt_ns = new_nsproxy->mnt_ns; + if (nsproxy->mnt_ns) + get_mnt_ns(nsproxy->mnt_ns); + } else + old_ns = NULL; + + if (mask & CLONE_NEWUTS) { + old_uts = nsproxy->uts_ns; + nsproxy->uts_ns = new_nsproxy->uts_ns; + if (nsproxy->uts_ns) + get_uts_ns(nsproxy->uts_ns); + } else + old_uts = NULL; + + if (mask & CLONE_NEWIPC) { + old_ipc = nsproxy->ipc_ns; + nsproxy->ipc_ns = new_nsproxy->ipc_ns; + if (nsproxy->ipc_ns) + get_ipc_ns(nsproxy->ipc_ns); + } else + old_ipc = NULL; + + if (mask & CLONE_NEWUSER) { + old_user = nsproxy->user_ns; + nsproxy->user_ns = new_nsproxy->user_ns; + if (nsproxy->user_ns) + get_user_ns(nsproxy->user_ns); + } else + old_user = NULL; + +#ifdef CONFIG_PID_NS + if (mask & CLONE_NEWPID) { + old_pid = nsproxy->pid_ns; + nsproxy->pid_ns = new_nsproxy->pid_ns; + if (nsproxy->pid_ns) + get_pid_ns(nsproxy->pid_ns); + } else + old_pid = NULL; +#endif +#ifdef CONFIG_NET_NS + if (mask & CLONE_NEWNET) { + old_net = nsproxy->net_ns; + nsproxy->net_ns = new_nsproxy->net_ns; + if (nsproxy->net_ns) + get_net(nsproxy->net_ns); + } else + old_net = NULL; +#endif + if (old_ns) + put_mnt_ns(old_ns); + if (old_uts) + put_uts_ns(old_uts); + if (old_ipc) + put_ipc_ns(old_ipc); + if (old_user) + put_user_ns(old_user); +#ifdef CONFIG_PID_NS + if (old_pid) + put_pid_ns(old_pid); +#endif +#ifdef CONFIG_NET_NS + if (old_net) + put_net(old_net); +#endif +out: + return nsproxy; +} + + +/* + * merge two nsproxy structs into a new one. + * will hold a reference on the result. + */ + +static inline +struct nsproxy *__vs_merge_nsproxy(struct nsproxy *old, + struct nsproxy *proxy, unsigned long mask) +{ + struct nsproxy null_proxy = { .mnt_ns = NULL }; + + if (!proxy) + return NULL; + + if (mask) { + /* vs_mix_nsproxy returns with reference */ + return vs_mix_nsproxy(old ? old : &null_proxy, + proxy, mask); + } + get_nsproxy(proxy); + return proxy; +} + +/* + * merge two fs structs into a new one. + * will take a reference on the result. + */ + +static inline +struct fs_struct *__vs_merge_fs(struct fs_struct *old, + struct fs_struct *fs, unsigned long mask) +{ + if (!(mask & CLONE_FS)) { + if (old) + atomic_inc(&old->count); + return old; + } + + if (!fs) + return NULL; + + return copy_fs_struct(fs); +} + + +int vx_enter_space(struct vx_info *vxi, unsigned long mask, unsigned index) +{ + struct nsproxy *proxy, *proxy_cur, *proxy_new; + struct fs_struct *fs, *fs_cur, *fs_new; + int ret; + + vxdprintk(VXD_CBIT(space, 8), "vx_enter_space(%p[#%u],0x%08lx,%d)", + vxi, vxi->vx_id, mask, index); + + if (vx_info_flags(vxi, VXF_INFO_PRIVATE, 0)) + return -EACCES; + + if (!mask) + mask = vxi->vx_nsmask[index]; + + if ((mask & vxi->vx_nsmask[index]) != mask) + return -EINVAL; + + proxy = vxi->vx_nsproxy[index]; + fs = vxi->vx_fs[index]; + + task_lock(current); + fs_cur = current->fs; + atomic_inc(&fs_cur->count); + proxy_cur = current->nsproxy; + get_nsproxy(proxy_cur); + task_unlock(current); + + fs_new = __vs_merge_fs(fs_cur, fs, mask); + if (IS_ERR(fs_new)) { + ret = PTR_ERR(fs_new); + goto out_put; + } + + proxy_new = __vs_merge_nsproxy(proxy_cur, proxy, mask); + if (IS_ERR(proxy_new)) { + ret = PTR_ERR(proxy_new); + goto out_put_fs; + } + + fs_new = xchg(¤t->fs, fs_new); + proxy_new = xchg(¤t->nsproxy, proxy_new); + ret = 0; + + if (proxy_new) + put_nsproxy(proxy_new); +out_put_fs: + if (fs_new) + put_fs_struct(fs_new); +out_put: + if (proxy_cur) + put_nsproxy(proxy_cur); + if (fs_cur) + put_fs_struct(fs_cur); + return ret; +} + + +int vx_set_space(struct vx_info *vxi, unsigned long mask, unsigned index) +{ + struct nsproxy *proxy_vxi, *proxy_cur, *proxy_new; + struct fs_struct *fs_vxi, *fs_cur, *fs_new; + int ret; + + vxdprintk(VXD_CBIT(space, 8), "vx_set_space(%p[#%u],0x%08lx,%d)", + vxi, vxi->vx_id, mask, index); +#if 0 + if (!mask) + mask = default_space_mask.mask; +#endif + if ((mask & space_mask.mask) != mask) + return -EINVAL; + + proxy_vxi = vxi->vx_nsproxy[index]; + fs_vxi = vxi->vx_fs[index]; + + task_lock(current); + fs_cur = current->fs; + atomic_inc(&fs_cur->count); + proxy_cur = current->nsproxy; + get_nsproxy(proxy_cur); + task_unlock(current); + + fs_new = __vs_merge_fs(fs_vxi, fs_cur, mask); + if (IS_ERR(fs_new)) { + ret = PTR_ERR(fs_new); + goto out_put; + } + + proxy_new = __vs_merge_nsproxy(proxy_vxi, proxy_cur, mask); + if (IS_ERR(proxy_new)) { + ret = PTR_ERR(proxy_new); + goto out_put_fs; + } + + fs_new = xchg(&vxi->vx_fs[index], fs_new); + proxy_new = xchg(&vxi->vx_nsproxy[index], proxy_new); + vxi->vx_nsmask[index] |= mask; + ret = 0; + + if (proxy_new) + put_nsproxy(proxy_new); +out_put_fs: + if (fs_new) + put_fs_struct(fs_new); +out_put: + if (proxy_cur) + put_nsproxy(proxy_cur); + if (fs_cur) + put_fs_struct(fs_cur); + return ret; +} + + +int vc_enter_space_v1(struct vx_info *vxi, void __user *data) +{ + struct vcmd_space_mask_v1 vc_data = { .mask = 0 }; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return vx_enter_space(vxi, vc_data.mask, 0); +} + +int vc_enter_space(struct vx_info *vxi, void __user *data) +{ + struct vcmd_space_mask_v2 vc_data = { .mask = 0 }; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + if (vc_data.index >= VX_SPACES) + return -EINVAL; + + return vx_enter_space(vxi, vc_data.mask, vc_data.index); +} + +int vc_set_space_v1(struct vx_info *vxi, void __user *data) +{ + struct vcmd_space_mask_v1 vc_data = { .mask = 0 }; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + return vx_set_space(vxi, vc_data.mask, 0); +} + +int vc_set_space(struct vx_info *vxi, void __user *data) +{ + struct vcmd_space_mask_v2 vc_data = { .mask = 0 }; + + if (data && copy_from_user(&vc_data, data, sizeof(vc_data))) + return -EFAULT; + + if (vc_data.index >= VX_SPACES) + return -EINVAL; + + return vx_set_space(vxi, vc_data.mask, vc_data.index); +} + +int vc_get_space_mask(void __user *data, int type) +{ + const struct vcmd_space_mask_v1 *mask; + + if (type == 0) + mask = &space_mask_v0; + else if (type == 1) + mask = &space_mask; + else + mask = &default_space_mask; + + vxdprintk(VXD_CBIT(space, 10), + "vc_get_space_mask(%d) = %08llx", type, mask->mask); + + if (copy_to_user(data, mask, sizeof(*mask))) + return -EFAULT; + return 0; +} + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/switch.c linux-2.6.27.15-g-v/kernel/vserver/switch.c --- linux-2.6.27.15/kernel/vserver/switch.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/switch.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,543 @@ +/* + * linux/kernel/vserver/switch.c + * + * Virtual Server: Syscall Switch + * + * Copyright (C) 2003-2007 Herbert Pötzl + * + * V0.01 syscall switch + * V0.02 added signal to context + * V0.03 added rlimit functions + * V0.04 added iattr, task/xid functions + * V0.05 added debug/history stuff + * V0.06 added compat32 layer + * V0.07 vcmd args and perms + * V0.08 added status commands + * V0.09 added tag commands + * V0.10 added oom bias + * V0.11 added device commands + * + */ + +#include +#include +#include + +#include "vci_config.h" + + +static inline +int vc_get_version(uint32_t id) +{ + return VCI_VERSION; +} + +static inline +int vc_get_vci(uint32_t id) +{ + return vci_kernel_config(); +} + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + + +#ifdef CONFIG_COMPAT +#define __COMPAT(name, id, data, compat) \ + (compat) ? name ## _x32(id, data) : name(id, data) +#define __COMPAT_NO_ID(name, data, compat) \ + (compat) ? name ## _x32(data) : name(data) +#else +#define __COMPAT(name, id, data, compat) \ + name(id, data) +#define __COMPAT_NO_ID(name, data, compat) \ + name(data) +#endif + + +static inline +long do_vcmd(uint32_t cmd, uint32_t id, + struct vx_info *vxi, struct nx_info *nxi, + void __user *data, int compat) +{ + switch (cmd) { + + case VCMD_get_version: + return vc_get_version(id); + case VCMD_get_vci: + return vc_get_vci(id); + + case VCMD_task_xid: + return vc_task_xid(id); + case VCMD_vx_info: + return vc_vx_info(vxi, data); + + case VCMD_task_nid: + return vc_task_nid(id); + case VCMD_nx_info: + return vc_nx_info(nxi, data); + + case VCMD_task_tag: + return vc_task_tag(id); + + case VCMD_set_space_v1: + return vc_set_space_v1(vxi, data); + /* this is version 2 */ + case VCMD_set_space: + return vc_set_space(vxi, data); + + case VCMD_get_space_mask_v0: + return vc_get_space_mask(data, 0); + /* this is version 1 */ + case VCMD_get_space_mask: + return vc_get_space_mask(data, 1); + + case VCMD_get_space_default: + return vc_get_space_mask(data, -1); + +#ifdef CONFIG_IA32_EMULATION + case VCMD_get_rlimit: + return __COMPAT(vc_get_rlimit, vxi, data, compat); + case VCMD_set_rlimit: + return __COMPAT(vc_set_rlimit, vxi, data, compat); +#else + case VCMD_get_rlimit: + return vc_get_rlimit(vxi, data); + case VCMD_set_rlimit: + return vc_set_rlimit(vxi, data); +#endif + case VCMD_get_rlimit_mask: + return vc_get_rlimit_mask(id, data); + case VCMD_reset_minmax: + return vc_reset_minmax(vxi, data); + + case VCMD_get_vhi_name: + return vc_get_vhi_name(vxi, data); + case VCMD_set_vhi_name: + return vc_set_vhi_name(vxi, data); + + case VCMD_ctx_stat: + return vc_ctx_stat(vxi, data); + case VCMD_virt_stat: + return vc_virt_stat(vxi, data); + case VCMD_sock_stat: + return vc_sock_stat(vxi, data); + case VCMD_rlimit_stat: + return vc_rlimit_stat(vxi, data); + + case VCMD_set_cflags: + return vc_set_cflags(vxi, data); + case VCMD_get_cflags: + return vc_get_cflags(vxi, data); + + /* this is version 1 */ + case VCMD_set_ccaps: + return vc_set_ccaps(vxi, data); + /* this is version 1 */ + case VCMD_get_ccaps: + return vc_get_ccaps(vxi, data); + case VCMD_set_bcaps: + return vc_set_bcaps(vxi, data); + case VCMD_get_bcaps: + return vc_get_bcaps(vxi, data); + + case VCMD_set_badness: + return vc_set_badness(vxi, data); + case VCMD_get_badness: + return vc_get_badness(vxi, data); + + case VCMD_set_nflags: + return vc_set_nflags(nxi, data); + case VCMD_get_nflags: + return vc_get_nflags(nxi, data); + + case VCMD_set_ncaps: + return vc_set_ncaps(nxi, data); + case VCMD_get_ncaps: + return vc_get_ncaps(nxi, data); + + case VCMD_set_sched_v4: + return vc_set_sched_v4(vxi, data); + /* this is version 5 */ + case VCMD_set_sched: + return vc_set_sched(vxi, data); + case VCMD_get_sched: + return vc_get_sched(vxi, data); + case VCMD_sched_info: + return vc_sched_info(vxi, data); + + case VCMD_add_dlimit: + return __COMPAT(vc_add_dlimit, id, data, compat); + case VCMD_rem_dlimit: + return __COMPAT(vc_rem_dlimit, id, data, compat); + case VCMD_set_dlimit: + return __COMPAT(vc_set_dlimit, id, data, compat); + case VCMD_get_dlimit: + return __COMPAT(vc_get_dlimit, id, data, compat); + + case VCMD_ctx_kill: + return vc_ctx_kill(vxi, data); + + case VCMD_wait_exit: + return vc_wait_exit(vxi, data); + + case VCMD_get_iattr: + return __COMPAT_NO_ID(vc_get_iattr, data, compat); + case VCMD_set_iattr: + return __COMPAT_NO_ID(vc_set_iattr, data, compat); + + case VCMD_fget_iattr: + return vc_fget_iattr(id, data); + case VCMD_fset_iattr: + return vc_fset_iattr(id, data); + + case VCMD_enter_space_v0: + return vc_enter_space_v1(vxi, NULL); + case VCMD_enter_space_v1: + return vc_enter_space_v1(vxi, data); + /* this is version 2 */ + case VCMD_enter_space: + return vc_enter_space(vxi, data); + + case VCMD_ctx_create_v0: + return vc_ctx_create(id, NULL); + case VCMD_ctx_create: + return vc_ctx_create(id, data); + case VCMD_ctx_migrate_v0: + return vc_ctx_migrate(vxi, NULL); + case VCMD_ctx_migrate: + return vc_ctx_migrate(vxi, data); + + case VCMD_net_create_v0: + return vc_net_create(id, NULL); + case VCMD_net_create: + return vc_net_create(id, data); + case VCMD_net_migrate: + return vc_net_migrate(nxi, data); + + case VCMD_tag_migrate: + return vc_tag_migrate(id); + + case VCMD_net_add: + return vc_net_add(nxi, data); + case VCMD_net_remove: + return vc_net_remove(nxi, data); + + case VCMD_net_add_ipv4: + return vc_net_add_ipv4(nxi, data); + case VCMD_net_remove_ipv4: + return vc_net_remove_ipv4(nxi, data); +#ifdef CONFIG_IPV6 + case VCMD_net_add_ipv6: + return vc_net_add_ipv6(nxi, data); + case VCMD_net_remove_ipv6: + return vc_net_remove_ipv6(nxi, data); +#endif +/* case VCMD_add_match_ipv4: + return vc_add_match_ipv4(nxi, data); + case VCMD_get_match_ipv4: + return vc_get_match_ipv4(nxi, data); +#ifdef CONFIG_IPV6 + case VCMD_add_match_ipv6: + return vc_add_match_ipv6(nxi, data); + case VCMD_get_match_ipv6: + return vc_get_match_ipv6(nxi, data); +#endif */ + +#ifdef CONFIG_VSERVER_DEVICE + case VCMD_set_mapping: + return __COMPAT(vc_set_mapping, vxi, data, compat); + case VCMD_unset_mapping: + return __COMPAT(vc_unset_mapping, vxi, data, compat); +#endif +#ifdef CONFIG_VSERVER_HISTORY + case VCMD_dump_history: + return vc_dump_history(id); + case VCMD_read_history: + return __COMPAT(vc_read_history, id, data, compat); +#endif +#ifdef CONFIG_VSERVER_MONITOR + case VCMD_read_monitor: + return __COMPAT(vc_read_monitor, id, data, compat); +#endif + default: + vxwprintk_task(1, "unimplemented VCMD_%02d_%d[%d]", + VC_CATEGORY(cmd), VC_COMMAND(cmd), VC_VERSION(cmd)); + } + return -ENOSYS; +} + + +#define __VCMD(vcmd, _perm, _args, _flags) \ + case VCMD_ ## vcmd: perm = _perm; \ + args = _args; flags = _flags; break + + +#define VCA_NONE 0x00 +#define VCA_VXI 0x01 +#define VCA_NXI 0x02 + +#define VCF_NONE 0x00 +#define VCF_INFO 0x01 +#define VCF_ADMIN 0x02 +#define VCF_ARES 0x06 /* includes admin */ +#define VCF_SETUP 0x08 + +#define VCF_ZIDOK 0x10 /* zero id okay */ + + +static inline +long do_vserver(uint32_t cmd, uint32_t id, void __user *data, int compat) +{ + long ret; + int permit = -1, state = 0; + int perm = -1, args = 0, flags = 0; + struct vx_info *vxi = NULL; + struct nx_info *nxi = NULL; + + switch (cmd) { + /* unpriviledged commands */ + __VCMD(get_version, 0, VCA_NONE, 0); + __VCMD(get_vci, 0, VCA_NONE, 0); + __VCMD(get_rlimit_mask, 0, VCA_NONE, 0); + __VCMD(get_space_mask_v0,0, VCA_NONE, 0); + __VCMD(get_space_mask, 0, VCA_NONE, 0); + __VCMD(get_space_default,0, VCA_NONE, 0); + + /* info commands */ + __VCMD(task_xid, 2, VCA_NONE, 0); + __VCMD(reset_minmax, 2, VCA_VXI, 0); + __VCMD(vx_info, 3, VCA_VXI, VCF_INFO); + __VCMD(get_bcaps, 3, VCA_VXI, VCF_INFO); + __VCMD(get_ccaps, 3, VCA_VXI, VCF_INFO); + __VCMD(get_cflags, 3, VCA_VXI, VCF_INFO); + __VCMD(get_badness, 3, VCA_VXI, VCF_INFO); + __VCMD(get_vhi_name, 3, VCA_VXI, VCF_INFO); + __VCMD(get_rlimit, 3, VCA_VXI, VCF_INFO); + + __VCMD(ctx_stat, 3, VCA_VXI, VCF_INFO); + __VCMD(virt_stat, 3, VCA_VXI, VCF_INFO); + __VCMD(sock_stat, 3, VCA_VXI, VCF_INFO); + __VCMD(rlimit_stat, 3, VCA_VXI, VCF_INFO); + + __VCMD(task_nid, 2, VCA_NONE, 0); + __VCMD(nx_info, 3, VCA_NXI, VCF_INFO); + __VCMD(get_ncaps, 3, VCA_NXI, VCF_INFO); + __VCMD(get_nflags, 3, VCA_NXI, VCF_INFO); + + __VCMD(task_tag, 2, VCA_NONE, 0); + + __VCMD(get_iattr, 2, VCA_NONE, 0); + __VCMD(fget_iattr, 2, VCA_NONE, 0); + __VCMD(get_dlimit, 3, VCA_NONE, VCF_INFO); + __VCMD(get_sched, 3, VCA_VXI, VCF_INFO); + __VCMD(sched_info, 3, VCA_VXI, VCF_INFO | VCF_ZIDOK); + + /* lower admin commands */ + __VCMD(wait_exit, 4, VCA_VXI, VCF_INFO); + __VCMD(ctx_create_v0, 5, VCA_NONE, 0); + __VCMD(ctx_create, 5, VCA_NONE, 0); + __VCMD(ctx_migrate_v0, 5, VCA_VXI, VCF_ADMIN); + __VCMD(ctx_migrate, 5, VCA_VXI, VCF_ADMIN); + __VCMD(enter_space_v0, 5, VCA_VXI, VCF_ADMIN); + __VCMD(enter_space_v1, 5, VCA_VXI, VCF_ADMIN); + __VCMD(enter_space, 5, VCA_VXI, VCF_ADMIN); + + __VCMD(net_create_v0, 5, VCA_NONE, 0); + __VCMD(net_create, 5, VCA_NONE, 0); + __VCMD(net_migrate, 5, VCA_NXI, VCF_ADMIN); + + __VCMD(tag_migrate, 5, VCA_NONE, VCF_ADMIN); + + /* higher admin commands */ + __VCMD(ctx_kill, 6, VCA_VXI, VCF_ARES); + __VCMD(set_space_v1, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + __VCMD(set_space, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + + __VCMD(set_ccaps, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + __VCMD(set_bcaps, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + __VCMD(set_cflags, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + __VCMD(set_badness, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + + __VCMD(set_vhi_name, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + __VCMD(set_rlimit, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + __VCMD(set_sched, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + __VCMD(set_sched_v4, 7, VCA_VXI, VCF_ARES | VCF_SETUP); + + __VCMD(set_ncaps, 7, VCA_NXI, VCF_ARES | VCF_SETUP); + __VCMD(set_nflags, 7, VCA_NXI, VCF_ARES | VCF_SETUP); + __VCMD(net_add, 8, VCA_NXI, VCF_ARES | VCF_SETUP); + __VCMD(net_remove, 8, VCA_NXI, VCF_ARES | VCF_SETUP); + __VCMD(net_add_ipv4, 8, VCA_NXI, VCF_ARES | VCF_SETUP); + __VCMD(net_remove_ipv4, 8, VCA_NXI, VCF_ARES | VCF_SETUP); +#ifdef CONFIG_IPV6 + __VCMD(net_add_ipv6, 8, VCA_NXI, VCF_ARES | VCF_SETUP); + __VCMD(net_remove_ipv6, 8, VCA_NXI, VCF_ARES | VCF_SETUP); +#endif + __VCMD(set_iattr, 7, VCA_NONE, 0); + __VCMD(fset_iattr, 7, VCA_NONE, 0); + __VCMD(set_dlimit, 7, VCA_NONE, VCF_ARES); + __VCMD(add_dlimit, 8, VCA_NONE, VCF_ARES); + __VCMD(rem_dlimit, 8, VCA_NONE, VCF_ARES); + +#ifdef CONFIG_VSERVER_DEVICE + __VCMD(set_mapping, 8, VCA_VXI, VCF_ARES|VCF_ZIDOK); + __VCMD(unset_mapping, 8, VCA_VXI, VCF_ARES|VCF_ZIDOK); +#endif + /* debug level admin commands */ +#ifdef CONFIG_VSERVER_HISTORY + __VCMD(dump_history, 9, VCA_NONE, 0); + __VCMD(read_history, 9, VCA_NONE, 0); +#endif +#ifdef CONFIG_VSERVER_MONITOR + __VCMD(read_monitor, 9, VCA_NONE, 0); +#endif + + default: + perm = -1; + } + + vxdprintk(VXD_CBIT(switch, 0), + "vc: VCMD_%02d_%d[%d], %d,%p [%d,%d,%x,%x]", + VC_CATEGORY(cmd), VC_COMMAND(cmd), + VC_VERSION(cmd), id, data, compat, + perm, args, flags); + + ret = -ENOSYS; + if (perm < 0) + goto out; + + state = 1; + if (!capable(CAP_CONTEXT)) + goto out; + + state = 2; + /* moved here from the individual commands */ + ret = -EPERM; + if ((perm > 1) && !capable(CAP_SYS_ADMIN)) + goto out; + + state = 3; + /* vcmd involves resource management */ + ret = -EPERM; + if ((flags & VCF_ARES) && !capable(CAP_SYS_RESOURCE)) + goto out; + + state = 4; + /* various legacy exceptions */ + switch (cmd) { + /* will go away when spectator is a cap */ + case VCMD_ctx_migrate_v0: + case VCMD_ctx_migrate: + if (id == 1) { + current->xid = 1; + ret = 1; + goto out; + } + break; + + /* will go away when spectator is a cap */ + case VCMD_net_migrate: + if (id == 1) { + current->nid = 1; + ret = 1; + goto out; + } + break; + } + + /* vcmds are fine by default */ + permit = 1; + + /* admin type vcmds require admin ... */ + if (flags & VCF_ADMIN) + permit = vx_check(0, VS_ADMIN) ? 1 : 0; + + /* ... but setup type vcmds override that */ + if (!permit && (flags & VCF_SETUP)) + permit = vx_flags(VXF_STATE_SETUP, 0) ? 2 : 0; + + state = 5; + ret = -EPERM; + if (!permit) + goto out; + + state = 6; + if (!id && (flags & VCF_ZIDOK)) + goto skip_id; + + ret = -ESRCH; + if (args & VCA_VXI) { + vxi = lookup_vx_info(id); + if (!vxi) + goto out; + + if ((flags & VCF_ADMIN) && + /* special case kill for shutdown */ + (cmd != VCMD_ctx_kill) && + /* can context be administrated? */ + !vx_info_flags(vxi, VXF_STATE_ADMIN, 0)) { + ret = -EACCES; + goto out_vxi; + } + } + state = 7; + if (args & VCA_NXI) { + nxi = lookup_nx_info(id); + if (!nxi) + goto out_vxi; + + if ((flags & VCF_ADMIN) && + /* can context be administrated? */ + !nx_info_flags(nxi, NXF_STATE_ADMIN, 0)) { + ret = -EACCES; + goto out_nxi; + } + } +skip_id: + state = 8; + ret = do_vcmd(cmd, id, vxi, nxi, data, compat); + +out_nxi: + if ((args & VCA_NXI) && nxi) + put_nx_info(nxi); +out_vxi: + if ((args & VCA_VXI) && vxi) + put_vx_info(vxi); +out: + vxdprintk(VXD_CBIT(switch, 1), + "vc: VCMD_%02d_%d[%d] = %08lx(%ld) [%d,%d]", + VC_CATEGORY(cmd), VC_COMMAND(cmd), + VC_VERSION(cmd), ret, ret, state, permit); + return ret; +} + +asmlinkage long +sys_vserver(uint32_t cmd, uint32_t id, void __user *data) +{ + return do_vserver(cmd, id, data, 0); +} + +#ifdef CONFIG_COMPAT + +asmlinkage long +sys32_vserver(uint32_t cmd, uint32_t id, void __user *data) +{ + return do_vserver(cmd, id, data, 1); +} + +#endif /* CONFIG_COMPAT */ diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/sysctl.c linux-2.6.27.15-g-v/kernel/vserver/sysctl.c --- linux-2.6.27.15/kernel/vserver/sysctl.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/sysctl.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,244 @@ +/* + * kernel/vserver/sysctl.c + * + * Virtual Context Support + * + * Copyright (C) 2004-2007 Herbert Pötzl + * + * V0.01 basic structure + * + */ + +#include +#include +#include +#include +#include + + +enum { + CTL_DEBUG_ERROR = 0, + CTL_DEBUG_SWITCH = 1, + CTL_DEBUG_XID, + CTL_DEBUG_NID, + CTL_DEBUG_TAG, + CTL_DEBUG_NET, + CTL_DEBUG_LIMIT, + CTL_DEBUG_CRES, + CTL_DEBUG_DLIM, + CTL_DEBUG_QUOTA, + CTL_DEBUG_CVIRT, + CTL_DEBUG_SPACE, + CTL_DEBUG_MISC, +}; + + +unsigned int vx_debug_switch = 0; +unsigned int vx_debug_xid = 0; +unsigned int vx_debug_nid = 0; +unsigned int vx_debug_tag = 0; +unsigned int vx_debug_net = 0; +unsigned int vx_debug_limit = 0; +unsigned int vx_debug_cres = 0; +unsigned int vx_debug_dlim = 0; +unsigned int vx_debug_quota = 0; +unsigned int vx_debug_cvirt = 0; +unsigned int vx_debug_space = 0; +unsigned int vx_debug_misc = 0; + + +static struct ctl_table_header *vserver_table_header; +static ctl_table vserver_root_table[]; + + +void vserver_register_sysctl(void) +{ + if (!vserver_table_header) { + vserver_table_header = register_sysctl_table(vserver_root_table); + } + +} + +void vserver_unregister_sysctl(void) +{ + if (vserver_table_header) { + unregister_sysctl_table(vserver_table_header); + vserver_table_header = NULL; + } +} + + +static int proc_dodebug(ctl_table *table, int write, + struct file *filp, void __user *buffer, size_t *lenp, loff_t *ppos) +{ + char tmpbuf[20], *p, c; + unsigned int value; + size_t left, len; + + if ((*ppos && !write) || !*lenp) { + *lenp = 0; + return 0; + } + + left = *lenp; + + if (write) { + if (!access_ok(VERIFY_READ, buffer, left)) + return -EFAULT; + p = (char *)buffer; + while (left && __get_user(c, p) >= 0 && isspace(c)) + left--, p++; + if (!left) + goto done; + + if (left > sizeof(tmpbuf) - 1) + return -EINVAL; + if (copy_from_user(tmpbuf, p, left)) + return -EFAULT; + tmpbuf[left] = '\0'; + + for (p = tmpbuf, value = 0; '0' <= *p && *p <= '9'; p++, left--) + value = 10 * value + (*p - '0'); + if (*p && !isspace(*p)) + return -EINVAL; + while (left && isspace(*p)) + left--, p++; + *(unsigned int *)table->data = value; + } else { + if (!access_ok(VERIFY_WRITE, buffer, left)) + return -EFAULT; + len = sprintf(tmpbuf, "%d", *(unsigned int *)table->data); + if (len > left) + len = left; + if (__copy_to_user(buffer, tmpbuf, len)) + return -EFAULT; + if ((left -= len) > 0) { + if (put_user('\n', (char *)buffer + len)) + return -EFAULT; + left--; + } + } + +done: + *lenp -= left; + *ppos += *lenp; + return 0; +} + +static int zero; + +#define CTL_ENTRY(ctl, name) \ + { \ + .ctl_name = ctl, \ + .procname = #name, \ + .data = &vx_ ## name, \ + .maxlen = sizeof(int), \ + .mode = 0644, \ + .proc_handler = &proc_dodebug, \ + .strategy = &sysctl_intvec, \ + .extra1 = &zero, \ + } + +static ctl_table vserver_debug_table[] = { + CTL_ENTRY(CTL_DEBUG_SWITCH, debug_switch), + CTL_ENTRY(CTL_DEBUG_XID, debug_xid), + CTL_ENTRY(CTL_DEBUG_NID, debug_nid), + CTL_ENTRY(CTL_DEBUG_TAG, debug_tag), + CTL_ENTRY(CTL_DEBUG_NET, debug_net), + CTL_ENTRY(CTL_DEBUG_LIMIT, debug_limit), + CTL_ENTRY(CTL_DEBUG_CRES, debug_cres), + CTL_ENTRY(CTL_DEBUG_DLIM, debug_dlim), + CTL_ENTRY(CTL_DEBUG_QUOTA, debug_quota), + CTL_ENTRY(CTL_DEBUG_CVIRT, debug_cvirt), + CTL_ENTRY(CTL_DEBUG_SPACE, debug_space), + CTL_ENTRY(CTL_DEBUG_MISC, debug_misc), + { .ctl_name = 0 } +}; + +static ctl_table vserver_root_table[] = { + { + .ctl_name = CTL_VSERVER, + .procname = "vserver", + .mode = 0555, + .child = vserver_debug_table + }, + { .ctl_name = 0 } +}; + + +static match_table_t tokens = { + { CTL_DEBUG_SWITCH, "switch=%x" }, + { CTL_DEBUG_XID, "xid=%x" }, + { CTL_DEBUG_NID, "nid=%x" }, + { CTL_DEBUG_TAG, "tag=%x" }, + { CTL_DEBUG_NET, "net=%x" }, + { CTL_DEBUG_LIMIT, "limit=%x" }, + { CTL_DEBUG_CRES, "cres=%x" }, + { CTL_DEBUG_DLIM, "dlim=%x" }, + { CTL_DEBUG_QUOTA, "quota=%x" }, + { CTL_DEBUG_CVIRT, "cvirt=%x" }, + { CTL_DEBUG_SPACE, "space=%x" }, + { CTL_DEBUG_MISC, "misc=%x" }, + { CTL_DEBUG_ERROR, NULL } +}; + +#define HANDLE_CASE(id, name, val) \ + case CTL_DEBUG_ ## id: \ + vx_debug_ ## name = val; \ + printk("vs_debug_" #name "=0x%x\n", val); \ + break + + +static int __init vs_debug_setup(char *str) +{ + char *p; + int token; + + printk("vs_debug_setup(%s)\n", str); + while ((p = strsep(&str, ",")) != NULL) { + substring_t args[MAX_OPT_ARGS]; + unsigned int value; + + if (!*p) + continue; + + token = match_token(p, tokens, args); + value = (token > 0) ? simple_strtoul(args[0].from, NULL, 0) : 0; + + switch (token) { + HANDLE_CASE(SWITCH, switch, value); + HANDLE_CASE(XID, xid, value); + HANDLE_CASE(NID, nid, value); + HANDLE_CASE(TAG, tag, value); + HANDLE_CASE(NET, net, value); + HANDLE_CASE(LIMIT, limit, value); + HANDLE_CASE(CRES, cres, value); + HANDLE_CASE(DLIM, dlim, value); + HANDLE_CASE(QUOTA, quota, value); + HANDLE_CASE(CVIRT, cvirt, value); + HANDLE_CASE(SPACE, space, value); + HANDLE_CASE(MISC, misc, value); + default: + return -EINVAL; + break; + } + } + return 1; +} + +__setup("vsdebug=", vs_debug_setup); + + + +EXPORT_SYMBOL_GPL(vx_debug_switch); +EXPORT_SYMBOL_GPL(vx_debug_xid); +EXPORT_SYMBOL_GPL(vx_debug_nid); +EXPORT_SYMBOL_GPL(vx_debug_net); +EXPORT_SYMBOL_GPL(vx_debug_limit); +EXPORT_SYMBOL_GPL(vx_debug_cres); +EXPORT_SYMBOL_GPL(vx_debug_dlim); +EXPORT_SYMBOL_GPL(vx_debug_quota); +EXPORT_SYMBOL_GPL(vx_debug_cvirt); +EXPORT_SYMBOL_GPL(vx_debug_space); +EXPORT_SYMBOL_GPL(vx_debug_misc); + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/tag.c linux-2.6.27.15-g-v/kernel/vserver/tag.c --- linux-2.6.27.15/kernel/vserver/tag.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/tag.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,63 @@ +/* + * linux/kernel/vserver/tag.c + * + * Virtual Server: Shallow Tag Space + * + * Copyright (C) 2007 Herbert Pötzl + * + * V0.01 basic implementation + * + */ + +#include +#include +#include +#include + +#include + + +int dx_migrate_task(struct task_struct *p, tag_t tag) +{ + if (!p) + BUG(); + + vxdprintk(VXD_CBIT(tag, 5), + "dx_migrate_task(%p[#%d],#%d)", p, p->tag, tag); + + task_lock(p); + p->tag = tag; + task_unlock(p); + + vxdprintk(VXD_CBIT(tag, 5), + "moved task %p into [#%d]", p, tag); + return 0; +} + +/* vserver syscall commands below here */ + +/* taks xid and vx_info functions */ + + +int vc_task_tag(uint32_t id) +{ + tag_t tag; + + if (id) { + struct task_struct *tsk; + read_lock(&tasklist_lock); + tsk = find_task_by_real_pid(id); + tag = (tsk) ? tsk->tag : -ESRCH; + read_unlock(&tasklist_lock); + } else + tag = dx_current_tag(); + return tag; +} + + +int vc_tag_migrate(uint32_t tag) +{ + return dx_migrate_task(current, tag & 0xFFFF); +} + + diff -NurpP --minimal linux-2.6.27.15/kernel/vserver/vci_config.h linux-2.6.27.15-g-v/kernel/vserver/vci_config.h --- linux-2.6.27.15/kernel/vserver/vci_config.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/kernel/vserver/vci_config.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,81 @@ + +/* interface version */ + +#define VCI_VERSION 0x00020304 + + +enum { + VCI_KCBIT_NO_DYNAMIC = 0, + + VCI_KCBIT_PROC_SECURE = 4, + VCI_KCBIT_HARDCPU = 5, + VCI_KCBIT_IDLELIMIT = 6, + VCI_KCBIT_IDLETIME = 7, + + VCI_KCBIT_COWBL = 8, + VCI_KCBIT_FULLCOWBL = 9, + VCI_KCBIT_SPACES = 10, + VCI_KCBIT_NETV2 = 11, + + VCI_KCBIT_DEBUG = 16, + VCI_KCBIT_HISTORY = 20, + VCI_KCBIT_TAGGED = 24, + VCI_KCBIT_PPTAG = 28, + + VCI_KCBIT_MORE = 31, +}; + + +static inline uint32_t vci_kernel_config(void) +{ + return + (1 << VCI_KCBIT_NO_DYNAMIC) | + + /* configured features */ +#ifdef CONFIG_VSERVER_PROC_SECURE + (1 << VCI_KCBIT_PROC_SECURE) | +#endif +#ifdef CONFIG_VSERVER_HARDCPU + (1 << VCI_KCBIT_HARDCPU) | +#endif +#ifdef CONFIG_VSERVER_IDLELIMIT + (1 << VCI_KCBIT_IDLELIMIT) | +#endif +#ifdef CONFIG_VSERVER_IDLETIME + (1 << VCI_KCBIT_IDLETIME) | +#endif +#ifdef CONFIG_VSERVER_COWBL + (1 << VCI_KCBIT_COWBL) | + (1 << VCI_KCBIT_FULLCOWBL) | +#endif + (1 << VCI_KCBIT_SPACES) | + (1 << VCI_KCBIT_NETV2) | + + /* debug options */ +#ifdef CONFIG_VSERVER_DEBUG + (1 << VCI_KCBIT_DEBUG) | +#endif +#ifdef CONFIG_VSERVER_HISTORY + (1 << VCI_KCBIT_HISTORY) | +#endif + + /* inode context tagging */ +#if defined(CONFIG_TAGGING_NONE) + (0 << VCI_KCBIT_TAGGED) | +#elif defined(CONFIG_TAGGING_UID16) + (1 << VCI_KCBIT_TAGGED) | +#elif defined(CONFIG_TAGGING_GID16) + (2 << VCI_KCBIT_TAGGED) | +#elif defined(CONFIG_TAGGING_ID24) + (3 << VCI_KCBIT_TAGGED) | +#elif defined(CONFIG_TAGGING_INTERN) + (4 << VCI_KCBIT_TAGGED) | +#elif defined(CONFIG_TAGGING_RUNTIME) + (5 << VCI_KCBIT_TAGGED) | +#else + (7 << VCI_KCBIT_TAGGED) | +#endif + (1 << VCI_KCBIT_PPTAG) | + 0; +} + diff -NurpP --minimal linux-2.6.27.15/lib/radix-tree.c linux-2.6.27.15-g-v/lib/radix-tree.c --- linux-2.6.27.15/lib/radix-tree.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/lib/radix-tree.c 2009-02-10 20:32:16.000000000 +0100 @@ -81,7 +81,7 @@ struct radix_tree_preload { int nr; struct radix_tree_node *nodes[RADIX_TREE_MAX_PATH]; }; -DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads) = { 0, }; +DEFINE_PER_CPU(struct radix_tree_preload, radix_tree_preloads); static inline gfp_t root_gfp_mask(struct radix_tree_root *root) { diff -NurpP --minimal linux-2.6.27.15/localversion-grsec linux-2.6.27.15-g-v/localversion-grsec --- linux-2.6.27.15/localversion-grsec 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/localversion-grsec 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1 @@ +-grsec-2.1.12 diff -NurpP --minimal linux-2.6.27.15/localversion-vserver linux-2.6.27.15-g-v/localversion-vserver --- linux-2.6.27.15/localversion-vserver 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/localversion-vserver 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1 @@ +-vs2.3.0.36.4 diff -NurpP --minimal linux-2.6.27.15/Makefile linux-2.6.27.15-g-v/Makefile --- linux-2.6.27.15/Makefile 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/Makefile 2009-02-10 20:32:16.000000000 +0100 @@ -221,7 +221,7 @@ CONFIG_SHELL := $(shell if [ -x "$$BASH" HOSTCC = gcc HOSTCXX = g++ -HOSTCFLAGS = -Wall -Wstrict-prototypes -O2 -fomit-frame-pointer +HOSTCFLAGS = -Wall -W -Wno-unused -Wno-sign-compare -Wstrict-prototypes -O2 -fomit-frame-pointer HOSTCXXFLAGS = -O2 # Decide whether to build built-in, modular, or both. @@ -619,7 +619,7 @@ export mod_strip_cmd ifeq ($(KBUILD_EXTMOD),) -core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ +core-y += kernel/ mm/ fs/ ipc/ security/ crypto/ block/ grsecurity/ vmlinux-dirs := $(patsubst %/,%,$(filter %/, $(init-y) $(init-m) \ $(core-y) $(core-m) $(drivers-y) $(drivers-m) \ diff -NurpP --minimal linux-2.6.27.15/mm/filemap.c linux-2.6.27.15-g-v/mm/filemap.c --- linux-2.6.27.15/mm/filemap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/filemap.c 2009-02-10 20:32:16.000000000 +0100 @@ -33,6 +33,7 @@ #include #include /* for BUG_ON(!in_atomic()) only */ #include +#include #include "internal.h" /* @@ -1596,7 +1597,7 @@ int generic_file_mmap(struct file * file struct address_space *mapping = file->f_mapping; if (!mapping->a_ops->readpage) - return -ENOEXEC; + return -ENODEV; file_accessed(file); vma->vm_ops = &generic_file_vm_ops; vma->vm_flags |= VM_CAN_NONLINEAR; @@ -1957,6 +1958,7 @@ inline int generic_write_checks(struct f *pos = i_size_read(inode); if (limit != RLIM_INFINITY) { + gr_learn_resource(current, RLIMIT_FSIZE,*pos, 0); if (*pos >= limit) { send_sig(SIGXFSZ, current, 0); return -EFBIG; diff -NurpP --minimal linux-2.6.27.15/mm/filemap_xip.c linux-2.6.27.15-g-v/mm/filemap_xip.c --- linux-2.6.27.15/mm/filemap_xip.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/filemap_xip.c 2009-02-10 20:32:16.000000000 +0100 @@ -17,6 +17,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/mm/fremap.c linux-2.6.27.15-g-v/mm/fremap.c --- linux-2.6.27.15/mm/fremap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/fremap.c 2009-02-10 20:32:16.000000000 +0100 @@ -16,6 +16,7 @@ #include #include #include +#include #include #include @@ -151,6 +152,13 @@ SYSCALL_DEFINE5(remap_file_pages, unsign retry: vma = find_vma(mm, start); +#ifdef CONFIG_PAX_SEGMEXEC + if (vma && (mm->pax_flags & MF_PAX_SEGMEXEC) && (vma->vm_flags & VM_MAYEXEC)) { + up_read(&mm->mmap_sem); + return err; + } +#endif + /* * Make sure the vma is shared, that it supports prefaulting, * and that the remapped range is valid and fully within diff -NurpP --minimal linux-2.6.27.15/mm/hugetlb.c linux-2.6.27.15-g-v/mm/hugetlb.c --- linux-2.6.27.15/mm/hugetlb.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/hugetlb.c 2009-02-10 20:32:16.000000000 +0100 @@ -23,6 +23,7 @@ #include #include +#include #include "internal.h" const unsigned long hugetlb_zero = 0, hugetlb_infinity = ~0UL; @@ -1833,6 +1834,26 @@ int unmap_ref_private(struct mm_struct * return 1; } +#ifdef CONFIG_PAX_SEGMEXEC +static void pax_mirror_huge_pte(struct vm_area_struct *vma, unsigned long address, struct page *page_m) +{ + struct mm_struct *mm = vma->vm_mm; + struct vm_area_struct *vma_m; + unsigned long address_m; + pte_t *ptep_m; + + vma_m = pax_find_mirror_vma(vma); + if (!vma_m) + return; + + BUG_ON(address >= SEGMEXEC_TASK_SIZE); + address_m = address + SEGMEXEC_TASK_SIZE; + ptep_m = huge_pte_offset(mm, address_m & HPAGE_MASK); + get_page(page_m); + set_huge_pte_at(mm, address_m, ptep_m, make_huge_pte(vma_m, page_m, 0)); +} +#endif + static int hugetlb_cow(struct mm_struct *mm, struct vm_area_struct *vma, unsigned long address, pte_t *ptep, pte_t pte, struct page *pagecache_page) @@ -1904,6 +1925,11 @@ retry_avoidcopy: huge_ptep_clear_flush(vma, address, ptep); set_huge_pte_at(mm, address, ptep, make_huge_pte(vma, new_page, 1)); + +#ifdef CONFIG_PAX_SEGMEXEC + pax_mirror_huge_pte(vma, address, new_page); +#endif + /* Make the old page be freed below */ new_page = old_page; } @@ -2013,6 +2039,10 @@ retry: && (vma->vm_flags & VM_SHARED))); set_huge_pte_at(mm, address, ptep, new_pte); +#ifdef CONFIG_PAX_SEGMEXEC + pax_mirror_huge_pte(vma, address, page); +#endif + if (write_access && !(vma->vm_flags & VM_SHARED)) { /* Optimization, do the COW without a second fault */ ret = hugetlb_cow(mm, vma, address, ptep, new_pte, page); @@ -2041,6 +2071,28 @@ int hugetlb_fault(struct mm_struct *mm, static DEFINE_MUTEX(hugetlb_instantiation_mutex); struct hstate *h = hstate_vma(vma); +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m; + + vma_m = pax_find_mirror_vma(vma); + if (vma_m) { + unsigned long address_m; + + if (vma->vm_start > vma_m->vm_start) { + address_m = address; + address -= SEGMEXEC_TASK_SIZE; + vma = vma_m; + h = hstate_vma(vma); + } else + address_m = address + SEGMEXEC_TASK_SIZE; + + if (!huge_pte_alloc(mm, address_m, huge_page_size(h))) + return VM_FAULT_OOM; + address_m &= HPAGE_MASK; + unmap_hugepage_range(vma, address_m, address_m + HPAGE_SIZE, NULL); + } +#endif + ptep = huge_pte_alloc(mm, address, huge_page_size(h)); if (!ptep) return VM_FAULT_OOM; diff -NurpP --minimal linux-2.6.27.15/mm/madvise.c linux-2.6.27.15-g-v/mm/madvise.c --- linux-2.6.27.15/mm/madvise.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/madvise.c 2009-02-10 20:32:16.000000000 +0100 @@ -43,6 +43,10 @@ static long madvise_behavior(struct vm_a pgoff_t pgoff; int new_flags = vma->vm_flags; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m; +#endif + switch (behavior) { case MADV_NORMAL: new_flags = new_flags & ~VM_RAND_READ & ~VM_SEQ_READ; @@ -92,6 +96,13 @@ success: /* * vm_flags is protected by the mmap_sem held in write mode. */ + +#ifdef CONFIG_PAX_SEGMEXEC + vma_m = pax_find_mirror_vma(vma); + if (vma_m) + vma_m->vm_flags = new_flags & ~(VM_WRITE | VM_MAYWRITE | VM_ACCOUNT); +#endif + vma->vm_flags = new_flags; out: @@ -236,6 +247,17 @@ madvise_vma(struct vm_area_struct *vma, case MADV_DONTNEED: error = madvise_dontneed(vma, prev, start, end); + +#ifdef CONFIG_PAX_SEGMEXEC + if (!error) { + struct vm_area_struct *vma_m, *prev_m; + + vma_m = pax_find_mirror_vma(vma); + if (vma_m) + error = madvise_dontneed(vma_m, &prev_m, start + SEGMEXEC_TASK_SIZE, end + SEGMEXEC_TASK_SIZE); + } +#endif + break; default: @@ -308,6 +330,16 @@ SYSCALL_DEFINE3(madvise, unsigned long, if (end < start) goto out; +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) { + if (end > SEGMEXEC_TASK_SIZE) + goto out; + } else +#endif + + if (end > TASK_SIZE) + goto out; + error = 0; if (end == start) goto out; diff -NurpP --minimal linux-2.6.27.15/mm/memory.c linux-2.6.27.15-g-v/mm/memory.c --- linux-2.6.27.15/mm/memory.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/memory.c 2009-02-10 20:32:16.000000000 +0100 @@ -52,6 +52,7 @@ #include #include #include +#include #include #include @@ -562,6 +563,9 @@ static int copy_pte_range(struct mm_stru int progress = 0; int rss[2]; + if (!vx_rss_avail(dst_mm, ((end - addr)/PAGE_SIZE + 1))) + return -ENOMEM; + again: rss[1] = rss[0] = 0; dst_pte = pte_alloc_map_lock(dst_mm, dst_pmd, addr, &dst_ptl); @@ -1146,11 +1150,11 @@ int get_user_pages(struct task_struct *t vm_flags &= force ? (VM_MAYREAD | VM_MAYWRITE) : (VM_READ | VM_WRITE); i = 0; - do { + while (len) { struct vm_area_struct *vma; unsigned int foll_flags; - vma = find_extend_vma(mm, start); + vma = find_vma(mm, start); if (!vma && in_gate_area(tsk, start)) { unsigned long pg = start & PAGE_MASK; struct vm_area_struct *gate_vma = get_gate_vma(tsk); @@ -1190,7 +1194,7 @@ int get_user_pages(struct task_struct *t continue; } - if (!vma || (vma->vm_flags & (VM_IO | VM_PFNMAP)) + if (!vma || start < vma->vm_start || (vma->vm_flags & (VM_IO | VM_PFNMAP)) || !(vm_flags & vma->vm_flags)) return i ? : -EFAULT; @@ -1263,7 +1267,7 @@ int get_user_pages(struct task_struct *t start += PAGE_SIZE; len--; } while (len && start < vma->vm_end); - } while (len); + } return i; } EXPORT_SYMBOL(get_user_pages); @@ -1741,6 +1745,186 @@ static inline void cow_user_page(struct copy_user_highpage(dst, src, va, vma); } +#ifdef CONFIG_PAX_SEGMEXEC +static void pax_unmap_mirror_pte(struct vm_area_struct *vma, unsigned long address, pmd_t *pmd) +{ + struct mm_struct *mm = vma->vm_mm; + spinlock_t *ptl; + pte_t *pte, entry; + + pte = pte_offset_map_lock(mm, pmd, address, &ptl); + entry = *pte; + if (!pte_present(entry)) { + if (!pte_none(entry)) { + BUG_ON(pte_file(entry)); + free_swap_and_cache(pte_to_swp_entry(entry)); + pte_clear_not_present_full(mm, address, pte, 0); + } + } else { + struct page *page; + + flush_cache_page(vma, address, pte_pfn(entry)); + entry = ptep_clear_flush(vma, address, pte); + BUG_ON(pte_dirty(entry)); + page = vm_normal_page(vma, address, entry); + if (page) { + update_hiwater_rss(mm); + if (PageAnon(page)) + dec_mm_counter(mm, anon_rss); + else + dec_mm_counter(mm, file_rss); + page_remove_rmap(page, vma); + page_cache_release(page); + } + } + pte_unmap_unlock(pte, ptl); +} + +/* PaX: if vma is mirrored, synchronize the mirror's PTE + * + * the ptl of the lower mapped page is held on entry and is not released on exit + * or inside to ensure atomic changes to the PTE states (swapout, mremap, munmap, etc) + */ +static void pax_mirror_anon_pte(struct vm_area_struct *vma, unsigned long address, struct page *page_m, spinlock_t *ptl) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long address_m; + spinlock_t *ptl_m; + struct vm_area_struct *vma_m; + pmd_t *pmd_m; + pte_t *pte_m, entry_m; + + BUG_ON(!page_m || !PageAnon(page_m)); + + vma_m = pax_find_mirror_vma(vma); + if (!vma_m) + return; + + BUG_ON(!PageLocked(page_m)); + BUG_ON(address >= SEGMEXEC_TASK_SIZE); + address_m = address + SEGMEXEC_TASK_SIZE; + pmd_m = pmd_offset(pud_offset(pgd_offset(mm, address_m), address_m), address_m); + pte_m = pte_offset_map_nested(pmd_m, address_m); + ptl_m = pte_lockptr(mm, pmd_m); + if (ptl != ptl_m) { + spin_lock_nested(ptl_m, SINGLE_DEPTH_NESTING); + if (!pte_none(*pte_m)) + goto out; + } + + entry_m = pfn_pte(page_to_pfn(page_m), vma_m->vm_page_prot); + page_cache_get(page_m); + page_add_anon_rmap(page_m, vma_m, address_m); + inc_mm_counter(mm, anon_rss); + set_pte_at(mm, address_m, pte_m, entry_m); + update_mmu_cache(vma_m, address_m, entry_m); +out: + if (ptl != ptl_m) + spin_unlock(ptl_m); + pte_unmap_nested(pte_m); + unlock_page(page_m); +} + +void pax_mirror_file_pte(struct vm_area_struct *vma, unsigned long address, struct page *page_m, spinlock_t *ptl) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long address_m; + spinlock_t *ptl_m; + struct vm_area_struct *vma_m; + pmd_t *pmd_m; + pte_t *pte_m, entry_m; + + BUG_ON(!page_m || PageAnon(page_m)); + + vma_m = pax_find_mirror_vma(vma); + if (!vma_m) + return; + + BUG_ON(address >= SEGMEXEC_TASK_SIZE); + address_m = address + SEGMEXEC_TASK_SIZE; + pmd_m = pmd_offset(pud_offset(pgd_offset(mm, address_m), address_m), address_m); + pte_m = pte_offset_map_nested(pmd_m, address_m); + ptl_m = pte_lockptr(mm, pmd_m); + if (ptl != ptl_m) { + spin_lock_nested(ptl_m, SINGLE_DEPTH_NESTING); + if (!pte_none(*pte_m)) + goto out; + } + + entry_m = pfn_pte(page_to_pfn(page_m), vma_m->vm_page_prot); + page_cache_get(page_m); + page_add_file_rmap(page_m); + inc_mm_counter(mm, file_rss); + set_pte_at(mm, address_m, pte_m, entry_m); + update_mmu_cache(vma_m, address_m, entry_m); +out: + if (ptl != ptl_m) + spin_unlock(ptl_m); + pte_unmap_nested(pte_m); +} + +static void pax_mirror_pfn_pte(struct vm_area_struct *vma, unsigned long address, unsigned long pfn_m, spinlock_t *ptl) +{ + struct mm_struct *mm = vma->vm_mm; + unsigned long address_m; + spinlock_t *ptl_m; + struct vm_area_struct *vma_m; + pmd_t *pmd_m; + pte_t *pte_m, entry_m; + + vma_m = pax_find_mirror_vma(vma); + if (!vma_m) + return; + + BUG_ON(address >= SEGMEXEC_TASK_SIZE); + address_m = address + SEGMEXEC_TASK_SIZE; + pmd_m = pmd_offset(pud_offset(pgd_offset(mm, address_m), address_m), address_m); + pte_m = pte_offset_map_nested(pmd_m, address_m); + ptl_m = pte_lockptr(mm, pmd_m); + if (ptl != ptl_m) { + spin_lock_nested(ptl_m, SINGLE_DEPTH_NESTING); + if (!pte_none(*pte_m)) + goto out; + } + + entry_m = pfn_pte(pfn_m, vma_m->vm_page_prot); + set_pte_at(mm, address_m, pte_m, entry_m); +out: + if (ptl != ptl_m) + spin_unlock(ptl_m); + pte_unmap_nested(pte_m); +} + +static void pax_mirror_pte(struct vm_area_struct *vma, unsigned long address, pte_t *pte, pmd_t *pmd, spinlock_t *ptl) +{ + struct page *page_m; + pte_t entry; + + if (!(vma->vm_mm->pax_flags & MF_PAX_SEGMEXEC)) + goto out; + + entry = *pte; + page_m = vm_normal_page(vma, address, entry); + if (!page_m) + pax_mirror_pfn_pte(vma, address, pte_pfn(entry), ptl); + else if (PageAnon(page_m)) { + if (pax_find_mirror_vma(vma)) { + pte_unmap_unlock(pte, ptl); + lock_page(page_m); + pte = pte_offset_map_lock(vma->vm_mm, pmd, address, &ptl); + if (pte_same(entry, *pte)) + pax_mirror_anon_pte(vma, address, page_m, ptl); + else + unlock_page(page_m); + } + } else + pax_mirror_file_pte(vma, address, page_m, ptl); + +out: + pte_unmap_unlock(pte, ptl); +} +#endif + /* * This routine handles present pages, when users try to write * to a shared page. It is done by copying the page to a new address @@ -1869,6 +2053,12 @@ gotten: */ page_table = pte_offset_map_lock(mm, pmd, address, &ptl); if (likely(pte_same(*page_table, orig_pte))) { + +#ifdef CONFIG_PAX_SEGMEXEC + if (pax_find_mirror_vma(vma)) + BUG_ON(!trylock_page(new_page)); +#endif + if (old_page) { if (!PageAnon(old_page)) { dec_mm_counter(mm, file_rss); @@ -1917,6 +2107,10 @@ gotten: page_remove_rmap(old_page, vma); } +#ifdef CONFIG_PAX_SEGMEXEC + pax_mirror_anon_pte(vma, address, new_page, ptl); +#endif + /* Free the old page.. */ new_page = old_page; ret |= VM_FAULT_WRITE; @@ -2176,6 +2370,7 @@ int vmtruncate(struct inode * inode, lof unsigned long limit; limit = current->signal->rlim[RLIMIT_FSIZE].rlim_cur; + gr_learn_resource(current, RLIMIT_FSIZE, offset, 1); if (limit != RLIM_INFINITY && offset > limit) goto out_sig; if (offset > inode->i_sb->s_maxbytes) @@ -2294,6 +2489,11 @@ static int do_swap_page(struct mm_struct goto out; } + if (!vx_rss_avail(mm, 1)) { + ret = VM_FAULT_OOM; + goto out; + } + mark_page_accessed(page); lock_page(page); delayacct_clear_flag(DELAYACCT_PF_SWAPIN); @@ -2326,6 +2526,11 @@ static int do_swap_page(struct mm_struct swap_free(entry); if (vm_swap_full()) remove_exclusive_swap_page(page); + +#ifdef CONFIG_PAX_SEGMEXEC + if (write_access || !pax_find_mirror_vma(vma)) +#endif + unlock_page(page); if (write_access) { @@ -2337,6 +2542,11 @@ static int do_swap_page(struct mm_struct /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, address, pte); + +#ifdef CONFIG_PAX_SEGMEXEC + pax_mirror_anon_pte(vma, address, page, ptl); +#endif + unlock: pte_unmap_unlock(page_table, ptl); out: @@ -2365,6 +2575,8 @@ static int do_anonymous_page(struct mm_s /* Allocate our own private page. */ pte_unmap(page_table); + if (!vx_rss_avail(mm, 1)) + goto oom; if (unlikely(anon_vma_prepare(vma))) goto oom; page = alloc_zeroed_user_highpage_movable(vma, address); @@ -2381,6 +2593,12 @@ static int do_anonymous_page(struct mm_s page_table = pte_offset_map_lock(mm, pmd, address, &ptl); if (!pte_none(*page_table)) goto release; + +#ifdef CONFIG_PAX_SEGMEXEC + if (pax_find_mirror_vma(vma)) + BUG_ON(!trylock_page(page)); +#endif + inc_mm_counter(mm, anon_rss); lru_cache_add_active(page); page_add_new_anon_rmap(page, vma, address); @@ -2388,6 +2606,11 @@ static int do_anonymous_page(struct mm_s /* No need to invalidate - it was non-present before */ update_mmu_cache(vma, address, entry); + +#ifdef CONFIG_PAX_SEGMEXEC + pax_mirror_anon_pte(vma, address, page, ptl); +#endif + unlock: pte_unmap_unlock(page_table, ptl); return 0; @@ -2516,6 +2739,12 @@ static int __do_fault(struct mm_struct * */ /* Only go through if we didn't race with anybody else... */ if (likely(pte_same(*page_table, orig_pte))) { + +#ifdef CONFIG_PAX_SEGMEXEC + if (anon && pax_find_mirror_vma(vma)) + BUG_ON(!trylock_page(page)); +#endif + flush_icache_page(vma, page); entry = mk_pte(page, vma->vm_page_prot); if (flags & FAULT_FLAG_WRITE) @@ -2536,6 +2765,14 @@ static int __do_fault(struct mm_struct * /* no need to invalidate: a not-present page won't be cached */ update_mmu_cache(vma, address, entry); + +#ifdef CONFIG_PAX_SEGMEXEC + if (anon) + pax_mirror_anon_pte(vma, address, page, ptl); + else + pax_mirror_file_pte(vma, address, page, ptl); +#endif + } else { mem_cgroup_uncharge_page(page); if (anon) @@ -2626,6 +2863,7 @@ static inline int handle_pte_fault(struc { pte_t entry; spinlock_t *ptl; + int ret = 0, type = VXPT_UNKNOWN; entry = *pte; if (!pte_present(entry)) { @@ -2650,9 +2888,12 @@ static inline int handle_pte_fault(struc if (unlikely(!pte_same(*pte, entry))) goto unlock; if (write_access) { - if (!pte_write(entry)) - return do_wp_page(mm, vma, address, + if (!pte_write(entry)) { + ret = do_wp_page(mm, vma, address, pte, pmd, ptl, entry); + type = VXPT_WRITE; + goto out; + } entry = pte_mkdirty(entry); } entry = pte_mkyoung(entry); @@ -2668,9 +2909,18 @@ static inline int handle_pte_fault(struc if (write_access) flush_tlb_page(vma, address); } + +#ifdef CONFIG_PAX_SEGMEXEC + pax_mirror_pte(vma, address, pte, pmd, ptl); + return 0; +#endif + unlock: pte_unmap_unlock(pte, ptl); - return 0; + ret = 0; +out: + vx_page_fault(mm, vma, type, ret); + return ret; } /* @@ -2684,6 +2934,10 @@ int handle_mm_fault(struct mm_struct *mm pmd_t *pmd; pte_t *pte; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m; +#endif + __set_current_state(TASK_RUNNING); count_vm_event(PGFAULT); @@ -2691,6 +2945,34 @@ int handle_mm_fault(struct mm_struct *mm if (unlikely(is_vm_hugetlb_page(vma))) return hugetlb_fault(mm, vma, address, write_access); +#ifdef CONFIG_PAX_SEGMEXEC + vma_m = pax_find_mirror_vma(vma); + if (vma_m) { + unsigned long address_m; + pgd_t *pgd_m; + pud_t *pud_m; + pmd_t *pmd_m; + + if (vma->vm_start > vma_m->vm_start) { + address_m = address; + address -= SEGMEXEC_TASK_SIZE; + vma = vma_m; + } else + address_m = address + SEGMEXEC_TASK_SIZE; + + pgd_m = pgd_offset(mm, address_m); + pud_m = pud_alloc(mm, pgd_m, address_m); + if (!pud_m) + return VM_FAULT_OOM; + pmd_m = pmd_alloc(mm, pud_m, address_m); + if (!pmd_m) + return VM_FAULT_OOM; + if (!pmd_present(*pmd_m) && __pte_alloc(mm, pmd_m, address_m)) + return VM_FAULT_OOM; + pax_unmap_mirror_pte(vma_m, address_m, pmd_m); + } +#endif + pgd = pgd_offset(mm, address); pud = pud_alloc(mm, pgd, address); if (!pud) @@ -2798,7 +3080,7 @@ static int __init gate_vma_init(void) gate_vma.vm_start = FIXADDR_USER_START; gate_vma.vm_end = FIXADDR_USER_END; gate_vma.vm_flags = VM_READ | VM_MAYREAD | VM_EXEC | VM_MAYEXEC; - gate_vma.vm_page_prot = __P101; + gate_vma.vm_page_prot = vm_get_page_prot(gate_vma.vm_flags); /* * Make sure the vDSO gets into every core dump. * Dumping its contents makes post-mortem fully interpretable later diff -NurpP --minimal linux-2.6.27.15/mm/mempolicy.c linux-2.6.27.15-g-v/mm/mempolicy.c --- linux-2.6.27.15/mm/mempolicy.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/mempolicy.c 2009-02-10 20:32:16.000000000 +0100 @@ -555,6 +555,10 @@ static int mbind_range(struct vm_area_st struct vm_area_struct *next; int err; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m; +#endif + err = 0; for (; vma && vma->vm_start < end; vma = next) { next = vma->vm_next; @@ -566,6 +570,16 @@ static int mbind_range(struct vm_area_st err = policy_vma(vma, new); if (err) break; + +#ifdef CONFIG_PAX_SEGMEXEC + vma_m = pax_find_mirror_vma(vma); + if (vma_m) { + err = policy_vma(vma_m, new); + if (err) + break; + } +#endif + } return err; } @@ -951,6 +965,17 @@ static long do_mbind(unsigned long start if (end < start) return -EINVAL; + +#ifdef CONFIG_PAX_SEGMEXEC + if (mm->pax_flags & MF_PAX_SEGMEXEC) { + if (end > SEGMEXEC_TASK_SIZE) + return -EINVAL; + } else +#endif + + if (end > TASK_SIZE) + return -EINVAL; + if (end == start) return 0; diff -NurpP --minimal linux-2.6.27.15/mm/mlock.c linux-2.6.27.15-g-v/mm/mlock.c --- linux-2.6.27.15/mm/mlock.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/mlock.c 2009-02-10 20:32:16.000000000 +0100 @@ -12,6 +12,8 @@ #include #include #include +#include +#include int can_do_mlock(void) { @@ -76,7 +78,7 @@ success: ret = make_pages_present(start, end); } - mm->locked_vm -= pages; + vx_vmlocked_sub(mm, pages); out: return ret; } @@ -93,6 +95,17 @@ static int do_mlock(unsigned long start, return -EINVAL; if (end == start) return 0; + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) { + if (end > SEGMEXEC_TASK_SIZE) + return -EINVAL; + } else +#endif + + if (end > TASK_SIZE) + return -EINVAL; + vma = find_vma_prev(current->mm, start, &prev); if (!vma || vma->vm_start > start) return -ENOMEM; @@ -132,7 +145,7 @@ static int do_mlock(unsigned long start, SYSCALL_DEFINE2(mlock, unsigned long, start, size_t, len) { - unsigned long locked; + unsigned long locked, grow; unsigned long lock_limit; int error = -ENOMEM; @@ -143,15 +156,19 @@ SYSCALL_DEFINE2(mlock, unsigned long, st len = PAGE_ALIGN(len + (start & ~PAGE_MASK)); start &= PAGE_MASK; - locked = len >> PAGE_SHIFT; - locked += current->mm->locked_vm; + grow = len >> PAGE_SHIFT; + if (!vx_vmlocked_avail(current->mm, grow)) + goto out; + locked = current->mm->locked_vm + grow; lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; /* check against resource limits */ + gr_learn_resource(current, RLIMIT_MEMLOCK, (current->mm->locked_vm << PAGE_SHIFT) + len, 1); if ((locked <= lock_limit) || capable(CAP_IPC_LOCK)) error = do_mlock(start, len, 1); +out: up_write(¤t->mm->mmap_sem); return error; } @@ -171,10 +188,10 @@ SYSCALL_DEFINE2(munlock, unsigned long, static int do_mlockall(int flags) { struct vm_area_struct * vma, * prev = NULL; - unsigned int def_flags = 0; + unsigned int def_flags = current->mm->def_flags & ~VM_LOCKED; if (flags & MCL_FUTURE) - def_flags = VM_LOCKED; + def_flags |= VM_LOCKED; current->mm->def_flags = def_flags; if (flags == MCL_FUTURE) goto out; @@ -182,6 +199,12 @@ static int do_mlockall(int flags) for (vma = current->mm->mmap; vma ; vma = prev->vm_next) { unsigned int newflags; +#ifdef CONFIG_PAX_SEGMEXEC + if ((current->mm->pax_flags & MF_PAX_SEGMEXEC) && (vma->vm_start >= SEGMEXEC_TASK_SIZE)) + break; +#endif + + BUG_ON(vma->vm_end > TASK_SIZE); newflags = vma->vm_flags | VM_LOCKED; if (!(flags & MCL_CURRENT)) newflags &= ~VM_LOCKED; @@ -211,6 +234,9 @@ SYSCALL_DEFINE1(mlockall, int, flags) lock_limit >>= PAGE_SHIFT; ret = -ENOMEM; + if (!vx_vmlocked_avail(current->mm, current->mm->total_vm)) + goto out; + gr_learn_resource(current, RLIMIT_MEMLOCK, current->mm->total_vm, 1); if (!(flags & MCL_CURRENT) || (current->mm->total_vm <= lock_limit) || capable(CAP_IPC_LOCK)) ret = do_mlockall(flags); diff -NurpP --minimal linux-2.6.27.15/mm/mmap.c linux-2.6.27.15-g-v/mm/mmap.c --- linux-2.6.27.15/mm/mmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/mmap.c 2009-02-10 20:32:16.000000000 +0100 @@ -27,6 +27,7 @@ #include #include #include +#include #include #include @@ -43,6 +44,16 @@ #define arch_rebalance_pgtables(addr, len) (addr) #endif +static inline void verify_mm_writelocked(struct mm_struct *mm) +{ +#if defined(CONFIG_DEBUG_VM) || defined(CONFIG_PAX) + if (unlikely(down_read_trylock(&mm->mmap_sem))) { + up_read(&mm->mmap_sem); + BUG(); + } +#endif +} + static void unmap_region(struct mm_struct *mm, struct vm_area_struct *vma, struct vm_area_struct *prev, unsigned long start, unsigned long end); @@ -68,16 +79,25 @@ static void unmap_region(struct mm_struc * x: (no) no x: (no) yes x: (no) yes x: (yes) yes * */ -pgprot_t protection_map[16] = { +pgprot_t protection_map[16] __read_only = { __P000, __P001, __P010, __P011, __P100, __P101, __P110, __P111, __S000, __S001, __S010, __S011, __S100, __S101, __S110, __S111 }; pgprot_t vm_get_page_prot(unsigned long vm_flags) { - return __pgprot(pgprot_val(protection_map[vm_flags & + pgprot_t prot = __pgprot(pgprot_val(protection_map[vm_flags & (VM_READ|VM_WRITE|VM_EXEC|VM_SHARED)]) | pgprot_val(arch_vm_get_page_prot(vm_flags))); + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_X86_32) + if (!nx_enabled && + (vm_flags & (VM_PAGEEXEC | VM_EXEC)) == VM_PAGEEXEC && + (vm_flags & (VM_READ | VM_WRITE))) + prot = __pgprot(pte_val(pte_exprotect(__pte(pgprot_val(prot))))); +#endif + + return prot; } EXPORT_SYMBOL(vm_get_page_prot); @@ -232,6 +252,7 @@ static struct vm_area_struct *remove_vma struct vm_area_struct *next = vma->vm_next; might_sleep(); + BUG_ON(vma->vm_mirror); if (vma->vm_ops && vma->vm_ops->close) vma->vm_ops->close(vma); if (vma->vm_file) { @@ -268,6 +289,7 @@ SYSCALL_DEFINE1(brk, unsigned long, brk) * not page aligned -Ram Gupta */ rlim = current->signal->rlim[RLIMIT_DATA].rlim_cur; + gr_learn_resource(current, RLIMIT_DATA, (brk - mm->start_brk) + (mm->end_data - mm->start_data), 1); if (rlim < RLIM_INFINITY && (brk - mm->start_brk) + (mm->end_data - mm->start_data) > rlim) goto out; @@ -697,6 +719,12 @@ static int can_vma_merge_before(struct vm_area_struct *vma, unsigned long vm_flags, struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) { + +#ifdef CONFIG_PAX_SEGMEXEC + if ((vma->vm_mm->pax_flags & MF_PAX_SEGMEXEC) && vma->vm_start == SEGMEXEC_TASK_SIZE) + return 0; +#endif + if (is_mergeable_vma(vma, file, vm_flags) && is_mergeable_anon_vma(anon_vma, vma->anon_vma)) { if (vma->vm_pgoff == vm_pgoff) @@ -716,6 +744,12 @@ static int can_vma_merge_after(struct vm_area_struct *vma, unsigned long vm_flags, struct anon_vma *anon_vma, struct file *file, pgoff_t vm_pgoff) { + +#ifdef CONFIG_PAX_SEGMEXEC + if ((vma->vm_mm->pax_flags & MF_PAX_SEGMEXEC) && vma->vm_end == SEGMEXEC_TASK_SIZE) + return 0; +#endif + if (is_mergeable_vma(vma, file, vm_flags) && is_mergeable_anon_vma(anon_vma, vma->anon_vma)) { pgoff_t vm_pglen; @@ -758,12 +792,19 @@ can_vma_merge_after(struct vm_area_struc struct vm_area_struct *vma_merge(struct mm_struct *mm, struct vm_area_struct *prev, unsigned long addr, unsigned long end, unsigned long vm_flags, - struct anon_vma *anon_vma, struct file *file, + struct anon_vma *anon_vma, struct file *file, pgoff_t pgoff, struct mempolicy *policy) { pgoff_t pglen = (end - addr) >> PAGE_SHIFT; struct vm_area_struct *area, *next; +#ifdef CONFIG_PAX_SEGMEXEC + unsigned long addr_m = addr + SEGMEXEC_TASK_SIZE, end_m = end + SEGMEXEC_TASK_SIZE; + struct vm_area_struct *area_m = NULL, *next_m = NULL, *prev_m = NULL; + + BUG_ON((mm->pax_flags & MF_PAX_SEGMEXEC) && SEGMEXEC_TASK_SIZE < end); +#endif + /* * We later require that vma->vm_flags == vm_flags, * so this tests vma->vm_flags & VM_SPECIAL, too. @@ -779,6 +820,15 @@ struct vm_area_struct *vma_merge(struct if (next && next->vm_end == end) /* cases 6, 7, 8 */ next = next->vm_next; +#ifdef CONFIG_PAX_SEGMEXEC + if (prev) + prev_m = pax_find_mirror_vma(prev); + if (area) + area_m = pax_find_mirror_vma(area); + if (next) + next_m = pax_find_mirror_vma(next); +#endif + /* * Can it merge with the predecessor? */ @@ -798,9 +848,24 @@ struct vm_area_struct *vma_merge(struct /* cases 1, 6 */ vma_adjust(prev, prev->vm_start, next->vm_end, prev->vm_pgoff, NULL); - } else /* cases 2, 5, 7 */ + +#ifdef CONFIG_PAX_SEGMEXEC + if (prev_m) + vma_adjust(prev_m, prev_m->vm_start, + next_m->vm_end, prev_m->vm_pgoff, NULL); +#endif + + } else { /* cases 2, 5, 7 */ vma_adjust(prev, prev->vm_start, end, prev->vm_pgoff, NULL); + +#ifdef CONFIG_PAX_SEGMEXEC + if (prev_m) + vma_adjust(prev_m, prev_m->vm_start, + end_m, prev_m->vm_pgoff, NULL); +#endif + + } return prev; } @@ -811,12 +876,27 @@ struct vm_area_struct *vma_merge(struct mpol_equal(policy, vma_policy(next)) && can_vma_merge_before(next, vm_flags, anon_vma, file, pgoff+pglen)) { - if (prev && addr < prev->vm_end) /* case 4 */ + if (prev && addr < prev->vm_end) { /* case 4 */ vma_adjust(prev, prev->vm_start, addr, prev->vm_pgoff, NULL); - else /* cases 3, 8 */ + +#ifdef CONFIG_PAX_SEGMEXEC + if (prev_m) + vma_adjust(prev_m, prev_m->vm_start, + addr_m, prev_m->vm_pgoff, NULL); +#endif + + } else { /* cases 3, 8 */ vma_adjust(area, addr, next->vm_end, next->vm_pgoff - pglen, NULL); + +#ifdef CONFIG_PAX_SEGMEXEC + if (area_m) + vma_adjust(area_m, addr_m, next_m->vm_end, + next_m->vm_pgoff - pglen, NULL); +#endif + + } return area; } @@ -891,14 +971,11 @@ none: void vm_stat_account(struct mm_struct *mm, unsigned long flags, struct file *file, long pages) { - const unsigned long stack_flags - = VM_STACK_FLAGS & (VM_GROWSUP|VM_GROWSDOWN); - if (file) { mm->shared_vm += pages; if ((flags & (VM_EXEC|VM_WRITE)) == VM_EXEC) mm->exec_vm += pages; - } else if (flags & stack_flags) + } else if (flags & (VM_GROWSUP|VM_GROWSDOWN)) mm->stack_vm += pages; if (flags & (VM_RESERVED|VM_IO)) mm->reserved_vm += pages; @@ -926,7 +1003,7 @@ unsigned long do_mmap_pgoff(struct file * (the exception is when the underlying filesystem is noexec * mounted, in which case we dont add PROT_EXEC.) */ - if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) + if ((prot & (PROT_READ | PROT_WRITE)) && (current->personality & READ_IMPLIES_EXEC)) if (!(file && (file->f_path.mnt->mnt_flags & MNT_NOEXEC))) prot |= PROT_EXEC; @@ -936,15 +1013,15 @@ unsigned long do_mmap_pgoff(struct file if (!(flags & MAP_FIXED)) addr = round_hint_to_min(addr); - error = arch_mmap_check(addr, len, flags); - if (error) - return error; - /* Careful about overflows.. */ len = PAGE_ALIGN(len); if (!len || len > TASK_SIZE) return -ENOMEM; + error = arch_mmap_check(addr, len, flags); + if (error) + return error; + /* offset overflow? */ if ((pgoff + (len >> PAGE_SHIFT)) < pgoff) return -EOVERFLOW; @@ -956,7 +1033,7 @@ unsigned long do_mmap_pgoff(struct file /* Obtain the address to map to. we verify (or select) it and ensure * that it represents a valid section of the address space. */ - addr = get_unmapped_area(file, addr, len, pgoff, flags); + addr = get_unmapped_area(file, addr, len, pgoff, flags | ((prot & PROT_EXEC) ? MAP_EXECUTABLE : 0)); if (addr & ~PAGE_MASK) return addr; @@ -967,6 +1044,26 @@ unsigned long do_mmap_pgoff(struct file vm_flags = calc_vm_prot_bits(prot) | calc_vm_flag_bits(flags) | mm->def_flags | VM_MAYREAD | VM_MAYWRITE | VM_MAYEXEC; +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (mm->pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) { + +#ifdef CONFIG_PAX_MPROTECT + if (mm->pax_flags & MF_PAX_MPROTECT) { + if ((prot & (PROT_WRITE | PROT_EXEC)) != PROT_EXEC) + vm_flags &= ~(VM_EXEC | VM_MAYEXEC); + else + vm_flags &= ~(VM_WRITE | VM_MAYWRITE); + } +#endif + + } +#endif + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_X86_32) + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && file) + vm_flags &= ~VM_PAGEEXEC; +#endif + if (flags & MAP_LOCKED) { if (!can_do_mlock()) return -EPERM; @@ -979,6 +1076,7 @@ unsigned long do_mmap_pgoff(struct file locked += mm->locked_vm; lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; + gr_learn_resource(current, RLIMIT_MEMLOCK, locked << PAGE_SHIFT, 1); if (locked > lock_limit && !capable(CAP_IPC_LOCK)) return -EAGAIN; } @@ -1051,6 +1149,9 @@ unsigned long do_mmap_pgoff(struct file if (error) return error; + if (!gr_acl_handle_mmap(file, prot)) + return -EACCES; + return mmap_region(file, addr, len, flags, vm_flags, pgoff, accountable); } @@ -1064,10 +1165,10 @@ EXPORT_SYMBOL(do_mmap_pgoff); */ int vma_wants_writenotify(struct vm_area_struct *vma) { - unsigned int vm_flags = vma->vm_flags; + unsigned long vm_flags = vma->vm_flags; /* If it was private or non-writable, the write bit is already clear */ - if ((vm_flags & (VM_WRITE|VM_SHARED)) != ((VM_WRITE|VM_SHARED))) + if ((vm_flags & (VM_WRITE|VM_SHARED)) != (VM_WRITE|VM_SHARED)) return 0; /* The backer wishes to know when pages are first written to? */ @@ -1101,14 +1202,24 @@ unsigned long mmap_region(struct file *f unsigned long charged = 0; struct inode *inode = file ? file->f_path.dentry->d_inode : NULL; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m = NULL; +#endif + + /* + * mm->mmap_sem is required to protect against another thread + * changing the mappings in case we sleep. + */ + verify_mm_writelocked(mm); + /* Clear old maps */ error = -ENOMEM; -munmap_back: vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); if (vma && vma->vm_start < addr + len) { if (do_munmap(mm, addr, len)) return -ENOMEM; - goto munmap_back; + vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); + BUG_ON(vma && vma->vm_start < addr + len); } /* Check against address space limit. */ @@ -1155,6 +1266,16 @@ munmap_back: goto unacct_error; } +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && (vm_flags & VM_EXEC)) { + vma_m = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + if (!vma_m) { + error = -ENOMEM; + goto free_vma; + } + } +#endif + vma->vm_mm = mm; vma->vm_start = addr; vma->vm_end = addr + len; @@ -1177,6 +1298,19 @@ munmap_back: error = file->f_op->mmap(file, vma); if (error) goto unmap_and_free_vma; + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma_m && (vm_flags & VM_EXECUTABLE)) + added_exe_file_vma(mm); +#endif + +#if defined(CONFIG_PAX_PAGEEXEC) && defined(CONFIG_X86_32) + if ((mm->pax_flags & MF_PAX_PAGEEXEC) && !(vma->vm_flags & VM_SPECIAL)) { + vma->vm_flags |= VM_PAGEEXEC; + vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); + } +#endif + if (vm_flags & VM_EXECUTABLE) added_exe_file_vma(mm); } else if (vm_flags & VM_SHARED) { @@ -1209,22 +1343,40 @@ munmap_back: vma->vm_flags, NULL, file, pgoff, vma_policy(vma))) { mpol_put(vma_policy(vma)); kmem_cache_free(vm_area_cachep, vma); + vma = NULL; fput(file); + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma_m) { + kmem_cache_free(vm_area_cachep, vma_m); + + if (vm_flags & VM_EXECUTABLE) + removed_exe_file_vma(mm); + } +#endif + if (vm_flags & VM_EXECUTABLE) removed_exe_file_vma(mm); } else { vma_link(mm, vma, prev, rb_link, rb_parent); file = vma->vm_file; + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma_m) + pax_mirror_vma(vma_m, vma); +#endif + } /* Once vma denies write, undo our temporary denial count */ if (correct_wcount) atomic_inc(&inode->i_writecount); out: - mm->total_vm += len >> PAGE_SHIFT; + vx_vmpages_add(mm, len >> PAGE_SHIFT); vm_stat_account(mm, vm_flags, file, len >> PAGE_SHIFT); + track_exec_limit(mm, addr, addr + len, vm_flags); if (vm_flags & VM_LOCKED) { - mm->locked_vm += len >> PAGE_SHIFT; + vx_vmlocked_add(mm, len >> PAGE_SHIFT); make_pages_present(addr, addr + len); } if ((flags & MAP_POPULATE) && !(flags & MAP_NONBLOCK)) @@ -1241,6 +1393,12 @@ unmap_and_free_vma: unmap_region(mm, vma, prev, vma->vm_start, vma->vm_end); charged = 0; free_vma: + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma_m) + kmem_cache_free(vm_area_cachep, vma_m); +#endif + kmem_cache_free(vm_area_cachep, vma); unacct_error: if (charged) @@ -1274,6 +1432,10 @@ arch_get_unmapped_area(struct file *filp if (flags & MAP_FIXED) return addr; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + if (addr) { addr = PAGE_ALIGN(addr); vma = find_vma(mm, addr); @@ -1282,10 +1444,10 @@ arch_get_unmapped_area(struct file *filp return addr; } if (len > mm->cached_hole_size) { - start_addr = addr = mm->free_area_cache; + start_addr = addr = mm->free_area_cache; } else { - start_addr = addr = TASK_UNMAPPED_BASE; - mm->cached_hole_size = 0; + start_addr = addr = mm->mmap_base; + mm->cached_hole_size = 0; } full_search: @@ -1296,9 +1458,8 @@ full_search: * Start a new search - just in case we missed * some holes. */ - if (start_addr != TASK_UNMAPPED_BASE) { - addr = TASK_UNMAPPED_BASE; - start_addr = addr; + if (start_addr != mm->mmap_base) { + start_addr = addr = mm->mmap_base; mm->cached_hole_size = 0; goto full_search; } @@ -1320,10 +1481,16 @@ full_search: void arch_unmap_area(struct mm_struct *mm, unsigned long addr) { + +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && SEGMEXEC_TASK_SIZE <= addr) + return; +#endif + /* * Is this a new hole at the lowest possible address? */ - if (addr >= TASK_UNMAPPED_BASE && addr < mm->free_area_cache) { + if (addr >= mm->mmap_base && addr < mm->free_area_cache) { mm->free_area_cache = addr; mm->cached_hole_size = ~0UL; } @@ -1341,7 +1508,7 @@ arch_get_unmapped_area_topdown(struct fi { struct vm_area_struct *vma; struct mm_struct *mm = current->mm; - unsigned long addr = addr0; + unsigned long base = mm->mmap_base, addr = addr0; /* requested length too big for entire address space */ if (len > TASK_SIZE) @@ -1350,6 +1517,10 @@ arch_get_unmapped_area_topdown(struct fi if (flags & MAP_FIXED) return addr; +#ifdef CONFIG_PAX_RANDMMAP + if (!(mm->pax_flags & MF_PAX_RANDMMAP)) +#endif + /* requesting a specific address */ if (addr) { addr = PAGE_ALIGN(addr); @@ -1407,13 +1578,21 @@ bottomup: * 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; - mm->free_area_cache = TASK_UNMAPPED_BASE; addr = arch_get_unmapped_area(filp, addr0, len, pgoff, flags); /* * Restore the topdown base: */ - mm->free_area_cache = mm->mmap_base; + mm->mmap_base = base; + mm->free_area_cache = base; mm->cached_hole_size = ~0UL; return addr; @@ -1422,6 +1601,12 @@ bottomup: void arch_unmap_area_topdown(struct mm_struct *mm, unsigned long addr) { + +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && SEGMEXEC_TASK_SIZE <= addr) + return; +#endif + /* * Is this a new hole at the highest possible address? */ @@ -1429,8 +1614,10 @@ void arch_unmap_area_topdown(struct mm_s mm->free_area_cache = addr; /* dont allow allocations above current base */ - if (mm->free_area_cache > mm->mmap_base) + if (mm->free_area_cache > mm->mmap_base) { mm->free_area_cache = mm->mmap_base; + mm->cached_hole_size = ~0UL; + } } unsigned long @@ -1530,6 +1717,27 @@ out: return prev ? prev->vm_next : vma; } +#ifdef CONFIG_PAX_SEGMEXEC +struct vm_area_struct *pax_find_mirror_vma(struct vm_area_struct *vma) +{ + struct vm_area_struct *vma_m; + + BUG_ON(!vma || vma->vm_start >= vma->vm_end); + if (!(vma->vm_mm->pax_flags & MF_PAX_SEGMEXEC) || !(vma->vm_flags & VM_EXEC)) { + BUG_ON(vma->vm_mirror); + return NULL; + } + BUG_ON(vma->vm_start < SEGMEXEC_TASK_SIZE && SEGMEXEC_TASK_SIZE < vma->vm_end); + vma_m = vma->vm_mirror; + BUG_ON(!vma_m || vma_m->vm_mirror != vma); + BUG_ON(vma->vm_file != vma_m->vm_file); + BUG_ON(vma->vm_end - vma->vm_start != vma_m->vm_end - vma_m->vm_start); + BUG_ON(vma->vm_pgoff != vma_m->vm_pgoff || vma->anon_vma != vma_m->anon_vma); + BUG_ON((vma->vm_flags ^ vma_m->vm_flags) & ~(VM_WRITE | VM_MAYWRITE | VM_ACCOUNT | VM_LOCKED)); + return vma_m; +} +#endif + /* * Verify that the stack growth is acceptable and * update accounting. This is shared with both the @@ -1546,6 +1754,7 @@ static int acct_stack_growth(struct vm_a return -ENOMEM; /* Stack limit test */ + gr_learn_resource(current, RLIMIT_STACK, size, 1); if (size > rlim[RLIMIT_STACK].rlim_cur) return -ENOMEM; @@ -1555,6 +1764,7 @@ static int acct_stack_growth(struct vm_a unsigned long limit; locked = mm->locked_vm + grow; limit = rlim[RLIMIT_MEMLOCK].rlim_cur >> PAGE_SHIFT; + gr_learn_resource(current, RLIMIT_MEMLOCK, locked << PAGE_SHIFT, 1); if (locked > limit && !capable(CAP_IPC_LOCK)) return -ENOMEM; } @@ -1569,13 +1779,13 @@ static int acct_stack_growth(struct vm_a * Overcommit.. This must be the final test, as it will * update security statistics. */ - if (security_vm_enough_memory(grow)) + if (security_vm_enough_memory_mm(mm, grow)) return -ENOMEM; /* Ok, everything looks good - let it rip */ - mm->total_vm += grow; + vx_vmpages_add(mm, grow); if (vma->vm_flags & VM_LOCKED) - mm->locked_vm += grow; + vx_vmlocked_add(mm, grow); vm_stat_account(mm, vma->vm_flags, vma->vm_file, grow); return 0; } @@ -1590,35 +1800,40 @@ static inline #endif int expand_upwards(struct vm_area_struct *vma, unsigned long address) { - int error; + int error, locknext; if (!(vma->vm_flags & VM_GROWSUP)) return -EFAULT; + /* Also guard against wrapping around to address 0. */ + if (address < PAGE_ALIGN(address+1)) + address = PAGE_ALIGN(address+1); + else + return -ENOMEM; + /* * We must make sure the anon_vma is allocated * so that the anon_vma locking is not a noop. */ if (unlikely(anon_vma_prepare(vma))) return -ENOMEM; + locknext = vma->vm_next && (vma->vm_next->vm_flags & VM_GROWSDOWN); + if (locknext && unlikely(anon_vma_prepare(vma->vm_next))) + return -ENOMEM; anon_vma_lock(vma); + if (locknext) + anon_vma_lock(vma->vm_next); /* * vma->vm_start/vm_end cannot change under us because the caller * is required to hold the mmap_sem in read mode. We need the - * anon_vma lock to serialize against concurrent expand_stacks. - * Also guard against wrapping around to address 0. + * anon_vma locks to serialize against concurrent expand_stacks + * and expand_upwards. */ - if (address < PAGE_ALIGN(address+4)) - address = PAGE_ALIGN(address+4); - else { - anon_vma_unlock(vma); - return -ENOMEM; - } error = 0; /* Somebody else might have raced and expanded it already */ - if (address > vma->vm_end) { + if (address > vma->vm_end && (!locknext || vma->vm_next->vm_start >= address)) { unsigned long size, grow; size = address - vma->vm_start; @@ -1628,6 +1843,8 @@ int expand_upwards(struct vm_area_struct if (!error) vma->vm_end = address; } + if (locknext) + anon_vma_unlock(vma->vm_next); anon_vma_unlock(vma); return error; } @@ -1639,7 +1856,8 @@ int expand_upwards(struct vm_area_struct static inline int expand_downwards(struct vm_area_struct *vma, unsigned long address) { - int error; + int error, lockprev = 0; + struct vm_area_struct *prev = NULL; /* * We must make sure the anon_vma is allocated @@ -1653,6 +1871,15 @@ static inline int expand_downwards(struc if (error) return error; +#if defined(CONFIG_STACK_GROWSUP) || defined(CONFIG_IA64) + find_vma_prev(vma->vm_mm, address, &prev); + lockprev = prev && (prev->vm_flags & VM_GROWSUP); +#endif + if (lockprev && unlikely(anon_vma_prepare(prev))) + return -ENOMEM; + if (lockprev) + anon_vma_lock(prev); + anon_vma_lock(vma); /* @@ -1662,9 +1889,15 @@ static inline int expand_downwards(struc */ /* Somebody else might have raced and expanded it already */ - if (address < vma->vm_start) { + if (address < vma->vm_start && (!lockprev || prev->vm_end <= address)) { unsigned long size, grow; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m; + + vma_m = pax_find_mirror_vma(vma); +#endif + size = vma->vm_end - address; grow = (vma->vm_start - address) >> PAGE_SHIFT; @@ -1672,9 +1905,20 @@ static inline int expand_downwards(struc if (!error) { vma->vm_start = address; vma->vm_pgoff -= grow; + track_exec_limit(vma->vm_mm, vma->vm_start, vma->vm_end, vma->vm_flags); + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma_m) { + vma_m->vm_start -= grow << PAGE_SHIFT; + vma_m->vm_pgoff -= grow; + } +#endif + } } anon_vma_unlock(vma); + if (lockprev) + anon_vma_unlock(prev); return error; } @@ -1745,10 +1989,15 @@ static void remove_vma_list(struct mm_st update_hiwater_vm(mm); do { long nrpages = vma_pages(vma); - - mm->total_vm -= nrpages; +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && (vma->vm_start >= SEGMEXEC_TASK_SIZE)) { + vma = remove_vma(vma); + continue; + } +#endif + vx_vmpages_sub(mm, nrpages); if (vma->vm_flags & VM_LOCKED) - mm->locked_vm -= nrpages; + vx_vmlocked_sub(mm, nrpages); vm_stat_account(mm, vma->vm_flags, vma->vm_file, -nrpages); vma = remove_vma(vma); } while (vma); @@ -1792,6 +2041,16 @@ detach_vmas_to_be_unmapped(struct mm_str insertion_point = (prev ? &prev->vm_next : &mm->mmap); do { + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma->vm_mirror) { + BUG_ON(!vma->vm_mirror->vm_mirror || vma->vm_mirror->vm_mirror != vma); + vma->vm_mirror->vm_mirror = NULL; + vma->vm_mirror->vm_flags &= ~VM_EXEC; + vma->vm_mirror = NULL; + } +#endif + rb_erase(&vma->vm_rb, &mm->mm_rb); mm->map_count--; tail_vma = vma; @@ -1811,6 +2070,108 @@ detach_vmas_to_be_unmapped(struct mm_str * Split a vma into two pieces at address 'addr', a new vma is allocated * either for the first part or the tail. */ + +#ifdef CONFIG_PAX_SEGMEXEC +int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, + unsigned long addr, int new_below) +{ + struct mempolicy *pol; + struct vm_area_struct *new, *vma_m, *new_m = NULL; + unsigned long addr_m = addr + SEGMEXEC_TASK_SIZE; + + if (is_vm_hugetlb_page(vma) && (addr & ~HPAGE_MASK)) + return -EINVAL; + + vma_m = pax_find_mirror_vma(vma); + if (vma_m) { + BUG_ON(vma->vm_end > SEGMEXEC_TASK_SIZE); + if (mm->map_count >= sysctl_max_map_count-1) + return -ENOMEM; + } else if (mm->map_count >= sysctl_max_map_count) + return -ENOMEM; + + new = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + if (!new) + return -ENOMEM; + + if (vma_m) { + new_m = kmem_cache_alloc(vm_area_cachep, GFP_KERNEL); + if (!new_m) { + kmem_cache_free(vm_area_cachep, new); + return -ENOMEM; + } + } + + /* most fields are the same, copy all, and then fixup */ + *new = *vma; + + if (new_below) + new->vm_end = addr; + else { + new->vm_start = addr; + new->vm_pgoff += ((addr - vma->vm_start) >> PAGE_SHIFT); + } + + if (vma_m) { + *new_m = *vma_m; + new_m->vm_mirror = new; + new->vm_mirror = new_m; + + if (new_below) + new_m->vm_end = addr_m; + else { + new_m->vm_start = addr_m; + new_m->vm_pgoff += ((addr_m - vma_m->vm_start) >> PAGE_SHIFT); + } + } + + pol = mpol_dup(vma_policy(vma)); + if (IS_ERR(pol)) { + if (new_m) + kmem_cache_free(vm_area_cachep, new_m); + kmem_cache_free(vm_area_cachep, new); + return PTR_ERR(pol); + } + vma_set_policy(new, pol); + + if (new->vm_file) { + get_file(new->vm_file); + if (vma->vm_flags & VM_EXECUTABLE) + added_exe_file_vma(mm); + } + + if (new->vm_ops && new->vm_ops->open) + new->vm_ops->open(new); + + if (new_below) + vma_adjust(vma, addr, vma->vm_end, vma->vm_pgoff + + ((addr - new->vm_start) >> PAGE_SHIFT), new); + else + vma_adjust(vma, vma->vm_start, addr, vma->vm_pgoff, new); + + if (vma_m) { + mpol_get(pol); + vma_set_policy(new_m, pol); + + if (new_m->vm_file) { + get_file(new_m->vm_file); + if (vma_m->vm_flags & VM_EXECUTABLE) + added_exe_file_vma(mm); + } + + if (new_m->vm_ops && new_m->vm_ops->open) + new_m->vm_ops->open(new_m); + + if (new_below) + vma_adjust(vma_m, addr_m, vma_m->vm_end, vma_m->vm_pgoff + + ((addr_m - new_m->vm_start) >> PAGE_SHIFT), new_m); + else + vma_adjust(vma_m, vma_m->vm_start, addr_m, vma_m->vm_pgoff, new_m); + } + + return 0; +} +#else int split_vma(struct mm_struct * mm, struct vm_area_struct * vma, unsigned long addr, int new_below) { @@ -1862,17 +2223,37 @@ int split_vma(struct mm_struct * mm, str return 0; } +#endif /* Munmap is split into 2 main parts -- this part which finds * what needs doing, and the areas themselves, which do the * work. This now handles partial unmappings. * Jeremy Fitzhardinge */ +#ifdef CONFIG_PAX_SEGMEXEC int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) { + int ret = __do_munmap(mm, start, len); + if (ret || !(mm->pax_flags & MF_PAX_SEGMEXEC)) + return ret; + + return __do_munmap(mm, start + SEGMEXEC_TASK_SIZE, len); +} + +int __do_munmap(struct mm_struct *mm, unsigned long start, size_t len) +#else +int do_munmap(struct mm_struct *mm, unsigned long start, size_t len) +#endif +{ unsigned long end; struct vm_area_struct *vma, *prev, *last; + /* + * mm->mmap_sem is required to protect against another thread + * changing the mappings in case we sleep. + */ + verify_mm_writelocked(mm); + if ((start & ~PAGE_MASK) || start > TASK_SIZE || len > TASK_SIZE-start) return -EINVAL; @@ -1922,6 +2303,8 @@ int do_munmap(struct mm_struct *mm, unsi /* Fix up all other VM information */ remove_vma_list(mm, vma); + track_exec_limit(mm, start, end, 0UL); + return 0; } @@ -1934,22 +2317,18 @@ SYSCALL_DEFINE2(munmap, unsigned long, a profile_munmap(addr); +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && + (len > SEGMEXEC_TASK_SIZE || addr > SEGMEXEC_TASK_SIZE-len)) + return -EINVAL; +#endif + down_write(&mm->mmap_sem); ret = do_munmap(mm, addr, len); up_write(&mm->mmap_sem); return ret; } -static inline void verify_mm_writelocked(struct mm_struct *mm) -{ -#ifdef CONFIG_DEBUG_VM - if (unlikely(down_read_trylock(&mm->mmap_sem))) { - WARN_ON(1); - up_read(&mm->mmap_sem); - } -#endif -} - /* * this is really a simplified "do_mmap". it only handles * anonymous maps. eventually we may be able to do some @@ -1963,6 +2342,11 @@ unsigned long do_brk(unsigned long addr, struct rb_node ** rb_link, * rb_parent; pgoff_t pgoff = addr >> PAGE_SHIFT; int error; + unsigned long charged; + +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m = NULL; +#endif len = PAGE_ALIGN(len); if (!len) @@ -1980,21 +2364,38 @@ unsigned long do_brk(unsigned long addr, flags = VM_DATA_DEFAULT_FLAGS | VM_ACCOUNT | mm->def_flags; +#if defined(CONFIG_PAX_PAGEEXEC) || defined(CONFIG_PAX_SEGMEXEC) + if (mm->pax_flags & (MF_PAX_PAGEEXEC | MF_PAX_SEGMEXEC)) { + flags &= ~VM_EXEC; + +#ifdef CONFIG_PAX_MPROTECT + if (mm->pax_flags & MF_PAX_MPROTECT) + flags &= ~VM_MAYEXEC; +#endif + + } +#endif + error = arch_mmap_check(addr, len, flags); if (error) return error; + charged = len >> PAGE_SHIFT; + /* * mlock MCL_FUTURE? */ if (mm->def_flags & VM_LOCKED) { unsigned long locked, lock_limit; - locked = len >> PAGE_SHIFT; + locked = charged; locked += mm->locked_vm; lock_limit = current->signal->rlim[RLIMIT_MEMLOCK].rlim_cur; lock_limit >>= PAGE_SHIFT; + gr_learn_resource(current, RLIMIT_MEMLOCK, locked << PAGE_SHIFT, 1); if (locked > lock_limit && !capable(CAP_IPC_LOCK)) return -EAGAIN; + if (!vx_vmlocked_avail(mm, charged)) + return -ENOMEM; } /* @@ -2006,22 +2407,23 @@ unsigned long do_brk(unsigned long addr, /* * Clear old maps. this also does some error checking for us */ - munmap_back: vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); if (vma && vma->vm_start < addr + len) { if (do_munmap(mm, addr, len)) return -ENOMEM; - goto munmap_back; + vma = find_vma_prepare(mm, addr, &prev, &rb_link, &rb_parent); + BUG_ON(vma && vma->vm_start < addr + len); } /* Check against address space limits *after* clearing old maps... */ - if (!may_expand_vm(mm, len >> PAGE_SHIFT)) + if (!may_expand_vm(mm, charged)) return -ENOMEM; if (mm->map_count > sysctl_max_map_count) return -ENOMEM; - if (security_vm_enough_memory(len >> PAGE_SHIFT)) + if (security_vm_enough_memory(charged) || + !vx_vmpages_avail(mm, charged)) return -ENOMEM; /* Can we just expand an old private anonymous mapping? */ @@ -2034,10 +2436,21 @@ unsigned long do_brk(unsigned long addr, */ vma = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); if (!vma) { - vm_unacct_memory(len >> PAGE_SHIFT); + vm_unacct_memory(charged); return -ENOMEM; } +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && (flags & VM_EXEC)) { + vma_m = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + if (!vma_m) { + kmem_cache_free(vm_area_cachep, vma); + vm_unacct_memory(charged); + return -ENOMEM; + } + } +#endif + vma->vm_mm = mm; vma->vm_start = addr; vma->vm_end = addr + len; @@ -2045,12 +2458,17 @@ unsigned long do_brk(unsigned long addr, vma->vm_flags = flags; vma->vm_page_prot = vm_get_page_prot(flags); vma_link(mm, vma, prev, rb_link, rb_parent); +#ifdef CONFIG_PAX_SEGMEXEC + if (vma_m) + pax_mirror_vma(vma_m, vma); +#endif out: - mm->total_vm += len >> PAGE_SHIFT; + vx_vmpages_add(mm, charged); if (flags & VM_LOCKED) { - mm->locked_vm += len >> PAGE_SHIFT; + vx_vmlocked_add(mm, charged); make_pages_present(addr, addr + len); } + track_exec_limit(mm, addr, addr + len, flags); return addr; } @@ -2078,12 +2496,19 @@ void exit_mmap(struct mm_struct *mm) free_pgtables(tlb, vma, FIRST_USER_ADDRESS, 0); tlb_finish_mmu(tlb, 0, end); + set_mm_counter(mm, file_rss, 0); + set_mm_counter(mm, anon_rss, 0); + vx_vmpages_sub(mm, mm->total_vm); + vx_vmlocked_sub(mm, mm->locked_vm); + /* * Walk the list again, actually closing and freeing it, * with preemption enabled, without holding any MM locks. */ - while (vma) + while (vma) { + vma->vm_mirror = NULL; vma = remove_vma(vma); + } BUG_ON(mm->nr_ptes > (FIRST_USER_ADDRESS+PMD_SIZE-1)>>PMD_SHIFT); } @@ -2097,6 +2522,10 @@ int insert_vm_struct(struct mm_struct * struct vm_area_struct * __vma, * prev; struct rb_node ** rb_link, * rb_parent; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m = NULL; +#endif + /* * The vm_pgoff of a purely anonymous vma should be irrelevant * until its first write fault, when page's anon_vma and index @@ -2117,9 +2546,25 @@ int insert_vm_struct(struct mm_struct * if (__vma && __vma->vm_start < vma->vm_end) return -ENOMEM; if ((vma->vm_flags & VM_ACCOUNT) && - security_vm_enough_memory_mm(mm, vma_pages(vma))) + (security_vm_enough_memory_mm(mm, vma_pages(vma)) || + !vx_vmpages_avail(mm, vma_pages(vma)))) return -ENOMEM; + +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && (vma->vm_flags & VM_EXEC)) { + vma_m = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + if (!vma_m) + return -ENOMEM; + } +#endif + vma_link(mm, vma, prev, rb_link, rb_parent); + +#ifdef CONFIG_PAX_SEGMEXEC + if (vma_m) + pax_mirror_vma(vma_m, vma); +#endif + return 0; } @@ -2137,6 +2582,8 @@ struct vm_area_struct *copy_vma(struct v struct rb_node **rb_link, *rb_parent; struct mempolicy *pol; + BUG_ON(vma->vm_mirror); + /* * If anonymous vma has not yet been faulted, update new pgoff * to match new location, to increase its chance of merging. @@ -2180,6 +2627,35 @@ struct vm_area_struct *copy_vma(struct v return new_vma; } +#ifdef CONFIG_PAX_SEGMEXEC +void pax_mirror_vma(struct vm_area_struct *vma_m, struct vm_area_struct *vma) +{ + struct vm_area_struct *prev_m; + struct rb_node **rb_link_m, *rb_parent_m; + struct mempolicy *pol_m; + + BUG_ON(!(vma->vm_mm->pax_flags & MF_PAX_SEGMEXEC) || !(vma->vm_flags & VM_EXEC)); + BUG_ON(vma->vm_mirror || vma_m->vm_mirror); + BUG_ON(!mpol_equal(vma_policy(vma), vma_policy(vma_m))); + *vma_m = *vma; + pol_m = vma_policy(vma_m); + mpol_get(pol_m); + vma_set_policy(vma_m, pol_m); + vma_m->vm_start += SEGMEXEC_TASK_SIZE; + vma_m->vm_end += SEGMEXEC_TASK_SIZE; + vma_m->vm_flags &= ~(VM_WRITE | VM_MAYWRITE | VM_ACCOUNT | VM_LOCKED); + vma_m->vm_page_prot = vm_get_page_prot(vma_m->vm_flags); + if (vma_m->vm_file) + get_file(vma_m->vm_file); + if (vma_m->vm_ops && vma_m->vm_ops->open) + vma_m->vm_ops->open(vma_m); + find_vma_prepare(vma->vm_mm, vma_m->vm_start, &prev_m, &rb_link_m, &rb_parent_m); + vma_link(vma->vm_mm, vma_m, prev_m, rb_link_m, rb_parent_m); + vma_m->vm_mirror = vma; + vma->vm_mirror = vma_m; +} +#endif + /* * Return true if the calling process may expand its vm space by the passed * number of pages @@ -2190,9 +2666,11 @@ int may_expand_vm(struct mm_struct *mm, unsigned long lim; lim = current->signal->rlim[RLIMIT_AS].rlim_cur >> PAGE_SHIFT; - + gr_learn_resource(current, RLIMIT_AS, (cur + npages) << PAGE_SHIFT, 1); if (cur + npages > lim) return 0; + if (!vx_vmpages_avail(mm, npages)) + return 0; return 1; } @@ -2259,6 +2737,15 @@ int install_special_mapping(struct mm_st vma->vm_start = addr; vma->vm_end = addr + len; +#ifdef CONFIG_PAX_MPROTECT + if (mm->pax_flags & MF_PAX_MPROTECT) { + if ((vm_flags & (VM_WRITE | VM_EXEC)) != VM_EXEC) + vm_flags &= ~(VM_EXEC | VM_MAYEXEC); + else + vm_flags &= ~(VM_WRITE | VM_MAYWRITE); + } +#endif + vma->vm_flags = vm_flags | mm->def_flags | VM_DONTEXPAND; vma->vm_page_prot = vm_get_page_prot(vma->vm_flags); @@ -2270,8 +2757,7 @@ int install_special_mapping(struct mm_st return -ENOMEM; } - mm->total_vm += len >> PAGE_SHIFT; - + vx_vmpages_add(mm, len >> PAGE_SHIFT); return 0; } diff -NurpP --minimal linux-2.6.27.15/mm/mprotect.c linux-2.6.27.15-g-v/mm/mprotect.c --- linux-2.6.27.15/mm/mprotect.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/mprotect.c 2009-02-10 20:32:16.000000000 +0100 @@ -22,10 +22,17 @@ #include #include #include +#include + +#ifdef CONFIG_PAX_MPROTECT +#include +#endif + #include #include #include #include +#include #ifndef pgprot_modify static inline pgprot_t pgprot_modify(pgprot_t oldprot, pgprot_t newprot) @@ -133,6 +140,48 @@ static void change_protection(struct vm_ flush_tlb_range(vma, start, end); } +#ifdef CONFIG_ARCH_TRACK_EXEC_LIMIT +/* called while holding the mmap semaphor for writing except stack expansion */ +void track_exec_limit(struct mm_struct *mm, unsigned long start, unsigned long end, unsigned long prot) +{ + unsigned long oldlimit, newlimit = 0UL; + + if (!(mm->pax_flags & MF_PAX_PAGEEXEC) || nx_enabled) + return; + + spin_lock(&mm->page_table_lock); + oldlimit = mm->context.user_cs_limit; + if ((prot & VM_EXEC) && oldlimit < end) + /* USER_CS limit moved up */ + newlimit = end; + else if (!(prot & VM_EXEC) && start < oldlimit && oldlimit <= end) + /* USER_CS limit moved down */ + newlimit = start; + + if (newlimit) { + mm->context.user_cs_limit = newlimit; + +#ifdef CONFIG_SMP + wmb(); + cpus_clear(mm->context.cpu_user_cs_mask); + cpu_set(smp_processor_id(), mm->context.cpu_user_cs_mask); +#endif + + set_user_cs(mm->context.user_cs_base, mm->context.user_cs_limit, smp_processor_id()); + } + spin_unlock(&mm->page_table_lock); + if (newlimit == end) { + struct vm_area_struct *vma = find_vma(mm, oldlimit); + + for (; vma && vma->vm_start < end; vma = vma->vm_next) + if (is_vm_hugetlb_page(vma)) + hugetlb_change_protection(vma, vma->vm_start, vma->vm_end, vma->vm_page_prot); + else + change_protection(vma, vma->vm_start, vma->vm_end, vma->vm_page_prot, vma_wants_writenotify(vma)); + } +} +#endif + int mprotect_fixup(struct vm_area_struct *vma, struct vm_area_struct **pprev, unsigned long start, unsigned long end, unsigned long newflags) @@ -145,6 +194,14 @@ mprotect_fixup(struct vm_area_struct *vm int error; int dirty_accountable = 0; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m = NULL; + unsigned long start_m, end_m; + + start_m = start + SEGMEXEC_TASK_SIZE; + end_m = end + SEGMEXEC_TASK_SIZE; +#endif + if (newflags == oldflags) { *pprev = vma; return 0; @@ -165,6 +222,38 @@ mprotect_fixup(struct vm_area_struct *vm } } +#ifdef CONFIG_PAX_SEGMEXEC + if ((mm->pax_flags & MF_PAX_SEGMEXEC) && ((oldflags ^ newflags) & VM_EXEC)) { + if (start != vma->vm_start) { + error = split_vma(mm, vma, start, 1); + if (error) + goto fail; + BUG_ON(!*pprev || (*pprev)->vm_next == vma); + *pprev = (*pprev)->vm_next; + } + + if (end != vma->vm_end) { + error = split_vma(mm, vma, end, 0); + if (error) + goto fail; + } + + if (pax_find_mirror_vma(vma)) { + error = __do_munmap(mm, start_m, end_m - start_m); + if (error) + goto fail; + } else { + vma_m = kmem_cache_zalloc(vm_area_cachep, GFP_KERNEL); + if (!vma_m) { + error = -ENOMEM; + goto fail; + } + vma->vm_flags = newflags; + pax_mirror_vma(vma_m, vma); + } + } +#endif + /* * First try to merge with previous and/or next vma. */ @@ -196,8 +285,14 @@ success: * held in write mode. */ vma->vm_flags = newflags; + +#ifdef CONFIG_PAX_MPROTECT + if (current->binfmt && current->binfmt->handle_mprotect) + current->binfmt->handle_mprotect(vma, newflags); +#endif + vma->vm_page_prot = pgprot_modify(vma->vm_page_prot, - vm_get_page_prot(newflags)); + vm_get_page_prot(vma->vm_flags)); if (vma_wants_writenotify(vma)) { vma->vm_page_prot = vm_get_page_prot(newflags & ~VM_SHARED); @@ -238,6 +333,17 @@ SYSCALL_DEFINE3(mprotect, unsigned long, end = start + len; if (end <= start) return -ENOMEM; + +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) { + if (end > SEGMEXEC_TASK_SIZE) + return -EINVAL; + } else +#endif + + if (end > TASK_SIZE) + return -EINVAL; + if (!arch_validate_prot(prot)) return -EINVAL; @@ -245,7 +351,7 @@ SYSCALL_DEFINE3(mprotect, unsigned long, /* * Does the application expect PROT_READ to imply PROT_EXEC: */ - if ((prot & PROT_READ) && (current->personality & READ_IMPLIES_EXEC)) + if ((prot & (PROT_READ | PROT_WRITE)) && (current->personality & READ_IMPLIES_EXEC)) prot |= PROT_EXEC; vm_flags = calc_vm_prot_bits(prot); @@ -277,6 +383,16 @@ SYSCALL_DEFINE3(mprotect, unsigned long, if (start > vma->vm_start) prev = vma; + if (!gr_acl_handle_mprotect(vma->vm_file, prot)) { + error = -EACCES; + goto out; + } + +#ifdef CONFIG_PAX_MPROTECT + if (current->binfmt && current->binfmt->handle_mprotect) + current->binfmt->handle_mprotect(vma, vm_flags); +#endif + for (nstart = start ; ; ) { unsigned long newflags; @@ -300,6 +416,9 @@ SYSCALL_DEFINE3(mprotect, unsigned long, error = mprotect_fixup(vma, &prev, nstart, tmp, newflags); if (error) goto out; + + track_exec_limit(current->mm, nstart, tmp, vm_flags); + nstart = tmp; if (nstart < prev->vm_end) diff -NurpP --minimal linux-2.6.27.15/mm/mremap.c linux-2.6.27.15-g-v/mm/mremap.c --- linux-2.6.27.15/mm/mremap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/mremap.c 2009-02-10 20:32:16.000000000 +0100 @@ -19,6 +19,7 @@ #include #include #include +#include #include #include @@ -111,6 +112,12 @@ static void move_ptes(struct vm_area_str continue; pte = ptep_clear_flush(vma, old_addr, old_pte); pte = move_pte(pte, new_vma->vm_page_prot, old_addr, new_addr); + +#ifdef CONFIG_ARCH_TRACK_EXEC_LIMIT + if (!nx_enabled && (new_vma->vm_flags & (VM_PAGEEXEC | VM_EXEC)) == VM_PAGEEXEC) + pte = pte_exprotect(pte); +#endif + set_pte_at(mm, new_addr, new_pte, pte); } @@ -218,7 +225,7 @@ static unsigned long move_vma(struct vm_ * If this were a serious issue, we'd add a flag to do_munmap(). */ hiwater_vm = mm->hiwater_vm; - mm->total_vm += new_len >> PAGE_SHIFT; + vx_vmpages_add(mm, new_len >> PAGE_SHIFT); vm_stat_account(mm, vma->vm_flags, vma->vm_file, new_len>>PAGE_SHIFT); if (do_munmap(mm, old_addr, old_len) < 0) { @@ -236,7 +243,7 @@ static unsigned long move_vma(struct vm_ } if (vm_flags & VM_LOCKED) { - mm->locked_vm += new_len >> PAGE_SHIFT; + vx_vmlocked_add(mm, new_len >> PAGE_SHIFT); if (new_len > old_len) make_pages_present(new_addr + old_len, new_addr + new_len); @@ -260,6 +267,7 @@ unsigned long do_mremap(unsigned long ad struct vm_area_struct *vma; unsigned long ret = -EINVAL; unsigned long charged = 0; + unsigned long pax_task_size = TASK_SIZE; if (flags & ~(MREMAP_FIXED | MREMAP_MAYMOVE)) goto out; @@ -278,6 +286,15 @@ unsigned long do_mremap(unsigned long ad if (!new_len) goto out; +#ifdef CONFIG_PAX_SEGMEXEC + if (current->mm->pax_flags & MF_PAX_SEGMEXEC) + pax_task_size = SEGMEXEC_TASK_SIZE; +#endif + + if (new_len > pax_task_size || addr > pax_task_size-new_len || + old_len > pax_task_size || addr > pax_task_size-old_len) + goto out; + /* new_addr is only valid if MREMAP_FIXED is specified */ if (flags & MREMAP_FIXED) { if (new_addr & ~PAGE_MASK) @@ -285,16 +302,13 @@ unsigned long do_mremap(unsigned long ad if (!(flags & MREMAP_MAYMOVE)) goto out; - if (new_len > TASK_SIZE || new_addr > TASK_SIZE - new_len) + if (new_addr > pax_task_size - new_len) goto out; /* Check if the location we're moving into overlaps the * old location at all, and fail if it does. */ - if ((new_addr <= addr) && (new_addr+new_len) > addr) - goto out; - - if ((addr <= new_addr) && (addr+old_len) > new_addr) + if (addr + old_len > new_addr && new_addr + new_len > addr) goto out; ret = security_file_mmap(NULL, 0, 0, 0, new_addr, 1); @@ -332,6 +346,14 @@ unsigned long do_mremap(unsigned long ad ret = -EINVAL; goto out; } + +#ifdef CONFIG_PAX_SEGMEXEC + if (pax_find_mirror_vma(vma)) { + ret = -EINVAL; + goto out; + } +#endif + /* We can't remap across vm area boundaries */ if (old_len > vma->vm_end - addr) goto out; @@ -347,6 +369,9 @@ unsigned long do_mremap(unsigned long ad ret = -EAGAIN; if (locked > lock_limit && !capable(CAP_IPC_LOCK)) goto out; + if (!vx_vmlocked_avail(current->mm, + (new_len - old_len) >> PAGE_SHIFT)) + goto out; } if (!may_expand_vm(mm, (new_len - old_len) >> PAGE_SHIFT)) { ret = -ENOMEM; @@ -365,7 +390,7 @@ unsigned long do_mremap(unsigned long ad if (old_len == vma->vm_end - addr && !((flags & MREMAP_FIXED) && (addr != new_addr)) && (old_len != new_len || !(flags & MREMAP_MAYMOVE))) { - unsigned long max_addr = TASK_SIZE; + unsigned long max_addr = pax_task_size; if (vma->vm_next) max_addr = vma->vm_next->vm_start; /* can we just expand the current mapping? */ @@ -375,14 +400,15 @@ unsigned long do_mremap(unsigned long ad vma_adjust(vma, vma->vm_start, addr + new_len, vma->vm_pgoff, NULL); - mm->total_vm += pages; + vx_vmpages_add(mm, pages); vm_stat_account(mm, vma->vm_flags, vma->vm_file, pages); if (vma->vm_flags & VM_LOCKED) { - mm->locked_vm += pages; + vx_vmlocked_add(mm, pages); make_pages_present(addr + old_len, addr + new_len); } ret = addr; + track_exec_limit(vma->vm_mm, vma->vm_start, addr + new_len, vma->vm_flags); goto out; } } @@ -393,8 +419,8 @@ unsigned long do_mremap(unsigned long ad */ ret = -ENOMEM; if (flags & MREMAP_MAYMOVE) { + unsigned long map_flags = 0; if (!(flags & MREMAP_FIXED)) { - unsigned long map_flags = 0; if (vma->vm_flags & VM_MAYSHARE) map_flags |= MAP_SHARED; @@ -409,7 +435,12 @@ unsigned long do_mremap(unsigned long ad if (ret) goto out; } + map_flags = vma->vm_flags; ret = move_vma(vma, addr, old_len, new_len, new_addr); + if (!(ret & ~PAGE_MASK)) { + track_exec_limit(current->mm, addr, addr + old_len, 0UL); + track_exec_limit(current->mm, new_addr, new_addr + new_len, map_flags); + } } out: if (ret & ~PAGE_MASK) diff -NurpP --minimal linux-2.6.27.15/mm/nommu.c linux-2.6.27.15-g-v/mm/nommu.c --- linux-2.6.27.15/mm/nommu.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/nommu.c 2009-02-10 20:32:16.000000000 +0100 @@ -437,15 +437,6 @@ struct vm_area_struct *find_vma(struct m } EXPORT_SYMBOL(find_vma); -/* - * find a VMA - * - we don't extend stack VMAs under NOMMU conditions - */ -struct vm_area_struct *find_extend_vma(struct mm_struct *mm, unsigned long addr) -{ - return find_vma(mm, addr); -} - int expand_stack(struct vm_area_struct *vma, unsigned long address) { return -ENOMEM; @@ -1028,7 +1019,7 @@ unsigned long do_mmap_pgoff(struct file realalloc += kobjsize(vma); askedalloc += sizeof(*vma); - current->mm->total_vm += len >> PAGE_SHIFT; + vx_vmpages_add(current->mm, len >> PAGE_SHIFT); add_nommu_vma(vma); @@ -1160,7 +1151,7 @@ int do_munmap(struct mm_struct *mm, unsi kfree(vml); update_hiwater_vm(mm); - mm->total_vm -= len >> PAGE_SHIFT; + vx_vmpages_sub(mm, len >> PAGE_SHIFT); #ifdef DEBUG show_process_blocks(); @@ -1193,7 +1184,7 @@ void exit_mmap(struct mm_struct * mm) printk("Exit_mmap:\n"); #endif - mm->total_vm = 0; + vx_vmpages_sub(mm, mm->total_vm); while ((tmp = mm->context.vmlist)) { mm->context.vmlist = tmp->next; diff -NurpP --minimal linux-2.6.27.15/mm/oom_kill.c linux-2.6.27.15-g-v/mm/oom_kill.c --- linux-2.6.27.15/mm/oom_kill.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/oom_kill.c 2009-02-10 20:32:16.000000000 +0100 @@ -27,6 +27,7 @@ #include #include #include +#include int sysctl_panic_on_oom; int sysctl_oom_kill_allocating_task; @@ -73,6 +74,12 @@ unsigned long badness(struct task_struct points = mm->total_vm; /* + * add points for context badness + */ + + points += vx_badness(p, mm); + + /* * After this unlock we can no longer dereference local variable `mm' */ task_unlock(p); @@ -163,8 +170,8 @@ unsigned long badness(struct task_struct } #ifdef DEBUG - printk(KERN_DEBUG "OOMkill: task %d (%s) got %lu points\n", - p->pid, p->comm, points); + printk(KERN_DEBUG "OOMkill: task %d:#%u (%s) got %d points\n", + task_pid_nr(p), p->xid, p->comm, points); #endif return points; } @@ -325,8 +332,8 @@ static void __oom_kill_task(struct task_ } if (verbose) - printk(KERN_ERR "Killed process %d (%s)\n", - task_pid_nr(p), p->comm); + printk(KERN_ERR "Killed process %d:#%u (%s)\n", + task_pid_nr(p), p->xid, p->comm); /* * We give our sacrificial lamb high priority and access to @@ -406,8 +413,8 @@ static int oom_kill_process(struct task_ return 0; } - printk(KERN_ERR "%s: kill process %d (%s) score %li or a child\n", - message, task_pid_nr(p), p->comm, points); + printk(KERN_ERR "%s: kill process %d:#%u (%s) score %li or a child\n", + message, task_pid_nr(p), p->xid, p->comm, points); /* Try to kill a child first */ list_for_each_entry(c, &p->children, sibling) { diff -NurpP --minimal linux-2.6.27.15/mm/page_alloc.c linux-2.6.27.15-g-v/mm/page_alloc.c --- linux-2.6.27.15/mm/page_alloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/page_alloc.c 2009-02-10 20:32:16.000000000 +0100 @@ -46,6 +46,8 @@ #include #include #include +#include +#include #include #include @@ -515,9 +517,20 @@ static void free_pages_bulk(struct zone static void free_one_page(struct zone *zone, struct page *page, int order) { + +#ifdef CONFIG_PAX_MEMORY_SANITIZE + unsigned long index = 1UL << order; +#endif + spin_lock(&zone->lock); zone_clear_flag(zone, ZONE_ALL_UNRECLAIMABLE); zone->pages_scanned = 0; + +#ifdef CONFIG_PAX_MEMORY_SANITIZE + for (; index; --index) + sanitize_highpage(page + index - 1); +#endif + __free_one_page(page, zone, order); spin_unlock(&zone->lock); } @@ -635,8 +648,10 @@ static int prep_new_page(struct page *pa arch_alloc_page(page, order); kernel_map_pages(page, 1 << order, 1); +#ifndef CONFIG_PAX_MEMORY_SANITIZE if (gfp_flags & __GFP_ZERO) prep_zero_page(page, order, gfp_flags); +#endif if (order && (gfp_flags & __GFP_COMP)) prep_compound_page(page, order); @@ -1009,6 +1024,11 @@ static void free_hot_cold_page(struct pa list_add(&page->lru, &pcp->list); set_page_private(page, get_pageblock_migratetype(page)); pcp->count++; + +#ifdef CONFIG_PAX_MEMORY_SANITIZE + sanitize_highpage(page); +#endif + if (pcp->count >= pcp->high) { free_pages_bulk(zone, pcp->batch, &pcp->list, 0); pcp->count -= pcp->batch; @@ -1823,6 +1843,9 @@ void si_meminfo(struct sysinfo *val) val->totalhigh = totalhigh_pages; val->freehigh = nr_free_highpages(); val->mem_unit = PAGE_SIZE; + + if (vx_flags(VXF_VIRT_MEM, 0)) + vx_vsi_meminfo(val); } EXPORT_SYMBOL(si_meminfo); @@ -1843,6 +1866,9 @@ void si_meminfo_node(struct sysinfo *val val->freehigh = 0; #endif val->mem_unit = PAGE_SIZE; + + if (vx_flags(VXF_VIRT_MEM, 0)) + vx_vsi_meminfo(val); } #endif diff -NurpP --minimal linux-2.6.27.15/mm/rmap.c linux-2.6.27.15-g-v/mm/rmap.c --- linux-2.6.27.15/mm/rmap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/rmap.c 2009-02-10 20:32:16.000000000 +0100 @@ -50,6 +50,7 @@ #include #include #include +#include #include @@ -91,6 +92,10 @@ int anon_vma_prepare(struct vm_area_stru struct mm_struct *mm = vma->vm_mm; struct anon_vma *allocated; +#ifdef CONFIG_PAX_SEGMEXEC + struct vm_area_struct *vma_m; +#endif + anon_vma = find_mergeable_anon_vma(vma); allocated = NULL; if (!anon_vma) { @@ -104,6 +109,15 @@ int anon_vma_prepare(struct vm_area_stru /* page_table_lock to protect against threads */ spin_lock(&mm->page_table_lock); if (likely(!vma->anon_vma)) { + +#ifdef CONFIG_PAX_SEGMEXEC + vma_m = pax_find_mirror_vma(vma); + if (vma_m) { + vma_m->anon_vma = anon_vma; + __anon_vma_link(vma_m); + } +#endif + vma->anon_vma = anon_vma; list_add_tail(&vma->anon_vma_node, &anon_vma->head); allocated = NULL; diff -NurpP --minimal linux-2.6.27.15/mm/shmem.c linux-2.6.27.15-g-v/mm/shmem.c --- linux-2.6.27.15/mm/shmem.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/shmem.c 2009-02-10 20:32:16.000000000 +0100 @@ -56,7 +56,6 @@ #include /* This magic number is used in glibc for posix shared memory */ -#define TMPFS_MAGIC 0x01021994 #define ENTRIES_PER_PAGE (PAGE_CACHE_SIZE/sizeof(unsigned long)) #define ENTRIES_PER_PAGEPAGE (ENTRIES_PER_PAGE*ENTRIES_PER_PAGE) @@ -1738,7 +1737,7 @@ static int shmem_statfs(struct dentry *d { struct shmem_sb_info *sbinfo = SHMEM_SB(dentry->d_sb); - buf->f_type = TMPFS_MAGIC; + buf->f_type = TMPFS_SUPER_MAGIC; buf->f_bsize = PAGE_CACHE_SIZE; buf->f_namelen = NAME_MAX; spin_lock(&sbinfo->stat_lock); @@ -2306,7 +2305,7 @@ static int shmem_fill_super(struct super sb->s_maxbytes = SHMEM_MAX_BYTES; sb->s_blocksize = PAGE_CACHE_SIZE; sb->s_blocksize_bits = PAGE_CACHE_SHIFT; - sb->s_magic = TMPFS_MAGIC; + sb->s_magic = TMPFS_SUPER_MAGIC; sb->s_op = &shmem_ops; sb->s_time_gran = 1; #ifdef CONFIG_TMPFS_POSIX_ACL @@ -2483,7 +2482,7 @@ static struct file_system_type tmpfs_fs_ .get_sb = shmem_get_sb, .kill_sb = kill_litter_super, }; -static struct vfsmount *shm_mnt; +struct vfsmount *shm_mnt; static int __init init_tmpfs(void) { diff -NurpP --minimal linux-2.6.27.15/mm/slab.c linux-2.6.27.15-g-v/mm/slab.c --- linux-2.6.27.15/mm/slab.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/slab.c 2009-02-10 20:32:16.000000000 +0100 @@ -304,7 +304,7 @@ struct kmem_list3 { * Need this for bootstrapping a per node allocator. */ #define NUM_INIT_LISTS (3 * MAX_NUMNODES) -struct kmem_list3 __initdata initkmem_list3[NUM_INIT_LISTS]; +struct kmem_list3 initkmem_list3[NUM_INIT_LISTS]; #define CACHE_CACHE 0 #define SIZE_AC MAX_NUMNODES #define SIZE_L3 (2 * MAX_NUMNODES) @@ -508,6 +508,8 @@ struct kmem_cache { #define STATS_INC_FREEMISS(x) do { } while (0) #endif +#include "slab_vs.h" + #if DEBUG /* @@ -653,14 +655,14 @@ struct cache_names { static struct cache_names __initdata cache_names[] = { #define CACHE(x) { .name = "size-" #x, .name_dma = "size-" #x "(DMA)" }, #include - {NULL,} + {NULL, NULL} #undef CACHE }; static struct arraycache_init initarray_cache __initdata = - { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; + { {0, BOOT_CPUCACHE_ENTRIES, 1, 0}, {NULL} }; static struct arraycache_init initarray_generic = - { {0, BOOT_CPUCACHE_ENTRIES, 1, 0} }; + { {0, BOOT_CPUCACHE_ENTRIES, 1, 0}, {NULL} }; /* internal cache of cache description objs */ static struct kmem_cache cache_cache = { @@ -2996,7 +2998,7 @@ retry: * there must be at least one object available for * allocation. */ - BUG_ON(slabp->inuse < 0 || slabp->inuse >= cachep->num); + BUG_ON(slabp->inuse >= cachep->num); while (slabp->inuse < cachep->num && batchcount--) { STATS_INC_ALLOCED(cachep); @@ -3337,6 +3339,7 @@ retry: obj = slab_get_obj(cachep, slabp, nodeid); check_slabp(cachep, slabp); + vx_slab_alloc(cachep, flags); l3->free_objects--; /* move slabp to correct slabp list: */ list_del(&slabp->list); @@ -3409,6 +3412,7 @@ __cache_alloc_node(struct kmem_cache *ca /* ___cache_alloc_node can fall back to other nodes */ ptr = ____cache_alloc_node(cachep, flags, nodeid); out: + vx_slab_alloc(cachep, flags); local_irq_restore(save_flags); ptr = cache_alloc_debugcheck_after(cachep, flags, ptr, caller); @@ -3580,6 +3584,7 @@ static inline void __cache_free(struct k check_irq_off(); objp = cache_free_debugcheck(cachep, objp, __builtin_return_address(0)); + vx_slab_free(cachep); /* * Skip calling cache_free_alien() when the platform is not numa. diff -NurpP --minimal linux-2.6.27.15/mm/slab_vs.h linux-2.6.27.15-g-v/mm/slab_vs.h --- linux-2.6.27.15/mm/slab_vs.h 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/slab_vs.h 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,27 @@ + +#include + +#include + +static inline +void vx_slab_alloc(struct kmem_cache *cachep, gfp_t flags) +{ + int what = gfp_zone(cachep->gfpflags); + + if (!current->vx_info) + return; + + atomic_add(cachep->buffer_size, ¤t->vx_info->cacct.slab[what]); +} + +static inline +void vx_slab_free(struct kmem_cache *cachep) +{ + int what = gfp_zone(cachep->gfpflags); + + if (!current->vx_info) + return; + + atomic_sub(cachep->buffer_size, ¤t->vx_info->cacct.slab[what]); +} + diff -NurpP --minimal linux-2.6.27.15/mm/swapfile.c linux-2.6.27.15-g-v/mm/swapfile.c --- linux-2.6.27.15/mm/swapfile.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/swapfile.c 2009-02-10 20:32:16.000000000 +0100 @@ -32,6 +32,8 @@ #include #include #include +#include +#include static DEFINE_SPINLOCK(swap_lock); static unsigned int nr_swapfiles; @@ -1748,6 +1750,8 @@ void si_swapinfo(struct sysinfo *val) val->freeswap = nr_swap_pages + nr_to_be_unused; val->totalswap = total_swap_pages + nr_to_be_unused; spin_unlock(&swap_lock); + if (vx_flags(VXF_VIRT_MEM, 0)) + vx_vsi_swapinfo(val); } /* diff -NurpP --minimal linux-2.6.27.15/mm/tiny-shmem.c linux-2.6.27.15-g-v/mm/tiny-shmem.c --- linux-2.6.27.15/mm/tiny-shmem.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/tiny-shmem.c 2009-02-10 20:32:16.000000000 +0100 @@ -26,7 +26,7 @@ static struct file_system_type tmpfs_fs_ .kill_sb = kill_litter_super, }; -static struct vfsmount *shm_mnt; +struct vfsmount *shm_mnt; static int __init init_tmpfs(void) { diff -NurpP --minimal linux-2.6.27.15/mm/util.c linux-2.6.27.15-g-v/mm/util.c --- linux-2.6.27.15/mm/util.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/util.c 2009-02-10 20:32:16.000000000 +0100 @@ -167,6 +167,12 @@ EXPORT_SYMBOL(strndup_user); void arch_pick_mmap_layout(struct mm_struct *mm) { 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; } diff -NurpP --minimal linux-2.6.27.15/mm/vmalloc.c linux-2.6.27.15-g-v/mm/vmalloc.c --- linux-2.6.27.15/mm/vmalloc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/mm/vmalloc.c 2009-02-10 20:32:16.000000000 +0100 @@ -98,19 +98,36 @@ static int vmap_pte_range(pmd_t *pmd, un unsigned long end, pgprot_t prot, struct page ***pages) { pte_t *pte; + int ret = -ENOMEM; + +#ifdef CONFIG_PAX_KERNEXEC + unsigned long cr0; +#endif pte = pte_alloc_kernel(pmd, addr); if (!pte) return -ENOMEM; + +#ifdef CONFIG_PAX_KERNEXEC + pax_open_kernel(cr0); +#endif + do { struct page *page = **pages; WARN_ON(!pte_none(*pte)); if (!page) - return -ENOMEM; + goto out; set_pte_at(&init_mm, addr, pte, mk_pte(page, prot)); (*pages)++; } while (pte++, addr += PAGE_SIZE, addr != end); - return 0; + ret = 0; +out: + +#ifdef CONFIG_PAX_KERNEXEC + pax_close_kernel(cr0); +#endif + + return ret; } static inline int vmap_pmd_range(pud_t *pud, unsigned long addr, @@ -215,6 +232,16 @@ __get_vm_area_node(unsigned long size, u unsigned long addr; BUG_ON(in_interrupt()); + +#if defined(CONFIG_MODULES) && defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if (flags & VM_KERNEXEC) { + if (start != VMALLOC_START || end != VMALLOC_END) + return NULL; + start = (unsigned long)MODULES_VADDR; + end = (unsigned long)MODULES_END; + } +#endif + if (flags & VM_IOREMAP) { int bit = fls(size); @@ -248,20 +275,15 @@ __get_vm_area_node(unsigned long size, u (unsigned long)tmp->addr, align); continue; } - if ((size + addr) < addr) - goto out; if (size + addr <= (unsigned long)tmp->addr) - goto found; + break; addr = ALIGN(tmp->size + (unsigned long)tmp->addr, align); - if (addr > end - size) - goto out; } if ((size + addr) < addr) goto out; if (addr > end - size) goto out; -found: area->next = *p; *p = area; @@ -466,6 +488,11 @@ void *vmap(struct page **pages, unsigned if (count > num_physpages) return NULL; +#if defined(CONFIG_MODULES) && defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if (!(pgprot_val(prot) & _PAGE_NX)) + flags |= VM_KERNEXEC; +#endif + area = get_vm_area_caller((count << PAGE_SHIFT), flags, __builtin_return_address(0)); if (!area) @@ -560,6 +587,13 @@ static void *__vmalloc_node(unsigned lon if (!size || (size >> PAGE_SHIFT) > num_physpages) return NULL; +#if defined(CONFIG_MODULES) && defined(CONFIG_X86_32) && defined(CONFIG_PAX_KERNEXEC) + if (!(pgprot_val(prot) & _PAGE_NX)) + area = __get_vm_area_node(size, VM_ALLOC | VM_KERNEXEC, VMALLOC_START, VMALLOC_END, + node, gfp_mask, caller); + else +#endif + area = __get_vm_area_node(size, VM_ALLOC, VMALLOC_START, VMALLOC_END, node, gfp_mask, caller); @@ -651,7 +685,7 @@ EXPORT_SYMBOL(vmalloc_node); void *vmalloc_exec(unsigned long size) { - return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM, PAGE_KERNEL_EXEC); + return __vmalloc(size, GFP_KERNEL | __GFP_HIGHMEM | __GFP_ZERO, PAGE_KERNEL_EXEC); } #if defined(CONFIG_64BIT) && defined(CONFIG_ZONE_DMA32) diff -NurpP --minimal linux-2.6.27.15/net/bridge/br_stp_if.c linux-2.6.27.15-g-v/net/bridge/br_stp_if.c --- linux-2.6.27.15/net/bridge/br_stp_if.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/bridge/br_stp_if.c 2009-02-10 20:32:16.000000000 +0100 @@ -146,7 +146,7 @@ static void br_stp_stop(struct net_bridg char *envp[] = { NULL }; if (br->stp_enabled == BR_USER_STP) { - r = call_usermodehelper(BR_STP_PROG, argv, envp, 1); + r = call_usermodehelper(BR_STP_PROG, argv, envp, UMH_WAIT_PROC); printk(KERN_INFO "%s: userspace STP stopped, return code %d\n", br->dev->name, r); diff -NurpP --minimal linux-2.6.27.15/net/core/dev.c linux-2.6.27.15-g-v/net/core/dev.c --- linux-2.6.27.15/net/core/dev.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/core/dev.c 2009-02-10 20:32:16.000000000 +0100 @@ -127,6 +127,7 @@ #include #include #include +#include #include "net-sysfs.h" @@ -925,10 +926,15 @@ int dev_change_name(struct net_device *d strlcpy(dev->name, newname, IFNAMSIZ); rollback: - err = device_rename(&dev->dev, dev->name); - if (err) { - memcpy(dev->name, oldname, IFNAMSIZ); - return err; + /* For now only devices in the initial network namespace + * are in sysfs. + */ + if (net == &init_net) { + ret = device_rename(&dev->dev, dev->name); + if (ret) { + memcpy(dev->name, oldname, IFNAMSIZ); + return ret; + } } write_lock_bh(&dev_base_lock); @@ -2518,6 +2524,8 @@ static int dev_ifconf(struct net *net, c total = 0; for_each_netdev(net, dev) { + if (!nx_dev_visible(current->nx_info, dev)) + continue; for (i = 0; i < NPROTO; i++) { if (gifconf_list[i]) { int done; @@ -2586,6 +2594,9 @@ static void dev_seq_printf_stats(struct { struct net_device_stats *stats = dev->get_stats(dev); + if (!nx_dev_visible(current->nx_info, dev)) + return; + seq_printf(seq, "%6s:%8lu %7lu %4lu %4lu %4lu %5lu %10lu %9lu " "%8lu %7lu %4lu %4lu %4lu %5lu %7lu %10lu\n", dev->name, stats->rx_bytes, stats->rx_packets, @@ -4388,6 +4399,15 @@ int dev_change_net_namespace(struct net_ if (dev->features & NETIF_F_NETNS_LOCAL) goto out; +#ifdef CONFIG_SYSFS + /* Don't allow real devices to be moved when sysfs + * is enabled. + */ + err = -EINVAL; + if (dev->dev.parent) + goto out; +#endif + /* Ensure the device has been registrered */ err = -EINVAL; if (dev->reg_state != NETREG_REGISTERED) @@ -4445,6 +4465,8 @@ int dev_change_net_namespace(struct net_ */ dev_addr_discard(dev); + netdev_unregister_kobject(dev); + /* Actually switch the network namespace */ dev_net_set(dev, net); @@ -4461,7 +4483,6 @@ int dev_change_net_namespace(struct net_ } /* Fixup kobjects */ - netdev_unregister_kobject(dev); err = netdev_register_kobject(dev); WARN_ON(err); diff -NurpP --minimal linux-2.6.27.15/net/core/flow.c linux-2.6.27.15-g-v/net/core/flow.c --- linux-2.6.27.15/net/core/flow.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/core/flow.c 2009-02-10 20:32:16.000000000 +0100 @@ -39,7 +39,7 @@ atomic_t flow_cache_genid = ATOMIC_INIT( static u32 flow_hash_shift; #define flow_hash_size (1 << flow_hash_shift) -static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables) = { NULL }; +static DEFINE_PER_CPU(struct flow_cache_entry **, flow_tables); #define flow_table(cpu) (per_cpu(flow_tables, cpu)) @@ -52,7 +52,7 @@ struct flow_percpu_info { u32 hash_rnd; int count; }; -static DEFINE_PER_CPU(struct flow_percpu_info, flow_hash_info) = { 0 }; +static DEFINE_PER_CPU(struct flow_percpu_info, flow_hash_info); #define flow_hash_rnd_recalc(cpu) \ (per_cpu(flow_hash_info, cpu).hash_rnd_recalc) @@ -69,7 +69,7 @@ struct flow_flush_info { atomic_t cpuleft; struct completion completion; }; -static DEFINE_PER_CPU(struct tasklet_struct, flow_flush_tasklets) = { NULL }; +static DEFINE_PER_CPU(struct tasklet_struct, flow_flush_tasklets); #define flow_flush_tasklet(cpu) (&per_cpu(flow_flush_tasklets, cpu)) diff -NurpP --minimal linux-2.6.27.15/net/core/net-sysfs.c linux-2.6.27.15-g-v/net/core/net-sysfs.c --- linux-2.6.27.15/net/core/net-sysfs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/core/net-sysfs.c 2009-02-10 20:32:16.000000000 +0100 @@ -440,6 +440,10 @@ void netdev_unregister_kobject(struct ne struct device *dev = &(net->dev); kobject_get(&dev->kobj); + + if (dev_net(net) != &init_net) + return; + device_del(dev); } @@ -465,6 +469,9 @@ int netdev_register_kobject(struct net_d #endif #endif /* CONFIG_SYSFS */ + if (dev_net(net) != &init_net) + return 0; + return device_add(dev); } diff -NurpP --minimal linux-2.6.27.15/net/core/rtnetlink.c linux-2.6.27.15-g-v/net/core/rtnetlink.c --- linux-2.6.27.15/net/core/rtnetlink.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/core/rtnetlink.c 2009-02-10 20:32:16.000000000 +0100 @@ -686,6 +686,8 @@ static int rtnl_dump_ifinfo(struct sk_bu idx = 0; for_each_netdev(net, dev) { + if (!nx_dev_visible(skb->sk->sk_nx_info, dev)) + continue; if (idx < s_idx) goto cont; if (rtnl_fill_ifinfo(skb, dev, RTM_NEWLINK, @@ -1219,6 +1221,9 @@ void rtmsg_ifinfo(int type, struct net_d struct sk_buff *skb; int err = -ENOBUFS; + if (!nx_dev_visible(current->nx_info, dev)) + return; + skb = nlmsg_new(if_nlmsg_size(dev), GFP_KERNEL); if (skb == NULL) goto errout; diff -NurpP --minimal linux-2.6.27.15/net/core/sock.c linux-2.6.27.15-g-v/net/core/sock.c --- linux-2.6.27.15/net/core/sock.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/core/sock.c 2009-02-10 20:32:16.000000000 +0100 @@ -124,6 +124,10 @@ #include #include +#include +#include +#include +#include #ifdef CONFIG_INET #include @@ -897,6 +901,8 @@ static struct sock *sk_prot_alloc(struct if (!try_module_get(prot->owner)) goto out_free_sec; } + sock_vx_init(sk); + sock_nx_init(sk); return sk; @@ -973,6 +979,11 @@ void sk_free(struct sock *sk) __func__, atomic_read(&sk->sk_omem_alloc)); put_net(sock_net(sk)); + vx_sock_dec(sk); + clr_vx_info(&sk->sk_vx_info); + sk->sk_xid = -1; + clr_nx_info(&sk->sk_nx_info); + sk->sk_nid = -1; sk_prot_free(sk->sk_prot_creator, sk); } @@ -1008,6 +1019,8 @@ struct sock *sk_clone(const struct sock /* SANITY */ get_net(sock_net(newsk)); + sock_vx_init(newsk); + sock_nx_init(newsk); sk_node_init(&newsk->sk_node); sock_lock_init(newsk); bh_lock_sock(newsk); @@ -1054,6 +1067,12 @@ struct sock *sk_clone(const struct sock newsk->sk_priority = 0; atomic_set(&newsk->sk_refcnt, 2); + set_vx_info(&newsk->sk_vx_info, sk->sk_vx_info); + newsk->sk_xid = sk->sk_xid; + vx_sock_inc(newsk); + set_nx_info(&newsk->sk_nx_info, sk->sk_nx_info); + newsk->sk_nid = sk->sk_nid; + /* * Increment the counter in the same struct proto as the master * sock (sk_refcnt_debug_inc uses newsk->sk_prot->socks, that @@ -1738,6 +1757,11 @@ void sock_init_data(struct socket *sock, sk->sk_stamp = ktime_set(-1L, 0); + set_vx_info(&sk->sk_vx_info, current->vx_info); + sk->sk_xid = vx_current_xid(); + vx_sock_inc(sk); + set_nx_info(&sk->sk_nx_info, current->nx_info); + sk->sk_nid = nx_current_nid(); atomic_set(&sk->sk_refcnt, 1); atomic_set(&sk->sk_drops, 0); } diff -NurpP --minimal linux-2.6.27.15/net/dccp/ccids/ccid3.c linux-2.6.27.15-g-v/net/dccp/ccids/ccid3.c --- linux-2.6.27.15/net/dccp/ccids/ccid3.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/dccp/ccids/ccid3.c 2009-02-10 20:32:16.000000000 +0100 @@ -43,7 +43,7 @@ static int ccid3_debug; #define ccid3_pr_debug(format, a...) DCCP_PR_DEBUG(ccid3_debug, format, ##a) #else -#define ccid3_pr_debug(format, a...) +#define ccid3_pr_debug(format, a...) do {} while (0) #endif /* diff -NurpP --minimal linux-2.6.27.15/net/dccp/dccp.h linux-2.6.27.15-g-v/net/dccp/dccp.h --- linux-2.6.27.15/net/dccp/dccp.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/dccp/dccp.h 2009-02-10 20:32:16.000000000 +0100 @@ -43,8 +43,8 @@ extern int dccp_debug; #define dccp_pr_debug(format, a...) DCCP_PR_DEBUG(dccp_debug, format, ##a) #define dccp_pr_debug_cat(format, a...) DCCP_PRINTK(dccp_debug, format, ##a) #else -#define dccp_pr_debug(format, a...) -#define dccp_pr_debug_cat(format, a...) +#define dccp_pr_debug(format, a...) do {} while (0) +#define dccp_pr_debug_cat(format, a...) do {} while (0) #endif extern struct inet_hashinfo dccp_hashinfo; diff -NurpP --minimal linux-2.6.27.15/net/ipv4/af_inet.c linux-2.6.27.15-g-v/net/ipv4/af_inet.c --- linux-2.6.27.15/net/ipv4/af_inet.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/af_inet.c 2009-02-10 20:32:16.000000000 +0100 @@ -114,6 +114,7 @@ #ifdef CONFIG_IP_MROUTE #include #endif +#include extern void ip_mc_drop_socket(struct sock *sk); @@ -325,9 +326,12 @@ lookup_protocol: } err = -EPERM; + if ((protocol == IPPROTO_ICMP) && + nx_capable(answer->capability, NXC_RAW_ICMP)) + goto override; if (answer->capability > 0 && !capable(answer->capability)) goto out_rcu_unlock; - +override: err = -EAFNOSUPPORT; if (!inet_netns_ok(net, protocol)) goto out_rcu_unlock; @@ -445,6 +449,7 @@ int inet_bind(struct socket *sock, struc struct sockaddr_in *addr = (struct sockaddr_in *)uaddr; struct sock *sk = sock->sk; struct inet_sock *inet = inet_sk(sk); + struct nx_v4_sock_addr nsa; unsigned short snum; int chk_addr_ret; int err; @@ -458,7 +463,11 @@ int inet_bind(struct socket *sock, struc if (addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); + err = v4_map_sock_addr(inet, addr, &nsa); + if (err) + goto out; + + chk_addr_ret = inet_addr_type(sock_net(sk), nsa.saddr); /* Not specified by any standard per-se, however it breaks too * many applications when removed. It is unfortunate since @@ -470,7 +479,7 @@ int inet_bind(struct socket *sock, struc err = -EADDRNOTAVAIL; if (!sysctl_ip_nonlocal_bind && !inet->freebind && - addr->sin_addr.s_addr != htonl(INADDR_ANY) && + nsa.saddr != htonl(INADDR_ANY) && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) @@ -495,7 +504,7 @@ int inet_bind(struct socket *sock, struc if (sk->sk_state != TCP_CLOSE || inet->num) goto out_release_sock; - inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; + v4_set_sock_addr(inet, &nsa); if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) inet->saddr = 0; /* Use device */ @@ -688,11 +697,13 @@ int inet_getname(struct socket *sock, st peer == 1)) return -ENOTCONN; sin->sin_port = inet->dport; - sin->sin_addr.s_addr = inet->daddr; + sin->sin_addr.s_addr = + nx_map_sock_lback(sk->sk_nx_info, inet->daddr); } else { __be32 addr = inet->rcv_saddr; if (!addr) addr = inet->saddr; + addr = nx_map_sock_lback(sk->sk_nx_info, addr); sin->sin_port = inet->sport; sin->sin_addr.s_addr = addr; } diff -NurpP --minimal linux-2.6.27.15/net/ipv4/devinet.c linux-2.6.27.15-g-v/net/ipv4/devinet.c --- linux-2.6.27.15/net/ipv4/devinet.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/devinet.c 2009-02-10 20:32:16.000000000 +0100 @@ -420,6 +420,7 @@ struct in_device *inetdev_by_index(struc return in_dev; } + /* Called only from RTNL semaphored context. No locks. */ struct in_ifaddr *inet_ifa_byprefix(struct in_device *in_dev, __be32 prefix, @@ -662,6 +663,8 @@ int devinet_ioctl(struct net *net, unsig *colon = ':'; if ((in_dev = __in_dev_get_rtnl(dev)) != NULL) { + struct nx_info *nxi = current->nx_info; + if (tryaddrmatch) { /* Matthias Andree */ /* compare label and address (4.4BSD style) */ @@ -670,6 +673,8 @@ int devinet_ioctl(struct net *net, unsig This is checked above. */ for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; ifap = &ifa->ifa_next) { + if (!nx_v4_ifa_visible(nxi, ifa)) + continue; if (!strcmp(ifr.ifr_name, ifa->ifa_label) && sin_orig.sin_addr.s_addr == ifa->ifa_address) { @@ -682,9 +687,12 @@ int devinet_ioctl(struct net *net, unsig comparing just the label */ if (!ifa) { for (ifap = &in_dev->ifa_list; (ifa = *ifap) != NULL; - ifap = &ifa->ifa_next) + ifap = &ifa->ifa_next) { + if (!nx_v4_ifa_visible(nxi, ifa)) + continue; if (!strcmp(ifr.ifr_name, ifa->ifa_label)) break; + } } } @@ -835,6 +843,8 @@ static int inet_gifconf(struct net_devic goto out; for (; ifa; ifa = ifa->ifa_next) { + if (!nx_v4_ifa_visible(current->nx_info, ifa)) + continue; if (!buf) { done += sizeof(ifr); continue; @@ -1165,6 +1175,7 @@ static int inet_dump_ifaddr(struct sk_bu struct net_device *dev; struct in_device *in_dev; struct in_ifaddr *ifa; + struct sock *sk = skb->sk; int s_ip_idx, s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; @@ -1179,6 +1190,8 @@ static int inet_dump_ifaddr(struct sk_bu for (ifa = in_dev->ifa_list, ip_idx = 0; ifa; ifa = ifa->ifa_next, ip_idx++) { + if (sk && !nx_v4_ifa_visible(sk->sk_nx_info, ifa)) + continue; if (ip_idx < s_ip_idx) continue; if (inet_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, diff -NurpP --minimal linux-2.6.27.15/net/ipv4/fib_hash.c linux-2.6.27.15-g-v/net/ipv4/fib_hash.c --- linux-2.6.27.15/net/ipv4/fib_hash.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/fib_hash.c 2009-02-10 20:32:16.000000000 +0100 @@ -1022,7 +1022,7 @@ static int fib_seq_show(struct seq_file prefix = f->fn_key; mask = FZ_MASK(iter->zone); flags = fib_flag_trans(fa->fa_type, mask, fi); - if (fi) + if (fi && nx_dev_visible(current->nx_info, fi->fib_dev)) seq_printf(seq, "%s\t%08X\t%08X\t%04X\t%d\t%u\t%d\t%08X\t%d\t%u\t%u%n", fi->fib_dev ? fi->fib_dev->name : "*", prefix, diff -NurpP --minimal linux-2.6.27.15/net/ipv4/inet_connection_sock.c linux-2.6.27.15-g-v/net/ipv4/inet_connection_sock.c --- linux-2.6.27.15/net/ipv4/inet_connection_sock.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/inet_connection_sock.c 2009-02-10 20:32:16.000000000 +0100 @@ -15,6 +15,7 @@ #include #include +#include #include #include @@ -47,10 +48,40 @@ void inet_get_local_port_range(int *low, } EXPORT_SYMBOL(inet_get_local_port_range); +int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) +{ + __be32 sk1_rcv_saddr = inet_rcv_saddr(sk1), + sk2_rcv_saddr = inet_rcv_saddr(sk2); + + if (inet_v6_ipv6only(sk2)) + return 0; + + if (sk1_rcv_saddr && + sk2_rcv_saddr && + sk1_rcv_saddr == sk2_rcv_saddr) + return 1; + + if (sk1_rcv_saddr && + !sk2_rcv_saddr && + v4_addr_in_nx_info(sk2->sk_nx_info, sk1_rcv_saddr, NXA_MASK_BIND)) + return 1; + + if (sk2_rcv_saddr && + !sk1_rcv_saddr && + v4_addr_in_nx_info(sk1->sk_nx_info, sk2_rcv_saddr, NXA_MASK_BIND)) + return 1; + + if (!sk1_rcv_saddr && + !sk2_rcv_saddr && + nx_v4_addr_conflict(sk1->sk_nx_info, sk2->sk_nx_info)) + return 1; + + return 0; +} + int inet_csk_bind_conflict(const struct sock *sk, const struct inet_bind_bucket *tb) { - const __be32 sk_rcv_saddr = inet_rcv_saddr(sk); struct sock *sk2; struct hlist_node *node; int reuse = sk->sk_reuse; @@ -70,9 +101,7 @@ int inet_csk_bind_conflict(const struct sk->sk_bound_dev_if == sk2->sk_bound_dev_if)) { if (!reuse || !sk2->sk_reuse || sk2->sk_state == TCP_LISTEN) { - const __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); - if (!sk2_rcv_saddr || !sk_rcv_saddr || - sk2_rcv_saddr == sk_rcv_saddr) + if (ipv4_rcv_saddr_equal(sk, sk2)) break; } } diff -NurpP --minimal linux-2.6.27.15/net/ipv4/inet_diag.c linux-2.6.27.15-g-v/net/ipv4/inet_diag.c --- linux-2.6.27.15/net/ipv4/inet_diag.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/inet_diag.c 2009-02-10 20:32:16.000000000 +0100 @@ -32,6 +32,8 @@ #include #include +#include +#include static const struct inet_diag_handler **inet_diag_table; @@ -120,8 +122,8 @@ static int inet_csk_diag_fill(struct soc r->id.idiag_sport = inet->sport; r->id.idiag_dport = inet->dport; - r->id.idiag_src[0] = inet->rcv_saddr; - r->id.idiag_dst[0] = inet->daddr; + r->id.idiag_src[0] = nx_map_sock_lback(sk->sk_nx_info, inet->rcv_saddr); + r->id.idiag_dst[0] = nx_map_sock_lback(sk->sk_nx_info, inet->daddr); #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) if (r->idiag_family == AF_INET6) { @@ -208,8 +210,8 @@ static int inet_twsk_diag_fill(struct in r->id.idiag_cookie[1] = (u32)(((unsigned long)tw >> 31) >> 1); r->id.idiag_sport = tw->tw_sport; r->id.idiag_dport = tw->tw_dport; - r->id.idiag_src[0] = tw->tw_rcv_saddr; - r->id.idiag_dst[0] = tw->tw_daddr; + r->id.idiag_src[0] = nx_map_sock_lback(tw->tw_nx_info, tw->tw_rcv_saddr); + r->id.idiag_dst[0] = nx_map_sock_lback(tw->tw_nx_info, tw->tw_daddr); r->idiag_state = tw->tw_substate; r->idiag_timer = 3; r->idiag_expires = DIV_ROUND_UP(tmo * 1000, HZ); @@ -266,6 +268,7 @@ static int inet_diag_get_exact(struct sk err = -EINVAL; if (req->idiag_family == AF_INET) { + /* TODO: lback */ sk = inet_lookup(&init_net, hashinfo, req->id.idiag_dst[0], req->id.idiag_dport, req->id.idiag_src[0], req->id.idiag_sport, req->id.idiag_if); @@ -508,6 +511,7 @@ static int inet_csk_diag_dump(struct soc } else #endif { + /* TODO: lback */ entry.saddr = &inet->rcv_saddr; entry.daddr = &inet->daddr; } @@ -544,6 +548,7 @@ static int inet_twsk_diag_dump(struct in } else #endif { + /* TODO: lback */ entry.saddr = &tw->tw_rcv_saddr; entry.daddr = &tw->tw_daddr; } @@ -590,8 +595,8 @@ static int inet_diag_fill_req(struct sk_ r->id.idiag_sport = inet->sport; r->id.idiag_dport = ireq->rmt_port; - r->id.idiag_src[0] = ireq->loc_addr; - r->id.idiag_dst[0] = ireq->rmt_addr; + r->id.idiag_src[0] = nx_map_sock_lback(sk->sk_nx_info, ireq->loc_addr); + r->id.idiag_dst[0] = nx_map_sock_lback(sk->sk_nx_info, ireq->rmt_addr); r->idiag_expires = jiffies_to_msecs(tmo); r->idiag_rqueue = 0; r->idiag_wqueue = 0; @@ -661,6 +666,7 @@ static int inet_diag_dump_reqs(struct sk continue; if (bc) { + /* TODO: lback */ entry.saddr = #if defined(CONFIG_IPV6) || defined (CONFIG_IPV6_MODULE) (entry.family == AF_INET6) ? @@ -729,6 +735,8 @@ static int inet_diag_dump(struct sk_buff sk_for_each(sk, node, &hashinfo->listening_hash[i]) { struct inet_sock *inet = inet_sk(sk); + if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (num < s_num) { num++; continue; @@ -790,6 +798,8 @@ skip_listen_ht: sk_for_each(sk, node, &head->chain) { struct inet_sock *inet = inet_sk(sk); + if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (num < s_num) goto next_normal; if (!(r->idiag_states & (1 << sk->sk_state))) @@ -814,6 +824,8 @@ next_normal: inet_twsk_for_each(tw, node, &head->twchain) { + if (!nx_check(tw->tw_nid, VS_WATCH_P | VS_IDENT)) + continue; if (num < s_num) goto next_dying; if (r->id.idiag_sport != tw->tw_sport && diff -NurpP --minimal linux-2.6.27.15/net/ipv4/inet_hashtables.c linux-2.6.27.15-g-v/net/ipv4/inet_hashtables.c --- linux-2.6.27.15/net/ipv4/inet_hashtables.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/inet_hashtables.c 2009-02-10 20:32:16.000000000 +0100 @@ -18,11 +18,15 @@ #include #include #include +#include #include #include +#include #include +extern void gr_update_task_in_ip_table(struct task_struct *task, const struct inet_sock *inet); + /* * Allocate and initialize a new local port bind bucket. * The bindhash mutex for snum's hash chain must be held here. @@ -163,11 +167,10 @@ static struct sock *inet_lookup_listener const __be32 rcv_saddr = inet->rcv_saddr; int score = sk->sk_family == PF_INET ? 1 : 0; - if (rcv_saddr) { - if (rcv_saddr != daddr) - continue; + if (v4_inet_addr_match(sk->sk_nx_info, daddr, rcv_saddr)) score += 2; - } + else + continue; if (sk->sk_bound_dev_if) { if (sk->sk_bound_dev_if != dif) continue; @@ -199,7 +202,7 @@ struct sock *__inet_lookup_listener(stru const struct inet_sock *inet = inet_sk((sk = __sk_head(head))); if (inet->num == hnum && !sk->sk_node.next && - (!inet->rcv_saddr || inet->rcv_saddr == daddr) && + v4_inet_addr_match(sk->sk_nx_info, daddr, inet->rcv_saddr) && (sk->sk_family == PF_INET || !ipv6_only_sock(sk)) && !sk->sk_bound_dev_if && net_eq(sock_net(sk), net)) goto sherry_cache; @@ -487,6 +490,8 @@ ok: } spin_unlock(&head->lock); + gr_update_task_in_ip_table(current, inet_sk(sk)); + if (tw) { inet_twsk_deschedule(tw, death_row); inet_twsk_put(tw); diff -NurpP --minimal linux-2.6.27.15/net/ipv4/netfilter/ipt_stealth.c linux-2.6.27.15-g-v/net/ipv4/netfilter/ipt_stealth.c --- linux-2.6.27.15/net/ipv4/netfilter/ipt_stealth.c 1970-01-01 01:00:00.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/netfilter/ipt_stealth.c 2009-02-10 20:32:16.000000000 +0100 @@ -0,0 +1,114 @@ +/* Kernel module to add stealth support. + * + * Copyright (C) 2002-2006 Brad Spengler + * + */ + +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include + +MODULE_LICENSE("GPL"); + +extern struct sock *udp_v4_lookup(struct net *net, u32 saddr, u16 sport, u32 daddr, u16 dport, int dif); + +static bool +match(const struct sk_buff *skb, + const struct net_device *in, + const struct net_device *out, + const struct xt_match *match, + const void *matchinfo, + int offset, + unsigned int protoff, + bool *hotdrop) +{ + struct iphdr *ip = ip_hdr(skb); + struct tcphdr th; + struct udphdr uh; + struct sock *sk = NULL; + + if (!ip || offset) return false; + + switch(ip->protocol) { + case IPPROTO_TCP: + if (skb_copy_bits(skb, (ip_hdr(skb))->ihl*4, &th, sizeof(th)) < 0) { + *hotdrop = true; + return false; + } + if (!(th.syn && !th.ack)) return false; + sk = inet_lookup_listener(dev_net(skb->dev), &tcp_hashinfo, ip->daddr, th.dest, inet_iif(skb)); + break; + case IPPROTO_UDP: + if (skb_copy_bits(skb, (ip_hdr(skb))->ihl*4, &uh, sizeof(uh)) < 0) { + *hotdrop = true; + return false; + } + sk = udp_v4_lookup(dev_net(skb->dev), ip->saddr, uh.source, ip->daddr, uh.dest, skb->dev->ifindex); + break; + default: + return false; + } + + if(!sk) // port is being listened on, match this + return true; + else { + sock_put(sk); + return false; + } +} + +/* Called when user tries to insert an entry of this type. */ +static bool +checkentry(const char *tablename, + const void *nip, + const struct xt_match *match, + void *matchinfo, + unsigned int hook_mask) +{ + const struct ipt_ip *ip = (const struct ipt_ip *)nip; + + if(((ip->proto == IPPROTO_TCP && !(ip->invflags & IPT_INV_PROTO)) || + ((ip->proto == IPPROTO_UDP) && !(ip->invflags & IPT_INV_PROTO))) + && (hook_mask & (1 << NF_INET_LOCAL_IN))) + return true; + + printk("stealth: Only works on TCP and UDP for the INPUT chain.\n"); + + return false; +} + + +static struct xt_match stealth_match __read_mostly = { + .name = "stealth", + .family = AF_INET, + .match = match, + .checkentry = checkentry, + .destroy = NULL, + .me = THIS_MODULE +}; + +static int __init init(void) +{ + return xt_register_match(&stealth_match); +} + +static void __exit fini(void) +{ + xt_unregister_match(&stealth_match); +} + +module_init(init); +module_exit(fini); diff -NurpP --minimal linux-2.6.27.15/net/ipv4/netfilter/Kconfig linux-2.6.27.15-g-v/net/ipv4/netfilter/Kconfig --- linux-2.6.27.15/net/ipv4/netfilter/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/netfilter/Kconfig 2009-02-10 20:32:17.000000000 +0100 @@ -111,6 +111,21 @@ config IP_NF_MATCH_ADDRTYPE If you want to compile it as a module, say M here and read . If unsure, say `N'. +config IP_NF_MATCH_STEALTH + tristate "stealth match support" + depends on IP_NF_IPTABLES + help + Enabling this option will drop all syn packets coming to unserved tcp + ports as well as all packets coming to unserved udp ports. If you + are using your system to route any type of packets (ie. via NAT) + you should put this module at the end of your ruleset, since it will + drop packets that aren't going to ports that are listening on your + machine itself, it doesn't take into account that the packet might be + destined for someone on your internal network if you're using NAT for + instance. + + To compile it as a module, choose M here. If unsure, say N. + # `filter', generic and specific targets config IP_NF_FILTER tristate "Packet filtering" @@ -407,4 +422,3 @@ config IP_NF_ARP_MANGLE hardware and network addresses. endmenu - diff -NurpP --minimal linux-2.6.27.15/net/ipv4/netfilter/Makefile linux-2.6.27.15-g-v/net/ipv4/netfilter/Makefile --- linux-2.6.27.15/net/ipv4/netfilter/Makefile 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/netfilter/Makefile 2009-02-10 20:32:17.000000000 +0100 @@ -59,6 +59,7 @@ obj-$(CONFIG_IP_NF_TARGET_MASQUERADE) += obj-$(CONFIG_IP_NF_TARGET_NETMAP) += ipt_NETMAP.o obj-$(CONFIG_IP_NF_TARGET_REDIRECT) += ipt_REDIRECT.o obj-$(CONFIG_IP_NF_TARGET_REJECT) += ipt_REJECT.o +obj-$(CONFIG_IP_NF_MATCH_STEALTH) += ipt_stealth.o obj-$(CONFIG_IP_NF_TARGET_TTL) += ipt_TTL.o obj-$(CONFIG_IP_NF_TARGET_ULOG) += ipt_ULOG.o diff -NurpP --minimal linux-2.6.27.15/net/ipv4/netfilter/nf_nat_helper.c linux-2.6.27.15-g-v/net/ipv4/netfilter/nf_nat_helper.c --- linux-2.6.27.15/net/ipv4/netfilter/nf_nat_helper.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/netfilter/nf_nat_helper.c 2009-02-10 20:32:17.000000000 +0100 @@ -18,6 +18,7 @@ #include #include +#include #include #include #include diff -NurpP --minimal linux-2.6.27.15/net/ipv4/netfilter.c linux-2.6.27.15-g-v/net/ipv4/netfilter.c --- linux-2.6.27.15/net/ipv4/netfilter.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/netfilter.c 2009-02-10 20:32:17.000000000 +0100 @@ -4,7 +4,7 @@ #include #include #include -#include +// #include #include #include #include diff -NurpP --minimal linux-2.6.27.15/net/ipv4/raw.c linux-2.6.27.15-g-v/net/ipv4/raw.c --- linux-2.6.27.15/net/ipv4/raw.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/raw.c 2009-02-10 20:32:17.000000000 +0100 @@ -117,7 +117,7 @@ static struct sock *__raw_v4_lookup(stru if (net_eq(sock_net(sk), net) && inet->num == num && !(inet->daddr && inet->daddr != raddr) && - !(inet->rcv_saddr && inet->rcv_saddr != laddr) && + v4_sock_addr_match(sk->sk_nx_info, inet, laddr) && !(sk->sk_bound_dev_if && sk->sk_bound_dev_if != dif)) goto found; /* gotcha */ } @@ -372,6 +372,12 @@ static int raw_send_hdrinc(struct sock * icmp_out_count(net, ((struct icmphdr *) skb_transport_header(skb))->type); + err = -EPERM; + if (!nx_check(0, VS_ADMIN) && !capable(CAP_NET_RAW) && + sk->sk_nx_info && + !v4_addr_in_nx_info(sk->sk_nx_info, iph->saddr, NXA_MASK_BIND)) + goto error_free; + err = NF_HOOK(PF_INET, NF_INET_LOCAL_OUT, skb, NULL, rt->u.dst.dev, dst_output); if (err > 0) @@ -383,6 +389,7 @@ out: error_fault: err = -EFAULT; +error_free: kfree_skb(skb); error: IP_INC_STATS(net, IPSTATS_MIB_OUTDISCARDS); @@ -550,6 +557,13 @@ static int raw_sendmsg(struct kiocb *ioc } security_sk_classify_flow(sk, &fl); + if (sk->sk_nx_info) { + err = ip_v4_find_src(sock_net(sk), + sk->sk_nx_info, &rt, &fl); + + if (err) + goto done; + } err = ip_route_output_flow(sock_net(sk), &rt, &fl, sk, 1); } if (err) @@ -619,17 +633,19 @@ static int raw_bind(struct sock *sk, str { struct inet_sock *inet = inet_sk(sk); struct sockaddr_in *addr = (struct sockaddr_in *) uaddr; + struct nx_v4_sock_addr nsa = { 0 }; int ret = -EINVAL; int chk_addr_ret; if (sk->sk_state != TCP_CLOSE || addr_len < sizeof(struct sockaddr_in)) goto out; - chk_addr_ret = inet_addr_type(sock_net(sk), addr->sin_addr.s_addr); + v4_map_sock_addr(inet, addr, &nsa); + chk_addr_ret = inet_addr_type(sock_net(sk), nsa.saddr); ret = -EADDRNOTAVAIL; - if (addr->sin_addr.s_addr && chk_addr_ret != RTN_LOCAL && + if (nsa.saddr && chk_addr_ret != RTN_LOCAL && chk_addr_ret != RTN_MULTICAST && chk_addr_ret != RTN_BROADCAST) goto out; - inet->rcv_saddr = inet->saddr = addr->sin_addr.s_addr; + v4_set_sock_addr(inet, &nsa); if (chk_addr_ret == RTN_MULTICAST || chk_addr_ret == RTN_BROADCAST) inet->saddr = 0; /* Use device */ sk_dst_reset(sk); @@ -681,7 +697,8 @@ static int raw_recvmsg(struct kiocb *ioc /* Copy the address. */ if (sin) { sin->sin_family = AF_INET; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + sin->sin_addr.s_addr = + nx_map_sock_lback(sk->sk_nx_info, ip_hdr(skb)->saddr); sin->sin_port = 0; memset(&sin->sin_zero, 0, sizeof(sin->sin_zero)); } @@ -858,7 +875,8 @@ static struct sock *raw_get_first(struct struct hlist_node *node; sk_for_each(sk, node, &state->h->ht[state->bucket]) - if (sock_net(sk) == seq_file_net(seq)) + if ((sock_net(sk) == seq_file_net(seq)) && + nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) goto found; } sk = NULL; @@ -874,7 +892,8 @@ static struct sock *raw_get_next(struct sk = sk_next(sk); try_again: ; - } while (sk && sock_net(sk) != seq_file_net(seq)); + } while (sk && ((sock_net(sk) != seq_file_net(seq)) || + !nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT))); if (!sk && ++state->bucket < RAW_HTABLE_SIZE) { sk = sk_head(&state->h->ht[state->bucket]); @@ -933,7 +952,10 @@ static void raw_sock_seq_show(struct seq seq_printf(seq, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d\n", - i, src, srcp, dest, destp, sp->sk_state, + i, + nx_map_sock_lback(current_nx_info(), src), srcp, + nx_map_sock_lback(current_nx_info(), dest), destp, + sp->sk_state, atomic_read(&sp->sk_wmem_alloc), atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), diff -NurpP --minimal linux-2.6.27.15/net/ipv4/syncookies.c linux-2.6.27.15-g-v/net/ipv4/syncookies.c --- linux-2.6.27.15/net/ipv4/syncookies.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/syncookies.c 2009-02-10 20:32:17.000000000 +0100 @@ -16,6 +16,7 @@ #include #include #include +#include /* Timestamps: lowest 9 bits store TCP options */ #define TSBITS 9 diff -NurpP --minimal linux-2.6.27.15/net/ipv4/tcp.c linux-2.6.27.15-g-v/net/ipv4/tcp.c --- linux-2.6.27.15/net/ipv4/tcp.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/tcp.c 2009-02-10 20:32:17.000000000 +0100 @@ -264,6 +264,7 @@ #include #include #include +#include #include #include diff -NurpP --minimal linux-2.6.27.15/net/ipv4/tcp_ipv4.c linux-2.6.27.15-g-v/net/ipv4/tcp_ipv4.c --- linux-2.6.27.15/net/ipv4/tcp_ipv4.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/tcp_ipv4.c 2009-02-10 20:32:17.000000000 +0100 @@ -59,6 +59,7 @@ #include #include #include +#include #include #include @@ -1886,6 +1887,12 @@ static void *listening_get_next(struct s req = req->dl_next; while (1) { while (req) { + vxdprintk(VXD_CBIT(net, 6), + "sk,req: %p [#%d] (from %d)", req->sk, + (req->sk)?req->sk->sk_nid:0, nx_current_nid()); + if (req->sk && + !nx_check(req->sk->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (req->rsk_ops->family == st->family) { cur = req; goto out; @@ -1910,6 +1917,10 @@ get_req: } get_sk: sk_for_each_from(sk, node) { + vxdprintk(VXD_CBIT(net, 6), "sk: %p [#%d] (from %d)", + sk, sk->sk_nid, nx_current_nid()); + if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) { cur = sk; goto out; @@ -1960,6 +1971,11 @@ static void *established_get_first(struc read_lock_bh(lock); sk_for_each(sk, node, &tcp_hashinfo.ehash[st->bucket].chain) { + vxdprintk(VXD_CBIT(net, 6), + "sk,egf: %p [#%d] (from %d)", + sk, sk->sk_nid, nx_current_nid()); + if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (sk->sk_family != st->family || !net_eq(sock_net(sk), net)) { continue; @@ -1970,6 +1986,11 @@ static void *established_get_first(struc st->state = TCP_SEQ_STATE_TIME_WAIT; inet_twsk_for_each(tw, node, &tcp_hashinfo.ehash[st->bucket].twchain) { + vxdprintk(VXD_CBIT(net, 6), + "tw: %p [#%d] (from %d)", + tw, tw->tw_nid, nx_current_nid()); + if (!nx_check(tw->tw_nid, VS_WATCH_P | VS_IDENT)) + continue; if (tw->tw_family != st->family || !net_eq(twsk_net(tw), net)) { continue; @@ -1998,7 +2019,9 @@ static void *established_get_next(struct tw = cur; tw = tw_next(tw); get_tw: - while (tw && (tw->tw_family != st->family || !net_eq(twsk_net(tw), net))) { + while (tw && (tw->tw_family != st->family || + !net_eq(twsk_net(tw), net) || + !nx_check(tw->tw_nid, VS_WATCH_P | VS_IDENT))) { tw = tw_next(tw); } if (tw) { @@ -2019,6 +2042,11 @@ get_tw: sk = sk_next(sk); sk_for_each_from(sk, node) { + vxdprintk(VXD_CBIT(net, 6), + "sk,egn: %p [#%d] (from %d)", + sk, sk->sk_nid, nx_current_nid()); + if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (sk->sk_family == st->family && net_eq(sock_net(sk), net)) goto found; } @@ -2173,9 +2201,9 @@ static void get_openreq4(struct sock *sk seq_printf(f, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %u %d %p%n", i, - ireq->loc_addr, + nx_map_sock_lback(current_nx_info(), ireq->loc_addr), ntohs(inet_sk(sk)->sport), - ireq->rmt_addr, + nx_map_sock_lback(current_nx_info(), ireq->rmt_addr), ntohs(ireq->rmt_port), TCP_SYN_RECV, 0, 0, /* could print option size, but that is af dependent. */ @@ -2218,7 +2246,10 @@ static void get_tcp4_sock(struct sock *s seq_printf(f, "%4d: %08X:%04X %08X:%04X %02X %08X:%08X %02X:%08lX " "%08X %5d %8d %lu %d %p %lu %lu %u %u %d%n", - i, src, srcp, dest, destp, sk->sk_state, + i, + nx_map_sock_lback(current_nx_info(), src), srcp, + nx_map_sock_lback(current_nx_info(), dest), destp, + sk->sk_state, tp->write_seq - tp->snd_una, sk->sk_state == TCP_LISTEN ? sk->sk_ack_backlog : (tp->rcv_nxt - tp->copied_seq), @@ -2254,7 +2285,10 @@ static void get_timewait4_sock(struct in seq_printf(f, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %d %d %p%n", - i, src, srcp, dest, destp, tw->tw_substate, 0, 0, + i, + nx_map_sock_lback(current_nx_info(), src), srcp, + nx_map_sock_lback(current_nx_info(), dest), destp, + tw->tw_substate, 0, 0, 3, jiffies_to_clock_t(ttd), 0, 0, 0, 0, atomic_read(&tw->tw_refcnt), tw, len); } diff -NurpP --minimal linux-2.6.27.15/net/ipv4/tcp_minisocks.c linux-2.6.27.15-g-v/net/ipv4/tcp_minisocks.c --- linux-2.6.27.15/net/ipv4/tcp_minisocks.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/tcp_minisocks.c 2009-02-10 20:32:17.000000000 +0100 @@ -26,6 +26,10 @@ #include #include +#include +#include +#include + #ifdef CONFIG_SYSCTL #define SYNC_INIT 0 /* let the user enable it */ #else @@ -293,6 +297,11 @@ void tcp_time_wait(struct sock *sk, int tcptw->tw_ts_recent = tp->rx_opt.ts_recent; tcptw->tw_ts_recent_stamp = tp->rx_opt.ts_recent_stamp; + tw->tw_xid = sk->sk_xid; + tw->tw_vx_info = NULL; + tw->tw_nid = sk->sk_nid; + tw->tw_nx_info = NULL; + #if defined(CONFIG_IPV6) || defined(CONFIG_IPV6_MODULE) if (tw->tw_family == PF_INET6) { struct ipv6_pinfo *np = inet6_sk(sk); diff -NurpP --minimal linux-2.6.27.15/net/ipv4/udp.c linux-2.6.27.15-g-v/net/ipv4/udp.c --- linux-2.6.27.15/net/ipv4/udp.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv4/udp.c 2009-02-10 20:32:17.000000000 +0100 @@ -97,6 +97,7 @@ #include #include #include +#include #include #include #include @@ -104,6 +105,11 @@ #include #include "udp_impl.h" +extern int gr_search_udp_recvmsg(const struct sock *sk, + const struct sk_buff *skb); +extern int gr_search_udp_sendmsg(const struct sock *sk, + const struct sockaddr_in *addr); + /* * Snmp MIB for the UDP layer */ @@ -234,20 +240,14 @@ fail: return error; } -static int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2) -{ - struct inet_sock *inet1 = inet_sk(sk1), *inet2 = inet_sk(sk2); - - return ( !ipv6_only_sock(sk2) && - (!inet1->rcv_saddr || !inet2->rcv_saddr || - inet1->rcv_saddr == inet2->rcv_saddr )); -} +extern int ipv4_rcv_saddr_equal(const struct sock *, const struct sock *); int udp_v4_get_port(struct sock *sk, unsigned short snum) { return udp_lib_get_port(sk, snum, ipv4_rcv_saddr_equal); } + /* UDP is nearly always wildcards out the wazoo, it makes no sense to try * harder than this. -DaveM */ @@ -267,10 +267,16 @@ static struct sock *__udp4_lib_lookup(st if (net_eq(sock_net(sk), net) && sk->sk_hash == hnum && !ipv6_only_sock(sk)) { int score = (sk->sk_family == PF_INET ? 1 : 0); + if (inet->rcv_saddr) { if (inet->rcv_saddr != daddr) continue; score+=2; + } else { + /* block non nx_info ips */ + if (!v4_addr_in_nx_info(sk->sk_nx_info, + daddr, NXA_MASK_BIND)) + continue; } if (inet->daddr) { if (inet->daddr != saddr) @@ -296,12 +302,20 @@ static struct sock *__udp4_lib_lookup(st } } } + if (result) sock_hold(result); read_unlock(&udp_hash_lock); return result; } +struct sock *udp_v4_lookup(struct net *net, __be32 saddr, __be16 sport, + __be32 daddr, __be16 dport, int dif) +{ + return __udp4_lib_lookup(net, saddr, sport, daddr, dport, dif, udp_hash); +} + + static inline struct sock *udp_v4_mcast_next(struct net *net, struct sock *sk, __be16 loc_port, __be32 loc_addr, __be16 rmt_port, __be32 rmt_addr, @@ -318,7 +332,7 @@ static inline struct sock *udp_v4_mcast_ s->sk_hash != hnum || (inet->daddr && inet->daddr != rmt_addr) || (inet->dport != rmt_port && inet->dport) || - (inet->rcv_saddr && inet->rcv_saddr != loc_addr) || + !v4_sock_addr_match(sk->sk_nx_info, inet, loc_addr) || ipv6_only_sock(s) || (s->sk_bound_dev_if && s->sk_bound_dev_if != dif)) continue; @@ -592,9 +606,16 @@ int udp_sendmsg(struct kiocb *iocb, stru dport = usin->sin_port; if (dport == 0) return -EINVAL; + + if (!gr_search_udp_sendmsg(sk, usin)) + return -EPERM; } else { if (sk->sk_state != TCP_ESTABLISHED) return -EDESTADDRREQ; + + if (!gr_search_udp_sendmsg(sk, NULL)) + return -EPERM; + daddr = inet->daddr; dport = inet->dport; /* Open fast path for connected socket. @@ -655,8 +676,13 @@ int udp_sendmsg(struct kiocb *iocb, stru { .sport = inet->sport, .dport = dport } } }; struct net *net = sock_net(sk); + struct nx_info *nxi = sk->sk_nx_info; security_sk_classify_flow(sk, &fl); + err = ip_v4_find_src(net, nxi, &rt, &fl); + if (err) + goto out; + err = ip_route_output_flow(net, &rt, &fl, sk, 1); if (err) { if (err == -ENETUNREACH) @@ -859,6 +885,11 @@ try_again: if (!skb) goto out; + if (!gr_search_udp_recvmsg(sk, skb)) { + err = -EPERM; + goto out_free; + } + ulen = skb->len - sizeof(struct udphdr); copied = len; if (copied > ulen) @@ -901,7 +932,8 @@ try_again: { sin->sin_family = AF_INET; sin->sin_port = udp_hdr(skb)->source; - sin->sin_addr.s_addr = ip_hdr(skb)->saddr; + sin->sin_addr.s_addr = nx_map_sock_lback( + skb->sk->sk_nx_info, ip_hdr(skb)->saddr); memset(sin->sin_zero, 0, sizeof(sin->sin_zero)); } if (inet->cmsg_flags) @@ -1530,6 +1562,8 @@ static struct sock *udp_get_first(struct sk_for_each(sk, node, state->hashtable + state->bucket) { if (!net_eq(sock_net(sk), net)) continue; + if (!nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (sk->sk_family == state->family) goto found; } @@ -1548,7 +1582,9 @@ static struct sock *udp_get_next(struct sk = sk_next(sk); try_again: ; - } while (sk && (!net_eq(sock_net(sk), net) || sk->sk_family != state->family)); + } while (sk && (!net_eq(sock_net(sk), net) || + sk->sk_family != state->family || + !nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT))); if (!sk && ++state->bucket < UDP_HTABLE_SIZE) { sk = sk_head(state->hashtable + state->bucket); @@ -1649,7 +1685,10 @@ static void udp4_format_sock(struct sock seq_printf(f, "%4d: %08X:%04X %08X:%04X" " %02X %08X:%08X %02X:%08lX %08X %5d %8d %lu %d %p %d%n", - bucket, src, srcp, dest, destp, sp->sk_state, + bucket, + nx_map_sock_lback(current_nx_info(), src), srcp, + nx_map_sock_lback(current_nx_info(), dest), destp, + sp->sk_state, atomic_read(&sp->sk_wmem_alloc), atomic_read(&sp->sk_rmem_alloc), 0, 0L, 0, sock_i_uid(sp), 0, sock_i_ino(sp), diff -NurpP --minimal linux-2.6.27.15/net/ipv6/addrconf.c linux-2.6.27.15-g-v/net/ipv6/addrconf.c --- linux-2.6.27.15/net/ipv6/addrconf.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/addrconf.c 2009-02-10 20:32:17.000000000 +0100 @@ -85,6 +85,8 @@ #include #include +#include +#include /* Set to 3 to get tracing... */ #define ACONF_DEBUG 2 @@ -1108,7 +1110,7 @@ out: int ipv6_dev_get_saddr(struct net *net, struct net_device *dst_dev, const struct in6_addr *daddr, unsigned int prefs, - struct in6_addr *saddr) + struct in6_addr *saddr, struct nx_info *nxi) { struct ipv6_saddr_score scores[2], *score = &scores[0], *hiscore = &scores[1]; @@ -1181,6 +1183,8 @@ int ipv6_dev_get_saddr(struct net *net, dev->name); continue; } + if (!v6_addr_in_nx_info(nxi, &score->ifa->addr, -1)) + continue; score->rule = -1; bitmap_zero(score->scorebits, IPV6_SADDR_RULE_MAX); @@ -1364,35 +1368,46 @@ struct inet6_ifaddr *ipv6_get_ifaddr(str return ifp; } +extern int ipv4_rcv_saddr_equal(const struct sock *sk1, const struct sock *sk2); + int ipv6_rcv_saddr_equal(const struct sock *sk, const struct sock *sk2) { const struct in6_addr *sk_rcv_saddr6 = &inet6_sk(sk)->rcv_saddr; const struct in6_addr *sk2_rcv_saddr6 = inet6_rcv_saddr(sk2); - __be32 sk_rcv_saddr = inet_sk(sk)->rcv_saddr; __be32 sk2_rcv_saddr = inet_rcv_saddr(sk2); int sk_ipv6only = ipv6_only_sock(sk); int sk2_ipv6only = inet_v6_ipv6only(sk2); int addr_type = ipv6_addr_type(sk_rcv_saddr6); int addr_type2 = sk2_rcv_saddr6 ? ipv6_addr_type(sk2_rcv_saddr6) : IPV6_ADDR_MAPPED; - if (!sk2_rcv_saddr && !sk_ipv6only) + /* FIXME: needs handling for v4 ANY */ + if (!sk2_rcv_saddr && !sk_ipv6only && !sk2->sk_nx_info) return 1; if (addr_type2 == IPV6_ADDR_ANY && - !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED)) + !(sk2_ipv6only && addr_type == IPV6_ADDR_MAPPED) && + v6_addr_in_nx_info(sk2->sk_nx_info, sk_rcv_saddr6, -1)) return 1; if (addr_type == IPV6_ADDR_ANY && - !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED)) + !(sk_ipv6only && addr_type2 == IPV6_ADDR_MAPPED) && + (sk2_rcv_saddr6 && v6_addr_in_nx_info(sk->sk_nx_info, sk2_rcv_saddr6, -1))) + return 1; + + if (addr_type == IPV6_ADDR_ANY && + addr_type2 == IPV6_ADDR_ANY && + nx_v6_addr_conflict(sk->sk_nx_info, sk2->sk_nx_info)) return 1; if (sk2_rcv_saddr6 && + addr_type != IPV6_ADDR_ANY && + addr_type != IPV6_ADDR_ANY && ipv6_addr_equal(sk_rcv_saddr6, sk2_rcv_saddr6)) return 1; if (addr_type == IPV6_ADDR_MAPPED && !sk2_ipv6only && - (!sk2_rcv_saddr || !sk_rcv_saddr || sk_rcv_saddr == sk2_rcv_saddr)) + ipv4_rcv_saddr_equal(sk, sk2)) return 1; return 0; @@ -2986,7 +3001,10 @@ static void if6_seq_stop(struct seq_file static int if6_seq_show(struct seq_file *seq, void *v) { struct inet6_ifaddr *ifp = (struct inet6_ifaddr *)v; - seq_printf(seq, + + if (nx_check(0, VS_ADMIN|VS_WATCH) || + v6_addr_in_nx_info(current_nx_info(), &ifp->addr, -1)) + seq_printf(seq, NIP6_SEQFMT " %02x %02x %02x %02x %8s\n", NIP6(ifp->addr), ifp->idev->dev->ifindex, @@ -3481,6 +3499,12 @@ static int inet6_dump_addr(struct sk_buf struct ifmcaddr6 *ifmca; struct ifacaddr6 *ifaca; struct net *net = sock_net(skb->sk); + struct nx_info *nxi = skb->sk ? skb->sk->sk_nx_info : NULL; + + /* disable ipv6 on non v6 guests */ + if (nxi && !nx_info_has_v6(nxi)) + return skb->len; + s_idx = cb->args[0]; s_ip_idx = ip_idx = cb->args[1]; @@ -3502,6 +3526,8 @@ static int inet6_dump_addr(struct sk_buf ifa = ifa->if_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (!v6_addr_in_nx_info(nxi, &ifa->addr, -1)) + continue; err = inet6_fill_ifaddr(skb, ifa, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, @@ -3515,6 +3541,8 @@ static int inet6_dump_addr(struct sk_buf ifmca = ifmca->next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (!v6_addr_in_nx_info(nxi, &ifmca->mca_addr, -1)) + continue; err = inet6_fill_ifmcaddr(skb, ifmca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, @@ -3528,6 +3556,8 @@ static int inet6_dump_addr(struct sk_buf ifaca = ifaca->aca_next, ip_idx++) { if (ip_idx < s_ip_idx) continue; + if (!v6_addr_in_nx_info(nxi, &ifaca->aca_addr, -1)) + continue; err = inet6_fill_ifacaddr(skb, ifaca, NETLINK_CB(cb->skb).pid, cb->nlh->nlmsg_seq, @@ -3813,12 +3843,19 @@ static int inet6_dump_ifinfo(struct sk_b int s_idx = cb->args[0]; struct net_device *dev; struct inet6_dev *idev; + struct nx_info *nxi = skb->sk ? skb->sk->sk_nx_info : NULL; + + /* FIXME: maybe disable ipv6 on non v6 guests? + if (skb->sk && skb->sk->sk_vx_info) + return skb->len; */ read_lock(&dev_base_lock); idx = 0; for_each_netdev(net, dev) { if (idx < s_idx) goto cont; + if (!v6_dev_in_nx_info(dev, nxi)) + goto cont; if ((idev = in6_dev_get(dev)) == NULL) goto cont; err = inet6_fill_ifinfo(skb, idev, NETLINK_CB(cb->skb).pid, diff -NurpP --minimal linux-2.6.27.15/net/ipv6/af_inet6.c linux-2.6.27.15-g-v/net/ipv6/af_inet6.c --- linux-2.6.27.15/net/ipv6/af_inet6.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/af_inet6.c 2009-02-10 20:32:17.000000000 +0100 @@ -41,6 +41,8 @@ #include #include #include +#include +#include #include #include @@ -49,6 +51,7 @@ #include #include #include +#include #include #include #include @@ -141,9 +144,12 @@ lookup_protocol: } err = -EPERM; + if ((protocol == IPPROTO_ICMPV6) && + nx_capable(answer->capability, NXC_RAW_ICMP)) + goto override; if (answer->capability > 0 && !capable(answer->capability)) goto out_rcu_unlock; - +override: sock->ops = answer->ops; answer_prot = answer->prot; answer_no_check = answer->no_check; @@ -242,6 +248,7 @@ int inet6_bind(struct socket *sock, stru struct inet_sock *inet = inet_sk(sk); struct ipv6_pinfo *np = inet6_sk(sk); struct net *net = sock_net(sk); + struct nx_v6_sock_addr nsa; __be32 v4addr = 0; unsigned short snum; int addr_type = 0; @@ -253,6 +260,11 @@ int inet6_bind(struct socket *sock, stru if (addr_len < SIN6_LEN_RFC2133) return -EINVAL; + + err = v6_map_sock_addr(inet, addr, &nsa); + if (err) + return err; + addr_type = ipv6_addr_type(&addr->sin6_addr); if ((addr_type & IPV6_ADDR_MULTICAST) && sock->type == SOCK_STREAM) return -EINVAL; @@ -276,6 +288,10 @@ int inet6_bind(struct socket *sock, stru err = -EADDRNOTAVAIL; goto out; } + if (!v4_addr_in_nx_info(sk->sk_nx_info, v4addr, NXA_MASK_BIND)) { + err = -EADDRNOTAVAIL; + goto out; + } } else { if (addr_type != IPV6_ADDR_ANY) { struct net_device *dev = NULL; @@ -301,6 +317,11 @@ int inet6_bind(struct socket *sock, stru } } + if (!v6_addr_in_nx_info(sk->sk_nx_info, &addr->sin6_addr, -1)) { + err = -EADDRNOTAVAIL; + goto out; + } + /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. */ @@ -319,6 +340,8 @@ int inet6_bind(struct socket *sock, stru } } + v6_set_sock_addr(inet, &nsa); + inet->rcv_saddr = v4addr; inet->saddr = v4addr; @@ -411,9 +434,11 @@ int inet6_getname(struct socket *sock, s return -ENOTCONN; sin->sin6_port = inet->dport; ipv6_addr_copy(&sin->sin6_addr, &np->daddr); + /* FIXME: remap lback? */ if (np->sndflow) sin->sin6_flowinfo = np->flow_label; } else { + /* FIXME: remap lback? */ if (ipv6_addr_any(&np->rcv_saddr)) ipv6_addr_copy(&sin->sin6_addr, &np->saddr); else diff -NurpP --minimal linux-2.6.27.15/net/ipv6/exthdrs.c linux-2.6.27.15-g-v/net/ipv6/exthdrs.c --- linux-2.6.27.15/net/ipv6/exthdrs.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/exthdrs.c 2009-02-10 20:32:17.000000000 +0100 @@ -624,7 +624,7 @@ static struct tlvtype_proc tlvprochopopt .type = IPV6_TLV_JUMBO, .func = ipv6_hop_jumbo, }, - { -1, } + { -1, NULL } }; int ipv6_parse_hopopts(struct sk_buff *skb) diff -NurpP --minimal linux-2.6.27.15/net/ipv6/fib6_rules.c linux-2.6.27.15-g-v/net/ipv6/fib6_rules.c --- linux-2.6.27.15/net/ipv6/fib6_rules.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/fib6_rules.c 2009-02-10 20:32:17.000000000 +0100 @@ -96,7 +96,7 @@ static int fib6_rule_action(struct fib_r if (ipv6_dev_get_saddr(net, ip6_dst_idev(&rt->u.dst)->dev, &flp->fl6_dst, srcprefs, - &saddr)) + &saddr, NULL)) goto again; if (!ipv6_prefix_equal(&saddr, &r->src.addr, r->src.plen)) diff -NurpP --minimal linux-2.6.27.15/net/ipv6/inet6_hashtables.c linux-2.6.27.15-g-v/net/ipv6/inet6_hashtables.c --- linux-2.6.27.15/net/ipv6/inet6_hashtables.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/inet6_hashtables.c 2009-02-10 20:32:17.000000000 +0100 @@ -16,6 +16,7 @@ #include #include +#include #include #include @@ -115,6 +116,9 @@ struct sock *inet6_lookup_listener(struc if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) continue; score++; + } else { + if (!v6_addr_in_nx_info(sk->sk_nx_info, daddr, -1)) + continue; } if (sk->sk_bound_dev_if) { if (sk->sk_bound_dev_if != dif) diff -NurpP --minimal linux-2.6.27.15/net/ipv6/ip6_output.c linux-2.6.27.15-g-v/net/ipv6/ip6_output.c --- linux-2.6.27.15/net/ipv6/ip6_output.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/ip6_output.c 2009-02-10 20:32:17.000000000 +0100 @@ -937,7 +937,7 @@ static int ip6_dst_lookup_tail(struct so err = ipv6_dev_get_saddr(net, ip6_dst_idev(*dst)->dev, &fl->fl6_dst, sk ? inet6_sk(sk)->srcprefs : 0, - &fl->fl6_src); + &fl->fl6_src, sk->sk_nx_info); if (err) goto out_err_release; } diff -NurpP --minimal linux-2.6.27.15/net/ipv6/Kconfig linux-2.6.27.15-g-v/net/ipv6/Kconfig --- linux-2.6.27.15/net/ipv6/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/Kconfig 2009-02-10 20:32:17.000000000 +0100 @@ -4,8 +4,8 @@ # IPv6 as module will cause a CRASH if you try to unload it menuconfig IPV6 - tristate "The IPv6 protocol" - default m + bool "The IPv6 protocol" + default n ---help--- This is complemental support for the IP version 6. You will still be able to do traditional IPv4 networking as well. diff -NurpP --minimal linux-2.6.27.15/net/ipv6/ndisc.c linux-2.6.27.15-g-v/net/ipv6/ndisc.c --- linux-2.6.27.15/net/ipv6/ndisc.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/ndisc.c 2009-02-10 20:32:17.000000000 +0100 @@ -551,7 +551,7 @@ static void ndisc_send_na(struct net_dev } else { if (ipv6_dev_get_saddr(dev_net(dev), dev, daddr, inet6_sk(dev_net(dev)->ipv6.ndisc_sk)->srcprefs, - &tmpaddr)) + &tmpaddr, NULL /* FIXME: ? */ )) return; src_addr = &tmpaddr; } diff -NurpP --minimal linux-2.6.27.15/net/ipv6/raw.c linux-2.6.27.15-g-v/net/ipv6/raw.c --- linux-2.6.27.15/net/ipv6/raw.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/raw.c 2009-02-10 20:32:17.000000000 +0100 @@ -29,6 +29,7 @@ #include #include #include +#include #include #include #include @@ -281,6 +282,13 @@ static int rawv6_bind(struct sock *sk, s } } + if (!v6_addr_in_nx_info(sk->sk_nx_info, &addr->sin6_addr, -1)) { + err = -EADDRNOTAVAIL; + if (dev) + dev_put(dev); + goto out; + } + /* ipv4 addr of the socket is invalid. Only the * unspecified and mapped address have a v4 equivalent. */ @@ -600,7 +608,7 @@ out: return err; } -static int rawv6_send_hdrinc(struct sock *sk, void *from, int length, +static int rawv6_send_hdrinc(struct sock *sk, void *from, unsigned int length, struct flowi *fl, struct rt6_info *rt, unsigned int flags) { diff -NurpP --minimal linux-2.6.27.15/net/ipv6/route.c linux-2.6.27.15-g-v/net/ipv6/route.c --- linux-2.6.27.15/net/ipv6/route.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/route.c 2009-02-10 20:32:17.000000000 +0100 @@ -2191,7 +2191,8 @@ static int rt6_fill_node(struct net *net struct inet6_dev *idev = ip6_dst_idev(&rt->u.dst); struct in6_addr saddr_buf; if (ipv6_dev_get_saddr(net, idev ? idev->dev : NULL, - dst, 0, &saddr_buf) == 0) + dst, 0, &saddr_buf, + (skb->sk ? skb->sk->sk_nx_info : NULL)) == 0) NLA_PUT(skb, RTA_PREFSRC, 16, &saddr_buf); } diff -NurpP --minimal linux-2.6.27.15/net/ipv6/tcp_ipv6.c linux-2.6.27.15-g-v/net/ipv6/tcp_ipv6.c --- linux-2.6.27.15/net/ipv6/tcp_ipv6.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/tcp_ipv6.c 2009-02-10 20:32:17.000000000 +0100 @@ -67,6 +67,7 @@ #include #include +#include static void tcp_v6_send_reset(struct sock *sk, struct sk_buff *skb); static void tcp_v6_reqsk_send_ack(struct sock *sk, struct sk_buff *skb, @@ -155,8 +156,15 @@ static int tcp_v6_connect(struct sock *s * connect() to INADDR_ANY means loopback (BSD'ism). */ - if(ipv6_addr_any(&usin->sin6_addr)) - usin->sin6_addr.s6_addr[15] = 0x1; + if(ipv6_addr_any(&usin->sin6_addr)) { + struct nx_info *nxi = sk->sk_nx_info; + + if (nxi && nx_info_has_v6(nxi)) + /* FIXME: remap lback? */ + usin->sin6_addr = nxi->v6.ip; + else + usin->sin6_addr.s6_addr[15] = 0x1; + } addr_type = ipv6_addr_type(&usin->sin6_addr); diff -NurpP --minimal linux-2.6.27.15/net/ipv6/udp.c linux-2.6.27.15-g-v/net/ipv6/udp.c --- linux-2.6.27.15/net/ipv6/udp.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/udp.c 2009-02-10 20:32:17.000000000 +0100 @@ -47,6 +47,7 @@ #include #include +#include #include "udp_impl.h" int udp_v6_get_port(struct sock *sk, unsigned short snum) @@ -81,6 +82,10 @@ static struct sock *__udp6_lib_lookup(st if (!ipv6_addr_equal(&np->rcv_saddr, daddr)) continue; score++; + } else { + /* block non nx_info ips */ + if (!v6_addr_in_nx_info(sk->sk_nx_info, daddr, -1)) + continue; } if (!ipv6_addr_any(&np->daddr)) { if (!ipv6_addr_equal(&np->daddr, saddr)) diff -NurpP --minimal linux-2.6.27.15/net/ipv6/xfrm6_policy.c linux-2.6.27.15-g-v/net/ipv6/xfrm6_policy.c --- linux-2.6.27.15/net/ipv6/xfrm6_policy.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/ipv6/xfrm6_policy.c 2009-02-10 20:32:17.000000000 +0100 @@ -61,7 +61,7 @@ static int xfrm6_get_saddr(xfrm_address_ dev = ip6_dst_idev(dst)->dev; ipv6_dev_get_saddr(dev_net(dev), dev, (struct in6_addr *)&daddr->a6, 0, - (struct in6_addr *)&saddr->a6); + (struct in6_addr *)&saddr->a6, NULL); dst_release(dst); return 0; } diff -NurpP --minimal linux-2.6.27.15/net/irda/ircomm/ircomm_tty.c linux-2.6.27.15-g-v/net/irda/ircomm/ircomm_tty.c --- linux-2.6.27.15/net/irda/ircomm/ircomm_tty.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/irda/ircomm/ircomm_tty.c 2009-02-10 20:32:17.000000000 +0100 @@ -371,7 +371,7 @@ static int ircomm_tty_open(struct tty_st IRDA_DEBUG(2, "%s()\n", __func__ ); line = tty->index; - if ((line < 0) || (line >= IRCOMM_TTY_PORTS)) { + if (line >= IRCOMM_TTY_PORTS) { return -ENODEV; } diff -NurpP --minimal linux-2.6.27.15/net/Kconfig linux-2.6.27.15-g-v/net/Kconfig --- linux-2.6.27.15/net/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/Kconfig 2009-02-10 20:32:18.000000000 +0100 @@ -27,7 +27,7 @@ menu "Networking options" config NET_NS bool "Network namespace support" default n - depends on EXPERIMENTAL && !SYSFS && NAMESPACES + depends on EXPERIMENTAL && NAMESPACES help Allow user space to create what appear to be multiple instances of the network stack. diff -NurpP --minimal linux-2.6.27.15/net/netlink/af_netlink.c linux-2.6.27.15-g-v/net/netlink/af_netlink.c --- linux-2.6.27.15/net/netlink/af_netlink.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/netlink/af_netlink.c 2009-02-10 20:32:18.000000000 +0100 @@ -55,6 +55,9 @@ #include #include #include +#include +#include +#include #include #include @@ -1761,6 +1764,8 @@ static struct sock *netlink_seq_socket_i sk_for_each(s, node, &hash->table[j]) { if (sock_net(s) != seq_file_net(seq)) continue; + if (!nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (off == pos) { iter->link = i; iter->hash_idx = j; @@ -1795,7 +1800,8 @@ static void *netlink_seq_next(struct seq s = v; do { s = sk_next(s); - } while (s && sock_net(s) != seq_file_net(seq)); + } while (s && (sock_net(s) != seq_file_net(seq) || + !nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT))); if (s) return s; @@ -1807,7 +1813,8 @@ static void *netlink_seq_next(struct seq for (; j <= hash->mask; j++) { s = sk_head(&hash->table[j]); - while (s && sock_net(s) != seq_file_net(seq)) + while (s && (sock_net(s) != seq_file_net(seq) || + !nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT))) s = sk_next(s); if (s) { iter->link = i; diff -NurpP --minimal linux-2.6.27.15/net/sctp/ipv6.c linux-2.6.27.15-g-v/net/sctp/ipv6.c --- linux-2.6.27.15/net/sctp/ipv6.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/sctp/ipv6.c 2009-02-10 20:32:18.000000000 +0100 @@ -323,7 +323,8 @@ static void sctp_v6_get_saddr(struct sct dst ? ip6_dst_idev(dst)->dev : NULL, &daddr->v6.sin6_addr, inet6_sk(&sk->inet.sk)->srcprefs, - &saddr->v6.sin6_addr); + &saddr->v6.sin6_addr, + asoc->base.sk->sk_nx_info); SCTP_DEBUG_PRINTK("saddr from ipv6_get_saddr: " NIP6_FMT "\n", NIP6(saddr->v6.sin6_addr)); return; diff -NurpP --minimal linux-2.6.27.15/net/sctp/socket.c linux-2.6.27.15-g-v/net/sctp/socket.c --- linux-2.6.27.15/net/sctp/socket.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/sctp/socket.c 2009-02-10 20:32:18.000000000 +0100 @@ -1434,7 +1434,7 @@ SCTP_STATIC int sctp_sendmsg(struct kioc struct sctp_sndrcvinfo *sinfo; struct sctp_initmsg *sinit; sctp_assoc_t associd = 0; - sctp_cmsgs_t cmsgs = { NULL }; + sctp_cmsgs_t cmsgs = { NULL, NULL }; int err; sctp_scope_t scope; long timeo; @@ -5616,7 +5616,6 @@ pp_found: */ int reuse = sk->sk_reuse; struct sock *sk2; - struct hlist_node *node; SCTP_DEBUG_PRINTK("sctp_get_port() found a possible match\n"); if (pp->fastreuse && sk->sk_reuse && diff -NurpP --minimal linux-2.6.27.15/net/socket.c linux-2.6.27.15-g-v/net/socket.c --- linux-2.6.27.15/net/socket.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/socket.c 2009-02-10 20:32:18.000000000 +0100 @@ -87,6 +87,7 @@ #include #include #include +#include #include #include @@ -96,6 +97,25 @@ #include #include +#include +#include +#include +#include + +extern void gr_attach_curr_ip(const struct sock *sk); +extern int gr_handle_sock_all(const int family, const int type, + const int protocol); +extern int gr_handle_sock_server(const struct sockaddr *sck); +extern int gr_handle_sock_server_other(const struct socket *sck); +extern int gr_handle_sock_client(const struct sockaddr *sck); +extern int gr_search_connect(const struct socket * sock, + const struct sockaddr_in * addr); +extern int gr_search_bind(const struct socket * sock, + const struct sockaddr_in * addr); +extern int gr_search_listen(const struct socket * sock); +extern int gr_search_accept(const struct socket * sock); +extern int gr_search_socket(const int domain, const int type, + const int protocol); static int sock_no_open(struct inode *irrelevant, struct file *dontcare); static ssize_t sock_aio_read(struct kiocb *iocb, const struct iovec *iov, @@ -300,7 +320,7 @@ static int sockfs_get_sb(struct file_sys mnt); } -static struct vfsmount *sock_mnt __read_mostly; +struct vfsmount *sock_mnt __read_mostly; static struct file_system_type sock_fs_type = { .name = "sockfs", @@ -550,7 +570,7 @@ static inline int __sock_sendmsg(struct struct msghdr *msg, size_t size) { struct sock_iocb *si = kiocb_to_siocb(iocb); - int err; + int err, len; si->sock = sock; si->scm = NULL; @@ -561,7 +581,22 @@ static inline int __sock_sendmsg(struct if (err) return err; - return sock->ops->sendmsg(iocb, sock, msg, size); + len = sock->ops->sendmsg(iocb, sock, msg, size); + if (sock->sk) { + if (len == size) + vx_sock_send(sock->sk, size); + else + vx_sock_fail(sock->sk, size); + } + vxdprintk(VXD_CBIT(net, 7), + "__sock_sendmsg: %p[%p,%p,%p;%d/%d]:%d/%d", + sock, sock->sk, + (sock->sk)?sock->sk->sk_nx_info:0, + (sock->sk)?sock->sk->sk_vx_info:0, + (sock->sk)?sock->sk->sk_xid:0, + (sock->sk)?sock->sk->sk_nid:0, + (unsigned int)size, len); + return len; } int sock_sendmsg(struct socket *sock, struct msghdr *msg, size_t size) @@ -630,7 +665,7 @@ EXPORT_SYMBOL_GPL(__sock_recv_timestamp) static inline int __sock_recvmsg(struct kiocb *iocb, struct socket *sock, struct msghdr *msg, size_t size, int flags) { - int err; + int err, len; struct sock_iocb *si = kiocb_to_siocb(iocb); si->sock = sock; @@ -643,7 +678,18 @@ static inline int __sock_recvmsg(struct if (err) return err; - return sock->ops->recvmsg(iocb, sock, msg, size, flags); + len = sock->ops->recvmsg(iocb, sock, msg, size, flags); + if ((len >= 0) && sock->sk) + vx_sock_recv(sock->sk, len); + vxdprintk(VXD_CBIT(net, 7), + "__sock_recvmsg: %p[%p,%p,%p;%d/%d]:%d/%d", + sock, sock->sk, + (sock->sk)?sock->sk->sk_nx_info:0, + (sock->sk)?sock->sk->sk_vx_info:0, + (sock->sk)?sock->sk->sk_xid:0, + (sock->sk)?sock->sk->sk_nid:0, + (unsigned int)size, len); + return len; } int sock_recvmsg(struct socket *sock, struct msghdr *msg, @@ -1108,6 +1154,13 @@ static int __sock_create(struct net *net if (type < 0 || type >= SOCK_MAX) return -EINVAL; + if (!nx_check(0, VS_ADMIN)) { + if (family == PF_INET && !current_nx_info_has_v4()) + return -EAFNOSUPPORT; + if (family == PF_INET6 && !current_nx_info_has_v6()) + return -EAFNOSUPPORT; + } + /* Compatibility. This uglymoron is moved from INET layer to here to avoid @@ -1236,10 +1289,21 @@ SYSCALL_DEFINE3(socket, int, family, int if (SOCK_NONBLOCK != O_NONBLOCK && (flags & SOCK_NONBLOCK)) flags = (flags & ~SOCK_NONBLOCK) | O_NONBLOCK; + if(!gr_search_socket(family, type, protocol)) { + retval = -EACCES; + goto out; + } + + if (gr_handle_sock_all(family, type, protocol)) { + retval = -EACCES; + goto out; + } + retval = sock_create(family, type, protocol, &sock); if (retval < 0) goto out; + set_bit(SOCK_USER_SOCKET, &sock->flags); retval = sock_map_fd(sock, flags & (O_CLOEXEC | O_NONBLOCK)); if (retval < 0) goto out_release; @@ -1281,10 +1345,12 @@ SYSCALL_DEFINE4(socketpair, int, family, err = sock_create(family, type, protocol, &sock1); if (err < 0) goto out; + set_bit(SOCK_USER_SOCKET, &sock1->flags); err = sock_create(family, type, protocol, &sock2); if (err < 0) goto out_release_1; + set_bit(SOCK_USER_SOCKET, &sock2->flags); err = sock1->ops->socketpair(sock1, sock2); if (err < 0) @@ -1375,6 +1441,12 @@ SYSCALL_DEFINE3(bind, int, fd, struct so if (sock) { err = move_addr_to_kernel(umyaddr, addrlen, (struct sockaddr *)&address); if (err >= 0) { + if (!gr_search_bind(sock, (struct sockaddr_in *)&address) || + gr_handle_sock_server((struct sockaddr *)&address)) { + err = -EACCES; + goto error; + } + err = security_socket_bind(sock, (struct sockaddr *)&address, addrlen); @@ -1383,6 +1455,7 @@ SYSCALL_DEFINE3(bind, int, fd, struct so (struct sockaddr *) &address, addrlen); } +error: fput_light(sock->file, fput_needed); } return err; @@ -1406,10 +1479,17 @@ SYSCALL_DEFINE2(listen, int, fd, int, ba if ((unsigned)backlog > somaxconn) backlog = somaxconn; + if (gr_handle_sock_server_other(sock) || + !gr_search_listen(sock)) { + err = -EPERM; + goto error; + } + err = security_socket_listen(sock, backlog); if (!err) err = sock->ops->listen(sock, backlog); +error: fput_light(sock->file, fput_needed); } return err; @@ -1452,6 +1532,13 @@ long do_accept(int fd, struct sockaddr _ newsock->type = sock->type; newsock->ops = sock->ops; + if (gr_handle_sock_server_other(sock) || + !gr_search_accept(sock)) { + err = -EPERM; + sock_release(newsock); + goto out_put; + } + /* * We don't need try_module_get here, as the listening socket (sock) * has the protocol module (sock->ops->owner) held. @@ -1495,6 +1582,7 @@ long do_accept(int fd, struct sockaddr _ err = newfd; security_socket_post_accept(sock, newsock); + gr_attach_curr_ip(newsock->sk); out_put: fput_light(sock->file, fput_needed); @@ -1589,6 +1677,7 @@ SYSCALL_DEFINE3(connect, int, fd, struct int, addrlen) { struct socket *sock; + struct sockaddr *sck; struct sockaddr_storage address; int err, fput_needed; @@ -1599,6 +1688,13 @@ SYSCALL_DEFINE3(connect, int, fd, struct if (err < 0) goto out_put; + sck = (struct sockaddr *)&address; + if (!gr_search_connect(sock, (struct sockaddr_in *)sck) || + gr_handle_sock_client(sck)) { + err = -EACCES; + goto out_put; + } + err = security_socket_connect(sock, (struct sockaddr *)&address, addrlen); if (err) @@ -1867,6 +1963,7 @@ SYSCALL_DEFINE2(shutdown, int, fd, int, err = sock->ops->shutdown(sock, how); fput_light(sock->file, fput_needed); } + return err; } diff -NurpP --minimal linux-2.6.27.15/net/sunrpc/auth.c linux-2.6.27.15-g-v/net/sunrpc/auth.c --- linux-2.6.27.15/net/sunrpc/auth.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/sunrpc/auth.c 2009-02-10 20:32:18.000000000 +0100 @@ -14,6 +14,7 @@ #include #include #include +#include #ifdef RPC_DEBUG # define RPCDBG_FACILITY RPCDBG_AUTH @@ -353,6 +354,7 @@ rpcauth_lookupcred(struct rpc_auth *auth struct auth_cred acred = { .uid = current->fsuid, .gid = current->fsgid, + .tag = dx_current_tag(), .group_info = current->group_info, }; struct rpc_cred *ret; @@ -398,6 +400,7 @@ rpcauth_bind_root_cred(struct rpc_task * struct auth_cred acred = { .uid = 0, .gid = 0, + .tag = dx_current_tag(), }; struct rpc_cred *ret; diff -NurpP --minimal linux-2.6.27.15/net/sunrpc/auth_unix.c linux-2.6.27.15-g-v/net/sunrpc/auth_unix.c --- linux-2.6.27.15/net/sunrpc/auth_unix.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/sunrpc/auth_unix.c 2009-02-10 20:32:18.000000000 +0100 @@ -11,12 +11,14 @@ #include #include #include +#include #define NFS_NGROUPS 16 struct unx_cred { struct rpc_cred uc_base; gid_t uc_gid; + tag_t uc_tag; gid_t uc_gids[NFS_NGROUPS]; }; #define uc_uid uc_base.cr_uid @@ -78,6 +80,7 @@ unx_create_cred(struct rpc_auth *auth, s groups = NFS_NGROUPS; cred->uc_gid = acred->gid; + cred->uc_tag = acred->tag; for (i = 0; i < groups; i++) cred->uc_gids[i] = GROUP_AT(acred->group_info, i); if (i < NFS_NGROUPS) @@ -119,7 +122,9 @@ unx_match(struct auth_cred *acred, struc unsigned int i; - if (cred->uc_uid != acred->uid || cred->uc_gid != acred->gid) + if (cred->uc_uid != acred->uid || + cred->uc_gid != acred->gid || + cred->uc_tag != acred->tag) return 0; if (acred->group_info != NULL) @@ -142,7 +147,7 @@ unx_marshal(struct rpc_task *task, __be3 struct rpc_clnt *clnt = task->tk_client; struct unx_cred *cred = container_of(task->tk_msg.rpc_cred, struct unx_cred, uc_base); __be32 *base, *hold; - int i; + int i, tag; *p++ = htonl(RPC_AUTH_UNIX); base = p++; @@ -152,9 +157,12 @@ unx_marshal(struct rpc_task *task, __be3 * Copy the UTS nodename captured when the client was created. */ p = xdr_encode_array(p, clnt->cl_nodename, clnt->cl_nodelen); + tag = task->tk_client->cl_tag; - *p++ = htonl((u32) cred->uc_uid); - *p++ = htonl((u32) cred->uc_gid); + *p++ = htonl((u32) TAGINO_UID(tag, + cred->uc_uid, cred->uc_tag)); + *p++ = htonl((u32) TAGINO_GID(tag, + cred->uc_gid, cred->uc_tag)); hold = p++; for (i = 0; i < 16 && cred->uc_gids[i] != (gid_t) NOGROUP; i++) *p++ = htonl((u32) cred->uc_gids[i]); diff -NurpP --minimal linux-2.6.27.15/net/sunrpc/clnt.c linux-2.6.27.15-g-v/net/sunrpc/clnt.c --- linux-2.6.27.15/net/sunrpc/clnt.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/sunrpc/clnt.c 2009-02-10 20:32:18.000000000 +0100 @@ -32,6 +32,7 @@ #include #include #include +#include #include #include @@ -327,6 +328,9 @@ struct rpc_clnt *rpc_create(struct rpc_c if (!(args->flags & RPC_CLNT_CREATE_QUIET)) clnt->cl_chatty = 1; + /* TODO: handle RPC_CLNT_CREATE_TAGGED + if (args->flags & RPC_CLNT_CREATE_TAGGED) + clnt->cl_tag = 1; */ return clnt; } EXPORT_SYMBOL_GPL(rpc_create); diff -NurpP --minimal linux-2.6.27.15/net/unix/af_unix.c linux-2.6.27.15-g-v/net/unix/af_unix.c --- linux-2.6.27.15/net/unix/af_unix.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/unix/af_unix.c 2009-02-10 20:32:18.000000000 +0100 @@ -114,6 +114,9 @@ #include #include #include +#include +#include +#include static struct hlist_head unix_socket_table[UNIX_HASH_SIZE + 1]; static DEFINE_SPINLOCK(unix_table_lock); @@ -258,6 +261,8 @@ static struct sock *__unix_find_socket_b if (!net_eq(sock_net(s), net)) continue; + if (!nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (u->addr->len == len && !memcmp(u->addr->name, sunname, len)) goto found; @@ -725,6 +730,12 @@ static struct sock *unix_find_other(stru err = -ECONNREFUSED; if (!S_ISSOCK(nd.path.dentry->d_inode->i_mode)) goto put_fail; + + if (!gr_acl_handle_unix(nd.path.dentry, nd.path.mnt)) { + err = -EACCES; + goto put_fail; + } + u = unix_find_socket_byinode(net, nd.path.dentry->d_inode); if (!u) goto put_fail; @@ -745,6 +756,13 @@ static struct sock *unix_find_other(stru if (u) { struct dentry *dentry; dentry = unix_sk(u)->dentry; + + if (!gr_handle_chroot_unix(u->sk_peercred.pid)) { + err = -EPERM; + sock_put(u); + goto fail; + } + if (dentry) touch_atime(unix_sk(u)->mnt, dentry); } else @@ -827,10 +845,20 @@ static int unix_bind(struct socket *sock err = mnt_want_write(nd.path.mnt); if (err) goto out_mknod_dput; + + if (!gr_acl_handle_mknod(dentry, nd.path.dentry, nd.path.mnt, mode)) { + err = -EACCES; + mnt_drop_write(nd.path.mnt); + goto out_mknod_dput; + } + err = vfs_mknod(nd.path.dentry->d_inode, dentry, mode, 0); mnt_drop_write(nd.path.mnt); if (err) goto out_mknod_dput; + + gr_handle_create(dentry, nd.path.mnt); + mutex_unlock(&nd.path.dentry->d_inode->i_mutex); dput(nd.path.dentry); nd.path.dentry = dentry; @@ -848,6 +876,10 @@ static int unix_bind(struct socket *sock goto out_unlock; } +#ifdef CONFIG_GRKERNSEC_CHROOT_UNIX + sk->sk_peercred.pid = current->pid; +#endif + list = &unix_socket_table[addr->hash]; } else { list = &unix_socket_table[dentry->d_inode->i_ino & (UNIX_HASH_SIZE-1)]; @@ -2103,6 +2135,8 @@ static struct sock *unix_seq_idx(struct for (s = first_unix_socket(&iter->i); s; s = next_unix_socket(&iter->i, s)) { if (sock_net(s) != seq_file_net(seq)) continue; + if (!nx_check(s->sk_nid, VS_WATCH_P | VS_IDENT)) + continue; if (off == pos) return s; ++off; @@ -2128,7 +2162,8 @@ static void *unix_seq_next(struct seq_fi sk = first_unix_socket(&iter->i); else sk = next_unix_socket(&iter->i, sk); - while (sk && (sock_net(sk) != seq_file_net(seq))) + while (sk && (sock_net(sk) != seq_file_net(seq) || + !nx_check(sk->sk_nid, VS_WATCH_P | VS_IDENT))) sk = next_unix_socket(&iter->i, sk); return sk; } diff -NurpP --minimal linux-2.6.27.15/net/x25/af_x25.c linux-2.6.27.15-g-v/net/x25/af_x25.c --- linux-2.6.27.15/net/x25/af_x25.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/net/x25/af_x25.c 2009-02-10 20:32:18.000000000 +0100 @@ -506,7 +506,10 @@ static int x25_create(struct net *net, s x25 = x25_sk(sk); - sock_init_data(sock, sk); + sk->sk_socket = sock; + sk->sk_type = sock->type; + sk->sk_sleep = &sock->wait; + sock->sk = sk; x25_init_timers(sk); diff -NurpP --minimal linux-2.6.27.15/scripts/checksyscalls.sh linux-2.6.27.15-g-v/scripts/checksyscalls.sh --- linux-2.6.27.15/scripts/checksyscalls.sh 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/scripts/checksyscalls.sh 2009-02-10 20:32:18.000000000 +0100 @@ -108,7 +108,6 @@ cat << EOF #define __IGNORE_afs_syscall #define __IGNORE_getpmsg #define __IGNORE_putpmsg -#define __IGNORE_vserver EOF } diff -NurpP --minimal linux-2.6.27.15/scripts/pnmtologo.c linux-2.6.27.15-g-v/scripts/pnmtologo.c --- linux-2.6.27.15/scripts/pnmtologo.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/scripts/pnmtologo.c 2009-02-10 20:32:18.000000000 +0100 @@ -237,14 +237,14 @@ static void write_header(void) fprintf(out, " * Linux logo %s\n", logoname); fputs(" */\n\n", out); fputs("#include \n\n", out); - fprintf(out, "static unsigned char %s_data[] __initdata = {\n", + fprintf(out, "static unsigned char %s_data[] = {\n", logoname); } static void write_footer(void) { fputs("\n};\n\n", out); - fprintf(out, "struct linux_logo %s __initdata = {\n", logoname); + fprintf(out, "struct linux_logo %s = {\n", logoname); fprintf(out, " .type\t= %s,\n", logo_types[logo_type]); fprintf(out, " .width\t= %d,\n", logo_width); fprintf(out, " .height\t= %d,\n", logo_height); @@ -374,7 +374,7 @@ static void write_logo_clut224(void) fputs("\n};\n\n", out); /* write logo clut */ - fprintf(out, "static unsigned char %s_clut[] __initdata = {\n", + fprintf(out, "static unsigned char %s_clut[] = {\n", logoname); write_hex_cnt = 0; for (i = 0; i < logo_clutsize; i++) { diff -NurpP --minimal linux-2.6.27.15/security/commoncap.c linux-2.6.27.15-g-v/security/commoncap.c --- linux-2.6.27.15/security/commoncap.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/security/commoncap.c 2009-02-10 20:32:18.000000000 +0100 @@ -26,10 +26,14 @@ #include #include #include +#include +#include + +extern kernel_cap_t gr_cap_rtnetlink(struct sock *sk); int cap_netlink_send(struct sock *sk, struct sk_buff *skb) { - NETLINK_CB(skb).eff_cap = current->cap_effective; + NETLINK_CB(skb).eff_cap = vx_mbcaps(gr_cap_rtnetlink(sk)); return 0; } @@ -50,9 +54,47 @@ EXPORT_SYMBOL(cap_netlink_recv); */ int cap_capable (struct task_struct *tsk, int cap) { + struct vx_info *vxi = tsk->vx_info; + +#if 0 + printk("cap_capable() VXF_STATE_SETUP = %llx, raised = %x, eff = %08x:%08x\n", + vx_info_flags(vxi, VXF_STATE_SETUP, 0), + cap_raised(tsk->cap_effective, cap), + tsk->cap_effective.cap[1], tsk->cap_effective.cap[0]); +#endif + + /* special case SETUP */ + if (vx_info_flags(vxi, VXF_STATE_SETUP, 0) && + cap_raised(tsk->cap_effective, cap)) + return 0; + /* Derived from include/linux/sched.h:capable. */ - if (cap_raised(tsk->cap_effective, cap)) + if (vx_cap_raised(vxi, tsk->cap_effective, cap)) + return 0; + + return -EPERM; +} + +int cap_capable_nolog (struct task_struct *tsk, int cap) +{ + struct vx_info *vxi = tsk->vx_info; + +#if 0 + printk("cap_capable() VXF_STATE_SETUP = %llx, raised = %x, eff = %08x:%08x\n", + vx_info_flags(vxi, VXF_STATE_SETUP, 0), + cap_raised(tsk->cap_effective, cap), + tsk->cap_effective.cap[1], tsk->cap_effective.cap[0]); +#endif + + /* special case SETUP */ + if (vx_info_flags(vxi, VXF_STATE_SETUP, 0) && + cap_raised(tsk->cap_effective, cap) && gr_is_capable_nolog(cap)) + return 0; + + /* Derived from include/linux/sched.h:capable. */ + if (vx_cap_raised(vxi, tsk->cap_effective, cap)) return 0; + return -EPERM; } @@ -379,8 +421,11 @@ void cap_bprm_apply_creds (struct linux_ } } - current->suid = current->euid = current->fsuid = bprm->e_uid; - current->sgid = current->egid = current->fsgid = bprm->e_gid; + if (!gr_check_user_change(-1, bprm->e_uid, bprm->e_uid)) + current->suid = current->euid = current->fsuid = bprm->e_uid; + + if (!gr_check_group_change(-1, bprm->e_gid, bprm->e_gid)) + current->sgid = current->egid = current->fsgid = bprm->e_gid; /* For init, we want to retain the capabilities set * in the init_task struct. Thus we skip the usual @@ -393,6 +438,8 @@ void cap_bprm_apply_creds (struct linux_ cap_clear(current->cap_effective); } + gr_handle_chroot_caps(current); + /* AUD: Audit candidate if current->cap_effective is set */ current->securebits &= ~issecure_mask(SECURE_KEEP_CAPS); @@ -696,7 +743,8 @@ void cap_task_reparent_to_init (struct t int cap_syslog (int type) { - if ((type != 3 && type != 10) && !capable(CAP_SYS_ADMIN)) + if ((type != 3 && type != 10) && + !vx_capable(CAP_SYS_ADMIN, VXC_SYSLOG)) return -EPERM; return 0; } @@ -705,7 +753,7 @@ int cap_vm_enough_memory(struct mm_struc { int cap_sys_admin = 0; - if (cap_capable(current, CAP_SYS_ADMIN) == 0) + if (cap_capable_nolog(current, CAP_SYS_ADMIN) == 0) cap_sys_admin = 1; return __vm_enough_memory(mm, pages, cap_sys_admin); } diff -NurpP --minimal linux-2.6.27.15/security/Kconfig linux-2.6.27.15-g-v/security/Kconfig --- linux-2.6.27.15/security/Kconfig 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/security/Kconfig 2009-02-10 20:32:18.000000000 +0100 @@ -4,6 +4,447 @@ menu "Security options" +source grsecurity/Kconfig + +menu "PaX" + +config PAX + bool "Enable various PaX features" + depends on GRKERNSEC && (ALPHA || ARM || AVR32 || IA64 || MIPS32 || MIPS64 || PARISC || PPC32 || PPC64 || SPARC32 || SPARC64 || X86) + help + This allows you to enable various PaX features. PaX adds + intrusion prevention mechanisms to the kernel that reduce + the risks posed by exploitable memory corruption bugs. + +menu "PaX Control" + depends on PAX + +config PAX_SOFTMODE + bool 'Support soft mode' + help + Enabling this option will allow you to run PaX in soft mode, that + is, PaX features will not be enforced by default, only on executables + marked explicitly. You must also enable PT_PAX_FLAGS support as it + is the only way to mark executables for soft mode use. + + Soft mode can be activated by using the "pax_softmode=1" kernel command + line option on boot. Furthermore you can control various PaX features + at runtime via the entries in /proc/sys/kernel/pax. + +config PAX_EI_PAX + bool 'Use legacy ELF header marking' + help + Enabling this option will allow you to control PaX features on + a per executable basis via the 'chpax' utility available at + http://pax.grsecurity.net/. The control flags will be read from + an otherwise reserved part of the ELF header. This marking has + numerous drawbacks (no support for soft-mode, toolchain does not + know about the non-standard use of the ELF header) therefore it + has been deprecated in favour of PT_PAX_FLAGS support. + + If you have applications not marked by the PT_PAX_FLAGS ELF + program header then you MUST enable this option otherwise they + will not get any protection. + + Note that if you enable PT_PAX_FLAGS marking support as well, + the PT_PAX_FLAG marks will override the legacy EI_PAX marks. + +config PAX_PT_PAX_FLAGS + bool 'Use ELF program header marking' + help + Enabling this option will allow you to control PaX features on + a per executable basis via the 'paxctl' utility available at + http://pax.grsecurity.net/. The control flags will be read from + a PaX specific ELF program header (PT_PAX_FLAGS). This marking + has the benefits of supporting both soft mode and being fully + integrated into the toolchain (the binutils patch is available + from http://pax.grsecurity.net). + + If you have applications not marked by the PT_PAX_FLAGS ELF + program header then you MUST enable the EI_PAX marking support + otherwise they will not get any protection. + + Note that if you enable the legacy EI_PAX marking support as well, + the EI_PAX marks will be overridden by the PT_PAX_FLAGS marks. + +choice + prompt 'MAC system integration' + default PAX_HAVE_ACL_FLAGS + help + Mandatory Access Control systems have the option of controlling + PaX flags on a per executable basis, choose the method supported + by your particular system. + + - "none": if your MAC system does not interact with PaX, + - "direct": if your MAC system defines pax_set_initial_flags() itself, + - "hook": if your MAC system uses the pax_set_initial_flags_func callback. + + NOTE: this option is for developers/integrators only. + + config PAX_NO_ACL_FLAGS + bool 'none' + + config PAX_HAVE_ACL_FLAGS + bool 'direct' + + config PAX_HOOK_ACL_FLAGS + bool 'hook' +endchoice + +endmenu + +menu "Non-executable pages" + depends on PAX + +config PAX_NOEXEC + bool "Enforce non-executable pages" + depends on (PAX_EI_PAX || PAX_PT_PAX_FLAGS || PAX_HAVE_ACL_FLAGS || PAX_HOOK_ACL_FLAGS) && (ALPHA || IA64 || MIPS32 || MIPS64 || PARISC || PPC32 || PPC64 || SPARC32 || SPARC64 || X86) + help + By design some architectures do not allow for protecting memory + pages against execution or even if they do, Linux does not make + use of this feature. In practice this means that if a page is + readable (such as the stack or heap) it is also executable. + + There is a well known exploit technique that makes use of this + fact and a common programming mistake where an attacker can + introduce code of his choice somewhere in the attacked program's + memory (typically the stack or the heap) and then execute it. + + If the attacked program was running with different (typically + higher) privileges than that of the attacker, then he can elevate + his own privilege level (e.g. get a root shell, write to files for + which he does not have write access to, etc). + + Enabling this option will let you choose from various features + that prevent the injection and execution of 'foreign' code in + a program. + + This will also break programs that rely on the old behaviour and + expect that dynamically allocated memory via the malloc() family + of functions is executable (which it is not). Notable examples + are the XFree86 4.x server, the java runtime and wine. + +config PAX_PAGEEXEC + bool "Paging based non-executable pages" + depends on !COMPAT_VDSO && PAX_NOEXEC && (!X86_32 || M586 || M586TSC || M586MMX || M686 || MPENTIUMII || MPENTIUMIII || MPENTIUMM || MCORE2 || MPENTIUM4 || MPSC || MK7 || MK8 || MWINCHIPC6 || MWINCHIP2 || MWINCHIP3D || MVIAC3_2 || MVIAC7) + help + This implementation is based on the paging feature of the CPU. + On i386 without hardware non-executable bit support there is a + variable but usually low performance impact, however on Intel's + P4 core based CPUs it is very high so you should not enable this + for kernels meant to be used on such CPUs. + + On alpha, avr32, ia64, parisc, sparc, sparc64, x86_64 and i386 + with hardware non-executable bit support there is no performance + impact, on ppc the impact is negligible. + + Note that several architectures require various emulations due to + badly designed userland ABIs, this will cause a performance impact + but will disappear as soon as userland is fixed (e.g., ppc users + can make use of the secure-plt feature found in binutils). + +config PAX_SEGMEXEC + bool "Segmentation based non-executable pages" + depends on !COMPAT_VDSO && PAX_NOEXEC && X86_32 + help + This implementation is based on the segmentation feature of the + CPU and has a very small performance impact, however applications + will be limited to a 1.5 GB address space instead of the normal + 3 GB. + +config PAX_EMUTRAMP + bool "Emulate trampolines" if (PAX_PAGEEXEC || PAX_SEGMEXEC) && (PARISC || PPC32 || X86) + default y if PARISC || PPC32 + help + There are some programs and libraries that for one reason or + another attempt to execute special small code snippets from + non-executable memory pages. Most notable examples are the + signal handler return code generated by the kernel itself and + the GCC trampolines. + + If you enabled CONFIG_PAX_PAGEEXEC or CONFIG_PAX_SEGMEXEC then + such programs will no longer work under your kernel. + + As a remedy you can say Y here and use the 'chpax' or 'paxctl' + utilities to enable trampoline emulation for the affected programs + yet still have the protection provided by the non-executable pages. + + On parisc and ppc you MUST enable this option and EMUSIGRT as + well, otherwise your system will not even boot. + + Alternatively you can say N here and use the 'chpax' or 'paxctl' + utilities to disable CONFIG_PAX_PAGEEXEC and CONFIG_PAX_SEGMEXEC + for the affected files. + + NOTE: enabling this feature *may* open up a loophole in the + protection provided by non-executable pages that an attacker + could abuse. Therefore the best solution is to not have any + files on your system that would require this option. This can + be achieved by not using libc5 (which relies on the kernel + signal handler return code) and not using or rewriting programs + that make use of the nested function implementation of GCC. + Skilled users can just fix GCC itself so that it implements + nested function calls in a way that does not interfere with PaX. + +config PAX_EMUSIGRT + bool "Automatically emulate sigreturn trampolines" + depends on PAX_EMUTRAMP && (PARISC || PPC32) + default y + help + Enabling this option will have the kernel automatically detect + and emulate signal return trampolines executing on the stack + that would otherwise lead to task termination. + + This solution is intended as a temporary one for users with + legacy versions of libc (libc5, glibc 2.0, uClibc before 0.9.17, + Modula-3 runtime, etc) or executables linked to such, basically + everything that does not specify its own SA_RESTORER function in + normal executable memory like glibc 2.1+ does. + + On parisc and ppc you MUST enable this option, otherwise your + system will not even boot. + + NOTE: this feature cannot be disabled on a per executable basis + and since it *does* open up a loophole in the protection provided + by non-executable pages, the best solution is to not have any + files on your system that would require this option. + +config PAX_MPROTECT + bool "Restrict mprotect()" + depends on (PAX_PAGEEXEC || PAX_SEGMEXEC) && !PPC64 + help + Enabling this option will prevent programs from + - changing the executable status of memory pages that were + not originally created as executable, + - making read-only executable pages writable again, + - creating executable pages from anonymous memory. + + You should say Y here to complete the protection provided by + the enforcement of non-executable pages. + + NOTE: you can use the 'chpax' or 'paxctl' utilities to control + this feature on a per file basis. + +config PAX_NOELFRELOCS + bool "Disallow ELF text relocations" + depends on PAX_MPROTECT && !PAX_ETEXECRELOCS && (IA64 || X86) + help + Non-executable pages and mprotect() restrictions are effective + in preventing the introduction of new executable code into an + attacked task's address space. There remain only two venues + for this kind of attack: if the attacker can execute already + existing code in the attacked task then he can either have it + create and mmap() a file containing his code or have it mmap() + an already existing ELF library that does not have position + independent code in it and use mprotect() on it to make it + writable and copy his code there. While protecting against + the former approach is beyond PaX, the latter can be prevented + by having only PIC ELF libraries on one's system (which do not + need to relocate their code). If you are sure this is your case, + then enable this option otherwise be careful as you may not even + be able to boot or log on your system (for example, some PAM + modules are erroneously compiled as non-PIC by default). + + NOTE: if you are using dynamic ELF executables (as suggested + when using ASLR) then you must have made sure that you linked + your files using the PIC version of crt1 (the et_dyn.tar.gz package + referenced there has already been updated to support this). + +config PAX_ETEXECRELOCS + bool "Allow ELF ET_EXEC text relocations" + depends on PAX_MPROTECT && (ALPHA || IA64 || PARISC) + default y + help + On some architectures there are incorrectly created applications + that require text relocations and would not work without enabling + this option. If you are an alpha, ia64 or parisc user, you should + enable this option and disable it once you have made sure that + none of your applications need it. + +config PAX_EMUPLT + bool "Automatically emulate ELF PLT" + depends on PAX_MPROTECT && (ALPHA || PARISC || PPC32 || SPARC32 || SPARC64) + default y + help + Enabling this option will have the kernel automatically detect + and emulate the Procedure Linkage Table entries in ELF files. + On some architectures such entries are in writable memory, and + become non-executable leading to task termination. Therefore + it is mandatory that you enable this option on alpha, parisc, + ppc (if secure-plt is not used throughout in userland), sparc + and sparc64, otherwise your system would not even boot. + + NOTE: this feature *does* open up a loophole in the protection + provided by the non-executable pages, therefore the proper + solution is to modify the toolchain to produce a PLT that does + not need to be writable. + +config PAX_DLRESOLVE + bool + depends on PAX_EMUPLT && (SPARC32 || SPARC64) + default y + +config PAX_SYSCALL + bool + depends on PAX_PAGEEXEC && PPC32 + default y + +config PAX_KERNEXEC + bool "Enforce non-executable kernel pages" + depends on PAX_NOEXEC && X86 && !EFI && !COMPAT_VDSO && (!X86_32 || X86_WP_WORKS_OK) && !PARAVIRT + help + This is the kernel land equivalent of PAGEEXEC and MPROTECT, + that is, enabling this option will make it harder to inject + and execute 'foreign' code in kernel memory itself. + +endmenu + +menu "Address Space Layout Randomization" + depends on PAX + +config PAX_ASLR + bool "Address Space Layout Randomization" + depends on PAX_EI_PAX || PAX_PT_PAX_FLAGS || PAX_HAVE_ACL_FLAGS || PAX_HOOK_ACL_FLAGS + help + Many if not most exploit techniques rely on the knowledge of + certain addresses in the attacked program. The following options + will allow the kernel to apply a certain amount of randomization + to specific parts of the program thereby forcing an attacker to + guess them in most cases. Any failed guess will most likely crash + the attacked program which allows the kernel to detect such attempts + and react on them. PaX itself provides no reaction mechanisms, + instead it is strongly encouraged that you make use of Nergal's + segvguard (ftp://ftp.pl.openwall.com/misc/segvguard/) or grsecurity's + (http://www.grsecurity.net/) built-in crash detection features or + develop one yourself. + + By saying Y here you can choose to randomize the following areas: + - top of the task's kernel stack + - top of the task's userland stack + - base address for mmap() requests that do not specify one + (this includes all libraries) + - base address of the main executable + + It is strongly recommended to say Y here as address space layout + randomization has negligible impact on performance yet it provides + a very effective protection. + + NOTE: you can use the 'chpax' or 'paxctl' utilities to control + this feature on a per file basis. + +config PAX_RANDKSTACK + bool "Randomize kernel stack base" + depends on PAX_ASLR && X86_TSC && X86_32 + help + By saying Y here the kernel will randomize every task's kernel + stack on every system call. This will not only force an attacker + to guess it but also prevent him from making use of possible + leaked information about it. + + Since the kernel stack is a rather scarce resource, randomization + may cause unexpected stack overflows, therefore you should very + carefully test your system. Note that once enabled in the kernel + configuration, this feature cannot be disabled on a per file basis. + +config PAX_RANDUSTACK + bool "Randomize user stack base" + depends on PAX_ASLR + help + By saying Y here the kernel will randomize every task's userland + stack. The randomization is done in two steps where the second + one may apply a big amount of shift to the top of the stack and + cause problems for programs that want to use lots of memory (more + than 2.5 GB if SEGMEXEC is not active, or 1.25 GB when it is). + For this reason the second step can be controlled by 'chpax' or + 'paxctl' on a per file basis. + +config PAX_RANDMMAP + bool "Randomize mmap() base" + depends on PAX_ASLR + help + By saying Y here the kernel will use a randomized base address for + mmap() requests that do not specify one themselves. As a result + all dynamically loaded libraries will appear at random addresses + and therefore be harder to exploit by a technique where an attacker + attempts to execute library code for his purposes (e.g. spawn a + shell from an exploited program that is running at an elevated + privilege level). + + Furthermore, if a program is relinked as a dynamic ELF file, its + base address will be randomized as well, completing the full + randomization of the address space layout. Attacking such programs + becomes a guess game. You can find an example of doing this at + http://pax.grsecurity.net/et_dyn.tar.gz and practical samples at + http://www.grsecurity.net/grsec-gcc-specs.tar.gz . + + NOTE: you can use the 'chpax' or 'paxctl' utilities to control this + feature on a per file basis. + +endmenu + +menu "Miscellaneous hardening features" + +config PAX_MEMORY_SANITIZE + bool "Sanitize all freed memory" + help + By saying Y here the kernel will erase memory pages as soon as they + are freed. This in turn reduces the lifetime of data stored in the + pages, making it less likely that sensitive information such as + passwords, cryptographic secrets, etc stay in memory for too long. + + This is especially useful for programs whose runtime is short, long + lived processes and the kernel itself benefit from this as long as + they operate on whole memory pages and ensure timely freeing of pages + that may hold sensitive information. + + The tradeoff is performance impact, on a single CPU system kernel + compilation sees a 3% slowdown, other systems and workloads may vary + and you are advised to test this feature on your expected workload + before deploying it. + + Note that this feature does not protect data stored in live pages, + e.g., process memory swapped to disk may stay there for a long time. + +config PAX_MEMORY_UDEREF + bool "Prevent invalid userland pointer dereference" + depends on X86_32 && !COMPAT_VDSO && !UML_X86 + help + By saying Y here the kernel will be prevented from dereferencing + userland pointers in contexts where the kernel expects only kernel + pointers. This is both a useful runtime debugging feature and a + security measure that prevents exploiting a class of kernel bugs. + + The tradeoff is that some virtualization solutions may experience + a huge slowdown and therefore you should not enable this feature + for kernels meant to run in such environments. Whether a given VM + solution is affected or not is best determined by simply trying it + out, the performance impact will be obvious right on boot as this + mechanism engages from very early on. A good rule of thumb is that + VMs running on CPUs without hardware virtualization support (i.e., + the majority of IA-32 CPUs) will likely experience the slowdown. + +config PAX_REFCOUNT + bool "Prevent various kernel object reference counter overflows" + depends on X86 + help + By saying Y here the kernel will detect and prevent overflowing + various (but not all) kinds of object reference counters. Such + overflows can normally occur due to bugs only and are often, if + not always, exploitable. + + The tradeoff is that data structures protected by an oveflowed + refcount will never be freed and therefore will leak memory. Note + that this leak also happens even without this protection but in + that case the overflow can eventually trigger the freeing of the + data structure while it is still being used elsewhere, resulting + in the exploitable situation that this feature prevents. + + Since this has a negligible performance impact, you should enable + this feature. +endmenu + +endmenu + config KEYS bool "Enable access key retention support" help diff -NurpP --minimal linux-2.6.27.15/security/selinux/hooks.c linux-2.6.27.15-g-v/security/selinux/hooks.c --- linux-2.6.27.15/security/selinux/hooks.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/security/selinux/hooks.c 2009-02-10 20:32:18.000000000 +0100 @@ -64,7 +64,6 @@ #include #include #include /* for Unix socket types */ -#include /* for Unix socket types */ #include #include #include diff -NurpP --minimal linux-2.6.27.15/sound/core/oss/pcm_oss.c linux-2.6.27.15-g-v/sound/core/oss/pcm_oss.c --- linux-2.6.27.15/sound/core/oss/pcm_oss.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/sound/core/oss/pcm_oss.c 2009-02-10 20:32:18.000000000 +0100 @@ -2911,8 +2911,8 @@ static void snd_pcm_oss_proc_done(struct } } #else /* !CONFIG_SND_VERBOSE_PROCFS */ -#define snd_pcm_oss_proc_init(pcm) -#define snd_pcm_oss_proc_done(pcm) +#define snd_pcm_oss_proc_init(pcm) do {} while (0) +#define snd_pcm_oss_proc_done(pcm) do {} while (0) #endif /* CONFIG_SND_VERBOSE_PROCFS */ /* diff -NurpP --minimal linux-2.6.27.15/sound/core/seq/seq_lock.h linux-2.6.27.15-g-v/sound/core/seq/seq_lock.h --- linux-2.6.27.15/sound/core/seq/seq_lock.h 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/sound/core/seq/seq_lock.h 2009-02-10 20:32:18.000000000 +0100 @@ -23,10 +23,10 @@ void snd_use_lock_sync_helper(snd_use_lo #else /* SMP || CONFIG_SND_DEBUG */ typedef spinlock_t snd_use_lock_t; /* dummy */ -#define snd_use_lock_init(lockp) /**/ -#define snd_use_lock_use(lockp) /**/ -#define snd_use_lock_free(lockp) /**/ -#define snd_use_lock_sync(lockp) /**/ +#define snd_use_lock_init(lockp) do {} while (0) +#define snd_use_lock_use(lockp) do {} while (0) +#define snd_use_lock_free(lockp) do {} while (0) +#define snd_use_lock_sync(lockp) do {} while (0) #endif /* SMP || CONFIG_SND_DEBUG */ diff -NurpP --minimal linux-2.6.27.15/sound/pci/ac97/ac97_patch.c linux-2.6.27.15-g-v/sound/pci/ac97/ac97_patch.c --- linux-2.6.27.15/sound/pci/ac97/ac97_patch.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/sound/pci/ac97/ac97_patch.c 2009-02-10 20:32:18.000000000 +0100 @@ -1498,7 +1498,7 @@ static const struct snd_ac97_res_table a { AC97_VIDEO, 0x9f1f }, { AC97_AUX, 0x9f1f }, { AC97_PCM, 0x9f1f }, - { } /* terminator */ + { 0, 0 } /* terminator */ }; static int patch_ad1819(struct snd_ac97 * ac97) @@ -3668,7 +3668,7 @@ static struct snd_ac97_res_table lm4550_ { AC97_AUX, 0x1f1f }, { AC97_PCM, 0x1f1f }, { AC97_REC_GAIN, 0x0f0f }, - { } /* terminator */ + { 0, 0 } /* terminator */ }; static int patch_lm4550(struct snd_ac97 *ac97) diff -NurpP --minimal linux-2.6.27.15/sound/pci/ens1370.c linux-2.6.27.15-g-v/sound/pci/ens1370.c --- linux-2.6.27.15/sound/pci/ens1370.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/sound/pci/ens1370.c 2009-02-10 20:32:18.000000000 +0100 @@ -452,7 +452,7 @@ static struct pci_device_id snd_audiopci { 0x1274, 0x5880, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* ES1373 - CT5880 */ { 0x1102, 0x8938, PCI_ANY_ID, PCI_ANY_ID, 0, 0, 0, }, /* Ectiva EV1938 */ #endif - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, snd_audiopci_ids); diff -NurpP --minimal linux-2.6.27.15/sound/pci/intel8x0.c linux-2.6.27.15-g-v/sound/pci/intel8x0.c --- linux-2.6.27.15/sound/pci/intel8x0.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/sound/pci/intel8x0.c 2009-02-10 20:32:18.000000000 +0100 @@ -437,7 +437,7 @@ static struct pci_device_id snd_intel8x0 { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */ { 0x1022, 0x7445, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD768 */ { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI }, /* Ali5455 */ - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, snd_intel8x0_ids); @@ -2076,7 +2076,7 @@ static struct ac97_quirk ac97_quirks[] _ .type = AC97_TUNE_HP_ONLY }, #endif - { } /* terminator */ + { 0, 0, 0, 0, NULL, 0 } /* terminator */ }; static int __devinit snd_intel8x0_mixer(struct intel8x0 *chip, int ac97_clock, diff -NurpP --minimal linux-2.6.27.15/sound/pci/intel8x0m.c linux-2.6.27.15-g-v/sound/pci/intel8x0m.c --- linux-2.6.27.15/sound/pci/intel8x0m.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/sound/pci/intel8x0m.c 2009-02-10 20:32:18.000000000 +0100 @@ -239,7 +239,7 @@ static struct pci_device_id snd_intel8x0 { 0x1022, 0x746d, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_INTEL }, /* AMD8111 */ { 0x10b9, 0x5455, PCI_ANY_ID, PCI_ANY_ID, 0, 0, DEVICE_ALI }, /* Ali5455 */ #endif - { 0, } + { 0, 0, 0, 0, 0, 0, 0 } }; MODULE_DEVICE_TABLE(pci, snd_intel8x0m_ids); @@ -1257,7 +1257,7 @@ static struct shortname_table { { 0x5455, "ALi M5455" }, { 0x746d, "AMD AMD8111" }, #endif - { 0 }, + { 0, NULL }, }; static int __devinit snd_intel8x0m_probe(struct pci_dev *pci, diff -NurpP --minimal linux-2.6.27.15/virt/kvm/kvm_main.c linux-2.6.27.15-g-v/virt/kvm/kvm_main.c --- linux-2.6.27.15/virt/kvm/kvm_main.c 2009-02-06 23:49:24.000000000 +0100 +++ linux-2.6.27.15-g-v/virt/kvm/kvm_main.c 2009-02-10 20:32:18.000000000 +0100 @@ -1469,6 +1469,9 @@ static struct miscdevice kvm_dev = { KVM_MINOR, "kvm", &kvm_chardev_ops, + {NULL, NULL}, + NULL, + NULL }; static void hardware_enable(void *junk)