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