summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authordrochner <drochner@NetBSD.org>2010-02-18 14:57:01 +0000
committerdrochner <drochner@NetBSD.org>2010-02-18 14:57:01 +0000
commitdda500d0d8a5edd00a1ba42f05bfcdc646dbfc88 (patch)
tree0b7f4e774046e654dfdd9208b4e9af85f5769b8a
parentfe9cd1c415ddbf294f5edf31013ff5602fc0cde6 (diff)
Disable mapping of virtual address 0 by user programs per default.
This blocks an easy exploit of kernel bugs leading to dereference of a NULL pointer on some architectures (eg i386). The check can be disabled in various ways: -by CPP definitions in machine/types.h (portmaster's choice) -by a kernel config option USER_VA0_DISABLED_DEFAULT=0 -at runtime by sysctl vm.user_va0_disabled (cannot be cleared at securelevel>0)
-rw-r--r--sys/uvm/files.uvm3
-rw-r--r--sys/uvm/uvm_map.c63
2 files changed, 63 insertions, 3 deletions
diff --git a/sys/uvm/files.uvm b/sys/uvm/files.uvm
index 4d33c5b4a2c..4bfffb64ec6 100644
--- a/sys/uvm/files.uvm
+++ b/sys/uvm/files.uvm
@@ -1,4 +1,4 @@
-# $NetBSD: files.uvm,v 1.16 2009/10/21 21:12:07 rmind Exp $
+# $NetBSD: files.uvm,v 1.17 2010/02/18 14:57:01 drochner Exp $
#
# UVM options
@@ -10,6 +10,7 @@ defflag opt_readahead.h READAHEAD_STATS
defflag opt_ubc.h UBC_STATS
defparam opt_pagermap.h PAGER_MAP_SIZE
defflag PDPOLICY_CLOCKPRO
+defparam USER_VA0_DISABLED_DEFAULT
file uvm/uvm_amap.c
file uvm/uvm_anon.c
diff --git a/sys/uvm/uvm_map.c b/sys/uvm/uvm_map.c
index 797e2a17755..bf867eb5010 100644
--- a/sys/uvm/uvm_map.c
+++ b/sys/uvm/uvm_map.c
@@ -1,4 +1,4 @@
-/* $NetBSD: uvm_map.c,v 1.287 2010/02/08 19:02:33 joerg Exp $ */
+/* $NetBSD: uvm_map.c,v 1.288 2010/02/18 14:57:01 drochner Exp $ */
/*
* Copyright (c) 1997 Charles D. Cranor and Washington University.
@@ -71,7 +71,7 @@
*/
#include <sys/cdefs.h>
-__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.287 2010/02/08 19:02:33 joerg Exp $");
+__KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.288 2010/02/18 14:57:01 drochner Exp $");
#include "opt_ddb.h"
#include "opt_uvmhist.h"
@@ -89,6 +89,11 @@ __KERNEL_RCSID(0, "$NetBSD: uvm_map.c,v 1.287 2010/02/08 19:02:33 joerg Exp $");
#include <sys/vnode.h>
#include <sys/lockdebug.h>
#include <sys/atomic.h>
+#ifndef __USER_VA0_IS_SAFE
+#include <sys/sysctl.h>
+#include <sys/kauth.h>
+#include "opt_user_va0_disabled_default.h"
+#endif
#ifdef SYSVSHM
#include <sys/shm.h>
@@ -168,6 +173,17 @@ MALLOC_DEFINE(M_VMPMAP, "VM pmap", "VM pmap");
vaddr_t uvm_maxkaddr;
#endif
+#ifndef __USER_VA0_IS_SAFE
+#ifndef __USER_VA0_DISABLED_DEFAULT
+#define __USER_VA0_DISABLED_DEFAULT 1
+#endif
+#ifdef USER_VA0_DISABLED_DEFAULT /* kernel config option overrides */
+#undef __USER_VA0_DISABLED_DEFAULT
+#define __USER_VA0_DISABLED_DEFAULT USER_VA0_DISABLED_DEFAULT
+#endif
+static int user_va0_disabled = __USER_VA0_DISABLED_DEFAULT;
+#endif
+
/*
* macros
*/
@@ -1174,6 +1190,12 @@ uvm_map(struct vm_map *map, vaddr_t *startp /* IN/OUT */, vsize_t size,
KASSERT((flags & UVM_FLAG_QUANTUM) == 0 || VM_MAP_IS_KERNEL(map));
KASSERT((size & PAGE_MASK) == 0);
+#ifndef __USER_VA0_IS_SAFE
+ if ((flags & UVM_FLAG_FIXED) && *startp == 0 &&
+ !VM_MAP_IS_KERNEL(map) && user_va0_disabled)
+ return EACCES;
+#endif
+
/*
* for pager_map, allocate the new entry first to avoid sleeping
* for memory while we have the map locked.
@@ -5215,3 +5237,40 @@ uvm_whatis(uintptr_t addr, void (*pr)(const char *, ...))
}
#endif /* DDB || DEBUGPRINT */
+
+#ifndef __USER_VA0_IS_SAFE
+static int
+sysctl_user_va0_disabled(SYSCTLFN_ARGS)
+{
+ struct sysctlnode node;
+ int t, error;
+
+ node = *rnode;
+ node.sysctl_data = &t;
+ t = user_va0_disabled;
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error || newp == NULL)
+ return (error);
+
+ /* lower only at securelevel < 1 */
+ if (!t && user_va0_disabled &&
+ kauth_authorize_system(l->l_cred,
+ KAUTH_SYSTEM_CHSYSFLAGS /* XXX */, 0,
+ NULL, NULL, NULL))
+ return EPERM;
+
+ user_va0_disabled = !!t;
+ return 0;
+}
+
+SYSCTL_SETUP(sysctl_uvmmap_setup, "sysctl uvmmap setup")
+{
+
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "user_va0_disabled",
+ SYSCTL_DESCR("Disable VA 0"),
+ sysctl_user_va0_disabled, 0, &user_va0_disabled, 0,
+ CTL_VM, CTL_CREATE, CTL_EOL);
+}
+#endif