Subject: Disallowing mmapping of NULL
To: None <tech-kern@netbsd.org>
From: Joerg Sonnenberger <joerg@britannica.bec.de>
List: tech-kern
Date: 01/29/2007 20:06:22
--PNTmBPCT7hxwcZjr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: inline

Hi all,
attached is a small patch that allows disabling mapping of page 0 of the
(userland) address space. It also exempts page 0 from normal mmap
allocation. Both are expected to reduce exploitability of NULL
deferences. The test program should segfault when this is active :-)

For architectures with shared user/kernel address space, any userland
code which can trigger a function call through a NULL pointer results in
execution of arbitrary code as shown on 23C3 for another BSD. Other
exploits can be thought of as well.

It can't be activated by default as some emulation require this (like SYSV)
or because it allows heavy optimisations with prefetching. I consider it
useful enough to force under securelevel 2 though.

Avoiding it for non-fixed mappings is important as some applications are
known to get memory like nothing else (firefox!) and even remotely
triggerable. The NULL page should never be allocated if not explicitly
requested to avoid issues for such programs.

Joerg

--PNTmBPCT7hxwcZjr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="mapnull.diff"

Index: sys/kauth.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/sys/kauth.h,v
retrieving revision 1.35
diff -u -r1.35 kauth.h
--- sys/kauth.h	20 Jan 2007 16:47:38 -0000	1.35
+++ sys/kauth.h	29 Jan 2007 18:48:12 -0000
@@ -84,6 +84,7 @@
 	KAUTH_SYSTEM_DEBUG,
 	KAUTH_SYSTEM_FILEHANDLE,
 	KAUTH_SYSTEM_LKM,
+	KAUTH_SYSTEM_MAPNULL,
 	KAUTH_SYSTEM_MKNOD,
 	KAUTH_SYSTEM_MOUNT,
 	KAUTH_SYSTEM_REBOOT,
Index: secmodel/bsd44/secmodel_bsd44.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/secmodel/bsd44/secmodel_bsd44.c,v
retrieving revision 1.10
diff -u -r1.10 secmodel_bsd44.c
--- secmodel/bsd44/secmodel_bsd44.c	16 Jan 2007 11:53:00 -0000	1.10
+++ secmodel/bsd44/secmodel_bsd44.c	29 Jan 2007 18:50:40 -0000
@@ -87,6 +87,13 @@
 
 	sysctl_createv(clog, 0, &rnode, NULL,
 		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+		       CTLTYPE_INT, "mapnull",
+		       SYSCTL_DESCR("Allow mapping of page zero"),
+		       NULL, 0, &secmodel_bsd44_mapnull, 0,
+		       CTL_CREATE, CTL_EOL);
+
+	sysctl_createv(clog, 0, &rnode, NULL,
+		       CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
 		       CTLTYPE_INT, "curtain",
 		       SYSCTL_DESCR("Curtain information about objects to "
 				    "users not owning them."),
Index: secmodel/bsd44/secmodel_bsd44_securelevel.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/secmodel/bsd44/secmodel_bsd44_securelevel.c,v
retrieving revision 1.29
diff -u -r1.29 secmodel_bsd44_securelevel.c
--- secmodel/bsd44/secmodel_bsd44_securelevel.c	10 Jan 2007 11:20:21 -0000	1.29
+++ secmodel/bsd44/secmodel_bsd44_securelevel.c	29 Jan 2007 18:50:09 -0000
@@ -55,6 +55,7 @@
 #include <secmodel/bsd44/securelevel.h>
 
 static int securelevel;
+int secmodel_bsd44_mapnull = 1;
 
 static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
 
@@ -187,6 +188,11 @@
 			result = KAUTH_RESULT_ALLOW;
 		break;
 
+	case KAUTH_SYSTEM_MAPNULL:
+		if (securelevel < 2 && secmodel_bsd44_mapnull != 0)
+			result = KAUTH_RESULT_ALLOW;
+		break;
+
 	case KAUTH_SYSTEM_MOUNT:
 		switch (req) {
 		case KAUTH_REQ_SYSTEM_MOUNT_NEW:
Index: secmodel/bsd44/securelevel.h
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/secmodel/bsd44/securelevel.h,v
retrieving revision 1.5
diff -u -r1.5 securelevel.h
--- secmodel/bsd44/securelevel.h	9 Jan 2007 12:57:56 -0000	1.5
+++ secmodel/bsd44/securelevel.h	29 Jan 2007 18:54:54 -0000
@@ -29,6 +29,8 @@
 #ifndef _SECMODEL_BSD44_SECURELEVEL_H_
 #define	_SECMODEL_BSD44_SECURELEVEL_H_
 
+extern int secmodel_bsd44_mapnull;
+
 int secmodel_bsd44_sysctl_securelevel(SYSCTLFN_PROTO);
 
 void secmodel_bsd44_securelevel_init(void);
Index: uvm/uvm_map.c
===================================================================
RCS file: /home/joerg/repo/netbsd/src/sys/uvm/uvm_map.c,v
retrieving revision 1.232
diff -u -r1.232 uvm_map.c
--- uvm/uvm_map.c	1 Nov 2006 10:18:27 -0000	1.232
+++ uvm/uvm_map.c	29 Jan 2007 18:59:02 -0000
@@ -87,6 +87,7 @@
 #include <sys/kernel.h>
 #include <sys/mount.h>
 #include <sys/vnode.h>
+#include <sys/kauth.h>
 
 #ifdef SYSVSHM
 #include <sys/shm.h>
@@ -1909,6 +1910,21 @@
 	}
 
  found:
+	/*
+	 * Mapping valid content to the NULL page can allow
+	 * exploits of NULL pointer references.
+	 *
+	 * Reject the attempt if NULL was not explicitly requested
+	 * or if the security model says so.
+	 */
+	if (hint == 0) {
+		if ((flags & UVM_FLAG_FIXED) == 0)
+			goto notfound;
+		if (kauth_authorize_system(kauth_cred_get(),
+		    KAUTH_SYSTEM_MAPNULL, 0, NULL, NULL, NULL))
+			goto notfound;
+	}
+
 	SAVE_HINT(map, map->hint, entry);
 	*result = hint;
 	UVMHIST_LOG(maphist,"<- got it!  (result=0x%x)", hint, 0,0,0);

--PNTmBPCT7hxwcZjr
Content-Type: text/plain; charset=us-ascii
Content-Disposition: attachment; filename="mapnull.c"

#include <sys/mman.h>
#include <errno.h>

int main(void)
{
	char *test = 0;
	
	mmap(0, 4096, PROT_READ, MAP_ANON | MAP_FIXED, -1, 0);

	return *test;
}

--PNTmBPCT7hxwcZjr--