diff -r 915814194076 -r 8af5f55ad449 sys/conf/std --- a/sys/conf/std Fri Dec 04 18:00:12 2015 -0800 +++ b/sys/conf/std Fri Dec 04 23:28:39 2015 -0800 @@ -35,7 +35,7 @@ # # Security model. # -options secmodel_bsd44 # Traditional 4.4BSD security model +options secmodel_netbsd # Simplified flat security model # # Scheduling algorithm diff -r 915814194076 -r 8af5f55ad449 sys/secmodel/files.secmodel --- a/sys/secmodel/files.secmodel Fri Dec 04 18:00:12 2015 -0800 +++ b/sys/secmodel/files.secmodel Fri Dec 04 23:28:39 2015 -0800 @@ -3,31 +3,6 @@ file secmodel/secmodel.c # -# Traditional 4.4BSD - Superuser ("root" as effective user-id 0) +# Flattened security model for simplicity # -include "secmodel/suser/files.suser" - -# -# Traditional 4.4BSD - Securelevel -# -include "secmodel/securelevel/files.securelevel" - -# -# NetBSD Extensions -# -include "secmodel/extensions/files.extensions" - -# -# Traditional NetBSD (derived from 4.4BSD) -# -include "secmodel/bsd44/files.bsd44" - -# -# Sample overlay model on-top of the traditional one -# -include "secmodel/overlay/files.overlay" - -# -# Multi-position keylock -# -include "secmodel/keylock/files.keylock" +include "secmodel/netbsd/files.netbsd" diff -r 915814194076 -r 8af5f55ad449 sys/secmodel/netbsd/files.netbsd --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/secmodel/netbsd/files.netbsd Fri Dec 04 23:28:39 2015 -0800 @@ -0,0 +1,5 @@ +# $NetBSD: files.netbsd,v 1.1 2009/10/02 18:50:13 elad Exp $ + +defflag secmodel_netbsd + +file secmodel/netbsd/secmodel_netbsd.c secmodel_netbsd diff -r 915814194076 -r 8af5f55ad449 sys/secmodel/netbsd/secmodel_netbsd.c --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/secmodel/netbsd/secmodel_netbsd.c Fri Dec 04 23:28:39 2015 -0800 @@ -0,0 +1,1385 @@ +/* $NetBSD: secmodel_netbsd.c,v 1.42 2015/08/17 06:16:03 knakahara Exp $ */ +/*- + * Copyright (c) 2006 Elad Efrat + * 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 superuser access restrictions. + * + * There are two main resources a request can be issued to: user-owned and + * system owned. For the first, traditional Unix access checks are done, as + * well as superuser checks. If needed, the request context is examined before + * a decision is made. For the latter, usually only superuser checks are done + * as normal users are not allowed to access system resources. + */ + +#include +__KERNEL_RCSID(0, "$NetBSD: secmodel_netbsd.c,v 1.42 2015/08/17 06:16:03 knakahara Exp $"); + +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#include +#include + +MODULE(MODULE_CLASS_SECMODEL, netbsd, NULL); + +static int securelevel; + +static int dovfsusermount; +static int curtain; +static int user_set_cpu_affinity; + +static kauth_listener_t l_generic, l_system, l_process, l_network, l_machdep, + l_device, l_vnode; + +static secmodel_t netbsd_sm; +static struct sysctllog *netbsd_sysctl_log; + +/* + * Sysctl helper routine for securelevel. Ensures that the value only rises + * unless the caller is init. + */ +static 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_proc != initproc)) + return (EPERM); + + securelevel = newsecurelevel; + + return (error); +} + +static int +sysctl_netbsd_curtain_handler(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + int val, error; + + val = *(int *)rnode->sysctl_data; + + node = *rnode; + node.sysctl_data = &val; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return error; + + /* shortcut */ + if (val == *(int *)rnode->sysctl_data) + return 0; + + /* curtain cannot be disabled when securelevel is above 0 */ + if (val == 0 && securelevel > 0) { + return EPERM; + } + + *(int *)rnode->sysctl_data = val; + return 0; +} + +/* + * Generic sysctl extensions handler for user mount and set CPU affinity + * rights. Checks the following conditions: + * - setting value to 0 is always permitted (decrease user rights) + * - setting value != 0 is not permitted when securelevel is above 0 (increase + * user rights). + */ +static int +sysctl_netbsd_user_handler(SYSCTLFN_ARGS) +{ + struct sysctlnode node; + int val, error; + + val = *(int *)rnode->sysctl_data; + + node = *rnode; + node.sysctl_data = &val; + + error = sysctl_lookup(SYSCTLFN_CALL(&node)); + if (error || newp == NULL) + return error; + + /* shortcut */ + if (val == *(int *)rnode->sysctl_data) + return 0; + + /* we cannot grant more rights to users when securelevel is above 0 */ + if (val != 0 && securelevel > 0) { + return EPERM; + } + + *(int *)rnode->sysctl_data = val; + return 0; +} + +static bool +euid_is_root(kauth_cred_t cred) +{ + return kauth_cred_geteuid(cred) == 0; +} + +static int +netbsd_modcmd(modcmd_t cmd, void *arg) +{ + int error = 0; + + switch (cmd) { + case MODULE_CMD_INIT: + error = secmodel_register(&netbsd_sm, + SECMODEL_NETBSD_ID, SECMODEL_NETBSD_NAME, + NULL, NULL, NULL); + if (error != 0) + printf("netbsd_modcmd::init: secmodel_register " + "returned %d\n", error); + + secmodel_netbsd_init(); + secmodel_netbsd_start(); + sysctl_security_netbsd_setup(&netbsd_sysctl_log); + break; + + case MODULE_CMD_FINI: + sysctl_teardown(&netbsd_sysctl_log); + secmodel_netbsd_stop(); + + error = secmodel_deregister(netbsd_sm); + if (error != 0) + printf("netbsd_modcmd::fini: secmodel_deregister " + "returned %d\n", error); + + break; + + case MODULE_CMD_AUTOUNLOAD: + error = EPERM; + break; + + default: + error = ENOTTY; + break; + } + + return (error); +} + +/******************************************************************/ + +void +sysctl_security_netbsd_setup(struct sysctllog **clog) +{ + const struct sysctlnode *rnode, *rnode2; + + sysctl_createv(clog, 0, NULL, &rnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "models", NULL, + NULL, 0, NULL, 0, + CTL_SECURITY, CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, &rnode, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "netbsd", NULL, + NULL, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + + /* Compatibility: security.models.bsd44.curtain */ + sysctl_createv(clog, 0, &rnode2, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "curtain", + SYSCTL_DESCR("Curtain information about objects to "\ + "users not owning them."), + sysctl_netbsd_curtain_handler, 0, &curtain, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_STRING, "name", NULL, + NULL, 0, __UNCONST(SECMODEL_NETBSD_NAME), 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "usermount", + SYSCTL_DESCR("Whether unprivileged users may mount " + "filesystems"), + sysctl_netbsd_user_handler, 0, &dovfsusermount, 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."), + sysctl_netbsd_curtain_handler, 0, &curtain, 0, + CTL_CREATE, CTL_EOL); + + sysctl_createv(clog, 0, &rnode, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "user_set_cpu_affinity", + SYSCTL_DESCR("Whether unprivileged users may control "\ + "CPU affinity."), + sysctl_netbsd_user_handler, 0, + &user_set_cpu_affinity, 0, + CTL_CREATE, CTL_EOL); + + /* Compatibility: vfs.generic.usermount */ + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT, + CTLTYPE_NODE, "generic", + SYSCTL_DESCR("Non-specific vfs related information"), + NULL, 0, NULL, 0, + CTL_VFS, VFS_GENERIC, CTL_EOL); + + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "usermount", + SYSCTL_DESCR("Whether unprivileged users may mount " + "filesystems"), + sysctl_netbsd_user_handler, 0, &dovfsusermount, 0, + CTL_VFS, VFS_GENERIC, VFS_USERMOUNT, CTL_EOL); + + /* Compatibility: security.curtain */ + sysctl_createv(clog, 0, NULL, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "curtain", + SYSCTL_DESCR("Curtain information about objects to "\ + "users not owning them."), + sysctl_netbsd_curtain_handler, 0, &curtain, 0, + CTL_SECURITY, CTL_CREATE, CTL_EOL); + + /* Compatibility: security.models.bsd44.securelevel */ + sysctl_createv(clog, 0, &rnode2, NULL, + CTLFLAG_PERMANENT|CTLFLAG_READWRITE, + CTLTYPE_INT, "securelevel", + SYSCTL_DESCR("System security level"), + secmodel_securelevel_sysctl, 0, NULL, 0, + CTL_CREATE, CTL_EOL); + + /* Compatibility: kern.securelevel */ + 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_netbsd_init(void) +{ + curtain = 0; + user_set_cpu_affinity = 0; +#ifdef INSECURE + securelevel = -1; +#else + securelevel = 0; +#endif /* INSECURE */ +} + +void +secmodel_netbsd_start(void) +{ + l_generic = kauth_listen_scope(KAUTH_SCOPE_GENERIC, + secmodel_netbsd_generic_cb, NULL); + l_system = kauth_listen_scope(KAUTH_SCOPE_SYSTEM, + secmodel_netbsd_system_cb, NULL); + l_process = kauth_listen_scope(KAUTH_SCOPE_PROCESS, + secmodel_netbsd_process_cb, NULL); + l_network = kauth_listen_scope(KAUTH_SCOPE_NETWORK, + secmodel_netbsd_network_cb, NULL); + l_machdep = kauth_listen_scope(KAUTH_SCOPE_MACHDEP, + secmodel_netbsd_machdep_cb, NULL); + l_device = kauth_listen_scope(KAUTH_SCOPE_DEVICE, + secmodel_netbsd_device_cb, NULL); + l_vnode = kauth_listen_scope(KAUTH_SCOPE_VNODE, + secmodel_netbsd_vnode_cb, NULL); +} + +void +secmodel_netbsd_stop(void) +{ + kauth_unlisten_scope(l_generic); + 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); + kauth_unlisten_scope(l_vnode); +} + +/* + * kauth(9) listener + * + * Security model: Traditional NetBSD + * Scope: Generic + * Responsibility: Superuser access + */ +int +secmodel_netbsd_generic_cb(kauth_cred_t cred, kauth_action_t action, + void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) +{ + bool isroot; + int result; + + isroot = euid_is_root(cred); + result = KAUTH_RESULT_DEFER; + + switch (action) { + case KAUTH_GENERIC_ISSUSER: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + return (result); +} + +/* + * kauth(9) listener + * + * Security model: Traditional NetBSD + * Scope: System + * Responsibility: Superuser access + */ +int +secmodel_netbsd_system_cb(kauth_cred_t cred, kauth_action_t action, + void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) +{ + vnode_t *vp; + struct vattr va; + struct mount *mp; + unsigned long flags; + bool isroot; + int result; + enum kauth_system_req req; + int error; + + isroot = euid_is_root(cred); + result = KAUTH_RESULT_DEFER; + req = (enum kauth_system_req)arg0; + + switch (action) { + case KAUTH_SYSTEM_CPU: + switch (req) { + case KAUTH_REQ_SYSTEM_CPU_SETSTATE: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_DEVMAPPER: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + case KAUTH_SYSTEM_FS_QUOTA: + switch (req) { + case KAUTH_REQ_SYSTEM_FS_QUOTA_GET: + case KAUTH_REQ_SYSTEM_FS_QUOTA_ONOFF: + case KAUTH_REQ_SYSTEM_FS_QUOTA_MANAGE: + case KAUTH_REQ_SYSTEM_FS_QUOTA_NOLIMIT: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_SYSVIPC: + switch (req) { + case KAUTH_REQ_SYSTEM_SYSVIPC_BYPASS: + case KAUTH_REQ_SYSTEM_SYSVIPC_SHM_LOCK: + case KAUTH_REQ_SYSTEM_SYSVIPC_SHM_UNLOCK: + case KAUTH_REQ_SYSTEM_SYSVIPC_MSGQ_OVERSIZE: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_MOUNT: + switch (req) { + case KAUTH_REQ_SYSTEM_MOUNT_DEVICE: + case KAUTH_REQ_SYSTEM_MOUNT_GET: + case KAUTH_REQ_SYSTEM_MOUNT_UMAP: + if (isroot || dovfsusermount) { + result = KAUTH_RESULT_ALLOW; + break; + } + + break; + case KAUTH_REQ_SYSTEM_MOUNT_NEW: + if (securelevel > 1) { + result = KAUTH_RESULT_DENY; + break; + } + if (isroot) { + result = KAUTH_RESULT_ALLOW; + break; + } + if (!dovfsusermount) { + result = KAUTH_RESULT_ALLOW; + break; + } + vp = (vnode_t *)arg1; + mp = vp->v_mount; + flags = (u_long)arg2; + + /* + * Ensure that the user owns the directory onto which the + * mount is attempted. + */ + vn_lock(vp, LK_SHARED | LK_RETRY); + error = VOP_GETATTR(vp, &va, cred); + VOP_UNLOCK(vp); + if (error) + break; + + if (va.va_uid != kauth_cred_geteuid(cred)) + break; + + error = usermount_common_policy(mp, flags); + if (error) + break; + + result = KAUTH_RESULT_ALLOW; + + break; + + case KAUTH_REQ_SYSTEM_MOUNT_UNMOUNT: + if (isroot) { + result = KAUTH_RESULT_ALLOW; + break; + } + if (!dovfsusermount) { + result = KAUTH_RESULT_ALLOW; + break; + } + mp = arg1; + + /* Must own the mount. */ + if (mp->mnt_stat.f_owner == kauth_cred_geteuid(cred)) + result = KAUTH_RESULT_ALLOW; + + break; + + case KAUTH_REQ_SYSTEM_MOUNT_UPDATE: + if (securelevel > 1) { + mp = arg1; + 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)) { + result = KAUTH_RESULT_DENY; + break; + } + } + if (isroot) { + result = KAUTH_RESULT_ALLOW; + break; + } + if (!dovfsusermount) { + result = KAUTH_RESULT_ALLOW; + break; + } + + mp = arg1; + flags = (u_long)arg2; + + /* Must own the mount. */ + if (mp->mnt_stat.f_owner == kauth_cred_geteuid(cred) && + usermount_common_policy(mp, flags) == 0) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_MQUEUE: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + case KAUTH_SYSTEM_PSET: + switch (req) { + case KAUTH_REQ_SYSTEM_PSET_ASSIGN: + case KAUTH_REQ_SYSTEM_PSET_BIND: + case KAUTH_REQ_SYSTEM_PSET_CREATE: + case KAUTH_REQ_SYSTEM_PSET_DESTROY: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_TIME: + switch (req) { + case KAUTH_REQ_SYSTEM_TIME_ADJTIME: + case KAUTH_REQ_SYSTEM_TIME_NTPADJTIME: + case KAUTH_REQ_SYSTEM_TIME_TIMECOUNTERS: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + /* from securelevel */ + case KAUTH_REQ_SYSTEM_TIME_RTCOFFSET: + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + /* from securelevel */ + case KAUTH_REQ_SYSTEM_TIME_SYSTEM: { + struct timespec *ts = arg1; + struct timespec *delta = arg2; + + if (securelevel > 1 && time_wraps(ts, delta)) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + } + + default: + break; + } + break; + + case KAUTH_SYSTEM_SEMAPHORE: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + 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: + case KAUTH_REQ_SYSTEM_SYSCTL_MODIFY: + case KAUTH_REQ_SYSTEM_SYSCTL_PRVT: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_SWAPCTL: + case KAUTH_SYSTEM_ACCOUNTING: + case KAUTH_SYSTEM_REBOOT: + case KAUTH_SYSTEM_CHROOT: + case KAUTH_SYSTEM_FILEHANDLE: + case KAUTH_SYSTEM_MKNOD: + case KAUTH_SYSTEM_SETIDCORE: + case KAUTH_SYSTEM_MODULE: + case KAUTH_SYSTEM_FS_RESERVEDSPACE: + case KAUTH_SYSTEM_FS_EXTATTR: + case KAUTH_SYSTEM_FS_SNAPSHOT: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + case KAUTH_SYSTEM_MAP_VA_ZERO: + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_SYSTEM_DEBUG: + switch (req) { + case KAUTH_REQ_SYSTEM_DEBUG_IPKDB: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_CHSYSFLAGS: + /* Deprecated. */ + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_DENY; + + break; + + case KAUTH_SYSTEM_VERIEXEC: + switch (req) { + case KAUTH_REQ_SYSTEM_VERIEXEC_ACCESS: + case KAUTH_REQ_SYSTEM_VERIEXEC_MODIFY: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_LFS: + switch (req) { + case KAUTH_REQ_SYSTEM_LFS_MARKV: + case KAUTH_REQ_SYSTEM_LFS_BMAPV: + case KAUTH_REQ_SYSTEM_LFS_SEGCLEAN: + case KAUTH_REQ_SYSTEM_LFS_SEGWAIT: + case KAUTH_REQ_SYSTEM_LFS_FCNTL: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + default: + break; + } + + break; + + case KAUTH_SYSTEM_INTR: + switch (req) { + case KAUTH_REQ_SYSTEM_INTR_AFFINITY: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + default: + break; + } + + return (result); +} + +/* + * kauth(9) listener + * + * Security model: Traditional NetBSD + * Scope: Process + * Responsibility: Superuser access + */ +int +secmodel_netbsd_process_cb(kauth_cred_t cred, kauth_action_t action, + void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) +{ + enum kauth_process_req req; + struct proc *p; + bool isroot; + int result; + + isroot = euid_is_root(cred); + result = KAUTH_RESULT_DEFER; + + req = (enum kauth_process_req)arg2; + p = arg0; + + switch (action) { + case KAUTH_PROCESS_SIGNAL: + case KAUTH_PROCESS_KTRACE: + case KAUTH_PROCESS_SCHEDULER_GETPARAM: + case KAUTH_PROCESS_SCHEDULER_SETPARAM: + case KAUTH_PROCESS_SCHEDULER_GETAFFINITY: + case KAUTH_PROCESS_SCHEDULER_SETAFFINITY: + case KAUTH_PROCESS_SETID: + case KAUTH_PROCESS_KEVENT_FILTER: + case KAUTH_PROCESS_NICE: + case KAUTH_PROCESS_FORK: + case KAUTH_PROCESS_STOPFLAG: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + case KAUTH_PROCESS_PTRACE: + if ((p == initproc) && (securelevel > -1)) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + case KAUTH_PROCESS_PROCFS: + switch (req) { + case KAUTH_REQ_PROCESS_PROCFS_READ: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_REQ_PROCESS_PROCFS_RW: + case KAUTH_REQ_PROCESS_PROCFS_WRITE: + if ((p == initproc) && (securelevel > -1)) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + break; + + case KAUTH_PROCESS_CORENAME: + if (securelevel > 1) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_PROCESS_CANSEE: + switch (req) { + case KAUTH_REQ_PROCESS_CANSEE_ARGS: + case KAUTH_REQ_PROCESS_CANSEE_ENTRY: + case KAUTH_REQ_PROCESS_CANSEE_OPENFILES: + /* + * Only process' owner and root can see + * through curtain + */ + if (kauth_cred_uidmatch(cred, p->p_cred) || isroot) { + result = KAUTH_RESULT_ALLOW; + break; + } + + break; + + case KAUTH_REQ_PROCESS_CANSEE_ENV: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_PROCESS_RLIMIT: { + switch (req) { + case KAUTH_REQ_PROCESS_RLIMIT_SET: + case KAUTH_REQ_PROCESS_RLIMIT_GET: + case KAUTH_REQ_PROCESS_RLIMIT_BYPASS: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + } + + default: + break; + } + + return (result); +} + +/* + * kauth(9) listener + * + * Security model: Traditional NetBSD + * Scope: Network + * Responsibility: Superuser access + */ +int +secmodel_netbsd_network_cb(kauth_cred_t cred, kauth_action_t action, + void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) +{ + struct socket *so; + bool isroot; + int result; + enum kauth_network_req req; + + isroot = euid_is_root(cred); + result = KAUTH_RESULT_DEFER; + req = (enum kauth_network_req)arg0; + + switch (action) { + case KAUTH_NETWORK_ALTQ: + switch (req) { + case KAUTH_REQ_NETWORK_ALTQ_AFMAP: + case KAUTH_REQ_NETWORK_ALTQ_BLUE: + case KAUTH_REQ_NETWORK_ALTQ_CBQ: + case KAUTH_REQ_NETWORK_ALTQ_CDNR: + case KAUTH_REQ_NETWORK_ALTQ_CONF: + case KAUTH_REQ_NETWORK_ALTQ_FIFOQ: + case KAUTH_REQ_NETWORK_ALTQ_HFSC: + case KAUTH_REQ_NETWORK_ALTQ_JOBS: + case KAUTH_REQ_NETWORK_ALTQ_PRIQ: + case KAUTH_REQ_NETWORK_ALTQ_RED: + case KAUTH_REQ_NETWORK_ALTQ_RIO: + case KAUTH_REQ_NETWORK_ALTQ_WFQ: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_BIND: + switch (req) { + case KAUTH_REQ_NETWORK_BIND_PORT: + case KAUTH_REQ_NETWORK_BIND_PRIVPORT: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + break; + + case KAUTH_NETWORK_FIREWALL: + switch (req) { + case KAUTH_REQ_NETWORK_FIREWALL_FW: + case KAUTH_REQ_NETWORK_FIREWALL_NAT: + if (securelevel > 1) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + break; + + case KAUTH_NETWORK_FORWSRCRT: + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_NETWORK_ROUTE: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + case KAUTH_NETWORK_INTERFACE: + switch (req) { + case KAUTH_REQ_NETWORK_INTERFACE_GET: + case KAUTH_REQ_NETWORK_INTERFACE_SET: + case KAUTH_REQ_NETWORK_INTERFACE_GETPRIV: + case KAUTH_REQ_NETWORK_INTERFACE_SETPRIV: + case KAUTH_REQ_NETWORK_INTERFACE_FIRMWARE: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + break; + + case KAUTH_NETWORK_INTERFACE_BRIDGE: + switch (req) { + case KAUTH_REQ_NETWORK_INTERFACE_BRIDGE_GETPRIV: + case KAUTH_REQ_NETWORK_INTERFACE_BRIDGE_SETPRIV: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_INTERFACE_PPP: + switch (req) { + case KAUTH_REQ_NETWORK_INTERFACE_PPP_ADD: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_INTERFACE_PVC: + switch (req) { + case KAUTH_REQ_NETWORK_INTERFACE_PVC_ADD: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_INTERFACE_SLIP: + switch (req) { + case KAUTH_REQ_NETWORK_INTERFACE_SLIP_ADD: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_INTERFACE_STRIP: + switch (req) { + case KAUTH_REQ_NETWORK_INTERFACE_STRIP_ADD: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_INTERFACE_TUN: + switch (req) { + case KAUTH_REQ_NETWORK_INTERFACE_TUN_ADD: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_IPV6: + switch (req) { + case KAUTH_REQ_NETWORK_IPV6_HOPBYHOP: + case KAUTH_REQ_NETWORK_IPV6_JOIN_MULTICAST: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_NFS: + switch (req) { + case KAUTH_REQ_NETWORK_NFS_EXPORT: + case KAUTH_REQ_NETWORK_NFS_SVC: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + break; + + case KAUTH_NETWORK_SMB: + switch (req) { + case KAUTH_REQ_NETWORK_SMB_SHARE_ACCESS: + case KAUTH_REQ_NETWORK_SMB_SHARE_CREATE: + case KAUTH_REQ_NETWORK_SMB_VC_ACCESS: + case KAUTH_REQ_NETWORK_SMB_VC_CREATE: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_SOCKET: + switch (req) { + case KAUTH_REQ_NETWORK_SOCKET_DROP: + case KAUTH_REQ_NETWORK_SOCKET_OPEN: + case KAUTH_REQ_NETWORK_SOCKET_RAWSOCK: + case KAUTH_REQ_NETWORK_SOCKET_SETPRIV: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_REQ_NETWORK_SOCKET_CANSEE: + so = (struct socket *)arg1; + + if (__predict_false(so == NULL || so->so_cred == NULL)) + return KAUTH_RESULT_DENY; + + if (isroot) { + result = KAUTH_RESULT_ALLOW; + break; + } + + break; + + default: + break; + } + + break; + + case KAUTH_NETWORK_IPSEC: + switch (req) { + case KAUTH_REQ_NETWORK_IPSEC_BYPASS: + if (isroot) + result = KAUTH_RESULT_ALLOW; + + break; + + default: + break; + } + + break; + + default: + break; + } + + return (result); +} + +/* + * kauth(9) listener + * + * Security model: Traditional NetBSD + * Scope: Machdep + * Responsibility: Superuser access + */ +int +secmodel_netbsd_machdep_cb(kauth_cred_t cred, kauth_action_t action, + void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) +{ + bool isroot; + int result; + + isroot = euid_is_root(cred); + result = KAUTH_RESULT_DEFER; + + switch (action) { + case KAUTH_MACHDEP_IOPERM_GET: + case KAUTH_MACHDEP_LDT_GET: + case KAUTH_MACHDEP_LDT_SET: + case KAUTH_MACHDEP_MTRR_GET: + case KAUTH_MACHDEP_CACHEFLUSH: + case KAUTH_MACHDEP_IOPERM_SET: + case KAUTH_MACHDEP_MTRR_SET: + case KAUTH_MACHDEP_NVRAM: + case KAUTH_MACHDEP_PXG: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_MACHDEP_IOPL: + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_MACHDEP_UNMANAGEDMEM: + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_MACHDEP_CPU_UCODE_APPLY: + if (securelevel > 1) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + return (result); +} + +/* + * kauth(9) listener + * + * Security model: Traditional NetBSD + * Scope: Device + * Responsibility: Superuser access + */ +int +secmodel_netbsd_device_cb(kauth_cred_t cred, kauth_action_t action, + void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) +{ + bool isroot; + int result; + + isroot = euid_is_root(cred); + result = KAUTH_RESULT_DEFER; + + switch (action) { + case KAUTH_DEVICE_BLUETOOTH_SETPRIV: + case KAUTH_DEVICE_BLUETOOTH_SEND: + case KAUTH_DEVICE_BLUETOOTH_RECV: + case KAUTH_DEVICE_TTY_OPEN: + case KAUTH_DEVICE_TTY_PRIVSET: + case KAUTH_DEVICE_TTY_STI: + case KAUTH_DEVICE_TTY_VIRTUAL: + case KAUTH_DEVICE_RND_ADDDATA: + case KAUTH_DEVICE_RND_GETPRIV: + case KAUTH_DEVICE_RND_SETPRIV: + case KAUTH_DEVICE_WSCONS_KEYBOARD_BELL: + case KAUTH_DEVICE_WSCONS_KEYBOARD_KEYREPEAT: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_DEVICE_BLUETOOTH_BCSP: + case KAUTH_DEVICE_BLUETOOTH_BTUART: { + enum kauth_device_req req; + + req = (enum kauth_device_req)arg0; + switch (req) { + case KAUTH_REQ_DEVICE_BLUETOOTH_BCSP_ADD: + case KAUTH_REQ_DEVICE_BLUETOOTH_BTUART_ADD: + if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + break; + } + + case KAUTH_DEVICE_RAWIO_SPEC: { + struct vnode *vp; + enum kauth_device_req req; + + req = (enum kauth_device_req)arg0; + vp = arg1; + + KASSERT(vp != NULL); + + /* Handle /dev/mem and /dev/kmem. */ + if (iskmemvp(vp)) { + switch (req) { + case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: + break; + + case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: + case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + + break; + + default: + break; + } + + break; + } + + switch (req) { + case KAUTH_REQ_DEVICE_RAWIO_SPEC_READ: + break; + + case KAUTH_REQ_DEVICE_RAWIO_SPEC_WRITE: + case KAUTH_REQ_DEVICE_RAWIO_SPEC_RW: { + int error; + + error = rawdev_mounted(vp, NULL); + + /* Not a disk. */ + if (error == EINVAL) + break; + + if (error && securelevel > 0) + result = KAUTH_RESULT_DENY; + + if (securelevel > 1) + result = KAUTH_RESULT_DENY; + + break; + } + + default: + 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; + } + + break; + + case KAUTH_DEVICE_GPIO_PINSET: + /* + * root can access gpio pins, secmodel_securlevel can veto + * this decision. + */ + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + case KAUTH_DEVICE_RND_ADDDATA_ESTIMATE: + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + else if (isroot) + result = KAUTH_RESULT_ALLOW; + break; + + default: + break; + } + + return (result); +} + +int +secmodel_netbsd_vnode_cb(kauth_cred_t cred, kauth_action_t action, + void *cookie, void *arg0, void *arg1, void *arg2, void *arg3) +{ + bool isroot; + int result; + + isroot = euid_is_root(cred); + result = KAUTH_RESULT_DEFER; + + /* XXX - agc - are these flags right? */ + if ((action & KAUTH_VNODE_WRITE_SYSFLAGS) && + (action & KAUTH_VNODE_HAS_SYSFLAGS)) { + if (securelevel > 0) + result = KAUTH_RESULT_DENY; + } else if (isroot) { + /* Superuser can execute only if the file's executable. */ + if ((action & KAUTH_VNODE_EXECUTE) == 0 || + (action & KAUTH_VNODE_IS_EXEC)) + result = KAUTH_RESULT_ALLOW; + } + + return (result); +} + diff -r 915814194076 -r 8af5f55ad449 sys/secmodel/netbsd/secmodel_netbsd.h --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/sys/secmodel/netbsd/secmodel_netbsd.h Fri Dec 04 23:28:39 2015 -0800 @@ -0,0 +1,56 @@ +/* $NetBSD: netbsd.h,v 1.2 2011/12/04 19:25:01 jym Exp $ */ +/*- + * Copyright (c) 2006 Elad Efrat + * 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_NETBSD_NETBSD_H_ +#define _SECMODEL_NETBSD_NETBSD_H_ + +#define SECMODEL_NETBSD_ID "org.netbsd.secmodel.netbsd" +#define SECMODEL_NETBSD_NAME "Traditional NetBSD: Superuser" + +void secmodel_netbsd_init(void); +void secmodel_netbsd_start(void); +void secmodel_netbsd_stop(void); + +void sysctl_security_netbsd_setup(struct sysctllog **); + +int secmodel_netbsd_generic_cb(kauth_cred_t, kauth_action_t, void *, + void *, void *, void *, void *); +int secmodel_netbsd_system_cb(kauth_cred_t, kauth_action_t, void *, + void *, void *, void *, void *); +int secmodel_netbsd_process_cb(kauth_cred_t, kauth_action_t, void *, + void *, void *, void *, void *); +int secmodel_netbsd_network_cb(kauth_cred_t, kauth_action_t, void *, + void *, void *, void *, void *); +int secmodel_netbsd_machdep_cb(kauth_cred_t, kauth_action_t, void *, + void *, void *, void *, void *); +int secmodel_netbsd_device_cb(kauth_cred_t, kauth_action_t, void *, + void *, void *, void *, void *); +int secmodel_netbsd_vnode_cb(kauth_cred_t, kauth_action_t, void *, + void *, void *, void *, void *); + +#endif /* !_SECMODEL_NETBSD_NETBSD_H_ */