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
 
 /*

Reply via email to