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