mac_syscalls.c revision 122584
1/*-
2 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001, 2002, 2003 Networks Associates Technology, Inc.
5 * All rights reserved.
6 *
7 * This software was developed by Robert Watson and Ilmar Habibulin for the
8 * TrustedBSD Project.
9 *
10 * This software was developed for the FreeBSD Project in part by Network
11 * Associates Laboratories, the Security Research Division of Network
12 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
13 * as part of the DARPA CHATS research program.
14 *
15 * Redistribution and use in source and binary forms, with or without
16 * modification, are permitted provided that the following conditions
17 * are met:
18 * 1. Redistributions of source code must retain the above copyright
19 *    notice, this list of conditions and the following disclaimer.
20 * 2. Redistributions in binary form must reproduce the above copyright
21 *    notice, this list of conditions and the following disclaimer in the
22 *    documentation and/or other materials provided with the distribution.
23 *
24 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
25 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
26 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
27 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
28 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
29 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
30 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
31 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
32 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
33 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
34 * SUCH DAMAGE.
35 */
36
37/*-
38 * Framework for extensible kernel access control.  This file contains
39 * Kernel and userland interface to the framework, policy registration
40 * and composition.  Per-object interfaces, controls, and labeling may be
41 * found in src/sys/mac/.  Sample policies may be found in src/sys/mac*.
42 */
43
44#include <sys/cdefs.h>
45__FBSDID("$FreeBSD: head/sys/security/mac/mac_syscalls.c 122584 2003-11-12 22:19:15Z rwatson $");
46
47#include "opt_mac.h"
48#include "opt_devfs.h"
49
50#include <sys/param.h>
51#include <sys/condvar.h>
52#include <sys/extattr.h>
53#include <sys/imgact.h>
54#include <sys/kernel.h>
55#include <sys/lock.h>
56#include <sys/malloc.h>
57#include <sys/mutex.h>
58#include <sys/mac.h>
59#include <sys/module.h>
60#include <sys/proc.h>
61#include <sys/sbuf.h>
62#include <sys/systm.h>
63#include <sys/sysproto.h>
64#include <sys/sysent.h>
65#include <sys/vnode.h>
66#include <sys/mount.h>
67#include <sys/file.h>
68#include <sys/namei.h>
69#include <sys/socket.h>
70#include <sys/pipe.h>
71#include <sys/socketvar.h>
72#include <sys/sysctl.h>
73
74#include <vm/vm.h>
75#include <vm/pmap.h>
76#include <vm/vm_map.h>
77#include <vm/vm_object.h>
78
79#include <sys/mac_policy.h>
80
81#include <fs/devfs/devfs.h>
82
83#include <net/bpfdesc.h>
84#include <net/if.h>
85#include <net/if_var.h>
86
87#include <netinet/in.h>
88#include <netinet/ip_var.h>
89
90#include <security/mac/mac_internal.h>
91
92#ifdef MAC
93
94/*
95 * Declare that the kernel provides MAC support, version 1.  This permits
96 * modules to refuse to be loaded if the necessary support isn't present,
97 * even if it's pre-boot.
98 */
99MODULE_VERSION(kernel_mac_support, 1);
100
101SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW, 0,
102    "TrustedBSD MAC policy controls");
103
104#if MAC_MAX_SLOTS > 32
105#error "MAC_MAX_SLOTS too large"
106#endif
107
108static unsigned int mac_max_slots = MAC_MAX_SLOTS;
109static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
110SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD,
111    &mac_max_slots, 0, "");
112
113/*
114 * Has the kernel started generating labeled objects yet?  All read/write
115 * access to this variable is serialized during the boot process.  Following
116 * the end of serialization, we don't update this flag; no locking.
117 */
118int	mac_late = 0;
119
120/*
121 * Flag to indicate whether or not we should allocate label storage for
122 * new mbufs.  Since most dynamic policies we currently work with don't
123 * rely on mbuf labeling, try to avoid paying the cost of mtag allocation
124 * unless specifically notified of interest.  One result of this is
125 * that if a dynamically loaded policy requests mbuf labels, it must
126 * be able to deal with a NULL label being returned on any mbufs that
127 * were already in flight when the policy was loaded.  Since the policy
128 * already has to deal with uninitialized labels, this probably won't
129 * be a problem.  Note: currently no locking.  Will this be a problem?
130 */
131#ifndef MAC_ALWAYS_LABEL_MBUF
132int	mac_labelmbufs = 0;
133#endif
134
135#ifdef MAC_DEBUG
136SYSCTL_NODE(_security_mac, OID_AUTO, debug, CTLFLAG_RW, 0,
137    "TrustedBSD MAC debug info");
138SYSCTL_NODE(_security_mac_debug, OID_AUTO, counters, CTLFLAG_RW, 0,
139    "TrustedBSD MAC object counters");
140
141static unsigned int nmactemp;
142SYSCTL_UINT(_security_mac_debug_counters, OID_AUTO, temp, CTLFLAG_RD,
143    &nmactemp, 0, "number of temporary labels in use");
144#endif
145
146static int	mac_policy_register(struct mac_policy_conf *mpc);
147static int	mac_policy_unregister(struct mac_policy_conf *mpc);
148
149MALLOC_DEFINE(M_MACTEMP, "mactemp", "MAC temporary label storage");
150
151/*
152 * mac_static_policy_list holds a list of policy modules that are not
153 * loaded while the system is "live", and cannot be unloaded.  These
154 * policies can be invoked without holding the busy count.
155 *
156 * mac_policy_list stores the list of dynamic policies.  A busy count is
157 * maintained for the list, stored in mac_policy_busy.  The busy count
158 * is protected by mac_policy_mtx; the list may be modified only
159 * while the busy count is 0, requiring that the lock be held to
160 * prevent new references to the list from being acquired.  For almost
161 * all operations, incrementing the busy count is sufficient to
162 * guarantee consistency, as the list cannot be modified while the
163 * busy count is elevated.  For a few special operations involving a
164 * change to the list of active policies, the mtx itself must be held.
165 * A condition variable, mac_policy_cv, is used to signal potential
166 * exclusive consumers that they should try to acquire the lock if a
167 * first attempt at exclusive access fails.
168 */
169static struct mtx mac_policy_mtx;
170static struct cv mac_policy_cv;
171static int mac_policy_count;
172struct mac_policy_list_head mac_policy_list;
173struct mac_policy_list_head mac_static_policy_list;
174
175/*
176 * We manually invoke WITNESS_WARN() to allow Witness to generate
177 * warnings even if we don't end up ever triggering the wait at
178 * run-time.  The consumer of the exclusive interface must not hold
179 * any locks (other than potentially Giant) since we may sleep for
180 * long (potentially indefinite) periods of time waiting for the
181 * framework to become quiescent so that a policy list change may
182 * be made.
183 */
184void
185mac_policy_grab_exclusive(void)
186{
187
188	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
189 	    "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
190	mtx_lock(&mac_policy_mtx);
191	while (mac_policy_count != 0)
192		cv_wait(&mac_policy_cv, &mac_policy_mtx);
193}
194
195void
196mac_policy_assert_exclusive(void)
197{
198
199	mtx_assert(&mac_policy_mtx, MA_OWNED);
200	KASSERT(mac_policy_count == 0,
201	    ("mac_policy_assert_exclusive(): not exclusive"));
202}
203
204void
205mac_policy_release_exclusive(void)
206{
207
208	KASSERT(mac_policy_count == 0,
209	    ("mac_policy_release_exclusive(): not exclusive"));
210	mtx_unlock(&mac_policy_mtx);
211	cv_signal(&mac_policy_cv);
212}
213
214void
215mac_policy_list_busy(void)
216{
217
218	mtx_lock(&mac_policy_mtx);
219	mac_policy_count++;
220	mtx_unlock(&mac_policy_mtx);
221}
222
223int
224mac_policy_list_conditional_busy(void)
225{
226	int ret;
227
228	mtx_lock(&mac_policy_mtx);
229	if (!LIST_EMPTY(&mac_policy_list)) {
230		mac_policy_count++;
231		ret = 1;
232	} else
233		ret = 0;
234	mtx_unlock(&mac_policy_mtx);
235	return (ret);
236}
237
238void
239mac_policy_list_unbusy(void)
240{
241
242	mtx_lock(&mac_policy_mtx);
243	mac_policy_count--;
244	KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
245	if (mac_policy_count == 0)
246		cv_signal(&mac_policy_cv);
247	mtx_unlock(&mac_policy_mtx);
248}
249
250/*
251 * Initialize the MAC subsystem, including appropriate SMP locks.
252 */
253static void
254mac_init(void)
255{
256
257	LIST_INIT(&mac_static_policy_list);
258	LIST_INIT(&mac_policy_list);
259	mac_labelzone_init();
260
261	mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
262	cv_init(&mac_policy_cv, "mac_policy_cv");
263}
264
265/*
266 * For the purposes of modules that want to know if they were loaded
267 * "early", set the mac_late flag once we've processed modules either
268 * linked into the kernel, or loaded before the kernel startup.
269 */
270static void
271mac_late_init(void)
272{
273
274	mac_late = 1;
275}
276
277/*
278 * After the policy list has changed, walk the list to update any global
279 * flags.  Currently, we support only one flag, and it's conditionally
280 * defined; as a result, the entire function is conditional.  Eventually,
281 * the #else case might also iterate across the policies.
282 */
283static void
284mac_policy_updateflags(void)
285{
286#ifndef MAC_ALWAYS_LABEL_MBUF
287	struct mac_policy_conf *tmpc;
288	int labelmbufs;
289
290	mac_policy_assert_exclusive();
291
292	labelmbufs = 0;
293	LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
294		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
295			labelmbufs++;
296	}
297	LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
298		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
299			labelmbufs++;
300	}
301	mac_labelmbufs = (labelmbufs != 0);
302#endif
303}
304
305/*
306 * Allow MAC policy modules to register during boot, etc.
307 */
308int
309mac_policy_modevent(module_t mod, int type, void *data)
310{
311	struct mac_policy_conf *mpc;
312	int error;
313
314	error = 0;
315	mpc = (struct mac_policy_conf *) data;
316
317	switch (type) {
318	case MOD_LOAD:
319		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
320		    mac_late) {
321			printf("mac_policy_modevent: can't load %s policy "
322			    "after booting\n", mpc->mpc_name);
323			error = EBUSY;
324			break;
325		}
326		error = mac_policy_register(mpc);
327		break;
328	case MOD_UNLOAD:
329		/* Don't unregister the module if it was never registered. */
330		if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
331		    != 0)
332			error = mac_policy_unregister(mpc);
333		else
334			error = 0;
335		break;
336	default:
337		break;
338	}
339
340	return (error);
341}
342
343static int
344mac_policy_register(struct mac_policy_conf *mpc)
345{
346	struct mac_policy_conf *tmpc;
347	int error, slot, static_entry;
348
349	error = 0;
350
351	/*
352	 * We don't technically need exclusive access while !mac_late,
353	 * but hold it for assertion consistency.
354	 */
355	mac_policy_grab_exclusive();
356
357	/*
358	 * If the module can potentially be unloaded, or we're loading
359	 * late, we have to stick it in the non-static list and pay
360	 * an extra performance overhead.  Otherwise, we can pay a
361	 * light locking cost and stick it in the static list.
362	 */
363	static_entry = (!mac_late &&
364	    !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
365
366	if (static_entry) {
367		LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
368			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
369				error = EEXIST;
370				goto out;
371			}
372		}
373	} else {
374		LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
375			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
376				error = EEXIST;
377				goto out;
378			}
379		}
380	}
381	if (mpc->mpc_field_off != NULL) {
382		slot = ffs(mac_slot_offsets_free);
383		if (slot == 0) {
384			error = ENOMEM;
385			goto out;
386		}
387		slot--;
388		mac_slot_offsets_free &= ~(1 << slot);
389		*mpc->mpc_field_off = slot;
390	}
391	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
392
393	/*
394	 * If we're loading a MAC module after the framework has
395	 * initialized, it has to go into the dynamic list.  If
396	 * we're loading it before we've finished initializing,
397	 * it can go into the static list with weaker locker
398	 * requirements.
399	 */
400	if (static_entry)
401		LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
402	else
403		LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
404
405	/* Per-policy initialization. */
406	if (mpc->mpc_ops->mpo_init != NULL)
407		(*(mpc->mpc_ops->mpo_init))(mpc);
408	mac_policy_updateflags();
409
410	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
411	    mpc->mpc_name);
412
413out:
414	mac_policy_release_exclusive();
415	return (error);
416}
417
418static int
419mac_policy_unregister(struct mac_policy_conf *mpc)
420{
421
422	/*
423	 * If we fail the load, we may get a request to unload.  Check
424	 * to see if we did the run-time registration, and if not,
425	 * silently succeed.
426	 */
427	mac_policy_grab_exclusive();
428	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
429		mac_policy_release_exclusive();
430		return (0);
431	}
432#if 0
433	/*
434	 * Don't allow unloading modules with private data.
435	 */
436	if (mpc->mpc_field_off != NULL) {
437		MAC_POLICY_LIST_UNLOCK();
438		return (EBUSY);
439	}
440#endif
441	/*
442	 * Only allow the unload to proceed if the module is unloadable
443	 * by its own definition.
444	 */
445	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
446		mac_policy_release_exclusive();
447		return (EBUSY);
448	}
449	if (mpc->mpc_ops->mpo_destroy != NULL)
450		(*(mpc->mpc_ops->mpo_destroy))(mpc);
451
452	LIST_REMOVE(mpc, mpc_list);
453	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
454	mac_policy_updateflags();
455
456	mac_policy_release_exclusive();
457
458	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
459	    mpc->mpc_name);
460
461	return (0);
462}
463
464/*
465 * Define an error value precedence, and given two arguments, selects the
466 * value with the higher precedence.
467 */
468int
469mac_error_select(int error1, int error2)
470{
471
472	/* Certain decision-making errors take top priority. */
473	if (error1 == EDEADLK || error2 == EDEADLK)
474		return (EDEADLK);
475
476	/* Invalid arguments should be reported where possible. */
477	if (error1 == EINVAL || error2 == EINVAL)
478		return (EINVAL);
479
480	/* Precedence goes to "visibility", with both process and file. */
481	if (error1 == ESRCH || error2 == ESRCH)
482		return (ESRCH);
483
484	if (error1 == ENOENT || error2 == ENOENT)
485		return (ENOENT);
486
487	/* Precedence goes to DAC/MAC protections. */
488	if (error1 == EACCES || error2 == EACCES)
489		return (EACCES);
490
491	/* Precedence goes to privilege. */
492	if (error1 == EPERM || error2 == EPERM)
493		return (EPERM);
494
495	/* Precedence goes to error over success; otherwise, arbitrary. */
496	if (error1 != 0)
497		return (error1);
498	return (error2);
499}
500
501void
502mac_init_label(struct label *label)
503{
504
505	bzero(label, sizeof(*label));
506	label->l_flags = MAC_FLAG_INITIALIZED;
507}
508
509void
510mac_destroy_label(struct label *label)
511{
512
513	KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
514	    ("destroying uninitialized label"));
515
516	bzero(label, sizeof(*label));
517	/* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
518}
519
520int
521mac_check_structmac_consistent(struct mac *mac)
522{
523
524	if (mac->m_buflen < 0 ||
525	    mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
526		return (EINVAL);
527
528	return (0);
529}
530
531/*
532 * MPSAFE
533 */
534int
535__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
536{
537	char *elements, *buffer;
538	struct mac mac;
539	struct proc *tproc;
540	struct ucred *tcred;
541	int error;
542
543	error = copyin(uap->mac_p, &mac, sizeof(mac));
544	if (error)
545		return (error);
546
547	error = mac_check_structmac_consistent(&mac);
548	if (error)
549		return (error);
550
551	tproc = pfind(uap->pid);
552	if (tproc == NULL)
553		return (ESRCH);
554
555	tcred = NULL;				/* Satisfy gcc. */
556	error = p_cansee(td, tproc);
557	if (error == 0)
558		tcred = crhold(tproc->p_ucred);
559	PROC_UNLOCK(tproc);
560	if (error)
561		return (error);
562
563	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
564	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
565	if (error) {
566		free(elements, M_MACTEMP);
567		crfree(tcred);
568		return (error);
569	}
570
571	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
572	error = mac_externalize_cred_label(tcred->cr_label, elements,
573	    buffer, mac.m_buflen);
574	if (error == 0)
575		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
576
577	free(buffer, M_MACTEMP);
578	free(elements, M_MACTEMP);
579	crfree(tcred);
580	return (error);
581}
582
583/*
584 * MPSAFE
585 */
586int
587__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
588{
589	char *elements, *buffer;
590	struct mac mac;
591	int error;
592
593	error = copyin(uap->mac_p, &mac, sizeof(mac));
594	if (error)
595		return (error);
596
597	error = mac_check_structmac_consistent(&mac);
598	if (error)
599		return (error);
600
601	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
602	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
603	if (error) {
604		free(elements, M_MACTEMP);
605		return (error);
606	}
607
608	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
609	error = mac_externalize_cred_label(td->td_ucred->cr_label,
610	    elements, buffer, mac.m_buflen);
611	if (error == 0)
612		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
613
614	free(buffer, M_MACTEMP);
615	free(elements, M_MACTEMP);
616	return (error);
617}
618
619/*
620 * MPSAFE
621 */
622int
623__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
624{
625	struct ucred *newcred, *oldcred;
626	struct label *intlabel;
627	struct proc *p;
628	struct mac mac;
629	char *buffer;
630	int error;
631
632	error = copyin(uap->mac_p, &mac, sizeof(mac));
633	if (error)
634		return (error);
635
636	error = mac_check_structmac_consistent(&mac);
637	if (error)
638		return (error);
639
640	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
641	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
642	if (error) {
643		free(buffer, M_MACTEMP);
644		return (error);
645	}
646
647	intlabel = mac_cred_label_alloc();
648	error = mac_internalize_cred_label(intlabel, buffer);
649	free(buffer, M_MACTEMP);
650	if (error)
651		goto out;
652
653	newcred = crget();
654
655	p = td->td_proc;
656	PROC_LOCK(p);
657	oldcred = p->p_ucred;
658
659	error = mac_check_cred_relabel(oldcred, intlabel);
660	if (error) {
661		PROC_UNLOCK(p);
662		crfree(newcred);
663		goto out;
664	}
665
666	setsugid(p);
667	crcopy(newcred, oldcred);
668	mac_relabel_cred(newcred, intlabel);
669	p->p_ucred = newcred;
670
671	/*
672	 * Grab additional reference for use while revoking mmaps, prior
673	 * to releasing the proc lock and sharing the cred.
674	 */
675	crhold(newcred);
676	PROC_UNLOCK(p);
677
678	if (mac_enforce_vm) {
679		mtx_lock(&Giant);
680		mac_cred_mmapped_drop_perms(td, newcred);
681		mtx_unlock(&Giant);
682	}
683
684	crfree(newcred);	/* Free revocation reference. */
685	crfree(oldcred);
686
687out:
688	mac_cred_label_free(intlabel);
689	return (error);
690}
691
692/*
693 * MPSAFE
694 */
695int
696__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
697{
698	char *elements, *buffer;
699	struct label *intlabel;
700	struct file *fp;
701	struct mac mac;
702	struct vnode *vp;
703	struct pipe *pipe;
704	short label_type;
705	int error;
706
707	error = copyin(uap->mac_p, &mac, sizeof(mac));
708	if (error)
709		return (error);
710
711	error = mac_check_structmac_consistent(&mac);
712	if (error)
713		return (error);
714
715	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
716	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
717	if (error) {
718		free(elements, M_MACTEMP);
719		return (error);
720	}
721
722	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
723	error = fget(td, uap->fd, &fp);
724	if (error)
725		goto out;
726
727	label_type = fp->f_type;
728	switch (fp->f_type) {
729	case DTYPE_FIFO:
730	case DTYPE_VNODE:
731		vp = fp->f_vnode;
732		intlabel = mac_vnode_label_alloc();
733		mtx_lock(&Giant);				/* VFS */
734		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
735		mac_copy_vnode_label(vp->v_label, intlabel);
736		VOP_UNLOCK(vp, 0, td);
737		mtx_unlock(&Giant);				/* VFS */
738		error = mac_externalize_vnode_label(intlabel, elements,
739		    buffer, mac.m_buflen);
740		mac_vnode_label_free(intlabel);
741		break;
742
743	case DTYPE_PIPE:
744		pipe = fp->f_data;
745		intlabel = mac_pipe_label_alloc();
746		PIPE_LOCK(pipe);
747		mac_copy_pipe_label(pipe->pipe_label, intlabel);
748		PIPE_UNLOCK(pipe);
749		error = mac_externalize_pipe_label(intlabel, elements,
750		    buffer, mac.m_buflen);
751		mac_pipe_label_free(intlabel);
752		break;
753
754	default:
755		error = EINVAL;
756	}
757	fdrop(fp, td);
758	if (error == 0)
759		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
760
761out:
762	free(buffer, M_MACTEMP);
763	free(elements, M_MACTEMP);
764	return (error);
765}
766
767/*
768 * MPSAFE
769 */
770int
771__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
772{
773	char *elements, *buffer;
774	struct nameidata nd;
775	struct label *intlabel;
776	struct mac mac;
777	int error;
778
779	error = copyin(uap->mac_p, &mac, sizeof(mac));
780	if (error)
781		return (error);
782
783	error = mac_check_structmac_consistent(&mac);
784	if (error)
785		return (error);
786
787	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
788	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
789	if (error) {
790		free(elements, M_MACTEMP);
791		return (error);
792	}
793
794	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
795	mtx_lock(&Giant);				/* VFS */
796	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
797	    td);
798	error = namei(&nd);
799	if (error)
800		goto out;
801
802	intlabel = mac_vnode_label_alloc();
803	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
804	error = mac_externalize_vnode_label(intlabel, elements, buffer,
805	    mac.m_buflen);
806
807	NDFREE(&nd, 0);
808	mac_vnode_label_free(intlabel);
809
810	if (error == 0)
811		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
812
813out:
814	mtx_unlock(&Giant);				/* VFS */
815
816	free(buffer, M_MACTEMP);
817	free(elements, M_MACTEMP);
818
819	return (error);
820}
821
822/*
823 * MPSAFE
824 */
825int
826__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
827{
828	char *elements, *buffer;
829	struct nameidata nd;
830	struct label *intlabel;
831	struct mac mac;
832	int error;
833
834	error = copyin(uap->mac_p, &mac, sizeof(mac));
835	if (error)
836		return (error);
837
838	error = mac_check_structmac_consistent(&mac);
839	if (error)
840		return (error);
841
842	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
843	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
844	if (error) {
845		free(elements, M_MACTEMP);
846		return (error);
847	}
848
849	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
850	mtx_lock(&Giant);				/* VFS */
851	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
852	    td);
853	error = namei(&nd);
854	if (error)
855		goto out;
856
857	intlabel = mac_vnode_label_alloc();
858	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
859	error = mac_externalize_vnode_label(intlabel, elements, buffer,
860	    mac.m_buflen);
861	NDFREE(&nd, 0);
862	mac_vnode_label_free(intlabel);
863
864	if (error == 0)
865		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
866
867out:
868	mtx_unlock(&Giant);				/* VFS */
869
870	free(buffer, M_MACTEMP);
871	free(elements, M_MACTEMP);
872
873	return (error);
874}
875
876/*
877 * MPSAFE
878 */
879int
880__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
881{
882	struct label *intlabel;
883	struct pipe *pipe;
884	struct file *fp;
885	struct mount *mp;
886	struct vnode *vp;
887	struct mac mac;
888	char *buffer;
889	int error;
890
891	error = copyin(uap->mac_p, &mac, sizeof(mac));
892	if (error)
893		return (error);
894
895	error = mac_check_structmac_consistent(&mac);
896	if (error)
897		return (error);
898
899	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
900	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
901	if (error) {
902		free(buffer, M_MACTEMP);
903		return (error);
904	}
905
906	error = fget(td, uap->fd, &fp);
907	if (error)
908		goto out;
909
910	switch (fp->f_type) {
911	case DTYPE_FIFO:
912	case DTYPE_VNODE:
913		intlabel = mac_vnode_label_alloc();
914		error = mac_internalize_vnode_label(intlabel, buffer);
915		if (error) {
916			mac_vnode_label_free(intlabel);
917			break;
918		}
919		vp = fp->f_vnode;
920		mtx_lock(&Giant);				/* VFS */
921		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
922		if (error != 0) {
923			mtx_unlock(&Giant);			/* VFS */
924			mac_vnode_label_free(intlabel);
925			break;
926		}
927		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
928		error = vn_setlabel(vp, intlabel, td->td_ucred);
929		VOP_UNLOCK(vp, 0, td);
930		vn_finished_write(mp);
931		mtx_unlock(&Giant);				/* VFS */
932		mac_vnode_label_free(intlabel);
933		break;
934
935	case DTYPE_PIPE:
936		intlabel = mac_pipe_label_alloc();
937		error = mac_internalize_pipe_label(intlabel, buffer);
938		if (error == 0) {
939			pipe = fp->f_data;
940			PIPE_LOCK(pipe);
941			error = mac_pipe_label_set(td->td_ucred, pipe,
942			    intlabel);
943			PIPE_UNLOCK(pipe);
944		}
945		mac_pipe_label_free(intlabel);
946		break;
947
948	default:
949		error = EINVAL;
950	}
951	fdrop(fp, td);
952out:
953	free(buffer, M_MACTEMP);
954	return (error);
955}
956
957/*
958 * MPSAFE
959 */
960int
961__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
962{
963	struct label *intlabel;
964	struct nameidata nd;
965	struct mount *mp;
966	struct mac mac;
967	char *buffer;
968	int error;
969
970	error = copyin(uap->mac_p, &mac, sizeof(mac));
971	if (error)
972		return (error);
973
974	error = mac_check_structmac_consistent(&mac);
975	if (error)
976		return (error);
977
978	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
979	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
980	if (error) {
981		free(buffer, M_MACTEMP);
982		return (error);
983	}
984
985	intlabel = mac_vnode_label_alloc();
986	error = mac_internalize_vnode_label(intlabel, buffer);
987	free(buffer, M_MACTEMP);
988	if (error)
989		goto out;
990
991	mtx_lock(&Giant);				/* VFS */
992
993	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
994	    td);
995	error = namei(&nd);
996	if (error == 0) {
997		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
998		if (error == 0)
999			error = vn_setlabel(nd.ni_vp, intlabel,
1000			    td->td_ucred);
1001		vn_finished_write(mp);
1002	}
1003
1004	NDFREE(&nd, 0);
1005	mtx_unlock(&Giant);				/* VFS */
1006out:
1007	mac_vnode_label_free(intlabel);
1008	return (error);
1009}
1010
1011/*
1012 * MPSAFE
1013 */
1014int
1015__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1016{
1017	struct label *intlabel;
1018	struct nameidata nd;
1019	struct mount *mp;
1020	struct mac mac;
1021	char *buffer;
1022	int error;
1023
1024	error = copyin(uap->mac_p, &mac, sizeof(mac));
1025	if (error)
1026		return (error);
1027
1028	error = mac_check_structmac_consistent(&mac);
1029	if (error)
1030		return (error);
1031
1032	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1033	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1034	if (error) {
1035		free(buffer, M_MACTEMP);
1036		return (error);
1037	}
1038
1039	intlabel = mac_vnode_label_alloc();
1040	error = mac_internalize_vnode_label(intlabel, buffer);
1041	free(buffer, M_MACTEMP);
1042	if (error)
1043		goto out;
1044
1045	mtx_lock(&Giant);				/* VFS */
1046
1047	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
1048	    td);
1049	error = namei(&nd);
1050	if (error == 0) {
1051		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1052		if (error == 0)
1053			error = vn_setlabel(nd.ni_vp, intlabel,
1054			    td->td_ucred);
1055		vn_finished_write(mp);
1056	}
1057
1058	NDFREE(&nd, 0);
1059	mtx_unlock(&Giant);				/* VFS */
1060out:
1061	mac_vnode_label_free(intlabel);
1062	return (error);
1063}
1064
1065/*
1066 * MPSAFE
1067 */
1068int
1069mac_syscall(struct thread *td, struct mac_syscall_args *uap)
1070{
1071	struct mac_policy_conf *mpc;
1072	char target[MAC_MAX_POLICY_NAME];
1073	int entrycount, error;
1074
1075	error = copyinstr(uap->policy, target, sizeof(target), NULL);
1076	if (error)
1077		return (error);
1078
1079	error = ENOSYS;
1080	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1081		if (strcmp(mpc->mpc_name, target) == 0 &&
1082		    mpc->mpc_ops->mpo_syscall != NULL) {
1083			error = mpc->mpc_ops->mpo_syscall(td,
1084			    uap->call, uap->arg);
1085			goto out;
1086		}
1087	}
1088
1089	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1090		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1091			if (strcmp(mpc->mpc_name, target) == 0 &&
1092			    mpc->mpc_ops->mpo_syscall != NULL) {
1093				error = mpc->mpc_ops->mpo_syscall(td,
1094				    uap->call, uap->arg);
1095				break;
1096			}
1097		}
1098		mac_policy_list_unbusy();
1099	}
1100out:
1101	return (error);
1102}
1103
1104SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1105SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1106
1107#else /* !MAC */
1108
1109int
1110__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1111{
1112
1113	return (ENOSYS);
1114}
1115
1116int
1117__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1118{
1119
1120	return (ENOSYS);
1121}
1122
1123int
1124__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1125{
1126
1127	return (ENOSYS);
1128}
1129
1130int
1131__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1132{
1133
1134	return (ENOSYS);
1135}
1136
1137int
1138__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1139{
1140
1141	return (ENOSYS);
1142}
1143
1144int
1145__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1146{
1147
1148	return (ENOSYS);
1149}
1150
1151int
1152__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1153{
1154
1155	return (ENOSYS);
1156}
1157
1158int
1159__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1160{
1161
1162	return (ENOSYS);
1163}
1164
1165int
1166__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1167{
1168
1169	return (ENOSYS);
1170}
1171
1172int
1173mac_syscall(struct thread *td, struct mac_syscall_args *uap)
1174{
1175
1176	return (ENOSYS);
1177}
1178
1179#endif
1180