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