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 145f7b951a8SRobert Watson MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 14695fab37eSRobert Watson 14795fab37eSRobert Watson /* 14817041e67SRobert Watson * mac_static_policy_list holds a list of policy modules that are not loaded 14917041e67SRobert Watson * while the system is "live", and cannot be unloaded. These policies can be 15017041e67SRobert Watson * invoked without holding the busy count. 15141a17fe3SRobert Watson * 15241a17fe3SRobert Watson * mac_policy_list stores the list of dynamic policies. A busy count is 15317041e67SRobert Watson * maintained for the list, stored in mac_policy_busy. The busy count is 15417041e67SRobert Watson * protected by mac_policy_mtx; the list may be modified only while the busy 15517041e67SRobert Watson * count is 0, requiring that the lock be held to prevent new references to 15617041e67SRobert Watson * the list from being acquired. For almost all operations, incrementing the 15717041e67SRobert Watson * busy count is sufficient to guarantee consistency, as the list cannot be 15817041e67SRobert Watson * modified while the busy count is elevated. For a few special operations 15917041e67SRobert Watson * involving a change to the list of active policies, the mtx itself must be 16017041e67SRobert Watson * held. A condition variable, mac_policy_cv, is used to signal potential 16117041e67SRobert Watson * exclusive consumers that they should try to acquire the lock if a first 16217041e67SRobert Watson * attempt at exclusive access fails. 16317041e67SRobert Watson * 16417041e67SRobert Watson * This design intentionally avoids fairness, and may starve attempts to 16517041e67SRobert Watson * acquire an exclusive lock on a busy system. This is required because we 16617041e67SRobert Watson * do not ever want acquiring a read reference to perform an unbounded length 16717041e67SRobert Watson * sleep. Read references are acquired in ithreads, network isrs, etc, and 16817041e67SRobert Watson * any unbounded blocking could lead quickly to deadlock. 16917041e67SRobert Watson * 17017041e67SRobert Watson * Another reason for never blocking on read references is that the MAC 17117041e67SRobert Watson * Framework may recurse: if a policy calls a VOP, for example, this might 17217041e67SRobert Watson * lead to vnode life cycle operations (such as init/destroy). 173471e5756SRobert Watson * 174471e5756SRobert Watson * If the kernel option MAC_STATIC has been compiled in, all locking becomes 175471e5756SRobert Watson * a no-op, and the global list of policies is not allowed to change after 176471e5756SRobert Watson * early boot. 177989d4098SRobert Watson * 178989d4098SRobert Watson * XXXRW: Currently, we signal mac_policy_cv every time the framework becomes 179989d4098SRobert Watson * unbusy and there is a thread waiting to enter it exclusively. Since it 180989d4098SRobert Watson * may take some time before the thread runs, we may issue a lot of signals. 181989d4098SRobert Watson * We should instead keep track of the fact that we've signalled, taking into 182989d4098SRobert Watson * account that the framework may be busy again by the time the thread runs, 183989d4098SRobert Watson * requiring us to re-signal. 18495fab37eSRobert Watson */ 1850a05006dSRobert Watson #ifndef MAC_STATIC 18641a17fe3SRobert Watson static struct mtx mac_policy_mtx; 18741a17fe3SRobert Watson static struct cv mac_policy_cv; 18841a17fe3SRobert Watson static int mac_policy_count; 189989d4098SRobert Watson static int mac_policy_wait; 1900a05006dSRobert Watson #endif 191089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list; 192089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list; 193a96acd1aSRobert Watson 194a96acd1aSRobert Watson /* 19517041e67SRobert Watson * We manually invoke WITNESS_WARN() to allow Witness to generate warnings 19617041e67SRobert Watson * even if we don't end up ever triggering the wait at run-time. The 19717041e67SRobert Watson * consumer of the exclusive interface must not hold any locks (other than 19817041e67SRobert Watson * potentially Giant) since we may sleep for long (potentially indefinite) 19917041e67SRobert Watson * periods of time waiting for the framework to become quiescent so that a 20017041e67SRobert Watson * policy list change may be made. 201a96acd1aSRobert Watson */ 202089c1bdaSRobert Watson void 20341a17fe3SRobert Watson mac_policy_grab_exclusive(void) 20441a17fe3SRobert Watson { 205c8e7bf92SRobert Watson 2060a05006dSRobert Watson #ifndef MAC_STATIC 2071e4cadcbSRobert Watson if (!mac_late) 2081e4cadcbSRobert Watson return; 2091e4cadcbSRobert Watson 21041a17fe3SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 21141a17fe3SRobert Watson "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); 21241a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 213989d4098SRobert Watson while (mac_policy_count != 0) { 214989d4098SRobert Watson mac_policy_wait++; 21541a17fe3SRobert Watson cv_wait(&mac_policy_cv, &mac_policy_mtx); 216989d4098SRobert Watson mac_policy_wait--; 217989d4098SRobert Watson } 2180a05006dSRobert Watson #endif 21941a17fe3SRobert Watson } 22095fab37eSRobert Watson 221089c1bdaSRobert Watson void 22241a17fe3SRobert Watson mac_policy_assert_exclusive(void) 22341a17fe3SRobert Watson { 224c8e7bf92SRobert Watson 2250a05006dSRobert Watson #ifndef MAC_STATIC 2261e4cadcbSRobert Watson if (!mac_late) 2271e4cadcbSRobert Watson return; 2281e4cadcbSRobert Watson 22941a17fe3SRobert Watson mtx_assert(&mac_policy_mtx, MA_OWNED); 23041a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 23141a17fe3SRobert Watson ("mac_policy_assert_exclusive(): not exclusive")); 2320a05006dSRobert Watson #endif 23341a17fe3SRobert Watson } 234225bff6fSRobert Watson 235089c1bdaSRobert Watson void 23641a17fe3SRobert Watson mac_policy_release_exclusive(void) 23741a17fe3SRobert Watson { 2380a05006dSRobert Watson #ifndef MAC_STATIC 239989d4098SRobert Watson int dowakeup; 240989d4098SRobert Watson 2411e4cadcbSRobert Watson if (!mac_late) 2421e4cadcbSRobert Watson return; 2431e4cadcbSRobert Watson 24441a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 24541a17fe3SRobert Watson ("mac_policy_release_exclusive(): not exclusive")); 246989d4098SRobert Watson dowakeup = (mac_policy_wait != 0); 24741a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 248989d4098SRobert Watson if (dowakeup) 24941a17fe3SRobert Watson cv_signal(&mac_policy_cv); 2500a05006dSRobert Watson #endif 25141a17fe3SRobert Watson } 25241a17fe3SRobert Watson 253089c1bdaSRobert Watson void 25441a17fe3SRobert Watson mac_policy_list_busy(void) 25541a17fe3SRobert Watson { 256c8e7bf92SRobert Watson 2570a05006dSRobert Watson #ifndef MAC_STATIC 2581e4cadcbSRobert Watson if (!mac_late) 2591e4cadcbSRobert Watson return; 2601e4cadcbSRobert Watson 26141a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 26241a17fe3SRobert Watson mac_policy_count++; 26341a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 2640a05006dSRobert Watson #endif 26541a17fe3SRobert Watson } 26641a17fe3SRobert Watson 267089c1bdaSRobert Watson int 26841a17fe3SRobert Watson mac_policy_list_conditional_busy(void) 26941a17fe3SRobert Watson { 2700a05006dSRobert Watson #ifndef MAC_STATIC 27141a17fe3SRobert Watson int ret; 27241a17fe3SRobert Watson 2731e4cadcbSRobert Watson if (!mac_late) 2741e4cadcbSRobert Watson return (1); 2751e4cadcbSRobert Watson 27641a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 27741a17fe3SRobert Watson if (!LIST_EMPTY(&mac_policy_list)) { 27841a17fe3SRobert Watson mac_policy_count++; 27941a17fe3SRobert Watson ret = 1; 28041a17fe3SRobert Watson } else 28141a17fe3SRobert Watson ret = 0; 28241a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 28341a17fe3SRobert Watson return (ret); 2840a05006dSRobert Watson #else 2851e4cadcbSRobert Watson if (!mac_late) 2861e4cadcbSRobert Watson return (1); 2871e4cadcbSRobert Watson 2880a05006dSRobert Watson return (1); 2890a05006dSRobert Watson #endif 29041a17fe3SRobert Watson } 29141a17fe3SRobert Watson 292089c1bdaSRobert Watson void 29341a17fe3SRobert Watson mac_policy_list_unbusy(void) 29441a17fe3SRobert Watson { 2950a05006dSRobert Watson #ifndef MAC_STATIC 296989d4098SRobert Watson int dowakeup; 297989d4098SRobert Watson 2981e4cadcbSRobert Watson if (!mac_late) 2991e4cadcbSRobert Watson return; 3001e4cadcbSRobert Watson 30141a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 30241a17fe3SRobert Watson mac_policy_count--; 30341a17fe3SRobert Watson KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); 304989d4098SRobert Watson dowakeup = (mac_policy_count == 0 && mac_policy_wait != 0); 30541a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 306989d4098SRobert Watson 307989d4098SRobert Watson if (dowakeup) 308989d4098SRobert Watson cv_signal(&mac_policy_cv); 3090a05006dSRobert Watson #endif 31041a17fe3SRobert Watson } 31195fab37eSRobert Watson 31295fab37eSRobert Watson /* 31395fab37eSRobert Watson * Initialize the MAC subsystem, including appropriate SMP locks. 31495fab37eSRobert Watson */ 31595fab37eSRobert Watson static void 31695fab37eSRobert Watson mac_init(void) 31795fab37eSRobert Watson { 31895fab37eSRobert Watson 31941a17fe3SRobert Watson LIST_INIT(&mac_static_policy_list); 32095fab37eSRobert Watson LIST_INIT(&mac_policy_list); 321eca8a663SRobert Watson mac_labelzone_init(); 32241a17fe3SRobert Watson 3230a05006dSRobert Watson #ifndef MAC_STATIC 32441a17fe3SRobert Watson mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); 32541a17fe3SRobert Watson cv_init(&mac_policy_cv, "mac_policy_cv"); 3260a05006dSRobert Watson #endif 32795fab37eSRobert Watson } 32895fab37eSRobert Watson 32995fab37eSRobert Watson /* 33017041e67SRobert Watson * For the purposes of modules that want to know if they were loaded "early", 33117041e67SRobert Watson * set the mac_late flag once we've processed modules either linked into the 33217041e67SRobert Watson * kernel, or loaded before the kernel startup. 33395fab37eSRobert Watson */ 33495fab37eSRobert Watson static void 33595fab37eSRobert Watson mac_late_init(void) 33695fab37eSRobert Watson { 33795fab37eSRobert Watson 33895fab37eSRobert Watson mac_late = 1; 33995fab37eSRobert Watson } 34095fab37eSRobert Watson 34195fab37eSRobert Watson /* 342225bff6fSRobert Watson * After the policy list has changed, walk the list to update any global 34319c3e120SRobert Watson * flags. Currently, we support only one flag, and it's conditionally 34417041e67SRobert Watson * defined; as a result, the entire function is conditional. Eventually, the 34517041e67SRobert Watson * #else case might also iterate across the policies. 346225bff6fSRobert Watson */ 347225bff6fSRobert Watson static void 348225bff6fSRobert Watson mac_policy_updateflags(void) 349225bff6fSRobert Watson { 350225bff6fSRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF 35119c3e120SRobert Watson struct mac_policy_conf *tmpc; 352225bff6fSRobert Watson int labelmbufs; 353225bff6fSRobert Watson 35441a17fe3SRobert Watson mac_policy_assert_exclusive(); 355225bff6fSRobert Watson 356225bff6fSRobert Watson labelmbufs = 0; 35741a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 35841a17fe3SRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 35941a17fe3SRobert Watson labelmbufs++; 36041a17fe3SRobert Watson } 361225bff6fSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 362225bff6fSRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 363225bff6fSRobert Watson labelmbufs++; 364225bff6fSRobert Watson } 365225bff6fSRobert Watson mac_labelmbufs = (labelmbufs != 0); 366225bff6fSRobert Watson #endif 367225bff6fSRobert Watson } 368225bff6fSRobert Watson 36995fab37eSRobert Watson static int 37095fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc) 37195fab37eSRobert Watson { 37295fab37eSRobert Watson struct mac_policy_conf *tmpc; 37341a17fe3SRobert Watson int error, slot, static_entry; 37495fab37eSRobert Watson 37541a17fe3SRobert Watson error = 0; 37641a17fe3SRobert Watson 37741a17fe3SRobert Watson /* 37817041e67SRobert Watson * We don't technically need exclusive access while !mac_late, but 37917041e67SRobert Watson * hold it for assertion consistency. 38041a17fe3SRobert Watson */ 38141a17fe3SRobert Watson mac_policy_grab_exclusive(); 38241a17fe3SRobert Watson 38341a17fe3SRobert Watson /* 38417041e67SRobert Watson * If the module can potentially be unloaded, or we're loading late, 38517041e67SRobert Watson * we have to stick it in the non-static list and pay an extra 38617041e67SRobert Watson * performance overhead. Otherwise, we can pay a light locking cost 38717041e67SRobert Watson * and stick it in the static list. 38841a17fe3SRobert Watson */ 38941a17fe3SRobert Watson static_entry = (!mac_late && 39041a17fe3SRobert Watson !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 39141a17fe3SRobert Watson 39241a17fe3SRobert Watson if (static_entry) { 39341a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 39441a17fe3SRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 39541a17fe3SRobert Watson error = EEXIST; 39641a17fe3SRobert Watson goto out; 39741a17fe3SRobert Watson } 39841a17fe3SRobert Watson } 39941a17fe3SRobert Watson } else { 40095fab37eSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 40195fab37eSRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 40241a17fe3SRobert Watson error = EEXIST; 40341a17fe3SRobert Watson goto out; 40441a17fe3SRobert Watson } 40595fab37eSRobert Watson } 40695fab37eSRobert Watson } 40795fab37eSRobert Watson if (mpc->mpc_field_off != NULL) { 408b2aef571SRobert Watson slot = ffs(mac_slot_offsets_free); 40995fab37eSRobert Watson if (slot == 0) { 41041a17fe3SRobert Watson error = ENOMEM; 41141a17fe3SRobert Watson goto out; 41295fab37eSRobert Watson } 41395fab37eSRobert Watson slot--; 414b2aef571SRobert Watson mac_slot_offsets_free &= ~(1 << slot); 41595fab37eSRobert Watson *mpc->mpc_field_off = slot; 41695fab37eSRobert Watson } 41795fab37eSRobert Watson mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 41841a17fe3SRobert Watson 41941a17fe3SRobert Watson /* 42017041e67SRobert Watson * If we're loading a MAC module after the framework has initialized, 42117041e67SRobert Watson * it has to go into the dynamic list. If we're loading it before 42217041e67SRobert Watson * we've finished initializing, it can go into the static list with 42317041e67SRobert Watson * weaker locker requirements. 42441a17fe3SRobert Watson */ 42541a17fe3SRobert Watson if (static_entry) 42641a17fe3SRobert Watson LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); 42741a17fe3SRobert Watson else 42895fab37eSRobert Watson LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 42995fab37eSRobert Watson 43017041e67SRobert Watson /* 43117041e67SRobert Watson * Per-policy initialization. Currently, this takes place under the 43217041e67SRobert Watson * exclusive lock, so policies must not sleep in their init method. 43317041e67SRobert Watson * In the future, we may want to separate "init" from "start", with 43417041e67SRobert Watson * "init" occuring without the lock held. Likewise, on tear-down, 43517041e67SRobert Watson * breaking out "stop" from "destroy". 43617041e67SRobert Watson */ 43795fab37eSRobert Watson if (mpc->mpc_ops->mpo_init != NULL) 43895fab37eSRobert Watson (*(mpc->mpc_ops->mpo_init))(mpc); 439225bff6fSRobert Watson mac_policy_updateflags(); 44095fab37eSRobert Watson 44195fab37eSRobert Watson printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 44295fab37eSRobert Watson mpc->mpc_name); 44395fab37eSRobert Watson 44441a17fe3SRobert Watson out: 44541a17fe3SRobert Watson mac_policy_release_exclusive(); 44641a17fe3SRobert Watson return (error); 44795fab37eSRobert Watson } 44895fab37eSRobert Watson 44995fab37eSRobert Watson static int 45095fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc) 45195fab37eSRobert Watson { 45295fab37eSRobert Watson 453ea599aa0SRobert Watson /* 45417041e67SRobert Watson * If we fail the load, we may get a request to unload. Check to see 45517041e67SRobert Watson * if we did the run-time registration, and if not, silently succeed. 456ea599aa0SRobert Watson */ 45741a17fe3SRobert Watson mac_policy_grab_exclusive(); 458ea599aa0SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 45941a17fe3SRobert Watson mac_policy_release_exclusive(); 460ea599aa0SRobert Watson return (0); 461ea599aa0SRobert Watson } 46295fab37eSRobert Watson #if 0 46395fab37eSRobert Watson /* 46495fab37eSRobert Watson * Don't allow unloading modules with private data. 46595fab37eSRobert Watson */ 466ea599aa0SRobert Watson if (mpc->mpc_field_off != NULL) { 467ea599aa0SRobert Watson MAC_POLICY_LIST_UNLOCK(); 46895fab37eSRobert Watson return (EBUSY); 469ea599aa0SRobert Watson } 47095fab37eSRobert Watson #endif 471ea599aa0SRobert Watson /* 47217041e67SRobert Watson * Only allow the unload to proceed if the module is unloadable by 47317041e67SRobert Watson * its own definition. 474ea599aa0SRobert Watson */ 475ea599aa0SRobert Watson if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 47641a17fe3SRobert Watson mac_policy_release_exclusive(); 47795fab37eSRobert Watson return (EBUSY); 478ea599aa0SRobert Watson } 47995fab37eSRobert Watson if (mpc->mpc_ops->mpo_destroy != NULL) 48095fab37eSRobert Watson (*(mpc->mpc_ops->mpo_destroy))(mpc); 48195fab37eSRobert Watson 48295fab37eSRobert Watson LIST_REMOVE(mpc, mpc_list); 4839aeffb2bSRobert Watson mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 484225bff6fSRobert Watson mac_policy_updateflags(); 48541a17fe3SRobert Watson 48641a17fe3SRobert Watson mac_policy_release_exclusive(); 487a96acd1aSRobert Watson 48895fab37eSRobert Watson printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 48995fab37eSRobert Watson mpc->mpc_name); 49095fab37eSRobert Watson 49195fab37eSRobert Watson return (0); 49295fab37eSRobert Watson } 49395fab37eSRobert Watson 49495fab37eSRobert Watson /* 495c441d123SRobert Watson * Allow MAC policy modules to register during boot, etc. 496c441d123SRobert Watson */ 497c441d123SRobert Watson int 498c441d123SRobert Watson mac_policy_modevent(module_t mod, int type, void *data) 499c441d123SRobert Watson { 500c441d123SRobert Watson struct mac_policy_conf *mpc; 501c441d123SRobert Watson int error; 502c441d123SRobert Watson 503c441d123SRobert Watson error = 0; 504c441d123SRobert Watson mpc = (struct mac_policy_conf *) data; 505c441d123SRobert Watson 506c441d123SRobert Watson #ifdef MAC_STATIC 507c441d123SRobert Watson if (mac_late) { 508c441d123SRobert Watson printf("mac_policy_modevent: MAC_STATIC and late\n"); 509c441d123SRobert Watson return (EBUSY); 510c441d123SRobert Watson } 511c441d123SRobert Watson #endif 512c441d123SRobert Watson 513c441d123SRobert Watson switch (type) { 514c441d123SRobert Watson case MOD_LOAD: 515c441d123SRobert Watson if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 516c441d123SRobert Watson mac_late) { 517c441d123SRobert Watson printf("mac_policy_modevent: can't load %s policy " 518c441d123SRobert Watson "after booting\n", mpc->mpc_name); 519c441d123SRobert Watson error = EBUSY; 520c441d123SRobert Watson break; 521c441d123SRobert Watson } 522c441d123SRobert Watson error = mac_policy_register(mpc); 523c441d123SRobert Watson break; 524c441d123SRobert Watson case MOD_UNLOAD: 525c441d123SRobert Watson /* Don't unregister the module if it was never registered. */ 526c441d123SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 527c441d123SRobert Watson != 0) 528c441d123SRobert Watson error = mac_policy_unregister(mpc); 529c441d123SRobert Watson else 530c441d123SRobert Watson error = 0; 531c441d123SRobert Watson break; 532c441d123SRobert Watson default: 533c441d123SRobert Watson error = EOPNOTSUPP; 534c441d123SRobert Watson break; 535c441d123SRobert Watson } 536c441d123SRobert Watson 537c441d123SRobert Watson return (error); 538c441d123SRobert Watson } 539c441d123SRobert Watson 540c441d123SRobert Watson /* 54195fab37eSRobert Watson * Define an error value precedence, and given two arguments, selects the 54295fab37eSRobert Watson * value with the higher precedence. 54395fab37eSRobert Watson */ 5449e7bf51cSRobert Watson int 5459e7bf51cSRobert Watson mac_error_select(int error1, int error2) 54695fab37eSRobert Watson { 54795fab37eSRobert Watson 54895fab37eSRobert Watson /* Certain decision-making errors take top priority. */ 54995fab37eSRobert Watson if (error1 == EDEADLK || error2 == EDEADLK) 55095fab37eSRobert Watson return (EDEADLK); 55195fab37eSRobert Watson 55295fab37eSRobert Watson /* Invalid arguments should be reported where possible. */ 55395fab37eSRobert Watson if (error1 == EINVAL || error2 == EINVAL) 55495fab37eSRobert Watson return (EINVAL); 55595fab37eSRobert Watson 55695fab37eSRobert Watson /* Precedence goes to "visibility", with both process and file. */ 55795fab37eSRobert Watson if (error1 == ESRCH || error2 == ESRCH) 55895fab37eSRobert Watson return (ESRCH); 55995fab37eSRobert Watson 56095fab37eSRobert Watson if (error1 == ENOENT || error2 == ENOENT) 56195fab37eSRobert Watson return (ENOENT); 56295fab37eSRobert Watson 56395fab37eSRobert Watson /* Precedence goes to DAC/MAC protections. */ 56495fab37eSRobert Watson if (error1 == EACCES || error2 == EACCES) 56595fab37eSRobert Watson return (EACCES); 56695fab37eSRobert Watson 56795fab37eSRobert Watson /* Precedence goes to privilege. */ 56895fab37eSRobert Watson if (error1 == EPERM || error2 == EPERM) 56995fab37eSRobert Watson return (EPERM); 57095fab37eSRobert Watson 57195fab37eSRobert Watson /* Precedence goes to error over success; otherwise, arbitrary. */ 57295fab37eSRobert Watson if (error1 != 0) 57395fab37eSRobert Watson return (error1); 57495fab37eSRobert Watson return (error2); 57595fab37eSRobert Watson } 57695fab37eSRobert Watson 5775e7ce478SRobert Watson int 578f7b951a8SRobert Watson mac_check_structmac_consistent(struct mac *mac) 579f7b951a8SRobert Watson { 580f7b951a8SRobert Watson 581cc7b13bfSRobert Watson if (mac->m_buflen < 0 || 582cc7b13bfSRobert Watson mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 583f7b951a8SRobert Watson return (EINVAL); 584f7b951a8SRobert Watson 585f7b951a8SRobert Watson return (0); 586f7b951a8SRobert Watson } 587f7b951a8SRobert Watson 58895fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 58995fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 590