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