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