17bc82500SRobert Watson /*- 291ec0006SRobert Watson * Copyright (c) 1999-2002, 2006, 2009 Robert N. M. Watson 37bc82500SRobert Watson * Copyright (c) 2001 Ilmar S. Habibulin 4f0c2044bSRobert Watson * Copyright (c) 2001-2005 Networks Associates Technology, Inc. 5aed55708SRobert Watson * Copyright (c) 2005-2006 SPARTA, Inc. 69162f64bSRobert Watson * Copyright (c) 2008-2009 Apple Inc. 77bc82500SRobert Watson * All rights reserved. 87bc82500SRobert Watson * 97bc82500SRobert Watson * This software was developed by Robert Watson and Ilmar Habibulin for the 107bc82500SRobert Watson * TrustedBSD Project. 117bc82500SRobert Watson * 126201265bSRobert Watson * This software was developed for the FreeBSD Project in part by Network 136201265bSRobert Watson * Associates Laboratories, the Security Research Division of Network 146201265bSRobert Watson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 156201265bSRobert Watson * as part of the DARPA CHATS research program. 167bc82500SRobert Watson * 1749bb6870SRobert Watson * This software was enhanced by SPARTA ISSO under SPAWAR contract 1849bb6870SRobert Watson * N66001-04-C-6019 ("SEFOS"). 1949bb6870SRobert Watson * 206f6174a7SRobert Watson * This software was developed at the University of Cambridge Computer 216f6174a7SRobert Watson * Laboratory with support from a grant from Google, Inc. 226f6174a7SRobert Watson * 237bc82500SRobert Watson * Redistribution and use in source and binary forms, with or without 247bc82500SRobert Watson * modification, are permitted provided that the following conditions 257bc82500SRobert Watson * are met: 267bc82500SRobert Watson * 1. Redistributions of source code must retain the above copyright 277bc82500SRobert Watson * notice, this list of conditions and the following disclaimer. 287bc82500SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 297bc82500SRobert Watson * notice, this list of conditions and the following disclaimer in the 307bc82500SRobert Watson * documentation and/or other materials provided with the distribution. 317bc82500SRobert Watson * 327bc82500SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 337bc82500SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 347bc82500SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 357bc82500SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 367bc82500SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 377bc82500SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 387bc82500SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 397bc82500SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 407bc82500SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 417bc82500SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 427bc82500SRobert Watson * SUCH DAMAGE. 437bc82500SRobert Watson */ 44677b542eSDavid E. O'Brien 45c8e7bf92SRobert Watson /*- 46471e5756SRobert Watson * Framework for extensible kernel access control. This file contains core 47471e5756SRobert Watson * kernel infrastructure for the TrustedBSD MAC Framework, including policy 48471e5756SRobert Watson * registration, versioning, locking, error composition operator, and system 49471e5756SRobert Watson * calls. 50471e5756SRobert Watson * 51471e5756SRobert Watson * The MAC Framework implements three programming interfaces: 52471e5756SRobert Watson * 53471e5756SRobert Watson * - The kernel MAC interface, defined in mac_framework.h, and invoked 54471e5756SRobert Watson * throughout the kernel to request security decisions, notify of security 55471e5756SRobert Watson * related events, etc. 56471e5756SRobert Watson * 57471e5756SRobert Watson * - The MAC policy module interface, defined in mac_policy.h, which is 58471e5756SRobert Watson * implemented by MAC policy modules and invoked by the MAC Framework to 59471e5756SRobert Watson * forward kernel security requests and notifications to policy modules. 60471e5756SRobert Watson * 61471e5756SRobert Watson * - The user MAC API, defined in mac.h, which allows user programs to query 62471e5756SRobert Watson * and set label state on objects. 63471e5756SRobert Watson * 64471e5756SRobert Watson * The majority of the MAC Framework implementation may be found in 65471e5756SRobert Watson * src/sys/security/mac. Sample policy modules may be found in 6649869305STom Rhodes * src/sys/security/mac_*. 677bc82500SRobert Watson */ 687bc82500SRobert Watson 6991ec0006SRobert Watson #include "opt_kdtrace.h" 7039b73a30SRobert Watson #include "opt_mac.h" 7139b73a30SRobert Watson 72677b542eSDavid E. O'Brien #include <sys/cdefs.h> 73677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 74677b542eSDavid E. O'Brien 757bc82500SRobert Watson #include <sys/param.h> 76a96acd1aSRobert Watson #include <sys/condvar.h> 7795fab37eSRobert Watson #include <sys/kernel.h> 7895fab37eSRobert Watson #include <sys/lock.h> 7995fab37eSRobert Watson #include <sys/mac.h> 807ba28492SRobert Watson #include <sys/module.h> 8181fee06fSRobert Watson #include <sys/rmlock.h> 8291ec0006SRobert Watson #include <sys/sdt.h> 8340202729SRobert Watson #include <sys/sx.h> 8495fab37eSRobert Watson #include <sys/systm.h> 8595fab37eSRobert Watson #include <sys/sysctl.h> 8695fab37eSRobert Watson 87aed55708SRobert Watson #include <security/mac/mac_framework.h> 886fa0475dSRobert Watson #include <security/mac/mac_internal.h> 890efd6615SRobert Watson #include <security/mac/mac_policy.h> 906fa0475dSRobert Watson 917ba28492SRobert Watson /* 922087a58cSRobert Watson * DTrace SDT providers for MAC. 9391ec0006SRobert Watson */ 9491ec0006SRobert Watson SDT_PROVIDER_DEFINE(mac); 952087a58cSRobert Watson SDT_PROVIDER_DEFINE(mac_framework); 962087a58cSRobert Watson 9779856499SRui Paulo SDT_PROBE_DEFINE2(mac, kernel, policy, modevent, modevent, "int", 9891ec0006SRobert Watson "struct mac_policy_conf *mpc"); 9979856499SRui Paulo SDT_PROBE_DEFINE1(mac, kernel, policy, register, register, 10079856499SRui Paulo "struct mac_policy_conf *"); 10179856499SRui Paulo SDT_PROBE_DEFINE1(mac, kernel, policy, unregister, unregister, 10279856499SRui Paulo "struct mac_policy_conf *"); 10391ec0006SRobert Watson 10491ec0006SRobert Watson /* 105471e5756SRobert Watson * Root sysctl node for all MAC and MAC policy controls. 1067ba28492SRobert Watson */ 10795fab37eSRobert Watson SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, 10895fab37eSRobert Watson "TrustedBSD MAC policy controls"); 109b2f0927aSRobert Watson 11017041e67SRobert Watson /* 111471e5756SRobert Watson * Declare that the kernel provides MAC support, version 3 (FreeBSD 7.x). 112471e5756SRobert Watson * This permits modules to refuse to be loaded if the necessary support isn't 113471e5756SRobert Watson * present, even if it's pre-boot. 114471e5756SRobert Watson */ 115471e5756SRobert Watson MODULE_VERSION(kernel_mac_support, MAC_VERSION); 116be23ba9aSRobert Watson 117be23ba9aSRobert Watson static unsigned int mac_version = MAC_VERSION; 118471e5756SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, version, CTLFLAG_RD, &mac_version, 0, 119471e5756SRobert Watson ""); 120471e5756SRobert Watson 121471e5756SRobert Watson /* 12217041e67SRobert Watson * Labels consist of a indexed set of "slots", which are allocated policies 12317041e67SRobert Watson * as required. The MAC Framework maintains a bitmask of slots allocated so 12417041e67SRobert Watson * far to prevent reuse. Slots cannot be reused, as the MAC Framework 12517041e67SRobert Watson * guarantees that newly allocated slots in labels will be NULL unless 12617041e67SRobert Watson * otherwise initialized, and because we do not have a mechanism to garbage 12717041e67SRobert Watson * collect slots on policy unload. As labeled policies tend to be statically 12817041e67SRobert Watson * loaded during boot, and not frequently unloaded and reloaded, this is not 12917041e67SRobert Watson * generally an issue. 13017041e67SRobert Watson */ 131b2aef571SRobert Watson #if MAC_MAX_SLOTS > 32 132b2aef571SRobert Watson #error "MAC_MAX_SLOTS too large" 13395fab37eSRobert Watson #endif 134a13c67daSRobert Watson 135b2aef571SRobert Watson static unsigned int mac_max_slots = MAC_MAX_SLOTS; 136b2aef571SRobert Watson static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1; 137471e5756SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, &mac_max_slots, 138471e5756SRobert Watson 0, ""); 13995fab37eSRobert Watson 140a67fe518SRobert Watson /* 141a67fe518SRobert Watson * Has the kernel started generating labeled objects yet? All read/write 142a67fe518SRobert Watson * access to this variable is serialized during the boot process. Following 143a67fe518SRobert Watson * the end of serialization, we don't update this flag; no locking. 144a67fe518SRobert Watson */ 145be23ba9aSRobert Watson static int mac_late = 0; 146763bbd2fSRobert Watson 147225bff6fSRobert Watson /* 1486356dba0SRobert Watson * Each policy declares a mask of object types requiring labels to be 1496356dba0SRobert Watson * allocated for them. For convenience, we combine and cache the bitwise or 1506356dba0SRobert Watson * of the per-policy object flags to track whether we will allocate a label 1516356dba0SRobert Watson * for an object type at run-time. 152225bff6fSRobert Watson */ 1536356dba0SRobert Watson uint64_t mac_labeled; 154*123d2cb7SMatthew D Fleming SYSCTL_UQUAD(_security_mac, OID_AUTO, labeled, CTLFLAG_RD, &mac_labeled, 0, 1556356dba0SRobert Watson "Mask of object types being labeled"); 156225bff6fSRobert Watson 157f7b951a8SRobert Watson MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 15895fab37eSRobert Watson 15995fab37eSRobert Watson /* 16040202729SRobert Watson * MAC policy modules are placed in one of two lists: mac_static_policy_list, 16140202729SRobert Watson * for policies that are loaded early and cannot be unloaded, and 16240202729SRobert Watson * mac_policy_list, which holds policies either loaded later in the boot 16340202729SRobert Watson * cycle or that may be unloaded. The static policy list does not require 16440202729SRobert Watson * locks to iterate over, but the dynamic list requires synchronization. 16540202729SRobert Watson * Support for dynamic policy loading can be compiled out using the 16640202729SRobert Watson * MAC_STATIC kernel option. 16741a17fe3SRobert Watson * 16840202729SRobert Watson * The dynamic policy list is protected by two locks: modifying the list 16940202729SRobert Watson * requires both locks to be held exclusively. One of the locks, 17081fee06fSRobert Watson * mac_policy_rm, is acquired over policy entry points that will never sleep; 17140202729SRobert Watson * the other, mac_policy_sx, is acquire over policy entry points that may 17240202729SRobert Watson * sleep. The former category will be used when kernel locks may be held 17340202729SRobert Watson * over calls to the MAC Framework, during network processing in ithreads, 17440202729SRobert Watson * etc. The latter will tend to involve potentially blocking memory 17540202729SRobert Watson * allocations, extended attribute I/O, etc. 17695fab37eSRobert Watson */ 1770a05006dSRobert Watson #ifndef MAC_STATIC 17881fee06fSRobert Watson static struct rmlock mac_policy_rm; /* Non-sleeping entry points. */ 17940202729SRobert Watson static struct sx mac_policy_sx; /* Sleeping entry points. */ 1800a05006dSRobert Watson #endif 18140202729SRobert Watson 182089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list; 183089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list; 184f93bfb23SRobert Watson u_int mac_policy_count; /* Registered policy count. */ 185a96acd1aSRobert Watson 18640202729SRobert Watson static void mac_policy_xlock(void); 18740202729SRobert Watson static void mac_policy_xlock_assert(void); 18840202729SRobert Watson static void mac_policy_xunlock(void); 18940202729SRobert Watson 190089c1bdaSRobert Watson void 19181fee06fSRobert Watson mac_policy_slock_nosleep(struct rm_priotracker *tracker) 19241a17fe3SRobert Watson { 193c8e7bf92SRobert Watson 1940a05006dSRobert Watson #ifndef MAC_STATIC 1951e4cadcbSRobert Watson if (!mac_late) 1961e4cadcbSRobert Watson return; 1971e4cadcbSRobert Watson 19881fee06fSRobert Watson rm_rlock(&mac_policy_rm, tracker); 19940202729SRobert Watson #endif 20040202729SRobert Watson } 20140202729SRobert Watson 20240202729SRobert Watson void 20340202729SRobert Watson mac_policy_slock_sleep(void) 20440202729SRobert Watson { 20540202729SRobert Watson 20641a17fe3SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 20740202729SRobert Watson "mac_policy_slock_sleep"); 20840202729SRobert Watson 20940202729SRobert Watson #ifndef MAC_STATIC 21040202729SRobert Watson if (!mac_late) 21140202729SRobert Watson return; 21240202729SRobert Watson 21340202729SRobert Watson sx_slock(&mac_policy_sx); 2140a05006dSRobert Watson #endif 21541a17fe3SRobert Watson } 21695fab37eSRobert Watson 217089c1bdaSRobert Watson void 21881fee06fSRobert Watson mac_policy_sunlock_nosleep(struct rm_priotracker *tracker) 21941a17fe3SRobert Watson { 220c8e7bf92SRobert Watson 2210a05006dSRobert Watson #ifndef MAC_STATIC 2221e4cadcbSRobert Watson if (!mac_late) 2231e4cadcbSRobert Watson return; 2241e4cadcbSRobert Watson 22581fee06fSRobert Watson rm_runlock(&mac_policy_rm, tracker); 2260a05006dSRobert Watson #endif 22741a17fe3SRobert Watson } 228225bff6fSRobert Watson 229089c1bdaSRobert Watson void 23040202729SRobert Watson mac_policy_sunlock_sleep(void) 23141a17fe3SRobert Watson { 232c8e7bf92SRobert Watson 2330a05006dSRobert Watson #ifndef MAC_STATIC 2341e4cadcbSRobert Watson if (!mac_late) 2351e4cadcbSRobert Watson return; 2361e4cadcbSRobert Watson 23740202729SRobert Watson sx_sunlock(&mac_policy_sx); 2380a05006dSRobert Watson #endif 23941a17fe3SRobert Watson } 24041a17fe3SRobert Watson 24140202729SRobert Watson static void 24240202729SRobert Watson mac_policy_xlock(void) 24341a17fe3SRobert Watson { 24440202729SRobert Watson 24540202729SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 24640202729SRobert Watson "mac_policy_xlock()"); 24740202729SRobert Watson 2480a05006dSRobert Watson #ifndef MAC_STATIC 2491e4cadcbSRobert Watson if (!mac_late) 2501e4cadcbSRobert Watson return; 2511e4cadcbSRobert Watson 25240202729SRobert Watson sx_xlock(&mac_policy_sx); 25381fee06fSRobert Watson rm_wlock(&mac_policy_rm); 25440202729SRobert Watson #endif 25540202729SRobert Watson } 256989d4098SRobert Watson 25740202729SRobert Watson static void 25840202729SRobert Watson mac_policy_xunlock(void) 25940202729SRobert Watson { 26040202729SRobert Watson 26140202729SRobert Watson #ifndef MAC_STATIC 26240202729SRobert Watson if (!mac_late) 26340202729SRobert Watson return; 26440202729SRobert Watson 26581fee06fSRobert Watson rm_wunlock(&mac_policy_rm); 26640202729SRobert Watson sx_xunlock(&mac_policy_sx); 26740202729SRobert Watson #endif 26840202729SRobert Watson } 26940202729SRobert Watson 27040202729SRobert Watson static void 27140202729SRobert Watson mac_policy_xlock_assert(void) 27240202729SRobert Watson { 27340202729SRobert Watson 27440202729SRobert Watson #ifndef MAC_STATIC 27540202729SRobert Watson if (!mac_late) 27640202729SRobert Watson return; 27740202729SRobert Watson 27881fee06fSRobert Watson /* XXXRW: rm_assert(&mac_policy_rm, RA_WLOCKED); */ 27940202729SRobert Watson sx_assert(&mac_policy_sx, SA_XLOCKED); 2800a05006dSRobert Watson #endif 28141a17fe3SRobert Watson } 28295fab37eSRobert Watson 28395fab37eSRobert Watson /* 28495fab37eSRobert Watson * Initialize the MAC subsystem, including appropriate SMP locks. 28595fab37eSRobert Watson */ 28695fab37eSRobert Watson static void 28795fab37eSRobert Watson mac_init(void) 28895fab37eSRobert Watson { 28995fab37eSRobert Watson 29041a17fe3SRobert Watson LIST_INIT(&mac_static_policy_list); 29195fab37eSRobert Watson LIST_INIT(&mac_policy_list); 292eca8a663SRobert Watson mac_labelzone_init(); 29341a17fe3SRobert Watson 2940a05006dSRobert Watson #ifndef MAC_STATIC 2955f51fb48SRobert Watson rm_init_flags(&mac_policy_rm, "mac_policy_rm", RM_NOWITNESS); 2965f51fb48SRobert Watson sx_init_flags(&mac_policy_sx, "mac_policy_sx", SX_NOWITNESS); 2970a05006dSRobert Watson #endif 29895fab37eSRobert Watson } 29995fab37eSRobert Watson 30095fab37eSRobert Watson /* 30117041e67SRobert Watson * For the purposes of modules that want to know if they were loaded "early", 30217041e67SRobert Watson * set the mac_late flag once we've processed modules either linked into the 30317041e67SRobert Watson * kernel, or loaded before the kernel startup. 30495fab37eSRobert Watson */ 30595fab37eSRobert Watson static void 30695fab37eSRobert Watson mac_late_init(void) 30795fab37eSRobert Watson { 30895fab37eSRobert Watson 30995fab37eSRobert Watson mac_late = 1; 31095fab37eSRobert Watson } 31195fab37eSRobert Watson 31295fab37eSRobert Watson /* 3139162f64bSRobert Watson * Given a policy, derive from its set of non-NULL label init methods what 3149162f64bSRobert Watson * object types the policy is interested in. 3159162f64bSRobert Watson */ 3169162f64bSRobert Watson static uint64_t 3179162f64bSRobert Watson mac_policy_getlabeled(struct mac_policy_conf *mpc) 3189162f64bSRobert Watson { 3199162f64bSRobert Watson uint64_t labeled; 3209162f64bSRobert Watson 3219162f64bSRobert Watson #define MPC_FLAG(method, flag) \ 3229162f64bSRobert Watson if (mpc->mpc_ops->mpo_ ## method != NULL) \ 3239162f64bSRobert Watson labeled |= (flag); \ 3249162f64bSRobert Watson 3259162f64bSRobert Watson labeled = 0; 3269162f64bSRobert Watson MPC_FLAG(cred_init_label, MPC_OBJECT_CRED); 3279162f64bSRobert Watson MPC_FLAG(proc_init_label, MPC_OBJECT_PROC); 3289162f64bSRobert Watson MPC_FLAG(vnode_init_label, MPC_OBJECT_VNODE); 3299162f64bSRobert Watson MPC_FLAG(inpcb_init_label, MPC_OBJECT_INPCB); 3309162f64bSRobert Watson MPC_FLAG(socket_init_label, MPC_OBJECT_SOCKET); 3319162f64bSRobert Watson MPC_FLAG(devfs_init_label, MPC_OBJECT_DEVFS); 3329162f64bSRobert Watson MPC_FLAG(mbuf_init_label, MPC_OBJECT_MBUF); 3339162f64bSRobert Watson MPC_FLAG(ipq_init_label, MPC_OBJECT_IPQ); 3349162f64bSRobert Watson MPC_FLAG(ifnet_init_label, MPC_OBJECT_IFNET); 3359162f64bSRobert Watson MPC_FLAG(bpfdesc_init_label, MPC_OBJECT_BPFDESC); 3369162f64bSRobert Watson MPC_FLAG(pipe_init_label, MPC_OBJECT_PIPE); 3379162f64bSRobert Watson MPC_FLAG(mount_init_label, MPC_OBJECT_MOUNT); 3389162f64bSRobert Watson MPC_FLAG(posixsem_init_label, MPC_OBJECT_POSIXSEM); 3399162f64bSRobert Watson MPC_FLAG(posixshm_init_label, MPC_OBJECT_POSIXSHM); 3409162f64bSRobert Watson MPC_FLAG(sysvmsg_init_label, MPC_OBJECT_SYSVMSG); 3419162f64bSRobert Watson MPC_FLAG(sysvmsq_init_label, MPC_OBJECT_SYSVMSQ); 3429162f64bSRobert Watson MPC_FLAG(sysvsem_init_label, MPC_OBJECT_SYSVSEM); 3439162f64bSRobert Watson MPC_FLAG(sysvshm_init_label, MPC_OBJECT_SYSVSHM); 3449162f64bSRobert Watson MPC_FLAG(syncache_init_label, MPC_OBJECT_SYNCACHE); 3459162f64bSRobert Watson MPC_FLAG(ip6q_init_label, MPC_OBJECT_IP6Q); 3469162f64bSRobert Watson 3479162f64bSRobert Watson #undef MPC_FLAG 3489162f64bSRobert Watson return (labeled); 3499162f64bSRobert Watson } 3509162f64bSRobert Watson 3519162f64bSRobert Watson /* 3529162f64bSRobert Watson * When policies are loaded or unloaded, walk the list of registered policies 3539162f64bSRobert Watson * and built mac_labeled, a bitmask representing the union of all objects 3549162f64bSRobert Watson * requiring labels across all policies. 355225bff6fSRobert Watson */ 356225bff6fSRobert Watson static void 357f93bfb23SRobert Watson mac_policy_update(void) 358225bff6fSRobert Watson { 3596356dba0SRobert Watson struct mac_policy_conf *mpc; 360225bff6fSRobert Watson 36140202729SRobert Watson mac_policy_xlock_assert(); 362225bff6fSRobert Watson 3636356dba0SRobert Watson mac_labeled = 0; 364f93bfb23SRobert Watson mac_policy_count = 0; 365f93bfb23SRobert Watson LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 3669162f64bSRobert Watson mac_labeled |= mac_policy_getlabeled(mpc); 367f93bfb23SRobert Watson mac_policy_count++; 368f93bfb23SRobert Watson } 369f93bfb23SRobert Watson LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 3709162f64bSRobert Watson mac_labeled |= mac_policy_getlabeled(mpc); 371f93bfb23SRobert Watson mac_policy_count++; 372f93bfb23SRobert Watson } 373225bff6fSRobert Watson } 374225bff6fSRobert Watson 37595fab37eSRobert Watson static int 37695fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc) 37795fab37eSRobert Watson { 37895fab37eSRobert Watson struct mac_policy_conf *tmpc; 37941a17fe3SRobert Watson int error, slot, static_entry; 38095fab37eSRobert Watson 38141a17fe3SRobert Watson error = 0; 38241a17fe3SRobert Watson 38341a17fe3SRobert Watson /* 38417041e67SRobert Watson * We don't technically need exclusive access while !mac_late, but 38517041e67SRobert Watson * hold it for assertion consistency. 38641a17fe3SRobert Watson */ 38740202729SRobert Watson mac_policy_xlock(); 38841a17fe3SRobert Watson 38941a17fe3SRobert Watson /* 39017041e67SRobert Watson * If the module can potentially be unloaded, or we're loading late, 39117041e67SRobert Watson * we have to stick it in the non-static list and pay an extra 39217041e67SRobert Watson * performance overhead. Otherwise, we can pay a light locking cost 39317041e67SRobert Watson * and stick it in the static list. 39441a17fe3SRobert Watson */ 39541a17fe3SRobert Watson static_entry = (!mac_late && 39641a17fe3SRobert Watson !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 39741a17fe3SRobert Watson 39841a17fe3SRobert Watson if (static_entry) { 39941a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 40041a17fe3SRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 40141a17fe3SRobert Watson error = EEXIST; 40241a17fe3SRobert Watson goto out; 40341a17fe3SRobert Watson } 40441a17fe3SRobert Watson } 40541a17fe3SRobert Watson } else { 40695fab37eSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 40795fab37eSRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 40841a17fe3SRobert Watson error = EEXIST; 40941a17fe3SRobert Watson goto out; 41041a17fe3SRobert Watson } 41195fab37eSRobert Watson } 41295fab37eSRobert Watson } 41395fab37eSRobert Watson if (mpc->mpc_field_off != NULL) { 414b2aef571SRobert Watson slot = ffs(mac_slot_offsets_free); 41595fab37eSRobert Watson if (slot == 0) { 41641a17fe3SRobert Watson error = ENOMEM; 41741a17fe3SRobert Watson goto out; 41895fab37eSRobert Watson } 41995fab37eSRobert Watson slot--; 420b2aef571SRobert Watson mac_slot_offsets_free &= ~(1 << slot); 42195fab37eSRobert Watson *mpc->mpc_field_off = slot; 42295fab37eSRobert Watson } 42395fab37eSRobert Watson mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 42441a17fe3SRobert Watson 42541a17fe3SRobert Watson /* 42617041e67SRobert Watson * If we're loading a MAC module after the framework has initialized, 42717041e67SRobert Watson * it has to go into the dynamic list. If we're loading it before 42817041e67SRobert Watson * we've finished initializing, it can go into the static list with 42917041e67SRobert Watson * weaker locker requirements. 43041a17fe3SRobert Watson */ 43141a17fe3SRobert Watson if (static_entry) 43241a17fe3SRobert Watson LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); 43341a17fe3SRobert Watson else 43495fab37eSRobert Watson LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 43595fab37eSRobert Watson 43617041e67SRobert Watson /* 43717041e67SRobert Watson * Per-policy initialization. Currently, this takes place under the 43817041e67SRobert Watson * exclusive lock, so policies must not sleep in their init method. 43917041e67SRobert Watson * In the future, we may want to separate "init" from "start", with 44017041e67SRobert Watson * "init" occuring without the lock held. Likewise, on tear-down, 44117041e67SRobert Watson * breaking out "stop" from "destroy". 44217041e67SRobert Watson */ 44395fab37eSRobert Watson if (mpc->mpc_ops->mpo_init != NULL) 44495fab37eSRobert Watson (*(mpc->mpc_ops->mpo_init))(mpc); 445f93bfb23SRobert Watson mac_policy_update(); 44695fab37eSRobert Watson 44791ec0006SRobert Watson SDT_PROBE(mac, kernel, policy, register, mpc, 0, 0, 0, 0); 44895fab37eSRobert Watson printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 44995fab37eSRobert Watson mpc->mpc_name); 45095fab37eSRobert Watson 45141a17fe3SRobert Watson out: 45240202729SRobert Watson mac_policy_xunlock(); 45341a17fe3SRobert Watson return (error); 45495fab37eSRobert Watson } 45595fab37eSRobert Watson 45695fab37eSRobert Watson static int 45795fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc) 45895fab37eSRobert Watson { 45995fab37eSRobert Watson 460ea599aa0SRobert Watson /* 46117041e67SRobert Watson * If we fail the load, we may get a request to unload. Check to see 46217041e67SRobert Watson * if we did the run-time registration, and if not, silently succeed. 463ea599aa0SRobert Watson */ 46440202729SRobert Watson mac_policy_xlock(); 465ea599aa0SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 46640202729SRobert Watson mac_policy_xunlock(); 467ea599aa0SRobert Watson return (0); 468ea599aa0SRobert Watson } 46995fab37eSRobert Watson #if 0 47095fab37eSRobert Watson /* 47195fab37eSRobert Watson * Don't allow unloading modules with private data. 47295fab37eSRobert Watson */ 473ea599aa0SRobert Watson if (mpc->mpc_field_off != NULL) { 47440202729SRobert Watson mac_policy_xunlock(); 47595fab37eSRobert Watson return (EBUSY); 476ea599aa0SRobert Watson } 47795fab37eSRobert Watson #endif 478ea599aa0SRobert Watson /* 47917041e67SRobert Watson * Only allow the unload to proceed if the module is unloadable by 48017041e67SRobert Watson * its own definition. 481ea599aa0SRobert Watson */ 482ea599aa0SRobert Watson if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 48340202729SRobert Watson mac_policy_xunlock(); 48495fab37eSRobert Watson return (EBUSY); 485ea599aa0SRobert Watson } 48695fab37eSRobert Watson if (mpc->mpc_ops->mpo_destroy != NULL) 48795fab37eSRobert Watson (*(mpc->mpc_ops->mpo_destroy))(mpc); 48895fab37eSRobert Watson 48995fab37eSRobert Watson LIST_REMOVE(mpc, mpc_list); 4909aeffb2bSRobert Watson mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 491f93bfb23SRobert Watson mac_policy_update(); 49240202729SRobert Watson mac_policy_xunlock(); 493a96acd1aSRobert Watson 49491ec0006SRobert Watson SDT_PROBE(mac, kernel, policy, unregister, mpc, 0, 0, 0, 0); 49595fab37eSRobert Watson printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 49695fab37eSRobert Watson mpc->mpc_name); 49795fab37eSRobert Watson 49895fab37eSRobert Watson return (0); 49995fab37eSRobert Watson } 50095fab37eSRobert Watson 50195fab37eSRobert Watson /* 502c441d123SRobert Watson * Allow MAC policy modules to register during boot, etc. 503c441d123SRobert Watson */ 504c441d123SRobert Watson int 505c441d123SRobert Watson mac_policy_modevent(module_t mod, int type, void *data) 506c441d123SRobert Watson { 507c441d123SRobert Watson struct mac_policy_conf *mpc; 508c441d123SRobert Watson int error; 509c441d123SRobert Watson 510c441d123SRobert Watson error = 0; 511c441d123SRobert Watson mpc = (struct mac_policy_conf *) data; 512c441d123SRobert Watson 513c441d123SRobert Watson #ifdef MAC_STATIC 514c441d123SRobert Watson if (mac_late) { 515c441d123SRobert Watson printf("mac_policy_modevent: MAC_STATIC and late\n"); 516c441d123SRobert Watson return (EBUSY); 517c441d123SRobert Watson } 518c441d123SRobert Watson #endif 519c441d123SRobert Watson 52091ec0006SRobert Watson SDT_PROBE(mac, kernel, policy, modevent, type, mpc, 0, 0, 0); 521c441d123SRobert Watson switch (type) { 522c441d123SRobert Watson case MOD_LOAD: 523c441d123SRobert Watson if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 524c441d123SRobert Watson mac_late) { 525c441d123SRobert Watson printf("mac_policy_modevent: can't load %s policy " 526c441d123SRobert Watson "after booting\n", mpc->mpc_name); 527c441d123SRobert Watson error = EBUSY; 528c441d123SRobert Watson break; 529c441d123SRobert Watson } 530c441d123SRobert Watson error = mac_policy_register(mpc); 531c441d123SRobert Watson break; 532c441d123SRobert Watson case MOD_UNLOAD: 533c441d123SRobert Watson /* Don't unregister the module if it was never registered. */ 534c441d123SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 535c441d123SRobert Watson != 0) 536c441d123SRobert Watson error = mac_policy_unregister(mpc); 537c441d123SRobert Watson else 538c441d123SRobert Watson error = 0; 539c441d123SRobert Watson break; 540c441d123SRobert Watson default: 541c441d123SRobert Watson error = EOPNOTSUPP; 542c441d123SRobert Watson break; 543c441d123SRobert Watson } 544c441d123SRobert Watson 545c441d123SRobert Watson return (error); 546c441d123SRobert Watson } 547c441d123SRobert Watson 548c441d123SRobert Watson /* 54995fab37eSRobert Watson * Define an error value precedence, and given two arguments, selects the 55095fab37eSRobert Watson * value with the higher precedence. 55195fab37eSRobert Watson */ 5529e7bf51cSRobert Watson int 5539e7bf51cSRobert Watson mac_error_select(int error1, int error2) 55495fab37eSRobert Watson { 55595fab37eSRobert Watson 55695fab37eSRobert Watson /* Certain decision-making errors take top priority. */ 55795fab37eSRobert Watson if (error1 == EDEADLK || error2 == EDEADLK) 55895fab37eSRobert Watson return (EDEADLK); 55995fab37eSRobert Watson 56095fab37eSRobert Watson /* Invalid arguments should be reported where possible. */ 56195fab37eSRobert Watson if (error1 == EINVAL || error2 == EINVAL) 56295fab37eSRobert Watson return (EINVAL); 56395fab37eSRobert Watson 56495fab37eSRobert Watson /* Precedence goes to "visibility", with both process and file. */ 56595fab37eSRobert Watson if (error1 == ESRCH || error2 == ESRCH) 56695fab37eSRobert Watson return (ESRCH); 56795fab37eSRobert Watson 56895fab37eSRobert Watson if (error1 == ENOENT || error2 == ENOENT) 56995fab37eSRobert Watson return (ENOENT); 57095fab37eSRobert Watson 57195fab37eSRobert Watson /* Precedence goes to DAC/MAC protections. */ 57295fab37eSRobert Watson if (error1 == EACCES || error2 == EACCES) 57395fab37eSRobert Watson return (EACCES); 57495fab37eSRobert Watson 57595fab37eSRobert Watson /* Precedence goes to privilege. */ 57695fab37eSRobert Watson if (error1 == EPERM || error2 == EPERM) 57795fab37eSRobert Watson return (EPERM); 57895fab37eSRobert Watson 57995fab37eSRobert Watson /* Precedence goes to error over success; otherwise, arbitrary. */ 58095fab37eSRobert Watson if (error1 != 0) 58195fab37eSRobert Watson return (error1); 58295fab37eSRobert Watson return (error2); 58395fab37eSRobert Watson } 58495fab37eSRobert Watson 5855e7ce478SRobert Watson int 586f7b951a8SRobert Watson mac_check_structmac_consistent(struct mac *mac) 587f7b951a8SRobert Watson { 588f7b951a8SRobert Watson 589cc7b13bfSRobert Watson if (mac->m_buflen < 0 || 590cc7b13bfSRobert Watson mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 591f7b951a8SRobert Watson return (EINVAL); 592f7b951a8SRobert Watson 593f7b951a8SRobert Watson return (0); 594f7b951a8SRobert Watson } 595f7b951a8SRobert Watson 59695fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 59795fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 598