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 6939b73a30SRobert Watson #include "opt_mac.h" 7039b73a30SRobert Watson 717bc82500SRobert Watson #include <sys/param.h> 727a7ce668SAndriy Gapon #include <sys/systm.h> 73a96acd1aSRobert Watson #include <sys/condvar.h> 74*5041b205SOlivier Certner #include <sys/jail.h> 7595fab37eSRobert Watson #include <sys/kernel.h> 7695fab37eSRobert Watson #include <sys/lock.h> 7795fab37eSRobert Watson #include <sys/mac.h> 787ba28492SRobert Watson #include <sys/module.h> 7981fee06fSRobert Watson #include <sys/rmlock.h> 8091ec0006SRobert Watson #include <sys/sdt.h> 8140202729SRobert Watson #include <sys/sx.h> 8295fab37eSRobert Watson #include <sys/sysctl.h> 8333f3e81dSMateusz Guzik #include <sys/vnode.h> 8495fab37eSRobert Watson 85aed55708SRobert Watson #include <security/mac/mac_framework.h> 866fa0475dSRobert Watson #include <security/mac/mac_internal.h> 870efd6615SRobert Watson #include <security/mac/mac_policy.h> 886fa0475dSRobert Watson 897ba28492SRobert Watson /* 902087a58cSRobert Watson * DTrace SDT providers for MAC. 9191ec0006SRobert Watson */ 9291ec0006SRobert Watson SDT_PROVIDER_DEFINE(mac); 932087a58cSRobert Watson SDT_PROVIDER_DEFINE(mac_framework); 942087a58cSRobert Watson 9536160958SMark Johnston SDT_PROBE_DEFINE2(mac, , policy, modevent, "int", 9692c6196cSMark Johnston "struct mac_policy_conf *"); 9736160958SMark Johnston SDT_PROBE_DEFINE1(mac, , policy, register, 9879856499SRui Paulo "struct mac_policy_conf *"); 9936160958SMark Johnston SDT_PROBE_DEFINE1(mac, , policy, unregister, 10079856499SRui Paulo "struct mac_policy_conf *"); 10191ec0006SRobert Watson 10291ec0006SRobert Watson /* 103471e5756SRobert Watson * Root sysctl node for all MAC and MAC policy controls. 1047ba28492SRobert Watson */ 1057029da5cSPawel Biernacki SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW | CTLFLAG_MPSAFE, 0, 10695fab37eSRobert Watson "TrustedBSD MAC policy controls"); 107b2f0927aSRobert Watson 10817041e67SRobert Watson /* 109*5041b205SOlivier Certner * Root sysctl node for MAC modules' jail parameters. 110*5041b205SOlivier Certner */ 111*5041b205SOlivier Certner SYSCTL_JAIL_PARAM_NODE(mac, "Jail parameters for MAC policy controls"); 112*5041b205SOlivier Certner 113*5041b205SOlivier Certner /* 11490678c89SOlivier Certner * Declare that the kernel provides a specific version of MAC support. 115471e5756SRobert Watson * This permits modules to refuse to be loaded if the necessary support isn't 116471e5756SRobert Watson * present, even if it's pre-boot. 117471e5756SRobert Watson */ 118471e5756SRobert Watson MODULE_VERSION(kernel_mac_support, MAC_VERSION); 119be23ba9aSRobert Watson 120be23ba9aSRobert Watson static unsigned int mac_version = MAC_VERSION; 121471e5756SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, version, CTLFLAG_RD, &mac_version, 0, 122471e5756SRobert Watson ""); 123471e5756SRobert Watson 124471e5756SRobert Watson /* 1253ea3fbe6SMateusz Guzik * Flags for inlined checks. Note this would be best hotpatched at runtime. 1263ea3fbe6SMateusz Guzik * The following is a band-aid. 1273ea3fbe6SMateusz Guzik * 1283ea3fbe6SMateusz Guzik * Use FPFLAG for hooks running in commonly executed paths and FPFLAG_RARE 1293ea3fbe6SMateusz Guzik * for the rest. 13091061084SMateusz Guzik */ 13191061084SMateusz Guzik #define FPFLAG(f) \ 13291061084SMateusz Guzik bool __read_frequently mac_##f##_fp_flag 13391061084SMateusz Guzik 1343ea3fbe6SMateusz Guzik #define FPFLAG_RARE(f) \ 1353ea3fbe6SMateusz Guzik bool __read_mostly mac_##f##_fp_flag 1363ea3fbe6SMateusz Guzik 13791061084SMateusz Guzik FPFLAG(priv_check); 13891061084SMateusz Guzik FPFLAG(priv_grant); 1396ebab6baSMateusz Guzik FPFLAG(vnode_check_lookup); 1406ebab6baSMateusz Guzik FPFLAG(vnode_check_open); 1416ebab6baSMateusz Guzik FPFLAG(vnode_check_stat); 1426ebab6baSMateusz Guzik FPFLAG(vnode_check_read); 1436ebab6baSMateusz Guzik FPFLAG(vnode_check_write); 1446ebab6baSMateusz Guzik FPFLAG(vnode_check_mmap); 1453ea3fbe6SMateusz Guzik FPFLAG_RARE(vnode_check_poll); 146fad6dd77SMateusz Guzik FPFLAG_RARE(vnode_check_rename_from); 14718f67bc4SMateusz Guzik FPFLAG_RARE(vnode_check_access); 14877589de8SMateusz Guzik FPFLAG_RARE(vnode_check_readlink); 14989744405SMateusz Guzik FPFLAG_RARE(pipe_check_stat); 15089744405SMateusz Guzik FPFLAG_RARE(pipe_check_poll); 15160dae3b8SMateusz Guzik FPFLAG_RARE(pipe_check_read); 152f77697ddSMateusz Guzik FPFLAG_RARE(ifnet_create_mbuf); 153f77697ddSMateusz Guzik FPFLAG_RARE(ifnet_check_transmit); 15491061084SMateusz Guzik 15591061084SMateusz Guzik #undef FPFLAG 1563ea3fbe6SMateusz Guzik #undef FPFLAG_RARE 15791061084SMateusz Guzik 15891061084SMateusz Guzik /* 15917041e67SRobert Watson * Labels consist of a indexed set of "slots", which are allocated policies 16017041e67SRobert Watson * as required. The MAC Framework maintains a bitmask of slots allocated so 16117041e67SRobert Watson * far to prevent reuse. Slots cannot be reused, as the MAC Framework 16217041e67SRobert Watson * guarantees that newly allocated slots in labels will be NULL unless 16317041e67SRobert Watson * otherwise initialized, and because we do not have a mechanism to garbage 16417041e67SRobert Watson * collect slots on policy unload. As labeled policies tend to be statically 16517041e67SRobert Watson * loaded during boot, and not frequently unloaded and reloaded, this is not 16617041e67SRobert Watson * generally an issue. 16717041e67SRobert Watson */ 168b2aef571SRobert Watson #if MAC_MAX_SLOTS > 32 169b2aef571SRobert Watson #error "MAC_MAX_SLOTS too large" 17095fab37eSRobert Watson #endif 171a13c67daSRobert Watson 172b2aef571SRobert Watson static unsigned int mac_max_slots = MAC_MAX_SLOTS; 173b2aef571SRobert Watson static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1; 174471e5756SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, &mac_max_slots, 175471e5756SRobert Watson 0, ""); 17695fab37eSRobert Watson 177a67fe518SRobert Watson /* 178a67fe518SRobert Watson * Has the kernel started generating labeled objects yet? All read/write 179a67fe518SRobert Watson * access to this variable is serialized during the boot process. Following 180a67fe518SRobert Watson * the end of serialization, we don't update this flag; no locking. 181a67fe518SRobert Watson */ 182be23ba9aSRobert Watson static int mac_late = 0; 183763bbd2fSRobert Watson 184225bff6fSRobert Watson /* 1856356dba0SRobert Watson * Each policy declares a mask of object types requiring labels to be 1866356dba0SRobert Watson * allocated for them. For convenience, we combine and cache the bitwise or 1876356dba0SRobert Watson * of the per-policy object flags to track whether we will allocate a label 1886356dba0SRobert Watson * for an object type at run-time. 189225bff6fSRobert Watson */ 1906356dba0SRobert Watson uint64_t mac_labeled; 191123d2cb7SMatthew D Fleming SYSCTL_UQUAD(_security_mac, OID_AUTO, labeled, CTLFLAG_RD, &mac_labeled, 0, 1926356dba0SRobert Watson "Mask of object types being labeled"); 193225bff6fSRobert Watson 194f7b951a8SRobert Watson MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 19595fab37eSRobert Watson 19695fab37eSRobert Watson /* 19740202729SRobert Watson * MAC policy modules are placed in one of two lists: mac_static_policy_list, 19840202729SRobert Watson * for policies that are loaded early and cannot be unloaded, and 19940202729SRobert Watson * mac_policy_list, which holds policies either loaded later in the boot 20040202729SRobert Watson * cycle or that may be unloaded. The static policy list does not require 20140202729SRobert Watson * locks to iterate over, but the dynamic list requires synchronization. 20240202729SRobert Watson * Support for dynamic policy loading can be compiled out using the 20340202729SRobert Watson * MAC_STATIC kernel option. 20441a17fe3SRobert Watson * 20540202729SRobert Watson * The dynamic policy list is protected by two locks: modifying the list 20640202729SRobert Watson * requires both locks to be held exclusively. One of the locks, 20781fee06fSRobert Watson * mac_policy_rm, is acquired over policy entry points that will never sleep; 208407a5b79SJason A. Harmening * the other, mac_policy_rms, is acquired over policy entry points that may 20940202729SRobert Watson * sleep. The former category will be used when kernel locks may be held 21040202729SRobert Watson * over calls to the MAC Framework, during network processing in ithreads, 21140202729SRobert Watson * etc. The latter will tend to involve potentially blocking memory 21240202729SRobert Watson * allocations, extended attribute I/O, etc. 21395fab37eSRobert Watson */ 2140a05006dSRobert Watson #ifndef MAC_STATIC 21581fee06fSRobert Watson static struct rmlock mac_policy_rm; /* Non-sleeping entry points. */ 216407a5b79SJason A. Harmening static struct rmslock mac_policy_rms; /* Sleeping entry points. */ 2170a05006dSRobert Watson #endif 21840202729SRobert Watson 219089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list; 220089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list; 221f93bfb23SRobert Watson u_int mac_policy_count; /* Registered policy count. */ 222a96acd1aSRobert Watson 22340202729SRobert Watson static void mac_policy_xlock(void); 22440202729SRobert Watson static void mac_policy_xlock_assert(void); 22540202729SRobert Watson static void mac_policy_xunlock(void); 22640202729SRobert Watson 227089c1bdaSRobert Watson void 22881fee06fSRobert Watson mac_policy_slock_nosleep(struct rm_priotracker *tracker) 22941a17fe3SRobert Watson { 230c8e7bf92SRobert Watson 2310a05006dSRobert Watson #ifndef MAC_STATIC 2321e4cadcbSRobert Watson if (!mac_late) 2331e4cadcbSRobert Watson return; 2341e4cadcbSRobert Watson 23581fee06fSRobert Watson rm_rlock(&mac_policy_rm, tracker); 23640202729SRobert Watson #endif 23740202729SRobert Watson } 23840202729SRobert Watson 23940202729SRobert Watson void 24040202729SRobert Watson mac_policy_slock_sleep(void) 24140202729SRobert Watson { 24240202729SRobert Watson 24341a17fe3SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 24440202729SRobert Watson "mac_policy_slock_sleep"); 24540202729SRobert Watson 24640202729SRobert Watson #ifndef MAC_STATIC 24740202729SRobert Watson if (!mac_late) 24840202729SRobert Watson return; 24940202729SRobert Watson 250deb2e577SMateusz Guzik rms_rlock(&mac_policy_rms); 2510a05006dSRobert Watson #endif 25241a17fe3SRobert Watson } 25395fab37eSRobert Watson 254089c1bdaSRobert Watson void 25581fee06fSRobert Watson mac_policy_sunlock_nosleep(struct rm_priotracker *tracker) 25641a17fe3SRobert Watson { 257c8e7bf92SRobert Watson 2580a05006dSRobert Watson #ifndef MAC_STATIC 2591e4cadcbSRobert Watson if (!mac_late) 2601e4cadcbSRobert Watson return; 2611e4cadcbSRobert Watson 26281fee06fSRobert Watson rm_runlock(&mac_policy_rm, tracker); 2630a05006dSRobert Watson #endif 26441a17fe3SRobert Watson } 265225bff6fSRobert Watson 266089c1bdaSRobert Watson void 26740202729SRobert Watson mac_policy_sunlock_sleep(void) 26841a17fe3SRobert Watson { 269c8e7bf92SRobert Watson 2700a05006dSRobert Watson #ifndef MAC_STATIC 2711e4cadcbSRobert Watson if (!mac_late) 2721e4cadcbSRobert Watson return; 2731e4cadcbSRobert Watson 274deb2e577SMateusz Guzik rms_runlock(&mac_policy_rms); 2750a05006dSRobert Watson #endif 27641a17fe3SRobert Watson } 27741a17fe3SRobert Watson 27840202729SRobert Watson static void 27940202729SRobert Watson mac_policy_xlock(void) 28041a17fe3SRobert Watson { 28140202729SRobert Watson 28240202729SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 28340202729SRobert Watson "mac_policy_xlock()"); 28440202729SRobert Watson 2850a05006dSRobert Watson #ifndef MAC_STATIC 2861e4cadcbSRobert Watson if (!mac_late) 2871e4cadcbSRobert Watson return; 2881e4cadcbSRobert Watson 289deb2e577SMateusz Guzik rms_wlock(&mac_policy_rms); 29081fee06fSRobert Watson rm_wlock(&mac_policy_rm); 29140202729SRobert Watson #endif 29240202729SRobert Watson } 293989d4098SRobert Watson 29440202729SRobert Watson static void 29540202729SRobert Watson mac_policy_xunlock(void) 29640202729SRobert Watson { 29740202729SRobert Watson 29840202729SRobert Watson #ifndef MAC_STATIC 29940202729SRobert Watson if (!mac_late) 30040202729SRobert Watson return; 30140202729SRobert Watson 30281fee06fSRobert Watson rm_wunlock(&mac_policy_rm); 303deb2e577SMateusz Guzik rms_wunlock(&mac_policy_rms); 30440202729SRobert Watson #endif 30540202729SRobert Watson } 30640202729SRobert Watson 30740202729SRobert Watson static void 30840202729SRobert Watson mac_policy_xlock_assert(void) 30940202729SRobert Watson { 31040202729SRobert Watson 31140202729SRobert Watson #ifndef MAC_STATIC 31240202729SRobert Watson if (!mac_late) 31340202729SRobert Watson return; 31440202729SRobert Watson 315407a5b79SJason A. Harmening rm_assert(&mac_policy_rm, RA_WLOCKED); 3160a05006dSRobert Watson #endif 31741a17fe3SRobert Watson } 31895fab37eSRobert Watson 31995fab37eSRobert Watson /* 32095fab37eSRobert Watson * Initialize the MAC subsystem, including appropriate SMP locks. 32195fab37eSRobert Watson */ 32295fab37eSRobert Watson static void 32395fab37eSRobert Watson mac_init(void) 32495fab37eSRobert Watson { 32595fab37eSRobert Watson 32641a17fe3SRobert Watson LIST_INIT(&mac_static_policy_list); 32795fab37eSRobert Watson LIST_INIT(&mac_policy_list); 328eca8a663SRobert Watson mac_labelzone_init(); 32941a17fe3SRobert Watson 3300a05006dSRobert Watson #ifndef MAC_STATIC 331f7fadf1fSKonstantin Belousov rm_init_flags(&mac_policy_rm, "mac_policy_rm", RM_NOWITNESS | 332f7fadf1fSKonstantin Belousov RM_RECURSE); 333deb2e577SMateusz Guzik rms_init(&mac_policy_rms, "mac_policy_rms"); 3340a05006dSRobert Watson #endif 33595fab37eSRobert Watson } 33695fab37eSRobert Watson 33795fab37eSRobert Watson /* 33817041e67SRobert Watson * For the purposes of modules that want to know if they were loaded "early", 33917041e67SRobert Watson * set the mac_late flag once we've processed modules either linked into the 34017041e67SRobert Watson * kernel, or loaded before the kernel startup. 34195fab37eSRobert Watson */ 34295fab37eSRobert Watson static void 34395fab37eSRobert Watson mac_late_init(void) 34495fab37eSRobert Watson { 34595fab37eSRobert Watson 34695fab37eSRobert Watson mac_late = 1; 34795fab37eSRobert Watson } 34895fab37eSRobert Watson 34995fab37eSRobert Watson /* 3509162f64bSRobert Watson * Given a policy, derive from its set of non-NULL label init methods what 3519162f64bSRobert Watson * object types the policy is interested in. 3529162f64bSRobert Watson */ 3539162f64bSRobert Watson static uint64_t 3549162f64bSRobert Watson mac_policy_getlabeled(struct mac_policy_conf *mpc) 3559162f64bSRobert Watson { 3569162f64bSRobert Watson uint64_t labeled; 3579162f64bSRobert Watson 3589162f64bSRobert Watson #define MPC_FLAG(method, flag) \ 3599162f64bSRobert Watson if (mpc->mpc_ops->mpo_ ## method != NULL) \ 3609162f64bSRobert Watson labeled |= (flag); \ 3619162f64bSRobert Watson 3629162f64bSRobert Watson labeled = 0; 3639162f64bSRobert Watson MPC_FLAG(cred_init_label, MPC_OBJECT_CRED); 3649162f64bSRobert Watson MPC_FLAG(proc_init_label, MPC_OBJECT_PROC); 3659162f64bSRobert Watson MPC_FLAG(vnode_init_label, MPC_OBJECT_VNODE); 3669162f64bSRobert Watson MPC_FLAG(inpcb_init_label, MPC_OBJECT_INPCB); 3679162f64bSRobert Watson MPC_FLAG(socket_init_label, MPC_OBJECT_SOCKET); 3689162f64bSRobert Watson MPC_FLAG(devfs_init_label, MPC_OBJECT_DEVFS); 3699162f64bSRobert Watson MPC_FLAG(mbuf_init_label, MPC_OBJECT_MBUF); 3709162f64bSRobert Watson MPC_FLAG(ipq_init_label, MPC_OBJECT_IPQ); 3719162f64bSRobert Watson MPC_FLAG(ifnet_init_label, MPC_OBJECT_IFNET); 3729162f64bSRobert Watson MPC_FLAG(bpfdesc_init_label, MPC_OBJECT_BPFDESC); 3739162f64bSRobert Watson MPC_FLAG(pipe_init_label, MPC_OBJECT_PIPE); 3749162f64bSRobert Watson MPC_FLAG(mount_init_label, MPC_OBJECT_MOUNT); 3759162f64bSRobert Watson MPC_FLAG(posixsem_init_label, MPC_OBJECT_POSIXSEM); 3769162f64bSRobert Watson MPC_FLAG(posixshm_init_label, MPC_OBJECT_POSIXSHM); 3779162f64bSRobert Watson MPC_FLAG(sysvmsg_init_label, MPC_OBJECT_SYSVMSG); 3789162f64bSRobert Watson MPC_FLAG(sysvmsq_init_label, MPC_OBJECT_SYSVMSQ); 3799162f64bSRobert Watson MPC_FLAG(sysvsem_init_label, MPC_OBJECT_SYSVSEM); 3809162f64bSRobert Watson MPC_FLAG(sysvshm_init_label, MPC_OBJECT_SYSVSHM); 3819162f64bSRobert Watson MPC_FLAG(syncache_init_label, MPC_OBJECT_SYNCACHE); 3829162f64bSRobert Watson MPC_FLAG(ip6q_init_label, MPC_OBJECT_IP6Q); 3839162f64bSRobert Watson 3849162f64bSRobert Watson #undef MPC_FLAG 3859162f64bSRobert Watson return (labeled); 3869162f64bSRobert Watson } 3879162f64bSRobert Watson 3889162f64bSRobert Watson /* 3899162f64bSRobert Watson * When policies are loaded or unloaded, walk the list of registered policies 3909162f64bSRobert Watson * and built mac_labeled, a bitmask representing the union of all objects 3919162f64bSRobert Watson * requiring labels across all policies. 392225bff6fSRobert Watson */ 393225bff6fSRobert Watson static void 394f93bfb23SRobert Watson mac_policy_update(void) 395225bff6fSRobert Watson { 3966356dba0SRobert Watson struct mac_policy_conf *mpc; 397225bff6fSRobert Watson 39840202729SRobert Watson mac_policy_xlock_assert(); 399225bff6fSRobert Watson 4006356dba0SRobert Watson mac_labeled = 0; 401f93bfb23SRobert Watson mac_policy_count = 0; 402f93bfb23SRobert Watson LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 4039162f64bSRobert Watson mac_labeled |= mac_policy_getlabeled(mpc); 404f93bfb23SRobert Watson mac_policy_count++; 405f93bfb23SRobert Watson } 406f93bfb23SRobert Watson LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 4079162f64bSRobert Watson mac_labeled |= mac_policy_getlabeled(mpc); 408f93bfb23SRobert Watson mac_policy_count++; 409f93bfb23SRobert Watson } 41033f3e81dSMateusz Guzik 41133f3e81dSMateusz Guzik cache_fast_lookup_enabled_recalc(); 412225bff6fSRobert Watson } 413225bff6fSRobert Watson 41491061084SMateusz Guzik /* 41591061084SMateusz Guzik * There are frequently used code paths which check for rarely installed 41691061084SMateusz Guzik * policies. Gross hack below enables doing it in a cheap manner. 41791061084SMateusz Guzik */ 41891061084SMateusz Guzik 41991061084SMateusz Guzik #define FPO(f) (offsetof(struct mac_policy_ops, mpo_##f) / sizeof(uintptr_t)) 42091061084SMateusz Guzik 42191061084SMateusz Guzik struct mac_policy_fastpath_elem { 42291061084SMateusz Guzik int count; 42391061084SMateusz Guzik bool *flag; 42491061084SMateusz Guzik size_t offset; 42591061084SMateusz Guzik }; 42691061084SMateusz Guzik 42791061084SMateusz Guzik struct mac_policy_fastpath_elem mac_policy_fastpath_array[] = { 42891061084SMateusz Guzik { .offset = FPO(priv_check), .flag = &mac_priv_check_fp_flag }, 42991061084SMateusz Guzik { .offset = FPO(priv_grant), .flag = &mac_priv_grant_fp_flag }, 4306ebab6baSMateusz Guzik { .offset = FPO(vnode_check_lookup), 4316ebab6baSMateusz Guzik .flag = &mac_vnode_check_lookup_fp_flag }, 43277589de8SMateusz Guzik { .offset = FPO(vnode_check_readlink), 43377589de8SMateusz Guzik .flag = &mac_vnode_check_readlink_fp_flag }, 4346ebab6baSMateusz Guzik { .offset = FPO(vnode_check_open), 4356ebab6baSMateusz Guzik .flag = &mac_vnode_check_open_fp_flag }, 4366ebab6baSMateusz Guzik { .offset = FPO(vnode_check_stat), 4376ebab6baSMateusz Guzik .flag = &mac_vnode_check_stat_fp_flag }, 4386ebab6baSMateusz Guzik { .offset = FPO(vnode_check_read), 4396ebab6baSMateusz Guzik .flag = &mac_vnode_check_read_fp_flag }, 4406ebab6baSMateusz Guzik { .offset = FPO(vnode_check_write), 4416ebab6baSMateusz Guzik .flag = &mac_vnode_check_write_fp_flag }, 4426ebab6baSMateusz Guzik { .offset = FPO(vnode_check_mmap), 4436ebab6baSMateusz Guzik .flag = &mac_vnode_check_mmap_fp_flag }, 4443ea3fbe6SMateusz Guzik { .offset = FPO(vnode_check_poll), 4453ea3fbe6SMateusz Guzik .flag = &mac_vnode_check_poll_fp_flag }, 446fad6dd77SMateusz Guzik { .offset = FPO(vnode_check_rename_from), 447fad6dd77SMateusz Guzik .flag = &mac_vnode_check_rename_from_fp_flag }, 44818f67bc4SMateusz Guzik { .offset = FPO(vnode_check_access), 44918f67bc4SMateusz Guzik .flag = &mac_vnode_check_access_fp_flag }, 45089744405SMateusz Guzik { .offset = FPO(pipe_check_stat), 45189744405SMateusz Guzik .flag = &mac_pipe_check_stat_fp_flag }, 45289744405SMateusz Guzik { .offset = FPO(pipe_check_poll), 45389744405SMateusz Guzik .flag = &mac_pipe_check_poll_fp_flag }, 45460dae3b8SMateusz Guzik { .offset = FPO(pipe_check_read), 45560dae3b8SMateusz Guzik .flag = &mac_pipe_check_read_fp_flag }, 456f77697ddSMateusz Guzik { .offset = FPO(ifnet_create_mbuf), 457f77697ddSMateusz Guzik .flag = &mac_ifnet_create_mbuf_fp_flag }, 458f77697ddSMateusz Guzik { .offset = FPO(ifnet_check_transmit), 459f77697ddSMateusz Guzik .flag = &mac_ifnet_check_transmit_fp_flag }, 46091061084SMateusz Guzik }; 46191061084SMateusz Guzik 46291061084SMateusz Guzik static void 46391061084SMateusz Guzik mac_policy_fastpath_enable(struct mac_policy_fastpath_elem *mpfe) 46491061084SMateusz Guzik { 46591061084SMateusz Guzik 46691061084SMateusz Guzik MPASS(mpfe->count >= 0); 46791061084SMateusz Guzik mpfe->count++; 46891061084SMateusz Guzik if (mpfe->count == 1) { 46991061084SMateusz Guzik MPASS(*mpfe->flag == false); 47091061084SMateusz Guzik *mpfe->flag = true; 47191061084SMateusz Guzik } 47291061084SMateusz Guzik } 47391061084SMateusz Guzik 47491061084SMateusz Guzik static void 47591061084SMateusz Guzik mac_policy_fastpath_disable(struct mac_policy_fastpath_elem *mpfe) 47691061084SMateusz Guzik { 47791061084SMateusz Guzik 47891061084SMateusz Guzik MPASS(mpfe->count >= 1); 47991061084SMateusz Guzik mpfe->count--; 48091061084SMateusz Guzik if (mpfe->count == 0) { 48191061084SMateusz Guzik MPASS(*mpfe->flag == true); 48291061084SMateusz Guzik *mpfe->flag = false; 48391061084SMateusz Guzik } 48491061084SMateusz Guzik } 48591061084SMateusz Guzik 48691061084SMateusz Guzik static void 48791061084SMateusz Guzik mac_policy_fastpath_register(struct mac_policy_conf *mpc) 48891061084SMateusz Guzik { 48991061084SMateusz Guzik struct mac_policy_fastpath_elem *mpfe; 49091061084SMateusz Guzik uintptr_t **ops; 49191061084SMateusz Guzik int i; 49291061084SMateusz Guzik 49391061084SMateusz Guzik mac_policy_xlock_assert(); 49491061084SMateusz Guzik 49591061084SMateusz Guzik ops = (uintptr_t **)mpc->mpc_ops; 49691061084SMateusz Guzik for (i = 0; i < nitems(mac_policy_fastpath_array); i++) { 49791061084SMateusz Guzik mpfe = &mac_policy_fastpath_array[i]; 49891061084SMateusz Guzik if (ops[mpfe->offset] != NULL) 49991061084SMateusz Guzik mac_policy_fastpath_enable(mpfe); 50091061084SMateusz Guzik } 50191061084SMateusz Guzik } 50291061084SMateusz Guzik 50391061084SMateusz Guzik static void 50491061084SMateusz Guzik mac_policy_fastpath_unregister(struct mac_policy_conf *mpc) 50591061084SMateusz Guzik { 50691061084SMateusz Guzik struct mac_policy_fastpath_elem *mpfe; 50791061084SMateusz Guzik uintptr_t **ops; 50891061084SMateusz Guzik int i; 50991061084SMateusz Guzik 51091061084SMateusz Guzik mac_policy_xlock_assert(); 51191061084SMateusz Guzik 51291061084SMateusz Guzik ops = (uintptr_t **)mpc->mpc_ops; 51391061084SMateusz Guzik for (i = 0; i < nitems(mac_policy_fastpath_array); i++) { 51491061084SMateusz Guzik mpfe = &mac_policy_fastpath_array[i]; 51591061084SMateusz Guzik if (ops[mpfe->offset] != NULL) 51691061084SMateusz Guzik mac_policy_fastpath_disable(mpfe); 51791061084SMateusz Guzik } 51891061084SMateusz Guzik } 51991061084SMateusz Guzik 52091061084SMateusz Guzik #undef FPO 52191061084SMateusz Guzik 52295fab37eSRobert Watson static int 52395fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc) 52495fab37eSRobert Watson { 5258deb442cSSteve Kiernan struct mac_policy_list_head *mpc_list; 5268deb442cSSteve Kiernan struct mac_policy_conf *last_mpc, *tmpc; 52741a17fe3SRobert Watson int error, slot, static_entry; 52895fab37eSRobert Watson 52941a17fe3SRobert Watson error = 0; 53041a17fe3SRobert Watson 53141a17fe3SRobert Watson /* 53217041e67SRobert Watson * We don't technically need exclusive access while !mac_late, but 53317041e67SRobert Watson * hold it for assertion consistency. 53441a17fe3SRobert Watson */ 53540202729SRobert Watson mac_policy_xlock(); 53641a17fe3SRobert Watson 53741a17fe3SRobert Watson /* 53817041e67SRobert Watson * If the module can potentially be unloaded, or we're loading late, 53917041e67SRobert Watson * we have to stick it in the non-static list and pay an extra 54017041e67SRobert Watson * performance overhead. Otherwise, we can pay a light locking cost 54117041e67SRobert Watson * and stick it in the static list. 54241a17fe3SRobert Watson */ 54341a17fe3SRobert Watson static_entry = (!mac_late && 54441a17fe3SRobert Watson !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 54541a17fe3SRobert Watson 5468deb442cSSteve Kiernan mpc_list = (static_entry) ? &mac_static_policy_list : 5478deb442cSSteve Kiernan &mac_policy_list; 5488deb442cSSteve Kiernan last_mpc = NULL; 5498deb442cSSteve Kiernan LIST_FOREACH(tmpc, mpc_list, mpc_list) { 5508deb442cSSteve Kiernan last_mpc = tmpc; 55141a17fe3SRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 55241a17fe3SRobert Watson error = EEXIST; 55341a17fe3SRobert Watson goto out; 55441a17fe3SRobert Watson } 55541a17fe3SRobert Watson } 55695fab37eSRobert Watson if (mpc->mpc_field_off != NULL) { 557b2aef571SRobert Watson slot = ffs(mac_slot_offsets_free); 55895fab37eSRobert Watson if (slot == 0) { 55941a17fe3SRobert Watson error = ENOMEM; 56041a17fe3SRobert Watson goto out; 56195fab37eSRobert Watson } 56295fab37eSRobert Watson slot--; 563b2aef571SRobert Watson mac_slot_offsets_free &= ~(1 << slot); 56495fab37eSRobert Watson *mpc->mpc_field_off = slot; 56595fab37eSRobert Watson } 56695fab37eSRobert Watson mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 56741a17fe3SRobert Watson 56841a17fe3SRobert Watson /* 5698deb442cSSteve Kiernan * Some modules may depend on the operations of its dependencies. 5708deb442cSSteve Kiernan * Inserting modules in order of registration ensures operations 5718deb442cSSteve Kiernan * that work on the module list retain dependency order. 57241a17fe3SRobert Watson */ 5738deb442cSSteve Kiernan if (last_mpc == NULL) 5748deb442cSSteve Kiernan LIST_INSERT_HEAD(mpc_list, mpc, mpc_list); 57541a17fe3SRobert Watson else 5768deb442cSSteve Kiernan LIST_INSERT_AFTER(last_mpc, mpc, mpc_list); 57717041e67SRobert Watson /* 57817041e67SRobert Watson * Per-policy initialization. Currently, this takes place under the 57917041e67SRobert Watson * exclusive lock, so policies must not sleep in their init method. 58017041e67SRobert Watson * In the future, we may want to separate "init" from "start", with 581bc5ade0dSPedro F. Giffuni * "init" occurring without the lock held. Likewise, on tear-down, 58217041e67SRobert Watson * breaking out "stop" from "destroy". 58317041e67SRobert Watson */ 58495fab37eSRobert Watson if (mpc->mpc_ops->mpo_init != NULL) 58595fab37eSRobert Watson (*(mpc->mpc_ops->mpo_init))(mpc); 58691061084SMateusz Guzik 58791061084SMateusz Guzik mac_policy_fastpath_register(mpc); 58891061084SMateusz Guzik 589f93bfb23SRobert Watson mac_policy_update(); 59095fab37eSRobert Watson 59136160958SMark Johnston SDT_PROBE1(mac, , policy, register, mpc); 59295fab37eSRobert Watson printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 59395fab37eSRobert Watson mpc->mpc_name); 59495fab37eSRobert Watson 59541a17fe3SRobert Watson out: 59640202729SRobert Watson mac_policy_xunlock(); 59741a17fe3SRobert Watson return (error); 59895fab37eSRobert Watson } 59995fab37eSRobert Watson 60095fab37eSRobert Watson static int 60195fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc) 60295fab37eSRobert Watson { 60395fab37eSRobert Watson 604ea599aa0SRobert Watson /* 60517041e67SRobert Watson * If we fail the load, we may get a request to unload. Check to see 60617041e67SRobert Watson * if we did the run-time registration, and if not, silently succeed. 607ea599aa0SRobert Watson */ 60840202729SRobert Watson mac_policy_xlock(); 609ea599aa0SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 61040202729SRobert Watson mac_policy_xunlock(); 611ea599aa0SRobert Watson return (0); 612ea599aa0SRobert Watson } 61395fab37eSRobert Watson #if 0 61495fab37eSRobert Watson /* 61595fab37eSRobert Watson * Don't allow unloading modules with private data. 61695fab37eSRobert Watson */ 617ea599aa0SRobert Watson if (mpc->mpc_field_off != NULL) { 61840202729SRobert Watson mac_policy_xunlock(); 61995fab37eSRobert Watson return (EBUSY); 620ea599aa0SRobert Watson } 62195fab37eSRobert Watson #endif 622ea599aa0SRobert Watson /* 62317041e67SRobert Watson * Only allow the unload to proceed if the module is unloadable by 62417041e67SRobert Watson * its own definition. 625ea599aa0SRobert Watson */ 626ea599aa0SRobert Watson if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 62740202729SRobert Watson mac_policy_xunlock(); 62895fab37eSRobert Watson return (EBUSY); 629ea599aa0SRobert Watson } 63091061084SMateusz Guzik 63191061084SMateusz Guzik mac_policy_fastpath_unregister(mpc); 63291061084SMateusz Guzik 63395fab37eSRobert Watson if (mpc->mpc_ops->mpo_destroy != NULL) 63495fab37eSRobert Watson (*(mpc->mpc_ops->mpo_destroy))(mpc); 63595fab37eSRobert Watson 63695fab37eSRobert Watson LIST_REMOVE(mpc, mpc_list); 6379aeffb2bSRobert Watson mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 638f93bfb23SRobert Watson mac_policy_update(); 63940202729SRobert Watson mac_policy_xunlock(); 640a96acd1aSRobert Watson 64136160958SMark Johnston SDT_PROBE1(mac, , policy, unregister, mpc); 64295fab37eSRobert Watson printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 64395fab37eSRobert Watson mpc->mpc_name); 64495fab37eSRobert Watson 64595fab37eSRobert Watson return (0); 64695fab37eSRobert Watson } 64795fab37eSRobert Watson 64895fab37eSRobert Watson /* 649c441d123SRobert Watson * Allow MAC policy modules to register during boot, etc. 650c441d123SRobert Watson */ 651c441d123SRobert Watson int 652c441d123SRobert Watson mac_policy_modevent(module_t mod, int type, void *data) 653c441d123SRobert Watson { 654c441d123SRobert Watson struct mac_policy_conf *mpc; 655c441d123SRobert Watson int error; 656c441d123SRobert Watson 657c441d123SRobert Watson error = 0; 658c441d123SRobert Watson mpc = (struct mac_policy_conf *) data; 659c441d123SRobert Watson 660c441d123SRobert Watson #ifdef MAC_STATIC 661c441d123SRobert Watson if (mac_late) { 662c441d123SRobert Watson printf("mac_policy_modevent: MAC_STATIC and late\n"); 663c441d123SRobert Watson return (EBUSY); 664c441d123SRobert Watson } 665c441d123SRobert Watson #endif 666c441d123SRobert Watson 66736160958SMark Johnston SDT_PROBE2(mac, , policy, modevent, type, mpc); 668c441d123SRobert Watson switch (type) { 669c441d123SRobert Watson case MOD_LOAD: 670c441d123SRobert Watson if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 671c441d123SRobert Watson mac_late) { 672c441d123SRobert Watson printf("mac_policy_modevent: can't load %s policy " 673c441d123SRobert Watson "after booting\n", mpc->mpc_name); 674c441d123SRobert Watson error = EBUSY; 675c441d123SRobert Watson break; 676c441d123SRobert Watson } 677c441d123SRobert Watson error = mac_policy_register(mpc); 678c441d123SRobert Watson break; 679c441d123SRobert Watson case MOD_UNLOAD: 680c441d123SRobert Watson /* Don't unregister the module if it was never registered. */ 681c441d123SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 682c441d123SRobert Watson != 0) 683c441d123SRobert Watson error = mac_policy_unregister(mpc); 684c441d123SRobert Watson else 685c441d123SRobert Watson error = 0; 686c441d123SRobert Watson break; 687c441d123SRobert Watson default: 688c441d123SRobert Watson error = EOPNOTSUPP; 689c441d123SRobert Watson break; 690c441d123SRobert Watson } 691c441d123SRobert Watson 692c441d123SRobert Watson return (error); 693c441d123SRobert Watson } 694c441d123SRobert Watson 695c441d123SRobert Watson /* 69695fab37eSRobert Watson * Define an error value precedence, and given two arguments, selects the 69795fab37eSRobert Watson * value with the higher precedence. 69895fab37eSRobert Watson */ 6999e7bf51cSRobert Watson int 7009e7bf51cSRobert Watson mac_error_select(int error1, int error2) 70195fab37eSRobert Watson { 70295fab37eSRobert Watson 70395fab37eSRobert Watson /* Certain decision-making errors take top priority. */ 70495fab37eSRobert Watson if (error1 == EDEADLK || error2 == EDEADLK) 70595fab37eSRobert Watson return (EDEADLK); 70695fab37eSRobert Watson 70795fab37eSRobert Watson /* Invalid arguments should be reported where possible. */ 70895fab37eSRobert Watson if (error1 == EINVAL || error2 == EINVAL) 70995fab37eSRobert Watson return (EINVAL); 71095fab37eSRobert Watson 71195fab37eSRobert Watson /* Precedence goes to "visibility", with both process and file. */ 71295fab37eSRobert Watson if (error1 == ESRCH || error2 == ESRCH) 71395fab37eSRobert Watson return (ESRCH); 71495fab37eSRobert Watson 71595fab37eSRobert Watson if (error1 == ENOENT || error2 == ENOENT) 71695fab37eSRobert Watson return (ENOENT); 71795fab37eSRobert Watson 71895fab37eSRobert Watson /* Precedence goes to DAC/MAC protections. */ 71995fab37eSRobert Watson if (error1 == EACCES || error2 == EACCES) 72095fab37eSRobert Watson return (EACCES); 72195fab37eSRobert Watson 72295fab37eSRobert Watson /* Precedence goes to privilege. */ 72395fab37eSRobert Watson if (error1 == EPERM || error2 == EPERM) 72495fab37eSRobert Watson return (EPERM); 72595fab37eSRobert Watson 72695fab37eSRobert Watson /* Precedence goes to error over success; otherwise, arbitrary. */ 72795fab37eSRobert Watson if (error1 != 0) 72895fab37eSRobert Watson return (error1); 72995fab37eSRobert Watson return (error2); 73095fab37eSRobert Watson } 73195fab37eSRobert Watson 7325e7ce478SRobert Watson int 733f64a688dSBrooks Davis mac_check_structmac_consistent(const struct mac *mac) 734f7b951a8SRobert Watson { 7356324de03SMark Johnston /* Require that labels have a non-zero length. */ 7366324de03SMark Johnston if (mac->m_buflen > MAC_MAX_LABEL_BUF_LEN || 7376324de03SMark Johnston mac->m_buflen <= sizeof("")) 738f7b951a8SRobert Watson return (EINVAL); 739f7b951a8SRobert Watson 740f7b951a8SRobert Watson return (0); 741f7b951a8SRobert Watson } 742f7b951a8SRobert Watson 74395fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 74495fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 745