summaryrefslogtreecommitdiff
path: root/sys/secmodel/securelevel
diff options
context:
space:
mode:
authorelad <elad@NetBSD.org>2007-11-21 22:49:05 +0000
committerelad <elad@NetBSD.org>2007-11-21 22:49:05 +0000
commit6887492c261e6d27ac6fa6294fb8552ffcfd0c49 (patch)
tree78d111bde1dabc4e6b5af527827c1adb7b37e3e1 /sys/secmodel/securelevel
parente3e9b753513368b9a76956e04b089d78306a974d (diff)
Make securelevel a "secmodel" of its own.
While it's true that it's part of the traditional 4.4BSD security model, there may come a time where a different "primary" security model used for fine-grained privileges (ie., splitting root's responsibilities to various privileges that can be assigned) may want to still have a securelevel setting. Idea from Daniel Carosone: http://mail-index.netbsd.org/tech-security/2006/08/25/0001.html The location of the removed files, for reference, was: src/secmodel/bsd44/secmodel_bsd44_securelevel.c src/secmodel/bsd44/securelevel.h
Diffstat (limited to 'sys/secmodel/securelevel')
-rw-r--r--sys/secmodel/securelevel/files.securelevel5
-rw-r--r--sys/secmodel/securelevel/secmodel_securelevel.c558
-rw-r--r--sys/secmodel/securelevel/securelevel.h53
3 files changed, 616 insertions, 0 deletions
diff --git a/sys/secmodel/securelevel/files.securelevel b/sys/secmodel/securelevel/files.securelevel
new file mode 100644
index 00000000000..edaff734e7b
--- /dev/null
+++ b/sys/secmodel/securelevel/files.securelevel
@@ -0,0 +1,5 @@
+# $NetBSD: files.securelevel,v 1.1 2007/11/21 22:49:09 elad Exp $
+
+defflag secmodel_securelevel
+
+file secmodel/securelevel/secmodel_securelevel.c secmodel_securelevel
diff --git a/sys/secmodel/securelevel/secmodel_securelevel.c b/sys/secmodel/securelevel/secmodel_securelevel.c
new file mode 100644
index 00000000000..67d43e31e3c
--- /dev/null
+++ b/sys/secmodel/securelevel/secmodel_securelevel.c
@@ -0,0 +1,558 @@
+/* $NetBSD: secmodel_securelevel.c,v 1.1 2007/11/21 22:49:09 elad Exp $ */
+/*-
+ * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+/*
+ * This file contains kauth(9) listeners needed to implement the traditional
+ * NetBSD securelevel.
+ *
+ * The securelevel is a system-global indication on what operations are
+ * allowed or not. It affects all users, including root.
+ */
+
+#include <sys/cdefs.h>
+__KERNEL_RCSID(0, "$NetBSD: secmodel_securelevel.c,v 1.1 2007/11/21 22:49:09 elad Exp $");
+
+#ifdef _KERNEL_OPT
+#include "opt_insecure.h"
+#endif /* _KERNEL_OPT */
+
+#include <sys/types.h>
+#include <sys/param.h>
+#include <sys/kauth.h>
+
+#include <sys/conf.h>
+#include <sys/mount.h>
+#include <sys/sysctl.h>
+#include <sys/vnode.h>
+
+#include <miscfs/specfs/specdev.h>
+
+#include <secmodel/securelevel/securelevel.h>
+
+static int securelevel;
+
+static kauth_listener_t l_system, l_process, l_network, l_machdep, l_device;
+
+/*
+ * sysctl helper routine for securelevel. ensures that the value
+ * only rises unless the caller has pid 1 (assumed to be init).
+ */
+int
+secmodel_securelevel_sysctl(SYSCTLFN_ARGS)
+{
+ int newsecurelevel, error;
+ struct sysctlnode node;
+
+ newsecurelevel = securelevel;
+ node = *rnode;
+ node.sysctl_data = &newsecurelevel;
+ error = sysctl_lookup(SYSCTLFN_CALL(&node));
+ if (error || newp == NULL)
+ return (error);
+
+ if (newsecurelevel < securelevel && l && l->l_proc->p_pid != 1)
+ return (EPERM);
+
+ securelevel = newsecurelevel;
+
+ return (error);
+}
+
+void
+secmodel_securelevel_init(void)
+{
+#ifdef INSECURE
+ securelevel = -1;
+#else
+ securelevel = 0;
+#endif /* INSECURE */
+}
+
+SYSCTL_SETUP(sysctl_security_securelevel_setup,
+ "sysctl security securelevel setup")
+{
+ /*
+ * For compatibility, we create a kern.securelevel variable.
+ */
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT,
+ CTLTYPE_NODE, "kern", NULL,
+ NULL, 0, NULL, 0,
+ CTL_KERN, CTL_EOL);
+
+ sysctl_createv(clog, 0, NULL, NULL,
+ CTLFLAG_PERMANENT|CTLFLAG_READWRITE,
+ CTLTYPE_INT, "securelevel",
+ SYSCTL_DESCR("System security level"),
+ secmodel_securelevel_sysctl, 0, NULL, 0,
+ CTL_KERN, KERN_SECURELVL, CTL_EOL);
+}
+
+void
+secmodel_securelevel_start(void)
+{
+ l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM,
+ secmodel_securelevel_system_cb, NULL);
+ l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS,
+ secmodel_securelevel_process_cb, NULL);
+ l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK,
+ secmodel_securelevel_network_cb, NULL);
+ l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP,
+ secmodel_securelevel_machdep_cb, NULL);
+ l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE,
+ secmodel_securelevel_device_cb, NULL);
+}
+
+#if defined(_LKM)
+void
+secmodel_securelevel_stop(void)
+{
+ kauth_unlisten_scope(l_system);
+ kauth_unlisten_scope(l_process);
+ kauth_unlisten_scope(l_network);
+ kauth_unlisten_scope(l_machdep);
+ kauth_unlisten_scope(l_device);
+}
+#endif /* _LKM */
+
+/*
+ * kauth(9) listener
+ *
+ * Security model: Traditional NetBSD
+ * Scope: System
+ * Responsibility: Securelevel
+ */
+int
+secmodel_securelevel_system_cb(kauth_cred_t cred,
+ kauth_action_t action, void *cookie, void *arg0, void *arg1,
+ void *arg2, void *arg3)
+{
+ int result;
+ enum kauth_system_req req;
+
+ result = KAUTH_RESULT_DENY;
+ req = (enum kauth_system_req)arg0;
+
+ switch (action) {
+ case KAUTH_SYSTEM_CHSYSFLAGS:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_SYSTEM_TIME:
+ switch (req) {
+ case KAUTH_REQ_SYSTEM_TIME_BACKWARDS:
+ if (securelevel < 2)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+ break;
+
+ case KAUTH_SYSTEM_LKM:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_SYSTEM_MOUNT:
+ switch (req) {
+ case KAUTH_REQ_SYSTEM_MOUNT_NEW:
+ if (securelevel > 1)
+ break;
+
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_REQ_SYSTEM_MOUNT_UPDATE:
+ if (securelevel > 1) {
+ struct mount *mp = arg1;
+ u_long flags = (u_long)arg2;
+
+ /* Can only degrade from read/write to read-only. */
+ if (flags != (mp->mnt_flag | MNT_RDONLY | MNT_RELOAD |
+ MNT_FORCE | MNT_UPDATE))
+ break;
+ }
+
+ result = KAUTH_RESULT_ALLOW;
+
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ break;
+
+ case KAUTH_SYSTEM_SYSCTL:
+ switch (req) {
+ case KAUTH_REQ_SYSTEM_SYSCTL_ADD:
+ case KAUTH_REQ_SYSTEM_SYSCTL_DELETE:
+ case KAUTH_REQ_SYSTEM_SYSCTL_DESC:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+ break;
+
+ case KAUTH_SYSTEM_SETIDCORE:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_SYSTEM_DEBUG:
+ switch (req) {
+ case KAUTH_REQ_SYSTEM_DEBUG_IPKDB:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ return (result);
+}
+
+/*
+ * kauth(9) listener
+ *
+ * Security model: Traditional NetBSD
+ * Scope: Process
+ * Responsibility: Securelevel
+ */
+int
+secmodel_securelevel_process_cb(kauth_cred_t cred,
+ kauth_action_t action, void *cookie, void *arg0,
+ void *arg1, void *arg2, void *arg3)
+{
+ struct proc *p;
+ int result;
+
+ result = KAUTH_RESULT_DENY;
+ p = arg0;
+
+ switch (action) {
+ case KAUTH_PROCESS_CANPROCFS: {
+ enum kauth_process_req req;
+
+ req = (enum kauth_process_req)arg2;
+ switch (req) {
+ case KAUTH_REQ_PROCESS_CANPROCFS_READ:
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_REQ_PROCESS_CANPROCFS_RW:
+ case KAUTH_REQ_PROCESS_CANPROCFS_WRITE:
+ if ((p == initproc) && (securelevel > -1))
+ result = KAUTH_RESULT_DENY;
+ else
+ result = KAUTH_RESULT_ALLOW;
+
+ break;
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ break;
+ }
+
+ case KAUTH_PROCESS_CANPTRACE:
+ case KAUTH_PROCESS_CANSYSTRACE:
+ if ((p == initproc) && (securelevel >= 0)) {
+ result = KAUTH_RESULT_DENY;
+ break;
+ }
+
+ result = KAUTH_RESULT_ALLOW;
+
+ break;
+
+ case KAUTH_PROCESS_CORENAME:
+ if (securelevel < 2)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ return (result);
+}
+
+/*
+ * kauth(9) listener
+ *
+ * Security model: Traditional NetBSD
+ * Scope: Network
+ * Responsibility: Securelevel
+ */
+int
+secmodel_securelevel_network_cb(kauth_cred_t cred,
+ kauth_action_t action, void *cookie, void *arg0,
+ void *arg1, void *arg2, void *arg3)
+{
+ int result;
+ enum kauth_network_req req;
+
+ result = KAUTH_RESULT_DENY;
+ req = (enum kauth_network_req)arg0;
+
+ switch (action) {
+ case KAUTH_NETWORK_FIREWALL:
+ switch (req) {
+ case KAUTH_REQ_NETWORK_FIREWALL_FW:
+ case KAUTH_REQ_NETWORK_FIREWALL_NAT:
+ if (securelevel < 2)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+ break;
+
+ case KAUTH_NETWORK_FORWSRCRT:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ return (result);
+}
+
+/*
+ * kauth(9) listener
+ *
+ * Security model: Traditional NetBSD
+ * Scope: Machdep
+ * Responsibility: Securelevel
+ */
+int
+secmodel_securelevel_machdep_cb(kauth_cred_t cred,
+ kauth_action_t action, void *cookie, void *arg0,
+ void *arg1, void *arg2, void *arg3)
+{
+ int result;
+
+ result = KAUTH_RESULT_DENY;
+
+ switch (action) {
+ case KAUTH_MACHDEP_IOPERM_SET:
+ case KAUTH_MACHDEP_IOPL:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_MACHDEP_UNMANAGEDMEM:
+ if (securelevel <= 0)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ return (result);
+}
+
+/*
+ * kauth(9) listener
+ *
+ * Security model: Traditional NetBSD
+ * Scope: Device
+ * Responsibility: Securelevel
+ */
+int
+secmodel_securelevel_device_cb(kauth_cred_t cred,
+ kauth_action_t action, void *cookie, void *arg0,
+ void *arg1, void *arg2, void *arg3)
+{
+ int result;
+
+ result = KAUTH_RESULT_DENY;
+
+ switch (action) {
+ case KAUTH_DEVICE_RAWIO_SPEC: {
+ struct vnode *vp, *bvp;
+ enum kauth_device_req req;
+ dev_t dev;
+ int d_type;
+
+ req = (enum kauth_device_req)arg0;
+ vp = arg1;
+
+ KASSERT(vp != NULL);
+
+ dev = vp->v_un.vu_specinfo->si_rdev;
+ d_type = D_OTHER;
+ bvp = NULL;
+
+ /* Handle /dev/mem and /dev/kmem. */
+ if ((vp->v_type == VCHR) && iskmemdev(dev)) {
+ switch (req) {
+ case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
+ case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
+ if (securelevel < 1)
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ break;
+ }
+
+ switch (req) {
+ case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ:
+ result = KAUTH_RESULT_ALLOW;
+ break;
+
+ case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE:
+ case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW:
+ switch (vp->v_type) {
+ case VCHR: {
+ const struct cdevsw *cdev;
+
+ cdev = cdevsw_lookup(dev);
+ if (cdev != NULL) {
+ dev_t blkdev;
+
+ blkdev = devsw_chr2blk(dev);
+ if (blkdev != NODEV) {
+ vfinddev(blkdev, VBLK, &bvp);
+ if (bvp != NULL)
+ d_type = (cdev->d_flag
+ & D_TYPEMASK);
+ }
+ }
+
+ break;
+ }
+ case VBLK: {
+ const struct bdevsw *bdev;
+
+ bdev = bdevsw_lookup(dev);
+ if (bdev != NULL)
+ d_type = (bdev->d_flag & D_TYPEMASK);
+
+ bvp = vp;
+
+ break;
+ }
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ if (d_type != D_DISK) {
+ result = KAUTH_RESULT_ALLOW;
+ break;
+ }
+
+ /*
+ * XXX: This is bogus. We should be failing the request
+ * XXX: not only if this specific slice is mounted, but
+ * XXX: if it's on a disk with any other mounted slice.
+ */
+ if (vfs_mountedon(bvp) && (securelevel > 0))
+ break;
+
+ if (securelevel < 2)
+ result = KAUTH_RESULT_ALLOW;
+
+ break;
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ break;
+ }
+
+ case KAUTH_DEVICE_RAWIO_PASSTHRU: {
+ if (securelevel > 0) {
+ u_long bits;
+
+ bits = (u_long)arg0;
+
+ KASSERT(bits != 0);
+ KASSERT((bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_ALL) == 0);
+
+ if (bits & ~KAUTH_REQ_DEVICE_RAWIO_PASSTHRU_READCONF)
+ result = KAUTH_RESULT_DENY;
+ else
+ result = KAUTH_RESULT_ALLOW;
+ } else
+ result = KAUTH_RESULT_ALLOW;
+
+ break;
+ }
+
+ default:
+ result = KAUTH_RESULT_DEFER;
+ break;
+ }
+
+ return (result);
+}
diff --git a/sys/secmodel/securelevel/securelevel.h b/sys/secmodel/securelevel/securelevel.h
new file mode 100644
index 00000000000..f9f98f7f1fc
--- /dev/null
+++ b/sys/secmodel/securelevel/securelevel.h
@@ -0,0 +1,53 @@
+/* $NetBSD: securelevel.h,v 1.1 2007/11/21 22:49:09 elad Exp $ */
+/*-
+ * Copyright (c) 2006 Elad Efrat <elad@NetBSD.org>
+ * All rights reserved.
+ *
+ * Redistribution and use in source and binary forms, with or without
+ * modification, are permitted provided that the following conditions
+ * are met:
+ * 1. Redistributions of source code must retain the above copyright
+ * notice, this list of conditions and the following disclaimer.
+ * 2. Redistributions in binary form must reproduce the above copyright
+ * notice, this list of conditions and the following disclaimer in the
+ * documentation and/or other materials provided with the distribution.
+ * 3. The name of the author may not be used to endorse or promote products
+ * derived from this software without specific prior written permission.
+ *
+ * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
+ * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
+ * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
+ * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
+ * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
+ * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
+ * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
+ * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
+ * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
+ */
+
+#ifndef _SECMODEL_SECURELEVEL_SECURELEVEL_H_
+#define _SECMODEL_SECURELEVEL_SECURELEVEL_H_
+
+int secmodel_securelevel_sysctl(SYSCTLFN_PROTO);
+
+void secmodel_securelevel_init(void);
+void secmodel_securelevel_start(void);
+
+#if defined(_LKM)
+void secmodel_securelevel_stop(void);
+SYSCTL_SETUP_PROTO(sysctl_security_securelevel_setup);
+#endif /* _LKM */
+
+int secmodel_securelevel_system_cb(kauth_cred_t, kauth_action_t, void *,
+ void *, void *, void *, void *);
+int secmodel_securelevel_process_cb(kauth_cred_t, kauth_action_t, void *,
+ void *, void *, void *, void *);
+int secmodel_securelevel_network_cb(kauth_cred_t, kauth_action_t, void *,
+ void *, void *, void *, void *);
+int secmodel_securelevel_machdep_cb(kauth_cred_t, kauth_action_t, void *,
+ void *, void *, void *, void *);
+int secmodel_securelevel_device_cb(kauth_cred_t, kauth_action_t, void *,
+ void *, void *, void *, void *);
+
+#endif /* !_SECMODEL_SECURELEVEL_SECURELEVEL_H_ */