17bc82500SRobert Watson /*- 27bc82500SRobert Watson * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 37bc82500SRobert Watson * Copyright (c) 2001 Ilmar S. Habibulin 42d3db0b8SRobert Watson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc. 57bc82500SRobert Watson * All rights reserved. 67bc82500SRobert Watson * 77bc82500SRobert Watson * This software was developed by Robert Watson and Ilmar Habibulin for the 87bc82500SRobert Watson * TrustedBSD Project. 97bc82500SRobert Watson * 106201265bSRobert Watson * This software was developed for the FreeBSD Project in part by Network 116201265bSRobert Watson * Associates Laboratories, the Security Research Division of Network 126201265bSRobert Watson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 136201265bSRobert Watson * as part of the DARPA CHATS research program. 147bc82500SRobert Watson * 157bc82500SRobert Watson * Redistribution and use in source and binary forms, with or without 167bc82500SRobert Watson * modification, are permitted provided that the following conditions 177bc82500SRobert Watson * are met: 187bc82500SRobert Watson * 1. Redistributions of source code must retain the above copyright 197bc82500SRobert Watson * notice, this list of conditions and the following disclaimer. 207bc82500SRobert Watson * 2. Redistributions in binary form must reproduce the above copyright 217bc82500SRobert Watson * notice, this list of conditions and the following disclaimer in the 227bc82500SRobert Watson * documentation and/or other materials provided with the distribution. 237bc82500SRobert Watson * 247bc82500SRobert Watson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 257bc82500SRobert Watson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 267bc82500SRobert Watson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 277bc82500SRobert Watson * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 287bc82500SRobert Watson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 297bc82500SRobert Watson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 307bc82500SRobert Watson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 317bc82500SRobert Watson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 327bc82500SRobert Watson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 337bc82500SRobert Watson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 347bc82500SRobert Watson * SUCH DAMAGE. 357bc82500SRobert Watson */ 36677b542eSDavid E. O'Brien 377bc82500SRobert Watson /* 387bc82500SRobert Watson * Framework for extensible kernel access control. Kernel and userland 397bc82500SRobert Watson * interface to the framework, policy registration and composition. 407bc82500SRobert Watson */ 417bc82500SRobert Watson 42677b542eSDavid E. O'Brien #include <sys/cdefs.h> 43677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 44677b542eSDavid E. O'Brien 457bc82500SRobert Watson #include "opt_mac.h" 46328048bcSPoul-Henning Kamp #include "opt_devfs.h" 47f9d0d524SRobert Watson 487bc82500SRobert Watson #include <sys/param.h> 49a96acd1aSRobert Watson #include <sys/condvar.h> 5095fab37eSRobert Watson #include <sys/extattr.h> 51670cb89bSRobert Watson #include <sys/imgact.h> 5295fab37eSRobert Watson #include <sys/kernel.h> 5395fab37eSRobert Watson #include <sys/lock.h> 54b656366bSBruce Evans #include <sys/malloc.h> 5595fab37eSRobert Watson #include <sys/mutex.h> 5695fab37eSRobert Watson #include <sys/mac.h> 577ba28492SRobert Watson #include <sys/module.h> 5895fab37eSRobert Watson #include <sys/proc.h> 59f51e5803SRobert Watson #include <sys/sbuf.h> 6095fab37eSRobert Watson #include <sys/systm.h> 617bc82500SRobert Watson #include <sys/sysproto.h> 627bc82500SRobert Watson #include <sys/sysent.h> 6395fab37eSRobert Watson #include <sys/vnode.h> 6495fab37eSRobert Watson #include <sys/mount.h> 6595fab37eSRobert Watson #include <sys/file.h> 6695fab37eSRobert Watson #include <sys/namei.h> 6795fab37eSRobert Watson #include <sys/socket.h> 6895fab37eSRobert Watson #include <sys/pipe.h> 6995fab37eSRobert Watson #include <sys/socketvar.h> 7095fab37eSRobert Watson #include <sys/sysctl.h> 7195fab37eSRobert Watson 7295fab37eSRobert Watson #include <vm/vm.h> 7395fab37eSRobert Watson #include <vm/pmap.h> 7495fab37eSRobert Watson #include <vm/vm_map.h> 7595fab37eSRobert Watson #include <vm/vm_object.h> 7695fab37eSRobert Watson 7795fab37eSRobert Watson #include <sys/mac_policy.h> 7895fab37eSRobert Watson 7995fab37eSRobert Watson #include <fs/devfs/devfs.h> 8095fab37eSRobert Watson 8195fab37eSRobert Watson #include <net/bpfdesc.h> 8295fab37eSRobert Watson #include <net/if.h> 8395fab37eSRobert Watson #include <net/if_var.h> 8495fab37eSRobert Watson 8595fab37eSRobert Watson #include <netinet/in.h> 8695fab37eSRobert Watson #include <netinet/ip_var.h> 8795fab37eSRobert Watson 886fa0475dSRobert Watson #include <security/mac/mac_internal.h> 896fa0475dSRobert Watson 9095fab37eSRobert Watson #ifdef MAC 9195fab37eSRobert Watson 927ba28492SRobert Watson /* 937ba28492SRobert Watson * Declare that the kernel provides MAC support, version 1. This permits 947ba28492SRobert Watson * modules to refuse to be loaded if the necessary support isn't present, 957ba28492SRobert Watson * even if it's pre-boot. 967ba28492SRobert Watson */ 977ba28492SRobert Watson MODULE_VERSION(kernel_mac_support, 1); 987ba28492SRobert Watson 9995fab37eSRobert Watson SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, 10095fab37eSRobert Watson "TrustedBSD MAC policy controls"); 101b2f0927aSRobert Watson 102b2aef571SRobert Watson #if MAC_MAX_SLOTS > 32 103b2aef571SRobert Watson #error "MAC_MAX_SLOTS too large" 10495fab37eSRobert Watson #endif 105a13c67daSRobert Watson 106b2aef571SRobert Watson static unsigned int mac_max_slots = MAC_MAX_SLOTS; 107b2aef571SRobert Watson static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1; 108b2aef571SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, 109b2aef571SRobert Watson &mac_max_slots, 0, ""); 11095fab37eSRobert Watson 111a67fe518SRobert Watson /* 112a67fe518SRobert Watson * Has the kernel started generating labeled objects yet? All read/write 113a67fe518SRobert Watson * access to this variable is serialized during the boot process. Following 114a67fe518SRobert Watson * the end of serialization, we don't update this flag; no locking. 115a67fe518SRobert Watson */ 116089c1bdaSRobert Watson int mac_late = 0; 117763bbd2fSRobert Watson 118225bff6fSRobert Watson /* 119225bff6fSRobert Watson * Flag to indicate whether or not we should allocate label storage for 120225bff6fSRobert Watson * new mbufs. Since most dynamic policies we currently work with don't 121225bff6fSRobert Watson * rely on mbuf labeling, try to avoid paying the cost of mtag allocation 122225bff6fSRobert Watson * unless specifically notified of interest. One result of this is 123225bff6fSRobert Watson * that if a dynamically loaded policy requests mbuf labels, it must 124225bff6fSRobert Watson * be able to deal with a NULL label being returned on any mbufs that 125225bff6fSRobert Watson * were already in flight when the policy was loaded. Since the policy 126225bff6fSRobert Watson * already has to deal with uninitialized labels, this probably won't 127225bff6fSRobert Watson * be a problem. Note: currently no locking. Will this be a problem? 128225bff6fSRobert Watson */ 12919c3e120SRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF 130089c1bdaSRobert Watson int mac_labelmbufs = 0; 131225bff6fSRobert Watson #endif 132225bff6fSRobert Watson 133f050add5SRobert Watson #ifdef MAC_DEBUG 1346be0c25eSRobert Watson SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0, 1356be0c25eSRobert Watson "TrustedBSD MAC debug info"); 136b2f0927aSRobert Watson SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0, 137b2f0927aSRobert Watson "TrustedBSD MAC object counters"); 138b2f0927aSRobert Watson 1396fa0475dSRobert Watson static unsigned int nmactemp; 140b2f0927aSRobert Watson SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD, 14195fab37eSRobert Watson &nmactemp, 0, "number of temporary labels in use"); 142f050add5SRobert Watson #endif 14395fab37eSRobert Watson 14495fab37eSRobert Watson static int mac_policy_register(struct mac_policy_conf *mpc); 14595fab37eSRobert Watson static int mac_policy_unregister(struct mac_policy_conf *mpc); 14695fab37eSRobert Watson 147f7b951a8SRobert Watson MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 14895fab37eSRobert Watson 14995fab37eSRobert Watson /* 15041a17fe3SRobert Watson * mac_static_policy_list holds a list of policy modules that are not 15141a17fe3SRobert Watson * loaded while the system is "live", and cannot be unloaded. These 15241a17fe3SRobert Watson * policies can be invoked without holding the busy count. 15341a17fe3SRobert Watson * 15441a17fe3SRobert Watson * mac_policy_list stores the list of dynamic policies. A busy count is 155a96acd1aSRobert Watson * maintained for the list, stored in mac_policy_busy. The busy count 15641a17fe3SRobert Watson * is protected by mac_policy_mtx; the list may be modified only 157a96acd1aSRobert Watson * while the busy count is 0, requiring that the lock be held to 158a96acd1aSRobert Watson * prevent new references to the list from being acquired. For almost 159a96acd1aSRobert Watson * all operations, incrementing the busy count is sufficient to 160a96acd1aSRobert Watson * guarantee consistency, as the list cannot be modified while the 161a96acd1aSRobert Watson * busy count is elevated. For a few special operations involving a 16241a17fe3SRobert Watson * change to the list of active policies, the mtx itself must be held. 16341a17fe3SRobert Watson * A condition variable, mac_policy_cv, is used to signal potential 16441a17fe3SRobert Watson * exclusive consumers that they should try to acquire the lock if a 16541a17fe3SRobert Watson * first attempt at exclusive access fails. 16695fab37eSRobert Watson */ 16741a17fe3SRobert Watson static struct mtx mac_policy_mtx; 16841a17fe3SRobert Watson static struct cv mac_policy_cv; 16941a17fe3SRobert Watson static int mac_policy_count; 170089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list; 171089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list; 172a96acd1aSRobert Watson 173a96acd1aSRobert Watson /* 17426306795SJohn Baldwin * We manually invoke WITNESS_WARN() to allow Witness to generate 175a96acd1aSRobert Watson * warnings even if we don't end up ever triggering the wait at 176a96acd1aSRobert Watson * run-time. The consumer of the exclusive interface must not hold 177a96acd1aSRobert Watson * any locks (other than potentially Giant) since we may sleep for 178a96acd1aSRobert Watson * long (potentially indefinite) periods of time waiting for the 179a96acd1aSRobert Watson * framework to become quiescent so that a policy list change may 180a96acd1aSRobert Watson * be made. 181a96acd1aSRobert Watson */ 182089c1bdaSRobert Watson void 18341a17fe3SRobert Watson mac_policy_grab_exclusive(void) 18441a17fe3SRobert Watson { 18541a17fe3SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 18641a17fe3SRobert Watson "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); 18741a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 18841a17fe3SRobert Watson while (mac_policy_count != 0) 18941a17fe3SRobert Watson cv_wait(&mac_policy_cv, &mac_policy_mtx); 19041a17fe3SRobert Watson } 19195fab37eSRobert Watson 192089c1bdaSRobert Watson void 19341a17fe3SRobert Watson mac_policy_assert_exclusive(void) 19441a17fe3SRobert Watson { 19541a17fe3SRobert Watson mtx_assert(&mac_policy_mtx, MA_OWNED); 19641a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 19741a17fe3SRobert Watson ("mac_policy_assert_exclusive(): not exclusive")); 19841a17fe3SRobert Watson } 199225bff6fSRobert Watson 200089c1bdaSRobert Watson void 20141a17fe3SRobert Watson mac_policy_release_exclusive(void) 20241a17fe3SRobert Watson { 20395fab37eSRobert Watson 20441a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 20541a17fe3SRobert Watson ("mac_policy_release_exclusive(): not exclusive")); 20641a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 20741a17fe3SRobert Watson cv_signal(&mac_policy_cv); 20841a17fe3SRobert Watson } 20941a17fe3SRobert Watson 210089c1bdaSRobert Watson void 21141a17fe3SRobert Watson mac_policy_list_busy(void) 21241a17fe3SRobert Watson { 21341a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 21441a17fe3SRobert Watson mac_policy_count++; 21541a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 21641a17fe3SRobert Watson } 21741a17fe3SRobert Watson 218089c1bdaSRobert Watson int 21941a17fe3SRobert Watson mac_policy_list_conditional_busy(void) 22041a17fe3SRobert Watson { 22141a17fe3SRobert Watson int ret; 22241a17fe3SRobert Watson 22341a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 22441a17fe3SRobert Watson if (!LIST_EMPTY(&mac_policy_list)) { 22541a17fe3SRobert Watson mac_policy_count++; 22641a17fe3SRobert Watson ret = 1; 22741a17fe3SRobert Watson } else 22841a17fe3SRobert Watson ret = 0; 22941a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 23041a17fe3SRobert Watson return (ret); 23141a17fe3SRobert Watson } 23241a17fe3SRobert Watson 233089c1bdaSRobert Watson void 23441a17fe3SRobert Watson mac_policy_list_unbusy(void) 23541a17fe3SRobert Watson { 23641a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 23741a17fe3SRobert Watson mac_policy_count--; 23841a17fe3SRobert Watson KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); 23941a17fe3SRobert Watson if (mac_policy_count == 0) 24041a17fe3SRobert Watson cv_signal(&mac_policy_cv); 24141a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 24241a17fe3SRobert Watson } 24395fab37eSRobert Watson 24495fab37eSRobert Watson /* 24595fab37eSRobert Watson * Initialize the MAC subsystem, including appropriate SMP locks. 24695fab37eSRobert Watson */ 24795fab37eSRobert Watson static void 24895fab37eSRobert Watson mac_init(void) 24995fab37eSRobert Watson { 25095fab37eSRobert Watson 25141a17fe3SRobert Watson LIST_INIT(&mac_static_policy_list); 25295fab37eSRobert Watson LIST_INIT(&mac_policy_list); 25341a17fe3SRobert Watson 25441a17fe3SRobert Watson mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); 25541a17fe3SRobert Watson cv_init(&mac_policy_cv, "mac_policy_cv"); 25695fab37eSRobert Watson } 25795fab37eSRobert Watson 25895fab37eSRobert Watson /* 25995fab37eSRobert Watson * For the purposes of modules that want to know if they were loaded 26095fab37eSRobert Watson * "early", set the mac_late flag once we've processed modules either 26195fab37eSRobert Watson * linked into the kernel, or loaded before the kernel startup. 26295fab37eSRobert Watson */ 26395fab37eSRobert Watson static void 26495fab37eSRobert Watson mac_late_init(void) 26595fab37eSRobert Watson { 26695fab37eSRobert Watson 26795fab37eSRobert Watson mac_late = 1; 26895fab37eSRobert Watson } 26995fab37eSRobert Watson 27095fab37eSRobert Watson /* 271225bff6fSRobert Watson * After the policy list has changed, walk the list to update any global 27219c3e120SRobert Watson * flags. Currently, we support only one flag, and it's conditionally 27319c3e120SRobert Watson * defined; as a result, the entire function is conditional. Eventually, 27419c3e120SRobert Watson * the #else case might also iterate across the policies. 275225bff6fSRobert Watson */ 276225bff6fSRobert Watson static void 277225bff6fSRobert Watson mac_policy_updateflags(void) 278225bff6fSRobert Watson { 279225bff6fSRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF 28019c3e120SRobert Watson struct mac_policy_conf *tmpc; 281225bff6fSRobert Watson int labelmbufs; 282225bff6fSRobert Watson 28341a17fe3SRobert Watson mac_policy_assert_exclusive(); 284225bff6fSRobert Watson 285225bff6fSRobert Watson labelmbufs = 0; 28641a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 28741a17fe3SRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 28841a17fe3SRobert Watson labelmbufs++; 28941a17fe3SRobert Watson } 290225bff6fSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 291225bff6fSRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 292225bff6fSRobert Watson labelmbufs++; 293225bff6fSRobert Watson } 294225bff6fSRobert Watson mac_labelmbufs = (labelmbufs != 0); 295225bff6fSRobert Watson #endif 296225bff6fSRobert Watson } 297225bff6fSRobert Watson 298225bff6fSRobert Watson /* 29995fab37eSRobert Watson * Allow MAC policy modules to register during boot, etc. 30095fab37eSRobert Watson */ 30195fab37eSRobert Watson int 30295fab37eSRobert Watson mac_policy_modevent(module_t mod, int type, void *data) 30395fab37eSRobert Watson { 30495fab37eSRobert Watson struct mac_policy_conf *mpc; 30595fab37eSRobert Watson int error; 30695fab37eSRobert Watson 30795fab37eSRobert Watson error = 0; 30895fab37eSRobert Watson mpc = (struct mac_policy_conf *) data; 30995fab37eSRobert Watson 31095fab37eSRobert Watson switch (type) { 31195fab37eSRobert Watson case MOD_LOAD: 31295fab37eSRobert Watson if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 31395fab37eSRobert Watson mac_late) { 31495fab37eSRobert Watson printf("mac_policy_modevent: can't load %s policy " 31595fab37eSRobert Watson "after booting\n", mpc->mpc_name); 31695fab37eSRobert Watson error = EBUSY; 31795fab37eSRobert Watson break; 31895fab37eSRobert Watson } 31995fab37eSRobert Watson error = mac_policy_register(mpc); 32095fab37eSRobert Watson break; 32195fab37eSRobert Watson case MOD_UNLOAD: 32295fab37eSRobert Watson /* Don't unregister the module if it was never registered. */ 32395fab37eSRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 32495fab37eSRobert Watson != 0) 32595fab37eSRobert Watson error = mac_policy_unregister(mpc); 32695fab37eSRobert Watson else 32795fab37eSRobert Watson error = 0; 32895fab37eSRobert Watson break; 32995fab37eSRobert Watson default: 33095fab37eSRobert Watson break; 33195fab37eSRobert Watson } 33295fab37eSRobert Watson 33395fab37eSRobert Watson return (error); 33495fab37eSRobert Watson } 33595fab37eSRobert Watson 33695fab37eSRobert Watson static int 33795fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc) 33895fab37eSRobert Watson { 33995fab37eSRobert Watson struct mac_policy_conf *tmpc; 34041a17fe3SRobert Watson int error, slot, static_entry; 34195fab37eSRobert Watson 34241a17fe3SRobert Watson error = 0; 34341a17fe3SRobert Watson 34441a17fe3SRobert Watson /* 34541a17fe3SRobert Watson * We don't technically need exclusive access while !mac_late, 34641a17fe3SRobert Watson * but hold it for assertion consistency. 34741a17fe3SRobert Watson */ 34841a17fe3SRobert Watson mac_policy_grab_exclusive(); 34941a17fe3SRobert Watson 35041a17fe3SRobert Watson /* 35141a17fe3SRobert Watson * If the module can potentially be unloaded, or we're loading 35241a17fe3SRobert Watson * late, we have to stick it in the non-static list and pay 35341a17fe3SRobert Watson * an extra performance overhead. Otherwise, we can pay a 35441a17fe3SRobert Watson * light locking cost and stick it in the static list. 35541a17fe3SRobert Watson */ 35641a17fe3SRobert Watson static_entry = (!mac_late && 35741a17fe3SRobert Watson !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 35841a17fe3SRobert Watson 35941a17fe3SRobert Watson if (static_entry) { 36041a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 36141a17fe3SRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 36241a17fe3SRobert Watson error = EEXIST; 36341a17fe3SRobert Watson goto out; 36441a17fe3SRobert Watson } 36541a17fe3SRobert Watson } 36641a17fe3SRobert Watson } else { 36795fab37eSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 36895fab37eSRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 36941a17fe3SRobert Watson error = EEXIST; 37041a17fe3SRobert Watson goto out; 37141a17fe3SRobert Watson } 37295fab37eSRobert Watson } 37395fab37eSRobert Watson } 37495fab37eSRobert Watson if (mpc->mpc_field_off != NULL) { 375b2aef571SRobert Watson slot = ffs(mac_slot_offsets_free); 37695fab37eSRobert Watson if (slot == 0) { 37741a17fe3SRobert Watson error = ENOMEM; 37841a17fe3SRobert Watson goto out; 37995fab37eSRobert Watson } 38095fab37eSRobert Watson slot--; 381b2aef571SRobert Watson mac_slot_offsets_free &= ~(1 << slot); 38295fab37eSRobert Watson *mpc->mpc_field_off = slot; 38395fab37eSRobert Watson } 38495fab37eSRobert Watson mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 38541a17fe3SRobert Watson 38641a17fe3SRobert Watson /* 38741a17fe3SRobert Watson * If we're loading a MAC module after the framework has 38841a17fe3SRobert Watson * initialized, it has to go into the dynamic list. If 38941a17fe3SRobert Watson * we're loading it before we've finished initializing, 39041a17fe3SRobert Watson * it can go into the static list with weaker locker 39141a17fe3SRobert Watson * requirements. 39241a17fe3SRobert Watson */ 39341a17fe3SRobert Watson if (static_entry) 39441a17fe3SRobert Watson LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); 39541a17fe3SRobert Watson else 39695fab37eSRobert Watson LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 39795fab37eSRobert Watson 39895fab37eSRobert Watson /* Per-policy initialization. */ 39995fab37eSRobert Watson if (mpc->mpc_ops->mpo_init != NULL) 40095fab37eSRobert Watson (*(mpc->mpc_ops->mpo_init))(mpc); 401225bff6fSRobert Watson mac_policy_updateflags(); 40295fab37eSRobert Watson 40395fab37eSRobert Watson printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 40495fab37eSRobert Watson mpc->mpc_name); 40595fab37eSRobert Watson 40641a17fe3SRobert Watson out: 40741a17fe3SRobert Watson mac_policy_release_exclusive(); 40841a17fe3SRobert Watson return (error); 40995fab37eSRobert Watson } 41095fab37eSRobert Watson 41195fab37eSRobert Watson static int 41295fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc) 41395fab37eSRobert Watson { 41495fab37eSRobert Watson 415ea599aa0SRobert Watson /* 416ea599aa0SRobert Watson * If we fail the load, we may get a request to unload. Check 417ea599aa0SRobert Watson * to see if we did the run-time registration, and if not, 418ea599aa0SRobert Watson * silently succeed. 419ea599aa0SRobert Watson */ 42041a17fe3SRobert Watson mac_policy_grab_exclusive(); 421ea599aa0SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 42241a17fe3SRobert Watson mac_policy_release_exclusive(); 423ea599aa0SRobert Watson return (0); 424ea599aa0SRobert Watson } 42595fab37eSRobert Watson #if 0 42695fab37eSRobert Watson /* 42795fab37eSRobert Watson * Don't allow unloading modules with private data. 42895fab37eSRobert Watson */ 429ea599aa0SRobert Watson if (mpc->mpc_field_off != NULL) { 430ea599aa0SRobert Watson MAC_POLICY_LIST_UNLOCK(); 43195fab37eSRobert Watson return (EBUSY); 432ea599aa0SRobert Watson } 43395fab37eSRobert Watson #endif 434ea599aa0SRobert Watson /* 435ea599aa0SRobert Watson * Only allow the unload to proceed if the module is unloadable 436ea599aa0SRobert Watson * by its own definition. 437ea599aa0SRobert Watson */ 438ea599aa0SRobert Watson if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 43941a17fe3SRobert Watson mac_policy_release_exclusive(); 44095fab37eSRobert Watson return (EBUSY); 441ea599aa0SRobert Watson } 44295fab37eSRobert Watson if (mpc->mpc_ops->mpo_destroy != NULL) 44395fab37eSRobert Watson (*(mpc->mpc_ops->mpo_destroy))(mpc); 44495fab37eSRobert Watson 44595fab37eSRobert Watson LIST_REMOVE(mpc, mpc_list); 4469aeffb2bSRobert Watson mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 447225bff6fSRobert Watson mac_policy_updateflags(); 44841a17fe3SRobert Watson 44941a17fe3SRobert Watson mac_policy_release_exclusive(); 450a96acd1aSRobert Watson 45195fab37eSRobert Watson printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 45295fab37eSRobert Watson mpc->mpc_name); 45395fab37eSRobert Watson 45495fab37eSRobert Watson return (0); 45595fab37eSRobert Watson } 45695fab37eSRobert Watson 45795fab37eSRobert Watson /* 45895fab37eSRobert Watson * Define an error value precedence, and given two arguments, selects the 45995fab37eSRobert Watson * value with the higher precedence. 46095fab37eSRobert Watson */ 4619e7bf51cSRobert Watson int 4629e7bf51cSRobert Watson mac_error_select(int error1, int error2) 46395fab37eSRobert Watson { 46495fab37eSRobert Watson 46595fab37eSRobert Watson /* Certain decision-making errors take top priority. */ 46695fab37eSRobert Watson if (error1 == EDEADLK || error2 == EDEADLK) 46795fab37eSRobert Watson return (EDEADLK); 46895fab37eSRobert Watson 46995fab37eSRobert Watson /* Invalid arguments should be reported where possible. */ 47095fab37eSRobert Watson if (error1 == EINVAL || error2 == EINVAL) 47195fab37eSRobert Watson return (EINVAL); 47295fab37eSRobert Watson 47395fab37eSRobert Watson /* Precedence goes to "visibility", with both process and file. */ 47495fab37eSRobert Watson if (error1 == ESRCH || error2 == ESRCH) 47595fab37eSRobert Watson return (ESRCH); 47695fab37eSRobert Watson 47795fab37eSRobert Watson if (error1 == ENOENT || error2 == ENOENT) 47895fab37eSRobert Watson return (ENOENT); 47995fab37eSRobert Watson 48095fab37eSRobert Watson /* Precedence goes to DAC/MAC protections. */ 48195fab37eSRobert Watson if (error1 == EACCES || error2 == EACCES) 48295fab37eSRobert Watson return (EACCES); 48395fab37eSRobert Watson 48495fab37eSRobert Watson /* Precedence goes to privilege. */ 48595fab37eSRobert Watson if (error1 == EPERM || error2 == EPERM) 48695fab37eSRobert Watson return (EPERM); 48795fab37eSRobert Watson 48895fab37eSRobert Watson /* Precedence goes to error over success; otherwise, arbitrary. */ 48995fab37eSRobert Watson if (error1 != 0) 49095fab37eSRobert Watson return (error1); 49195fab37eSRobert Watson return (error2); 49295fab37eSRobert Watson } 49395fab37eSRobert Watson 4946fa0475dSRobert Watson void 49508bcdc58SRobert Watson mac_init_label(struct label *label) 49608bcdc58SRobert Watson { 49708bcdc58SRobert Watson 49808bcdc58SRobert Watson bzero(label, sizeof(*label)); 49908bcdc58SRobert Watson label->l_flags = MAC_FLAG_INITIALIZED; 50008bcdc58SRobert Watson } 50108bcdc58SRobert Watson 5026fa0475dSRobert Watson void 50308bcdc58SRobert Watson mac_destroy_label(struct label *label) 50408bcdc58SRobert Watson { 50508bcdc58SRobert Watson 50608bcdc58SRobert Watson KASSERT(label->l_flags & MAC_FLAG_INITIALIZED, 50708bcdc58SRobert Watson ("destroying uninitialized label")); 50808bcdc58SRobert Watson 50908bcdc58SRobert Watson bzero(label, sizeof(*label)); 51008bcdc58SRobert Watson /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */ 51108bcdc58SRobert Watson } 51208bcdc58SRobert Watson 5135e7ce478SRobert Watson int 514f7b951a8SRobert Watson mac_check_structmac_consistent(struct mac *mac) 515f7b951a8SRobert Watson { 516f7b951a8SRobert Watson 517cc7b13bfSRobert Watson if (mac->m_buflen < 0 || 518cc7b13bfSRobert Watson mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 519f7b951a8SRobert Watson return (EINVAL); 520f7b951a8SRobert Watson 521f7b951a8SRobert Watson return (0); 522f7b951a8SRobert Watson } 523f7b951a8SRobert Watson 524f7b951a8SRobert Watson int 525f7b951a8SRobert Watson __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 526f7b951a8SRobert Watson { 527f7b951a8SRobert Watson char *elements, *buffer; 528f7b951a8SRobert Watson struct mac mac; 529f7b951a8SRobert Watson struct proc *tproc; 530f7b951a8SRobert Watson struct ucred *tcred; 531f7b951a8SRobert Watson int error; 532f7b951a8SRobert Watson 533d1e405c5SAlfred Perlstein error = copyin(uap->mac_p, &mac, sizeof(mac)); 534f7b951a8SRobert Watson if (error) 535f7b951a8SRobert Watson return (error); 536f7b951a8SRobert Watson 537f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 538f7b951a8SRobert Watson if (error) 539f7b951a8SRobert Watson return (error); 540f7b951a8SRobert Watson 541f7b951a8SRobert Watson tproc = pfind(uap->pid); 542f7b951a8SRobert Watson if (tproc == NULL) 543f7b951a8SRobert Watson return (ESRCH); 544f7b951a8SRobert Watson 545f7b951a8SRobert Watson tcred = NULL; /* Satisfy gcc. */ 546f7b951a8SRobert Watson error = p_cansee(td, tproc); 547f7b951a8SRobert Watson if (error == 0) 548f7b951a8SRobert Watson tcred = crhold(tproc->p_ucred); 549f7b951a8SRobert Watson PROC_UNLOCK(tproc); 550f7b951a8SRobert Watson if (error) 551f7b951a8SRobert Watson return (error); 552f7b951a8SRobert Watson 553a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 554f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 555f7b951a8SRobert Watson if (error) { 556f7b951a8SRobert Watson free(elements, M_MACTEMP); 557f7b951a8SRobert Watson crfree(tcred); 558f7b951a8SRobert Watson return (error); 559f7b951a8SRobert Watson } 560f7b951a8SRobert Watson 561a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 562f7b951a8SRobert Watson error = mac_externalize_cred_label(&tcred->cr_label, elements, 563a163d034SWarner Losh buffer, mac.m_buflen, M_WAITOK); 564f7b951a8SRobert Watson if (error == 0) 565f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 566f7b951a8SRobert Watson 567f7b951a8SRobert Watson free(buffer, M_MACTEMP); 568f7b951a8SRobert Watson free(elements, M_MACTEMP); 569f7b951a8SRobert Watson crfree(tcred); 570f7b951a8SRobert Watson return (error); 571f7b951a8SRobert Watson } 572f7b951a8SRobert Watson 57395fab37eSRobert Watson /* 57495fab37eSRobert Watson * MPSAFE 57595fab37eSRobert Watson */ 57695fab37eSRobert Watson int 57795fab37eSRobert Watson __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 57895fab37eSRobert Watson { 579f7b951a8SRobert Watson char *elements, *buffer; 580f7b951a8SRobert Watson struct mac mac; 58195fab37eSRobert Watson int error; 58295fab37eSRobert Watson 583f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 584f7b951a8SRobert Watson if (error) 585f7b951a8SRobert Watson return (error); 58695fab37eSRobert Watson 587f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 588f7b951a8SRobert Watson if (error) 589f7b951a8SRobert Watson return (error); 590f7b951a8SRobert Watson 591a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 592f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 593f7b951a8SRobert Watson if (error) { 594f7b951a8SRobert Watson free(elements, M_MACTEMP); 595f7b951a8SRobert Watson return (error); 596f7b951a8SRobert Watson } 597f7b951a8SRobert Watson 598a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 599f7b951a8SRobert Watson error = mac_externalize_cred_label(&td->td_ucred->cr_label, 600a163d034SWarner Losh elements, buffer, mac.m_buflen, M_WAITOK); 601f7b951a8SRobert Watson if (error == 0) 602f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 603f7b951a8SRobert Watson 604f7b951a8SRobert Watson free(buffer, M_MACTEMP); 605f7b951a8SRobert Watson free(elements, M_MACTEMP); 60695fab37eSRobert Watson return (error); 60795fab37eSRobert Watson } 60895fab37eSRobert Watson 60995fab37eSRobert Watson /* 61095fab37eSRobert Watson * MPSAFE 61195fab37eSRobert Watson */ 61295fab37eSRobert Watson int 61395fab37eSRobert Watson __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 61495fab37eSRobert Watson { 61595fab37eSRobert Watson struct ucred *newcred, *oldcred; 61695fab37eSRobert Watson struct label intlabel; 617f7b951a8SRobert Watson struct proc *p; 618f7b951a8SRobert Watson struct mac mac; 619f7b951a8SRobert Watson char *buffer; 62095fab37eSRobert Watson int error; 62195fab37eSRobert Watson 622f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 62395fab37eSRobert Watson if (error) 62495fab37eSRobert Watson return (error); 62595fab37eSRobert Watson 626f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 62795fab37eSRobert Watson if (error) 62895fab37eSRobert Watson return (error); 62995fab37eSRobert Watson 630a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 631f7b951a8SRobert Watson error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 632f7b951a8SRobert Watson if (error) { 633f7b951a8SRobert Watson free(buffer, M_MACTEMP); 634f7b951a8SRobert Watson return (error); 635f7b951a8SRobert Watson } 636f7b951a8SRobert Watson 637f7b951a8SRobert Watson mac_init_cred_label(&intlabel); 638f7b951a8SRobert Watson error = mac_internalize_cred_label(&intlabel, buffer); 639f7b951a8SRobert Watson free(buffer, M_MACTEMP); 640f7b951a8SRobert Watson if (error) { 641f7b951a8SRobert Watson mac_destroy_cred_label(&intlabel); 642f7b951a8SRobert Watson return (error); 643f7b951a8SRobert Watson } 644f7b951a8SRobert Watson 64595fab37eSRobert Watson newcred = crget(); 64695fab37eSRobert Watson 64795fab37eSRobert Watson p = td->td_proc; 64895fab37eSRobert Watson PROC_LOCK(p); 64995fab37eSRobert Watson oldcred = p->p_ucred; 65095fab37eSRobert Watson 65195fab37eSRobert Watson error = mac_check_cred_relabel(oldcred, &intlabel); 65295fab37eSRobert Watson if (error) { 65395fab37eSRobert Watson PROC_UNLOCK(p); 65495fab37eSRobert Watson crfree(newcred); 655f7b951a8SRobert Watson goto out; 65695fab37eSRobert Watson } 65795fab37eSRobert Watson 65895fab37eSRobert Watson setsugid(p); 65995fab37eSRobert Watson crcopy(newcred, oldcred); 66095fab37eSRobert Watson mac_relabel_cred(newcred, &intlabel); 66195fab37eSRobert Watson p->p_ucred = newcred; 662e5cb5e37SRobert Watson 663e5cb5e37SRobert Watson /* 664e5cb5e37SRobert Watson * Grab additional reference for use while revoking mmaps, prior 665e5cb5e37SRobert Watson * to releasing the proc lock and sharing the cred. 666e5cb5e37SRobert Watson */ 667e5cb5e37SRobert Watson crhold(newcred); 66895fab37eSRobert Watson PROC_UNLOCK(p); 669e5cb5e37SRobert Watson 670f7b951a8SRobert Watson if (mac_enforce_vm) { 67116140035SRobert Watson mtx_lock(&Giant); 672e5cb5e37SRobert Watson mac_cred_mmapped_drop_perms(td, newcred); 67316140035SRobert Watson mtx_unlock(&Giant); 674f7b951a8SRobert Watson } 675e5cb5e37SRobert Watson 676e5cb5e37SRobert Watson crfree(newcred); /* Free revocation reference. */ 67795fab37eSRobert Watson crfree(oldcred); 678f7b951a8SRobert Watson 679f7b951a8SRobert Watson out: 680f7b951a8SRobert Watson mac_destroy_cred_label(&intlabel); 681f7b951a8SRobert Watson return (error); 68295fab37eSRobert Watson } 68395fab37eSRobert Watson 68495fab37eSRobert Watson /* 68595fab37eSRobert Watson * MPSAFE 68695fab37eSRobert Watson */ 68795fab37eSRobert Watson int 68895fab37eSRobert Watson __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 68995fab37eSRobert Watson { 690f7b951a8SRobert Watson char *elements, *buffer; 691f7b951a8SRobert Watson struct label intlabel; 69295fab37eSRobert Watson struct file *fp; 693f7b951a8SRobert Watson struct mac mac; 69495fab37eSRobert Watson struct vnode *vp; 69595fab37eSRobert Watson struct pipe *pipe; 696f7b951a8SRobert Watson short label_type; 69795fab37eSRobert Watson int error; 69895fab37eSRobert Watson 699f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 700f7b951a8SRobert Watson if (error) 701f7b951a8SRobert Watson return (error); 70295fab37eSRobert Watson 703f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 704f7b951a8SRobert Watson if (error) 705f7b951a8SRobert Watson return (error); 706f7b951a8SRobert Watson 707a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 708f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 709f7b951a8SRobert Watson if (error) { 710f7b951a8SRobert Watson free(elements, M_MACTEMP); 711f7b951a8SRobert Watson return (error); 712f7b951a8SRobert Watson } 713f7b951a8SRobert Watson 714a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 715f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 716d1e405c5SAlfred Perlstein error = fget(td, uap->fd, &fp); 71795fab37eSRobert Watson if (error) 71895fab37eSRobert Watson goto out; 71995fab37eSRobert Watson 720f7b951a8SRobert Watson label_type = fp->f_type; 72195fab37eSRobert Watson switch (fp->f_type) { 72295fab37eSRobert Watson case DTYPE_FIFO: 72395fab37eSRobert Watson case DTYPE_VNODE: 7243b6d9652SPoul-Henning Kamp vp = fp->f_vnode; 72595fab37eSRobert Watson 726f7b951a8SRobert Watson mac_init_vnode_label(&intlabel); 727f7b951a8SRobert Watson 72895fab37eSRobert Watson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 729f7b951a8SRobert Watson mac_copy_vnode_label(&vp->v_label, &intlabel); 73095fab37eSRobert Watson VOP_UNLOCK(vp, 0, td); 731f7b951a8SRobert Watson 73295fab37eSRobert Watson break; 73395fab37eSRobert Watson case DTYPE_PIPE: 73448e3128bSMatthew Dillon pipe = fp->f_data; 735f7b951a8SRobert Watson 736f7b951a8SRobert Watson mac_init_pipe_label(&intlabel); 737f7b951a8SRobert Watson 738f7b951a8SRobert Watson PIPE_LOCK(pipe); 739f7b951a8SRobert Watson mac_copy_pipe_label(pipe->pipe_label, &intlabel); 740f7b951a8SRobert Watson PIPE_UNLOCK(pipe); 74195fab37eSRobert Watson break; 74295fab37eSRobert Watson default: 74395fab37eSRobert Watson error = EINVAL; 744f7b951a8SRobert Watson fdrop(fp, td); 745f7b951a8SRobert Watson goto out; 746f7b951a8SRobert Watson } 747f7b951a8SRobert Watson fdrop(fp, td); 748f7b951a8SRobert Watson 749f7b951a8SRobert Watson switch (label_type) { 750f7b951a8SRobert Watson case DTYPE_FIFO: 751f7b951a8SRobert Watson case DTYPE_VNODE: 752f7b951a8SRobert Watson if (error == 0) 753f7b951a8SRobert Watson error = mac_externalize_vnode_label(&intlabel, 754a163d034SWarner Losh elements, buffer, mac.m_buflen, M_WAITOK); 755f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 756f7b951a8SRobert Watson break; 757f7b951a8SRobert Watson case DTYPE_PIPE: 758f7b951a8SRobert Watson error = mac_externalize_pipe_label(&intlabel, elements, 759a163d034SWarner Losh buffer, mac.m_buflen, M_WAITOK); 760f7b951a8SRobert Watson mac_destroy_pipe_label(&intlabel); 761f7b951a8SRobert Watson break; 762f7b951a8SRobert Watson default: 763f7b951a8SRobert Watson panic("__mac_get_fd: corrupted label_type"); 76495fab37eSRobert Watson } 76595fab37eSRobert Watson 76695fab37eSRobert Watson if (error == 0) 767f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 76895fab37eSRobert Watson 76995fab37eSRobert Watson out: 770f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 771f7b951a8SRobert Watson free(buffer, M_MACTEMP); 772f7b951a8SRobert Watson free(elements, M_MACTEMP); 773f7b951a8SRobert Watson 77495fab37eSRobert Watson return (error); 77595fab37eSRobert Watson } 77695fab37eSRobert Watson 77795fab37eSRobert Watson /* 77895fab37eSRobert Watson * MPSAFE 77995fab37eSRobert Watson */ 78095fab37eSRobert Watson int 78195fab37eSRobert Watson __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 78295fab37eSRobert Watson { 783f7b951a8SRobert Watson char *elements, *buffer; 78495fab37eSRobert Watson struct nameidata nd; 785f7b951a8SRobert Watson struct label intlabel; 786f7b951a8SRobert Watson struct mac mac; 78795fab37eSRobert Watson int error; 78895fab37eSRobert Watson 789f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 790f7b951a8SRobert Watson if (error) 791f7b951a8SRobert Watson return (error); 792f7b951a8SRobert Watson 793f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 794f7b951a8SRobert Watson if (error) 795f7b951a8SRobert Watson return (error); 796f7b951a8SRobert Watson 797a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 798f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 799f7b951a8SRobert Watson if (error) { 800f7b951a8SRobert Watson free(elements, M_MACTEMP); 801f7b951a8SRobert Watson return (error); 802f7b951a8SRobert Watson } 803f7b951a8SRobert Watson 804a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 805f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 806f7b951a8SRobert Watson NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, 807f7b951a8SRobert Watson td); 80895fab37eSRobert Watson error = namei(&nd); 80995fab37eSRobert Watson if (error) 81095fab37eSRobert Watson goto out; 81195fab37eSRobert Watson 812f7b951a8SRobert Watson mac_init_vnode_label(&intlabel); 813f7b951a8SRobert Watson mac_copy_vnode_label(&nd.ni_vp->v_label, &intlabel); 814763bbd2fSRobert Watson error = mac_externalize_vnode_label(&intlabel, elements, buffer, 815a163d034SWarner Losh mac.m_buflen, M_WAITOK); 816f7b951a8SRobert Watson 81795fab37eSRobert Watson NDFREE(&nd, 0); 818f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 819f7b951a8SRobert Watson 820f7b951a8SRobert Watson if (error == 0) 821f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 822f7b951a8SRobert Watson 823f7b951a8SRobert Watson out: 824f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 825f7b951a8SRobert Watson 826f7b951a8SRobert Watson free(buffer, M_MACTEMP); 827f7b951a8SRobert Watson free(elements, M_MACTEMP); 828f7b951a8SRobert Watson 829f7b951a8SRobert Watson return (error); 830f7b951a8SRobert Watson } 831f7b951a8SRobert Watson 832f7b951a8SRobert Watson /* 833f7b951a8SRobert Watson * MPSAFE 834f7b951a8SRobert Watson */ 835f7b951a8SRobert Watson int 836f7b951a8SRobert Watson __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 837f7b951a8SRobert Watson { 838f7b951a8SRobert Watson char *elements, *buffer; 839f7b951a8SRobert Watson struct nameidata nd; 840f7b951a8SRobert Watson struct label intlabel; 841f7b951a8SRobert Watson struct mac mac; 842f7b951a8SRobert Watson int error; 843f7b951a8SRobert Watson 844f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 845f7b951a8SRobert Watson if (error) 846f7b951a8SRobert Watson return (error); 847f7b951a8SRobert Watson 848f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 849f7b951a8SRobert Watson if (error) 850f7b951a8SRobert Watson return (error); 851f7b951a8SRobert Watson 852a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 853f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 854f7b951a8SRobert Watson if (error) { 855f7b951a8SRobert Watson free(elements, M_MACTEMP); 856f7b951a8SRobert Watson return (error); 857f7b951a8SRobert Watson } 858f7b951a8SRobert Watson 859a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 860f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 861f7b951a8SRobert Watson NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, 862f7b951a8SRobert Watson td); 863f7b951a8SRobert Watson error = namei(&nd); 86495fab37eSRobert Watson if (error) 86595fab37eSRobert Watson goto out; 86695fab37eSRobert Watson 867f7b951a8SRobert Watson mac_init_vnode_label(&intlabel); 868f7b951a8SRobert Watson mac_copy_vnode_label(&nd.ni_vp->v_label, &intlabel); 869763bbd2fSRobert Watson error = mac_externalize_vnode_label(&intlabel, elements, buffer, 870a163d034SWarner Losh mac.m_buflen, M_WAITOK); 871f7b951a8SRobert Watson NDFREE(&nd, 0); 872f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 873f7b951a8SRobert Watson 874f7b951a8SRobert Watson if (error == 0) 875f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 87695fab37eSRobert Watson 87795fab37eSRobert Watson out: 878f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 879f7b951a8SRobert Watson 880f7b951a8SRobert Watson free(buffer, M_MACTEMP); 881f7b951a8SRobert Watson free(elements, M_MACTEMP); 882f7b951a8SRobert Watson 88395fab37eSRobert Watson return (error); 88495fab37eSRobert Watson } 88595fab37eSRobert Watson 88695fab37eSRobert Watson /* 88795fab37eSRobert Watson * MPSAFE 88895fab37eSRobert Watson */ 88995fab37eSRobert Watson int 89095fab37eSRobert Watson __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 89195fab37eSRobert Watson { 89295fab37eSRobert Watson struct label intlabel; 893f7b951a8SRobert Watson struct pipe *pipe; 894f7b951a8SRobert Watson struct file *fp; 89595fab37eSRobert Watson struct mount *mp; 89695fab37eSRobert Watson struct vnode *vp; 897f7b951a8SRobert Watson struct mac mac; 898f7b951a8SRobert Watson char *buffer; 89995fab37eSRobert Watson int error; 90095fab37eSRobert Watson 901f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 902f7b951a8SRobert Watson if (error) 903f7b951a8SRobert Watson return (error); 904f7b951a8SRobert Watson 905f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 906f7b951a8SRobert Watson if (error) 907f7b951a8SRobert Watson return (error); 908f7b951a8SRobert Watson 909a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 910f7b951a8SRobert Watson error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 911f7b951a8SRobert Watson if (error) { 912f7b951a8SRobert Watson free(buffer, M_MACTEMP); 913f7b951a8SRobert Watson return (error); 914f7b951a8SRobert Watson } 915f7b951a8SRobert Watson 916f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 917f7b951a8SRobert Watson 918d1e405c5SAlfred Perlstein error = fget(td, uap->fd, &fp); 91995fab37eSRobert Watson if (error) 920f7b951a8SRobert Watson goto out; 92195fab37eSRobert Watson 92295fab37eSRobert Watson switch (fp->f_type) { 92395fab37eSRobert Watson case DTYPE_FIFO: 92495fab37eSRobert Watson case DTYPE_VNODE: 925f7b951a8SRobert Watson mac_init_vnode_label(&intlabel); 926f7b951a8SRobert Watson error = mac_internalize_vnode_label(&intlabel, buffer); 927f7b951a8SRobert Watson if (error) { 928f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 929f7b951a8SRobert Watson break; 930f7b951a8SRobert Watson } 931f7b951a8SRobert Watson 9323b6d9652SPoul-Henning Kamp vp = fp->f_vnode; 93395fab37eSRobert Watson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 934f7b951a8SRobert Watson if (error != 0) { 935f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 93695fab37eSRobert Watson break; 937f7b951a8SRobert Watson } 93895fab37eSRobert Watson 93995fab37eSRobert Watson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 94095fab37eSRobert Watson error = vn_setlabel(vp, &intlabel, td->td_ucred); 94195fab37eSRobert Watson VOP_UNLOCK(vp, 0, td); 94295fab37eSRobert Watson vn_finished_write(mp); 943f7b951a8SRobert Watson 944f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 94595fab37eSRobert Watson break; 946f7b951a8SRobert Watson 94795fab37eSRobert Watson case DTYPE_PIPE: 948f7b951a8SRobert Watson mac_init_pipe_label(&intlabel); 949f7b951a8SRobert Watson error = mac_internalize_pipe_label(&intlabel, buffer); 950f7b951a8SRobert Watson if (error == 0) { 95148e3128bSMatthew Dillon pipe = fp->f_data; 9521aa37f53SRobert Watson PIPE_LOCK(pipe); 953f7b951a8SRobert Watson error = mac_pipe_label_set(td->td_ucred, pipe, 954f7b951a8SRobert Watson &intlabel); 9551aa37f53SRobert Watson PIPE_UNLOCK(pipe); 956f7b951a8SRobert Watson } 957f7b951a8SRobert Watson 958f7b951a8SRobert Watson mac_destroy_pipe_label(&intlabel); 95995fab37eSRobert Watson break; 960f7b951a8SRobert Watson 96195fab37eSRobert Watson default: 96295fab37eSRobert Watson error = EINVAL; 96395fab37eSRobert Watson } 96495fab37eSRobert Watson 96595fab37eSRobert Watson fdrop(fp, td); 966f7b951a8SRobert Watson out: 967f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 968f7b951a8SRobert Watson 969f7b951a8SRobert Watson free(buffer, M_MACTEMP); 970f7b951a8SRobert Watson 97195fab37eSRobert Watson return (error); 97295fab37eSRobert Watson } 97395fab37eSRobert Watson 97495fab37eSRobert Watson /* 97595fab37eSRobert Watson * MPSAFE 97695fab37eSRobert Watson */ 97795fab37eSRobert Watson int 97895fab37eSRobert Watson __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 97995fab37eSRobert Watson { 98095fab37eSRobert Watson struct label intlabel; 981f7b951a8SRobert Watson struct nameidata nd; 98295fab37eSRobert Watson struct mount *mp; 983f7b951a8SRobert Watson struct mac mac; 984f7b951a8SRobert Watson char *buffer; 98595fab37eSRobert Watson int error; 98695fab37eSRobert Watson 987f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 98895fab37eSRobert Watson if (error) 989f7b951a8SRobert Watson return (error); 99095fab37eSRobert Watson 991f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 99295fab37eSRobert Watson if (error) 993f7b951a8SRobert Watson return (error); 99495fab37eSRobert Watson 995a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 996f7b951a8SRobert Watson error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 997f7b951a8SRobert Watson if (error) { 998f7b951a8SRobert Watson free(buffer, M_MACTEMP); 99995fab37eSRobert Watson return (error); 100095fab37eSRobert Watson } 100195fab37eSRobert Watson 1002f7b951a8SRobert Watson mac_init_vnode_label(&intlabel); 1003f7b951a8SRobert Watson error = mac_internalize_vnode_label(&intlabel, buffer); 1004f7b951a8SRobert Watson free(buffer, M_MACTEMP); 1005f7b951a8SRobert Watson if (error) { 1006f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 1007f7b951a8SRobert Watson return (error); 1008f7b951a8SRobert Watson } 1009f7b951a8SRobert Watson 1010f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 1011f7b951a8SRobert Watson 1012f7b951a8SRobert Watson NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, 1013f7b951a8SRobert Watson td); 1014f7b951a8SRobert Watson error = namei(&nd); 1015f7b951a8SRobert Watson if (error == 0) { 1016f7b951a8SRobert Watson error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 1017f7b951a8SRobert Watson if (error == 0) 1018f7b951a8SRobert Watson error = vn_setlabel(nd.ni_vp, &intlabel, 1019f7b951a8SRobert Watson td->td_ucred); 1020f7b951a8SRobert Watson vn_finished_write(mp); 1021f7b951a8SRobert Watson } 1022f7b951a8SRobert Watson 1023f7b951a8SRobert Watson NDFREE(&nd, 0); 1024f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 1025f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 1026f7b951a8SRobert Watson 1027f7b951a8SRobert Watson return (error); 1028f7b951a8SRobert Watson } 1029f7b951a8SRobert Watson 1030f7b951a8SRobert Watson /* 1031f7b951a8SRobert Watson * MPSAFE 1032f7b951a8SRobert Watson */ 1033f7b951a8SRobert Watson int 1034f7b951a8SRobert Watson __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 1035f7b951a8SRobert Watson { 1036f7b951a8SRobert Watson struct label intlabel; 1037f7b951a8SRobert Watson struct nameidata nd; 1038f7b951a8SRobert Watson struct mount *mp; 1039f7b951a8SRobert Watson struct mac mac; 1040f7b951a8SRobert Watson char *buffer; 1041f7b951a8SRobert Watson int error; 1042f7b951a8SRobert Watson 1043f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 1044f7b951a8SRobert Watson if (error) 1045f7b951a8SRobert Watson return (error); 1046f7b951a8SRobert Watson 1047f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 1048f7b951a8SRobert Watson if (error) 1049f7b951a8SRobert Watson return (error); 1050f7b951a8SRobert Watson 1051a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 1052f7b951a8SRobert Watson error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 1053f7b951a8SRobert Watson if (error) { 1054f7b951a8SRobert Watson free(buffer, M_MACTEMP); 1055f7b951a8SRobert Watson return (error); 1056f7b951a8SRobert Watson } 1057f7b951a8SRobert Watson 1058f7b951a8SRobert Watson mac_init_vnode_label(&intlabel); 1059f7b951a8SRobert Watson error = mac_internalize_vnode_label(&intlabel, buffer); 1060f7b951a8SRobert Watson free(buffer, M_MACTEMP); 1061f7b951a8SRobert Watson if (error) { 1062f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 1063f7b951a8SRobert Watson return (error); 1064f7b951a8SRobert Watson } 1065f7b951a8SRobert Watson 1066f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 1067f7b951a8SRobert Watson 1068f7b951a8SRobert Watson NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, 1069f7b951a8SRobert Watson td); 1070f7b951a8SRobert Watson error = namei(&nd); 1071f7b951a8SRobert Watson if (error == 0) { 1072f7b951a8SRobert Watson error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 1073f7b951a8SRobert Watson if (error == 0) 1074f7b951a8SRobert Watson error = vn_setlabel(nd.ni_vp, &intlabel, 1075f7b951a8SRobert Watson td->td_ucred); 1076f7b951a8SRobert Watson vn_finished_write(mp); 1077f7b951a8SRobert Watson } 1078f7b951a8SRobert Watson 1079f7b951a8SRobert Watson NDFREE(&nd, 0); 1080f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 1081f7b951a8SRobert Watson mac_destroy_vnode_label(&intlabel); 1082f7b951a8SRobert Watson 1083f7b951a8SRobert Watson return (error); 1084f7b951a8SRobert Watson } 1085f7b951a8SRobert Watson 1086f7b951a8SRobert Watson /* 1087f7b951a8SRobert Watson * MPSAFE 1088f7b951a8SRobert Watson */ 108927f2eac7SRobert Watson int 109027f2eac7SRobert Watson mac_syscall(struct thread *td, struct mac_syscall_args *uap) 109127f2eac7SRobert Watson { 109227f2eac7SRobert Watson struct mac_policy_conf *mpc; 109327f2eac7SRobert Watson char target[MAC_MAX_POLICY_NAME]; 109441a17fe3SRobert Watson int entrycount, error; 109527f2eac7SRobert Watson 1096d1e405c5SAlfred Perlstein error = copyinstr(uap->policy, target, sizeof(target), NULL); 109727f2eac7SRobert Watson if (error) 109827f2eac7SRobert Watson return (error); 109927f2eac7SRobert Watson 110027f2eac7SRobert Watson error = ENOSYS; 1101a6a65b05SRobert Watson LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 110227f2eac7SRobert Watson if (strcmp(mpc->mpc_name, target) == 0 && 110327f2eac7SRobert Watson mpc->mpc_ops->mpo_syscall != NULL) { 110427f2eac7SRobert Watson error = mpc->mpc_ops->mpo_syscall(td, 1105d1e405c5SAlfred Perlstein uap->call, uap->arg); 110627f2eac7SRobert Watson goto out; 110727f2eac7SRobert Watson } 110827f2eac7SRobert Watson } 110927f2eac7SRobert Watson 111041a17fe3SRobert Watson if ((entrycount = mac_policy_list_conditional_busy()) != 0) { 111141a17fe3SRobert Watson LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 111241a17fe3SRobert Watson if (strcmp(mpc->mpc_name, target) == 0 && 111341a17fe3SRobert Watson mpc->mpc_ops->mpo_syscall != NULL) { 111441a17fe3SRobert Watson error = mpc->mpc_ops->mpo_syscall(td, 111541a17fe3SRobert Watson uap->call, uap->arg); 111641a17fe3SRobert Watson break; 111741a17fe3SRobert Watson } 111841a17fe3SRobert Watson } 111941a17fe3SRobert Watson mac_policy_list_unbusy(); 112041a17fe3SRobert Watson } 112127f2eac7SRobert Watson out: 112227f2eac7SRobert Watson return (error); 112327f2eac7SRobert Watson } 112427f2eac7SRobert Watson 112595fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 112695fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 112795fab37eSRobert Watson 112895fab37eSRobert Watson #else /* !MAC */ 11297bc82500SRobert Watson 11307bc82500SRobert Watson int 1131f7b951a8SRobert Watson __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 1132f7b951a8SRobert Watson { 1133f7b951a8SRobert Watson 1134f7b951a8SRobert Watson return (ENOSYS); 1135f7b951a8SRobert Watson } 1136f7b951a8SRobert Watson 1137f7b951a8SRobert Watson int 11387bc82500SRobert Watson __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 11397bc82500SRobert Watson { 11407bc82500SRobert Watson 11417bc82500SRobert Watson return (ENOSYS); 11427bc82500SRobert Watson } 11437bc82500SRobert Watson 11447bc82500SRobert Watson int 11457bc82500SRobert Watson __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 11467bc82500SRobert Watson { 11477bc82500SRobert Watson 11487bc82500SRobert Watson return (ENOSYS); 11497bc82500SRobert Watson } 11507bc82500SRobert Watson 11517bc82500SRobert Watson int 11527bc82500SRobert Watson __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 11537bc82500SRobert Watson { 11547bc82500SRobert Watson 11557bc82500SRobert Watson return (ENOSYS); 11567bc82500SRobert Watson } 11577bc82500SRobert Watson 11587bc82500SRobert Watson int 11597bc82500SRobert Watson __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 11607bc82500SRobert Watson { 11617bc82500SRobert Watson 11627bc82500SRobert Watson return (ENOSYS); 11637bc82500SRobert Watson } 11647bc82500SRobert Watson 11657bc82500SRobert Watson int 1166f7b951a8SRobert Watson __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 1167f7b951a8SRobert Watson { 1168f7b951a8SRobert Watson 1169f7b951a8SRobert Watson return (ENOSYS); 1170f7b951a8SRobert Watson } 1171f7b951a8SRobert Watson 1172f7b951a8SRobert Watson int 11737bc82500SRobert Watson __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 11747bc82500SRobert Watson { 11757bc82500SRobert Watson 11767bc82500SRobert Watson return (ENOSYS); 11777bc82500SRobert Watson } 11787bc82500SRobert Watson 11797bc82500SRobert Watson int 11807bc82500SRobert Watson __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 11817bc82500SRobert Watson { 11827bc82500SRobert Watson 11837bc82500SRobert Watson return (ENOSYS); 11847bc82500SRobert Watson } 118595fab37eSRobert Watson 118627f2eac7SRobert Watson int 1187f7b951a8SRobert Watson __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 1188f7b951a8SRobert Watson { 1189f7b951a8SRobert Watson 1190f7b951a8SRobert Watson return (ENOSYS); 1191f7b951a8SRobert Watson } 1192f7b951a8SRobert Watson 1193f7b951a8SRobert Watson int 119427f2eac7SRobert Watson mac_syscall(struct thread *td, struct mac_syscall_args *uap) 119527f2eac7SRobert Watson { 119627f2eac7SRobert Watson 119727f2eac7SRobert Watson return (ENOSYS); 119827f2eac7SRobert Watson } 119927f2eac7SRobert Watson 1200f7b951a8SRobert Watson #endif 1201