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