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