Module Name: src Committed By: maxv Date: Sat Aug 6 15:13:14 UTC 2016
Modified Files: src/sys/compat/linux32/common: linux32_exec_elf32.c src/sys/compat/netbsd32: netbsd32_exec_aout.c netbsd32_exec_elf32.c src/sys/kern: kern_exec.c src/sys/sys: exec.h src/sys/uvm: uvm_map.c Log Message: The way the kernel tries to prevent a userland process from allocating page zero is hugely flawed. It is easy to demonstrate that one can trick UVM into chosing a NULL hint after the user_va0_disable check from uvm_map. Such a bypass allows kernel NULL pointer dereferences to be exploitable on architectures with a shared userland<->kernel VA, like amd64. Fix this by increasing the limit of the vm space made available for userland processes. This way, UVM will never chose a NULL hint, since it would be outside of the vm space. The user_va0_disable sysctl still controls this feature. To generate a diff of this commit: cvs rdiff -u -r1.18 -r1.19 src/sys/compat/linux32/common/linux32_exec_elf32.c cvs rdiff -u -r1.29 -r1.30 src/sys/compat/netbsd32/netbsd32_exec_aout.c cvs rdiff -u -r1.39 -r1.40 src/sys/compat/netbsd32/netbsd32_exec_elf32.c cvs rdiff -u -r1.435 -r1.436 src/sys/kern/kern_exec.c cvs rdiff -u -r1.150 -r1.151 src/sys/sys/exec.h cvs rdiff -u -r1.340 -r1.341 src/sys/uvm/uvm_map.c Please note that diffs are not public domain; they are subject to the copyright notices on the relevant files.
Modified files: Index: src/sys/compat/linux32/common/linux32_exec_elf32.c diff -u src/sys/compat/linux32/common/linux32_exec_elf32.c:1.18 src/sys/compat/linux32/common/linux32_exec_elf32.c:1.19 --- src/sys/compat/linux32/common/linux32_exec_elf32.c:1.18 Fri Mar 20 20:36:27 2015 +++ src/sys/compat/linux32/common/linux32_exec_elf32.c Sat Aug 6 15:13:13 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: linux32_exec_elf32.c,v 1.18 2015/03/20 20:36:27 maxv Exp $ */ +/* $NetBSD: linux32_exec_elf32.c,v 1.19 2016/08/06 15:13:13 maxv Exp $ */ /*- * Copyright (c) 1995, 1998, 2000, 2001,2006 The NetBSD Foundation, Inc. @@ -31,7 +31,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: linux32_exec_elf32.c,v 1.18 2015/03/20 20:36:27 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: linux32_exec_elf32.c,v 1.19 2016/08/06 15:13:13 maxv Exp $"); #define ELFSIZE 32 @@ -93,7 +93,7 @@ ELFNAME2(linux32,probe)(struct lwp *l, s #endif epp->ep_flags |= EXEC_32 | EXEC_FORCEAUX; - epp->ep_vm_minaddr = VM_MIN_ADDRESS; + epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); epp->ep_vm_maxaddr = USRSTACK32; return 0; Index: src/sys/compat/netbsd32/netbsd32_exec_aout.c diff -u src/sys/compat/netbsd32/netbsd32_exec_aout.c:1.29 src/sys/compat/netbsd32/netbsd32_exec_aout.c:1.30 --- src/sys/compat/netbsd32/netbsd32_exec_aout.c:1.29 Fri Dec 5 22:21:47 2014 +++ src/sys/compat/netbsd32/netbsd32_exec_aout.c Sat Aug 6 15:13:13 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_exec_aout.c,v 1.29 2014/12/05 22:21:47 christos Exp $ */ +/* $NetBSD: netbsd32_exec_aout.c,v 1.30 2016/08/06 15:13:13 maxv Exp $ */ /* from: NetBSD: exec_aout.c,v 1.15 1996/09/26 23:34:46 cgd Exp */ /* @@ -57,7 +57,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: netbsd32_exec_aout.c,v 1.29 2014/12/05 22:21:47 christos Exp $"); +__KERNEL_RCSID(0, "$NetBSD: netbsd32_exec_aout.c,v 1.30 2016/08/06 15:13:13 maxv Exp $"); #include <sys/param.h> #include <sys/systm.h> @@ -164,7 +164,7 @@ netbsd32_exec_aout_prep_zmagic(struct lw epp->ep_daddr = epp->ep_taddr + execp->a_text; epp->ep_dsize = execp->a_data + execp->a_bss; epp->ep_entry = execp->a_entry; - epp->ep_vm_minaddr = VM_MIN_ADDRESS; + epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; error = vn_marktext(epp->ep_vp); @@ -205,7 +205,7 @@ netbsd32_exec_aout_prep_nmagic(struct lw epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text, AOUT_LDPGSZ); epp->ep_dsize = execp->a_data + execp->a_bss; epp->ep_entry = execp->a_entry; - epp->ep_vm_minaddr = VM_MIN_ADDRESS; + epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; /* set up command for text segment */ @@ -244,7 +244,7 @@ netbsd32_exec_aout_prep_omagic(struct lw epp->ep_daddr = epp->ep_taddr + execp->a_text; epp->ep_dsize = execp->a_data + execp->a_bss; epp->ep_entry = execp->a_entry; - epp->ep_vm_minaddr = VM_MIN_ADDRESS; + epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; /* set up command for text and data segments */ @@ -294,7 +294,7 @@ netbsd32_exec_aout_prep_oldzmagic(struct epp->ep_daddr = epp->ep_taddr + execp->a_text; epp->ep_dsize = execp->a_data + execp->a_bss; epp->ep_entry = execp->a_entry; - epp->ep_vm_minaddr = VM_MIN_ADDRESS; + epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; error = vn_marktext(epp->ep_vp); @@ -342,7 +342,7 @@ netbsd32_exec_aout_prep_oldnmagic(struct epp->ep_daddr = roundup(epp->ep_taddr + execp->a_text, AOUT_LDPGSZ); epp->ep_dsize = execp->a_data + execp->a_bss; epp->ep_entry = execp->a_entry; - epp->ep_vm_minaddr = VM_MIN_ADDRESS; + epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS32; /* set up command for text segment */ Index: src/sys/compat/netbsd32/netbsd32_exec_elf32.c diff -u src/sys/compat/netbsd32/netbsd32_exec_elf32.c:1.39 src/sys/compat/netbsd32/netbsd32_exec_elf32.c:1.40 --- src/sys/compat/netbsd32/netbsd32_exec_elf32.c:1.39 Fri Mar 20 20:36:27 2015 +++ src/sys/compat/netbsd32/netbsd32_exec_elf32.c Sat Aug 6 15:13:13 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: netbsd32_exec_elf32.c,v 1.39 2015/03/20 20:36:27 maxv Exp $ */ +/* $NetBSD: netbsd32_exec_elf32.c,v 1.40 2016/08/06 15:13:13 maxv Exp $ */ /* from: NetBSD: exec_aout.c,v 1.15 1996/09/26 23:34:46 cgd Exp */ /* @@ -57,7 +57,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: netbsd32_exec_elf32.c,v 1.39 2015/03/20 20:36:27 maxv Exp $"); +__KERNEL_RCSID(0, "$NetBSD: netbsd32_exec_elf32.c,v 1.40 2016/08/06 15:13:13 maxv Exp $"); #define ELFSIZE 32 @@ -115,7 +115,7 @@ ELFNAME2(netbsd32,probe_noteless)(struct #ifdef _LP64 epp->ep_flags |= EXEC_32 | EXEC_FORCEAUX; #endif - epp->ep_vm_minaddr = VM_MIN_ADDRESS; + epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); epp->ep_vm_maxaddr = USRSTACK32; #ifdef ELF_INTERP_NON_RELOCATABLE *pos = ELF_LINK_ADDR; Index: src/sys/kern/kern_exec.c diff -u src/sys/kern/kern_exec.c:1.435 src/sys/kern/kern_exec.c:1.436 --- src/sys/kern/kern_exec.c:1.435 Thu Jul 7 06:55:43 2016 +++ src/sys/kern/kern_exec.c Sat Aug 6 15:13:13 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: kern_exec.c,v 1.435 2016/07/07 06:55:43 msaitoh Exp $ */ +/* $NetBSD: kern_exec.c,v 1.436 2016/08/06 15:13:13 maxv Exp $ */ /*- * Copyright (c) 2008 The NetBSD Foundation, Inc. @@ -59,7 +59,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.435 2016/07/07 06:55:43 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: kern_exec.c,v 1.436 2016/08/06 15:13:13 maxv Exp $"); #include "opt_exec.h" #include "opt_execfmt.h" @@ -122,6 +122,8 @@ __KERNEL_RCSID(0, "$NetBSD: kern_exec.c, struct execve_data; +extern int user_va0_disable; + static size_t calcargs(struct execve_data * restrict, const size_t); static size_t calcstack(struct execve_data * restrict, const size_t); static int copyoutargs(struct execve_data * restrict, struct lwp *, @@ -401,11 +403,10 @@ check_exec(struct lwp *l, struct exec_pa /* * Set up default address space limits. Can be overridden * by individual exec packages. - * - * XXX probably should be all done in the exec packages. */ - epp->ep_vm_minaddr = VM_MIN_ADDRESS; + epp->ep_vm_minaddr = exec_vm_minaddr(VM_MIN_ADDRESS); epp->ep_vm_maxaddr = VM_MAXUSER_ADDRESS; + /* * set up the vmcmds for creation of the process * address space @@ -652,6 +653,19 @@ out: return 0; } +vaddr_t +exec_vm_minaddr(vaddr_t va_min) +{ + /* + * Increase va_min if we don't want NULL to be mappable by the + * process. + */ +#define VM_MIN_GUARD (2 * PAGE_SIZE) + if (user_va0_disable && (va_min < VM_MIN_GUARD)) + return VM_MIN_GUARD; + return va_min; +} + static int execve_loadvm(struct lwp *l, const char *path, char * const *args, char * const *envs, execve_fetch_element_t fetch_element, Index: src/sys/sys/exec.h diff -u src/sys/sys/exec.h:1.150 src/sys/sys/exec.h:1.151 --- src/sys/sys/exec.h:1.150 Sat Jan 23 14:03:48 2016 +++ src/sys/sys/exec.h Sat Aug 6 15:13:14 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: exec.h,v 1.150 2016/01/23 14:03:48 christos Exp $ */ +/* $NetBSD: exec.h,v 1.151 2016/08/06 15:13:14 maxv Exp $ */ /*- * Copyright (c) 1992, 1993 @@ -250,6 +250,7 @@ struct exec_vmcmd { * funtions used either by execve() or the various CPU-dependent execve() * hooks. */ +vaddr_t exec_vm_minaddr (vaddr_t); void kill_vmcmd (struct exec_vmcmd **); int exec_makecmds (struct lwp *, struct exec_package *); int exec_runcmds (struct lwp *, struct exec_package *); Index: src/sys/uvm/uvm_map.c diff -u src/sys/uvm/uvm_map.c:1.340 src/sys/uvm/uvm_map.c:1.341 --- src/sys/uvm/uvm_map.c:1.340 Thu Jul 7 06:55:44 2016 +++ src/sys/uvm/uvm_map.c Sat Aug 6 15:13:14 2016 @@ -1,4 +1,4 @@ -/* $NetBSD: uvm_map.c,v 1.340 2016/07/07 06:55:44 msaitoh Exp $ */ +/* $NetBSD: uvm_map.c,v 1.341 2016/08/06 15:13:14 maxv Exp $ */ /* * Copyright (c) 1997 Charles D. Cranor and Washington University. @@ -66,7 +66,7 @@ */ #include <sys/cdefs.h> -__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.340 2016/07/07 06:55:44 msaitoh Exp $"); +__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.341 2016/08/06 15:13:14 maxv Exp $"); #include "opt_ddb.h" #include "opt_uvmhist.h" @@ -171,7 +171,7 @@ vaddr_t uvm_maxkaddr; #undef __USER_VA0_DISABLE_DEFAULT #define __USER_VA0_DISABLE_DEFAULT USER_VA0_DISABLE_DEFAULT #endif -static int user_va0_disable = __USER_VA0_DISABLE_DEFAULT; +int user_va0_disable = __USER_VA0_DISABLE_DEFAULT; #endif /*