mac_framework.c revision 122454
1100894Srwatson/*-
2100894Srwatson * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
3100894Srwatson * Copyright (c) 2001 Ilmar S. Habibulin
4113681Srwatson * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc.
5100894Srwatson * All rights reserved.
6100894Srwatson *
7100894Srwatson * This software was developed by Robert Watson and Ilmar Habibulin for the
8100894Srwatson * TrustedBSD Project.
9100894Srwatson *
10106392Srwatson * This software was developed for the FreeBSD Project in part by Network
11106392Srwatson * Associates Laboratories, the Security Research Division of Network
12106392Srwatson * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13106392Srwatson * as part of the DARPA CHATS research program.
14100894Srwatson *
15100894Srwatson * Redistribution and use in source and binary forms, with or without
16100894Srwatson * modification, are permitted provided that the following conditions
17100894Srwatson * are met:
18100894Srwatson * 1. Redistributions of source code must retain the above copyright
19100894Srwatson *    notice, this list of conditions and the following disclaimer.
20100894Srwatson * 2. Redistributions in binary form must reproduce the above copyright
21100894Srwatson *    notice, this list of conditions and the following disclaimer in the
22100894Srwatson *    documentation and/or other materials provided with the distribution.
23100894Srwatson *
24100894Srwatson * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25100894Srwatson * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26100894Srwatson * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27100894Srwatson * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28100894Srwatson * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29100894Srwatson * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30100894Srwatson * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31100894Srwatson * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32100894Srwatson * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33100894Srwatson * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34100894Srwatson * SUCH DAMAGE.
35100894Srwatson */
36116182Sobrien
37122454Srwatson/*-
38122454Srwatson * Framework for extensible kernel access control.  This file contains
39122454Srwatson * Kernel and userland interface to the framework, policy registration
40122454Srwatson * and composition.  Per-object interfaces, controls, and labeling may be
41122454Srwatson * found in src/sys/mac/.  Sample policies may be found in src/sys/mac*.
42100894Srwatson */
43100894Srwatson
44116182Sobrien#include <sys/cdefs.h>
45116182Sobrien__FBSDID("$FreeBSD: head/sys/security/mac/mac_framework.c 122454 2003-11-11 03:40:04Z rwatson $");
46116182Sobrien
47100894Srwatson#include "opt_mac.h"
48104300Sphk#include "opt_devfs.h"
49101173Srwatson
50100894Srwatson#include <sys/param.h>
51106856Srwatson#include <sys/condvar.h>
52100979Srwatson#include <sys/extattr.h>
53106468Srwatson#include <sys/imgact.h>
54100979Srwatson#include <sys/kernel.h>
55100979Srwatson#include <sys/lock.h>
56102949Sbde#include <sys/malloc.h>
57100979Srwatson#include <sys/mutex.h>
58100979Srwatson#include <sys/mac.h>
59101712Srwatson#include <sys/module.h>
60100979Srwatson#include <sys/proc.h>
61116701Srwatson#include <sys/sbuf.h>
62100979Srwatson#include <sys/systm.h>
63100894Srwatson#include <sys/sysproto.h>
64100894Srwatson#include <sys/sysent.h>
65100979Srwatson#include <sys/vnode.h>
66100979Srwatson#include <sys/mount.h>
67100979Srwatson#include <sys/file.h>
68100979Srwatson#include <sys/namei.h>
69100979Srwatson#include <sys/socket.h>
70100979Srwatson#include <sys/pipe.h>
71100979Srwatson#include <sys/socketvar.h>
72100979Srwatson#include <sys/sysctl.h>
73100894Srwatson
74100979Srwatson#include <vm/vm.h>
75100979Srwatson#include <vm/pmap.h>
76100979Srwatson#include <vm/vm_map.h>
77100979Srwatson#include <vm/vm_object.h>
78100979Srwatson
79100979Srwatson#include <sys/mac_policy.h>
80100979Srwatson
81100979Srwatson#include <fs/devfs/devfs.h>
82100979Srwatson
83100979Srwatson#include <net/bpfdesc.h>
84100979Srwatson#include <net/if.h>
85100979Srwatson#include <net/if_var.h>
86100979Srwatson
87100979Srwatson#include <netinet/in.h>
88100979Srwatson#include <netinet/ip_var.h>
89100979Srwatson
90121374Srwatson#include <security/mac/mac_internal.h>
91121374Srwatson
92100979Srwatson#ifdef MAC
93100979Srwatson
94101712Srwatson/*
95101712Srwatson * Declare that the kernel provides MAC support, version 1.  This permits
96101712Srwatson * modules to refuse to be loaded if the necessary support isn't present,
97101712Srwatson * even if it's pre-boot.
98101712Srwatson */
99101712SrwatsonMODULE_VERSION(kernel_mac_support, 1);
100101712Srwatson
101100979SrwatsonSYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
102100979Srwatson    "TrustedBSD MAC policy controls");
103104517Srwatson
104114846Srwatson#if MAC_MAX_SLOTS > 32
105114846Srwatson#error "MAC_MAX_SLOTS too large"
106100979Srwatson#endif
107105497Srwatson
108114846Srwatsonstatic unsigned int mac_max_slots = MAC_MAX_SLOTS;
109114846Srwatsonstatic unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
110114846SrwatsonSYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD,
111114846Srwatson    &mac_max_slots, 0, "");
112100979Srwatson
113105959Srwatson/*
114105959Srwatson * Has the kernel started generating labeled objects yet?  All read/write
115105959Srwatson * access to this variable is serialized during the boot process.  Following
116105959Srwatson * the end of serialization, we don't update this flag; no locking.
117105959Srwatson */
118121372Srwatsonint	mac_late = 0;
119100979Srwatson
120105988Srwatson/*
121113487Srwatson * Flag to indicate whether or not we should allocate label storage for
122113487Srwatson * new mbufs.  Since most dynamic policies we currently work with don't
123113487Srwatson * rely on mbuf labeling, try to avoid paying the cost of mtag allocation
124113487Srwatson * unless specifically notified of interest.  One result of this is
125113487Srwatson * that if a dynamically loaded policy requests mbuf labels, it must
126113487Srwatson * be able to deal with a NULL label being returned on any mbufs that
127113487Srwatson * were already in flight when the policy was loaded.  Since the policy
128113487Srwatson * already has to deal with uninitialized labels, this probably won't
129113487Srwatson * be a problem.  Note: currently no locking.  Will this be a problem?
130113487Srwatson */
131118308Srwatson#ifndef MAC_ALWAYS_LABEL_MBUF
132121372Srwatsonint	mac_labelmbufs = 0;
133113487Srwatson#endif
134113487Srwatson
135101988Srwatson#ifdef MAC_DEBUG
136104268SrwatsonSYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0,
137104268Srwatson    "TrustedBSD MAC debug info");
138104517SrwatsonSYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0,
139104517Srwatson    "TrustedBSD MAC object counters");
140104517Srwatson
141121374Srwatsonstatic unsigned int nmactemp;
142104517SrwatsonSYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD,
143100979Srwatson    &nmactemp, 0, "number of temporary labels in use");
144101988Srwatson#endif
145100979Srwatson
146100979Srwatsonstatic int	mac_policy_register(struct mac_policy_conf *mpc);
147100979Srwatsonstatic int	mac_policy_unregister(struct mac_policy_conf *mpc);
148100979Srwatson
149105694SrwatsonMALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
150100979Srwatson
151100979Srwatson/*
152114806Srwatson * mac_static_policy_list holds a list of policy modules that are not
153114806Srwatson * loaded while the system is "live", and cannot be unloaded.  These
154114806Srwatson * policies can be invoked without holding the busy count.
155114806Srwatson *
156114806Srwatson * mac_policy_list stores the list of dynamic policies.  A busy count is
157106856Srwatson * maintained for the list, stored in mac_policy_busy.  The busy count
158114806Srwatson * is protected by mac_policy_mtx; the list may be modified only
159106856Srwatson * while the busy count is 0, requiring that the lock be held to
160106856Srwatson * prevent new references to the list from being acquired.  For almost
161106856Srwatson * all operations, incrementing the busy count is sufficient to
162106856Srwatson * guarantee consistency, as the list cannot be modified while the
163106856Srwatson * busy count is elevated.  For a few special operations involving a
164114806Srwatson * change to the list of active policies, the mtx itself must be held.
165114806Srwatson * A condition variable, mac_policy_cv, is used to signal potential
166114806Srwatson * exclusive consumers that they should try to acquire the lock if a
167114806Srwatson * first attempt at exclusive access fails.
168100979Srwatson */
169114806Srwatsonstatic struct mtx mac_policy_mtx;
170114806Srwatsonstatic struct cv mac_policy_cv;
171114806Srwatsonstatic int mac_policy_count;
172121372Srwatsonstruct mac_policy_list_head mac_policy_list;
173121372Srwatsonstruct mac_policy_list_head mac_static_policy_list;
174100979Srwatson
175106856Srwatson/*
176111883Sjhb * We manually invoke WITNESS_WARN() to allow Witness to generate
177106856Srwatson * warnings even if we don't end up ever triggering the wait at
178106856Srwatson * run-time.  The consumer of the exclusive interface must not hold
179106856Srwatson * any locks (other than potentially Giant) since we may sleep for
180106856Srwatson * long (potentially indefinite) periods of time waiting for the
181106856Srwatson * framework to become quiescent so that a policy list change may
182106856Srwatson * be made.
183106856Srwatson */
184121372Srwatsonvoid
185114806Srwatsonmac_policy_grab_exclusive(void)
186114806Srwatson{
187122454Srwatson
188114806Srwatson	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
189114806Srwatson 	    "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
190114806Srwatson	mtx_lock(&mac_policy_mtx);
191114806Srwatson	while (mac_policy_count != 0)
192114806Srwatson		cv_wait(&mac_policy_cv, &mac_policy_mtx);
193114806Srwatson}
194106856Srwatson
195121372Srwatsonvoid
196114806Srwatsonmac_policy_assert_exclusive(void)
197114806Srwatson{
198122454Srwatson
199114806Srwatson	mtx_assert(&mac_policy_mtx, MA_OWNED);
200114806Srwatson	KASSERT(mac_policy_count == 0,
201114806Srwatson	    ("mac_policy_assert_exclusive(): not exclusive"));
202114806Srwatson}
203113487Srwatson
204121372Srwatsonvoid
205114806Srwatsonmac_policy_release_exclusive(void)
206114806Srwatson{
207100979Srwatson
208114806Srwatson	KASSERT(mac_policy_count == 0,
209114806Srwatson	    ("mac_policy_release_exclusive(): not exclusive"));
210114806Srwatson	mtx_unlock(&mac_policy_mtx);
211114806Srwatson	cv_signal(&mac_policy_cv);
212114806Srwatson}
213100979Srwatson
214121372Srwatsonvoid
215114806Srwatsonmac_policy_list_busy(void)
216114806Srwatson{
217122454Srwatson
218114806Srwatson	mtx_lock(&mac_policy_mtx);
219114806Srwatson	mac_policy_count++;
220114806Srwatson	mtx_unlock(&mac_policy_mtx);
221114806Srwatson}
222114806Srwatson
223121372Srwatsonint
224114806Srwatsonmac_policy_list_conditional_busy(void)
225114806Srwatson{
226114806Srwatson	int ret;
227114806Srwatson
228114806Srwatson	mtx_lock(&mac_policy_mtx);
229114806Srwatson	if (!LIST_EMPTY(&mac_policy_list)) {
230114806Srwatson		mac_policy_count++;
231114806Srwatson		ret = 1;
232114806Srwatson	} else
233114806Srwatson		ret = 0;
234114806Srwatson	mtx_unlock(&mac_policy_mtx);
235114806Srwatson	return (ret);
236114806Srwatson}
237114806Srwatson
238121372Srwatsonvoid
239114806Srwatsonmac_policy_list_unbusy(void)
240114806Srwatson{
241122454Srwatson
242114806Srwatson	mtx_lock(&mac_policy_mtx);
243114806Srwatson	mac_policy_count--;
244114806Srwatson	KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
245114806Srwatson	if (mac_policy_count == 0)
246114806Srwatson		cv_signal(&mac_policy_cv);
247114806Srwatson	mtx_unlock(&mac_policy_mtx);
248114806Srwatson}
249114806Srwatson
250100979Srwatson/*
251100979Srwatson * Initialize the MAC subsystem, including appropriate SMP locks.
252100979Srwatson */
253100979Srwatsonstatic void
254100979Srwatsonmac_init(void)
255100979Srwatson{
256100979Srwatson
257114806Srwatson	LIST_INIT(&mac_static_policy_list);
258100979Srwatson	LIST_INIT(&mac_policy_list);
259114806Srwatson
260114806Srwatson	mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
261114806Srwatson	cv_init(&mac_policy_cv, "mac_policy_cv");
262100979Srwatson}
263100979Srwatson
264100979Srwatson/*
265100979Srwatson * For the purposes of modules that want to know if they were loaded
266100979Srwatson * "early", set the mac_late flag once we've processed modules either
267100979Srwatson * linked into the kernel, or loaded before the kernel startup.
268100979Srwatson */
269100979Srwatsonstatic void
270100979Srwatsonmac_late_init(void)
271100979Srwatson{
272100979Srwatson
273100979Srwatson	mac_late = 1;
274100979Srwatson}
275100979Srwatson
276100979Srwatson/*
277113487Srwatson * After the policy list has changed, walk the list to update any global
278118308Srwatson * flags.  Currently, we support only one flag, and it's conditionally
279118308Srwatson * defined; as a result, the entire function is conditional.  Eventually,
280118308Srwatson * the #else case might also iterate across the policies.
281113487Srwatson */
282113487Srwatsonstatic void
283113487Srwatsonmac_policy_updateflags(void)
284113487Srwatson{
285118308Srwatson#ifndef MAC_ALWAYS_LABEL_MBUF
286113487Srwatson	struct mac_policy_conf *tmpc;
287113487Srwatson	int labelmbufs;
288113487Srwatson
289114806Srwatson	mac_policy_assert_exclusive();
290113487Srwatson
291113487Srwatson	labelmbufs = 0;
292114806Srwatson	LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
293114806Srwatson		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
294114806Srwatson			labelmbufs++;
295114806Srwatson	}
296113487Srwatson	LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
297113487Srwatson		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
298113487Srwatson			labelmbufs++;
299113487Srwatson	}
300113487Srwatson	mac_labelmbufs = (labelmbufs != 0);
301113487Srwatson#endif
302113487Srwatson}
303113487Srwatson
304113487Srwatson/*
305100979Srwatson * Allow MAC policy modules to register during boot, etc.
306100979Srwatson */
307100894Srwatsonint
308100979Srwatsonmac_policy_modevent(module_t mod, int type, void *data)
309100979Srwatson{
310100979Srwatson	struct mac_policy_conf *mpc;
311100979Srwatson	int error;
312100979Srwatson
313100979Srwatson	error = 0;
314100979Srwatson	mpc = (struct mac_policy_conf *) data;
315100979Srwatson
316100979Srwatson	switch (type) {
317100979Srwatson	case MOD_LOAD:
318100979Srwatson		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
319100979Srwatson		    mac_late) {
320100979Srwatson			printf("mac_policy_modevent: can't load %s policy "
321100979Srwatson			    "after booting\n", mpc->mpc_name);
322100979Srwatson			error = EBUSY;
323100979Srwatson			break;
324100979Srwatson		}
325100979Srwatson		error = mac_policy_register(mpc);
326100979Srwatson		break;
327100979Srwatson	case MOD_UNLOAD:
328100979Srwatson		/* Don't unregister the module if it was never registered. */
329100979Srwatson		if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
330100979Srwatson		    != 0)
331100979Srwatson			error = mac_policy_unregister(mpc);
332100979Srwatson		else
333100979Srwatson			error = 0;
334100979Srwatson		break;
335100979Srwatson	default:
336100979Srwatson		break;
337100979Srwatson	}
338100979Srwatson
339100979Srwatson	return (error);
340100979Srwatson}
341100979Srwatson
342100979Srwatsonstatic int
343100979Srwatsonmac_policy_register(struct mac_policy_conf *mpc)
344100979Srwatson{
345100979Srwatson	struct mac_policy_conf *tmpc;
346114806Srwatson	int error, slot, static_entry;
347100979Srwatson
348114806Srwatson	error = 0;
349114806Srwatson
350114806Srwatson	/*
351114806Srwatson	 * We don't technically need exclusive access while !mac_late,
352114806Srwatson	 * but hold it for assertion consistency.
353114806Srwatson	 */
354114806Srwatson	mac_policy_grab_exclusive();
355114806Srwatson
356114806Srwatson	/*
357114806Srwatson	 * If the module can potentially be unloaded, or we're loading
358114806Srwatson	 * late, we have to stick it in the non-static list and pay
359114806Srwatson	 * an extra performance overhead.  Otherwise, we can pay a
360114806Srwatson	 * light locking cost and stick it in the static list.
361114806Srwatson	 */
362114806Srwatson	static_entry = (!mac_late &&
363114806Srwatson	    !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
364114806Srwatson
365114806Srwatson	if (static_entry) {
366114806Srwatson		LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
367114806Srwatson			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
368114806Srwatson				error = EEXIST;
369114806Srwatson				goto out;
370114806Srwatson			}
371100979Srwatson		}
372114806Srwatson	} else {
373114806Srwatson		LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
374114806Srwatson			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
375114806Srwatson				error = EEXIST;
376114806Srwatson				goto out;
377114806Srwatson			}
378114806Srwatson		}
379100979Srwatson	}
380100979Srwatson	if (mpc->mpc_field_off != NULL) {
381114846Srwatson		slot = ffs(mac_slot_offsets_free);
382100979Srwatson		if (slot == 0) {
383114806Srwatson			error = ENOMEM;
384114806Srwatson			goto out;
385100979Srwatson		}
386100979Srwatson		slot--;
387114846Srwatson		mac_slot_offsets_free &= ~(1 << slot);
388100979Srwatson		*mpc->mpc_field_off = slot;
389100979Srwatson	}
390100979Srwatson	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
391100979Srwatson
392114806Srwatson	/*
393114806Srwatson	 * If we're loading a MAC module after the framework has
394114806Srwatson	 * initialized, it has to go into the dynamic list.  If
395114806Srwatson	 * we're loading it before we've finished initializing,
396114806Srwatson	 * it can go into the static list with weaker locker
397114806Srwatson	 * requirements.
398114806Srwatson	 */
399114806Srwatson	if (static_entry)
400114806Srwatson		LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
401114806Srwatson	else
402114806Srwatson		LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
403114806Srwatson
404100979Srwatson	/* Per-policy initialization. */
405100979Srwatson	if (mpc->mpc_ops->mpo_init != NULL)
406100979Srwatson		(*(mpc->mpc_ops->mpo_init))(mpc);
407113487Srwatson	mac_policy_updateflags();
408100979Srwatson
409100979Srwatson	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
410100979Srwatson	    mpc->mpc_name);
411100979Srwatson
412114806Srwatsonout:
413114806Srwatson	mac_policy_release_exclusive();
414114806Srwatson	return (error);
415100979Srwatson}
416100979Srwatson
417100979Srwatsonstatic int
418100979Srwatsonmac_policy_unregister(struct mac_policy_conf *mpc)
419100979Srwatson{
420100979Srwatson
421104520Srwatson	/*
422104520Srwatson	 * If we fail the load, we may get a request to unload.  Check
423104520Srwatson	 * to see if we did the run-time registration, and if not,
424104520Srwatson	 * silently succeed.
425104520Srwatson	 */
426114806Srwatson	mac_policy_grab_exclusive();
427104520Srwatson	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
428114806Srwatson		mac_policy_release_exclusive();
429104520Srwatson		return (0);
430104520Srwatson	}
431100979Srwatson#if 0
432100979Srwatson	/*
433100979Srwatson	 * Don't allow unloading modules with private data.
434100979Srwatson	 */
435104520Srwatson	if (mpc->mpc_field_off != NULL) {
436104520Srwatson		MAC_POLICY_LIST_UNLOCK();
437100979Srwatson		return (EBUSY);
438104520Srwatson	}
439100979Srwatson#endif
440104520Srwatson	/*
441104520Srwatson	 * Only allow the unload to proceed if the module is unloadable
442104520Srwatson	 * by its own definition.
443104520Srwatson	 */
444104520Srwatson	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
445114806Srwatson		mac_policy_release_exclusive();
446100979Srwatson		return (EBUSY);
447104520Srwatson	}
448100979Srwatson	if (mpc->mpc_ops->mpo_destroy != NULL)
449100979Srwatson		(*(mpc->mpc_ops->mpo_destroy))(mpc);
450100979Srwatson
451100979Srwatson	LIST_REMOVE(mpc, mpc_list);
452106856Srwatson	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
453113487Srwatson	mac_policy_updateflags();
454100979Srwatson
455114806Srwatson	mac_policy_release_exclusive();
456114806Srwatson
457100979Srwatson	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
458100979Srwatson	    mpc->mpc_name);
459100979Srwatson
460100979Srwatson	return (0);
461100979Srwatson}
462100979Srwatson
463100979Srwatson/*
464100979Srwatson * Define an error value precedence, and given two arguments, selects the
465100979Srwatson * value with the higher precedence.
466100979Srwatson */
467121371Srwatsonint
468121371Srwatsonmac_error_select(int error1, int error2)
469100979Srwatson{
470100979Srwatson
471100979Srwatson	/* Certain decision-making errors take top priority. */
472100979Srwatson	if (error1 == EDEADLK || error2 == EDEADLK)
473100979Srwatson		return (EDEADLK);
474100979Srwatson
475100979Srwatson	/* Invalid arguments should be reported where possible. */
476100979Srwatson	if (error1 == EINVAL || error2 == EINVAL)
477100979Srwatson		return (EINVAL);
478100979Srwatson
479100979Srwatson	/* Precedence goes to "visibility", with both process and file. */
480100979Srwatson	if (error1 == ESRCH || error2 == ESRCH)
481100979Srwatson		return (ESRCH);
482100979Srwatson
483100979Srwatson	if (error1 == ENOENT || error2 == ENOENT)
484100979Srwatson		return (ENOENT);
485100979Srwatson
486100979Srwatson	/* Precedence goes to DAC/MAC protections. */
487100979Srwatson	if (error1 == EACCES || error2 == EACCES)
488100979Srwatson		return (EACCES);
489100979Srwatson
490100979Srwatson	/* Precedence goes to privilege. */
491100979Srwatson	if (error1 == EPERM || error2 == EPERM)
492100979Srwatson		return (EPERM);
493100979Srwatson
494100979Srwatson	/* Precedence goes to error over success; otherwise, arbitrary. */
495100979Srwatson	if (error1 != 0)
496100979Srwatson		return (error1);
497100979Srwatson	return (error2);
498100979Srwatson}
499100979Srwatson
500121374Srwatsonvoid
501104521Srwatsonmac_init_label(struct label *label)
502104521Srwatson{
503104521Srwatson
504104521Srwatson	bzero(label, sizeof(*label));
505104521Srwatson	label->l_flags = MAC_FLAG_INITIALIZED;
506104521Srwatson}
507104521Srwatson
508121374Srwatsonvoid
509104521Srwatsonmac_destroy_label(struct label *label)
510104521Srwatson{
511104521Srwatson
512104521Srwatson	KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
513104521Srwatson	    ("destroying uninitialized label"));
514104521Srwatson
515104521Srwatson	bzero(label, sizeof(*label));
516104521Srwatson	/* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
517104521Srwatson}
518104521Srwatson
519112675Srwatsonint
520105694Srwatsonmac_check_structmac_consistent(struct mac *mac)
521104522Srwatson{
522105694Srwatson
523120582Srwatson	if (mac->m_buflen < 0 ||
524120582Srwatson	    mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
525105694Srwatson		return (EINVAL);
526105694Srwatson
527105694Srwatson	return (0);
528105694Srwatson}
529105694Srwatson
530105988Srwatsonint
531105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
532105694Srwatson{
533105694Srwatson	char *elements, *buffer;
534105694Srwatson	struct mac mac;
535105694Srwatson	struct proc *tproc;
536105694Srwatson	struct ucred *tcred;
537105694Srwatson	int error;
538105694Srwatson
539107849Salfred	error = copyin(uap->mac_p, &mac, sizeof(mac));
540105694Srwatson	if (error)
541105694Srwatson		return (error);
542105694Srwatson
543105694Srwatson	error = mac_check_structmac_consistent(&mac);
544105694Srwatson	if (error)
545105694Srwatson		return (error);
546105694Srwatson
547105694Srwatson	tproc = pfind(uap->pid);
548105694Srwatson	if (tproc == NULL)
549105694Srwatson		return (ESRCH);
550105694Srwatson
551105694Srwatson	tcred = NULL;				/* Satisfy gcc. */
552105694Srwatson	error = p_cansee(td, tproc);
553105694Srwatson	if (error == 0)
554105694Srwatson		tcred = crhold(tproc->p_ucred);
555105694Srwatson	PROC_UNLOCK(tproc);
556105694Srwatson	if (error)
557105694Srwatson		return (error);
558105694Srwatson
559111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
560105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
561105694Srwatson	if (error) {
562105694Srwatson		free(elements, M_MACTEMP);
563105694Srwatson		crfree(tcred);
564105694Srwatson		return (error);
565105694Srwatson	}
566105694Srwatson
567111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
568105694Srwatson	error = mac_externalize_cred_label(&tcred->cr_label, elements,
569122159Srwatson	    buffer, mac.m_buflen);
570105694Srwatson	if (error == 0)
571105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
572105694Srwatson
573105694Srwatson	free(buffer, M_MACTEMP);
574105694Srwatson	free(elements, M_MACTEMP);
575105694Srwatson	crfree(tcred);
576105694Srwatson	return (error);
577105694Srwatson}
578105694Srwatson
579100979Srwatson/*
580100979Srwatson * MPSAFE
581100979Srwatson */
582100979Srwatsonint
583100894Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
584100894Srwatson{
585105694Srwatson	char *elements, *buffer;
586105694Srwatson	struct mac mac;
587100979Srwatson	int error;
588100894Srwatson
589105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
590105694Srwatson	if (error)
591105694Srwatson		return (error);
592105694Srwatson
593105694Srwatson	error = mac_check_structmac_consistent(&mac);
594105694Srwatson	if (error)
595105694Srwatson		return (error);
596105694Srwatson
597111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
598105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
599105694Srwatson	if (error) {
600105694Srwatson		free(elements, M_MACTEMP);
601105694Srwatson		return (error);
602105694Srwatson	}
603105694Srwatson
604111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
605105694Srwatson	error = mac_externalize_cred_label(&td->td_ucred->cr_label,
606122159Srwatson	    elements, buffer, mac.m_buflen);
607100979Srwatson	if (error == 0)
608105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
609100979Srwatson
610105694Srwatson	free(buffer, M_MACTEMP);
611105694Srwatson	free(elements, M_MACTEMP);
612100979Srwatson	return (error);
613100979Srwatson}
614100979Srwatson
615100979Srwatson/*
616100979Srwatson * MPSAFE
617100979Srwatson */
618100979Srwatsonint
619100979Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
620100979Srwatson{
621100979Srwatson	struct ucred *newcred, *oldcred;
622105694Srwatson	struct label intlabel;
623100979Srwatson	struct proc *p;
624105694Srwatson	struct mac mac;
625105694Srwatson	char *buffer;
626100979Srwatson	int error;
627100979Srwatson
628105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
629100979Srwatson	if (error)
630100979Srwatson		return (error);
631100979Srwatson
632105694Srwatson	error = mac_check_structmac_consistent(&mac);
633100979Srwatson	if (error)
634100979Srwatson		return (error);
635100979Srwatson
636111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
637105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
638105694Srwatson	if (error) {
639105694Srwatson		free(buffer, M_MACTEMP);
640105694Srwatson		return (error);
641105694Srwatson	}
642105694Srwatson
643105694Srwatson	mac_init_cred_label(&intlabel);
644105694Srwatson	error = mac_internalize_cred_label(&intlabel, buffer);
645105694Srwatson	free(buffer, M_MACTEMP);
646105694Srwatson	if (error) {
647105694Srwatson		mac_destroy_cred_label(&intlabel);
648105694Srwatson		return (error);
649105694Srwatson	}
650105694Srwatson
651100979Srwatson	newcred = crget();
652100979Srwatson
653100979Srwatson	p = td->td_proc;
654100979Srwatson	PROC_LOCK(p);
655100979Srwatson	oldcred = p->p_ucred;
656100979Srwatson
657100979Srwatson	error = mac_check_cred_relabel(oldcred, &intlabel);
658100979Srwatson	if (error) {
659100979Srwatson		PROC_UNLOCK(p);
660100979Srwatson		crfree(newcred);
661105694Srwatson		goto out;
662100979Srwatson	}
663100979Srwatson
664100979Srwatson	setsugid(p);
665100979Srwatson	crcopy(newcred, oldcred);
666100979Srwatson	mac_relabel_cred(newcred, &intlabel);
667102136Srwatson	p->p_ucred = newcred;
668100979Srwatson
669102136Srwatson	/*
670102136Srwatson	 * Grab additional reference for use while revoking mmaps, prior
671102136Srwatson	 * to releasing the proc lock and sharing the cred.
672102136Srwatson	 */
673102136Srwatson	crhold(newcred);
674100979Srwatson	PROC_UNLOCK(p);
675102136Srwatson
676105694Srwatson	if (mac_enforce_vm) {
677105694Srwatson		mtx_lock(&Giant);
678105694Srwatson		mac_cred_mmapped_drop_perms(td, newcred);
679105694Srwatson		mtx_unlock(&Giant);
680105694Srwatson	}
681102136Srwatson
682102136Srwatson	crfree(newcred);	/* Free revocation reference. */
683100979Srwatson	crfree(oldcred);
684105694Srwatson
685105694Srwatsonout:
686105694Srwatson	mac_destroy_cred_label(&intlabel);
687105694Srwatson	return (error);
688100979Srwatson}
689100979Srwatson
690100979Srwatson/*
691100979Srwatson * MPSAFE
692100979Srwatson */
693100979Srwatsonint
694100979Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
695100979Srwatson{
696105694Srwatson	char *elements, *buffer;
697105694Srwatson	struct label intlabel;
698100979Srwatson	struct file *fp;
699105694Srwatson	struct mac mac;
700100979Srwatson	struct vnode *vp;
701100979Srwatson	struct pipe *pipe;
702105694Srwatson	short label_type;
703100979Srwatson	int error;
704100979Srwatson
705105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
706105694Srwatson	if (error)
707105694Srwatson		return (error);
708100979Srwatson
709105694Srwatson	error = mac_check_structmac_consistent(&mac);
710105694Srwatson	if (error)
711105694Srwatson		return (error);
712105694Srwatson
713111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
714105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
715105694Srwatson	if (error) {
716105694Srwatson		free(elements, M_MACTEMP);
717105694Srwatson		return (error);
718105694Srwatson	}
719105694Srwatson
720111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
721105694Srwatson	mtx_lock(&Giant);				/* VFS */
722107849Salfred	error = fget(td, uap->fd, &fp);
723100979Srwatson	if (error)
724100979Srwatson		goto out;
725100979Srwatson
726105694Srwatson	label_type = fp->f_type;
727100979Srwatson	switch (fp->f_type) {
728100979Srwatson	case DTYPE_FIFO:
729100979Srwatson	case DTYPE_VNODE:
730116678Sphk		vp = fp->f_vnode;
731100979Srwatson
732105694Srwatson		mac_init_vnode_label(&intlabel);
733105694Srwatson
734100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
735105988Srwatson		mac_copy_vnode_label(&vp->v_label, &intlabel);
736100979Srwatson		VOP_UNLOCK(vp, 0, td);
737105694Srwatson
738100979Srwatson		break;
739100979Srwatson	case DTYPE_PIPE:
740109153Sdillon		pipe = fp->f_data;
741105694Srwatson
742105694Srwatson		mac_init_pipe_label(&intlabel);
743105694Srwatson
744105694Srwatson		PIPE_LOCK(pipe);
745105694Srwatson		mac_copy_pipe_label(pipe->pipe_label, &intlabel);
746105694Srwatson		PIPE_UNLOCK(pipe);
747100979Srwatson		break;
748100979Srwatson	default:
749100979Srwatson		error = EINVAL;
750105694Srwatson		fdrop(fp, td);
751105694Srwatson		goto out;
752100979Srwatson	}
753105694Srwatson	fdrop(fp, td);
754100979Srwatson
755105694Srwatson	switch (label_type) {
756105694Srwatson	case DTYPE_FIFO:
757105694Srwatson	case DTYPE_VNODE:
758105694Srwatson		if (error == 0)
759105694Srwatson			error = mac_externalize_vnode_label(&intlabel,
760122159Srwatson			    elements, buffer, mac.m_buflen);
761105694Srwatson		mac_destroy_vnode_label(&intlabel);
762105694Srwatson		break;
763105694Srwatson	case DTYPE_PIPE:
764105694Srwatson		error = mac_externalize_pipe_label(&intlabel, elements,
765122159Srwatson		    buffer, mac.m_buflen);
766105694Srwatson		mac_destroy_pipe_label(&intlabel);
767105694Srwatson		break;
768105694Srwatson	default:
769105694Srwatson		panic("__mac_get_fd: corrupted label_type");
770105694Srwatson	}
771105694Srwatson
772100979Srwatson	if (error == 0)
773105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
774100979Srwatson
775105694Srwatsonout:
776105694Srwatson	mtx_unlock(&Giant);				/* VFS */
777105694Srwatson	free(buffer, M_MACTEMP);
778105694Srwatson	free(elements, M_MACTEMP);
779100979Srwatson
780100979Srwatson	return (error);
781100979Srwatson}
782100979Srwatson
783100979Srwatson/*
784100979Srwatson * MPSAFE
785100979Srwatson */
786100979Srwatsonint
787100979Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
788100979Srwatson{
789105694Srwatson	char *elements, *buffer;
790100979Srwatson	struct nameidata nd;
791105694Srwatson	struct label intlabel;
792105694Srwatson	struct mac mac;
793100979Srwatson	int error;
794100979Srwatson
795105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
796105694Srwatson	if (error)
797105694Srwatson		return (error);
798105694Srwatson
799105694Srwatson	error = mac_check_structmac_consistent(&mac);
800105694Srwatson	if (error)
801105694Srwatson		return (error);
802105694Srwatson
803111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
804105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
805105694Srwatson	if (error) {
806105694Srwatson		free(elements, M_MACTEMP);
807105694Srwatson		return (error);
808105694Srwatson	}
809105694Srwatson
810111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
811105694Srwatson	mtx_lock(&Giant);				/* VFS */
812105694Srwatson	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
813105694Srwatson	    td);
814100979Srwatson	error = namei(&nd);
815100979Srwatson	if (error)
816100979Srwatson		goto out;
817100979Srwatson
818105694Srwatson	mac_init_vnode_label(&intlabel);
819105988Srwatson	mac_copy_vnode_label(&nd.ni_vp->v_label, &intlabel);
820105988Srwatson	error = mac_externalize_vnode_label(&intlabel, elements, buffer,
821122159Srwatson	    mac.m_buflen);
822105694Srwatson
823100979Srwatson	NDFREE(&nd, 0);
824105694Srwatson	mac_destroy_vnode_label(&intlabel);
825105694Srwatson
826105694Srwatson	if (error == 0)
827105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
828105694Srwatson
829105694Srwatsonout:
830105694Srwatson	mtx_unlock(&Giant);				/* VFS */
831105694Srwatson
832105694Srwatson	free(buffer, M_MACTEMP);
833105694Srwatson	free(elements, M_MACTEMP);
834105694Srwatson
835105694Srwatson	return (error);
836105694Srwatson}
837105694Srwatson
838105694Srwatson/*
839105694Srwatson * MPSAFE
840105694Srwatson */
841105694Srwatsonint
842105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
843105694Srwatson{
844105694Srwatson	char *elements, *buffer;
845105694Srwatson	struct nameidata nd;
846105694Srwatson	struct label intlabel;
847105694Srwatson	struct mac mac;
848105694Srwatson	int error;
849105694Srwatson
850105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
851100979Srwatson	if (error)
852105694Srwatson		return (error);
853105694Srwatson
854105694Srwatson	error = mac_check_structmac_consistent(&mac);
855105694Srwatson	if (error)
856105694Srwatson		return (error);
857105694Srwatson
858111119Simp	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
859105694Srwatson	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
860105694Srwatson	if (error) {
861105694Srwatson		free(elements, M_MACTEMP);
862105694Srwatson		return (error);
863105694Srwatson	}
864105694Srwatson
865111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
866105694Srwatson	mtx_lock(&Giant);				/* VFS */
867105694Srwatson	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
868105694Srwatson	    td);
869105694Srwatson	error = namei(&nd);
870105694Srwatson	if (error)
871100979Srwatson		goto out;
872100979Srwatson
873105694Srwatson	mac_init_vnode_label(&intlabel);
874105988Srwatson	mac_copy_vnode_label(&nd.ni_vp->v_label, &intlabel);
875105988Srwatson	error = mac_externalize_vnode_label(&intlabel, elements, buffer,
876122159Srwatson	    mac.m_buflen);
877105694Srwatson	NDFREE(&nd, 0);
878105694Srwatson	mac_destroy_vnode_label(&intlabel);
879100979Srwatson
880105694Srwatson	if (error == 0)
881105694Srwatson		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
882105694Srwatson
883100979Srwatsonout:
884105694Srwatson	mtx_unlock(&Giant);				/* VFS */
885105694Srwatson
886105694Srwatson	free(buffer, M_MACTEMP);
887105694Srwatson	free(elements, M_MACTEMP);
888105694Srwatson
889100979Srwatson	return (error);
890100979Srwatson}
891100979Srwatson
892100979Srwatson/*
893100979Srwatson * MPSAFE
894100979Srwatson */
895100979Srwatsonint
896100979Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
897100979Srwatson{
898105694Srwatson	struct label intlabel;
899105694Srwatson	struct pipe *pipe;
900100979Srwatson	struct file *fp;
901100979Srwatson	struct mount *mp;
902100979Srwatson	struct vnode *vp;
903105694Srwatson	struct mac mac;
904105694Srwatson	char *buffer;
905100979Srwatson	int error;
906100979Srwatson
907105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
908100979Srwatson	if (error)
909105694Srwatson		return (error);
910100979Srwatson
911105694Srwatson	error = mac_check_structmac_consistent(&mac);
912100979Srwatson	if (error)
913105694Srwatson		return (error);
914100979Srwatson
915111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
916105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
917105694Srwatson	if (error) {
918105694Srwatson		free(buffer, M_MACTEMP);
919105694Srwatson		return (error);
920105694Srwatson	}
921105694Srwatson
922105694Srwatson	mtx_lock(&Giant);				/* VFS */
923105694Srwatson
924107849Salfred	error = fget(td, uap->fd, &fp);
925100979Srwatson	if (error)
926105694Srwatson		goto out;
927100979Srwatson
928100979Srwatson	switch (fp->f_type) {
929100979Srwatson	case DTYPE_FIFO:
930100979Srwatson	case DTYPE_VNODE:
931105694Srwatson		mac_init_vnode_label(&intlabel);
932105694Srwatson		error = mac_internalize_vnode_label(&intlabel, buffer);
933105694Srwatson		if (error) {
934105694Srwatson			mac_destroy_vnode_label(&intlabel);
935105694Srwatson			break;
936105694Srwatson		}
937105694Srwatson
938116678Sphk		vp = fp->f_vnode;
939100979Srwatson		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
940105694Srwatson		if (error != 0) {
941105694Srwatson			mac_destroy_vnode_label(&intlabel);
942100979Srwatson			break;
943105694Srwatson		}
944100979Srwatson
945100979Srwatson		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
946100979Srwatson		error = vn_setlabel(vp, &intlabel, td->td_ucred);
947100979Srwatson		VOP_UNLOCK(vp, 0, td);
948100979Srwatson		vn_finished_write(mp);
949105694Srwatson
950105694Srwatson		mac_destroy_vnode_label(&intlabel);
951100979Srwatson		break;
952105694Srwatson
953100979Srwatson	case DTYPE_PIPE:
954105694Srwatson		mac_init_pipe_label(&intlabel);
955105694Srwatson		error = mac_internalize_pipe_label(&intlabel, buffer);
956105694Srwatson		if (error == 0) {
957109153Sdillon			pipe = fp->f_data;
958105694Srwatson			PIPE_LOCK(pipe);
959105694Srwatson			error = mac_pipe_label_set(td->td_ucred, pipe,
960105694Srwatson			    &intlabel);
961105694Srwatson			PIPE_UNLOCK(pipe);
962105694Srwatson		}
963105694Srwatson
964105694Srwatson		mac_destroy_pipe_label(&intlabel);
965100979Srwatson		break;
966105694Srwatson
967100979Srwatson	default:
968100979Srwatson		error = EINVAL;
969100979Srwatson	}
970100979Srwatson
971100979Srwatson	fdrop(fp, td);
972105694Srwatsonout:
973105694Srwatson	mtx_unlock(&Giant);				/* VFS */
974105694Srwatson
975105694Srwatson	free(buffer, M_MACTEMP);
976105694Srwatson
977100979Srwatson	return (error);
978100979Srwatson}
979100979Srwatson
980100979Srwatson/*
981100979Srwatson * MPSAFE
982100979Srwatson */
983100979Srwatsonint
984100979Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
985100979Srwatson{
986105694Srwatson	struct label intlabel;
987100979Srwatson	struct nameidata nd;
988100979Srwatson	struct mount *mp;
989105694Srwatson	struct mac mac;
990105694Srwatson	char *buffer;
991100979Srwatson	int error;
992100979Srwatson
993105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
994100979Srwatson	if (error)
995105694Srwatson		return (error);
996100979Srwatson
997105694Srwatson	error = mac_check_structmac_consistent(&mac);
998100979Srwatson	if (error)
999105694Srwatson		return (error);
1000100979Srwatson
1001111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1002105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1003105694Srwatson	if (error) {
1004105694Srwatson		free(buffer, M_MACTEMP);
1005105694Srwatson		return (error);
1006105694Srwatson	}
1007105694Srwatson
1008105694Srwatson	mac_init_vnode_label(&intlabel);
1009105694Srwatson	error = mac_internalize_vnode_label(&intlabel, buffer);
1010105694Srwatson	free(buffer, M_MACTEMP);
1011105694Srwatson	if (error) {
1012105694Srwatson		mac_destroy_vnode_label(&intlabel);
1013105694Srwatson		return (error);
1014105694Srwatson	}
1015105694Srwatson
1016105694Srwatson	mtx_lock(&Giant);				/* VFS */
1017105694Srwatson
1018105694Srwatson	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
1019105694Srwatson	    td);
1020100979Srwatson	error = namei(&nd);
1021105694Srwatson	if (error == 0) {
1022105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1023105694Srwatson		if (error == 0)
1024105694Srwatson			error = vn_setlabel(nd.ni_vp, &intlabel,
1025105694Srwatson			    td->td_ucred);
1026105694Srwatson		vn_finished_write(mp);
1027105694Srwatson	}
1028105694Srwatson
1029105694Srwatson	NDFREE(&nd, 0);
1030105694Srwatson	mtx_unlock(&Giant);				/* VFS */
1031105694Srwatson	mac_destroy_vnode_label(&intlabel);
1032105694Srwatson
1033105694Srwatson	return (error);
1034105694Srwatson}
1035105694Srwatson
1036105694Srwatson/*
1037105694Srwatson * MPSAFE
1038105694Srwatson */
1039105694Srwatsonint
1040105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1041105694Srwatson{
1042105694Srwatson	struct label intlabel;
1043105694Srwatson	struct nameidata nd;
1044105694Srwatson	struct mount *mp;
1045105694Srwatson	struct mac mac;
1046105694Srwatson	char *buffer;
1047105694Srwatson	int error;
1048105694Srwatson
1049105694Srwatson	error = copyin(uap->mac_p, &mac, sizeof(mac));
1050100979Srwatson	if (error)
1051105694Srwatson		return (error);
1052105694Srwatson
1053105694Srwatson	error = mac_check_structmac_consistent(&mac);
1054100979Srwatson	if (error)
1055105694Srwatson		return (error);
1056100979Srwatson
1057111119Simp	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1058105694Srwatson	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1059105694Srwatson	if (error) {
1060105694Srwatson		free(buffer, M_MACTEMP);
1061105694Srwatson		return (error);
1062105694Srwatson	}
1063105694Srwatson
1064105694Srwatson	mac_init_vnode_label(&intlabel);
1065105694Srwatson	error = mac_internalize_vnode_label(&intlabel, buffer);
1066105694Srwatson	free(buffer, M_MACTEMP);
1067105694Srwatson	if (error) {
1068105694Srwatson		mac_destroy_vnode_label(&intlabel);
1069105694Srwatson		return (error);
1070105694Srwatson	}
1071105694Srwatson
1072105694Srwatson	mtx_lock(&Giant);				/* VFS */
1073105694Srwatson
1074105694Srwatson	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
1075105694Srwatson	    td);
1076105694Srwatson	error = namei(&nd);
1077105694Srwatson	if (error == 0) {
1078105694Srwatson		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1079105694Srwatson		if (error == 0)
1080105694Srwatson			error = vn_setlabel(nd.ni_vp, &intlabel,
1081105694Srwatson			    td->td_ucred);
1082105694Srwatson		vn_finished_write(mp);
1083105694Srwatson	}
1084105694Srwatson
1085100979Srwatson	NDFREE(&nd, 0);
1086105694Srwatson	mtx_unlock(&Giant);				/* VFS */
1087105694Srwatson	mac_destroy_vnode_label(&intlabel);
1088105694Srwatson
1089100979Srwatson	return (error);
1090100979Srwatson}
1091100979Srwatson
1092105694Srwatson/*
1093105694Srwatson * MPSAFE
1094105694Srwatson */
1095102123Srwatsonint
1096102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1097102123Srwatson{
1098102123Srwatson	struct mac_policy_conf *mpc;
1099102123Srwatson	char target[MAC_MAX_POLICY_NAME];
1100114806Srwatson	int entrycount, error;
1101102123Srwatson
1102107849Salfred	error = copyinstr(uap->policy, target, sizeof(target), NULL);
1103102123Srwatson	if (error)
1104102123Srwatson		return (error);
1105102123Srwatson
1106102123Srwatson	error = ENOSYS;
1107119494Srwatson	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1108102123Srwatson		if (strcmp(mpc->mpc_name, target) == 0 &&
1109102123Srwatson		    mpc->mpc_ops->mpo_syscall != NULL) {
1110102123Srwatson			error = mpc->mpc_ops->mpo_syscall(td,
1111107849Salfred			    uap->call, uap->arg);
1112102123Srwatson			goto out;
1113102123Srwatson		}
1114102123Srwatson	}
1115102123Srwatson
1116114806Srwatson	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1117114806Srwatson		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1118114806Srwatson			if (strcmp(mpc->mpc_name, target) == 0 &&
1119114806Srwatson			    mpc->mpc_ops->mpo_syscall != NULL) {
1120114806Srwatson				error = mpc->mpc_ops->mpo_syscall(td,
1121114806Srwatson				    uap->call, uap->arg);
1122114806Srwatson				break;
1123114806Srwatson			}
1124114806Srwatson		}
1125114806Srwatson		mac_policy_list_unbusy();
1126114806Srwatson	}
1127102123Srwatsonout:
1128102123Srwatson	return (error);
1129102123Srwatson}
1130102123Srwatson
1131100979SrwatsonSYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1132100979SrwatsonSYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1133100979Srwatson
1134100979Srwatson#else /* !MAC */
1135100979Srwatson
1136100979Srwatsonint
1137105694Srwatson__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1138105694Srwatson{
1139105694Srwatson
1140105694Srwatson	return (ENOSYS);
1141105694Srwatson}
1142105694Srwatson
1143105694Srwatsonint
1144100979Srwatson__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1145100979Srwatson{
1146100979Srwatson
1147100894Srwatson	return (ENOSYS);
1148100894Srwatson}
1149100894Srwatson
1150100894Srwatsonint
1151100894Srwatson__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1152100894Srwatson{
1153100894Srwatson
1154100894Srwatson	return (ENOSYS);
1155100894Srwatson}
1156100894Srwatson
1157100894Srwatsonint
1158100894Srwatson__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1159100894Srwatson{
1160100894Srwatson
1161100894Srwatson	return (ENOSYS);
1162100894Srwatson}
1163100894Srwatson
1164100894Srwatsonint
1165100894Srwatson__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1166100894Srwatson{
1167100894Srwatson
1168100894Srwatson	return (ENOSYS);
1169100894Srwatson}
1170100894Srwatson
1171100894Srwatsonint
1172105694Srwatson__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1173105694Srwatson{
1174105694Srwatson
1175105694Srwatson	return (ENOSYS);
1176105694Srwatson}
1177105694Srwatson
1178105694Srwatsonint
1179100894Srwatson__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1180100894Srwatson{
1181100894Srwatson
1182100894Srwatson	return (ENOSYS);
1183100894Srwatson}
1184100894Srwatson
1185100894Srwatsonint
1186100894Srwatson__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1187100894Srwatson{
1188100894Srwatson
1189100894Srwatson	return (ENOSYS);
1190100894Srwatson}
1191100979Srwatson
1192102123Srwatsonint
1193105694Srwatson__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1194105694Srwatson{
1195105694Srwatson
1196105694Srwatson	return (ENOSYS);
1197105694Srwatson}
1198105694Srwatson
1199105694Srwatsonint
1200102123Srwatsonmac_syscall(struct thread *td, struct mac_syscall_args *uap)
1201102123Srwatson{
1202102123Srwatson
1203102123Srwatson	return (ENOSYS);
1204102123Srwatson}
1205102123Srwatson
1206105694Srwatson#endif
1207