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 37c8e7bf92SRobert Watson /*- 38c8e7bf92SRobert Watson * Framework for extensible kernel access control. This file contains 39c8e7bf92SRobert Watson * Kernel and userland interface to the framework, policy registration 40c8e7bf92SRobert Watson * and composition. Per-object interfaces, controls, and labeling may be 41c8e7bf92SRobert Watson * found in src/sys/mac/. Sample policies may be found in src/sys/mac*. 427bc82500SRobert Watson */ 437bc82500SRobert Watson 44677b542eSDavid E. O'Brien #include <sys/cdefs.h> 45677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$"); 46677b542eSDavid E. O'Brien 477bc82500SRobert Watson #include "opt_mac.h" 48328048bcSPoul-Henning Kamp #include "opt_devfs.h" 49f9d0d524SRobert Watson 507bc82500SRobert Watson #include <sys/param.h> 51a96acd1aSRobert Watson #include <sys/condvar.h> 5295fab37eSRobert Watson #include <sys/extattr.h> 53670cb89bSRobert Watson #include <sys/imgact.h> 5495fab37eSRobert Watson #include <sys/kernel.h> 5595fab37eSRobert Watson #include <sys/lock.h> 56b656366bSBruce Evans #include <sys/malloc.h> 5795fab37eSRobert Watson #include <sys/mutex.h> 5895fab37eSRobert Watson #include <sys/mac.h> 597ba28492SRobert Watson #include <sys/module.h> 6095fab37eSRobert Watson #include <sys/proc.h> 61f51e5803SRobert Watson #include <sys/sbuf.h> 6295fab37eSRobert Watson #include <sys/systm.h> 637bc82500SRobert Watson #include <sys/sysproto.h> 647bc82500SRobert Watson #include <sys/sysent.h> 6595fab37eSRobert Watson #include <sys/vnode.h> 6695fab37eSRobert Watson #include <sys/mount.h> 6795fab37eSRobert Watson #include <sys/file.h> 6895fab37eSRobert Watson #include <sys/namei.h> 6995fab37eSRobert Watson #include <sys/socket.h> 7095fab37eSRobert Watson #include <sys/pipe.h> 7195fab37eSRobert Watson #include <sys/socketvar.h> 7295fab37eSRobert Watson #include <sys/sysctl.h> 7395fab37eSRobert Watson 7495fab37eSRobert Watson #include <vm/vm.h> 7595fab37eSRobert Watson #include <vm/pmap.h> 7695fab37eSRobert Watson #include <vm/vm_map.h> 7795fab37eSRobert Watson #include <vm/vm_object.h> 7895fab37eSRobert Watson 7995fab37eSRobert Watson #include <sys/mac_policy.h> 8095fab37eSRobert Watson 8195fab37eSRobert Watson #include <fs/devfs/devfs.h> 8295fab37eSRobert Watson 8395fab37eSRobert Watson #include <net/bpfdesc.h> 8495fab37eSRobert Watson #include <net/if.h> 8595fab37eSRobert Watson #include <net/if_var.h> 8695fab37eSRobert Watson 8795fab37eSRobert Watson #include <netinet/in.h> 8895fab37eSRobert Watson #include <netinet/ip_var.h> 8995fab37eSRobert Watson 906fa0475dSRobert Watson #include <security/mac/mac_internal.h> 916fa0475dSRobert Watson 9295fab37eSRobert Watson #ifdef MAC 9395fab37eSRobert Watson 947ba28492SRobert Watson /* 957ba28492SRobert Watson * Declare that the kernel provides MAC support, version 1. This permits 967ba28492SRobert Watson * modules to refuse to be loaded if the necessary support isn't present, 977ba28492SRobert Watson * even if it's pre-boot. 987ba28492SRobert Watson */ 997ba28492SRobert Watson MODULE_VERSION(kernel_mac_support, 1); 1007ba28492SRobert Watson 10195fab37eSRobert Watson SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0, 10295fab37eSRobert Watson "TrustedBSD MAC policy controls"); 103b2f0927aSRobert Watson 104b2aef571SRobert Watson #if MAC_MAX_SLOTS > 32 105b2aef571SRobert Watson #error "MAC_MAX_SLOTS too large" 10695fab37eSRobert Watson #endif 107a13c67daSRobert Watson 108b2aef571SRobert Watson static unsigned int mac_max_slots = MAC_MAX_SLOTS; 109b2aef571SRobert Watson static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1; 110b2aef571SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD, 111b2aef571SRobert Watson &mac_max_slots, 0, ""); 11295fab37eSRobert Watson 113a67fe518SRobert Watson /* 114a67fe518SRobert Watson * Has the kernel started generating labeled objects yet? All read/write 115a67fe518SRobert Watson * access to this variable is serialized during the boot process. Following 116a67fe518SRobert Watson * the end of serialization, we don't update this flag; no locking. 117a67fe518SRobert Watson */ 118089c1bdaSRobert Watson int mac_late = 0; 119763bbd2fSRobert Watson 120225bff6fSRobert Watson /* 121225bff6fSRobert Watson * Flag to indicate whether or not we should allocate label storage for 122225bff6fSRobert Watson * new mbufs. Since most dynamic policies we currently work with don't 123225bff6fSRobert Watson * rely on mbuf labeling, try to avoid paying the cost of mtag allocation 124225bff6fSRobert Watson * unless specifically notified of interest. One result of this is 125225bff6fSRobert Watson * that if a dynamically loaded policy requests mbuf labels, it must 126225bff6fSRobert Watson * be able to deal with a NULL label being returned on any mbufs that 127225bff6fSRobert Watson * were already in flight when the policy was loaded. Since the policy 128225bff6fSRobert Watson * already has to deal with uninitialized labels, this probably won't 129225bff6fSRobert Watson * be a problem. Note: currently no locking. Will this be a problem? 130225bff6fSRobert Watson */ 13119c3e120SRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF 132089c1bdaSRobert Watson int mac_labelmbufs = 0; 133225bff6fSRobert Watson #endif 134225bff6fSRobert Watson 135f050add5SRobert Watson #ifdef MAC_DEBUG 1366be0c25eSRobert Watson SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0, 1376be0c25eSRobert Watson "TrustedBSD MAC debug info"); 138b2f0927aSRobert Watson SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0, 139b2f0927aSRobert Watson "TrustedBSD MAC object counters"); 140b2f0927aSRobert Watson 1416fa0475dSRobert Watson static unsigned int nmactemp; 142b2f0927aSRobert Watson SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD, 14395fab37eSRobert Watson &nmactemp, 0, "number of temporary labels in use"); 144f050add5SRobert Watson #endif 14595fab37eSRobert Watson 14695fab37eSRobert Watson static int mac_policy_register(struct mac_policy_conf *mpc); 14795fab37eSRobert Watson static int mac_policy_unregister(struct mac_policy_conf *mpc); 14895fab37eSRobert Watson 149f7b951a8SRobert Watson MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage"); 15095fab37eSRobert Watson 15195fab37eSRobert Watson /* 15241a17fe3SRobert Watson * mac_static_policy_list holds a list of policy modules that are not 15341a17fe3SRobert Watson * loaded while the system is "live", and cannot be unloaded. These 15441a17fe3SRobert Watson * policies can be invoked without holding the busy count. 15541a17fe3SRobert Watson * 15641a17fe3SRobert Watson * mac_policy_list stores the list of dynamic policies. A busy count is 157a96acd1aSRobert Watson * maintained for the list, stored in mac_policy_busy. The busy count 15841a17fe3SRobert Watson * is protected by mac_policy_mtx; the list may be modified only 159a96acd1aSRobert Watson * while the busy count is 0, requiring that the lock be held to 160a96acd1aSRobert Watson * prevent new references to the list from being acquired. For almost 161a96acd1aSRobert Watson * all operations, incrementing the busy count is sufficient to 162a96acd1aSRobert Watson * guarantee consistency, as the list cannot be modified while the 163a96acd1aSRobert Watson * busy count is elevated. For a few special operations involving a 16441a17fe3SRobert Watson * change to the list of active policies, the mtx itself must be held. 16541a17fe3SRobert Watson * A condition variable, mac_policy_cv, is used to signal potential 16641a17fe3SRobert Watson * exclusive consumers that they should try to acquire the lock if a 16741a17fe3SRobert Watson * first attempt at exclusive access fails. 16895fab37eSRobert Watson */ 16941a17fe3SRobert Watson static struct mtx mac_policy_mtx; 17041a17fe3SRobert Watson static struct cv mac_policy_cv; 17141a17fe3SRobert Watson static int mac_policy_count; 172089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list; 173089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list; 174a96acd1aSRobert Watson 175a96acd1aSRobert Watson /* 17626306795SJohn Baldwin * We manually invoke WITNESS_WARN() to allow Witness to generate 177a96acd1aSRobert Watson * warnings even if we don't end up ever triggering the wait at 178a96acd1aSRobert Watson * run-time. The consumer of the exclusive interface must not hold 179a96acd1aSRobert Watson * any locks (other than potentially Giant) since we may sleep for 180a96acd1aSRobert Watson * long (potentially indefinite) periods of time waiting for the 181a96acd1aSRobert Watson * framework to become quiescent so that a policy list change may 182a96acd1aSRobert Watson * be made. 183a96acd1aSRobert Watson */ 184089c1bdaSRobert Watson void 18541a17fe3SRobert Watson mac_policy_grab_exclusive(void) 18641a17fe3SRobert Watson { 187c8e7bf92SRobert Watson 18841a17fe3SRobert Watson WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL, 18941a17fe3SRobert Watson "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__); 19041a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 19141a17fe3SRobert Watson while (mac_policy_count != 0) 19241a17fe3SRobert Watson cv_wait(&mac_policy_cv, &mac_policy_mtx); 19341a17fe3SRobert Watson } 19495fab37eSRobert Watson 195089c1bdaSRobert Watson void 19641a17fe3SRobert Watson mac_policy_assert_exclusive(void) 19741a17fe3SRobert Watson { 198c8e7bf92SRobert Watson 19941a17fe3SRobert Watson mtx_assert(&mac_policy_mtx, MA_OWNED); 20041a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 20141a17fe3SRobert Watson ("mac_policy_assert_exclusive(): not exclusive")); 20241a17fe3SRobert Watson } 203225bff6fSRobert Watson 204089c1bdaSRobert Watson void 20541a17fe3SRobert Watson mac_policy_release_exclusive(void) 20641a17fe3SRobert Watson { 20795fab37eSRobert Watson 20841a17fe3SRobert Watson KASSERT(mac_policy_count == 0, 20941a17fe3SRobert Watson ("mac_policy_release_exclusive(): not exclusive")); 21041a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 21141a17fe3SRobert Watson cv_signal(&mac_policy_cv); 21241a17fe3SRobert Watson } 21341a17fe3SRobert Watson 214089c1bdaSRobert Watson void 21541a17fe3SRobert Watson mac_policy_list_busy(void) 21641a17fe3SRobert Watson { 217c8e7bf92SRobert Watson 21841a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 21941a17fe3SRobert Watson mac_policy_count++; 22041a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 22141a17fe3SRobert Watson } 22241a17fe3SRobert Watson 223089c1bdaSRobert Watson int 22441a17fe3SRobert Watson mac_policy_list_conditional_busy(void) 22541a17fe3SRobert Watson { 22641a17fe3SRobert Watson int ret; 22741a17fe3SRobert Watson 22841a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 22941a17fe3SRobert Watson if (!LIST_EMPTY(&mac_policy_list)) { 23041a17fe3SRobert Watson mac_policy_count++; 23141a17fe3SRobert Watson ret = 1; 23241a17fe3SRobert Watson } else 23341a17fe3SRobert Watson ret = 0; 23441a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 23541a17fe3SRobert Watson return (ret); 23641a17fe3SRobert Watson } 23741a17fe3SRobert Watson 238089c1bdaSRobert Watson void 23941a17fe3SRobert Watson mac_policy_list_unbusy(void) 24041a17fe3SRobert Watson { 241c8e7bf92SRobert Watson 24241a17fe3SRobert Watson mtx_lock(&mac_policy_mtx); 24341a17fe3SRobert Watson mac_policy_count--; 24441a17fe3SRobert Watson KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK")); 24541a17fe3SRobert Watson if (mac_policy_count == 0) 24641a17fe3SRobert Watson cv_signal(&mac_policy_cv); 24741a17fe3SRobert Watson mtx_unlock(&mac_policy_mtx); 24841a17fe3SRobert Watson } 24995fab37eSRobert Watson 25095fab37eSRobert Watson /* 25195fab37eSRobert Watson * Initialize the MAC subsystem, including appropriate SMP locks. 25295fab37eSRobert Watson */ 25395fab37eSRobert Watson static void 25495fab37eSRobert Watson mac_init(void) 25595fab37eSRobert Watson { 25695fab37eSRobert Watson 25741a17fe3SRobert Watson LIST_INIT(&mac_static_policy_list); 25895fab37eSRobert Watson LIST_INIT(&mac_policy_list); 259eca8a663SRobert Watson mac_labelzone_init(); 26041a17fe3SRobert Watson 26141a17fe3SRobert Watson mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF); 26241a17fe3SRobert Watson cv_init(&mac_policy_cv, "mac_policy_cv"); 26395fab37eSRobert Watson } 26495fab37eSRobert Watson 26595fab37eSRobert Watson /* 26695fab37eSRobert Watson * For the purposes of modules that want to know if they were loaded 26795fab37eSRobert Watson * "early", set the mac_late flag once we've processed modules either 26895fab37eSRobert Watson * linked into the kernel, or loaded before the kernel startup. 26995fab37eSRobert Watson */ 27095fab37eSRobert Watson static void 27195fab37eSRobert Watson mac_late_init(void) 27295fab37eSRobert Watson { 27395fab37eSRobert Watson 27495fab37eSRobert Watson mac_late = 1; 27595fab37eSRobert Watson } 27695fab37eSRobert Watson 27795fab37eSRobert Watson /* 278225bff6fSRobert Watson * After the policy list has changed, walk the list to update any global 27919c3e120SRobert Watson * flags. Currently, we support only one flag, and it's conditionally 28019c3e120SRobert Watson * defined; as a result, the entire function is conditional. Eventually, 28119c3e120SRobert Watson * the #else case might also iterate across the policies. 282225bff6fSRobert Watson */ 283225bff6fSRobert Watson static void 284225bff6fSRobert Watson mac_policy_updateflags(void) 285225bff6fSRobert Watson { 286225bff6fSRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF 28719c3e120SRobert Watson struct mac_policy_conf *tmpc; 288225bff6fSRobert Watson int labelmbufs; 289225bff6fSRobert Watson 29041a17fe3SRobert Watson mac_policy_assert_exclusive(); 291225bff6fSRobert Watson 292225bff6fSRobert Watson labelmbufs = 0; 29341a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 29441a17fe3SRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 29541a17fe3SRobert Watson labelmbufs++; 29641a17fe3SRobert Watson } 297225bff6fSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 298225bff6fSRobert Watson if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS) 299225bff6fSRobert Watson labelmbufs++; 300225bff6fSRobert Watson } 301225bff6fSRobert Watson mac_labelmbufs = (labelmbufs != 0); 302225bff6fSRobert Watson #endif 303225bff6fSRobert Watson } 304225bff6fSRobert Watson 305225bff6fSRobert Watson /* 30695fab37eSRobert Watson * Allow MAC policy modules to register during boot, etc. 30795fab37eSRobert Watson */ 30895fab37eSRobert Watson int 30995fab37eSRobert Watson mac_policy_modevent(module_t mod, int type, void *data) 31095fab37eSRobert Watson { 31195fab37eSRobert Watson struct mac_policy_conf *mpc; 31295fab37eSRobert Watson int error; 31395fab37eSRobert Watson 31495fab37eSRobert Watson error = 0; 31595fab37eSRobert Watson mpc = (struct mac_policy_conf *) data; 31695fab37eSRobert Watson 31795fab37eSRobert Watson switch (type) { 31895fab37eSRobert Watson case MOD_LOAD: 31995fab37eSRobert Watson if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE && 32095fab37eSRobert Watson mac_late) { 32195fab37eSRobert Watson printf("mac_policy_modevent: can't load %s policy " 32295fab37eSRobert Watson "after booting\n", mpc->mpc_name); 32395fab37eSRobert Watson error = EBUSY; 32495fab37eSRobert Watson break; 32595fab37eSRobert Watson } 32695fab37eSRobert Watson error = mac_policy_register(mpc); 32795fab37eSRobert Watson break; 32895fab37eSRobert Watson case MOD_UNLOAD: 32995fab37eSRobert Watson /* Don't unregister the module if it was never registered. */ 33095fab37eSRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) 33195fab37eSRobert Watson != 0) 33295fab37eSRobert Watson error = mac_policy_unregister(mpc); 33395fab37eSRobert Watson else 33495fab37eSRobert Watson error = 0; 33595fab37eSRobert Watson break; 33695fab37eSRobert Watson default: 33795fab37eSRobert Watson break; 33895fab37eSRobert Watson } 33995fab37eSRobert Watson 34095fab37eSRobert Watson return (error); 34195fab37eSRobert Watson } 34295fab37eSRobert Watson 34395fab37eSRobert Watson static int 34495fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc) 34595fab37eSRobert Watson { 34695fab37eSRobert Watson struct mac_policy_conf *tmpc; 34741a17fe3SRobert Watson int error, slot, static_entry; 34895fab37eSRobert Watson 34941a17fe3SRobert Watson error = 0; 35041a17fe3SRobert Watson 35141a17fe3SRobert Watson /* 35241a17fe3SRobert Watson * We don't technically need exclusive access while !mac_late, 35341a17fe3SRobert Watson * but hold it for assertion consistency. 35441a17fe3SRobert Watson */ 35541a17fe3SRobert Watson mac_policy_grab_exclusive(); 35641a17fe3SRobert Watson 35741a17fe3SRobert Watson /* 35841a17fe3SRobert Watson * If the module can potentially be unloaded, or we're loading 35941a17fe3SRobert Watson * late, we have to stick it in the non-static list and pay 36041a17fe3SRobert Watson * an extra performance overhead. Otherwise, we can pay a 36141a17fe3SRobert Watson * light locking cost and stick it in the static list. 36241a17fe3SRobert Watson */ 36341a17fe3SRobert Watson static_entry = (!mac_late && 36441a17fe3SRobert Watson !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK)); 36541a17fe3SRobert Watson 36641a17fe3SRobert Watson if (static_entry) { 36741a17fe3SRobert Watson LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) { 36841a17fe3SRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 36941a17fe3SRobert Watson error = EEXIST; 37041a17fe3SRobert Watson goto out; 37141a17fe3SRobert Watson } 37241a17fe3SRobert Watson } 37341a17fe3SRobert Watson } else { 37495fab37eSRobert Watson LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) { 37595fab37eSRobert Watson if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) { 37641a17fe3SRobert Watson error = EEXIST; 37741a17fe3SRobert Watson goto out; 37841a17fe3SRobert Watson } 37995fab37eSRobert Watson } 38095fab37eSRobert Watson } 38195fab37eSRobert Watson if (mpc->mpc_field_off != NULL) { 382b2aef571SRobert Watson slot = ffs(mac_slot_offsets_free); 38395fab37eSRobert Watson if (slot == 0) { 38441a17fe3SRobert Watson error = ENOMEM; 38541a17fe3SRobert Watson goto out; 38695fab37eSRobert Watson } 38795fab37eSRobert Watson slot--; 388b2aef571SRobert Watson mac_slot_offsets_free &= ~(1 << slot); 38995fab37eSRobert Watson *mpc->mpc_field_off = slot; 39095fab37eSRobert Watson } 39195fab37eSRobert Watson mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED; 39241a17fe3SRobert Watson 39341a17fe3SRobert Watson /* 39441a17fe3SRobert Watson * If we're loading a MAC module after the framework has 39541a17fe3SRobert Watson * initialized, it has to go into the dynamic list. If 39641a17fe3SRobert Watson * we're loading it before we've finished initializing, 39741a17fe3SRobert Watson * it can go into the static list with weaker locker 39841a17fe3SRobert Watson * requirements. 39941a17fe3SRobert Watson */ 40041a17fe3SRobert Watson if (static_entry) 40141a17fe3SRobert Watson LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list); 40241a17fe3SRobert Watson else 40395fab37eSRobert Watson LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list); 40495fab37eSRobert Watson 40595fab37eSRobert Watson /* Per-policy initialization. */ 40695fab37eSRobert Watson if (mpc->mpc_ops->mpo_init != NULL) 40795fab37eSRobert Watson (*(mpc->mpc_ops->mpo_init))(mpc); 408225bff6fSRobert Watson mac_policy_updateflags(); 40995fab37eSRobert Watson 41095fab37eSRobert Watson printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname, 41195fab37eSRobert Watson mpc->mpc_name); 41295fab37eSRobert Watson 41341a17fe3SRobert Watson out: 41441a17fe3SRobert Watson mac_policy_release_exclusive(); 41541a17fe3SRobert Watson return (error); 41695fab37eSRobert Watson } 41795fab37eSRobert Watson 41895fab37eSRobert Watson static int 41995fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc) 42095fab37eSRobert Watson { 42195fab37eSRobert Watson 422ea599aa0SRobert Watson /* 423ea599aa0SRobert Watson * If we fail the load, we may get a request to unload. Check 424ea599aa0SRobert Watson * to see if we did the run-time registration, and if not, 425ea599aa0SRobert Watson * silently succeed. 426ea599aa0SRobert Watson */ 42741a17fe3SRobert Watson mac_policy_grab_exclusive(); 428ea599aa0SRobert Watson if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) { 42941a17fe3SRobert Watson mac_policy_release_exclusive(); 430ea599aa0SRobert Watson return (0); 431ea599aa0SRobert Watson } 43295fab37eSRobert Watson #if 0 43395fab37eSRobert Watson /* 43495fab37eSRobert Watson * Don't allow unloading modules with private data. 43595fab37eSRobert Watson */ 436ea599aa0SRobert Watson if (mpc->mpc_field_off != NULL) { 437ea599aa0SRobert Watson MAC_POLICY_LIST_UNLOCK(); 43895fab37eSRobert Watson return (EBUSY); 439ea599aa0SRobert Watson } 44095fab37eSRobert Watson #endif 441ea599aa0SRobert Watson /* 442ea599aa0SRobert Watson * Only allow the unload to proceed if the module is unloadable 443ea599aa0SRobert Watson * by its own definition. 444ea599aa0SRobert Watson */ 445ea599aa0SRobert Watson if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) { 44641a17fe3SRobert Watson mac_policy_release_exclusive(); 44795fab37eSRobert Watson return (EBUSY); 448ea599aa0SRobert Watson } 44995fab37eSRobert Watson if (mpc->mpc_ops->mpo_destroy != NULL) 45095fab37eSRobert Watson (*(mpc->mpc_ops->mpo_destroy))(mpc); 45195fab37eSRobert Watson 45295fab37eSRobert Watson LIST_REMOVE(mpc, mpc_list); 4539aeffb2bSRobert Watson mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED; 454225bff6fSRobert Watson mac_policy_updateflags(); 45541a17fe3SRobert Watson 45641a17fe3SRobert Watson mac_policy_release_exclusive(); 457a96acd1aSRobert Watson 45895fab37eSRobert Watson printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname, 45995fab37eSRobert Watson mpc->mpc_name); 46095fab37eSRobert Watson 46195fab37eSRobert Watson return (0); 46295fab37eSRobert Watson } 46395fab37eSRobert Watson 46495fab37eSRobert Watson /* 46595fab37eSRobert Watson * Define an error value precedence, and given two arguments, selects the 46695fab37eSRobert Watson * value with the higher precedence. 46795fab37eSRobert Watson */ 4689e7bf51cSRobert Watson int 4699e7bf51cSRobert Watson mac_error_select(int error1, int error2) 47095fab37eSRobert Watson { 47195fab37eSRobert Watson 47295fab37eSRobert Watson /* Certain decision-making errors take top priority. */ 47395fab37eSRobert Watson if (error1 == EDEADLK || error2 == EDEADLK) 47495fab37eSRobert Watson return (EDEADLK); 47595fab37eSRobert Watson 47695fab37eSRobert Watson /* Invalid arguments should be reported where possible. */ 47795fab37eSRobert Watson if (error1 == EINVAL || error2 == EINVAL) 47895fab37eSRobert Watson return (EINVAL); 47995fab37eSRobert Watson 48095fab37eSRobert Watson /* Precedence goes to "visibility", with both process and file. */ 48195fab37eSRobert Watson if (error1 == ESRCH || error2 == ESRCH) 48295fab37eSRobert Watson return (ESRCH); 48395fab37eSRobert Watson 48495fab37eSRobert Watson if (error1 == ENOENT || error2 == ENOENT) 48595fab37eSRobert Watson return (ENOENT); 48695fab37eSRobert Watson 48795fab37eSRobert Watson /* Precedence goes to DAC/MAC protections. */ 48895fab37eSRobert Watson if (error1 == EACCES || error2 == EACCES) 48995fab37eSRobert Watson return (EACCES); 49095fab37eSRobert Watson 49195fab37eSRobert Watson /* Precedence goes to privilege. */ 49295fab37eSRobert Watson if (error1 == EPERM || error2 == EPERM) 49395fab37eSRobert Watson return (EPERM); 49495fab37eSRobert Watson 49595fab37eSRobert Watson /* Precedence goes to error over success; otherwise, arbitrary. */ 49695fab37eSRobert Watson if (error1 != 0) 49795fab37eSRobert Watson return (error1); 49895fab37eSRobert Watson return (error2); 49995fab37eSRobert Watson } 50095fab37eSRobert Watson 5016fa0475dSRobert Watson void 50208bcdc58SRobert Watson mac_init_label(struct label *label) 50308bcdc58SRobert Watson { 50408bcdc58SRobert Watson 50508bcdc58SRobert Watson bzero(label, sizeof(*label)); 50608bcdc58SRobert Watson label->l_flags = MAC_FLAG_INITIALIZED; 50708bcdc58SRobert Watson } 50808bcdc58SRobert Watson 5096fa0475dSRobert Watson void 51008bcdc58SRobert Watson mac_destroy_label(struct label *label) 51108bcdc58SRobert Watson { 51208bcdc58SRobert Watson 51308bcdc58SRobert Watson KASSERT(label->l_flags & MAC_FLAG_INITIALIZED, 51408bcdc58SRobert Watson ("destroying uninitialized label")); 51508bcdc58SRobert Watson 51608bcdc58SRobert Watson bzero(label, sizeof(*label)); 51708bcdc58SRobert Watson /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */ 51808bcdc58SRobert Watson } 51908bcdc58SRobert Watson 5205e7ce478SRobert Watson int 521f7b951a8SRobert Watson mac_check_structmac_consistent(struct mac *mac) 522f7b951a8SRobert Watson { 523f7b951a8SRobert Watson 524cc7b13bfSRobert Watson if (mac->m_buflen < 0 || 525cc7b13bfSRobert Watson mac->m_buflen > MAC_MAX_LABEL_BUF_LEN) 526f7b951a8SRobert Watson return (EINVAL); 527f7b951a8SRobert Watson 528f7b951a8SRobert Watson return (0); 529f7b951a8SRobert Watson } 530f7b951a8SRobert Watson 531f0ab0442SRobert Watson /* 532f0ab0442SRobert Watson * MPSAFE 533f0ab0442SRobert Watson */ 534f7b951a8SRobert Watson int 535f7b951a8SRobert Watson __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 536f7b951a8SRobert Watson { 537f7b951a8SRobert Watson char *elements, *buffer; 538f7b951a8SRobert Watson struct mac mac; 539f7b951a8SRobert Watson struct proc *tproc; 540f7b951a8SRobert Watson struct ucred *tcred; 541f7b951a8SRobert Watson int error; 542f7b951a8SRobert Watson 543d1e405c5SAlfred Perlstein error = copyin(uap->mac_p, &mac, sizeof(mac)); 544f7b951a8SRobert Watson if (error) 545f7b951a8SRobert Watson return (error); 546f7b951a8SRobert Watson 547f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 548f7b951a8SRobert Watson if (error) 549f7b951a8SRobert Watson return (error); 550f7b951a8SRobert Watson 551f7b951a8SRobert Watson tproc = pfind(uap->pid); 552f7b951a8SRobert Watson if (tproc == NULL) 553f7b951a8SRobert Watson return (ESRCH); 554f7b951a8SRobert Watson 555f7b951a8SRobert Watson tcred = NULL; /* Satisfy gcc. */ 556f7b951a8SRobert Watson error = p_cansee(td, tproc); 557f7b951a8SRobert Watson if (error == 0) 558f7b951a8SRobert Watson tcred = crhold(tproc->p_ucred); 559f7b951a8SRobert Watson PROC_UNLOCK(tproc); 560f7b951a8SRobert Watson if (error) 561f7b951a8SRobert Watson return (error); 562f7b951a8SRobert Watson 563a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 564f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 565f7b951a8SRobert Watson if (error) { 566f7b951a8SRobert Watson free(elements, M_MACTEMP); 567f7b951a8SRobert Watson crfree(tcred); 568f7b951a8SRobert Watson return (error); 569f7b951a8SRobert Watson } 570f7b951a8SRobert Watson 571a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 572eca8a663SRobert Watson error = mac_externalize_cred_label(tcred->cr_label, elements, 57383b7b0edSRobert Watson buffer, mac.m_buflen); 574f7b951a8SRobert Watson if (error == 0) 575f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 576f7b951a8SRobert Watson 577f7b951a8SRobert Watson free(buffer, M_MACTEMP); 578f7b951a8SRobert Watson free(elements, M_MACTEMP); 579f7b951a8SRobert Watson crfree(tcred); 580f7b951a8SRobert Watson return (error); 581f7b951a8SRobert Watson } 582f7b951a8SRobert Watson 58395fab37eSRobert Watson /* 58495fab37eSRobert Watson * MPSAFE 58595fab37eSRobert Watson */ 58695fab37eSRobert Watson int 58795fab37eSRobert Watson __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 58895fab37eSRobert Watson { 589f7b951a8SRobert Watson char *elements, *buffer; 590f7b951a8SRobert Watson struct mac mac; 59195fab37eSRobert Watson int error; 59295fab37eSRobert Watson 593f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 594f7b951a8SRobert Watson if (error) 595f7b951a8SRobert Watson return (error); 59695fab37eSRobert Watson 597f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 598f7b951a8SRobert Watson if (error) 599f7b951a8SRobert Watson return (error); 600f7b951a8SRobert Watson 601a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 602f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 603f7b951a8SRobert Watson if (error) { 604f7b951a8SRobert Watson free(elements, M_MACTEMP); 605f7b951a8SRobert Watson return (error); 606f7b951a8SRobert Watson } 607f7b951a8SRobert Watson 608a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 609eca8a663SRobert Watson error = mac_externalize_cred_label(td->td_ucred->cr_label, 61083b7b0edSRobert Watson elements, buffer, mac.m_buflen); 611f7b951a8SRobert Watson if (error == 0) 612f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 613f7b951a8SRobert Watson 614f7b951a8SRobert Watson free(buffer, M_MACTEMP); 615f7b951a8SRobert Watson free(elements, M_MACTEMP); 61695fab37eSRobert Watson return (error); 61795fab37eSRobert Watson } 61895fab37eSRobert Watson 61995fab37eSRobert Watson /* 62095fab37eSRobert Watson * MPSAFE 62195fab37eSRobert Watson */ 62295fab37eSRobert Watson int 62395fab37eSRobert Watson __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 62495fab37eSRobert Watson { 62595fab37eSRobert Watson struct ucred *newcred, *oldcred; 626eca8a663SRobert Watson struct label *intlabel; 627f7b951a8SRobert Watson struct proc *p; 628f7b951a8SRobert Watson struct mac mac; 629f7b951a8SRobert Watson char *buffer; 63095fab37eSRobert Watson int error; 63195fab37eSRobert Watson 632f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 63395fab37eSRobert Watson if (error) 63495fab37eSRobert Watson return (error); 63595fab37eSRobert Watson 636f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 63795fab37eSRobert Watson if (error) 63895fab37eSRobert Watson return (error); 63995fab37eSRobert Watson 640a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 641f7b951a8SRobert Watson error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 642f7b951a8SRobert Watson if (error) { 643f7b951a8SRobert Watson free(buffer, M_MACTEMP); 644f7b951a8SRobert Watson return (error); 645f7b951a8SRobert Watson } 646f7b951a8SRobert Watson 647eca8a663SRobert Watson intlabel = mac_cred_label_alloc(); 648eca8a663SRobert Watson error = mac_internalize_cred_label(intlabel, buffer); 649f7b951a8SRobert Watson free(buffer, M_MACTEMP); 650eca8a663SRobert Watson if (error) 651eca8a663SRobert Watson goto out; 652f7b951a8SRobert Watson 65395fab37eSRobert Watson newcred = crget(); 65495fab37eSRobert Watson 65595fab37eSRobert Watson p = td->td_proc; 65695fab37eSRobert Watson PROC_LOCK(p); 65795fab37eSRobert Watson oldcred = p->p_ucred; 65895fab37eSRobert Watson 659eca8a663SRobert Watson error = mac_check_cred_relabel(oldcred, intlabel); 66095fab37eSRobert Watson if (error) { 66195fab37eSRobert Watson PROC_UNLOCK(p); 66295fab37eSRobert Watson crfree(newcred); 663f7b951a8SRobert Watson goto out; 66495fab37eSRobert Watson } 66595fab37eSRobert Watson 66695fab37eSRobert Watson setsugid(p); 66795fab37eSRobert Watson crcopy(newcred, oldcred); 668eca8a663SRobert Watson mac_relabel_cred(newcred, intlabel); 66995fab37eSRobert Watson p->p_ucred = newcred; 670e5cb5e37SRobert Watson 671e5cb5e37SRobert Watson /* 672e5cb5e37SRobert Watson * Grab additional reference for use while revoking mmaps, prior 673e5cb5e37SRobert Watson * to releasing the proc lock and sharing the cred. 674e5cb5e37SRobert Watson */ 675e5cb5e37SRobert Watson crhold(newcred); 67695fab37eSRobert Watson PROC_UNLOCK(p); 677e5cb5e37SRobert Watson 678f7b951a8SRobert Watson if (mac_enforce_vm) { 67916140035SRobert Watson mtx_lock(&Giant); 680e5cb5e37SRobert Watson mac_cred_mmapped_drop_perms(td, newcred); 68116140035SRobert Watson mtx_unlock(&Giant); 682f7b951a8SRobert Watson } 683e5cb5e37SRobert Watson 684e5cb5e37SRobert Watson crfree(newcred); /* Free revocation reference. */ 68595fab37eSRobert Watson crfree(oldcred); 686f7b951a8SRobert Watson 687f7b951a8SRobert Watson out: 688eca8a663SRobert Watson mac_cred_label_free(intlabel); 689f7b951a8SRobert Watson return (error); 69095fab37eSRobert Watson } 69195fab37eSRobert Watson 69295fab37eSRobert Watson /* 69395fab37eSRobert Watson * MPSAFE 69495fab37eSRobert Watson */ 69595fab37eSRobert Watson int 69695fab37eSRobert Watson __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 69795fab37eSRobert Watson { 698f7b951a8SRobert Watson char *elements, *buffer; 699eca8a663SRobert Watson struct label *intlabel; 70095fab37eSRobert Watson struct file *fp; 701f7b951a8SRobert Watson struct mac mac; 70295fab37eSRobert Watson struct vnode *vp; 70395fab37eSRobert Watson struct pipe *pipe; 704b0323ea3SRobert Watson struct socket *so; 705f7b951a8SRobert Watson short label_type; 70695fab37eSRobert Watson int error; 70795fab37eSRobert Watson 708f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 709f7b951a8SRobert Watson if (error) 710f7b951a8SRobert Watson return (error); 71195fab37eSRobert Watson 712f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 713f7b951a8SRobert Watson if (error) 714f7b951a8SRobert Watson return (error); 715f7b951a8SRobert Watson 716a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 717f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 718f7b951a8SRobert Watson if (error) { 719f7b951a8SRobert Watson free(elements, M_MACTEMP); 720f7b951a8SRobert Watson return (error); 721f7b951a8SRobert Watson } 722f7b951a8SRobert Watson 723a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 724d1e405c5SAlfred Perlstein error = fget(td, uap->fd, &fp); 72595fab37eSRobert Watson if (error) 72695fab37eSRobert Watson goto out; 72795fab37eSRobert Watson 728f7b951a8SRobert Watson label_type = fp->f_type; 72995fab37eSRobert Watson switch (fp->f_type) { 73095fab37eSRobert Watson case DTYPE_FIFO: 73195fab37eSRobert Watson case DTYPE_VNODE: 7323b6d9652SPoul-Henning Kamp vp = fp->f_vnode; 733eca8a663SRobert Watson intlabel = mac_vnode_label_alloc(); 734f0ab0442SRobert Watson mtx_lock(&Giant); /* VFS */ 73595fab37eSRobert Watson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 736eca8a663SRobert Watson mac_copy_vnode_label(vp->v_label, intlabel); 73795fab37eSRobert Watson VOP_UNLOCK(vp, 0, td); 738f0ab0442SRobert Watson mtx_unlock(&Giant); /* VFS */ 739f0ab0442SRobert Watson error = mac_externalize_vnode_label(intlabel, elements, 740f0ab0442SRobert Watson buffer, mac.m_buflen); 741f0ab0442SRobert Watson mac_vnode_label_free(intlabel); 74295fab37eSRobert Watson break; 743f0ab0442SRobert Watson 74495fab37eSRobert Watson case DTYPE_PIPE: 74548e3128bSMatthew Dillon pipe = fp->f_data; 746eca8a663SRobert Watson intlabel = mac_pipe_label_alloc(); 747f7b951a8SRobert Watson PIPE_LOCK(pipe); 748eca8a663SRobert Watson mac_copy_pipe_label(pipe->pipe_label, intlabel); 749f7b951a8SRobert Watson PIPE_UNLOCK(pipe); 750eca8a663SRobert Watson error = mac_externalize_pipe_label(intlabel, elements, 75183b7b0edSRobert Watson buffer, mac.m_buflen); 752eca8a663SRobert Watson mac_pipe_label_free(intlabel); 753f7b951a8SRobert Watson break; 75495fab37eSRobert Watson 755b0323ea3SRobert Watson case DTYPE_SOCKET: 756b0323ea3SRobert Watson so = fp->f_data; 757b0323ea3SRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK); 758b0323ea3SRobert Watson mtx_lock(&Giant); /* Sockets */ 759b0323ea3SRobert Watson /* XXX: Socket lock here. */ 760b0323ea3SRobert Watson mac_copy_socket_label(so->so_label, intlabel); 761b0323ea3SRobert Watson /* XXX: Socket unlock here. */ 762b0323ea3SRobert Watson mtx_unlock(&Giant); /* Sockets */ 763b0323ea3SRobert Watson error = mac_externalize_socket_label(intlabel, elements, 764b0323ea3SRobert Watson buffer, mac.m_buflen); 765b0323ea3SRobert Watson mac_socket_label_free(intlabel); 766b0323ea3SRobert Watson break; 767b0323ea3SRobert Watson 768f0ab0442SRobert Watson default: 769f0ab0442SRobert Watson error = EINVAL; 770f0ab0442SRobert Watson } 771f0ab0442SRobert Watson fdrop(fp, td); 77295fab37eSRobert Watson if (error == 0) 773f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 77495fab37eSRobert Watson 77595fab37eSRobert Watson out: 776f7b951a8SRobert Watson free(buffer, M_MACTEMP); 777f7b951a8SRobert Watson free(elements, M_MACTEMP); 77895fab37eSRobert Watson return (error); 77995fab37eSRobert Watson } 78095fab37eSRobert Watson 78195fab37eSRobert Watson /* 78295fab37eSRobert Watson * MPSAFE 78395fab37eSRobert Watson */ 78495fab37eSRobert Watson int 78595fab37eSRobert Watson __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 78695fab37eSRobert Watson { 787f7b951a8SRobert Watson char *elements, *buffer; 78895fab37eSRobert Watson struct nameidata nd; 789eca8a663SRobert Watson struct label *intlabel; 790f7b951a8SRobert Watson struct mac mac; 79195fab37eSRobert Watson int error; 79295fab37eSRobert Watson 793f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 794f7b951a8SRobert Watson if (error) 795f7b951a8SRobert Watson return (error); 796f7b951a8SRobert Watson 797f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 798f7b951a8SRobert Watson if (error) 799f7b951a8SRobert Watson return (error); 800f7b951a8SRobert Watson 801a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 802f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 803f7b951a8SRobert Watson if (error) { 804f7b951a8SRobert Watson free(elements, M_MACTEMP); 805f7b951a8SRobert Watson return (error); 806f7b951a8SRobert Watson } 807f7b951a8SRobert Watson 808a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 809f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 810f7b951a8SRobert Watson NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, 811f7b951a8SRobert Watson td); 81295fab37eSRobert Watson error = namei(&nd); 81395fab37eSRobert Watson if (error) 81495fab37eSRobert Watson goto out; 81595fab37eSRobert Watson 816eca8a663SRobert Watson intlabel = mac_vnode_label_alloc(); 817eca8a663SRobert Watson mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); 818eca8a663SRobert Watson error = mac_externalize_vnode_label(intlabel, elements, buffer, 81983b7b0edSRobert Watson mac.m_buflen); 820f7b951a8SRobert Watson 82195fab37eSRobert Watson NDFREE(&nd, 0); 822eca8a663SRobert Watson mac_vnode_label_free(intlabel); 823f7b951a8SRobert Watson 824f7b951a8SRobert Watson if (error == 0) 825f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 826f7b951a8SRobert Watson 827f7b951a8SRobert Watson out: 828f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 829f7b951a8SRobert Watson 830f7b951a8SRobert Watson free(buffer, M_MACTEMP); 831f7b951a8SRobert Watson free(elements, M_MACTEMP); 832f7b951a8SRobert Watson 833f7b951a8SRobert Watson return (error); 834f7b951a8SRobert Watson } 835f7b951a8SRobert Watson 836f7b951a8SRobert Watson /* 837f7b951a8SRobert Watson * MPSAFE 838f7b951a8SRobert Watson */ 839f7b951a8SRobert Watson int 840f7b951a8SRobert Watson __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 841f7b951a8SRobert Watson { 842f7b951a8SRobert Watson char *elements, *buffer; 843f7b951a8SRobert Watson struct nameidata nd; 844eca8a663SRobert Watson struct label *intlabel; 845f7b951a8SRobert Watson struct mac mac; 846f7b951a8SRobert Watson int error; 847f7b951a8SRobert Watson 848f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 849f7b951a8SRobert Watson if (error) 850f7b951a8SRobert Watson return (error); 851f7b951a8SRobert Watson 852f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 853f7b951a8SRobert Watson if (error) 854f7b951a8SRobert Watson return (error); 855f7b951a8SRobert Watson 856a163d034SWarner Losh elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 857f7b951a8SRobert Watson error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL); 858f7b951a8SRobert Watson if (error) { 859f7b951a8SRobert Watson free(elements, M_MACTEMP); 860f7b951a8SRobert Watson return (error); 861f7b951a8SRobert Watson } 862f7b951a8SRobert Watson 863a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 864f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 865f7b951a8SRobert Watson NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, 866f7b951a8SRobert Watson td); 867f7b951a8SRobert Watson error = namei(&nd); 86895fab37eSRobert Watson if (error) 86995fab37eSRobert Watson goto out; 87095fab37eSRobert Watson 871eca8a663SRobert Watson intlabel = mac_vnode_label_alloc(); 872eca8a663SRobert Watson mac_copy_vnode_label(nd.ni_vp->v_label, intlabel); 873eca8a663SRobert Watson error = mac_externalize_vnode_label(intlabel, elements, buffer, 87483b7b0edSRobert Watson mac.m_buflen); 875f7b951a8SRobert Watson NDFREE(&nd, 0); 876eca8a663SRobert Watson mac_vnode_label_free(intlabel); 877f7b951a8SRobert Watson 878f7b951a8SRobert Watson if (error == 0) 879f7b951a8SRobert Watson error = copyout(buffer, mac.m_string, strlen(buffer)+1); 88095fab37eSRobert Watson 88195fab37eSRobert Watson out: 882f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 883f7b951a8SRobert Watson 884f7b951a8SRobert Watson free(buffer, M_MACTEMP); 885f7b951a8SRobert Watson free(elements, M_MACTEMP); 886f7b951a8SRobert Watson 88795fab37eSRobert Watson return (error); 88895fab37eSRobert Watson } 88995fab37eSRobert Watson 89095fab37eSRobert Watson /* 89195fab37eSRobert Watson * MPSAFE 89295fab37eSRobert Watson */ 89395fab37eSRobert Watson int 89495fab37eSRobert Watson __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 89595fab37eSRobert Watson { 896eca8a663SRobert Watson struct label *intlabel; 897f7b951a8SRobert Watson struct pipe *pipe; 898b0323ea3SRobert Watson struct socket *so; 899f7b951a8SRobert Watson struct file *fp; 90095fab37eSRobert Watson struct mount *mp; 90195fab37eSRobert Watson struct vnode *vp; 902f7b951a8SRobert Watson struct mac mac; 903f7b951a8SRobert Watson char *buffer; 90495fab37eSRobert Watson int error; 90595fab37eSRobert Watson 906f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 907f7b951a8SRobert Watson if (error) 908f7b951a8SRobert Watson return (error); 909f7b951a8SRobert Watson 910f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 911f7b951a8SRobert Watson if (error) 912f7b951a8SRobert Watson return (error); 913f7b951a8SRobert Watson 914a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 915f7b951a8SRobert Watson error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 916f7b951a8SRobert Watson if (error) { 917f7b951a8SRobert Watson free(buffer, M_MACTEMP); 918f7b951a8SRobert Watson return (error); 919f7b951a8SRobert Watson } 920f7b951a8SRobert Watson 921d1e405c5SAlfred Perlstein error = fget(td, uap->fd, &fp); 92295fab37eSRobert Watson if (error) 923f7b951a8SRobert Watson goto out; 92495fab37eSRobert Watson 92595fab37eSRobert Watson switch (fp->f_type) { 92695fab37eSRobert Watson case DTYPE_FIFO: 92795fab37eSRobert Watson case DTYPE_VNODE: 928eca8a663SRobert Watson intlabel = mac_vnode_label_alloc(); 929eca8a663SRobert Watson error = mac_internalize_vnode_label(intlabel, buffer); 930f7b951a8SRobert Watson if (error) { 931eca8a663SRobert Watson mac_vnode_label_free(intlabel); 932f7b951a8SRobert Watson break; 933f7b951a8SRobert Watson } 9343b6d9652SPoul-Henning Kamp vp = fp->f_vnode; 935f0ab0442SRobert Watson mtx_lock(&Giant); /* VFS */ 93695fab37eSRobert Watson error = vn_start_write(vp, &mp, V_WAIT | PCATCH); 937f7b951a8SRobert Watson if (error != 0) { 938f0ab0442SRobert Watson mtx_unlock(&Giant); /* VFS */ 939eca8a663SRobert Watson mac_vnode_label_free(intlabel); 94095fab37eSRobert Watson break; 941f7b951a8SRobert Watson } 94295fab37eSRobert Watson vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td); 943eca8a663SRobert Watson error = vn_setlabel(vp, intlabel, td->td_ucred); 94495fab37eSRobert Watson VOP_UNLOCK(vp, 0, td); 94595fab37eSRobert Watson vn_finished_write(mp); 946f0ab0442SRobert Watson mtx_unlock(&Giant); /* VFS */ 947eca8a663SRobert Watson mac_vnode_label_free(intlabel); 94895fab37eSRobert Watson break; 949f7b951a8SRobert Watson 95095fab37eSRobert Watson case DTYPE_PIPE: 951eca8a663SRobert Watson intlabel = mac_pipe_label_alloc(); 952eca8a663SRobert Watson error = mac_internalize_pipe_label(intlabel, buffer); 953f7b951a8SRobert Watson if (error == 0) { 95448e3128bSMatthew Dillon pipe = fp->f_data; 9551aa37f53SRobert Watson PIPE_LOCK(pipe); 956f7b951a8SRobert Watson error = mac_pipe_label_set(td->td_ucred, pipe, 957eca8a663SRobert Watson intlabel); 9581aa37f53SRobert Watson PIPE_UNLOCK(pipe); 959f7b951a8SRobert Watson } 960eca8a663SRobert Watson mac_pipe_label_free(intlabel); 96195fab37eSRobert Watson break; 962f7b951a8SRobert Watson 963b0323ea3SRobert Watson case DTYPE_SOCKET: 964b0323ea3SRobert Watson intlabel = mac_socket_label_alloc(M_WAITOK); 965b0323ea3SRobert Watson error = mac_internalize_socket_label(intlabel, buffer); 966b0323ea3SRobert Watson if (error == 0) { 967b0323ea3SRobert Watson so = fp->f_data; 968b0323ea3SRobert Watson mtx_lock(&Giant); /* Sockets */ 969b0323ea3SRobert Watson /* XXX: Socket lock here. */ 970b0323ea3SRobert Watson error = mac_socket_label_set(td->td_ucred, so, 971b0323ea3SRobert Watson intlabel); 972b0323ea3SRobert Watson /* XXX: Socket unlock here. */ 973b0323ea3SRobert Watson mtx_unlock(&Giant); /* Sockets */ 974b0323ea3SRobert Watson } 975b0323ea3SRobert Watson mac_socket_label_free(intlabel); 976b0323ea3SRobert Watson break; 977b0323ea3SRobert Watson 97895fab37eSRobert Watson default: 97995fab37eSRobert Watson error = EINVAL; 98095fab37eSRobert Watson } 98195fab37eSRobert Watson fdrop(fp, td); 982f7b951a8SRobert Watson out: 983f7b951a8SRobert Watson free(buffer, M_MACTEMP); 98495fab37eSRobert Watson return (error); 98595fab37eSRobert Watson } 98695fab37eSRobert Watson 98795fab37eSRobert Watson /* 98895fab37eSRobert Watson * MPSAFE 98995fab37eSRobert Watson */ 99095fab37eSRobert Watson int 99195fab37eSRobert Watson __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 99295fab37eSRobert Watson { 993eca8a663SRobert Watson struct label *intlabel; 994f7b951a8SRobert Watson struct nameidata nd; 99595fab37eSRobert Watson struct mount *mp; 996f7b951a8SRobert Watson struct mac mac; 997f7b951a8SRobert Watson char *buffer; 99895fab37eSRobert Watson int error; 99995fab37eSRobert Watson 1000f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 100195fab37eSRobert Watson if (error) 1002f7b951a8SRobert Watson return (error); 100395fab37eSRobert Watson 1004f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 100595fab37eSRobert Watson if (error) 1006f7b951a8SRobert Watson return (error); 100795fab37eSRobert Watson 1008a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 1009f7b951a8SRobert Watson error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 1010f7b951a8SRobert Watson if (error) { 1011f7b951a8SRobert Watson free(buffer, M_MACTEMP); 101295fab37eSRobert Watson return (error); 101395fab37eSRobert Watson } 101495fab37eSRobert Watson 1015eca8a663SRobert Watson intlabel = mac_vnode_label_alloc(); 1016eca8a663SRobert Watson error = mac_internalize_vnode_label(intlabel, buffer); 1017f7b951a8SRobert Watson free(buffer, M_MACTEMP); 1018eca8a663SRobert Watson if (error) 1019eca8a663SRobert Watson goto out; 1020f7b951a8SRobert Watson 1021f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 1022f7b951a8SRobert Watson 1023f7b951a8SRobert Watson NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p, 1024f7b951a8SRobert Watson td); 1025f7b951a8SRobert Watson error = namei(&nd); 1026f7b951a8SRobert Watson if (error == 0) { 1027f7b951a8SRobert Watson error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 1028f7b951a8SRobert Watson if (error == 0) 1029eca8a663SRobert Watson error = vn_setlabel(nd.ni_vp, intlabel, 1030f7b951a8SRobert Watson td->td_ucred); 1031f7b951a8SRobert Watson vn_finished_write(mp); 1032f7b951a8SRobert Watson } 1033f7b951a8SRobert Watson 1034f7b951a8SRobert Watson NDFREE(&nd, 0); 1035f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 1036eca8a663SRobert Watson out: 1037eca8a663SRobert Watson mac_vnode_label_free(intlabel); 1038f7b951a8SRobert Watson return (error); 1039f7b951a8SRobert Watson } 1040f7b951a8SRobert Watson 1041f7b951a8SRobert Watson /* 1042f7b951a8SRobert Watson * MPSAFE 1043f7b951a8SRobert Watson */ 1044f7b951a8SRobert Watson int 1045f7b951a8SRobert Watson __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 1046f7b951a8SRobert Watson { 1047eca8a663SRobert Watson struct label *intlabel; 1048f7b951a8SRobert Watson struct nameidata nd; 1049f7b951a8SRobert Watson struct mount *mp; 1050f7b951a8SRobert Watson struct mac mac; 1051f7b951a8SRobert Watson char *buffer; 1052f7b951a8SRobert Watson int error; 1053f7b951a8SRobert Watson 1054f7b951a8SRobert Watson error = copyin(uap->mac_p, &mac, sizeof(mac)); 1055f7b951a8SRobert Watson if (error) 1056f7b951a8SRobert Watson return (error); 1057f7b951a8SRobert Watson 1058f7b951a8SRobert Watson error = mac_check_structmac_consistent(&mac); 1059f7b951a8SRobert Watson if (error) 1060f7b951a8SRobert Watson return (error); 1061f7b951a8SRobert Watson 1062a163d034SWarner Losh buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK); 1063f7b951a8SRobert Watson error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL); 1064f7b951a8SRobert Watson if (error) { 1065f7b951a8SRobert Watson free(buffer, M_MACTEMP); 1066f7b951a8SRobert Watson return (error); 1067f7b951a8SRobert Watson } 1068f7b951a8SRobert Watson 1069eca8a663SRobert Watson intlabel = mac_vnode_label_alloc(); 1070eca8a663SRobert Watson error = mac_internalize_vnode_label(intlabel, buffer); 1071f7b951a8SRobert Watson free(buffer, M_MACTEMP); 1072eca8a663SRobert Watson if (error) 1073eca8a663SRobert Watson goto out; 1074f7b951a8SRobert Watson 1075f7b951a8SRobert Watson mtx_lock(&Giant); /* VFS */ 1076f7b951a8SRobert Watson 1077f7b951a8SRobert Watson NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p, 1078f7b951a8SRobert Watson td); 1079f7b951a8SRobert Watson error = namei(&nd); 1080f7b951a8SRobert Watson if (error == 0) { 1081f7b951a8SRobert Watson error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH); 1082f7b951a8SRobert Watson if (error == 0) 1083eca8a663SRobert Watson error = vn_setlabel(nd.ni_vp, intlabel, 1084f7b951a8SRobert Watson td->td_ucred); 1085f7b951a8SRobert Watson vn_finished_write(mp); 1086f7b951a8SRobert Watson } 1087f7b951a8SRobert Watson 1088f7b951a8SRobert Watson NDFREE(&nd, 0); 1089f7b951a8SRobert Watson mtx_unlock(&Giant); /* VFS */ 1090eca8a663SRobert Watson out: 1091eca8a663SRobert Watson mac_vnode_label_free(intlabel); 1092f7b951a8SRobert Watson return (error); 1093f7b951a8SRobert Watson } 1094f7b951a8SRobert Watson 1095f7b951a8SRobert Watson /* 1096f7b951a8SRobert Watson * MPSAFE 1097f7b951a8SRobert Watson */ 109827f2eac7SRobert Watson int 109927f2eac7SRobert Watson mac_syscall(struct thread *td, struct mac_syscall_args *uap) 110027f2eac7SRobert Watson { 110127f2eac7SRobert Watson struct mac_policy_conf *mpc; 110227f2eac7SRobert Watson char target[MAC_MAX_POLICY_NAME]; 110341a17fe3SRobert Watson int entrycount, error; 110427f2eac7SRobert Watson 1105d1e405c5SAlfred Perlstein error = copyinstr(uap->policy, target, sizeof(target), NULL); 110627f2eac7SRobert Watson if (error) 110727f2eac7SRobert Watson return (error); 110827f2eac7SRobert Watson 110927f2eac7SRobert Watson error = ENOSYS; 1110a6a65b05SRobert Watson LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) { 111127f2eac7SRobert Watson if (strcmp(mpc->mpc_name, target) == 0 && 111227f2eac7SRobert Watson mpc->mpc_ops->mpo_syscall != NULL) { 111327f2eac7SRobert Watson error = mpc->mpc_ops->mpo_syscall(td, 1114d1e405c5SAlfred Perlstein uap->call, uap->arg); 111527f2eac7SRobert Watson goto out; 111627f2eac7SRobert Watson } 111727f2eac7SRobert Watson } 111827f2eac7SRobert Watson 111941a17fe3SRobert Watson if ((entrycount = mac_policy_list_conditional_busy()) != 0) { 112041a17fe3SRobert Watson LIST_FOREACH(mpc, &mac_policy_list, mpc_list) { 112141a17fe3SRobert Watson if (strcmp(mpc->mpc_name, target) == 0 && 112241a17fe3SRobert Watson mpc->mpc_ops->mpo_syscall != NULL) { 112341a17fe3SRobert Watson error = mpc->mpc_ops->mpo_syscall(td, 112441a17fe3SRobert Watson uap->call, uap->arg); 112541a17fe3SRobert Watson break; 112641a17fe3SRobert Watson } 112741a17fe3SRobert Watson } 112841a17fe3SRobert Watson mac_policy_list_unbusy(); 112941a17fe3SRobert Watson } 113027f2eac7SRobert Watson out: 113127f2eac7SRobert Watson return (error); 113227f2eac7SRobert Watson } 113327f2eac7SRobert Watson 113495fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL); 113595fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL); 113695fab37eSRobert Watson 113795fab37eSRobert Watson #else /* !MAC */ 11387bc82500SRobert Watson 11397bc82500SRobert Watson int 1140f7b951a8SRobert Watson __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap) 1141f7b951a8SRobert Watson { 1142f7b951a8SRobert Watson 1143f7b951a8SRobert Watson return (ENOSYS); 1144f7b951a8SRobert Watson } 1145f7b951a8SRobert Watson 1146f7b951a8SRobert Watson int 11477bc82500SRobert Watson __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap) 11487bc82500SRobert Watson { 11497bc82500SRobert Watson 11507bc82500SRobert Watson return (ENOSYS); 11517bc82500SRobert Watson } 11527bc82500SRobert Watson 11537bc82500SRobert Watson int 11547bc82500SRobert Watson __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap) 11557bc82500SRobert Watson { 11567bc82500SRobert Watson 11577bc82500SRobert Watson return (ENOSYS); 11587bc82500SRobert Watson } 11597bc82500SRobert Watson 11607bc82500SRobert Watson int 11617bc82500SRobert Watson __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap) 11627bc82500SRobert Watson { 11637bc82500SRobert Watson 11647bc82500SRobert Watson return (ENOSYS); 11657bc82500SRobert Watson } 11667bc82500SRobert Watson 11677bc82500SRobert Watson int 11687bc82500SRobert Watson __mac_get_file(struct thread *td, struct __mac_get_file_args *uap) 11697bc82500SRobert Watson { 11707bc82500SRobert Watson 11717bc82500SRobert Watson return (ENOSYS); 11727bc82500SRobert Watson } 11737bc82500SRobert Watson 11747bc82500SRobert Watson int 1175f7b951a8SRobert Watson __mac_get_link(struct thread *td, struct __mac_get_link_args *uap) 1176f7b951a8SRobert Watson { 1177f7b951a8SRobert Watson 1178f7b951a8SRobert Watson return (ENOSYS); 1179f7b951a8SRobert Watson } 1180f7b951a8SRobert Watson 1181f7b951a8SRobert Watson int 11827bc82500SRobert Watson __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap) 11837bc82500SRobert Watson { 11847bc82500SRobert Watson 11857bc82500SRobert Watson return (ENOSYS); 11867bc82500SRobert Watson } 11877bc82500SRobert Watson 11887bc82500SRobert Watson int 11897bc82500SRobert Watson __mac_set_file(struct thread *td, struct __mac_set_file_args *uap) 11907bc82500SRobert Watson { 11917bc82500SRobert Watson 11927bc82500SRobert Watson return (ENOSYS); 11937bc82500SRobert Watson } 119495fab37eSRobert Watson 119527f2eac7SRobert Watson int 1196f7b951a8SRobert Watson __mac_set_link(struct thread *td, struct __mac_set_link_args *uap) 1197f7b951a8SRobert Watson { 1198f7b951a8SRobert Watson 1199f7b951a8SRobert Watson return (ENOSYS); 1200f7b951a8SRobert Watson } 1201f7b951a8SRobert Watson 1202f7b951a8SRobert Watson int 120327f2eac7SRobert Watson mac_syscall(struct thread *td, struct mac_syscall_args *uap) 120427f2eac7SRobert Watson { 120527f2eac7SRobert Watson 120627f2eac7SRobert Watson return (ENOSYS); 120727f2eac7SRobert Watson } 120827f2eac7SRobert Watson 1209f7b951a8SRobert Watson #endif 1210