17bc82500SRobert Watson /*- 2471e5756SRobert Watson * Copyright (c) 1999-2002, 2006 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. 67bc82500SRobert Watson * All rights reserved. 77bc82500SRobert Watson * 87bc82500SRobert Watson * This software was developed by Robert Watson and Ilmar Habibulin for the 97bc82500SRobert Watson * TrustedBSD Project. 107bc82500SRobert Watson * 116201265bSRobert Watson * This software was developed for the FreeBSD Project in part by Network 126201265bSRobert Watson * Associates Laboratories, the Security Research Division of Network 136201265bSRobert Watson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 146201265bSRobert Watson * as part of the DARPA CHATS research program. 157bc82500SRobert Watson * 1649bb6870SRobert Watson * This software was enhanced by SPARTA ISSO under SPAWAR contract 1749bb6870SRobert Watson * N66001-04-C-6019 ("SEFOS"). 1849bb6870SRobert Watson * 197bc82500SRobert Watson * Redistribution and use in source and binary forms, with or without 207bc82500SRobert Watson * modification, are permitted provided that the following conditions 217bc82500SRobert Watson * are met: 227bc82500SRobert Watson * 1. Redistributions of source code must retain the above copyright 237bc82500SRobert Watson * notice, this list of conditions and the following disclaimer. 247bc82500SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 257bc82500SRobert Watson * notice, this list of conditions and the following disclaimer in the 267bc82500SRobert Watson * documentation and/or other materials provided with the distribution. 277bc82500SRobert Watson * 287bc82500SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 297bc82500SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 307bc82500SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 317bc82500SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 327bc82500SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 337bc82500SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 347bc82500SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 357bc82500SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 367bc82500SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 377bc82500SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 387bc82500SRobert Watson * SUCH DAMAGE. 397bc82500SRobert Watson */ 40677b542eSDavid E. O'Brien 41c8e7bf92SRobert Watson /*- 42471e5756SRobert Watson * Framework for extensible kernel access control. This file contains core 43471e5756SRobert Watson * kernel infrastructure for the TrustedBSD MAC Framework, including policy 44471e5756SRobert Watson * registration, versioning, locking, error composition operator, and system 45471e5756SRobert Watson * calls. 46471e5756SRobert Watson * 47471e5756SRobert Watson * The MAC Framework implements three programming interfaces: 48471e5756SRobert Watson * 49471e5756SRobert Watson * - The kernel MAC interface, defined in mac_framework.h, and invoked 50471e5756SRobert Watson * throughout the kernel to request security decisions, notify of security 51471e5756SRobert Watson * related events, etc. 52471e5756SRobert Watson * 53471e5756SRobert Watson * - The MAC policy module interface, defined in mac_policy.h, which is 54471e5756SRobert Watson * implemented by MAC policy modules and invoked by the MAC Framework to 55471e5756SRobert Watson * forward kernel security requests and notifications to policy modules. 56471e5756SRobert Watson * 57471e5756SRobert Watson * - The user MAC API, defined in mac.h, which allows user programs to query 58471e5756SRobert Watson * and set label state on objects. 59471e5756SRobert Watson * 60471e5756SRobert Watson * The majority of the MAC Framework implementation may be found in 61471e5756SRobert Watson * src/sys/security/mac. Sample policy modules may be found in 6249869305STom Rhodes * src/sys/security/mac_*. 637bc82500SRobert Watson */ 647bc82500SRobert Watson 6539b73a30SRobert Watson #include "opt_mac.h" 6639b73a30SRobert Watson 67677b542eSDavid E. O'Brien #include <sys/cdefs.h> 68677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 69677b542eSDavid E. O'Brien 707bc82500SRobert Watson #include <sys/param.h> 71a96acd1aSRobert Watson #include <sys/condvar.h> 7295fab37eSRobert Watson #include <sys/kernel.h> 7395fab37eSRobert Watson #include <sys/lock.h> 7495fab37eSRobert Watson #include <sys/mutex.h> 7595fab37eSRobert Watson #include <sys/mac.h> 767ba28492SRobert Watson #include <sys/module.h> 7795fab37eSRobert Watson #include <sys/systm.h> 7895fab37eSRobert Watson #include <sys/sysctl.h> 7995fab37eSRobert Watson 80aed55708SRobert Watson #include <security/mac/mac_framework.h> 816fa0475dSRobert Watson #include <security/mac/mac_internal.h> 820efd6615SRobert Watson #include <security/mac/mac_policy.h> 836fa0475dSRobert Watson 847ba28492SRobert Watson /* 85471e5756SRobert Watson * Root sysctl node for all MAC and MAC policy controls. 867ba28492SRobert Watson */ 8795fab37eSRobert Watson SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, 8895fab37eSRobert Watson "TrustedBSD MAC policy controls"); 89b2f0927aSRobert Watson 9017041e67SRobert Watson /* 91471e5756SRobert Watson * Declare that the kernel provides MAC support, version 3 (FreeBSD 7.x). 92471e5756SRobert Watson * This permits modules to refuse to be loaded if the necessary support isn't 93471e5756SRobert Watson * present, even if it's pre-boot. 94471e5756SRobert Watson */ 95471e5756SRobert Watson MODULE_VERSION(kernel_mac_support, MAC_VERSION); 96be23ba9aSRobert Watson 97be23ba9aSRobert Watson static unsigned int mac_version = MAC_VERSION; 98471e5756SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, version, CTLFLAG_RD, &mac_version, 0, 99471e5756SRobert Watson ""); 100471e5756SRobert Watson 101471e5756SRobert Watson /* 10217041e67SRobert Watson * Labels consist of a indexed set of "slots", which are allocated policies 10317041e67SRobert Watson * as required. The MAC Framework maintains a bitmask of slots allocated so 10417041e67SRobert Watson * far to prevent reuse. Slots cannot be reused, as the MAC Framework 10517041e67SRobert Watson * guarantees that newly allocated slots in labels will be NULL unless 10617041e67SRobert Watson * otherwise initialized, and because we do not have a mechanism to garbage 10717041e67SRobert Watson * collect slots on policy unload. As labeled policies tend to be statically 10817041e67SRobert Watson * loaded during boot, and not frequently unloaded and reloaded, this is not 10917041e67SRobert Watson * generally an issue. 11017041e67SRobert Watson */ 111b2aef571SRobert Watson #if MAC_MAX_SLOTS > 32 112b2aef571SRobert Watson #error "MAC_MAX_SLOTS too large" 11395fab37eSRobert Watson #endif 114a13c67daSRobert Watson 115b2aef571SRobert Watson static unsigned int mac_max_slots = MAC_MAX_SLOTS; 116b2aef571SRobert Watson static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1; 117471e5756SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, &mac_max_slots, 118471e5756SRobert Watson 0, ""); 11995fab37eSRobert Watson 120a67fe518SRobert Watson /* 121a67fe518SRobert Watson * Has the kernel started generating labeled objects yet? All read/write 122a67fe518SRobert Watson * access to this variable is serialized during the boot process. Following 123a67fe518SRobert Watson * the end of serialization, we don't update this flag; no locking. 124a67fe518SRobert Watson */ 125be23ba9aSRobert Watson static int mac_late = 0; 126763bbd2fSRobert Watson 127225bff6fSRobert Watson /* 12817041e67SRobert Watson * Flag to indicate whether or not we should allocate label storage for new 12917041e67SRobert Watson * mbufs. Since most dynamic policies we currently work with don't rely on 13017041e67SRobert Watson * mbuf labeling, try to avoid paying the cost of mtag allocation unless 13117041e67SRobert Watson * specifically notified of interest. One result of this is that if a 13217041e67SRobert Watson * dynamically loaded policy requests mbuf labels, it must be able to deal 13317041e67SRobert Watson * with a NULL label being returned on any mbufs that were already in flight 13417041e67SRobert Watson * when the policy was loaded. Since the policy already has to deal with 13517041e67SRobert Watson * uninitialized labels, this probably won't be a problem. Note: currently 13617041e67SRobert Watson * no locking. Will this be a problem? 13717041e67SRobert Watson * 13817041e67SRobert Watson * In the future, we may want to allow objects to request labeling on a per- 13917041e67SRobert Watson * object type basis, rather than globally for all objects. 140225bff6fSRobert Watson */ 14119c3e120SRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF 142089c1bdaSRobert Watson int mac_labelmbufs = 0; 143225bff6fSRobert Watson #endif 144225bff6fSRobert Watson 14595fab37eSRobert Watson static int mac_policy_register(struct mac_policy_conf *mpc); 14695fab37eSRobert Watson static int mac_policy_unregister(struct mac_policy_conf *mpc); 14795fab37eSRobert Watson 148f7b951a8SRobert Watson MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 14995fab37eSRobert Watson 15095fab37eSRobert Watson /* 15117041e67SRobert Watson * mac_static_policy_list holds a list of policy modules that are not loaded 15217041e67SRobert Watson * while the system is "live", and cannot be unloaded. These policies can be 15317041e67SRobert Watson * invoked without holding the busy count. 15441a17fe3SRobert Watson * 15541a17fe3SRobert Watson * mac_policy_list stores the list of dynamic policies. A busy count is 15617041e67SRobert Watson * maintained for the list, stored in mac_policy_busy. The busy count is 15717041e67SRobert Watson * protected by mac_policy_mtx; the list may be modified only while the busy 15817041e67SRobert Watson * count is 0, requiring that the lock be held to prevent new references to 15917041e67SRobert Watson * the list from being acquired. For almost all operations, incrementing the 16017041e67SRobert Watson * busy count is sufficient to guarantee consistency, as the list cannot be 16117041e67SRobert Watson * modified while the busy count is elevated. For a few special operations 16217041e67SRobert Watson * involving a change to the list of active policies, the mtx itself must be 16317041e67SRobert Watson * held. A condition variable, mac_policy_cv, is used to signal potential 16417041e67SRobert Watson * exclusive consumers that they should try to acquire the lock if a first 16517041e67SRobert Watson * attempt at exclusive access fails. 16617041e67SRobert Watson * 16717041e67SRobert Watson * This design intentionally avoids fairness, and may starve attempts to 16817041e67SRobert Watson * acquire an exclusive lock on a busy system. This is required because we 16917041e67SRobert Watson * do not ever want acquiring a read reference to perform an unbounded length 17017041e67SRobert Watson * sleep. Read references are acquired in ithreads, network isrs, etc, and 17117041e67SRobert Watson * any unbounded blocking could lead quickly to deadlock. 17217041e67SRobert Watson * 17317041e67SRobert Watson * Another reason for never blocking on read references is that the MAC 17417041e67SRobert Watson * Framework may recurse: if a policy calls a VOP, for example, this might 17517041e67SRobert Watson * lead to vnode life cycle operations (such as init/destroy). 176471e5756SRobert Watson * 177471e5756SRobert Watson * If the kernel option MAC_STATIC has been compiled in, all locking becomes 178471e5756SRobert Watson * a no-op, and the global list of policies is not allowed to change after 179471e5756SRobert Watson * early boot. 18095fab37eSRobert Watson */ 1810a05006dSRobert Watson #ifndef MAC_STATIC 18241a17fe3SRobert Watson static struct mtx mac_policy_mtx; 18341a17fe3SRobert Watson static struct cv mac_policy_cv; 18441a17fe3SRobert Watson static int mac_policy_count; 1850a05006dSRobert Watson #endif 186089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list; 187089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list; 188a96acd1aSRobert Watson 189a96acd1aSRobert Watson /* 19017041e67SRobert Watson * We manually invoke WITNESS_WARN() to allow Witness to generate warnings 19117041e67SRobert Watson * even if we don't end up ever triggering the wait at run-time. The 19217041e67SRobert Watson * consumer of the exclusive interface must not hold any locks (other than 19317041e67SRobert Watson * potentially Giant) since we may sleep for long (potentially indefinite) 19417041e67SRobert Watson * periods of time waiting for the framework to become quiescent so that a 19517041e67SRobert Watson * policy list change may be made. 196a96acd1aSRobert Watson */ 197089c1bdaSRobert Watson void 19841a17fe3SRobert Watson mac_policy_grab_exclusive(void) 19941a17fe3SRobert Watson { 200c8e7bf92SRobert Watson 2010a05006dSRobert Watson #ifndef MAC_STATIC 2021e4cadcbSRobert Watson if (!mac_late) 2031e4cadcbSRobert Watson return; 2041e4cadcbSRobert Watson 20541a17fe3SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 20641a17fe3SRobert Watson "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); 20741a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 20841a17fe3SRobert Watson while (mac_policy_count != 0) 20941a17fe3SRobert Watson cv_wait(&mac_policy_cv, &mac_policy_mtx); 2100a05006dSRobert Watson #endif 21141a17fe3SRobert Watson } 21295fab37eSRobert Watson 213089c1bdaSRobert Watson void 21441a17fe3SRobert Watson mac_policy_assert_exclusive(void) 21541a17fe3SRobert Watson { 216c8e7bf92SRobert Watson 2170a05006dSRobert Watson #ifndef MAC_STATIC 2181e4cadcbSRobert Watson if (!mac_late) 2191e4cadcbSRobert Watson return; 2201e4cadcbSRobert Watson 22141a17fe3SRobert Watson mtx_assert(&mac_policy_mtx, MA_OWNED); 22241a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 22341a17fe3SRobert Watson ("mac_policy_assert_exclusive(): not exclusive")); 2240a05006dSRobert Watson #endif 22541a17fe3SRobert Watson } 226225bff6fSRobert Watson 227089c1bdaSRobert Watson void 22841a17fe3SRobert Watson mac_policy_release_exclusive(void) 22941a17fe3SRobert Watson { 23095fab37eSRobert Watson 2310a05006dSRobert Watson #ifndef MAC_STATIC 2321e4cadcbSRobert Watson if (!mac_late) 2331e4cadcbSRobert Watson return; 2341e4cadcbSRobert Watson 23541a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 23641a17fe3SRobert Watson ("mac_policy_release_exclusive(): not exclusive")); 23741a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 23841a17fe3SRobert Watson cv_signal(&mac_policy_cv); 2390a05006dSRobert Watson #endif 24041a17fe3SRobert Watson } 24141a17fe3SRobert Watson 242089c1bdaSRobert Watson void 24341a17fe3SRobert Watson mac_policy_list_busy(void) 24441a17fe3SRobert Watson { 245c8e7bf92SRobert Watson 2460a05006dSRobert Watson #ifndef MAC_STATIC 2471e4cadcbSRobert Watson if (!mac_late) 2481e4cadcbSRobert Watson return; 2491e4cadcbSRobert Watson 25041a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 25141a17fe3SRobert Watson mac_policy_count++; 25241a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 2530a05006dSRobert Watson #endif 25441a17fe3SRobert Watson } 25541a17fe3SRobert Watson 256089c1bdaSRobert Watson int 25741a17fe3SRobert Watson mac_policy_list_conditional_busy(void) 25841a17fe3SRobert Watson { 2590a05006dSRobert Watson #ifndef MAC_STATIC 26041a17fe3SRobert Watson int ret; 26141a17fe3SRobert Watson 2621e4cadcbSRobert Watson if (!mac_late) 2631e4cadcbSRobert Watson return (1); 2641e4cadcbSRobert Watson 26541a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 26641a17fe3SRobert Watson if (!LIST_EMPTY(&mac_policy_list)) { 26741a17fe3SRobert Watson mac_policy_count++; 26841a17fe3SRobert Watson ret = 1; 26941a17fe3SRobert Watson } else 27041a17fe3SRobert Watson ret = 0; 27141a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 27241a17fe3SRobert Watson return (ret); 2730a05006dSRobert Watson #else 2741e4cadcbSRobert Watson if (!mac_late) 2751e4cadcbSRobert Watson return (1); 2761e4cadcbSRobert Watson 2770a05006dSRobert Watson return (1); 2780a05006dSRobert Watson #endif 27941a17fe3SRobert Watson } 28041a17fe3SRobert Watson 281089c1bdaSRobert Watson void 28241a17fe3SRobert Watson mac_policy_list_unbusy(void) 28341a17fe3SRobert Watson { 284c8e7bf92SRobert Watson 2850a05006dSRobert Watson #ifndef MAC_STATIC 2861e4cadcbSRobert Watson if (!mac_late) 2871e4cadcbSRobert Watson return; 2881e4cadcbSRobert Watson 28941a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 29041a17fe3SRobert Watson mac_policy_count--; 29141a17fe3SRobert Watson KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); 29241a17fe3SRobert Watson if (mac_policy_count == 0) 29341a17fe3SRobert Watson cv_signal(&mac_policy_cv); 29441a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 2950a05006dSRobert Watson #endif 29641a17fe3SRobert Watson } 29795fab37eSRobert Watson 29895fab37eSRobert Watson /* 29995fab37eSRobert Watson * Initialize the MAC subsystem, including appropriate SMP locks. 30095fab37eSRobert Watson */ 30195fab37eSRobert Watson static void 30295fab37eSRobert Watson mac_init(void) 30395fab37eSRobert Watson { 30495fab37eSRobert Watson 30541a17fe3SRobert Watson LIST_INIT(&mac_static_policy_list); 30695fab37eSRobert Watson LIST_INIT(&mac_policy_list); 307eca8a663SRobert Watson mac_labelzone_init(); 30841a17fe3SRobert Watson 3090a05006dSRobert Watson #ifndef MAC_STATIC 31041a17fe3SRobert Watson mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); 31141a17fe3SRobert Watson cv_init(&mac_policy_cv, "mac_policy_cv"); 3120a05006dSRobert Watson #endif 31395fab37eSRobert Watson } 31495fab37eSRobert Watson 31595fab37eSRobert Watson /* 31617041e67SRobert Watson * For the purposes of modules that want to know if they were loaded "early", 31717041e67SRobert Watson * set the mac_late flag once we've processed modules either linked into the 31817041e67SRobert Watson * kernel, or loaded before the kernel startup. 31995fab37eSRobert Watson */ 32095fab37eSRobert Watson static void 32195fab37eSRobert Watson mac_late_init(void) 32295fab37eSRobert Watson { 32395fab37eSRobert Watson 32495fab37eSRobert Watson mac_late = 1; 32595fab37eSRobert Watson } 32695fab37eSRobert Watson 32795fab37eSRobert Watson /* 328225bff6fSRobert Watson * After the policy list has changed, walk the list to update any global 32919c3e120SRobert Watson * flags. Currently, we support only one flag, and it's conditionally 33017041e67SRobert Watson * defined; as a result, the entire function is conditional. Eventually, the 33117041e67SRobert Watson * #else case might also iterate across the policies. 332225bff6fSRobert Watson */ 333225bff6fSRobert Watson static void 334225bff6fSRobert Watson mac_policy_updateflags(void) 335225bff6fSRobert Watson { 336225bff6fSRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF 33719c3e120SRobert Watson struct mac_policy_conf *tmpc; 338225bff6fSRobert Watson int labelmbufs; 339225bff6fSRobert Watson 34041a17fe3SRobert Watson mac_policy_assert_exclusive(); 341225bff6fSRobert Watson 342225bff6fSRobert Watson labelmbufs = 0; 34341a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 34441a17fe3SRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 34541a17fe3SRobert Watson labelmbufs++; 34641a17fe3SRobert Watson } 347225bff6fSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 348225bff6fSRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 349225bff6fSRobert Watson labelmbufs++; 350225bff6fSRobert Watson } 351225bff6fSRobert Watson mac_labelmbufs = (labelmbufs != 0); 352225bff6fSRobert Watson #endif 353225bff6fSRobert Watson } 354225bff6fSRobert Watson 355225bff6fSRobert Watson /* 35695fab37eSRobert Watson * Allow MAC policy modules to register during boot, etc. 35795fab37eSRobert Watson */ 35895fab37eSRobert Watson int 35995fab37eSRobert Watson mac_policy_modevent(module_t mod, int type, void *data) 36095fab37eSRobert Watson { 36195fab37eSRobert Watson struct mac_policy_conf *mpc; 36295fab37eSRobert Watson int error; 36395fab37eSRobert Watson 36495fab37eSRobert Watson error = 0; 36595fab37eSRobert Watson mpc = (struct mac_policy_conf *) data; 36695fab37eSRobert Watson 3670a05006dSRobert Watson #ifdef MAC_STATIC 3680a05006dSRobert Watson if (mac_late) { 3690a05006dSRobert Watson printf("mac_policy_modevent: MAC_STATIC and late\n"); 3700a05006dSRobert Watson return (EBUSY); 3710a05006dSRobert Watson } 3720a05006dSRobert Watson #endif 3730a05006dSRobert Watson 37495fab37eSRobert Watson switch (type) { 37595fab37eSRobert Watson case MOD_LOAD: 37695fab37eSRobert Watson if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 37795fab37eSRobert Watson mac_late) { 37895fab37eSRobert Watson printf("mac_policy_modevent: can't load %s policy " 37995fab37eSRobert Watson "after booting\n", mpc->mpc_name); 38095fab37eSRobert Watson error = EBUSY; 38195fab37eSRobert Watson break; 38295fab37eSRobert Watson } 38395fab37eSRobert Watson error = mac_policy_register(mpc); 38495fab37eSRobert Watson break; 38595fab37eSRobert Watson case MOD_UNLOAD: 38695fab37eSRobert Watson /* Don't unregister the module if it was never registered. */ 38795fab37eSRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 38895fab37eSRobert Watson != 0) 38995fab37eSRobert Watson error = mac_policy_unregister(mpc); 39095fab37eSRobert Watson else 39195fab37eSRobert Watson error = 0; 39295fab37eSRobert Watson break; 39395fab37eSRobert Watson default: 3943e019deaSPoul-Henning Kamp error = EOPNOTSUPP; 39595fab37eSRobert Watson break; 39695fab37eSRobert Watson } 39795fab37eSRobert Watson 39895fab37eSRobert Watson return (error); 39995fab37eSRobert Watson } 40095fab37eSRobert Watson 40195fab37eSRobert Watson static int 40295fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc) 40395fab37eSRobert Watson { 40495fab37eSRobert Watson struct mac_policy_conf *tmpc; 40541a17fe3SRobert Watson int error, slot, static_entry; 40695fab37eSRobert Watson 40741a17fe3SRobert Watson error = 0; 40841a17fe3SRobert Watson 40941a17fe3SRobert Watson /* 41017041e67SRobert Watson * We don't technically need exclusive access while !mac_late, but 41117041e67SRobert Watson * hold it for assertion consistency. 41241a17fe3SRobert Watson */ 41341a17fe3SRobert Watson mac_policy_grab_exclusive(); 41441a17fe3SRobert Watson 41541a17fe3SRobert Watson /* 41617041e67SRobert Watson * If the module can potentially be unloaded, or we're loading late, 41717041e67SRobert Watson * we have to stick it in the non-static list and pay an extra 41817041e67SRobert Watson * performance overhead. Otherwise, we can pay a light locking cost 41917041e67SRobert Watson * and stick it in the static list. 42041a17fe3SRobert Watson */ 42141a17fe3SRobert Watson static_entry = (!mac_late && 42241a17fe3SRobert Watson !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 42341a17fe3SRobert Watson 42441a17fe3SRobert Watson if (static_entry) { 42541a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 42641a17fe3SRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 42741a17fe3SRobert Watson error = EEXIST; 42841a17fe3SRobert Watson goto out; 42941a17fe3SRobert Watson } 43041a17fe3SRobert Watson } 43141a17fe3SRobert Watson } else { 43295fab37eSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 43395fab37eSRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 43441a17fe3SRobert Watson error = EEXIST; 43541a17fe3SRobert Watson goto out; 43641a17fe3SRobert Watson } 43795fab37eSRobert Watson } 43895fab37eSRobert Watson } 43995fab37eSRobert Watson if (mpc->mpc_field_off != NULL) { 440b2aef571SRobert Watson slot = ffs(mac_slot_offsets_free); 44195fab37eSRobert Watson if (slot == 0) { 44241a17fe3SRobert Watson error = ENOMEM; 44341a17fe3SRobert Watson goto out; 44495fab37eSRobert Watson } 44595fab37eSRobert Watson slot--; 446b2aef571SRobert Watson mac_slot_offsets_free &= ~(1 << slot); 44795fab37eSRobert Watson *mpc->mpc_field_off = slot; 44895fab37eSRobert Watson } 44995fab37eSRobert Watson mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 45041a17fe3SRobert Watson 45141a17fe3SRobert Watson /* 45217041e67SRobert Watson * If we're loading a MAC module after the framework has initialized, 45317041e67SRobert Watson * it has to go into the dynamic list. If we're loading it before 45417041e67SRobert Watson * we've finished initializing, it can go into the static list with 45517041e67SRobert Watson * weaker locker requirements. 45641a17fe3SRobert Watson */ 45741a17fe3SRobert Watson if (static_entry) 45841a17fe3SRobert Watson LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); 45941a17fe3SRobert Watson else 46095fab37eSRobert Watson LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 46195fab37eSRobert Watson 46217041e67SRobert Watson /* 46317041e67SRobert Watson * Per-policy initialization. Currently, this takes place under the 46417041e67SRobert Watson * exclusive lock, so policies must not sleep in their init method. 46517041e67SRobert Watson * In the future, we may want to separate "init" from "start", with 46617041e67SRobert Watson * "init" occuring without the lock held. Likewise, on tear-down, 46717041e67SRobert Watson * breaking out "stop" from "destroy". 46817041e67SRobert Watson */ 46995fab37eSRobert Watson if (mpc->mpc_ops->mpo_init != NULL) 47095fab37eSRobert Watson (*(mpc->mpc_ops->mpo_init))(mpc); 471225bff6fSRobert Watson mac_policy_updateflags(); 47295fab37eSRobert Watson 47395fab37eSRobert Watson printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 47495fab37eSRobert Watson mpc->mpc_name); 47595fab37eSRobert Watson 47641a17fe3SRobert Watson out: 47741a17fe3SRobert Watson mac_policy_release_exclusive(); 47841a17fe3SRobert Watson return (error); 47995fab37eSRobert Watson } 48095fab37eSRobert Watson 48195fab37eSRobert Watson static int 48295fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc) 48395fab37eSRobert Watson { 48495fab37eSRobert Watson 485ea599aa0SRobert Watson /* 48617041e67SRobert Watson * If we fail the load, we may get a request to unload. Check to see 48717041e67SRobert Watson * if we did the run-time registration, and if not, silently succeed. 488ea599aa0SRobert Watson */ 48941a17fe3SRobert Watson mac_policy_grab_exclusive(); 490ea599aa0SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 49141a17fe3SRobert Watson mac_policy_release_exclusive(); 492ea599aa0SRobert Watson return (0); 493ea599aa0SRobert Watson } 49495fab37eSRobert Watson #if 0 49595fab37eSRobert Watson /* 49695fab37eSRobert Watson * Don't allow unloading modules with private data. 49795fab37eSRobert Watson */ 498ea599aa0SRobert Watson if (mpc->mpc_field_off != NULL) { 499ea599aa0SRobert Watson MAC_POLICY_LIST_UNLOCK(); 50095fab37eSRobert Watson return (EBUSY); 501ea599aa0SRobert Watson } 50295fab37eSRobert Watson #endif 503ea599aa0SRobert Watson /* 50417041e67SRobert Watson * Only allow the unload to proceed if the module is unloadable by 50517041e67SRobert Watson * its own definition. 506ea599aa0SRobert Watson */ 507ea599aa0SRobert Watson if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 50841a17fe3SRobert Watson mac_policy_release_exclusive(); 50995fab37eSRobert Watson return (EBUSY); 510ea599aa0SRobert Watson } 51195fab37eSRobert Watson if (mpc->mpc_ops->mpo_destroy != NULL) 51295fab37eSRobert Watson (*(mpc->mpc_ops->mpo_destroy))(mpc); 51395fab37eSRobert Watson 51495fab37eSRobert Watson LIST_REMOVE(mpc, mpc_list); 5159aeffb2bSRobert Watson mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 516225bff6fSRobert Watson mac_policy_updateflags(); 51741a17fe3SRobert Watson 51841a17fe3SRobert Watson mac_policy_release_exclusive(); 519a96acd1aSRobert Watson 52095fab37eSRobert Watson printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 52195fab37eSRobert Watson mpc->mpc_name); 52295fab37eSRobert Watson 52395fab37eSRobert Watson return (0); 52495fab37eSRobert Watson } 52595fab37eSRobert Watson 52695fab37eSRobert Watson /* 52795fab37eSRobert Watson * Define an error value precedence, and given two arguments, selects the 52895fab37eSRobert Watson * value with the higher precedence. 52995fab37eSRobert Watson */ 5309e7bf51cSRobert Watson int 5319e7bf51cSRobert Watson mac_error_select(int error1, int error2) 53295fab37eSRobert Watson { 53395fab37eSRobert Watson 53495fab37eSRobert Watson /* Certain decision-making errors take top priority. */ 53595fab37eSRobert Watson if (error1 == EDEADLK || error2 == EDEADLK) 53695fab37eSRobert Watson return (EDEADLK); 53795fab37eSRobert Watson 53895fab37eSRobert Watson /* Invalid arguments should be reported where possible. */ 53995fab37eSRobert Watson if (error1 == EINVAL || error2 == EINVAL) 54095fab37eSRobert Watson return (EINVAL); 54195fab37eSRobert Watson 54295fab37eSRobert Watson /* Precedence goes to "visibility", with both process and file. */ 54395fab37eSRobert Watson if (error1 == ESRCH || error2 == ESRCH) 54495fab37eSRobert Watson return (ESRCH); 54595fab37eSRobert Watson 54695fab37eSRobert Watson if (error1 == ENOENT || error2 == ENOENT) 54795fab37eSRobert Watson return (ENOENT); 54895fab37eSRobert Watson 54995fab37eSRobert Watson /* Precedence goes to DAC/MAC protections. */ 55095fab37eSRobert Watson if (error1 == EACCES || error2 == EACCES) 55195fab37eSRobert Watson return (EACCES); 55295fab37eSRobert Watson 55395fab37eSRobert Watson /* Precedence goes to privilege. */ 55495fab37eSRobert Watson if (error1 == EPERM || error2 == EPERM) 55595fab37eSRobert Watson return (EPERM); 55695fab37eSRobert Watson 55795fab37eSRobert Watson /* Precedence goes to error over success; otherwise, arbitrary. */ 55895fab37eSRobert Watson if (error1 != 0) 55995fab37eSRobert Watson return (error1); 56095fab37eSRobert Watson return (error2); 56195fab37eSRobert Watson } 56295fab37eSRobert Watson 5635e7ce478SRobert Watson int 564f7b951a8SRobert Watson mac_check_structmac_consistent(struct mac *mac) 565f7b951a8SRobert Watson { 566f7b951a8SRobert Watson 567cc7b13bfSRobert Watson if (mac->m_buflen < 0 || 568cc7b13bfSRobert Watson mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 569f7b951a8SRobert Watson return (EINVAL); 570f7b951a8SRobert Watson 571f7b951a8SRobert Watson return (0); 572f7b951a8SRobert Watson } 573f7b951a8SRobert Watson 57495fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 57595fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 576