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