xref: /freebsd/sys/security/mac/mac_framework.c (revision 498693053c8087c41ae0f8162f35913d11e277ad)
17bc82500SRobert Watson /*-
2f6a41092SRobert Watson  * Copyright (c) 1999-2002 Robert N. M. Watson
37bc82500SRobert Watson  * Copyright (c) 2001 Ilmar S. Habibulin
4f0c2044bSRobert Watson  * Copyright (c) 2001-2005 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
4149869305STom Rhodes  * found in src/sys/security/mac/.  Sample policies may be found in
4249869305STom Rhodes  * src/sys/security/mac_*.
437bc82500SRobert Watson  */
447bc82500SRobert Watson 
45677b542eSDavid E. O'Brien #include <sys/cdefs.h>
46677b542eSDavid E. O'Brien __FBSDID("$FreeBSD$");
47677b542eSDavid E. O'Brien 
487bc82500SRobert Watson #include "opt_mac.h"
49328048bcSPoul-Henning Kamp #include "opt_devfs.h"
50f9d0d524SRobert Watson 
517bc82500SRobert Watson #include <sys/param.h>
52a96acd1aSRobert Watson #include <sys/condvar.h>
5395fab37eSRobert Watson #include <sys/extattr.h>
54670cb89bSRobert Watson #include <sys/imgact.h>
5595fab37eSRobert Watson #include <sys/kernel.h>
5695fab37eSRobert Watson #include <sys/lock.h>
57b656366bSBruce Evans #include <sys/malloc.h>
5895fab37eSRobert Watson #include <sys/mutex.h>
5995fab37eSRobert Watson #include <sys/mac.h>
607ba28492SRobert Watson #include <sys/module.h>
6195fab37eSRobert Watson #include <sys/proc.h>
62f51e5803SRobert Watson #include <sys/sbuf.h>
6395fab37eSRobert Watson #include <sys/systm.h>
647bc82500SRobert Watson #include <sys/sysproto.h>
657bc82500SRobert Watson #include <sys/sysent.h>
6695fab37eSRobert Watson #include <sys/vnode.h>
6795fab37eSRobert Watson #include <sys/mount.h>
6895fab37eSRobert Watson #include <sys/file.h>
6995fab37eSRobert Watson #include <sys/namei.h>
7095fab37eSRobert Watson #include <sys/socket.h>
7195fab37eSRobert Watson #include <sys/pipe.h>
7295fab37eSRobert Watson #include <sys/socketvar.h>
7395fab37eSRobert Watson #include <sys/sysctl.h>
7495fab37eSRobert Watson 
7595fab37eSRobert Watson #include <vm/vm.h>
7695fab37eSRobert Watson #include <vm/pmap.h>
7795fab37eSRobert Watson #include <vm/vm_map.h>
7895fab37eSRobert Watson #include <vm/vm_object.h>
7995fab37eSRobert Watson 
8095fab37eSRobert Watson #include <sys/mac_policy.h>
8195fab37eSRobert Watson 
8295fab37eSRobert Watson #include <fs/devfs/devfs.h>
8395fab37eSRobert Watson 
8495fab37eSRobert Watson #include <net/bpfdesc.h>
8595fab37eSRobert Watson #include <net/if.h>
8695fab37eSRobert Watson #include <net/if_var.h>
8795fab37eSRobert Watson 
8895fab37eSRobert Watson #include <netinet/in.h>
8995fab37eSRobert Watson #include <netinet/ip_var.h>
9095fab37eSRobert Watson 
916fa0475dSRobert Watson #include <security/mac/mac_internal.h>
926fa0475dSRobert Watson 
9395fab37eSRobert Watson #ifdef MAC
9495fab37eSRobert Watson 
957ba28492SRobert Watson /*
967ba28492SRobert Watson  * Declare that the kernel provides MAC support, version 1.  This permits
977ba28492SRobert Watson  * modules to refuse to be loaded if the necessary support isn't present,
987ba28492SRobert Watson  * even if it's pre-boot.
997ba28492SRobert Watson  */
100af8d7cbeSRobert Watson MODULE_VERSION(kernel_mac_support, 2);
1017ba28492SRobert Watson 
10295fab37eSRobert Watson SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
10395fab37eSRobert Watson     "TrustedBSD MAC policy controls");
104b2f0927aSRobert Watson 
105b2aef571SRobert Watson #if MAC_MAX_SLOTS > 32
106b2aef571SRobert Watson #error "MAC_MAX_SLOTS too large"
10795fab37eSRobert Watson #endif
108a13c67daSRobert Watson 
109b2aef571SRobert Watson static unsigned int mac_max_slots = MAC_MAX_SLOTS;
110b2aef571SRobert Watson static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
111b2aef571SRobert Watson SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD,
112b2aef571SRobert Watson     &mac_max_slots, 0, "");
11395fab37eSRobert Watson 
114a67fe518SRobert Watson /*
115a67fe518SRobert Watson  * Has the kernel started generating labeled objects yet?  All read/write
116a67fe518SRobert Watson  * access to this variable is serialized during the boot process.  Following
117a67fe518SRobert Watson  * the end of serialization, we don't update this flag; no locking.
118a67fe518SRobert Watson  */
119089c1bdaSRobert Watson int	mac_late = 0;
120763bbd2fSRobert Watson 
121225bff6fSRobert Watson /*
122225bff6fSRobert Watson  * Flag to indicate whether or not we should allocate label storage for
123225bff6fSRobert Watson  * new mbufs.  Since most dynamic policies we currently work with don't
124225bff6fSRobert Watson  * rely on mbuf labeling, try to avoid paying the cost of mtag allocation
125225bff6fSRobert Watson  * unless specifically notified of interest.  One result of this is
126225bff6fSRobert Watson  * that if a dynamically loaded policy requests mbuf labels, it must
127225bff6fSRobert Watson  * be able to deal with a NULL label being returned on any mbufs that
128225bff6fSRobert Watson  * were already in flight when the policy was loaded.  Since the policy
129225bff6fSRobert Watson  * already has to deal with uninitialized labels, this probably won't
130225bff6fSRobert Watson  * be a problem.  Note: currently no locking.  Will this be a problem?
131225bff6fSRobert Watson  */
13219c3e120SRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF
133089c1bdaSRobert Watson int	mac_labelmbufs = 0;
134225bff6fSRobert Watson #endif
135225bff6fSRobert Watson 
136f050add5SRobert Watson #ifdef MAC_DEBUG
1376be0c25eSRobert Watson SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0,
1386be0c25eSRobert Watson     "TrustedBSD MAC debug info");
139b2f0927aSRobert Watson SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0,
140b2f0927aSRobert Watson     "TrustedBSD MAC object counters");
141b2f0927aSRobert Watson 
1426fa0475dSRobert Watson static unsigned int nmactemp;
143b2f0927aSRobert Watson SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD,
14495fab37eSRobert Watson     &nmactemp, 0, "number of temporary labels in use");
145f050add5SRobert Watson #endif
14695fab37eSRobert Watson 
14795fab37eSRobert Watson static int	mac_policy_register(struct mac_policy_conf *mpc);
14895fab37eSRobert Watson static int	mac_policy_unregister(struct mac_policy_conf *mpc);
14995fab37eSRobert Watson 
150f7b951a8SRobert Watson MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
15195fab37eSRobert Watson 
15295fab37eSRobert Watson /*
15341a17fe3SRobert Watson  * mac_static_policy_list holds a list of policy modules that are not
15441a17fe3SRobert Watson  * loaded while the system is "live", and cannot be unloaded.  These
15541a17fe3SRobert Watson  * policies can be invoked without holding the busy count.
15641a17fe3SRobert Watson  *
15741a17fe3SRobert Watson  * mac_policy_list stores the list of dynamic policies.  A busy count is
158a96acd1aSRobert Watson  * maintained for the list, stored in mac_policy_busy.  The busy count
15941a17fe3SRobert Watson  * is protected by mac_policy_mtx; the list may be modified only
160a96acd1aSRobert Watson  * while the busy count is 0, requiring that the lock be held to
161a96acd1aSRobert Watson  * prevent new references to the list from being acquired.  For almost
162a96acd1aSRobert Watson  * all operations, incrementing the busy count is sufficient to
163a96acd1aSRobert Watson  * guarantee consistency, as the list cannot be modified while the
164a96acd1aSRobert Watson  * busy count is elevated.  For a few special operations involving a
16541a17fe3SRobert Watson  * change to the list of active policies, the mtx itself must be held.
16641a17fe3SRobert Watson  * A condition variable, mac_policy_cv, is used to signal potential
16741a17fe3SRobert Watson  * exclusive consumers that they should try to acquire the lock if a
16841a17fe3SRobert Watson  * first attempt at exclusive access fails.
16995fab37eSRobert Watson  */
1700a05006dSRobert Watson #ifndef MAC_STATIC
17141a17fe3SRobert Watson static struct mtx mac_policy_mtx;
17241a17fe3SRobert Watson static struct cv mac_policy_cv;
17341a17fe3SRobert Watson static int mac_policy_count;
1740a05006dSRobert Watson #endif
175089c1bdaSRobert Watson struct mac_policy_list_head mac_policy_list;
176089c1bdaSRobert Watson struct mac_policy_list_head mac_static_policy_list;
177a96acd1aSRobert Watson 
178a96acd1aSRobert Watson /*
17926306795SJohn Baldwin  * We manually invoke WITNESS_WARN() to allow Witness to generate
180a96acd1aSRobert Watson  * warnings even if we don't end up ever triggering the wait at
181a96acd1aSRobert Watson  * run-time.  The consumer of the exclusive interface must not hold
182a96acd1aSRobert Watson  * any locks (other than potentially Giant) since we may sleep for
183a96acd1aSRobert Watson  * long (potentially indefinite) periods of time waiting for the
184a96acd1aSRobert Watson  * framework to become quiescent so that a policy list change may
185a96acd1aSRobert Watson  * be made.
186a96acd1aSRobert Watson  */
187089c1bdaSRobert Watson void
18841a17fe3SRobert Watson mac_policy_grab_exclusive(void)
18941a17fe3SRobert Watson {
190c8e7bf92SRobert Watson 
1910a05006dSRobert Watson #ifndef MAC_STATIC
1921e4cadcbSRobert Watson 	if (!mac_late)
1931e4cadcbSRobert Watson 		return;
1941e4cadcbSRobert Watson 
19541a17fe3SRobert Watson 	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
19641a17fe3SRobert Watson  	    "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
19741a17fe3SRobert Watson 	mtx_lock(&mac_policy_mtx);
19841a17fe3SRobert Watson 	while (mac_policy_count != 0)
19941a17fe3SRobert Watson 		cv_wait(&mac_policy_cv, &mac_policy_mtx);
2000a05006dSRobert Watson #endif
20141a17fe3SRobert Watson }
20295fab37eSRobert Watson 
203089c1bdaSRobert Watson void
20441a17fe3SRobert Watson mac_policy_assert_exclusive(void)
20541a17fe3SRobert Watson {
206c8e7bf92SRobert Watson 
2070a05006dSRobert Watson #ifndef MAC_STATIC
2081e4cadcbSRobert Watson 	if (!mac_late)
2091e4cadcbSRobert Watson 		return;
2101e4cadcbSRobert Watson 
21141a17fe3SRobert Watson 	mtx_assert(&mac_policy_mtx, MA_OWNED);
21241a17fe3SRobert Watson 	KASSERT(mac_policy_count == 0,
21341a17fe3SRobert Watson 	    ("mac_policy_assert_exclusive(): not exclusive"));
2140a05006dSRobert Watson #endif
21541a17fe3SRobert Watson }
216225bff6fSRobert Watson 
217089c1bdaSRobert Watson void
21841a17fe3SRobert Watson mac_policy_release_exclusive(void)
21941a17fe3SRobert Watson {
22095fab37eSRobert Watson 
2210a05006dSRobert Watson #ifndef MAC_STATIC
2221e4cadcbSRobert Watson 	if (!mac_late)
2231e4cadcbSRobert Watson 		return;
2241e4cadcbSRobert Watson 
22541a17fe3SRobert Watson 	KASSERT(mac_policy_count == 0,
22641a17fe3SRobert Watson 	    ("mac_policy_release_exclusive(): not exclusive"));
22741a17fe3SRobert Watson 	mtx_unlock(&mac_policy_mtx);
22841a17fe3SRobert Watson 	cv_signal(&mac_policy_cv);
2290a05006dSRobert Watson #endif
23041a17fe3SRobert Watson }
23141a17fe3SRobert Watson 
232089c1bdaSRobert Watson void
23341a17fe3SRobert Watson mac_policy_list_busy(void)
23441a17fe3SRobert Watson {
235c8e7bf92SRobert Watson 
2360a05006dSRobert Watson #ifndef MAC_STATIC
2371e4cadcbSRobert Watson 	if (!mac_late)
2381e4cadcbSRobert Watson 		return;
2391e4cadcbSRobert Watson 
24041a17fe3SRobert Watson 	mtx_lock(&mac_policy_mtx);
24141a17fe3SRobert Watson 	mac_policy_count++;
24241a17fe3SRobert Watson 	mtx_unlock(&mac_policy_mtx);
2430a05006dSRobert Watson #endif
24441a17fe3SRobert Watson }
24541a17fe3SRobert Watson 
246089c1bdaSRobert Watson int
24741a17fe3SRobert Watson mac_policy_list_conditional_busy(void)
24841a17fe3SRobert Watson {
2490a05006dSRobert Watson #ifndef MAC_STATIC
25041a17fe3SRobert Watson 	int ret;
25141a17fe3SRobert Watson 
2521e4cadcbSRobert Watson 	if (!mac_late)
2531e4cadcbSRobert Watson 		return (1);
2541e4cadcbSRobert Watson 
25541a17fe3SRobert Watson 	mtx_lock(&mac_policy_mtx);
25641a17fe3SRobert Watson 	if (!LIST_EMPTY(&mac_policy_list)) {
25741a17fe3SRobert Watson 		mac_policy_count++;
25841a17fe3SRobert Watson 		ret = 1;
25941a17fe3SRobert Watson 	} else
26041a17fe3SRobert Watson 		ret = 0;
26141a17fe3SRobert Watson 	mtx_unlock(&mac_policy_mtx);
26241a17fe3SRobert Watson 	return (ret);
2630a05006dSRobert Watson #else
2641e4cadcbSRobert Watson 	if (!mac_late)
2651e4cadcbSRobert Watson 		return (1);
2661e4cadcbSRobert Watson 
2670a05006dSRobert Watson 	return (1);
2680a05006dSRobert Watson #endif
26941a17fe3SRobert Watson }
27041a17fe3SRobert Watson 
271089c1bdaSRobert Watson void
27241a17fe3SRobert Watson mac_policy_list_unbusy(void)
27341a17fe3SRobert Watson {
274c8e7bf92SRobert Watson 
2750a05006dSRobert Watson #ifndef MAC_STATIC
2761e4cadcbSRobert Watson 	if (!mac_late)
2771e4cadcbSRobert Watson 		return;
2781e4cadcbSRobert Watson 
27941a17fe3SRobert Watson 	mtx_lock(&mac_policy_mtx);
28041a17fe3SRobert Watson 	mac_policy_count--;
28141a17fe3SRobert Watson 	KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
28241a17fe3SRobert Watson 	if (mac_policy_count == 0)
28341a17fe3SRobert Watson 		cv_signal(&mac_policy_cv);
28441a17fe3SRobert Watson 	mtx_unlock(&mac_policy_mtx);
2850a05006dSRobert Watson #endif
28641a17fe3SRobert Watson }
28795fab37eSRobert Watson 
28895fab37eSRobert Watson /*
28995fab37eSRobert Watson  * Initialize the MAC subsystem, including appropriate SMP locks.
29095fab37eSRobert Watson  */
29195fab37eSRobert Watson static void
29295fab37eSRobert Watson mac_init(void)
29395fab37eSRobert Watson {
29495fab37eSRobert Watson 
29541a17fe3SRobert Watson 	LIST_INIT(&mac_static_policy_list);
29695fab37eSRobert Watson 	LIST_INIT(&mac_policy_list);
297eca8a663SRobert Watson 	mac_labelzone_init();
29841a17fe3SRobert Watson 
2990a05006dSRobert Watson #ifndef MAC_STATIC
30041a17fe3SRobert Watson 	mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
30141a17fe3SRobert Watson 	cv_init(&mac_policy_cv, "mac_policy_cv");
3020a05006dSRobert Watson #endif
30395fab37eSRobert Watson }
30495fab37eSRobert Watson 
30595fab37eSRobert Watson /*
30695fab37eSRobert Watson  * For the purposes of modules that want to know if they were loaded
30795fab37eSRobert Watson  * "early", set the mac_late flag once we've processed modules either
30895fab37eSRobert Watson  * linked into the kernel, or loaded before the kernel startup.
30995fab37eSRobert Watson  */
31095fab37eSRobert Watson static void
31195fab37eSRobert Watson mac_late_init(void)
31295fab37eSRobert Watson {
31395fab37eSRobert Watson 
31495fab37eSRobert Watson 	mac_late = 1;
31595fab37eSRobert Watson }
31695fab37eSRobert Watson 
31795fab37eSRobert Watson /*
318225bff6fSRobert Watson  * After the policy list has changed, walk the list to update any global
31919c3e120SRobert Watson  * flags.  Currently, we support only one flag, and it's conditionally
32019c3e120SRobert Watson  * defined; as a result, the entire function is conditional.  Eventually,
32119c3e120SRobert Watson  * the #else case might also iterate across the policies.
322225bff6fSRobert Watson  */
323225bff6fSRobert Watson static void
324225bff6fSRobert Watson mac_policy_updateflags(void)
325225bff6fSRobert Watson {
326225bff6fSRobert Watson #ifndef MAC_ALWAYS_LABEL_MBUF
32719c3e120SRobert Watson 	struct mac_policy_conf *tmpc;
328225bff6fSRobert Watson 	int labelmbufs;
329225bff6fSRobert Watson 
33041a17fe3SRobert Watson 	mac_policy_assert_exclusive();
331225bff6fSRobert Watson 
332225bff6fSRobert Watson 	labelmbufs = 0;
33341a17fe3SRobert Watson 	LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
33441a17fe3SRobert Watson 		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
33541a17fe3SRobert Watson 			labelmbufs++;
33641a17fe3SRobert Watson 	}
337225bff6fSRobert Watson 	LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
338225bff6fSRobert Watson 		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
339225bff6fSRobert Watson 			labelmbufs++;
340225bff6fSRobert Watson 	}
341225bff6fSRobert Watson 	mac_labelmbufs = (labelmbufs != 0);
342225bff6fSRobert Watson #endif
343225bff6fSRobert Watson }
344225bff6fSRobert Watson 
345225bff6fSRobert Watson /*
34695fab37eSRobert Watson  * Allow MAC policy modules to register during boot, etc.
34795fab37eSRobert Watson  */
34895fab37eSRobert Watson int
34995fab37eSRobert Watson mac_policy_modevent(module_t mod, int type, void *data)
35095fab37eSRobert Watson {
35195fab37eSRobert Watson 	struct mac_policy_conf *mpc;
35295fab37eSRobert Watson 	int error;
35395fab37eSRobert Watson 
35495fab37eSRobert Watson 	error = 0;
35595fab37eSRobert Watson 	mpc = (struct mac_policy_conf *) data;
35695fab37eSRobert Watson 
3570a05006dSRobert Watson #ifdef MAC_STATIC
3580a05006dSRobert Watson 	if (mac_late) {
3590a05006dSRobert Watson 		printf("mac_policy_modevent: MAC_STATIC and late\n");
3600a05006dSRobert Watson 		return (EBUSY);
3610a05006dSRobert Watson 	}
3620a05006dSRobert Watson #endif
3630a05006dSRobert Watson 
36495fab37eSRobert Watson 	switch (type) {
36595fab37eSRobert Watson 	case MOD_LOAD:
36695fab37eSRobert Watson 		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
36795fab37eSRobert Watson 		    mac_late) {
36895fab37eSRobert Watson 			printf("mac_policy_modevent: can't load %s policy "
36995fab37eSRobert Watson 			    "after booting\n", mpc->mpc_name);
37095fab37eSRobert Watson 			error = EBUSY;
37195fab37eSRobert Watson 			break;
37295fab37eSRobert Watson 		}
37395fab37eSRobert Watson 		error = mac_policy_register(mpc);
37495fab37eSRobert Watson 		break;
37595fab37eSRobert Watson 	case MOD_UNLOAD:
37695fab37eSRobert Watson 		/* Don't unregister the module if it was never registered. */
37795fab37eSRobert Watson 		if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
37895fab37eSRobert Watson 		    != 0)
37995fab37eSRobert Watson 			error = mac_policy_unregister(mpc);
38095fab37eSRobert Watson 		else
38195fab37eSRobert Watson 			error = 0;
38295fab37eSRobert Watson 		break;
38395fab37eSRobert Watson 	default:
3843e019deaSPoul-Henning Kamp 		error = EOPNOTSUPP;
38595fab37eSRobert Watson 		break;
38695fab37eSRobert Watson 	}
38795fab37eSRobert Watson 
38895fab37eSRobert Watson 	return (error);
38995fab37eSRobert Watson }
39095fab37eSRobert Watson 
39195fab37eSRobert Watson static int
39295fab37eSRobert Watson mac_policy_register(struct mac_policy_conf *mpc)
39395fab37eSRobert Watson {
39495fab37eSRobert Watson 	struct mac_policy_conf *tmpc;
39541a17fe3SRobert Watson 	int error, slot, static_entry;
39695fab37eSRobert Watson 
39741a17fe3SRobert Watson 	error = 0;
39841a17fe3SRobert Watson 
39941a17fe3SRobert Watson 	/*
40041a17fe3SRobert Watson 	 * We don't technically need exclusive access while !mac_late,
40141a17fe3SRobert Watson 	 * but hold it for assertion consistency.
40241a17fe3SRobert Watson 	 */
40341a17fe3SRobert Watson 	mac_policy_grab_exclusive();
40441a17fe3SRobert Watson 
40541a17fe3SRobert Watson 	/*
40641a17fe3SRobert Watson 	 * If the module can potentially be unloaded, or we're loading
40741a17fe3SRobert Watson 	 * late, we have to stick it in the non-static list and pay
40841a17fe3SRobert Watson 	 * an extra performance overhead.  Otherwise, we can pay a
40941a17fe3SRobert Watson 	 * light locking cost and stick it in the static list.
41041a17fe3SRobert Watson 	 */
41141a17fe3SRobert Watson 	static_entry = (!mac_late &&
41241a17fe3SRobert Watson 	    !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
41341a17fe3SRobert Watson 
41441a17fe3SRobert Watson 	if (static_entry) {
41541a17fe3SRobert Watson 		LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
41641a17fe3SRobert Watson 			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
41741a17fe3SRobert Watson 				error = EEXIST;
41841a17fe3SRobert Watson 				goto out;
41941a17fe3SRobert Watson 			}
42041a17fe3SRobert Watson 		}
42141a17fe3SRobert Watson 	} else {
42295fab37eSRobert Watson 		LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
42395fab37eSRobert Watson 			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
42441a17fe3SRobert Watson 				error = EEXIST;
42541a17fe3SRobert Watson 				goto out;
42641a17fe3SRobert Watson 			}
42795fab37eSRobert Watson 		}
42895fab37eSRobert Watson 	}
42995fab37eSRobert Watson 	if (mpc->mpc_field_off != NULL) {
430b2aef571SRobert Watson 		slot = ffs(mac_slot_offsets_free);
43195fab37eSRobert Watson 		if (slot == 0) {
43241a17fe3SRobert Watson 			error = ENOMEM;
43341a17fe3SRobert Watson 			goto out;
43495fab37eSRobert Watson 		}
43595fab37eSRobert Watson 		slot--;
436b2aef571SRobert Watson 		mac_slot_offsets_free &= ~(1 << slot);
43795fab37eSRobert Watson 		*mpc->mpc_field_off = slot;
43895fab37eSRobert Watson 	}
43995fab37eSRobert Watson 	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
44041a17fe3SRobert Watson 
44141a17fe3SRobert Watson 	/*
44241a17fe3SRobert Watson 	 * If we're loading a MAC module after the framework has
44341a17fe3SRobert Watson 	 * initialized, it has to go into the dynamic list.  If
44441a17fe3SRobert Watson 	 * we're loading it before we've finished initializing,
44541a17fe3SRobert Watson 	 * it can go into the static list with weaker locker
44641a17fe3SRobert Watson 	 * requirements.
44741a17fe3SRobert Watson 	 */
44841a17fe3SRobert Watson 	if (static_entry)
44941a17fe3SRobert Watson 		LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
45041a17fe3SRobert Watson 	else
45195fab37eSRobert Watson 		LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
45295fab37eSRobert Watson 
45395fab37eSRobert Watson 	/* Per-policy initialization. */
45495fab37eSRobert Watson 	if (mpc->mpc_ops->mpo_init != NULL)
45595fab37eSRobert Watson 		(*(mpc->mpc_ops->mpo_init))(mpc);
456225bff6fSRobert Watson 	mac_policy_updateflags();
45795fab37eSRobert Watson 
45895fab37eSRobert Watson 	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
45995fab37eSRobert Watson 	    mpc->mpc_name);
46095fab37eSRobert Watson 
46141a17fe3SRobert Watson out:
46241a17fe3SRobert Watson 	mac_policy_release_exclusive();
46341a17fe3SRobert Watson 	return (error);
46495fab37eSRobert Watson }
46595fab37eSRobert Watson 
46695fab37eSRobert Watson static int
46795fab37eSRobert Watson mac_policy_unregister(struct mac_policy_conf *mpc)
46895fab37eSRobert Watson {
46995fab37eSRobert Watson 
470ea599aa0SRobert Watson 	/*
471ea599aa0SRobert Watson 	 * If we fail the load, we may get a request to unload.  Check
472ea599aa0SRobert Watson 	 * to see if we did the run-time registration, and if not,
473ea599aa0SRobert Watson 	 * silently succeed.
474ea599aa0SRobert Watson 	 */
47541a17fe3SRobert Watson 	mac_policy_grab_exclusive();
476ea599aa0SRobert Watson 	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
47741a17fe3SRobert Watson 		mac_policy_release_exclusive();
478ea599aa0SRobert Watson 		return (0);
479ea599aa0SRobert Watson 	}
48095fab37eSRobert Watson #if 0
48195fab37eSRobert Watson 	/*
48295fab37eSRobert Watson 	 * Don't allow unloading modules with private data.
48395fab37eSRobert Watson 	 */
484ea599aa0SRobert Watson 	if (mpc->mpc_field_off != NULL) {
485ea599aa0SRobert Watson 		MAC_POLICY_LIST_UNLOCK();
48695fab37eSRobert Watson 		return (EBUSY);
487ea599aa0SRobert Watson 	}
48895fab37eSRobert Watson #endif
489ea599aa0SRobert Watson 	/*
490ea599aa0SRobert Watson 	 * Only allow the unload to proceed if the module is unloadable
491ea599aa0SRobert Watson 	 * by its own definition.
492ea599aa0SRobert Watson 	 */
493ea599aa0SRobert Watson 	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
49441a17fe3SRobert Watson 		mac_policy_release_exclusive();
49595fab37eSRobert Watson 		return (EBUSY);
496ea599aa0SRobert Watson 	}
49795fab37eSRobert Watson 	if (mpc->mpc_ops->mpo_destroy != NULL)
49895fab37eSRobert Watson 		(*(mpc->mpc_ops->mpo_destroy))(mpc);
49995fab37eSRobert Watson 
50095fab37eSRobert Watson 	LIST_REMOVE(mpc, mpc_list);
5019aeffb2bSRobert Watson 	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
502225bff6fSRobert Watson 	mac_policy_updateflags();
50341a17fe3SRobert Watson 
50441a17fe3SRobert Watson 	mac_policy_release_exclusive();
505a96acd1aSRobert Watson 
50695fab37eSRobert Watson 	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
50795fab37eSRobert Watson 	    mpc->mpc_name);
50895fab37eSRobert Watson 
50995fab37eSRobert Watson 	return (0);
51095fab37eSRobert Watson }
51195fab37eSRobert Watson 
51295fab37eSRobert Watson /*
51395fab37eSRobert Watson  * Define an error value precedence, and given two arguments, selects the
51495fab37eSRobert Watson  * value with the higher precedence.
51595fab37eSRobert Watson  */
5169e7bf51cSRobert Watson int
5179e7bf51cSRobert Watson mac_error_select(int error1, int error2)
51895fab37eSRobert Watson {
51995fab37eSRobert Watson 
52095fab37eSRobert Watson 	/* Certain decision-making errors take top priority. */
52195fab37eSRobert Watson 	if (error1 == EDEADLK || error2 == EDEADLK)
52295fab37eSRobert Watson 		return (EDEADLK);
52395fab37eSRobert Watson 
52495fab37eSRobert Watson 	/* Invalid arguments should be reported where possible. */
52595fab37eSRobert Watson 	if (error1 == EINVAL || error2 == EINVAL)
52695fab37eSRobert Watson 		return (EINVAL);
52795fab37eSRobert Watson 
52895fab37eSRobert Watson 	/* Precedence goes to "visibility", with both process and file. */
52995fab37eSRobert Watson 	if (error1 == ESRCH || error2 == ESRCH)
53095fab37eSRobert Watson 		return (ESRCH);
53195fab37eSRobert Watson 
53295fab37eSRobert Watson 	if (error1 == ENOENT || error2 == ENOENT)
53395fab37eSRobert Watson 		return (ENOENT);
53495fab37eSRobert Watson 
53595fab37eSRobert Watson 	/* Precedence goes to DAC/MAC protections. */
53695fab37eSRobert Watson 	if (error1 == EACCES || error2 == EACCES)
53795fab37eSRobert Watson 		return (EACCES);
53895fab37eSRobert Watson 
53995fab37eSRobert Watson 	/* Precedence goes to privilege. */
54095fab37eSRobert Watson 	if (error1 == EPERM || error2 == EPERM)
54195fab37eSRobert Watson 		return (EPERM);
54295fab37eSRobert Watson 
54395fab37eSRobert Watson 	/* Precedence goes to error over success; otherwise, arbitrary. */
54495fab37eSRobert Watson 	if (error1 != 0)
54595fab37eSRobert Watson 		return (error1);
54695fab37eSRobert Watson 	return (error2);
54795fab37eSRobert Watson }
54895fab37eSRobert Watson 
5496fa0475dSRobert Watson void
55008bcdc58SRobert Watson mac_init_label(struct label *label)
55108bcdc58SRobert Watson {
55208bcdc58SRobert Watson 
55308bcdc58SRobert Watson 	bzero(label, sizeof(*label));
55408bcdc58SRobert Watson 	label->l_flags = MAC_FLAG_INITIALIZED;
55508bcdc58SRobert Watson }
55608bcdc58SRobert Watson 
5576fa0475dSRobert Watson void
55808bcdc58SRobert Watson mac_destroy_label(struct label *label)
55908bcdc58SRobert Watson {
56008bcdc58SRobert Watson 
56108bcdc58SRobert Watson 	KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
56208bcdc58SRobert Watson 	    ("destroying uninitialized label"));
56308bcdc58SRobert Watson 
56408bcdc58SRobert Watson 	bzero(label, sizeof(*label));
56508bcdc58SRobert Watson 	/* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
56608bcdc58SRobert Watson }
56708bcdc58SRobert Watson 
5685e7ce478SRobert Watson int
569f7b951a8SRobert Watson mac_check_structmac_consistent(struct mac *mac)
570f7b951a8SRobert Watson {
571f7b951a8SRobert Watson 
572cc7b13bfSRobert Watson 	if (mac->m_buflen < 0 ||
573cc7b13bfSRobert Watson 	    mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
574f7b951a8SRobert Watson 		return (EINVAL);
575f7b951a8SRobert Watson 
576f7b951a8SRobert Watson 	return (0);
577f7b951a8SRobert Watson }
578f7b951a8SRobert Watson 
579f0ab0442SRobert Watson /*
580f0ab0442SRobert Watson  * MPSAFE
581f0ab0442SRobert Watson  */
582f7b951a8SRobert Watson int
583f7b951a8SRobert Watson __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
584f7b951a8SRobert Watson {
585f7b951a8SRobert Watson 	char *elements, *buffer;
586f7b951a8SRobert Watson 	struct mac mac;
587f7b951a8SRobert Watson 	struct proc *tproc;
588f7b951a8SRobert Watson 	struct ucred *tcred;
589f7b951a8SRobert Watson 	int error;
590f7b951a8SRobert Watson 
591d1e405c5SAlfred Perlstein 	error = copyin(uap->mac_p, &mac, sizeof(mac));
592f7b951a8SRobert Watson 	if (error)
593f7b951a8SRobert Watson 		return (error);
594f7b951a8SRobert Watson 
595f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
596f7b951a8SRobert Watson 	if (error)
597f7b951a8SRobert Watson 		return (error);
598f7b951a8SRobert Watson 
599f7b951a8SRobert Watson 	tproc = pfind(uap->pid);
600f7b951a8SRobert Watson 	if (tproc == NULL)
601f7b951a8SRobert Watson 		return (ESRCH);
602f7b951a8SRobert Watson 
603f7b951a8SRobert Watson 	tcred = NULL;				/* Satisfy gcc. */
604f7b951a8SRobert Watson 	error = p_cansee(td, tproc);
605f7b951a8SRobert Watson 	if (error == 0)
606f7b951a8SRobert Watson 		tcred = crhold(tproc->p_ucred);
607f7b951a8SRobert Watson 	PROC_UNLOCK(tproc);
608f7b951a8SRobert Watson 	if (error)
609f7b951a8SRobert Watson 		return (error);
610f7b951a8SRobert Watson 
611a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
612f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
613f7b951a8SRobert Watson 	if (error) {
614f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
615f7b951a8SRobert Watson 		crfree(tcred);
616f7b951a8SRobert Watson 		return (error);
617f7b951a8SRobert Watson 	}
618f7b951a8SRobert Watson 
619a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
620eca8a663SRobert Watson 	error = mac_externalize_cred_label(tcred->cr_label, elements,
62183b7b0edSRobert Watson 	    buffer, mac.m_buflen);
622f7b951a8SRobert Watson 	if (error == 0)
623f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
624f7b951a8SRobert Watson 
625f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
626f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
627f7b951a8SRobert Watson 	crfree(tcred);
628f7b951a8SRobert Watson 	return (error);
629f7b951a8SRobert Watson }
630f7b951a8SRobert Watson 
63195fab37eSRobert Watson /*
63295fab37eSRobert Watson  * MPSAFE
63395fab37eSRobert Watson  */
63495fab37eSRobert Watson int
63595fab37eSRobert Watson __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
63695fab37eSRobert Watson {
637f7b951a8SRobert Watson 	char *elements, *buffer;
638f7b951a8SRobert Watson 	struct mac mac;
63995fab37eSRobert Watson 	int error;
64095fab37eSRobert Watson 
641f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
642f7b951a8SRobert Watson 	if (error)
643f7b951a8SRobert Watson 		return (error);
64495fab37eSRobert Watson 
645f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
646f7b951a8SRobert Watson 	if (error)
647f7b951a8SRobert Watson 		return (error);
648f7b951a8SRobert Watson 
649a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
650f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
651f7b951a8SRobert Watson 	if (error) {
652f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
653f7b951a8SRobert Watson 		return (error);
654f7b951a8SRobert Watson 	}
655f7b951a8SRobert Watson 
656a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
657eca8a663SRobert Watson 	error = mac_externalize_cred_label(td->td_ucred->cr_label,
65883b7b0edSRobert Watson 	    elements, buffer, mac.m_buflen);
659f7b951a8SRobert Watson 	if (error == 0)
660f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
661f7b951a8SRobert Watson 
662f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
663f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
66495fab37eSRobert Watson 	return (error);
66595fab37eSRobert Watson }
66695fab37eSRobert Watson 
66795fab37eSRobert Watson /*
66895fab37eSRobert Watson  * MPSAFE
66995fab37eSRobert Watson  */
67095fab37eSRobert Watson int
67195fab37eSRobert Watson __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
67295fab37eSRobert Watson {
67395fab37eSRobert Watson 	struct ucred *newcred, *oldcred;
674eca8a663SRobert Watson 	struct label *intlabel;
675f7b951a8SRobert Watson 	struct proc *p;
676f7b951a8SRobert Watson 	struct mac mac;
677f7b951a8SRobert Watson 	char *buffer;
67895fab37eSRobert Watson 	int error;
67995fab37eSRobert Watson 
680f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
68195fab37eSRobert Watson 	if (error)
68295fab37eSRobert Watson 		return (error);
68395fab37eSRobert Watson 
684f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
68595fab37eSRobert Watson 	if (error)
68695fab37eSRobert Watson 		return (error);
68795fab37eSRobert Watson 
688a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
689f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
690f7b951a8SRobert Watson 	if (error) {
691f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
692f7b951a8SRobert Watson 		return (error);
693f7b951a8SRobert Watson 	}
694f7b951a8SRobert Watson 
695eca8a663SRobert Watson 	intlabel = mac_cred_label_alloc();
696eca8a663SRobert Watson 	error = mac_internalize_cred_label(intlabel, buffer);
697f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
698eca8a663SRobert Watson 	if (error)
699eca8a663SRobert Watson 		goto out;
700f7b951a8SRobert Watson 
70195fab37eSRobert Watson 	newcred = crget();
70295fab37eSRobert Watson 
70395fab37eSRobert Watson 	p = td->td_proc;
70495fab37eSRobert Watson 	PROC_LOCK(p);
70595fab37eSRobert Watson 	oldcred = p->p_ucred;
70695fab37eSRobert Watson 
707eca8a663SRobert Watson 	error = mac_check_cred_relabel(oldcred, intlabel);
70895fab37eSRobert Watson 	if (error) {
70995fab37eSRobert Watson 		PROC_UNLOCK(p);
71095fab37eSRobert Watson 		crfree(newcred);
711f7b951a8SRobert Watson 		goto out;
71295fab37eSRobert Watson 	}
71395fab37eSRobert Watson 
71495fab37eSRobert Watson 	setsugid(p);
71595fab37eSRobert Watson 	crcopy(newcred, oldcred);
716eca8a663SRobert Watson 	mac_relabel_cred(newcred, intlabel);
71795fab37eSRobert Watson 	p->p_ucred = newcred;
718e5cb5e37SRobert Watson 
719e5cb5e37SRobert Watson 	/*
720e5cb5e37SRobert Watson 	 * Grab additional reference for use while revoking mmaps, prior
721e5cb5e37SRobert Watson 	 * to releasing the proc lock and sharing the cred.
722e5cb5e37SRobert Watson 	 */
723e5cb5e37SRobert Watson 	crhold(newcred);
72495fab37eSRobert Watson 	PROC_UNLOCK(p);
725e5cb5e37SRobert Watson 
726f7b951a8SRobert Watson 	if (mac_enforce_vm) {
72716140035SRobert Watson 		mtx_lock(&Giant);
728e5cb5e37SRobert Watson 		mac_cred_mmapped_drop_perms(td, newcred);
72916140035SRobert Watson 		mtx_unlock(&Giant);
730f7b951a8SRobert Watson 	}
731e5cb5e37SRobert Watson 
732e5cb5e37SRobert Watson 	crfree(newcred);	/* Free revocation reference. */
73395fab37eSRobert Watson 	crfree(oldcred);
734f7b951a8SRobert Watson 
735f7b951a8SRobert Watson out:
736eca8a663SRobert Watson 	mac_cred_label_free(intlabel);
737f7b951a8SRobert Watson 	return (error);
73895fab37eSRobert Watson }
73995fab37eSRobert Watson 
74095fab37eSRobert Watson /*
74195fab37eSRobert Watson  * MPSAFE
74295fab37eSRobert Watson  */
74395fab37eSRobert Watson int
74495fab37eSRobert Watson __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
74595fab37eSRobert Watson {
746f7b951a8SRobert Watson 	char *elements, *buffer;
747eca8a663SRobert Watson 	struct label *intlabel;
74895fab37eSRobert Watson 	struct file *fp;
749f7b951a8SRobert Watson 	struct mac mac;
75095fab37eSRobert Watson 	struct vnode *vp;
75195fab37eSRobert Watson 	struct pipe *pipe;
752b0323ea3SRobert Watson 	struct socket *so;
753f7b951a8SRobert Watson 	short label_type;
75495fab37eSRobert Watson 	int error;
75595fab37eSRobert Watson 
756f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
757f7b951a8SRobert Watson 	if (error)
758f7b951a8SRobert Watson 		return (error);
75995fab37eSRobert Watson 
760f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
761f7b951a8SRobert Watson 	if (error)
762f7b951a8SRobert Watson 		return (error);
763f7b951a8SRobert Watson 
764a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
765f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
766f7b951a8SRobert Watson 	if (error) {
767f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
768f7b951a8SRobert Watson 		return (error);
769f7b951a8SRobert Watson 	}
770f7b951a8SRobert Watson 
771a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
772d1e405c5SAlfred Perlstein 	error = fget(td, uap->fd, &fp);
77395fab37eSRobert Watson 	if (error)
77495fab37eSRobert Watson 		goto out;
77595fab37eSRobert Watson 
776f7b951a8SRobert Watson 	label_type = fp->f_type;
77795fab37eSRobert Watson 	switch (fp->f_type) {
77895fab37eSRobert Watson 	case DTYPE_FIFO:
77995fab37eSRobert Watson 	case DTYPE_VNODE:
7803b6d9652SPoul-Henning Kamp 		vp = fp->f_vnode;
781eca8a663SRobert Watson 		intlabel = mac_vnode_label_alloc();
782f0ab0442SRobert Watson 		mtx_lock(&Giant);				/* VFS */
78395fab37eSRobert Watson 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
784eca8a663SRobert Watson 		mac_copy_vnode_label(vp->v_label, intlabel);
78595fab37eSRobert Watson 		VOP_UNLOCK(vp, 0, td);
786f0ab0442SRobert Watson 		mtx_unlock(&Giant);				/* VFS */
787f0ab0442SRobert Watson 		error = mac_externalize_vnode_label(intlabel, elements,
788f0ab0442SRobert Watson 		    buffer, mac.m_buflen);
789f0ab0442SRobert Watson 		mac_vnode_label_free(intlabel);
79095fab37eSRobert Watson 		break;
791f0ab0442SRobert Watson 
79295fab37eSRobert Watson 	case DTYPE_PIPE:
79348e3128bSMatthew Dillon 		pipe = fp->f_data;
794eca8a663SRobert Watson 		intlabel = mac_pipe_label_alloc();
795f7b951a8SRobert Watson 		PIPE_LOCK(pipe);
7964795b82cSRobert Watson 		mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel);
797f7b951a8SRobert Watson 		PIPE_UNLOCK(pipe);
798eca8a663SRobert Watson 		error = mac_externalize_pipe_label(intlabel, elements,
79983b7b0edSRobert Watson 		    buffer, mac.m_buflen);
800eca8a663SRobert Watson 		mac_pipe_label_free(intlabel);
801f7b951a8SRobert Watson 		break;
80295fab37eSRobert Watson 
803b0323ea3SRobert Watson 	case DTYPE_SOCKET:
804b0323ea3SRobert Watson 		so = fp->f_data;
805b0323ea3SRobert Watson 		intlabel = mac_socket_label_alloc(M_WAITOK);
806f0c2044bSRobert Watson 		NET_LOCK_GIANT();
807f0c2044bSRobert Watson 		SOCK_LOCK(so);
808b0323ea3SRobert Watson 		mac_copy_socket_label(so->so_label, intlabel);
809f0c2044bSRobert Watson 		SOCK_UNLOCK(so);
810f0c2044bSRobert Watson 		NET_UNLOCK_GIANT();
811b0323ea3SRobert Watson 		error = mac_externalize_socket_label(intlabel, elements,
812b0323ea3SRobert Watson 		    buffer, mac.m_buflen);
813b0323ea3SRobert Watson 		mac_socket_label_free(intlabel);
814b0323ea3SRobert Watson 		break;
815b0323ea3SRobert Watson 
816f0ab0442SRobert Watson 	default:
817f0ab0442SRobert Watson 		error = EINVAL;
818f0ab0442SRobert Watson 	}
819f0ab0442SRobert Watson 	fdrop(fp, td);
82095fab37eSRobert Watson 	if (error == 0)
821f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
82295fab37eSRobert Watson 
82395fab37eSRobert Watson out:
824f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
825f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
82695fab37eSRobert Watson 	return (error);
82795fab37eSRobert Watson }
82895fab37eSRobert Watson 
82995fab37eSRobert Watson /*
83095fab37eSRobert Watson  * MPSAFE
83195fab37eSRobert Watson  */
83295fab37eSRobert Watson int
83395fab37eSRobert Watson __mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
83495fab37eSRobert Watson {
835f7b951a8SRobert Watson 	char *elements, *buffer;
83695fab37eSRobert Watson 	struct nameidata nd;
837eca8a663SRobert Watson 	struct label *intlabel;
838f7b951a8SRobert Watson 	struct mac mac;
83995fab37eSRobert Watson 	int error;
84095fab37eSRobert Watson 
841f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
842f7b951a8SRobert Watson 	if (error)
843f7b951a8SRobert Watson 		return (error);
844f7b951a8SRobert Watson 
845f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
846f7b951a8SRobert Watson 	if (error)
847f7b951a8SRobert Watson 		return (error);
848f7b951a8SRobert Watson 
849a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
850f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
851f7b951a8SRobert Watson 	if (error) {
852f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
853f7b951a8SRobert Watson 		return (error);
854f7b951a8SRobert Watson 	}
855f7b951a8SRobert Watson 
856a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
857f7b951a8SRobert Watson 	mtx_lock(&Giant);				/* VFS */
858f7b951a8SRobert Watson 	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
859f7b951a8SRobert Watson 	    td);
86095fab37eSRobert Watson 	error = namei(&nd);
86195fab37eSRobert Watson 	if (error)
86295fab37eSRobert Watson 		goto out;
86395fab37eSRobert Watson 
864eca8a663SRobert Watson 	intlabel = mac_vnode_label_alloc();
865eca8a663SRobert Watson 	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
866eca8a663SRobert Watson 	error = mac_externalize_vnode_label(intlabel, elements, buffer,
86783b7b0edSRobert Watson 	    mac.m_buflen);
868f7b951a8SRobert Watson 
86995fab37eSRobert Watson 	NDFREE(&nd, 0);
870eca8a663SRobert Watson 	mac_vnode_label_free(intlabel);
871f7b951a8SRobert Watson 
872f7b951a8SRobert Watson 	if (error == 0)
873f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
874f7b951a8SRobert Watson 
875f7b951a8SRobert Watson out:
876f7b951a8SRobert Watson 	mtx_unlock(&Giant);				/* VFS */
877f7b951a8SRobert Watson 
878f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
879f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
880f7b951a8SRobert Watson 
881f7b951a8SRobert Watson 	return (error);
882f7b951a8SRobert Watson }
883f7b951a8SRobert Watson 
884f7b951a8SRobert Watson /*
885f7b951a8SRobert Watson  * MPSAFE
886f7b951a8SRobert Watson  */
887f7b951a8SRobert Watson int
888f7b951a8SRobert Watson __mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
889f7b951a8SRobert Watson {
890f7b951a8SRobert Watson 	char *elements, *buffer;
891f7b951a8SRobert Watson 	struct nameidata nd;
892eca8a663SRobert Watson 	struct label *intlabel;
893f7b951a8SRobert Watson 	struct mac mac;
894f7b951a8SRobert Watson 	int error;
895f7b951a8SRobert Watson 
896f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
897f7b951a8SRobert Watson 	if (error)
898f7b951a8SRobert Watson 		return (error);
899f7b951a8SRobert Watson 
900f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
901f7b951a8SRobert Watson 	if (error)
902f7b951a8SRobert Watson 		return (error);
903f7b951a8SRobert Watson 
904a163d034SWarner Losh 	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
905f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
906f7b951a8SRobert Watson 	if (error) {
907f7b951a8SRobert Watson 		free(elements, M_MACTEMP);
908f7b951a8SRobert Watson 		return (error);
909f7b951a8SRobert Watson 	}
910f7b951a8SRobert Watson 
911a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
912f7b951a8SRobert Watson 	mtx_lock(&Giant);				/* VFS */
913f7b951a8SRobert Watson 	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
914f7b951a8SRobert Watson 	    td);
915f7b951a8SRobert Watson 	error = namei(&nd);
91695fab37eSRobert Watson 	if (error)
91795fab37eSRobert Watson 		goto out;
91895fab37eSRobert Watson 
919eca8a663SRobert Watson 	intlabel = mac_vnode_label_alloc();
920eca8a663SRobert Watson 	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
921eca8a663SRobert Watson 	error = mac_externalize_vnode_label(intlabel, elements, buffer,
92283b7b0edSRobert Watson 	    mac.m_buflen);
923f7b951a8SRobert Watson 	NDFREE(&nd, 0);
924eca8a663SRobert Watson 	mac_vnode_label_free(intlabel);
925f7b951a8SRobert Watson 
926f7b951a8SRobert Watson 	if (error == 0)
927f7b951a8SRobert Watson 		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
92895fab37eSRobert Watson 
92995fab37eSRobert Watson out:
930f7b951a8SRobert Watson 	mtx_unlock(&Giant);				/* VFS */
931f7b951a8SRobert Watson 
932f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
933f7b951a8SRobert Watson 	free(elements, M_MACTEMP);
934f7b951a8SRobert Watson 
93595fab37eSRobert Watson 	return (error);
93695fab37eSRobert Watson }
93795fab37eSRobert Watson 
93895fab37eSRobert Watson /*
93995fab37eSRobert Watson  * MPSAFE
94095fab37eSRobert Watson  */
94195fab37eSRobert Watson int
94295fab37eSRobert Watson __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
94395fab37eSRobert Watson {
944eca8a663SRobert Watson 	struct label *intlabel;
945f7b951a8SRobert Watson 	struct pipe *pipe;
946b0323ea3SRobert Watson 	struct socket *so;
947f7b951a8SRobert Watson 	struct file *fp;
94895fab37eSRobert Watson 	struct mount *mp;
94995fab37eSRobert Watson 	struct vnode *vp;
950f7b951a8SRobert Watson 	struct mac mac;
951f7b951a8SRobert Watson 	char *buffer;
95295fab37eSRobert Watson 	int error;
95395fab37eSRobert Watson 
954f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
955f7b951a8SRobert Watson 	if (error)
956f7b951a8SRobert Watson 		return (error);
957f7b951a8SRobert Watson 
958f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
959f7b951a8SRobert Watson 	if (error)
960f7b951a8SRobert Watson 		return (error);
961f7b951a8SRobert Watson 
962a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
963f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
964f7b951a8SRobert Watson 	if (error) {
965f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
966f7b951a8SRobert Watson 		return (error);
967f7b951a8SRobert Watson 	}
968f7b951a8SRobert Watson 
969d1e405c5SAlfred Perlstein 	error = fget(td, uap->fd, &fp);
97095fab37eSRobert Watson 	if (error)
971f7b951a8SRobert Watson 		goto out;
97295fab37eSRobert Watson 
97395fab37eSRobert Watson 	switch (fp->f_type) {
97495fab37eSRobert Watson 	case DTYPE_FIFO:
97595fab37eSRobert Watson 	case DTYPE_VNODE:
976eca8a663SRobert Watson 		intlabel = mac_vnode_label_alloc();
977eca8a663SRobert Watson 		error = mac_internalize_vnode_label(intlabel, buffer);
978f7b951a8SRobert Watson 		if (error) {
979eca8a663SRobert Watson 			mac_vnode_label_free(intlabel);
980f7b951a8SRobert Watson 			break;
981f7b951a8SRobert Watson 		}
9823b6d9652SPoul-Henning Kamp 		vp = fp->f_vnode;
983f0ab0442SRobert Watson 		mtx_lock(&Giant);				/* VFS */
98495fab37eSRobert Watson 		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
985f7b951a8SRobert Watson 		if (error != 0) {
986f0ab0442SRobert Watson 			mtx_unlock(&Giant);			/* VFS */
987eca8a663SRobert Watson 			mac_vnode_label_free(intlabel);
98895fab37eSRobert Watson 			break;
989f7b951a8SRobert Watson 		}
99095fab37eSRobert Watson 		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
991eca8a663SRobert Watson 		error = vn_setlabel(vp, intlabel, td->td_ucred);
99295fab37eSRobert Watson 		VOP_UNLOCK(vp, 0, td);
99395fab37eSRobert Watson 		vn_finished_write(mp);
994f0ab0442SRobert Watson 		mtx_unlock(&Giant);				/* VFS */
995eca8a663SRobert Watson 		mac_vnode_label_free(intlabel);
99695fab37eSRobert Watson 		break;
997f7b951a8SRobert Watson 
99895fab37eSRobert Watson 	case DTYPE_PIPE:
999eca8a663SRobert Watson 		intlabel = mac_pipe_label_alloc();
1000eca8a663SRobert Watson 		error = mac_internalize_pipe_label(intlabel, buffer);
1001f7b951a8SRobert Watson 		if (error == 0) {
100248e3128bSMatthew Dillon 			pipe = fp->f_data;
10031aa37f53SRobert Watson 			PIPE_LOCK(pipe);
10044795b82cSRobert Watson 			error = mac_pipe_label_set(td->td_ucred,
10054795b82cSRobert Watson 			    pipe->pipe_pair, intlabel);
10061aa37f53SRobert Watson 			PIPE_UNLOCK(pipe);
1007f7b951a8SRobert Watson 		}
1008eca8a663SRobert Watson 		mac_pipe_label_free(intlabel);
100995fab37eSRobert Watson 		break;
1010f7b951a8SRobert Watson 
1011b0323ea3SRobert Watson 	case DTYPE_SOCKET:
1012b0323ea3SRobert Watson 		intlabel = mac_socket_label_alloc(M_WAITOK);
1013b0323ea3SRobert Watson 		error = mac_internalize_socket_label(intlabel, buffer);
1014b0323ea3SRobert Watson 		if (error == 0) {
1015b0323ea3SRobert Watson 			so = fp->f_data;
1016f0c2044bSRobert Watson 			NET_LOCK_GIANT();
1017b0323ea3SRobert Watson 			error = mac_socket_label_set(td->td_ucred, so,
1018b0323ea3SRobert Watson 			    intlabel);
1019f0c2044bSRobert Watson 			NET_UNLOCK_GIANT();
1020b0323ea3SRobert Watson 		}
1021b0323ea3SRobert Watson 		mac_socket_label_free(intlabel);
1022b0323ea3SRobert Watson 		break;
1023b0323ea3SRobert Watson 
102495fab37eSRobert Watson 	default:
102595fab37eSRobert Watson 		error = EINVAL;
102695fab37eSRobert Watson 	}
102795fab37eSRobert Watson 	fdrop(fp, td);
1028f7b951a8SRobert Watson out:
1029f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
103095fab37eSRobert Watson 	return (error);
103195fab37eSRobert Watson }
103295fab37eSRobert Watson 
103395fab37eSRobert Watson /*
103495fab37eSRobert Watson  * MPSAFE
103595fab37eSRobert Watson  */
103695fab37eSRobert Watson int
103795fab37eSRobert Watson __mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
103895fab37eSRobert Watson {
1039eca8a663SRobert Watson 	struct label *intlabel;
1040f7b951a8SRobert Watson 	struct nameidata nd;
104195fab37eSRobert Watson 	struct mount *mp;
1042f7b951a8SRobert Watson 	struct mac mac;
1043f7b951a8SRobert Watson 	char *buffer;
104495fab37eSRobert Watson 	int error;
104595fab37eSRobert Watson 
1046f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
104795fab37eSRobert Watson 	if (error)
1048f7b951a8SRobert Watson 		return (error);
104995fab37eSRobert Watson 
1050f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
105195fab37eSRobert Watson 	if (error)
1052f7b951a8SRobert Watson 		return (error);
105395fab37eSRobert Watson 
1054a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1055f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1056f7b951a8SRobert Watson 	if (error) {
1057f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
105895fab37eSRobert Watson 		return (error);
105995fab37eSRobert Watson 	}
106095fab37eSRobert Watson 
1061eca8a663SRobert Watson 	intlabel = mac_vnode_label_alloc();
1062eca8a663SRobert Watson 	error = mac_internalize_vnode_label(intlabel, buffer);
1063f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
1064eca8a663SRobert Watson 	if (error)
1065eca8a663SRobert Watson 		goto out;
1066f7b951a8SRobert Watson 
1067f7b951a8SRobert Watson 	mtx_lock(&Giant);				/* VFS */
1068f7b951a8SRobert Watson 
1069f7b951a8SRobert Watson 	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
1070f7b951a8SRobert Watson 	    td);
1071f7b951a8SRobert Watson 	error = namei(&nd);
1072f7b951a8SRobert Watson 	if (error == 0) {
1073f7b951a8SRobert Watson 		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1074f7b951a8SRobert Watson 		if (error == 0)
1075eca8a663SRobert Watson 			error = vn_setlabel(nd.ni_vp, intlabel,
1076f7b951a8SRobert Watson 			    td->td_ucred);
1077f7b951a8SRobert Watson 		vn_finished_write(mp);
1078f7b951a8SRobert Watson 	}
1079f7b951a8SRobert Watson 
1080f7b951a8SRobert Watson 	NDFREE(&nd, 0);
1081f7b951a8SRobert Watson 	mtx_unlock(&Giant);				/* VFS */
1082eca8a663SRobert Watson out:
1083eca8a663SRobert Watson 	mac_vnode_label_free(intlabel);
1084f7b951a8SRobert Watson 	return (error);
1085f7b951a8SRobert Watson }
1086f7b951a8SRobert Watson 
1087f7b951a8SRobert Watson /*
1088f7b951a8SRobert Watson  * MPSAFE
1089f7b951a8SRobert Watson  */
1090f7b951a8SRobert Watson int
1091f7b951a8SRobert Watson __mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1092f7b951a8SRobert Watson {
1093eca8a663SRobert Watson 	struct label *intlabel;
1094f7b951a8SRobert Watson 	struct nameidata nd;
1095f7b951a8SRobert Watson 	struct mount *mp;
1096f7b951a8SRobert Watson 	struct mac mac;
1097f7b951a8SRobert Watson 	char *buffer;
1098f7b951a8SRobert Watson 	int error;
1099f7b951a8SRobert Watson 
1100f7b951a8SRobert Watson 	error = copyin(uap->mac_p, &mac, sizeof(mac));
1101f7b951a8SRobert Watson 	if (error)
1102f7b951a8SRobert Watson 		return (error);
1103f7b951a8SRobert Watson 
1104f7b951a8SRobert Watson 	error = mac_check_structmac_consistent(&mac);
1105f7b951a8SRobert Watson 	if (error)
1106f7b951a8SRobert Watson 		return (error);
1107f7b951a8SRobert Watson 
1108a163d034SWarner Losh 	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1109f7b951a8SRobert Watson 	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1110f7b951a8SRobert Watson 	if (error) {
1111f7b951a8SRobert Watson 		free(buffer, M_MACTEMP);
1112f7b951a8SRobert Watson 		return (error);
1113f7b951a8SRobert Watson 	}
1114f7b951a8SRobert Watson 
1115eca8a663SRobert Watson 	intlabel = mac_vnode_label_alloc();
1116eca8a663SRobert Watson 	error = mac_internalize_vnode_label(intlabel, buffer);
1117f7b951a8SRobert Watson 	free(buffer, M_MACTEMP);
1118eca8a663SRobert Watson 	if (error)
1119eca8a663SRobert Watson 		goto out;
1120f7b951a8SRobert Watson 
1121f7b951a8SRobert Watson 	mtx_lock(&Giant);				/* VFS */
1122f7b951a8SRobert Watson 
1123f7b951a8SRobert Watson 	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
1124f7b951a8SRobert Watson 	    td);
1125f7b951a8SRobert Watson 	error = namei(&nd);
1126f7b951a8SRobert Watson 	if (error == 0) {
1127f7b951a8SRobert Watson 		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1128f7b951a8SRobert Watson 		if (error == 0)
1129eca8a663SRobert Watson 			error = vn_setlabel(nd.ni_vp, intlabel,
1130f7b951a8SRobert Watson 			    td->td_ucred);
1131f7b951a8SRobert Watson 		vn_finished_write(mp);
1132f7b951a8SRobert Watson 	}
1133f7b951a8SRobert Watson 
1134f7b951a8SRobert Watson 	NDFREE(&nd, 0);
1135f7b951a8SRobert Watson 	mtx_unlock(&Giant);				/* VFS */
1136eca8a663SRobert Watson out:
1137eca8a663SRobert Watson 	mac_vnode_label_free(intlabel);
1138f7b951a8SRobert Watson 	return (error);
1139f7b951a8SRobert Watson }
1140f7b951a8SRobert Watson 
1141f7b951a8SRobert Watson /*
1142f7b951a8SRobert Watson  * MPSAFE
1143f7b951a8SRobert Watson  */
114427f2eac7SRobert Watson int
114527f2eac7SRobert Watson mac_syscall(struct thread *td, struct mac_syscall_args *uap)
114627f2eac7SRobert Watson {
114727f2eac7SRobert Watson 	struct mac_policy_conf *mpc;
114827f2eac7SRobert Watson 	char target[MAC_MAX_POLICY_NAME];
114941a17fe3SRobert Watson 	int entrycount, error;
115027f2eac7SRobert Watson 
1151d1e405c5SAlfred Perlstein 	error = copyinstr(uap->policy, target, sizeof(target), NULL);
115227f2eac7SRobert Watson 	if (error)
115327f2eac7SRobert Watson 		return (error);
115427f2eac7SRobert Watson 
115527f2eac7SRobert Watson 	error = ENOSYS;
1156a6a65b05SRobert Watson 	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
115727f2eac7SRobert Watson 		if (strcmp(mpc->mpc_name, target) == 0 &&
115827f2eac7SRobert Watson 		    mpc->mpc_ops->mpo_syscall != NULL) {
115927f2eac7SRobert Watson 			error = mpc->mpc_ops->mpo_syscall(td,
1160d1e405c5SAlfred Perlstein 			    uap->call, uap->arg);
116127f2eac7SRobert Watson 			goto out;
116227f2eac7SRobert Watson 		}
116327f2eac7SRobert Watson 	}
116427f2eac7SRobert Watson 
116541a17fe3SRobert Watson 	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
116641a17fe3SRobert Watson 		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
116741a17fe3SRobert Watson 			if (strcmp(mpc->mpc_name, target) == 0 &&
116841a17fe3SRobert Watson 			    mpc->mpc_ops->mpo_syscall != NULL) {
116941a17fe3SRobert Watson 				error = mpc->mpc_ops->mpo_syscall(td,
117041a17fe3SRobert Watson 				    uap->call, uap->arg);
117141a17fe3SRobert Watson 				break;
117241a17fe3SRobert Watson 			}
117341a17fe3SRobert Watson 		}
117441a17fe3SRobert Watson 		mac_policy_list_unbusy();
117541a17fe3SRobert Watson 	}
117627f2eac7SRobert Watson out:
117727f2eac7SRobert Watson 	return (error);
117827f2eac7SRobert Watson }
117927f2eac7SRobert Watson 
118095fab37eSRobert Watson SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
118195fab37eSRobert Watson SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
118295fab37eSRobert Watson 
118395fab37eSRobert Watson #else /* !MAC */
11847bc82500SRobert Watson 
11857bc82500SRobert Watson int
1186f7b951a8SRobert Watson __mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1187f7b951a8SRobert Watson {
1188f7b951a8SRobert Watson 
1189f7b951a8SRobert Watson 	return (ENOSYS);
1190f7b951a8SRobert Watson }
1191f7b951a8SRobert Watson 
1192f7b951a8SRobert Watson int
11937bc82500SRobert Watson __mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
11947bc82500SRobert Watson {
11957bc82500SRobert Watson 
11967bc82500SRobert Watson 	return (ENOSYS);
11977bc82500SRobert Watson }
11987bc82500SRobert Watson 
11997bc82500SRobert Watson int
12007bc82500SRobert Watson __mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
12017bc82500SRobert Watson {
12027bc82500SRobert Watson 
12037bc82500SRobert Watson 	return (ENOSYS);
12047bc82500SRobert Watson }
12057bc82500SRobert Watson 
12067bc82500SRobert Watson int
12077bc82500SRobert Watson __mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
12087bc82500SRobert Watson {
12097bc82500SRobert Watson 
12107bc82500SRobert Watson 	return (ENOSYS);
12117bc82500SRobert Watson }
12127bc82500SRobert Watson 
12137bc82500SRobert Watson int
12147bc82500SRobert Watson __mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
12157bc82500SRobert Watson {
12167bc82500SRobert Watson 
12177bc82500SRobert Watson 	return (ENOSYS);
12187bc82500SRobert Watson }
12197bc82500SRobert Watson 
12207bc82500SRobert Watson int
1221f7b951a8SRobert Watson __mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1222f7b951a8SRobert Watson {
1223f7b951a8SRobert Watson 
1224f7b951a8SRobert Watson 	return (ENOSYS);
1225f7b951a8SRobert Watson }
1226f7b951a8SRobert Watson 
1227f7b951a8SRobert Watson int
12287bc82500SRobert Watson __mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
12297bc82500SRobert Watson {
12307bc82500SRobert Watson 
12317bc82500SRobert Watson 	return (ENOSYS);
12327bc82500SRobert Watson }
12337bc82500SRobert Watson 
12347bc82500SRobert Watson int
12357bc82500SRobert Watson __mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
12367bc82500SRobert Watson {
12377bc82500SRobert Watson 
12387bc82500SRobert Watson 	return (ENOSYS);
12397bc82500SRobert Watson }
124095fab37eSRobert Watson 
124127f2eac7SRobert Watson int
1242f7b951a8SRobert Watson __mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1243f7b951a8SRobert Watson {
1244f7b951a8SRobert Watson 
1245f7b951a8SRobert Watson 	return (ENOSYS);
1246f7b951a8SRobert Watson }
1247f7b951a8SRobert Watson 
1248f7b951a8SRobert Watson int
124927f2eac7SRobert Watson mac_syscall(struct thread *td, struct mac_syscall_args *uap)
125027f2eac7SRobert Watson {
125127f2eac7SRobert Watson 
125227f2eac7SRobert Watson 	return (ENOSYS);
125327f2eac7SRobert Watson }
125427f2eac7SRobert Watson 
125519b78822SRobert Watson #endif /* !MAC */
1256