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