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