mac_syscalls.c revision 132199
1/*-
2 * Copyright (c) 1999-2002 Robert N. M. Watson
3 * Copyright (c) 2001 Ilmar S. Habibulin
4 * Copyright (c) 2001-2004 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 132199 2004-07-15 08:26:07Z phk $");
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 */
169#ifndef MAC_STATIC
170static struct mtx mac_policy_mtx;
171static struct cv mac_policy_cv;
172static int mac_policy_count;
173#endif
174struct mac_policy_list_head mac_policy_list;
175struct mac_policy_list_head mac_static_policy_list;
176
177/*
178 * We manually invoke WITNESS_WARN() to allow Witness to generate
179 * warnings even if we don't end up ever triggering the wait at
180 * run-time.  The consumer of the exclusive interface must not hold
181 * any locks (other than potentially Giant) since we may sleep for
182 * long (potentially indefinite) periods of time waiting for the
183 * framework to become quiescent so that a policy list change may
184 * be made.
185 */
186void
187mac_policy_grab_exclusive(void)
188{
189
190#ifndef MAC_STATIC
191	WITNESS_WARN(WARN_GIANTOK | WARN_SLEEPOK, NULL,
192 	    "mac_policy_grab_exclusive() at %s:%d", __FILE__, __LINE__);
193	mtx_lock(&mac_policy_mtx);
194	while (mac_policy_count != 0)
195		cv_wait(&mac_policy_cv, &mac_policy_mtx);
196#endif
197}
198
199void
200mac_policy_assert_exclusive(void)
201{
202
203#ifndef MAC_STATIC
204	mtx_assert(&mac_policy_mtx, MA_OWNED);
205	KASSERT(mac_policy_count == 0,
206	    ("mac_policy_assert_exclusive(): not exclusive"));
207#endif
208}
209
210void
211mac_policy_release_exclusive(void)
212{
213
214#ifndef MAC_STATIC
215	KASSERT(mac_policy_count == 0,
216	    ("mac_policy_release_exclusive(): not exclusive"));
217	mtx_unlock(&mac_policy_mtx);
218	cv_signal(&mac_policy_cv);
219#endif
220}
221
222void
223mac_policy_list_busy(void)
224{
225
226#ifndef MAC_STATIC
227	mtx_lock(&mac_policy_mtx);
228	mac_policy_count++;
229	mtx_unlock(&mac_policy_mtx);
230#endif
231}
232
233int
234mac_policy_list_conditional_busy(void)
235{
236#ifndef MAC_STATIC
237	int ret;
238
239	mtx_lock(&mac_policy_mtx);
240	if (!LIST_EMPTY(&mac_policy_list)) {
241		mac_policy_count++;
242		ret = 1;
243	} else
244		ret = 0;
245	mtx_unlock(&mac_policy_mtx);
246	return (ret);
247#else
248	return (1);
249#endif
250}
251
252void
253mac_policy_list_unbusy(void)
254{
255
256#ifndef MAC_STATIC
257	mtx_lock(&mac_policy_mtx);
258	mac_policy_count--;
259	KASSERT(mac_policy_count >= 0, ("MAC_POLICY_LIST_LOCK"));
260	if (mac_policy_count == 0)
261		cv_signal(&mac_policy_cv);
262	mtx_unlock(&mac_policy_mtx);
263#endif
264}
265
266/*
267 * Initialize the MAC subsystem, including appropriate SMP locks.
268 */
269static void
270mac_init(void)
271{
272
273	LIST_INIT(&mac_static_policy_list);
274	LIST_INIT(&mac_policy_list);
275	mac_labelzone_init();
276
277#ifndef MAC_STATIC
278	mtx_init(&mac_policy_mtx, "mac_policy_mtx", NULL, MTX_DEF);
279	cv_init(&mac_policy_cv, "mac_policy_cv");
280#endif
281}
282
283/*
284 * For the purposes of modules that want to know if they were loaded
285 * "early", set the mac_late flag once we've processed modules either
286 * linked into the kernel, or loaded before the kernel startup.
287 */
288static void
289mac_late_init(void)
290{
291
292	mac_late = 1;
293}
294
295/*
296 * After the policy list has changed, walk the list to update any global
297 * flags.  Currently, we support only one flag, and it's conditionally
298 * defined; as a result, the entire function is conditional.  Eventually,
299 * the #else case might also iterate across the policies.
300 */
301static void
302mac_policy_updateflags(void)
303{
304#ifndef MAC_ALWAYS_LABEL_MBUF
305	struct mac_policy_conf *tmpc;
306	int labelmbufs;
307
308	mac_policy_assert_exclusive();
309
310	labelmbufs = 0;
311	LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
312		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
313			labelmbufs++;
314	}
315	LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
316		if (tmpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_LABELMBUFS)
317			labelmbufs++;
318	}
319	mac_labelmbufs = (labelmbufs != 0);
320#endif
321}
322
323/*
324 * Allow MAC policy modules to register during boot, etc.
325 */
326int
327mac_policy_modevent(module_t mod, int type, void *data)
328{
329	struct mac_policy_conf *mpc;
330	int error;
331
332	error = 0;
333	mpc = (struct mac_policy_conf *) data;
334
335#ifdef MAC_STATIC
336	if (mac_late) {
337		printf("mac_policy_modevent: MAC_STATIC and late\n");
338		return (EBUSY);
339	}
340#endif
341
342	switch (type) {
343	case MOD_LOAD:
344		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE &&
345		    mac_late) {
346			printf("mac_policy_modevent: can't load %s policy "
347			    "after booting\n", mpc->mpc_name);
348			error = EBUSY;
349			break;
350		}
351		error = mac_policy_register(mpc);
352		break;
353	case MOD_UNLOAD:
354		/* Don't unregister the module if it was never registered. */
355		if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED)
356		    != 0)
357			error = mac_policy_unregister(mpc);
358		else
359			error = 0;
360		break;
361	default:
362		error = EOPNOTSUPP;
363		break;
364	}
365
366	return (error);
367}
368
369static int
370mac_policy_register(struct mac_policy_conf *mpc)
371{
372	struct mac_policy_conf *tmpc;
373	int error, slot, static_entry;
374
375	error = 0;
376
377	/*
378	 * We don't technically need exclusive access while !mac_late,
379	 * but hold it for assertion consistency.
380	 */
381	mac_policy_grab_exclusive();
382
383	/*
384	 * If the module can potentially be unloaded, or we're loading
385	 * late, we have to stick it in the non-static list and pay
386	 * an extra performance overhead.  Otherwise, we can pay a
387	 * light locking cost and stick it in the static list.
388	 */
389	static_entry = (!mac_late &&
390	    !(mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK));
391
392	if (static_entry) {
393		LIST_FOREACH(tmpc, &mac_static_policy_list, mpc_list) {
394			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
395				error = EEXIST;
396				goto out;
397			}
398		}
399	} else {
400		LIST_FOREACH(tmpc, &mac_policy_list, mpc_list) {
401			if (strcmp(tmpc->mpc_name, mpc->mpc_name) == 0) {
402				error = EEXIST;
403				goto out;
404			}
405		}
406	}
407	if (mpc->mpc_field_off != NULL) {
408		slot = ffs(mac_slot_offsets_free);
409		if (slot == 0) {
410			error = ENOMEM;
411			goto out;
412		}
413		slot--;
414		mac_slot_offsets_free &= ~(1 << slot);
415		*mpc->mpc_field_off = slot;
416	}
417	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
418
419	/*
420	 * If we're loading a MAC module after the framework has
421	 * initialized, it has to go into the dynamic list.  If
422	 * we're loading it before we've finished initializing,
423	 * it can go into the static list with weaker locker
424	 * requirements.
425	 */
426	if (static_entry)
427		LIST_INSERT_HEAD(&mac_static_policy_list, mpc, mpc_list);
428	else
429		LIST_INSERT_HEAD(&mac_policy_list, mpc, mpc_list);
430
431	/* Per-policy initialization. */
432	if (mpc->mpc_ops->mpo_init != NULL)
433		(*(mpc->mpc_ops->mpo_init))(mpc);
434	mac_policy_updateflags();
435
436	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
437	    mpc->mpc_name);
438
439out:
440	mac_policy_release_exclusive();
441	return (error);
442}
443
444static int
445mac_policy_unregister(struct mac_policy_conf *mpc)
446{
447
448	/*
449	 * If we fail the load, we may get a request to unload.  Check
450	 * to see if we did the run-time registration, and if not,
451	 * silently succeed.
452	 */
453	mac_policy_grab_exclusive();
454	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
455		mac_policy_release_exclusive();
456		return (0);
457	}
458#if 0
459	/*
460	 * Don't allow unloading modules with private data.
461	 */
462	if (mpc->mpc_field_off != NULL) {
463		MAC_POLICY_LIST_UNLOCK();
464		return (EBUSY);
465	}
466#endif
467	/*
468	 * Only allow the unload to proceed if the module is unloadable
469	 * by its own definition.
470	 */
471	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
472		mac_policy_release_exclusive();
473		return (EBUSY);
474	}
475	if (mpc->mpc_ops->mpo_destroy != NULL)
476		(*(mpc->mpc_ops->mpo_destroy))(mpc);
477
478	LIST_REMOVE(mpc, mpc_list);
479	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
480	mac_policy_updateflags();
481
482	mac_policy_release_exclusive();
483
484	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
485	    mpc->mpc_name);
486
487	return (0);
488}
489
490/*
491 * Define an error value precedence, and given two arguments, selects the
492 * value with the higher precedence.
493 */
494int
495mac_error_select(int error1, int error2)
496{
497
498	/* Certain decision-making errors take top priority. */
499	if (error1 == EDEADLK || error2 == EDEADLK)
500		return (EDEADLK);
501
502	/* Invalid arguments should be reported where possible. */
503	if (error1 == EINVAL || error2 == EINVAL)
504		return (EINVAL);
505
506	/* Precedence goes to "visibility", with both process and file. */
507	if (error1 == ESRCH || error2 == ESRCH)
508		return (ESRCH);
509
510	if (error1 == ENOENT || error2 == ENOENT)
511		return (ENOENT);
512
513	/* Precedence goes to DAC/MAC protections. */
514	if (error1 == EACCES || error2 == EACCES)
515		return (EACCES);
516
517	/* Precedence goes to privilege. */
518	if (error1 == EPERM || error2 == EPERM)
519		return (EPERM);
520
521	/* Precedence goes to error over success; otherwise, arbitrary. */
522	if (error1 != 0)
523		return (error1);
524	return (error2);
525}
526
527void
528mac_init_label(struct label *label)
529{
530
531	bzero(label, sizeof(*label));
532	label->l_flags = MAC_FLAG_INITIALIZED;
533}
534
535void
536mac_destroy_label(struct label *label)
537{
538
539	KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
540	    ("destroying uninitialized label"));
541
542	bzero(label, sizeof(*label));
543	/* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
544}
545
546int
547mac_check_structmac_consistent(struct mac *mac)
548{
549
550	if (mac->m_buflen < 0 ||
551	    mac->m_buflen > MAC_MAX_LABEL_BUF_LEN)
552		return (EINVAL);
553
554	return (0);
555}
556
557/*
558 * MPSAFE
559 */
560int
561__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
562{
563	char *elements, *buffer;
564	struct mac mac;
565	struct proc *tproc;
566	struct ucred *tcred;
567	int error;
568
569	error = copyin(uap->mac_p, &mac, sizeof(mac));
570	if (error)
571		return (error);
572
573	error = mac_check_structmac_consistent(&mac);
574	if (error)
575		return (error);
576
577	tproc = pfind(uap->pid);
578	if (tproc == NULL)
579		return (ESRCH);
580
581	tcred = NULL;				/* Satisfy gcc. */
582	error = p_cansee(td, tproc);
583	if (error == 0)
584		tcred = crhold(tproc->p_ucred);
585	PROC_UNLOCK(tproc);
586	if (error)
587		return (error);
588
589	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
590	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
591	if (error) {
592		free(elements, M_MACTEMP);
593		crfree(tcred);
594		return (error);
595	}
596
597	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
598	error = mac_externalize_cred_label(tcred->cr_label, elements,
599	    buffer, mac.m_buflen);
600	if (error == 0)
601		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
602
603	free(buffer, M_MACTEMP);
604	free(elements, M_MACTEMP);
605	crfree(tcred);
606	return (error);
607}
608
609/*
610 * MPSAFE
611 */
612int
613__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
614{
615	char *elements, *buffer;
616	struct mac mac;
617	int error;
618
619	error = copyin(uap->mac_p, &mac, sizeof(mac));
620	if (error)
621		return (error);
622
623	error = mac_check_structmac_consistent(&mac);
624	if (error)
625		return (error);
626
627	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
628	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
629	if (error) {
630		free(elements, M_MACTEMP);
631		return (error);
632	}
633
634	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
635	error = mac_externalize_cred_label(td->td_ucred->cr_label,
636	    elements, buffer, mac.m_buflen);
637	if (error == 0)
638		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
639
640	free(buffer, M_MACTEMP);
641	free(elements, M_MACTEMP);
642	return (error);
643}
644
645/*
646 * MPSAFE
647 */
648int
649__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
650{
651	struct ucred *newcred, *oldcred;
652	struct label *intlabel;
653	struct proc *p;
654	struct mac mac;
655	char *buffer;
656	int error;
657
658	error = copyin(uap->mac_p, &mac, sizeof(mac));
659	if (error)
660		return (error);
661
662	error = mac_check_structmac_consistent(&mac);
663	if (error)
664		return (error);
665
666	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
667	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
668	if (error) {
669		free(buffer, M_MACTEMP);
670		return (error);
671	}
672
673	intlabel = mac_cred_label_alloc();
674	error = mac_internalize_cred_label(intlabel, buffer);
675	free(buffer, M_MACTEMP);
676	if (error)
677		goto out;
678
679	newcred = crget();
680
681	p = td->td_proc;
682	PROC_LOCK(p);
683	oldcred = p->p_ucred;
684
685	error = mac_check_cred_relabel(oldcred, intlabel);
686	if (error) {
687		PROC_UNLOCK(p);
688		crfree(newcred);
689		goto out;
690	}
691
692	setsugid(p);
693	crcopy(newcred, oldcred);
694	mac_relabel_cred(newcred, intlabel);
695	p->p_ucred = newcred;
696
697	/*
698	 * Grab additional reference for use while revoking mmaps, prior
699	 * to releasing the proc lock and sharing the cred.
700	 */
701	crhold(newcred);
702	PROC_UNLOCK(p);
703
704	if (mac_enforce_vm) {
705		mtx_lock(&Giant);
706		mac_cred_mmapped_drop_perms(td, newcred);
707		mtx_unlock(&Giant);
708	}
709
710	crfree(newcred);	/* Free revocation reference. */
711	crfree(oldcred);
712
713out:
714	mac_cred_label_free(intlabel);
715	return (error);
716}
717
718/*
719 * MPSAFE
720 */
721int
722__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
723{
724	char *elements, *buffer;
725	struct label *intlabel;
726	struct file *fp;
727	struct mac mac;
728	struct vnode *vp;
729	struct pipe *pipe;
730	struct socket *so;
731	short label_type;
732	int error;
733
734	error = copyin(uap->mac_p, &mac, sizeof(mac));
735	if (error)
736		return (error);
737
738	error = mac_check_structmac_consistent(&mac);
739	if (error)
740		return (error);
741
742	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
743	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
744	if (error) {
745		free(elements, M_MACTEMP);
746		return (error);
747	}
748
749	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
750	error = fget(td, uap->fd, &fp);
751	if (error)
752		goto out;
753
754	label_type = fp->f_type;
755	switch (fp->f_type) {
756	case DTYPE_FIFO:
757	case DTYPE_VNODE:
758		vp = fp->f_vnode;
759		intlabel = mac_vnode_label_alloc();
760		mtx_lock(&Giant);				/* VFS */
761		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
762		mac_copy_vnode_label(vp->v_label, intlabel);
763		VOP_UNLOCK(vp, 0, td);
764		mtx_unlock(&Giant);				/* VFS */
765		error = mac_externalize_vnode_label(intlabel, elements,
766		    buffer, mac.m_buflen);
767		mac_vnode_label_free(intlabel);
768		break;
769
770	case DTYPE_PIPE:
771		pipe = fp->f_data;
772		intlabel = mac_pipe_label_alloc();
773		PIPE_LOCK(pipe);
774		mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel);
775		PIPE_UNLOCK(pipe);
776		error = mac_externalize_pipe_label(intlabel, elements,
777		    buffer, mac.m_buflen);
778		mac_pipe_label_free(intlabel);
779		break;
780
781	case DTYPE_SOCKET:
782		so = fp->f_data;
783		intlabel = mac_socket_label_alloc(M_WAITOK);
784		mtx_lock(&Giant);				/* Sockets */
785		/* XXX: Socket lock here. */
786		mac_copy_socket_label(so->so_label, intlabel);
787		/* XXX: Socket unlock here. */
788		mtx_unlock(&Giant);				/* Sockets */
789		error = mac_externalize_socket_label(intlabel, elements,
790		    buffer, mac.m_buflen);
791		mac_socket_label_free(intlabel);
792		break;
793
794	default:
795		error = EINVAL;
796	}
797	fdrop(fp, td);
798	if (error == 0)
799		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
800
801out:
802	free(buffer, M_MACTEMP);
803	free(elements, M_MACTEMP);
804	return (error);
805}
806
807/*
808 * MPSAFE
809 */
810int
811__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
812{
813	char *elements, *buffer;
814	struct nameidata nd;
815	struct label *intlabel;
816	struct mac mac;
817	int error;
818
819	error = copyin(uap->mac_p, &mac, sizeof(mac));
820	if (error)
821		return (error);
822
823	error = mac_check_structmac_consistent(&mac);
824	if (error)
825		return (error);
826
827	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
828	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
829	if (error) {
830		free(elements, M_MACTEMP);
831		return (error);
832	}
833
834	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
835	mtx_lock(&Giant);				/* VFS */
836	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
837	    td);
838	error = namei(&nd);
839	if (error)
840		goto out;
841
842	intlabel = mac_vnode_label_alloc();
843	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
844	error = mac_externalize_vnode_label(intlabel, elements, buffer,
845	    mac.m_buflen);
846
847	NDFREE(&nd, 0);
848	mac_vnode_label_free(intlabel);
849
850	if (error == 0)
851		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
852
853out:
854	mtx_unlock(&Giant);				/* VFS */
855
856	free(buffer, M_MACTEMP);
857	free(elements, M_MACTEMP);
858
859	return (error);
860}
861
862/*
863 * MPSAFE
864 */
865int
866__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
867{
868	char *elements, *buffer;
869	struct nameidata nd;
870	struct label *intlabel;
871	struct mac mac;
872	int error;
873
874	error = copyin(uap->mac_p, &mac, sizeof(mac));
875	if (error)
876		return (error);
877
878	error = mac_check_structmac_consistent(&mac);
879	if (error)
880		return (error);
881
882	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
883	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
884	if (error) {
885		free(elements, M_MACTEMP);
886		return (error);
887	}
888
889	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
890	mtx_lock(&Giant);				/* VFS */
891	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
892	    td);
893	error = namei(&nd);
894	if (error)
895		goto out;
896
897	intlabel = mac_vnode_label_alloc();
898	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
899	error = mac_externalize_vnode_label(intlabel, elements, buffer,
900	    mac.m_buflen);
901	NDFREE(&nd, 0);
902	mac_vnode_label_free(intlabel);
903
904	if (error == 0)
905		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
906
907out:
908	mtx_unlock(&Giant);				/* VFS */
909
910	free(buffer, M_MACTEMP);
911	free(elements, M_MACTEMP);
912
913	return (error);
914}
915
916/*
917 * MPSAFE
918 */
919int
920__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
921{
922	struct label *intlabel;
923	struct pipe *pipe;
924	struct socket *so;
925	struct file *fp;
926	struct mount *mp;
927	struct vnode *vp;
928	struct mac mac;
929	char *buffer;
930	int error;
931
932	error = copyin(uap->mac_p, &mac, sizeof(mac));
933	if (error)
934		return (error);
935
936	error = mac_check_structmac_consistent(&mac);
937	if (error)
938		return (error);
939
940	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
941	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
942	if (error) {
943		free(buffer, M_MACTEMP);
944		return (error);
945	}
946
947	error = fget(td, uap->fd, &fp);
948	if (error)
949		goto out;
950
951	switch (fp->f_type) {
952	case DTYPE_FIFO:
953	case DTYPE_VNODE:
954		intlabel = mac_vnode_label_alloc();
955		error = mac_internalize_vnode_label(intlabel, buffer);
956		if (error) {
957			mac_vnode_label_free(intlabel);
958			break;
959		}
960		vp = fp->f_vnode;
961		mtx_lock(&Giant);				/* VFS */
962		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
963		if (error != 0) {
964			mtx_unlock(&Giant);			/* VFS */
965			mac_vnode_label_free(intlabel);
966			break;
967		}
968		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
969		error = vn_setlabel(vp, intlabel, td->td_ucred);
970		VOP_UNLOCK(vp, 0, td);
971		vn_finished_write(mp);
972		mtx_unlock(&Giant);				/* VFS */
973		mac_vnode_label_free(intlabel);
974		break;
975
976	case DTYPE_PIPE:
977		intlabel = mac_pipe_label_alloc();
978		error = mac_internalize_pipe_label(intlabel, buffer);
979		if (error == 0) {
980			pipe = fp->f_data;
981			PIPE_LOCK(pipe);
982			error = mac_pipe_label_set(td->td_ucred,
983			    pipe->pipe_pair, intlabel);
984			PIPE_UNLOCK(pipe);
985		}
986		mac_pipe_label_free(intlabel);
987		break;
988
989	case DTYPE_SOCKET:
990		intlabel = mac_socket_label_alloc(M_WAITOK);
991		error = mac_internalize_socket_label(intlabel, buffer);
992		if (error == 0) {
993			so = fp->f_data;
994			mtx_lock(&Giant);			/* Sockets */
995			/* XXX: Socket lock here. */
996			error = mac_socket_label_set(td->td_ucred, so,
997			    intlabel);
998			/* XXX: Socket unlock here. */
999			mtx_unlock(&Giant);			/* Sockets */
1000		}
1001		mac_socket_label_free(intlabel);
1002		break;
1003
1004	default:
1005		error = EINVAL;
1006	}
1007	fdrop(fp, td);
1008out:
1009	free(buffer, M_MACTEMP);
1010	return (error);
1011}
1012
1013/*
1014 * MPSAFE
1015 */
1016int
1017__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1018{
1019	struct label *intlabel;
1020	struct nameidata nd;
1021	struct mount *mp;
1022	struct mac mac;
1023	char *buffer;
1024	int error;
1025
1026	error = copyin(uap->mac_p, &mac, sizeof(mac));
1027	if (error)
1028		return (error);
1029
1030	error = mac_check_structmac_consistent(&mac);
1031	if (error)
1032		return (error);
1033
1034	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1035	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1036	if (error) {
1037		free(buffer, M_MACTEMP);
1038		return (error);
1039	}
1040
1041	intlabel = mac_vnode_label_alloc();
1042	error = mac_internalize_vnode_label(intlabel, buffer);
1043	free(buffer, M_MACTEMP);
1044	if (error)
1045		goto out;
1046
1047	mtx_lock(&Giant);				/* VFS */
1048
1049	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
1050	    td);
1051	error = namei(&nd);
1052	if (error == 0) {
1053		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1054		if (error == 0)
1055			error = vn_setlabel(nd.ni_vp, intlabel,
1056			    td->td_ucred);
1057		vn_finished_write(mp);
1058	}
1059
1060	NDFREE(&nd, 0);
1061	mtx_unlock(&Giant);				/* VFS */
1062out:
1063	mac_vnode_label_free(intlabel);
1064	return (error);
1065}
1066
1067/*
1068 * MPSAFE
1069 */
1070int
1071__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1072{
1073	struct label *intlabel;
1074	struct nameidata nd;
1075	struct mount *mp;
1076	struct mac mac;
1077	char *buffer;
1078	int error;
1079
1080	error = copyin(uap->mac_p, &mac, sizeof(mac));
1081	if (error)
1082		return (error);
1083
1084	error = mac_check_structmac_consistent(&mac);
1085	if (error)
1086		return (error);
1087
1088	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1089	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1090	if (error) {
1091		free(buffer, M_MACTEMP);
1092		return (error);
1093	}
1094
1095	intlabel = mac_vnode_label_alloc();
1096	error = mac_internalize_vnode_label(intlabel, buffer);
1097	free(buffer, M_MACTEMP);
1098	if (error)
1099		goto out;
1100
1101	mtx_lock(&Giant);				/* VFS */
1102
1103	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
1104	    td);
1105	error = namei(&nd);
1106	if (error == 0) {
1107		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1108		if (error == 0)
1109			error = vn_setlabel(nd.ni_vp, intlabel,
1110			    td->td_ucred);
1111		vn_finished_write(mp);
1112	}
1113
1114	NDFREE(&nd, 0);
1115	mtx_unlock(&Giant);				/* VFS */
1116out:
1117	mac_vnode_label_free(intlabel);
1118	return (error);
1119}
1120
1121/*
1122 * MPSAFE
1123 */
1124int
1125mac_syscall(struct thread *td, struct mac_syscall_args *uap)
1126{
1127	struct mac_policy_conf *mpc;
1128	char target[MAC_MAX_POLICY_NAME];
1129	int entrycount, error;
1130
1131	error = copyinstr(uap->policy, target, sizeof(target), NULL);
1132	if (error)
1133		return (error);
1134
1135	error = ENOSYS;
1136	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1137		if (strcmp(mpc->mpc_name, target) == 0 &&
1138		    mpc->mpc_ops->mpo_syscall != NULL) {
1139			error = mpc->mpc_ops->mpo_syscall(td,
1140			    uap->call, uap->arg);
1141			goto out;
1142		}
1143	}
1144
1145	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1146		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1147			if (strcmp(mpc->mpc_name, target) == 0 &&
1148			    mpc->mpc_ops->mpo_syscall != NULL) {
1149				error = mpc->mpc_ops->mpo_syscall(td,
1150				    uap->call, uap->arg);
1151				break;
1152			}
1153		}
1154		mac_policy_list_unbusy();
1155	}
1156out:
1157	return (error);
1158}
1159
1160SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1161SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1162
1163#else /* !MAC */
1164
1165int
1166__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1167{
1168
1169	return (ENOSYS);
1170}
1171
1172int
1173__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1174{
1175
1176	return (ENOSYS);
1177}
1178
1179int
1180__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1181{
1182
1183	return (ENOSYS);
1184}
1185
1186int
1187__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1188{
1189
1190	return (ENOSYS);
1191}
1192
1193int
1194__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1195{
1196
1197	return (ENOSYS);
1198}
1199
1200int
1201__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1202{
1203
1204	return (ENOSYS);
1205}
1206
1207int
1208__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1209{
1210
1211	return (ENOSYS);
1212}
1213
1214int
1215__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1216{
1217
1218	return (ENOSYS);
1219}
1220
1221int
1222__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1223{
1224
1225	return (ENOSYS);
1226}
1227
1228int
1229mac_syscall(struct thread *td, struct mac_syscall_args *uap)
1230{
1231
1232	return (ENOSYS);
1233}
1234
1235#endif /* !MAC */
1236