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