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