17bc82500SRobert Watson /*- 291ec0006SRobert Watson * Copyright (c) 1999-2002, 2006, 2009 Robert N. M. Watson 37bc82500SRobert Watson * Copyright (c) 2001 Ilmar S. Habibulin 4f0c2044bSRobert Watson * Copyright (c) 2001-2005 Networks Associates Technology, Inc. 5aed55708SRobert Watson * Copyright (c) 2005-2006 SPARTA, Inc. 69162f64bSRobert Watson * Copyright (c) 2008-2009 Apple Inc. 77bc82500SRobert Watson * All rights reserved. 87bc82500SRobert Watson * 97bc82500SRobert Watson * This software was developed by Robert Watson and Ilmar Habibulin for the 107bc82500SRobert Watson * TrustedBSD Project. 117bc82500SRobert Watson * 126201265bSRobert Watson * This software was developed for the FreeBSD Project in part by Network 136201265bSRobert Watson * Associates Laboratories, the Security Research Division of Network 146201265bSRobert Watson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 156201265bSRobert Watson * as part of the DARPA CHATS research program. 167bc82500SRobert Watson * 1749bb6870SRobert Watson * This software was enhanced by SPARTA ISSO under SPAWAR contract 1849bb6870SRobert Watson * N66001-04-C-6019 ("SEFOS"). 1949bb6870SRobert Watson * 207bc82500SRobert Watson * Redistribution and use in source and binary forms, with or without 217bc82500SRobert Watson * modification, are permitted provided that the following conditions 227bc82500SRobert Watson * are met: 237bc82500SRobert Watson * 1. Redistributions of source code must retain the above copyright 247bc82500SRobert Watson * notice, this list of conditions and the following disclaimer. 257bc82500SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 267bc82500SRobert Watson * notice, this list of conditions and the following disclaimer in the 277bc82500SRobert Watson * documentation and/or other materials provided with the distribution. 287bc82500SRobert Watson * 297bc82500SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 307bc82500SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 317bc82500SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 327bc82500SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 337bc82500SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 347bc82500SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 357bc82500SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 367bc82500SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 377bc82500SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 387bc82500SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 397bc82500SRobert Watson * SUCH DAMAGE. 407bc82500SRobert Watson */ 41677b542eSDavid E. O'Brien 42c8e7bf92SRobert Watson /*- 43471e5756SRobert Watson * Framework for extensible kernel access control. This file contains core 44471e5756SRobert Watson * kernel infrastructure for the TrustedBSD MAC Framework, including policy 45471e5756SRobert Watson * registration, versioning, locking, error composition operator, and system 46471e5756SRobert Watson * calls. 47471e5756SRobert Watson * 48471e5756SRobert Watson * The MAC Framework implements three programming interfaces: 49471e5756SRobert Watson * 50471e5756SRobert Watson * - The kernel MAC interface, defined in mac_framework.h, and invoked 51471e5756SRobert Watson * throughout the kernel to request security decisions, notify of security 52471e5756SRobert Watson * related events, etc. 53471e5756SRobert Watson * 54471e5756SRobert Watson * - The MAC policy module interface, defined in mac_policy.h, which is 55471e5756SRobert Watson * implemented by MAC policy modules and invoked by the MAC Framework to 56471e5756SRobert Watson * forward kernel security requests and notifications to policy modules. 57471e5756SRobert Watson * 58471e5756SRobert Watson * - The user MAC API, defined in mac.h, which allows user programs to query 59471e5756SRobert Watson * and set label state on objects. 60471e5756SRobert Watson * 61471e5756SRobert Watson * The majority of the MAC Framework implementation may be found in 62471e5756SRobert Watson * src/sys/security/mac. Sample policy modules may be found in 6349869305STom Rhodes * src/sys/security/mac_*. 647bc82500SRobert Watson */ 657bc82500SRobert Watson 6691ec0006SRobert Watson #include "opt_kdtrace.h" 6739b73a30SRobert Watson #include "opt_mac.h" 6839b73a30SRobert Watson 69677b542eSDavid E. O'Brien #include <sys/cdefs.h> 70677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 71677b542eSDavid E. O'Brien 727bc82500SRobert Watson #include <sys/param.h> 73a96acd1aSRobert Watson #include <sys/condvar.h> 7495fab37eSRobert Watson #include <sys/kernel.h> 7595fab37eSRobert Watson #include <sys/lock.h> 7695fab37eSRobert Watson #include <sys/mutex.h> 7795fab37eSRobert Watson #include <sys/mac.h> 787ba28492SRobert Watson #include <sys/module.h> 7991ec0006SRobert Watson #include <sys/sdt.h> 8095fab37eSRobert Watson #include <sys/systm.h> 8195fab37eSRobert Watson #include <sys/sysctl.h> 8295fab37eSRobert Watson 83aed55708SRobert Watson #include <security/mac/mac_framework.h> 846fa0475dSRobert Watson #include <security/mac/mac_internal.h> 850efd6615SRobert Watson #include <security/mac/mac_policy.h> 866fa0475dSRobert Watson 877ba28492SRobert Watson /* 882087a58cSRobert Watson * DTrace SDT providers for MAC. 8991ec0006SRobert Watson */ 9091ec0006SRobert Watson SDT_PROVIDER_DEFINE(mac); 912087a58cSRobert Watson SDT_PROVIDER_DEFINE(mac_framework); 922087a58cSRobert Watson 9373e416e3SRobert Watson SDT_PROBE_DEFINE2(mac, kernel, policy, modevent, "int", 9491ec0006SRobert Watson "struct mac_policy_conf *mpc"); 9573e416e3SRobert Watson SDT_PROBE_DEFINE1(mac, kernel, policy, register, "struct mac_policy_conf *"); 9673e416e3SRobert Watson SDT_PROBE_DEFINE1(mac, kernel, policy, unregister, "struct mac_policy_conf *"); 9791ec0006SRobert Watson 9891ec0006SRobert Watson /* 99471e5756SRobert Watson * Root sysctl node for all MAC and MAC policy controls. 1007ba28492SRobert Watson */ 10195fab37eSRobert Watson SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, 10295fab37eSRobert Watson "TrustedBSD MAC policy controls"); 103b2f0927aSRobert Watson 10417041e67SRobert Watson /* 105471e5756SRobert Watson * Declare that the kernel provides MAC support, version 3 (FreeBSD 7.x). 106471e5756SRobert Watson * This permits modules to refuse to be loaded if the necessary support isn't 107471e5756SRobert Watson * present, even if it's pre-boot. 108471e5756SRobert Watson */ 109471e5756SRobert Watson MODULE_VERSION(kernel_mac_support, MAC_VERSION); 110be23ba9aSRobert Watson 111be23ba9aSRobert Watson static unsigned int mac_version = MAC_VERSION; 112471e5756SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, version, CTLFLAG_RD, &mac_version, 0, 113471e5756SRobert Watson ""); 114471e5756SRobert Watson 115471e5756SRobert Watson /* 11617041e67SRobert Watson * Labels consist of a indexed set of "slots", which are allocated policies 11717041e67SRobert Watson * as required. The MAC Framework maintains a bitmask of slots allocated so 11817041e67SRobert Watson * far to prevent reuse. Slots cannot be reused, as the MAC Framework 11917041e67SRobert Watson * guarantees that newly allocated slots in labels will be NULL unless 12017041e67SRobert Watson * otherwise initialized, and because we do not have a mechanism to garbage 12117041e67SRobert Watson * collect slots on policy unload. As labeled policies tend to be statically 12217041e67SRobert Watson * loaded during boot, and not frequently unloaded and reloaded, this is not 12317041e67SRobert Watson * generally an issue. 12417041e67SRobert Watson */ 125b2aef571SRobert Watson #if MAC_MAX_SLOTS > 32 126b2aef571SRobert Watson #error "MAC_MAX_SLOTS too large" 12795fab37eSRobert Watson #endif 128a13c67daSRobert Watson 129b2aef571SRobert Watson static unsigned int mac_max_slots = MAC_MAX_SLOTS; 130b2aef571SRobert Watson static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1; 131471e5756SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, &mac_max_slots, 132471e5756SRobert Watson 0, ""); 13395fab37eSRobert Watson 134a67fe518SRobert Watson /* 135a67fe518SRobert Watson * Has the kernel started generating labeled objects yet? All read/write 136a67fe518SRobert Watson * access to this variable is serialized during the boot process. Following 137a67fe518SRobert Watson * the end of serialization, we don't update this flag; no locking. 138a67fe518SRobert Watson */ 139be23ba9aSRobert Watson static int mac_late = 0; 140763bbd2fSRobert Watson 141225bff6fSRobert Watson /* 1426356dba0SRobert Watson * Each policy declares a mask of object types requiring labels to be 1436356dba0SRobert Watson * allocated for them. For convenience, we combine and cache the bitwise or 1446356dba0SRobert Watson * of the per-policy object flags to track whether we will allocate a label 1456356dba0SRobert Watson * for an object type at run-time. 146225bff6fSRobert Watson */ 1476356dba0SRobert Watson uint64_t mac_labeled; 1486356dba0SRobert Watson SYSCTL_QUAD(_security_mac, OID_AUTO, labeled, CTLFLAG_RD, &mac_labeled, 0, 1496356dba0SRobert Watson "Mask of object types being labeled"); 150225bff6fSRobert Watson 151f7b951a8SRobert Watson MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 15295fab37eSRobert Watson 15395fab37eSRobert Watson /* 15417041e67SRobert Watson * mac_static_policy_list holds a list of policy modules that are not loaded 15517041e67SRobert Watson * while the system is "live", and cannot be unloaded. These policies can be 15617041e67SRobert Watson * invoked without holding the busy count. 15741a17fe3SRobert Watson * 15841a17fe3SRobert Watson * mac_policy_list stores the list of dynamic policies. A busy count is 15917041e67SRobert Watson * maintained for the list, stored in mac_policy_busy. The busy count is 16017041e67SRobert Watson * protected by mac_policy_mtx; the list may be modified only while the busy 16117041e67SRobert Watson * count is 0, requiring that the lock be held to prevent new references to 16217041e67SRobert Watson * the list from being acquired. For almost all operations, incrementing the 16317041e67SRobert Watson * busy count is sufficient to guarantee consistency, as the list cannot be 16417041e67SRobert Watson * modified while the busy count is elevated. For a few special operations 16517041e67SRobert Watson * involving a change to the list of active policies, the mtx itself must be 16617041e67SRobert Watson * held. A condition variable, mac_policy_cv, is used to signal potential 16717041e67SRobert Watson * exclusive consumers that they should try to acquire the lock if a first 16817041e67SRobert Watson * attempt at exclusive access fails. 16917041e67SRobert Watson * 17017041e67SRobert Watson * This design intentionally avoids fairness, and may starve attempts to 17117041e67SRobert Watson * acquire an exclusive lock on a busy system. This is required because we 17217041e67SRobert Watson * do not ever want acquiring a read reference to perform an unbounded length 17317041e67SRobert Watson * sleep. Read references are acquired in ithreads, network isrs, etc, and 17417041e67SRobert Watson * any unbounded blocking could lead quickly to deadlock. 17517041e67SRobert Watson * 17617041e67SRobert Watson * Another reason for never blocking on read references is that the MAC 17717041e67SRobert Watson * Framework may recurse: if a policy calls a VOP, for example, this might 17817041e67SRobert Watson * lead to vnode life cycle operations (such as init/destroy). 179471e5756SRobert Watson * 180471e5756SRobert Watson * If the kernel option MAC_STATIC has been compiled in, all locking becomes 181471e5756SRobert Watson * a no-op, and the global list of policies is not allowed to change after 182471e5756SRobert Watson * early boot. 183989d4098SRobert Watson * 184989d4098SRobert Watson * XXXRW: Currently, we signal mac_policy_cv every time the framework becomes 185989d4098SRobert Watson * unbusy and there is a thread waiting to enter it exclusively. Since it 186989d4098SRobert Watson * may take some time before the thread runs, we may issue a lot of signals. 187989d4098SRobert Watson * We should instead keep track of the fact that we've signalled, taking into 188989d4098SRobert Watson * account that the framework may be busy again by the time the thread runs, 189989d4098SRobert Watson * requiring us to re-signal. 19095fab37eSRobert Watson */ 1910a05006dSRobert Watson #ifndef MAC_STATIC 19241a17fe3SRobert Watson static struct mtx mac_policy_mtx; 19341a17fe3SRobert Watson static struct cv mac_policy_cv; 19441a17fe3SRobert Watson static int mac_policy_count; 195989d4098SRobert Watson static int mac_policy_wait; 1960a05006dSRobert Watson #endif 197089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list; 198089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list; 199a96acd1aSRobert Watson 200a96acd1aSRobert Watson /* 20117041e67SRobert Watson * We manually invoke WITNESS_WARN() to allow Witness to generate warnings 20217041e67SRobert Watson * even if we don't end up ever triggering the wait at run-time. The 20317041e67SRobert Watson * consumer of the exclusive interface must not hold any locks (other than 20417041e67SRobert Watson * potentially Giant) since we may sleep for long (potentially indefinite) 20517041e67SRobert Watson * periods of time waiting for the framework to become quiescent so that a 20617041e67SRobert Watson * policy list change may be made. 207a96acd1aSRobert Watson */ 208089c1bdaSRobert Watson void 20941a17fe3SRobert Watson mac_policy_grab_exclusive(void) 21041a17fe3SRobert Watson { 211c8e7bf92SRobert Watson 2120a05006dSRobert Watson #ifndef MAC_STATIC 2131e4cadcbSRobert Watson if (!mac_late) 2141e4cadcbSRobert Watson return; 2151e4cadcbSRobert Watson 21641a17fe3SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 21741a17fe3SRobert Watson "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); 21841a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 219989d4098SRobert Watson while (mac_policy_count != 0) { 220989d4098SRobert Watson mac_policy_wait++; 22141a17fe3SRobert Watson cv_wait(&mac_policy_cv, &mac_policy_mtx); 222989d4098SRobert Watson mac_policy_wait--; 223989d4098SRobert Watson } 2240a05006dSRobert Watson #endif 22541a17fe3SRobert Watson } 22695fab37eSRobert Watson 227089c1bdaSRobert Watson void 22841a17fe3SRobert Watson mac_policy_assert_exclusive(void) 22941a17fe3SRobert Watson { 230c8e7bf92SRobert Watson 2310a05006dSRobert Watson #ifndef MAC_STATIC 2321e4cadcbSRobert Watson if (!mac_late) 2331e4cadcbSRobert Watson return; 2341e4cadcbSRobert Watson 23541a17fe3SRobert Watson mtx_assert(&mac_policy_mtx, MA_OWNED); 23641a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 23741a17fe3SRobert Watson ("mac_policy_assert_exclusive(): not exclusive")); 2380a05006dSRobert Watson #endif 23941a17fe3SRobert Watson } 240225bff6fSRobert Watson 241089c1bdaSRobert Watson void 24241a17fe3SRobert Watson mac_policy_release_exclusive(void) 24341a17fe3SRobert Watson { 2440a05006dSRobert Watson #ifndef MAC_STATIC 245989d4098SRobert Watson int dowakeup; 246989d4098SRobert Watson 2471e4cadcbSRobert Watson if (!mac_late) 2481e4cadcbSRobert Watson return; 2491e4cadcbSRobert Watson 25041a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 25141a17fe3SRobert Watson ("mac_policy_release_exclusive(): not exclusive")); 252989d4098SRobert Watson dowakeup = (mac_policy_wait != 0); 25341a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 254989d4098SRobert Watson if (dowakeup) 25541a17fe3SRobert Watson cv_signal(&mac_policy_cv); 2560a05006dSRobert Watson #endif 25741a17fe3SRobert Watson } 25841a17fe3SRobert Watson 259089c1bdaSRobert Watson void 26041a17fe3SRobert Watson mac_policy_list_busy(void) 26141a17fe3SRobert Watson { 262c8e7bf92SRobert Watson 2630a05006dSRobert Watson #ifndef MAC_STATIC 2641e4cadcbSRobert Watson if (!mac_late) 2651e4cadcbSRobert Watson return; 2661e4cadcbSRobert Watson 26741a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 26841a17fe3SRobert Watson mac_policy_count++; 26941a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 2700a05006dSRobert Watson #endif 27141a17fe3SRobert Watson } 27241a17fe3SRobert Watson 273089c1bdaSRobert Watson int 27441a17fe3SRobert Watson mac_policy_list_conditional_busy(void) 27541a17fe3SRobert Watson { 2760a05006dSRobert Watson #ifndef MAC_STATIC 27741a17fe3SRobert Watson int ret; 27841a17fe3SRobert Watson 2791e4cadcbSRobert Watson if (!mac_late) 2801e4cadcbSRobert Watson return (1); 2811e4cadcbSRobert Watson 28241a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 28341a17fe3SRobert Watson if (!LIST_EMPTY(&mac_policy_list)) { 28441a17fe3SRobert Watson mac_policy_count++; 28541a17fe3SRobert Watson ret = 1; 28641a17fe3SRobert Watson } else 28741a17fe3SRobert Watson ret = 0; 28841a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 28941a17fe3SRobert Watson return (ret); 2900a05006dSRobert Watson #else 2910a05006dSRobert Watson return (1); 2920a05006dSRobert Watson #endif 29341a17fe3SRobert Watson } 29441a17fe3SRobert Watson 295089c1bdaSRobert Watson void 29641a17fe3SRobert Watson mac_policy_list_unbusy(void) 29741a17fe3SRobert Watson { 2980a05006dSRobert Watson #ifndef MAC_STATIC 299989d4098SRobert Watson int dowakeup; 300989d4098SRobert Watson 3011e4cadcbSRobert Watson if (!mac_late) 3021e4cadcbSRobert Watson return; 3031e4cadcbSRobert Watson 30441a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 30541a17fe3SRobert Watson mac_policy_count--; 30641a17fe3SRobert Watson KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); 307989d4098SRobert Watson dowakeup = (mac_policy_count == 0 && mac_policy_wait != 0); 30841a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 309989d4098SRobert Watson 310989d4098SRobert Watson if (dowakeup) 311989d4098SRobert Watson cv_signal(&mac_policy_cv); 3120a05006dSRobert Watson #endif 31341a17fe3SRobert Watson } 31495fab37eSRobert Watson 31595fab37eSRobert Watson /* 31695fab37eSRobert Watson * Initialize the MAC subsystem, including appropriate SMP locks. 31795fab37eSRobert Watson */ 31895fab37eSRobert Watson static void 31995fab37eSRobert Watson mac_init(void) 32095fab37eSRobert Watson { 32195fab37eSRobert Watson 32241a17fe3SRobert Watson LIST_INIT(&mac_static_policy_list); 32395fab37eSRobert Watson LIST_INIT(&mac_policy_list); 324eca8a663SRobert Watson mac_labelzone_init(); 32541a17fe3SRobert Watson 3260a05006dSRobert Watson #ifndef MAC_STATIC 32741a17fe3SRobert Watson mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); 32841a17fe3SRobert Watson cv_init(&mac_policy_cv, "mac_policy_cv"); 3290a05006dSRobert Watson #endif 33095fab37eSRobert Watson } 33195fab37eSRobert Watson 33295fab37eSRobert Watson /* 33317041e67SRobert Watson * For the purposes of modules that want to know if they were loaded "early", 33417041e67SRobert Watson * set the mac_late flag once we've processed modules either linked into the 33517041e67SRobert Watson * kernel, or loaded before the kernel startup. 33695fab37eSRobert Watson */ 33795fab37eSRobert Watson static void 33895fab37eSRobert Watson mac_late_init(void) 33995fab37eSRobert Watson { 34095fab37eSRobert Watson 34195fab37eSRobert Watson mac_late = 1; 34295fab37eSRobert Watson } 34395fab37eSRobert Watson 34495fab37eSRobert Watson /* 3459162f64bSRobert Watson * Given a policy, derive from its set of non-NULL label init methods what 3469162f64bSRobert Watson * object types the policy is interested in. 3479162f64bSRobert Watson */ 3489162f64bSRobert Watson static uint64_t 3499162f64bSRobert Watson mac_policy_getlabeled(struct mac_policy_conf *mpc) 3509162f64bSRobert Watson { 3519162f64bSRobert Watson uint64_t labeled; 3529162f64bSRobert Watson 3539162f64bSRobert Watson #define MPC_FLAG(method, flag) \ 3549162f64bSRobert Watson if (mpc->mpc_ops->mpo_ ## method != NULL) \ 3559162f64bSRobert Watson labeled |= (flag); \ 3569162f64bSRobert Watson 3579162f64bSRobert Watson labeled = 0; 3589162f64bSRobert Watson MPC_FLAG(cred_init_label, MPC_OBJECT_CRED); 3599162f64bSRobert Watson MPC_FLAG(proc_init_label, MPC_OBJECT_PROC); 3609162f64bSRobert Watson MPC_FLAG(vnode_init_label, MPC_OBJECT_VNODE); 3619162f64bSRobert Watson MPC_FLAG(inpcb_init_label, MPC_OBJECT_INPCB); 3629162f64bSRobert Watson MPC_FLAG(socket_init_label, MPC_OBJECT_SOCKET); 3639162f64bSRobert Watson MPC_FLAG(devfs_init_label, MPC_OBJECT_DEVFS); 3649162f64bSRobert Watson MPC_FLAG(mbuf_init_label, MPC_OBJECT_MBUF); 3659162f64bSRobert Watson MPC_FLAG(ipq_init_label, MPC_OBJECT_IPQ); 3669162f64bSRobert Watson MPC_FLAG(ifnet_init_label, MPC_OBJECT_IFNET); 3679162f64bSRobert Watson MPC_FLAG(bpfdesc_init_label, MPC_OBJECT_BPFDESC); 3689162f64bSRobert Watson MPC_FLAG(pipe_init_label, MPC_OBJECT_PIPE); 3699162f64bSRobert Watson MPC_FLAG(mount_init_label, MPC_OBJECT_MOUNT); 3709162f64bSRobert Watson MPC_FLAG(posixsem_init_label, MPC_OBJECT_POSIXSEM); 3719162f64bSRobert Watson MPC_FLAG(posixshm_init_label, MPC_OBJECT_POSIXSHM); 3729162f64bSRobert Watson MPC_FLAG(sysvmsg_init_label, MPC_OBJECT_SYSVMSG); 3739162f64bSRobert Watson MPC_FLAG(sysvmsq_init_label, MPC_OBJECT_SYSVMSQ); 3749162f64bSRobert Watson MPC_FLAG(sysvsem_init_label, MPC_OBJECT_SYSVSEM); 3759162f64bSRobert Watson MPC_FLAG(sysvshm_init_label, MPC_OBJECT_SYSVSHM); 3769162f64bSRobert Watson MPC_FLAG(syncache_init_label, MPC_OBJECT_SYNCACHE); 3779162f64bSRobert Watson MPC_FLAG(ip6q_init_label, MPC_OBJECT_IP6Q); 3789162f64bSRobert Watson 3799162f64bSRobert Watson #undef MPC_FLAG 3809162f64bSRobert Watson return (labeled); 3819162f64bSRobert Watson } 3829162f64bSRobert Watson 3839162f64bSRobert Watson /* 3849162f64bSRobert Watson * When policies are loaded or unloaded, walk the list of registered policies 3859162f64bSRobert Watson * and built mac_labeled, a bitmask representing the union of all objects 3869162f64bSRobert Watson * requiring labels across all policies. 387225bff6fSRobert Watson */ 388225bff6fSRobert Watson static void 389225bff6fSRobert Watson mac_policy_updateflags(void) 390225bff6fSRobert Watson { 3916356dba0SRobert Watson struct mac_policy_conf *mpc; 392225bff6fSRobert Watson 39341a17fe3SRobert Watson mac_policy_assert_exclusive(); 394225bff6fSRobert Watson 3956356dba0SRobert Watson mac_labeled = 0; 3966356dba0SRobert Watson LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) 3979162f64bSRobert Watson mac_labeled |= mac_policy_getlabeled(mpc); 3986356dba0SRobert Watson LIST_FOREACH(mpc, &mac_policy_list, mpc_list) 3999162f64bSRobert Watson mac_labeled |= mac_policy_getlabeled(mpc); 400225bff6fSRobert Watson } 401225bff6fSRobert Watson 40295fab37eSRobert Watson static int 40395fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc) 40495fab37eSRobert Watson { 40595fab37eSRobert Watson struct mac_policy_conf *tmpc; 40641a17fe3SRobert Watson int error, slot, static_entry; 40795fab37eSRobert Watson 40841a17fe3SRobert Watson error = 0; 40941a17fe3SRobert Watson 41041a17fe3SRobert Watson /* 41117041e67SRobert Watson * We don't technically need exclusive access while !mac_late, but 41217041e67SRobert Watson * hold it for assertion consistency. 41341a17fe3SRobert Watson */ 41441a17fe3SRobert Watson mac_policy_grab_exclusive(); 41541a17fe3SRobert Watson 41641a17fe3SRobert Watson /* 41717041e67SRobert Watson * If the module can potentially be unloaded, or we're loading late, 41817041e67SRobert Watson * we have to stick it in the non-static list and pay an extra 41917041e67SRobert Watson * performance overhead. Otherwise, we can pay a light locking cost 42017041e67SRobert Watson * and stick it in the static list. 42141a17fe3SRobert Watson */ 42241a17fe3SRobert Watson static_entry = (!mac_late && 42341a17fe3SRobert Watson !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 42441a17fe3SRobert Watson 42541a17fe3SRobert Watson if (static_entry) { 42641a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 42741a17fe3SRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 42841a17fe3SRobert Watson error = EEXIST; 42941a17fe3SRobert Watson goto out; 43041a17fe3SRobert Watson } 43141a17fe3SRobert Watson } 43241a17fe3SRobert Watson } else { 43395fab37eSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 43495fab37eSRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 43541a17fe3SRobert Watson error = EEXIST; 43641a17fe3SRobert Watson goto out; 43741a17fe3SRobert Watson } 43895fab37eSRobert Watson } 43995fab37eSRobert Watson } 44095fab37eSRobert Watson if (mpc->mpc_field_off != NULL) { 441b2aef571SRobert Watson slot = ffs(mac_slot_offsets_free); 44295fab37eSRobert Watson if (slot == 0) { 44341a17fe3SRobert Watson error = ENOMEM; 44441a17fe3SRobert Watson goto out; 44595fab37eSRobert Watson } 44695fab37eSRobert Watson slot--; 447b2aef571SRobert Watson mac_slot_offsets_free &= ~(1 << slot); 44895fab37eSRobert Watson *mpc->mpc_field_off = slot; 44995fab37eSRobert Watson } 45095fab37eSRobert Watson mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 45141a17fe3SRobert Watson 45241a17fe3SRobert Watson /* 45317041e67SRobert Watson * If we're loading a MAC module after the framework has initialized, 45417041e67SRobert Watson * it has to go into the dynamic list. If we're loading it before 45517041e67SRobert Watson * we've finished initializing, it can go into the static list with 45617041e67SRobert Watson * weaker locker requirements. 45741a17fe3SRobert Watson */ 45841a17fe3SRobert Watson if (static_entry) 45941a17fe3SRobert Watson LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); 46041a17fe3SRobert Watson else 46195fab37eSRobert Watson LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 46295fab37eSRobert Watson 46317041e67SRobert Watson /* 46417041e67SRobert Watson * Per-policy initialization. Currently, this takes place under the 46517041e67SRobert Watson * exclusive lock, so policies must not sleep in their init method. 46617041e67SRobert Watson * In the future, we may want to separate "init" from "start", with 46717041e67SRobert Watson * "init" occuring without the lock held. Likewise, on tear-down, 46817041e67SRobert Watson * breaking out "stop" from "destroy". 46917041e67SRobert Watson */ 47095fab37eSRobert Watson if (mpc->mpc_ops->mpo_init != NULL) 47195fab37eSRobert Watson (*(mpc->mpc_ops->mpo_init))(mpc); 472225bff6fSRobert Watson mac_policy_updateflags(); 47395fab37eSRobert Watson 47491ec0006SRobert Watson SDT_PROBE(mac, kernel, policy, register, mpc, 0, 0, 0, 0); 47595fab37eSRobert Watson printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 47695fab37eSRobert Watson mpc->mpc_name); 47795fab37eSRobert Watson 47841a17fe3SRobert Watson out: 47941a17fe3SRobert Watson mac_policy_release_exclusive(); 48041a17fe3SRobert Watson return (error); 48195fab37eSRobert Watson } 48295fab37eSRobert Watson 48395fab37eSRobert Watson static int 48495fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc) 48595fab37eSRobert Watson { 48695fab37eSRobert Watson 487ea599aa0SRobert Watson /* 48817041e67SRobert Watson * If we fail the load, we may get a request to unload. Check to see 48917041e67SRobert Watson * if we did the run-time registration, and if not, silently succeed. 490ea599aa0SRobert Watson */ 49141a17fe3SRobert Watson mac_policy_grab_exclusive(); 492ea599aa0SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 49341a17fe3SRobert Watson mac_policy_release_exclusive(); 494ea599aa0SRobert Watson return (0); 495ea599aa0SRobert Watson } 49695fab37eSRobert Watson #if 0 49795fab37eSRobert Watson /* 49895fab37eSRobert Watson * Don't allow unloading modules with private data. 49995fab37eSRobert Watson */ 500ea599aa0SRobert Watson if (mpc->mpc_field_off != NULL) { 501ea599aa0SRobert Watson MAC_POLICY_LIST_UNLOCK(); 50295fab37eSRobert Watson return (EBUSY); 503ea599aa0SRobert Watson } 50495fab37eSRobert Watson #endif 505ea599aa0SRobert Watson /* 50617041e67SRobert Watson * Only allow the unload to proceed if the module is unloadable by 50717041e67SRobert Watson * its own definition. 508ea599aa0SRobert Watson */ 509ea599aa0SRobert Watson if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 51041a17fe3SRobert Watson mac_policy_release_exclusive(); 51195fab37eSRobert Watson return (EBUSY); 512ea599aa0SRobert Watson } 51395fab37eSRobert Watson if (mpc->mpc_ops->mpo_destroy != NULL) 51495fab37eSRobert Watson (*(mpc->mpc_ops->mpo_destroy))(mpc); 51595fab37eSRobert Watson 51695fab37eSRobert Watson LIST_REMOVE(mpc, mpc_list); 5179aeffb2bSRobert Watson mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 518225bff6fSRobert Watson mac_policy_updateflags(); 51941a17fe3SRobert Watson 52041a17fe3SRobert Watson mac_policy_release_exclusive(); 521a96acd1aSRobert Watson 52291ec0006SRobert Watson SDT_PROBE(mac, kernel, policy, unregister, mpc, 0, 0, 0, 0); 52395fab37eSRobert Watson printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 52495fab37eSRobert Watson mpc->mpc_name); 52595fab37eSRobert Watson 52695fab37eSRobert Watson return (0); 52795fab37eSRobert Watson } 52895fab37eSRobert Watson 52995fab37eSRobert Watson /* 530c441d123SRobert Watson * Allow MAC policy modules to register during boot, etc. 531c441d123SRobert Watson */ 532c441d123SRobert Watson int 533c441d123SRobert Watson mac_policy_modevent(module_t mod, int type, void *data) 534c441d123SRobert Watson { 535c441d123SRobert Watson struct mac_policy_conf *mpc; 536c441d123SRobert Watson int error; 537c441d123SRobert Watson 538c441d123SRobert Watson error = 0; 539c441d123SRobert Watson mpc = (struct mac_policy_conf *) data; 540c441d123SRobert Watson 541c441d123SRobert Watson #ifdef MAC_STATIC 542c441d123SRobert Watson if (mac_late) { 543c441d123SRobert Watson printf("mac_policy_modevent: MAC_STATIC and late\n"); 544c441d123SRobert Watson return (EBUSY); 545c441d123SRobert Watson } 546c441d123SRobert Watson #endif 547c441d123SRobert Watson 54891ec0006SRobert Watson SDT_PROBE(mac, kernel, policy, modevent, type, mpc, 0, 0, 0); 549c441d123SRobert Watson switch (type) { 550c441d123SRobert Watson case MOD_LOAD: 551c441d123SRobert Watson if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 552c441d123SRobert Watson mac_late) { 553c441d123SRobert Watson printf("mac_policy_modevent: can't load %s policy " 554c441d123SRobert Watson "after booting\n", mpc->mpc_name); 555c441d123SRobert Watson error = EBUSY; 556c441d123SRobert Watson break; 557c441d123SRobert Watson } 558c441d123SRobert Watson error = mac_policy_register(mpc); 559c441d123SRobert Watson break; 560c441d123SRobert Watson case MOD_UNLOAD: 561c441d123SRobert Watson /* Don't unregister the module if it was never registered. */ 562c441d123SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 563c441d123SRobert Watson != 0) 564c441d123SRobert Watson error = mac_policy_unregister(mpc); 565c441d123SRobert Watson else 566c441d123SRobert Watson error = 0; 567c441d123SRobert Watson break; 568c441d123SRobert Watson default: 569c441d123SRobert Watson error = EOPNOTSUPP; 570c441d123SRobert Watson break; 571c441d123SRobert Watson } 572c441d123SRobert Watson 573c441d123SRobert Watson return (error); 574c441d123SRobert Watson } 575c441d123SRobert Watson 576c441d123SRobert Watson /* 57795fab37eSRobert Watson * Define an error value precedence, and given two arguments, selects the 57895fab37eSRobert Watson * value with the higher precedence. 57995fab37eSRobert Watson */ 5809e7bf51cSRobert Watson int 5819e7bf51cSRobert Watson mac_error_select(int error1, int error2) 58295fab37eSRobert Watson { 58395fab37eSRobert Watson 58495fab37eSRobert Watson /* Certain decision-making errors take top priority. */ 58595fab37eSRobert Watson if (error1 == EDEADLK || error2 == EDEADLK) 58695fab37eSRobert Watson return (EDEADLK); 58795fab37eSRobert Watson 58895fab37eSRobert Watson /* Invalid arguments should be reported where possible. */ 58995fab37eSRobert Watson if (error1 == EINVAL || error2 == EINVAL) 59095fab37eSRobert Watson return (EINVAL); 59195fab37eSRobert Watson 59295fab37eSRobert Watson /* Precedence goes to "visibility", with both process and file. */ 59395fab37eSRobert Watson if (error1 == ESRCH || error2 == ESRCH) 59495fab37eSRobert Watson return (ESRCH); 59595fab37eSRobert Watson 59695fab37eSRobert Watson if (error1 == ENOENT || error2 == ENOENT) 59795fab37eSRobert Watson return (ENOENT); 59895fab37eSRobert Watson 59995fab37eSRobert Watson /* Precedence goes to DAC/MAC protections. */ 60095fab37eSRobert Watson if (error1 == EACCES || error2 == EACCES) 60195fab37eSRobert Watson return (EACCES); 60295fab37eSRobert Watson 60395fab37eSRobert Watson /* Precedence goes to privilege. */ 60495fab37eSRobert Watson if (error1 == EPERM || error2 == EPERM) 60595fab37eSRobert Watson return (EPERM); 60695fab37eSRobert Watson 60795fab37eSRobert Watson /* Precedence goes to error over success; otherwise, arbitrary. */ 60895fab37eSRobert Watson if (error1 != 0) 60995fab37eSRobert Watson return (error1); 61095fab37eSRobert Watson return (error2); 61195fab37eSRobert Watson } 61295fab37eSRobert Watson 6135e7ce478SRobert Watson int 614f7b951a8SRobert Watson mac_check_structmac_consistent(struct mac *mac) 615f7b951a8SRobert Watson { 616f7b951a8SRobert Watson 617cc7b13bfSRobert Watson if (mac->m_buflen < 0 || 618cc7b13bfSRobert Watson mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 619f7b951a8SRobert Watson return (EINVAL); 620f7b951a8SRobert Watson 621f7b951a8SRobert Watson return (0); 622f7b951a8SRobert Watson } 623f7b951a8SRobert Watson 62495fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 62595fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 626