mac_syscalls.c revision 147983
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 147983 2005-07-14 10:46:03Z rwatson $");
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		mtx_lock(&Giant);
732		mac_cred_mmapped_drop_perms(td, newcred);
733		mtx_unlock(&Giant);
734	}
735
736	crfree(newcred);	/* Free revocation reference. */
737	crfree(oldcred);
738
739out:
740	mac_cred_label_free(intlabel);
741	return (error);
742}
743
744/*
745 * MPSAFE
746 */
747int
748__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
749{
750	char *elements, *buffer;
751	struct label *intlabel;
752	struct file *fp;
753	struct mac mac;
754	struct vnode *vp;
755	struct pipe *pipe;
756	struct socket *so;
757	short label_type;
758	int error;
759
760	error = copyin(uap->mac_p, &mac, sizeof(mac));
761	if (error)
762		return (error);
763
764	error = mac_check_structmac_consistent(&mac);
765	if (error)
766		return (error);
767
768	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
769	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
770	if (error) {
771		free(elements, M_MACTEMP);
772		return (error);
773	}
774
775	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
776	error = fget(td, uap->fd, &fp);
777	if (error)
778		goto out;
779
780	label_type = fp->f_type;
781	switch (fp->f_type) {
782	case DTYPE_FIFO:
783	case DTYPE_VNODE:
784		vp = fp->f_vnode;
785		intlabel = mac_vnode_label_alloc();
786		mtx_lock(&Giant);				/* VFS */
787		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
788		mac_copy_vnode_label(vp->v_label, intlabel);
789		VOP_UNLOCK(vp, 0, td);
790		mtx_unlock(&Giant);				/* VFS */
791		error = mac_externalize_vnode_label(intlabel, elements,
792		    buffer, mac.m_buflen);
793		mac_vnode_label_free(intlabel);
794		break;
795
796	case DTYPE_PIPE:
797		pipe = fp->f_data;
798		intlabel = mac_pipe_label_alloc();
799		PIPE_LOCK(pipe);
800		mac_copy_pipe_label(pipe->pipe_pair->pp_label, intlabel);
801		PIPE_UNLOCK(pipe);
802		error = mac_externalize_pipe_label(intlabel, elements,
803		    buffer, mac.m_buflen);
804		mac_pipe_label_free(intlabel);
805		break;
806
807	case DTYPE_SOCKET:
808		so = fp->f_data;
809		intlabel = mac_socket_label_alloc(M_WAITOK);
810		NET_LOCK_GIANT();
811		SOCK_LOCK(so);
812		mac_copy_socket_label(so->so_label, intlabel);
813		SOCK_UNLOCK(so);
814		NET_UNLOCK_GIANT();
815		error = mac_externalize_socket_label(intlabel, elements,
816		    buffer, mac.m_buflen);
817		mac_socket_label_free(intlabel);
818		break;
819
820	default:
821		error = EINVAL;
822	}
823	fdrop(fp, td);
824	if (error == 0)
825		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
826
827out:
828	free(buffer, M_MACTEMP);
829	free(elements, M_MACTEMP);
830	return (error);
831}
832
833/*
834 * MPSAFE
835 */
836int
837__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
838{
839	char *elements, *buffer;
840	struct nameidata nd;
841	struct label *intlabel;
842	struct mac mac;
843	int error;
844
845	error = copyin(uap->mac_p, &mac, sizeof(mac));
846	if (error)
847		return (error);
848
849	error = mac_check_structmac_consistent(&mac);
850	if (error)
851		return (error);
852
853	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
854	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
855	if (error) {
856		free(elements, M_MACTEMP);
857		return (error);
858	}
859
860	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
861	mtx_lock(&Giant);				/* VFS */
862	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
863	    td);
864	error = namei(&nd);
865	if (error)
866		goto out;
867
868	intlabel = mac_vnode_label_alloc();
869	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
870	error = mac_externalize_vnode_label(intlabel, elements, buffer,
871	    mac.m_buflen);
872
873	NDFREE(&nd, 0);
874	mac_vnode_label_free(intlabel);
875
876	if (error == 0)
877		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
878
879out:
880	mtx_unlock(&Giant);				/* VFS */
881
882	free(buffer, M_MACTEMP);
883	free(elements, M_MACTEMP);
884
885	return (error);
886}
887
888/*
889 * MPSAFE
890 */
891int
892__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
893{
894	char *elements, *buffer;
895	struct nameidata nd;
896	struct label *intlabel;
897	struct mac mac;
898	int error;
899
900	error = copyin(uap->mac_p, &mac, sizeof(mac));
901	if (error)
902		return (error);
903
904	error = mac_check_structmac_consistent(&mac);
905	if (error)
906		return (error);
907
908	elements = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
909	error = copyinstr(mac.m_string, elements, mac.m_buflen, NULL);
910	if (error) {
911		free(elements, M_MACTEMP);
912		return (error);
913	}
914
915	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
916	mtx_lock(&Giant);				/* VFS */
917	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
918	    td);
919	error = namei(&nd);
920	if (error)
921		goto out;
922
923	intlabel = mac_vnode_label_alloc();
924	mac_copy_vnode_label(nd.ni_vp->v_label, intlabel);
925	error = mac_externalize_vnode_label(intlabel, elements, buffer,
926	    mac.m_buflen);
927	NDFREE(&nd, 0);
928	mac_vnode_label_free(intlabel);
929
930	if (error == 0)
931		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
932
933out:
934	mtx_unlock(&Giant);				/* VFS */
935
936	free(buffer, M_MACTEMP);
937	free(elements, M_MACTEMP);
938
939	return (error);
940}
941
942/*
943 * MPSAFE
944 */
945int
946__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
947{
948	struct label *intlabel;
949	struct pipe *pipe;
950	struct socket *so;
951	struct file *fp;
952	struct mount *mp;
953	struct vnode *vp;
954	struct mac mac;
955	char *buffer;
956	int error;
957
958	error = copyin(uap->mac_p, &mac, sizeof(mac));
959	if (error)
960		return (error);
961
962	error = mac_check_structmac_consistent(&mac);
963	if (error)
964		return (error);
965
966	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
967	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
968	if (error) {
969		free(buffer, M_MACTEMP);
970		return (error);
971	}
972
973	error = fget(td, uap->fd, &fp);
974	if (error)
975		goto out;
976
977	switch (fp->f_type) {
978	case DTYPE_FIFO:
979	case DTYPE_VNODE:
980		intlabel = mac_vnode_label_alloc();
981		error = mac_internalize_vnode_label(intlabel, buffer);
982		if (error) {
983			mac_vnode_label_free(intlabel);
984			break;
985		}
986		vp = fp->f_vnode;
987		mtx_lock(&Giant);				/* VFS */
988		error = vn_start_write(vp, &mp, V_WAIT | PCATCH);
989		if (error != 0) {
990			mtx_unlock(&Giant);			/* VFS */
991			mac_vnode_label_free(intlabel);
992			break;
993		}
994		vn_lock(vp, LK_EXCLUSIVE | LK_RETRY, td);
995		error = vn_setlabel(vp, intlabel, td->td_ucred);
996		VOP_UNLOCK(vp, 0, td);
997		vn_finished_write(mp);
998		mtx_unlock(&Giant);				/* VFS */
999		mac_vnode_label_free(intlabel);
1000		break;
1001
1002	case DTYPE_PIPE:
1003		intlabel = mac_pipe_label_alloc();
1004		error = mac_internalize_pipe_label(intlabel, buffer);
1005		if (error == 0) {
1006			pipe = fp->f_data;
1007			PIPE_LOCK(pipe);
1008			error = mac_pipe_label_set(td->td_ucred,
1009			    pipe->pipe_pair, intlabel);
1010			PIPE_UNLOCK(pipe);
1011		}
1012		mac_pipe_label_free(intlabel);
1013		break;
1014
1015	case DTYPE_SOCKET:
1016		intlabel = mac_socket_label_alloc(M_WAITOK);
1017		error = mac_internalize_socket_label(intlabel, buffer);
1018		if (error == 0) {
1019			so = fp->f_data;
1020			NET_LOCK_GIANT();
1021			error = mac_socket_label_set(td->td_ucred, so,
1022			    intlabel);
1023			NET_UNLOCK_GIANT();
1024		}
1025		mac_socket_label_free(intlabel);
1026		break;
1027
1028	default:
1029		error = EINVAL;
1030	}
1031	fdrop(fp, td);
1032out:
1033	free(buffer, M_MACTEMP);
1034	return (error);
1035}
1036
1037/*
1038 * MPSAFE
1039 */
1040int
1041__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1042{
1043	struct label *intlabel;
1044	struct nameidata nd;
1045	struct mount *mp;
1046	struct mac mac;
1047	char *buffer;
1048	int error;
1049
1050	error = copyin(uap->mac_p, &mac, sizeof(mac));
1051	if (error)
1052		return (error);
1053
1054	error = mac_check_structmac_consistent(&mac);
1055	if (error)
1056		return (error);
1057
1058	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1059	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1060	if (error) {
1061		free(buffer, M_MACTEMP);
1062		return (error);
1063	}
1064
1065	intlabel = mac_vnode_label_alloc();
1066	error = mac_internalize_vnode_label(intlabel, buffer);
1067	free(buffer, M_MACTEMP);
1068	if (error)
1069		goto out;
1070
1071	mtx_lock(&Giant);				/* VFS */
1072
1073	NDINIT(&nd, LOOKUP, LOCKLEAF | FOLLOW, UIO_USERSPACE, uap->path_p,
1074	    td);
1075	error = namei(&nd);
1076	if (error == 0) {
1077		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1078		if (error == 0)
1079			error = vn_setlabel(nd.ni_vp, intlabel,
1080			    td->td_ucred);
1081		vn_finished_write(mp);
1082	}
1083
1084	NDFREE(&nd, 0);
1085	mtx_unlock(&Giant);				/* VFS */
1086out:
1087	mac_vnode_label_free(intlabel);
1088	return (error);
1089}
1090
1091/*
1092 * MPSAFE
1093 */
1094int
1095__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1096{
1097	struct label *intlabel;
1098	struct nameidata nd;
1099	struct mount *mp;
1100	struct mac mac;
1101	char *buffer;
1102	int error;
1103
1104	error = copyin(uap->mac_p, &mac, sizeof(mac));
1105	if (error)
1106		return (error);
1107
1108	error = mac_check_structmac_consistent(&mac);
1109	if (error)
1110		return (error);
1111
1112	buffer = malloc(mac.m_buflen, M_MACTEMP, M_WAITOK);
1113	error = copyinstr(mac.m_string, buffer, mac.m_buflen, NULL);
1114	if (error) {
1115		free(buffer, M_MACTEMP);
1116		return (error);
1117	}
1118
1119	intlabel = mac_vnode_label_alloc();
1120	error = mac_internalize_vnode_label(intlabel, buffer);
1121	free(buffer, M_MACTEMP);
1122	if (error)
1123		goto out;
1124
1125	mtx_lock(&Giant);				/* VFS */
1126
1127	NDINIT(&nd, LOOKUP, LOCKLEAF | NOFOLLOW, UIO_USERSPACE, uap->path_p,
1128	    td);
1129	error = namei(&nd);
1130	if (error == 0) {
1131		error = vn_start_write(nd.ni_vp, &mp, V_WAIT | PCATCH);
1132		if (error == 0)
1133			error = vn_setlabel(nd.ni_vp, intlabel,
1134			    td->td_ucred);
1135		vn_finished_write(mp);
1136	}
1137
1138	NDFREE(&nd, 0);
1139	mtx_unlock(&Giant);				/* VFS */
1140out:
1141	mac_vnode_label_free(intlabel);
1142	return (error);
1143}
1144
1145/*
1146 * MPSAFE
1147 */
1148int
1149mac_syscall(struct thread *td, struct mac_syscall_args *uap)
1150{
1151	struct mac_policy_conf *mpc;
1152	char target[MAC_MAX_POLICY_NAME];
1153	int entrycount, error;
1154
1155	error = copyinstr(uap->policy, target, sizeof(target), NULL);
1156	if (error)
1157		return (error);
1158
1159	error = ENOSYS;
1160	LIST_FOREACH(mpc, &mac_static_policy_list, mpc_list) {
1161		if (strcmp(mpc->mpc_name, target) == 0 &&
1162		    mpc->mpc_ops->mpo_syscall != NULL) {
1163			error = mpc->mpc_ops->mpo_syscall(td,
1164			    uap->call, uap->arg);
1165			goto out;
1166		}
1167	}
1168
1169	if ((entrycount = mac_policy_list_conditional_busy()) != 0) {
1170		LIST_FOREACH(mpc, &mac_policy_list, mpc_list) {
1171			if (strcmp(mpc->mpc_name, target) == 0 &&
1172			    mpc->mpc_ops->mpo_syscall != NULL) {
1173				error = mpc->mpc_ops->mpo_syscall(td,
1174				    uap->call, uap->arg);
1175				break;
1176			}
1177		}
1178		mac_policy_list_unbusy();
1179	}
1180out:
1181	return (error);
1182}
1183
1184SYSINIT(mac, SI_SUB_MAC, SI_ORDER_FIRST, mac_init, NULL);
1185SYSINIT(mac_late, SI_SUB_MAC_LATE, SI_ORDER_FIRST, mac_late_init, NULL);
1186
1187#else /* !MAC */
1188
1189int
1190__mac_get_pid(struct thread *td, struct __mac_get_pid_args *uap)
1191{
1192
1193	return (ENOSYS);
1194}
1195
1196int
1197__mac_get_proc(struct thread *td, struct __mac_get_proc_args *uap)
1198{
1199
1200	return (ENOSYS);
1201}
1202
1203int
1204__mac_set_proc(struct thread *td, struct __mac_set_proc_args *uap)
1205{
1206
1207	return (ENOSYS);
1208}
1209
1210int
1211__mac_get_fd(struct thread *td, struct __mac_get_fd_args *uap)
1212{
1213
1214	return (ENOSYS);
1215}
1216
1217int
1218__mac_get_file(struct thread *td, struct __mac_get_file_args *uap)
1219{
1220
1221	return (ENOSYS);
1222}
1223
1224int
1225__mac_get_link(struct thread *td, struct __mac_get_link_args *uap)
1226{
1227
1228	return (ENOSYS);
1229}
1230
1231int
1232__mac_set_fd(struct thread *td, struct __mac_set_fd_args *uap)
1233{
1234
1235	return (ENOSYS);
1236}
1237
1238int
1239__mac_set_file(struct thread *td, struct __mac_set_file_args *uap)
1240{
1241
1242	return (ENOSYS);
1243}
1244
1245int
1246__mac_set_link(struct thread *td, struct __mac_set_link_args *uap)
1247{
1248
1249	return (ENOSYS);
1250}
1251
1252int
1253mac_syscall(struct thread *td, struct mac_syscall_args *uap)
1254{
1255
1256	return (ENOSYS);
1257}
1258
1259#endif /* !MAC */
1260