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