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. 17795fab37eSRobert Watson */ 1780a05006dSRobert Watson #ifndef MAC_STATIC 17941a17fe3SRobert Watson static struct mtx mac_policy_mtx; 18041a17fe3SRobert Watson static struct cv mac_policy_cv; 18141a17fe3SRobert Watson static int mac_policy_count; 1820a05006dSRobert Watson #endif 183089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list; 184089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list; 185a96acd1aSRobert Watson 186a96acd1aSRobert Watson /* 18717041e67SRobert Watson * We manually invoke WITNESS_WARN() to allow Witness to generate warnings 18817041e67SRobert Watson * even if we don't end up ever triggering the wait at run-time. The 18917041e67SRobert Watson * consumer of the exclusive interface must not hold any locks (other than 19017041e67SRobert Watson * potentially Giant) since we may sleep for long (potentially indefinite) 19117041e67SRobert Watson * periods of time waiting for the framework to become quiescent so that a 19217041e67SRobert Watson * policy list change may be made. 193a96acd1aSRobert Watson */ 194089c1bdaSRobert Watson void 19541a17fe3SRobert Watson mac_policy_grab_exclusive(void) 19641a17fe3SRobert Watson { 197c8e7bf92SRobert Watson 1980a05006dSRobert Watson #ifndef MAC_STATIC 1991e4cadcbSRobert Watson if (!mac_late) 2001e4cadcbSRobert Watson return; 2011e4cadcbSRobert Watson 20241a17fe3SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 20341a17fe3SRobert Watson "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); 20441a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 20541a17fe3SRobert Watson while (mac_policy_count != 0) 20641a17fe3SRobert Watson cv_wait(&mac_policy_cv, &mac_policy_mtx); 2070a05006dSRobert Watson #endif 20841a17fe3SRobert Watson } 20995fab37eSRobert Watson 210089c1bdaSRobert Watson void 21141a17fe3SRobert Watson mac_policy_assert_exclusive(void) 21241a17fe3SRobert Watson { 213c8e7bf92SRobert Watson 2140a05006dSRobert Watson #ifndef MAC_STATIC 2151e4cadcbSRobert Watson if (!mac_late) 2161e4cadcbSRobert Watson return; 2171e4cadcbSRobert Watson 21841a17fe3SRobert Watson mtx_assert(&mac_policy_mtx, MA_OWNED); 21941a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 22041a17fe3SRobert Watson ("mac_policy_assert_exclusive(): not exclusive")); 2210a05006dSRobert Watson #endif 22241a17fe3SRobert Watson } 223225bff6fSRobert Watson 224089c1bdaSRobert Watson void 22541a17fe3SRobert Watson mac_policy_release_exclusive(void) 22641a17fe3SRobert Watson { 22795fab37eSRobert Watson 2280a05006dSRobert Watson #ifndef MAC_STATIC 2291e4cadcbSRobert Watson if (!mac_late) 2301e4cadcbSRobert Watson return; 2311e4cadcbSRobert Watson 23241a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 23341a17fe3SRobert Watson ("mac_policy_release_exclusive(): not exclusive")); 23441a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 23541a17fe3SRobert Watson cv_signal(&mac_policy_cv); 2360a05006dSRobert Watson #endif 23741a17fe3SRobert Watson } 23841a17fe3SRobert Watson 239089c1bdaSRobert Watson void 24041a17fe3SRobert Watson mac_policy_list_busy(void) 24141a17fe3SRobert Watson { 242c8e7bf92SRobert Watson 2430a05006dSRobert Watson #ifndef MAC_STATIC 2441e4cadcbSRobert Watson if (!mac_late) 2451e4cadcbSRobert Watson return; 2461e4cadcbSRobert Watson 24741a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 24841a17fe3SRobert Watson mac_policy_count++; 24941a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 2500a05006dSRobert Watson #endif 25141a17fe3SRobert Watson } 25241a17fe3SRobert Watson 253089c1bdaSRobert Watson int 25441a17fe3SRobert Watson mac_policy_list_conditional_busy(void) 25541a17fe3SRobert Watson { 2560a05006dSRobert Watson #ifndef MAC_STATIC 25741a17fe3SRobert Watson int ret; 25841a17fe3SRobert Watson 2591e4cadcbSRobert Watson if (!mac_late) 2601e4cadcbSRobert Watson return (1); 2611e4cadcbSRobert Watson 26241a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 26341a17fe3SRobert Watson if (!LIST_EMPTY(&mac_policy_list)) { 26441a17fe3SRobert Watson mac_policy_count++; 26541a17fe3SRobert Watson ret = 1; 26641a17fe3SRobert Watson } else 26741a17fe3SRobert Watson ret = 0; 26841a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 26941a17fe3SRobert Watson return (ret); 2700a05006dSRobert Watson #else 2711e4cadcbSRobert Watson if (!mac_late) 2721e4cadcbSRobert Watson return (1); 2731e4cadcbSRobert Watson 2740a05006dSRobert Watson return (1); 2750a05006dSRobert Watson #endif 27641a17fe3SRobert Watson } 27741a17fe3SRobert Watson 278089c1bdaSRobert Watson void 27941a17fe3SRobert Watson mac_policy_list_unbusy(void) 28041a17fe3SRobert Watson { 281c8e7bf92SRobert Watson 2820a05006dSRobert Watson #ifndef MAC_STATIC 2831e4cadcbSRobert Watson if (!mac_late) 2841e4cadcbSRobert Watson return; 2851e4cadcbSRobert Watson 28641a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 28741a17fe3SRobert Watson mac_policy_count--; 28841a17fe3SRobert Watson KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); 28941a17fe3SRobert Watson if (mac_policy_count == 0) 29041a17fe3SRobert Watson cv_signal(&mac_policy_cv); 29141a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 2920a05006dSRobert Watson #endif 29341a17fe3SRobert Watson } 29495fab37eSRobert Watson 29595fab37eSRobert Watson /* 29695fab37eSRobert Watson * Initialize the MAC subsystem, including appropriate SMP locks. 29795fab37eSRobert Watson */ 29895fab37eSRobert Watson static void 29995fab37eSRobert Watson mac_init(void) 30095fab37eSRobert Watson { 30195fab37eSRobert Watson 30241a17fe3SRobert Watson LIST_INIT(&mac_static_policy_list); 30395fab37eSRobert Watson LIST_INIT(&mac_policy_list); 304eca8a663SRobert Watson mac_labelzone_init(); 30541a17fe3SRobert Watson 3060a05006dSRobert Watson #ifndef MAC_STATIC 30741a17fe3SRobert Watson mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); 30841a17fe3SRobert Watson cv_init(&mac_policy_cv, "mac_policy_cv"); 3090a05006dSRobert Watson #endif 31095fab37eSRobert Watson } 31195fab37eSRobert Watson 31295fab37eSRobert Watson /* 31317041e67SRobert Watson * For the purposes of modules that want to know if they were loaded "early", 31417041e67SRobert Watson * set the mac_late flag once we've processed modules either linked into the 31517041e67SRobert Watson * kernel, or loaded before the kernel startup. 31695fab37eSRobert Watson */ 31795fab37eSRobert Watson static void 31895fab37eSRobert Watson mac_late_init(void) 31995fab37eSRobert Watson { 32095fab37eSRobert Watson 32195fab37eSRobert Watson mac_late = 1; 32295fab37eSRobert Watson } 32395fab37eSRobert Watson 32495fab37eSRobert Watson /* 325225bff6fSRobert Watson * After the policy list has changed, walk the list to update any global 32619c3e120SRobert Watson * flags. Currently, we support only one flag, and it's conditionally 32717041e67SRobert Watson * defined; as a result, the entire function is conditional. Eventually, the 32817041e67SRobert Watson * #else case might also iterate across the policies. 329225bff6fSRobert Watson */ 330225bff6fSRobert Watson static void 331225bff6fSRobert Watson mac_policy_updateflags(void) 332225bff6fSRobert Watson { 333225bff6fSRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF 33419c3e120SRobert Watson struct mac_policy_conf *tmpc; 335225bff6fSRobert Watson int labelmbufs; 336225bff6fSRobert Watson 33741a17fe3SRobert Watson mac_policy_assert_exclusive(); 338225bff6fSRobert Watson 339225bff6fSRobert Watson labelmbufs = 0; 34041a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 34141a17fe3SRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 34241a17fe3SRobert Watson labelmbufs++; 34341a17fe3SRobert Watson } 344225bff6fSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 345225bff6fSRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 346225bff6fSRobert Watson labelmbufs++; 347225bff6fSRobert Watson } 348225bff6fSRobert Watson mac_labelmbufs = (labelmbufs != 0); 349225bff6fSRobert Watson #endif 350225bff6fSRobert Watson } 351225bff6fSRobert Watson 35295fab37eSRobert Watson static int 35395fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc) 35495fab37eSRobert Watson { 35595fab37eSRobert Watson struct mac_policy_conf *tmpc; 35641a17fe3SRobert Watson int error, slot, static_entry; 35795fab37eSRobert Watson 35841a17fe3SRobert Watson error = 0; 35941a17fe3SRobert Watson 36041a17fe3SRobert Watson /* 36117041e67SRobert Watson * We don't technically need exclusive access while !mac_late, but 36217041e67SRobert Watson * hold it for assertion consistency. 36341a17fe3SRobert Watson */ 36441a17fe3SRobert Watson mac_policy_grab_exclusive(); 36541a17fe3SRobert Watson 36641a17fe3SRobert Watson /* 36717041e67SRobert Watson * If the module can potentially be unloaded, or we're loading late, 36817041e67SRobert Watson * we have to stick it in the non-static list and pay an extra 36917041e67SRobert Watson * performance overhead. Otherwise, we can pay a light locking cost 37017041e67SRobert Watson * and stick it in the static list. 37141a17fe3SRobert Watson */ 37241a17fe3SRobert Watson static_entry = (!mac_late && 37341a17fe3SRobert Watson !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 37441a17fe3SRobert Watson 37541a17fe3SRobert Watson if (static_entry) { 37641a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 37741a17fe3SRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 37841a17fe3SRobert Watson error = EEXIST; 37941a17fe3SRobert Watson goto out; 38041a17fe3SRobert Watson } 38141a17fe3SRobert Watson } 38241a17fe3SRobert Watson } else { 38395fab37eSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 38495fab37eSRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 38541a17fe3SRobert Watson error = EEXIST; 38641a17fe3SRobert Watson goto out; 38741a17fe3SRobert Watson } 38895fab37eSRobert Watson } 38995fab37eSRobert Watson } 39095fab37eSRobert Watson if (mpc->mpc_field_off != NULL) { 391b2aef571SRobert Watson slot = ffs(mac_slot_offsets_free); 39295fab37eSRobert Watson if (slot == 0) { 39341a17fe3SRobert Watson error = ENOMEM; 39441a17fe3SRobert Watson goto out; 39595fab37eSRobert Watson } 39695fab37eSRobert Watson slot--; 397b2aef571SRobert Watson mac_slot_offsets_free &= ~(1 << slot); 39895fab37eSRobert Watson *mpc->mpc_field_off = slot; 39995fab37eSRobert Watson } 40095fab37eSRobert Watson mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 40141a17fe3SRobert Watson 40241a17fe3SRobert Watson /* 40317041e67SRobert Watson * If we're loading a MAC module after the framework has initialized, 40417041e67SRobert Watson * it has to go into the dynamic list. If we're loading it before 40517041e67SRobert Watson * we've finished initializing, it can go into the static list with 40617041e67SRobert Watson * weaker locker requirements. 40741a17fe3SRobert Watson */ 40841a17fe3SRobert Watson if (static_entry) 40941a17fe3SRobert Watson LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); 41041a17fe3SRobert Watson else 41195fab37eSRobert Watson LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 41295fab37eSRobert Watson 41317041e67SRobert Watson /* 41417041e67SRobert Watson * Per-policy initialization. Currently, this takes place under the 41517041e67SRobert Watson * exclusive lock, so policies must not sleep in their init method. 41617041e67SRobert Watson * In the future, we may want to separate "init" from "start", with 41717041e67SRobert Watson * "init" occuring without the lock held. Likewise, on tear-down, 41817041e67SRobert Watson * breaking out "stop" from "destroy". 41917041e67SRobert Watson */ 42095fab37eSRobert Watson if (mpc->mpc_ops->mpo_init != NULL) 42195fab37eSRobert Watson (*(mpc->mpc_ops->mpo_init))(mpc); 422225bff6fSRobert Watson mac_policy_updateflags(); 42395fab37eSRobert Watson 42495fab37eSRobert Watson printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 42595fab37eSRobert Watson mpc->mpc_name); 42695fab37eSRobert Watson 42741a17fe3SRobert Watson out: 42841a17fe3SRobert Watson mac_policy_release_exclusive(); 42941a17fe3SRobert Watson return (error); 43095fab37eSRobert Watson } 43195fab37eSRobert Watson 43295fab37eSRobert Watson static int 43395fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc) 43495fab37eSRobert Watson { 43595fab37eSRobert Watson 436ea599aa0SRobert Watson /* 43717041e67SRobert Watson * If we fail the load, we may get a request to unload. Check to see 43817041e67SRobert Watson * if we did the run-time registration, and if not, silently succeed. 439ea599aa0SRobert Watson */ 44041a17fe3SRobert Watson mac_policy_grab_exclusive(); 441ea599aa0SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 44241a17fe3SRobert Watson mac_policy_release_exclusive(); 443ea599aa0SRobert Watson return (0); 444ea599aa0SRobert Watson } 44595fab37eSRobert Watson #if 0 44695fab37eSRobert Watson /* 44795fab37eSRobert Watson * Don't allow unloading modules with private data. 44895fab37eSRobert Watson */ 449ea599aa0SRobert Watson if (mpc->mpc_field_off != NULL) { 450ea599aa0SRobert Watson MAC_POLICY_LIST_UNLOCK(); 45195fab37eSRobert Watson return (EBUSY); 452ea599aa0SRobert Watson } 45395fab37eSRobert Watson #endif 454ea599aa0SRobert Watson /* 45517041e67SRobert Watson * Only allow the unload to proceed if the module is unloadable by 45617041e67SRobert Watson * its own definition. 457ea599aa0SRobert Watson */ 458ea599aa0SRobert Watson if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 45941a17fe3SRobert Watson mac_policy_release_exclusive(); 46095fab37eSRobert Watson return (EBUSY); 461ea599aa0SRobert Watson } 46295fab37eSRobert Watson if (mpc->mpc_ops->mpo_destroy != NULL) 46395fab37eSRobert Watson (*(mpc->mpc_ops->mpo_destroy))(mpc); 46495fab37eSRobert Watson 46595fab37eSRobert Watson LIST_REMOVE(mpc, mpc_list); 4669aeffb2bSRobert Watson mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 467225bff6fSRobert Watson mac_policy_updateflags(); 46841a17fe3SRobert Watson 46941a17fe3SRobert Watson mac_policy_release_exclusive(); 470a96acd1aSRobert Watson 47195fab37eSRobert Watson printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 47295fab37eSRobert Watson mpc->mpc_name); 47395fab37eSRobert Watson 47495fab37eSRobert Watson return (0); 47595fab37eSRobert Watson } 47695fab37eSRobert Watson 47795fab37eSRobert Watson /* 478c441d123SRobert Watson * Allow MAC policy modules to register during boot, etc. 479c441d123SRobert Watson */ 480c441d123SRobert Watson int 481c441d123SRobert Watson mac_policy_modevent(module_t mod, int type, void *data) 482c441d123SRobert Watson { 483c441d123SRobert Watson struct mac_policy_conf *mpc; 484c441d123SRobert Watson int error; 485c441d123SRobert Watson 486c441d123SRobert Watson error = 0; 487c441d123SRobert Watson mpc = (struct mac_policy_conf *) data; 488c441d123SRobert Watson 489c441d123SRobert Watson #ifdef MAC_STATIC 490c441d123SRobert Watson if (mac_late) { 491c441d123SRobert Watson printf("mac_policy_modevent: MAC_STATIC and late\n"); 492c441d123SRobert Watson return (EBUSY); 493c441d123SRobert Watson } 494c441d123SRobert Watson #endif 495c441d123SRobert Watson 496c441d123SRobert Watson switch (type) { 497c441d123SRobert Watson case MOD_LOAD: 498c441d123SRobert Watson if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 499c441d123SRobert Watson mac_late) { 500c441d123SRobert Watson printf("mac_policy_modevent: can't load %s policy " 501c441d123SRobert Watson "after booting\n", mpc->mpc_name); 502c441d123SRobert Watson error = EBUSY; 503c441d123SRobert Watson break; 504c441d123SRobert Watson } 505c441d123SRobert Watson error = mac_policy_register(mpc); 506c441d123SRobert Watson break; 507c441d123SRobert Watson case MOD_UNLOAD: 508c441d123SRobert Watson /* Don't unregister the module if it was never registered. */ 509c441d123SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 510c441d123SRobert Watson != 0) 511c441d123SRobert Watson error = mac_policy_unregister(mpc); 512c441d123SRobert Watson else 513c441d123SRobert Watson error = 0; 514c441d123SRobert Watson break; 515c441d123SRobert Watson default: 516c441d123SRobert Watson error = EOPNOTSUPP; 517c441d123SRobert Watson break; 518c441d123SRobert Watson } 519c441d123SRobert Watson 520c441d123SRobert Watson return (error); 521c441d123SRobert Watson } 522c441d123SRobert Watson 523c441d123SRobert Watson /* 52495fab37eSRobert Watson * Define an error value precedence, and given two arguments, selects the 52595fab37eSRobert Watson * value with the higher precedence. 52695fab37eSRobert Watson */ 5279e7bf51cSRobert Watson int 5289e7bf51cSRobert Watson mac_error_select(int error1, int error2) 52995fab37eSRobert Watson { 53095fab37eSRobert Watson 53195fab37eSRobert Watson /* Certain decision-making errors take top priority. */ 53295fab37eSRobert Watson if (error1 == EDEADLK || error2 == EDEADLK) 53395fab37eSRobert Watson return (EDEADLK); 53495fab37eSRobert Watson 53595fab37eSRobert Watson /* Invalid arguments should be reported where possible. */ 53695fab37eSRobert Watson if (error1 == EINVAL || error2 == EINVAL) 53795fab37eSRobert Watson return (EINVAL); 53895fab37eSRobert Watson 53995fab37eSRobert Watson /* Precedence goes to "visibility", with both process and file. */ 54095fab37eSRobert Watson if (error1 == ESRCH || error2 == ESRCH) 54195fab37eSRobert Watson return (ESRCH); 54295fab37eSRobert Watson 54395fab37eSRobert Watson if (error1 == ENOENT || error2 == ENOENT) 54495fab37eSRobert Watson return (ENOENT); 54595fab37eSRobert Watson 54695fab37eSRobert Watson /* Precedence goes to DAC/MAC protections. */ 54795fab37eSRobert Watson if (error1 == EACCES || error2 == EACCES) 54895fab37eSRobert Watson return (EACCES); 54995fab37eSRobert Watson 55095fab37eSRobert Watson /* Precedence goes to privilege. */ 55195fab37eSRobert Watson if (error1 == EPERM || error2 == EPERM) 55295fab37eSRobert Watson return (EPERM); 55395fab37eSRobert Watson 55495fab37eSRobert Watson /* Precedence goes to error over success; otherwise, arbitrary. */ 55595fab37eSRobert Watson if (error1 != 0) 55695fab37eSRobert Watson return (error1); 55795fab37eSRobert Watson return (error2); 55895fab37eSRobert Watson } 55995fab37eSRobert Watson 5605e7ce478SRobert Watson int 561f7b951a8SRobert Watson mac_check_structmac_consistent(struct mac *mac) 562f7b951a8SRobert Watson { 563f7b951a8SRobert Watson 564cc7b13bfSRobert Watson if (mac->m_buflen < 0 || 565cc7b13bfSRobert Watson mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 566f7b951a8SRobert Watson return (EINVAL); 567f7b951a8SRobert Watson 568f7b951a8SRobert Watson return (0); 569f7b951a8SRobert Watson } 570f7b951a8SRobert Watson 57195fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 57295fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 573