diff options
| author | elad <elad@NetBSD.org> | 2007-11-21 22:49:05 +0000 |
|---|---|---|
| committer | elad <elad@NetBSD.org> | 2007-11-21 22:49:05 +0000 |
| commit | 6887492c261e6d27ac6fa6294fb8552ffcfd0c49 (patch) | |
| tree | 78d111bde1dabc4e6b5af527827c1adb7b37e3e1 /sys/secmodel/securelevel | |
| parent | e3e9b753513368b9a76956e04b089d78306a974d (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.securelevel | 5 | ||||
| -rw-r--r-- | sys/secmodel/securelevel/secmodel_securelevel.c | 558 | ||||
| -rw-r--r-- | sys/secmodel/securelevel/securelevel.h | 53 |
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_ */ |
