1/*
2 * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*-
29 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
30 * Copyright (c) 2001 Ilmar S. Habibulin
31 * Copyright (c) 2001, 2002, 2003, 2004 Networks Associates Technology, Inc.
32 * Copyright (c) 2005-2006 SPARTA, Inc.
33 *
34 * This software was developed by Robert Watson and Ilmar Habibulin for the
35 * TrustedBSD Project.
36 *
37 * This software was developed for the FreeBSD Project in part by Network
38 * Associates Laboratories, the Security Research Division of Network
39 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
40 * as part of the DARPA CHATS research program.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 *    notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 *    notice, this list of conditions and the following disclaimer in the
49 *    documentation and/or other materials provided with the distribution.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 */
64
65/*-
66 * Framework for extensible kernel access control.  This file contains
67 * Kernel and userland interface to the framework, policy registration
68 * and composition.  Per-object interfaces, controls, and labeling may be
69 * found in src/sys/mac/.  Sample policies may be found in src/sys/mac*.
70 */
71
72#include <stdarg.h>
73#include <string.h>
74#include <security/mac_internal.h>
75#include <security/mac_mach_internal.h>
76#include <sys/param.h>
77#include <sys/vnode.h>
78#include <sys/vnode_internal.h>
79#include <sys/vfs_context.h>
80#include <sys/namei.h>
81#include <bsd/bsm/audit.h>
82#include <bsd/security/audit/audit.h>
83#include <sys/file.h>
84#include <sys/file_internal.h>
85#include <sys/filedesc.h>
86#include <sys/proc.h>
87#include <sys/proc_internal.h>
88#include <sys/kauth.h>
89#include <sys/sysproto.h>
90
91#include <mach/exception_types.h>
92#include <mach/vm_types.h>
93#include <mach/vm_prot.h>
94
95#include <kern/zalloc.h>
96#include <kern/sched_prim.h>
97#include <osfmk/kern/task.h>
98#include <osfmk/kern/kalloc.h>
99
100#if CONFIG_MACF
101#include <security/mac.h>
102#include <security/mac_policy.h>
103#include <security/mac_framework.h>
104#include <security/mac_internal.h>
105#include <security/mac_mach_internal.h>
106#endif
107
108
109/*
110 * define MB_DEBUG to display run-time debugging information
111 * #define MB_DEBUG 1
112 */
113
114#ifdef MB_DEBUG
115#define DPRINTF(x)	printf x
116#else
117#define MB_DEBUG
118#define DPRINTF(x)
119#endif
120
121#if CONFIG_MACF
122SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
123    "Security Controls");
124SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW|CTLFLAG_LOCKED, 0,
125    "TrustedBSD MAC policy controls");
126
127#if DEBUG
128#define SECURITY_MAC_CTLFLAGS CTLFLAG_RW | CTLFLAG_LOCKED
129#else
130#define SECURITY_MAC_CTLFLAGS CTLFLAG_RD | CTLFLAG_LOCKED
131#endif
132
133/*
134 * Declare that the kernel provides MAC support, version 1.  This permits
135 * modules to refuse to be loaded if the necessary support isn't present,
136 * even if it's pre-boot.
137 */
138#if 0
139MODULE_VERSION(kernel_mac_support, 1);
140#endif
141
142#if MAC_MAX_SLOTS > 32
143#error "MAC_MAX_SLOTS too large"
144#endif
145
146static unsigned int mac_max_slots = MAC_MAX_SLOTS;
147static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
148SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD | CTLFLAG_LOCKED,
149    &mac_max_slots, 0, "");
150
151/*
152 * Has the kernel started generating labeled objects yet?  All read/write
153 * access to this variable is serialized during the boot process.  Following
154 * the end of serialization, we don't update this flag; no locking.
155 */
156int	mac_late = 0;
157
158/*
159 * Flag to indicate whether or not we should allocate label storage for
160 * new mbufs.  Since most dynamic policies we currently work with don't
161 * rely on mbuf labeling, try to avoid paying the cost of mtag allocation
162 * unless specifically notified of interest.  One result of this is
163 * that if a dynamically loaded policy requests mbuf labels, it must
164 * be able to deal with a NULL label being returned on any mbufs that
165 * were already in flight when the policy was loaded.  Since the policy
166 * already has to deal with uninitialized labels, this probably won't
167 * be a problem.  Note: currently no locking.  Will this be a problem?
168 */
169#if CONFIG_MACF_NET
170unsigned int mac_label_mbufs	= 1;
171SYSCTL_UINT(_security_mac, OID_AUTO, label_mbufs, SECURITY_MAC_CTLFLAGS,
172	&mac_label_mbufs, 0, "Label all MBUFs");
173#endif
174
175
176/*
177 * Flag to indicate whether or not we should allocate label storage for
178 * new vnodes.  Since most dynamic policies we currently work with don't
179 * rely on vnode labeling, try to avoid paying the cost of mtag allocation
180 * unless specifically notified of interest.  One result of this is
181 * that if a dynamically loaded policy requests vnode labels, it must
182 * be able to deal with a NULL label being returned on any vnodes that
183 * were already in flight when the policy was loaded.  Since the policy
184 * already has to deal with uninitialized labels, this probably won't
185 * be a problem.
186 */
187unsigned int	mac_label_vnodes = 0;
188SYSCTL_UINT(_security_mac, OID_AUTO, labelvnodes, SECURITY_MAC_CTLFLAGS,
189    &mac_label_vnodes, 0, "Label all vnodes");
190
191
192unsigned int	mac_mmap_revocation = 0;
193SYSCTL_UINT(_security_mac, OID_AUTO, mmap_revocation, SECURITY_MAC_CTLFLAGS,
194    &mac_mmap_revocation, 0, "Revoke mmap access to files on subject "
195    "relabel");
196
197unsigned int	mac_mmap_revocation_via_cow = 0;
198SYSCTL_UINT(_security_mac, OID_AUTO, mmap_revocation_via_cow, SECURITY_MAC_CTLFLAGS,
199    &mac_mmap_revocation_via_cow, 0, "Revoke mmap access to files via "
200    "copy-on-write semantics, or by removing all write access");
201
202unsigned int mac_device_enforce = 1;
203SYSCTL_UINT(_security_mac, OID_AUTO, device_enforce, SECURITY_MAC_CTLFLAGS,
204	   &mac_device_enforce, 0, "Enforce MAC policy on device operations");
205
206unsigned int	mac_pipe_enforce = 1;
207SYSCTL_UINT(_security_mac, OID_AUTO, pipe_enforce, SECURITY_MAC_CTLFLAGS,
208    &mac_pipe_enforce, 0, "Enforce MAC policy on pipe operations");
209
210unsigned int	mac_posixsem_enforce = 1;
211SYSCTL_UINT(_security_mac, OID_AUTO, posixsem_enforce, SECURITY_MAC_CTLFLAGS,
212    &mac_posixsem_enforce, 0, "Enforce MAC policy on POSIX semaphores");
213
214unsigned int mac_posixshm_enforce = 1;
215SYSCTL_UINT(_security_mac, OID_AUTO, posixshm_enforce, SECURITY_MAC_CTLFLAGS,
216    &mac_posixshm_enforce, 0, "Enforce MAC policy on Posix Shared Memory");
217
218unsigned int	mac_proc_enforce = 1;
219SYSCTL_UINT(_security_mac, OID_AUTO, proc_enforce, SECURITY_MAC_CTLFLAGS,
220	   &mac_proc_enforce, 0, "Enforce MAC policy on process operations");
221
222unsigned int mac_socket_enforce = 1;
223SYSCTL_UINT(_security_mac, OID_AUTO, socket_enforce, SECURITY_MAC_CTLFLAGS,
224	&mac_socket_enforce, 0, "Enforce MAC policy on socket operations");
225
226unsigned int	mac_system_enforce = 1;
227SYSCTL_UINT(_security_mac, OID_AUTO, system_enforce, SECURITY_MAC_CTLFLAGS,
228    &mac_system_enforce, 0, "Enforce MAC policy on system-wide interfaces");
229
230unsigned int	mac_sysvmsg_enforce = 1;
231SYSCTL_UINT(_security_mac, OID_AUTO, sysvmsg_enforce, SECURITY_MAC_CTLFLAGS,
232    &mac_sysvmsg_enforce, 0, "Enforce MAC policy on System V IPC message queues");
233
234unsigned int	mac_sysvsem_enforce = 1;
235SYSCTL_UINT(_security_mac, OID_AUTO, sysvsem_enforce, SECURITY_MAC_CTLFLAGS,
236    &mac_sysvsem_enforce, 0, "Enforce MAC policy on System V IPC semaphores");
237
238unsigned int	mac_sysvshm_enforce = 1;
239SYSCTL_INT(_security_mac, OID_AUTO, sysvshm_enforce, SECURITY_MAC_CTLFLAGS,
240    &mac_sysvshm_enforce, 0, "Enforce MAC policy on System V Shared Memory");
241
242unsigned int	mac_vm_enforce = 1;
243SYSCTL_INT(_security_mac, OID_AUTO, vm_enforce, SECURITY_MAC_CTLFLAGS,
244	   &mac_vm_enforce, 0, "Enforce MAC policy on VM operations");
245
246unsigned int	mac_vnode_enforce = 1;
247SYSCTL_UINT(_security_mac, OID_AUTO, vnode_enforce, SECURITY_MAC_CTLFLAGS,
248	   &mac_vnode_enforce, 0, "Enforce MAC policy on vnode operations");
249
250#if CONFIG_AUDIT
251/*
252 * mac_audit_data_zone is the zone used for data pushed into the audit
253 * record by policies. Using a zone simplifies memory management of this
254 * data, and allows tracking of the amount of data in flight.
255 */
256extern zone_t mac_audit_data_zone;
257#endif
258
259/*
260 * mac_policy_list holds the list of policy modules.  Modules with a
261 * handle lower than staticmax are considered "static" and cannot be
262 * unloaded.  Such policies can be invoked without holding the busy count.
263 *
264 * Modules with a handle at or above the staticmax high water mark
265 * are considered to be "dynamic" policies.  A busy count is maintained
266 * for the list, stored in mac_policy_busy.  The busy count is protected
267 * by mac_policy_mtx; the list may be modified only while the busy
268 * count is 0, requiring that the lock be held to prevent new references
269 * to the list from being acquired.  For almost all operations,
270 * incrementing the busy count is sufficient to guarantee consistency,
271 * as the list cannot be modified while the busy count is elevated.
272 * For a few special operations involving a change to the list of
273 * active policies, the mtx itself must be held.
274 */
275static lck_mtx_t *mac_policy_mtx;
276
277/*
278 * Policy list array allocation chunk size. Trying to set this so that we
279 * allocate a page at a time.
280 */
281#define MAC_POLICY_LIST_CHUNKSIZE 512
282
283static int mac_policy_busy;
284
285mac_policy_list_t mac_policy_list;
286
287/*
288 * mac_label_element_list holds the master list of label namespaces for
289 * all the policies. When a policy is loaded, each of it's label namespace
290 * elements is added to the master list if not already present. When a
291 * policy is unloaded, the namespace elements are removed if no other
292 * policy is interested in that namespace element.
293 */
294struct mac_label_element_list_t mac_label_element_list;
295struct mac_label_element_list_t mac_static_label_element_list;
296
297/*
298 * Journal of label operations that occur before policies are loaded.
299 */
300struct mac_label_journal_list_t mac_label_journal_list;
301
302int
303mac_label_journal_add (struct label *l, int type)
304{
305	struct mac_label_journal *mlj;
306
307	if (mac_label_journal_find(l))
308		return (0);
309
310	MALLOC(mlj, struct mac_label_journal *,
311		sizeof(struct mac_label_journal), M_MACTEMP, M_WAITOK);
312	mlj->l = l;
313	mlj->type = type;
314	TAILQ_INSERT_TAIL(&mac_label_journal_list, mlj, link);
315
316	return (0);
317}
318
319int
320mac_label_journal_remove (struct label *l)
321{
322	struct mac_label_journal *mlj;
323
324	mlj = mac_label_journal_find(l);
325	if (mlj == NULL)
326		return (-1);
327
328	TAILQ_REMOVE(&mac_label_journal_list, mlj, link);
329	FREE(mlj, M_MACTEMP);
330	return (0);
331}
332
333struct mac_label_journal *
334mac_label_journal_find (struct label *l)
335{
336	struct mac_label_journal *mlj;
337
338	TAILQ_FOREACH(mlj, &mac_label_journal_list, link) {
339		if (l == mlj->l)
340			return (mlj);
341	}
342
343	return (NULL);
344}
345
346int
347mac_label_journal (struct label *l, int op, ...)
348{
349	struct mac_label_journal *mlj;
350	va_list ap;
351
352	mlj = mac_label_journal_find(l);
353	if (mlj == NULL) {
354		printf("%s(): Label not in list!\n", __func__);
355		return (-1);
356	}
357
358	if (op == MLJ_PORT_OP_UPDATE) {
359		va_start(ap, op);
360		mlj->kotype = va_arg(ap, int);
361		va_end(ap);
362	}
363
364	mlj->ops |= op;
365	return (0);
366}
367
368/*
369 * The assumption during replay is that the system is totally
370 * serialized and no additional tasks/ports will be created.
371 */
372void
373mac_label_journal_replay (void)
374{
375	struct mac_label_journal *mlj;
376
377	TAILQ_FOREACH(mlj, &mac_label_journal_list, link) {
378		switch (mlj->type) {
379		case MLJ_TYPE_PORT:
380			if (mlj->ops & MLJ_PORT_OP_INIT)
381				MAC_PERFORM(port_label_init, mlj->l);
382			if (mlj->ops & MLJ_PORT_OP_CREATE_K)
383				MAC_PERFORM(port_label_associate_kernel, mlj->l, 0);
384			if (mlj->ops & MLJ_PORT_OP_UPDATE)
385				MAC_PERFORM(port_label_update_kobject, mlj->l,
386						mlj->kotype);
387			break;
388		case MLJ_TYPE_TASK:
389			if (mlj->ops & MLJ_TASK_OP_INIT)
390				MAC_PERFORM(task_label_init, mlj->l);
391#if 0
392			/* Not enough context to replay. */
393			if (mlj->ops & MLJ_TASK_OP_CREATE_K)
394				;
395#endif
396			break;
397		default:
398			break;
399		}
400	}
401
402	/* Free list */
403	while (!TAILQ_EMPTY(&mac_label_journal_list)) {
404		mlj = TAILQ_FIRST(&mac_label_journal_list);
405		TAILQ_REMOVE(&mac_label_journal_list, mlj, link);
406		FREE(mlj, M_MACTEMP);
407	}
408	return;
409}
410
411static __inline void
412mac_policy_grab_exclusive(void)
413{
414	lck_mtx_lock(mac_policy_mtx);
415	while (mac_policy_busy != 0) {
416		lck_mtx_sleep(mac_policy_mtx, LCK_SLEEP_UNLOCK,
417			      (event_t)&mac_policy_busy, THREAD_UNINT);
418		lck_mtx_lock(mac_policy_mtx);
419	}
420}
421
422static __inline void
423mac_policy_assert_exclusive(void)
424{
425	lck_mtx_assert(mac_policy_mtx, LCK_MTX_ASSERT_OWNED);
426	KASSERT(mac_policy_busy == 0,
427	    ("mac_policy_assert_exclusive(): not exclusive"));
428}
429
430static __inline void
431mac_policy_release_exclusive(void)
432{
433
434	KASSERT(mac_policy_busy == 0,
435	    ("mac_policy_release_exclusive(): not exclusive"));
436	lck_mtx_unlock(mac_policy_mtx);
437	thread_wakeup((event_t) &mac_policy_busy);
438}
439
440void
441mac_policy_list_busy(void)
442{
443        lck_mtx_lock(mac_policy_mtx);
444	mac_policy_busy++;
445	lck_mtx_unlock(mac_policy_mtx);
446}
447
448int
449mac_policy_list_conditional_busy(void)
450{
451	int ret;
452
453	if (mac_policy_list.numloaded <= mac_policy_list.staticmax)
454		return(0);
455
456	lck_mtx_lock(mac_policy_mtx);
457	if (mac_policy_list.numloaded > mac_policy_list.staticmax) {
458		mac_policy_busy++;
459		ret = 1;
460	} else
461		ret = 0;
462	lck_mtx_unlock(mac_policy_mtx);
463	return (ret);
464}
465
466void
467mac_policy_list_unbusy(void)
468{
469	lck_mtx_lock(mac_policy_mtx);
470	mac_policy_busy--;
471	KASSERT(mac_policy_busy >= 0, ("MAC_POLICY_LIST_LOCK"));
472	if (mac_policy_busy == 0)
473		thread_wakeup(&mac_policy_busy);
474	lck_mtx_unlock(mac_policy_mtx);
475}
476
477/*
478 * Early pre-malloc MAC initialization, including appropriate SMP locks.
479 */
480void
481mac_policy_init(void)
482{
483	lck_grp_attr_t *mac_lck_grp_attr;
484	lck_attr_t *mac_lck_attr;
485	lck_grp_t *mac_lck_grp;
486
487	mac_policy_list.numloaded = 0;
488	mac_policy_list.max = MAC_POLICY_LIST_CHUNKSIZE;
489	mac_policy_list.maxindex = 0;
490	mac_policy_list.staticmax = 0;
491	mac_policy_list.freehint = 0;
492	mac_policy_list.chunks = 1;
493
494	mac_policy_list.entries = kalloc(sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE);
495	bzero(mac_policy_list.entries, sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE);
496
497	LIST_INIT(&mac_label_element_list);
498	LIST_INIT(&mac_static_label_element_list);
499	TAILQ_INIT(&mac_label_journal_list);
500
501	mac_lck_grp_attr = lck_grp_attr_alloc_init();
502	lck_grp_attr_setstat(mac_lck_grp_attr);
503	mac_lck_grp = lck_grp_alloc_init("MAC lock", mac_lck_grp_attr);
504	mac_lck_attr = lck_attr_alloc_init();
505	lck_attr_setdefault(mac_lck_attr);
506	mac_policy_mtx = lck_mtx_alloc_init(mac_lck_grp, mac_lck_attr);
507	lck_attr_free(mac_lck_attr);
508	lck_grp_attr_free(mac_lck_grp_attr);
509	lck_grp_free(mac_lck_grp);
510
511	mac_labelzone_init();
512}
513
514/* Function pointer set up for loading security extensions.
515 * It is set to an actual function after OSlibkernInit()
516 * has been called, and is set back to 0 by OSKextRemoveKextBootstrap()
517 * after bsd_init().
518 */
519void (*load_security_extensions_function)(void) = 0;
520
521/*
522 * Init after early Mach startup, but before BSD
523 */
524void
525mac_policy_initmach(void)
526{
527
528	/*
529	 * For the purposes of modules that want to know if they were
530	 * loaded "early", set the mac_late flag once we've processed
531	 * modules either linked into the kernel, or loaded before the
532	 * kernel startup.
533	 */
534
535	if (load_security_extensions_function) {
536		load_security_extensions_function();
537	}
538	mac_late = 1;
539#if CONFIG_MACF_MACH
540	mac_label_journal_replay();
541#endif
542}
543
544/*
545 * BSD startup.
546 */
547void
548mac_policy_initbsd(void)
549{
550	struct mac_policy_conf *mpc;
551	u_int i;
552
553#if CONFIG_AUDIT
554	mac_audit_data_zone = zinit(MAC_AUDIT_DATA_LIMIT,
555				    AQ_HIWATER * MAC_AUDIT_DATA_LIMIT,
556				    8192, "mac_audit_data_zone");
557#endif
558
559	printf("MAC Framework successfully initialized\n");
560
561	/* Call bsd init functions of already loaded policies */
562
563	/*
564	 * Using the exclusive lock means no other framework entry
565	 * points can proceed while initializations are running.
566	 * This may not be necessary.
567	 */
568	mac_policy_grab_exclusive();
569
570	for (i = 0; i <= mac_policy_list.maxindex; i++) {
571		mpc = mac_get_mpc(i);
572		if ((mpc != NULL) && (mpc->mpc_ops->mpo_policy_initbsd != NULL))
573			(*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
574	}
575
576	mac_policy_release_exclusive();
577}
578
579/*
580 * After a policy has been loaded, add the label namespaces managed by the
581 * policy to either the static or non-static label namespace list.
582 * A namespace is added to the the list only if it is not already on one of
583 * the lists.
584 */
585void
586mac_policy_addto_labellist(mac_policy_handle_t handle, int static_entry)
587{
588	struct mac_label_listener **new_mlls;
589	struct mac_label_element *mle, **new_mles;
590	struct mac_label_element_list_t *list;
591	struct mac_policy_conf *mpc;
592	const char *name, *name2;
593	u_int idx, mle_free, mll_free;
594
595	mpc = mac_get_mpc(handle);
596
597	if (mpc->mpc_labelnames == NULL)
598		return;
599
600	if (mpc->mpc_labelname_count == 0)
601		return;
602
603	if (static_entry)
604		list = &mac_static_label_element_list;
605	else
606		list = &mac_label_element_list;
607
608	/*
609	 * Before we grab the policy list lock, allocate enough memory
610	 * to contain the potential new elements so we don't have to
611	 * give up the lock, or allocate with the lock held.
612	 */
613	MALLOC(new_mles, struct mac_label_element **,
614	    sizeof(struct mac_label_element *) *
615	    mpc->mpc_labelname_count, M_MACTEMP, M_WAITOK | M_ZERO);
616	for (idx = 0; idx < mpc->mpc_labelname_count; idx++)
617		MALLOC(new_mles[idx], struct mac_label_element *,
618		    sizeof(struct mac_label_element),
619		    M_MACTEMP, M_WAITOK);
620	mle_free = 0;
621	MALLOC(new_mlls, struct mac_label_listener **,
622	    sizeof(struct mac_label_listener *) *
623	    mpc->mpc_labelname_count, M_MACTEMP, M_WAITOK);
624	for (idx = 0; idx < mpc->mpc_labelname_count; idx++)
625		MALLOC(new_mlls[idx], struct mac_label_listener *,
626		    sizeof(struct mac_label_listener), M_MACTEMP, M_WAITOK);
627	mll_free = 0;
628
629	if (mac_late)
630		mac_policy_grab_exclusive();
631	for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
632
633		if (*(name = mpc->mpc_labelnames[idx]) == '?')
634			name++;
635		/*
636		 * Check both label element lists and add to the
637		 * appropriate list only if not already on a list.
638		 */
639		LIST_FOREACH(mle, &mac_static_label_element_list, mle_list) {
640			if (*(name2 = mle->mle_name) == '?')
641				name2++;
642			if (strcmp(name, name2) == 0)
643				break;
644		}
645		if (mle == NULL) {
646			LIST_FOREACH(mle, &mac_label_element_list, mle_list) {
647				if (*(name2 = mle->mle_name) == '?')
648					name2++;
649				if (strcmp(name, name2) == 0)
650					break;
651			}
652		}
653		if (mle == NULL) {
654			mle = new_mles[mle_free];
655			strlcpy(mle->mle_name, mpc->mpc_labelnames[idx],
656					MAC_MAX_LABEL_ELEMENT_NAME);
657			LIST_INIT(&mle->mle_listeners);
658			LIST_INSERT_HEAD(list, mle, mle_list);
659			mle_free++;
660		}
661		/* Add policy handler as a listener. */
662		new_mlls[mll_free]->mll_handle = handle;
663		LIST_INSERT_HEAD(&mle->mle_listeners, new_mlls[mll_free],
664		    mll_list);
665		mll_free++;
666	}
667	if (mac_late)
668		mac_policy_release_exclusive();
669
670	/* Free up any unused label elements and listeners */
671	for (idx = mle_free; idx < mpc->mpc_labelname_count; idx++)
672		FREE(new_mles[idx], M_MACTEMP);
673	FREE(new_mles, M_MACTEMP);
674	for (idx = mll_free; idx < mpc->mpc_labelname_count; idx++)
675		FREE(new_mlls[idx], M_MACTEMP);
676	FREE(new_mlls, M_MACTEMP);
677}
678
679/*
680 * After a policy has been unloaded, remove the label namespaces that the
681 * the policy manages from the non-static list of namespaces.
682 * The removal only takes place when no other policy is interested in the
683 * namespace.
684 *
685 * Must be called with the policy exclusive lock held.
686 */
687void
688mac_policy_removefrom_labellist(mac_policy_handle_t handle)
689{
690	struct mac_label_listener *mll;
691	struct mac_label_element *mle;
692	struct mac_policy_conf *mpc;
693
694	mpc = mac_get_mpc(handle);
695
696	if (mpc->mpc_labelnames == NULL)
697		return;
698
699	if (mpc->mpc_labelname_count == 0)
700		return;
701
702	/*
703	 * Unregister policy as being interested in any label
704	 * namespaces.  If no other policy is listening, remove
705	 * that label element from the list.  Note that we only
706	 * have to worry about the non-static list.
707	 */
708	LIST_FOREACH(mle, &mac_label_element_list, mle_list) {
709		LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
710			if (mll->mll_handle == handle) {
711				LIST_REMOVE(mll, mll_list);
712				FREE(mll, M_MACTEMP);
713				if (LIST_EMPTY(&mle->mle_listeners)) {
714					LIST_REMOVE(mle, mle_list);
715					FREE(mle, M_MACTEMP);
716				}
717				return;
718			}
719		}
720	}
721}
722
723/*
724 * After the policy list has changed, walk the list to update any global
725 * flags.
726 */
727static void
728mac_policy_updateflags(void)
729{
730}
731
732static __inline void
733mac_policy_fixup_mmd_list(struct mac_module_data *new)
734{
735	struct mac_module_data *old;
736	struct mac_module_data_element *ele, *aele;
737	struct mac_module_data_list *arr, *dict;
738	unsigned int i, j, k;
739
740	old = new->base_addr;
741	DPRINTF(("fixup_mmd: old %p new %p\n", old, new));
742	for (i = 0; i < new->count; i++) {
743		ele = &(new->data[i]);
744		DPRINTF(("fixup_mmd: ele %p\n", ele));
745		DPRINTF(("   key %p value %p\n", ele->key, ele->value));
746		mmd_fixup_ele(old, new, ele); /* Fix up key/value ptrs.       */
747		DPRINTF(("   key %p value %p\n", ele->key, ele->value));
748		if (ele->value_type == MAC_DATA_TYPE_ARRAY) {
749			arr = (struct mac_module_data_list *)ele->value;
750			DPRINTF(("fixup_mmd: array @%p\n", arr));
751			for (j = 0; j < arr->count; j++) {
752				aele = &(arr->list[j]);
753				DPRINTF(("fixup_mmd: aele %p\n", aele));
754				DPRINTF(("   key %p value %p\n", aele->key, aele->value));
755				mmd_fixup_ele(old, new, aele);
756				DPRINTF(("   key %p value %p\n", aele->key, aele->value));
757				if (arr->type == MAC_DATA_TYPE_DICT) {
758					dict = (struct mac_module_data_list *)aele->value;
759					DPRINTF(("fixup_mmd: dict @%p\n", dict));
760					for (k = 0; k < dict->count; k++)
761						mmd_fixup_ele(old, new,
762						    &(dict->list[k]));
763				}
764			}
765		}
766	}
767	new->base_addr = new;
768}
769
770int
771mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep,
772    void *xd)
773{
774	struct mac_policy_list_element *tmac_policy_list_element;
775	int error, slot, static_entry = 0;
776	u_int i;
777
778	/*
779	 * Some preliminary checks to make sure the policy's conf structure
780	 * contains the required fields.
781	 */
782	if (mpc->mpc_name == NULL)
783		panic("policy's name is not set\n");
784
785	if (mpc->mpc_fullname == NULL)
786		panic("policy's full name is not set\n");
787
788	if (mpc->mpc_labelname_count > MAC_MAX_MANAGED_NAMESPACES)
789		panic("policy's managed label namespaces exceeds maximum\n");
790
791	if (mpc->mpc_ops == NULL)
792		panic("policy's OPs field is NULL\n");
793
794	error = 0;
795
796	if (mac_late) {
797		if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE) {
798			printf("Module %s does not support late loading.\n",
799			    mpc->mpc_name);
800			return (EPERM);
801		}
802		mac_policy_grab_exclusive();
803	}
804
805	if (mac_policy_list.numloaded >= mac_policy_list.max) {
806		/* allocate new policy list array, zero new chunk */
807		tmac_policy_list_element =
808		    kalloc((sizeof(struct mac_policy_list_element) *
809		    MAC_POLICY_LIST_CHUNKSIZE) * (mac_policy_list.chunks + 1));
810		bzero(&tmac_policy_list_element[mac_policy_list.max],
811		    sizeof(struct mac_policy_list_element) *
812		    MAC_POLICY_LIST_CHUNKSIZE);
813
814		/* copy old entries into new list */
815		memcpy(tmac_policy_list_element, mac_policy_list.entries,
816		   sizeof(struct mac_policy_list_element) *
817		   MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks);
818
819		/* free old array */
820		kfree(mac_policy_list.entries,
821		    sizeof(struct mac_policy_list_element) *
822		    MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks);
823
824		mac_policy_list.entries = tmac_policy_list_element;
825
826		/* Update maximums, etc */
827		mac_policy_list.max += MAC_POLICY_LIST_CHUNKSIZE;
828		mac_policy_list.chunks++;
829	}
830
831	/* Check for policy with same name already loaded */
832	for (i = 0; i <= mac_policy_list.maxindex; i++) {
833		if (mac_policy_list.entries[i].mpc == NULL)
834			continue;
835
836		if (strcmp(mac_policy_list.entries[i].mpc->mpc_name,
837		    mpc->mpc_name) == 0) {
838			error = EEXIST;
839			goto out;
840		}
841	}
842
843	if (mpc->mpc_field_off != NULL) {
844		slot = ffs(mac_slot_offsets_free);
845		if (slot == 0) {
846			error = ENOMEM;
847			goto out;
848		}
849		slot--;
850		mac_slot_offsets_free &= ~(1 << slot);
851		*mpc->mpc_field_off = slot;
852	}
853	mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
854
855	if (xd) {
856		struct mac_module_data *mmd = xd; /* module data from plist */
857
858		/* Make a copy of the data. */
859		mpc->mpc_data = (void *)kalloc(mmd->size);
860		if (mpc->mpc_data != NULL) {
861			memcpy(mpc->mpc_data, mmd, mmd->size);
862
863			/* Fix up pointers after copy. */
864			mac_policy_fixup_mmd_list(mpc->mpc_data);
865		}
866	}
867
868	/* Find the first free handle in the list (using our hint). */
869	for (i = mac_policy_list.freehint; i < mac_policy_list.max; i++) {
870		if (mac_policy_list.entries[i].mpc == NULL) {
871			*handlep = i;
872			mac_policy_list.freehint = ++i;
873			break;
874		}
875	}
876
877	/*
878	 * If we are loading a MAC module before the framework has
879	 * finished initializing or the module is not unloadable and
880	 * we can place its handle adjacent to the last static entry,
881	 * bump the static policy high water mark.
882	 * Static policies can get by with weaker locking requirements.
883	 */
884	if (!mac_late ||
885	    ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0 &&
886	    *handlep == mac_policy_list.staticmax)) {
887		static_entry = 1;
888		mac_policy_list.staticmax++;
889	}
890
891	mac_policy_list.entries[*handlep].mpc = mpc;
892
893	/* Update counters, etc */
894	if (*handlep > mac_policy_list.maxindex)
895		mac_policy_list.maxindex = *handlep;
896	mac_policy_list.numloaded++;
897
898	/* Per-policy initialization. */
899	printf ("calling mpo_policy_init for %s\n", mpc->mpc_name);
900	if (mpc->mpc_ops->mpo_policy_init != NULL)
901		(*(mpc->mpc_ops->mpo_policy_init))(mpc);
902
903	if (mac_late && mpc->mpc_ops->mpo_policy_initbsd != NULL) {
904		printf ("calling mpo_policy_initbsd for %s\n", mpc->mpc_name);
905		(*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
906	}
907
908	mac_policy_updateflags();
909
910	if (mac_late)
911		mac_policy_release_exclusive();
912
913	mac_policy_addto_labellist(*handlep, static_entry);
914
915	printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
916	    mpc->mpc_name);
917
918	return (0);
919
920out:
921	if (mac_late)
922		mac_policy_release_exclusive();
923
924	return (error);
925}
926
927int
928mac_policy_unregister(mac_policy_handle_t handle)
929{
930	struct mac_policy_conf *mpc;
931
932	/*
933	 * If we fail the load, we may get a request to unload.  Check
934	 * to see if we did the run-time registration, and if not,
935	 * silently succeed.
936	 */
937	mac_policy_grab_exclusive();
938	mpc = mac_get_mpc(handle);
939	if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
940		mac_policy_release_exclusive();
941		return (0);
942	}
943
944#if 0
945	/*
946	 * Don't allow unloading modules with private data.
947	 */
948	if (mpc->mpc_field_off != NULL) {
949		MAC_POLICY_LIST_UNLOCK();
950		return (EBUSY);
951	}
952#endif
953	/*
954	 * Only allow the unload to proceed if the module is unloadable
955	 * by its own definition.
956	 */
957	if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
958		mac_policy_release_exclusive();
959		return (EBUSY);
960	}
961
962	mac_policy_removefrom_labellist(handle);
963
964	mac_get_mpc(handle) = NULL;
965	if (handle < mac_policy_list.freehint &&
966	    handle >= mac_policy_list.staticmax)
967		mac_policy_list.freehint = handle;
968
969	if (handle == mac_policy_list.maxindex)
970		mac_policy_list.maxindex--;
971
972	mac_policy_list.numloaded--;
973	if (mpc->mpc_field_off != NULL) {
974		mac_slot_offsets_free |= (1 << *mpc->mpc_field_off);
975	}
976
977	if (mpc->mpc_ops->mpo_policy_destroy != NULL)
978		(*(mpc->mpc_ops->mpo_policy_destroy))(mpc);
979
980	mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
981	mac_policy_updateflags();
982
983	mac_policy_release_exclusive();
984
985	if (mpc->mpc_data) {
986		struct mac_module_data *mmd = mpc->mpc_data;
987		kfree(mmd, mmd->size);
988		mpc->mpc_data = NULL;
989	}
990
991	printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
992	    mpc->mpc_name);
993
994	return (0);
995}
996
997/*
998 * Define an error value precedence, and given two arguments, selects the
999 * value with the higher precedence.
1000 */
1001int
1002mac_error_select(int error1, int error2)
1003{
1004
1005	/* Certain decision-making errors take top priority. */
1006	if (error1 == EDEADLK || error2 == EDEADLK)
1007		return (EDEADLK);
1008
1009	/* Invalid arguments should be reported where possible. */
1010	if (error1 == EINVAL || error2 == EINVAL)
1011		return (EINVAL);
1012
1013	/* Precedence goes to "visibility", with both process and file. */
1014	if (error1 == ESRCH || error2 == ESRCH)
1015		return (ESRCH);
1016
1017	if (error1 == ENOENT || error2 == ENOENT)
1018		return (ENOENT);
1019
1020	/* Precedence goes to DAC/MAC protections. */
1021	if (error1 == EACCES || error2 == EACCES)
1022		return (EACCES);
1023
1024	/* Precedence goes to privilege. */
1025	if (error1 == EPERM || error2 == EPERM)
1026		return (EPERM);
1027
1028	/* Precedence goes to error over success; otherwise, arbitrary. */
1029	if (error1 != 0)
1030		return (error1);
1031	return (error2);
1032}
1033
1034void
1035mac_label_init(struct label *label)
1036{
1037
1038	bzero(label, sizeof(*label));
1039	label->l_flags = MAC_FLAG_INITIALIZED;
1040}
1041
1042void
1043mac_label_destroy(struct label *label)
1044{
1045
1046	KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
1047	    ("destroying uninitialized label"));
1048
1049	bzero(label, sizeof(*label));
1050	/* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
1051}
1052
1053int
1054mac_port_check_service (struct label *subj, struct label *obj,
1055    const char *s, const char *p)
1056{
1057	int error;
1058
1059	MAC_CHECK(port_check_service, subj, obj, s, p);
1060	return (error);
1061}
1062
1063int
1064mac_port_label_compute(struct label *subj, struct label *obj,
1065    const char *s, struct label *out)
1066{
1067	int error;
1068
1069	MAC_CHECK(port_label_compute, subj, obj, s, out);
1070	return error;
1071}
1072
1073int
1074mac_check_structmac_consistent(struct user_mac *mac)
1075{
1076
1077	if (mac->m_buflen > MAC_MAX_LABEL_BUF_LEN || mac->m_buflen == 0)
1078		return (EINVAL);
1079
1080	return (0);
1081}
1082
1083/*
1084 * Get the external forms of labels from all policies, for a single
1085 * label namespace or "*" for all namespaces.  Returns ENOENT if no policy
1086 * is registered for the namespace, unless the namespace begins with a '?'.
1087 */
1088static int
1089mac_label_externalize(size_t mpo_externalize_off, struct label *label,
1090    const char *element, struct sbuf *sb)
1091{
1092	struct mac_policy_conf *mpc;
1093	struct mac_label_listener *mll;
1094	struct mac_label_element *mle;
1095	struct mac_label_element_list_t *element_list;
1096	const char *name;
1097	int (*mpo_externalize)(struct label *, char *, struct sbuf *);
1098	int all_labels = 0, ignorenotfound = 0, error = 0, busy = FALSE;
1099	unsigned int count = 0;
1100
1101	if (element[0] == '?') {
1102		element++;
1103		ignorenotfound = 1;
1104	} else if (element[0] == '*' && element[1] == '\0')
1105		all_labels = 1;
1106
1107	element_list = &mac_static_label_element_list;
1108element_loop:
1109	LIST_FOREACH(mle, element_list, mle_list) {
1110		name = mle->mle_name;
1111		if (all_labels) {
1112			if (*name == '?')
1113			    continue;
1114		} else {
1115			if (*name == '?')
1116				name++;
1117			if (strcmp(name, element) != 0)
1118				continue;
1119		}
1120		LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1121			mpc = mac_policy_list.entries[mll->mll_handle].mpc;
1122			if (mpc == NULL)
1123				continue;
1124			mpo_externalize = *(typeof(mpo_externalize) *)
1125			    ((char *)mpc->mpc_ops + mpo_externalize_off);
1126			if (mpo_externalize == NULL)
1127				continue;
1128			error = sbuf_printf(sb, "%s/", name);
1129			if (error)
1130				goto done;
1131			error = mpo_externalize(label, mle->mle_name, sb);
1132			if (error) {
1133				if (error != ENOENT)
1134					goto done;
1135				/*
1136				 * If a policy doesn't have a label to
1137				 * externalize it returns ENOENT.  This
1138				 * may occur for policies that support
1139				 * multiple label elements for some
1140				 * (but not all) object types.
1141				 */
1142				sbuf_setpos(sb, sbuf_len(sb) -
1143				    (strlen(name) + 1));
1144				error = 0;
1145				continue;
1146			}
1147			error = sbuf_putc(sb, ',');
1148			if (error)
1149				goto done;
1150			count++;
1151		}
1152	}
1153	/* If there are dynamic policies present, check their elements too. */
1154	if (!busy && mac_policy_list_conditional_busy() == 1) {
1155		element_list = &mac_label_element_list;
1156		busy = TRUE;
1157		goto element_loop;
1158	}
1159done:
1160	if (busy)
1161		mac_policy_list_unbusy();
1162	if (!error && count == 0) {
1163		if (!all_labels && !ignorenotfound)
1164			error = ENOENT;	/* XXX: ENOLABEL? */
1165	}
1166	return (error);
1167}
1168
1169/*
1170 * Get the external forms of labels from all policies, for all label
1171 * namespaces contained in a list.
1172 *
1173 * XXX This may be leaking an sbuf.
1174 */
1175int
1176mac_externalize(size_t mpo_externalize_off, struct label *label,
1177    const char *elementlist, char *outbuf, size_t outbuflen)
1178{
1179	char *element;
1180	char *scratch_base;
1181	char *scratch;
1182	struct sbuf sb;
1183	int error = 0, len;
1184
1185	/* allocate a scratch buffer the size of the string */
1186	MALLOC(scratch_base, char *, strlen(elementlist)+1, M_MACTEMP, M_WAITOK);
1187	if (scratch_base == NULL) {
1188		error = ENOMEM;
1189		goto out;
1190	}
1191
1192	/* copy the elementlist to the scratch buffer */
1193	strlcpy(scratch_base, elementlist, strlen(elementlist)+1);
1194
1195	/*
1196	 * set up a temporary pointer that can be used to iterate the
1197	 * scratch buffer without losing the allocation address
1198	 */
1199	scratch = scratch_base;
1200
1201	/* get an sbuf */
1202	if (sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN) == NULL) {
1203		/* could not allocate interior buffer */
1204		error = ENOMEM;
1205		goto out;
1206	}
1207	/* iterate the scratch buffer; NOTE: buffer contents modified! */
1208	while ((element = strsep(&scratch, ",")) != NULL) {
1209		error = mac_label_externalize(mpo_externalize_off, label,
1210		    element, &sb);
1211		if (error)
1212			break;
1213	}
1214	if ((len = sbuf_len(&sb)) > 0)
1215		sbuf_setpos(&sb, len - 1);	/* trim trailing comma */
1216	sbuf_finish(&sb);
1217
1218out:
1219	if (scratch_base != NULL)
1220		FREE(scratch_base, M_MACTEMP);
1221
1222	return (error);
1223}
1224
1225/*
1226 * Have all policies set the internal form of a label, for a single
1227 * label namespace.
1228 */
1229static int
1230mac_label_internalize(size_t mpo_internalize_off, struct label *label,
1231    char *element_name, char *element_data)
1232{
1233	struct mac_policy_conf *mpc;
1234	struct mac_label_listener *mll;
1235	struct mac_label_element *mle;
1236	struct mac_label_element_list_t *element_list;
1237	int (*mpo_internalize)(struct label *, char *, char *);
1238	int error = 0, busy = FALSE;
1239	unsigned int count = 0;
1240	const char *name;
1241
1242	element_list = &mac_static_label_element_list;
1243element_loop:
1244	LIST_FOREACH(mle, element_list, mle_list) {
1245		if (*(name = mle->mle_name) == '?')
1246			name++;
1247		if (strcmp(element_name, name) != 0)
1248			continue;
1249		LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1250			mpc = mac_policy_list.entries[mll->mll_handle].mpc;
1251			if (mpc == NULL)
1252				continue;
1253			mpo_internalize = *(typeof(mpo_internalize) *)
1254			    ((char *)mpc->mpc_ops + mpo_internalize_off);
1255			if (mpo_internalize == NULL)
1256				continue;
1257			error = mpo_internalize(label, element_name,
1258			    element_data);
1259			if (error)
1260				goto done;
1261			count++;
1262		}
1263	}
1264	/* If there are dynamic policies present, check their elements too. */
1265	if (!busy && mac_policy_list_conditional_busy() == 1) {
1266		element_list = &mac_label_element_list;
1267		busy = TRUE;
1268		goto element_loop;
1269	}
1270done:
1271	if (busy)
1272		mac_policy_list_unbusy();
1273	if (!error && count == 0)
1274		error = ENOPOLICY;
1275	return (error);
1276}
1277
1278int
1279mac_internalize(size_t mpo_internalize_off, struct label *label,
1280    char *textlabels)
1281{
1282	char *element_name, *element_data;
1283	int error = 0;
1284
1285	while (!error && (element_name = strsep(&textlabels, ",")) != NULL) {
1286		element_data = strchr(element_name, '/');
1287		if (element_data == NULL) {
1288			error = EINVAL;
1289			break;
1290		}
1291		*element_data++ = '\0';
1292		error = mac_label_internalize(mpo_internalize_off, label,
1293		    element_name, element_data);
1294	}
1295	return (error);
1296}
1297
1298/* system calls */
1299
1300int
1301__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, int *ret __unused)
1302{
1303	char *elements, *buffer;
1304	struct user_mac mac;
1305	struct proc *tproc;
1306	struct ucred *tcred;
1307	int error;
1308	size_t ulen;
1309
1310	AUDIT_ARG(pid, uap->pid);
1311	if (IS_64BIT_PROCESS(p)) {
1312		struct user64_mac mac64;
1313		error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1314		mac.m_buflen = mac64.m_buflen;
1315		mac.m_string = mac64.m_string;
1316	} else {
1317		struct user32_mac mac32;
1318		error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1319		mac.m_buflen = mac32.m_buflen;
1320		mac.m_string = mac32.m_string;
1321	}
1322	if (error)
1323		return (error);
1324
1325	error = mac_check_structmac_consistent(&mac);
1326	if (error)
1327		return (error);
1328
1329	tproc = proc_find(uap->pid);
1330	if (tproc == NULL)
1331		return (ESRCH);
1332	tcred = kauth_cred_proc_ref(tproc);
1333	proc_rele(tproc);
1334
1335	MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1336	error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1337	if (error) {
1338		FREE(elements, M_MACTEMP);
1339		kauth_cred_unref(&tcred);
1340		return (error);
1341	}
1342	AUDIT_ARG(mac_string, elements);
1343
1344	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1345	error = mac_cred_label_externalize(tcred->cr_label, elements,
1346	    buffer, mac.m_buflen, M_WAITOK);
1347	if (error == 0)
1348		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1349
1350	FREE(buffer, M_MACTEMP);
1351	FREE(elements, M_MACTEMP);
1352	kauth_cred_unref(&tcred);
1353	return (error);
1354}
1355
1356int
1357__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, int *ret __unused)
1358{
1359	char *elements, *buffer;
1360	struct user_mac mac;
1361	kauth_cred_t cr;
1362	int error;
1363	size_t ulen;
1364
1365	if (IS_64BIT_PROCESS(p)) {
1366		struct user64_mac mac64;
1367		error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1368		mac.m_buflen = mac64.m_buflen;
1369		mac.m_string = mac64.m_string;
1370	} else {
1371		struct user32_mac mac32;
1372		error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1373		mac.m_buflen = mac32.m_buflen;
1374		mac.m_string = mac32.m_string;
1375	}
1376	if (error)
1377		return (error);
1378
1379	error = mac_check_structmac_consistent(&mac);
1380	if (error)
1381		return (error);
1382
1383	MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1384	error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1385	if (error) {
1386		FREE(elements, M_MACTEMP);
1387		return (error);
1388	}
1389	AUDIT_ARG(mac_string, elements);
1390
1391	cr = kauth_cred_proc_ref(p);
1392
1393	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1394	error = mac_cred_label_externalize(cr->cr_label,
1395	    elements, buffer, mac.m_buflen, M_WAITOK);
1396	if (error == 0)
1397		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1398
1399	FREE(buffer, M_MACTEMP);
1400	FREE(elements, M_MACTEMP);
1401	kauth_cred_unref(&cr);
1402	return (error);
1403}
1404
1405int
1406__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, int *ret __unused)
1407{
1408	kauth_cred_t newcred;
1409	struct label *intlabel;
1410	struct user_mac mac;
1411	char *buffer;
1412	int error;
1413	size_t ulen;
1414
1415	if (IS_64BIT_PROCESS(p)) {
1416		struct user64_mac mac64;
1417		error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1418		mac.m_buflen = mac64.m_buflen;
1419		mac.m_string = mac64.m_string;
1420	} else {
1421		struct user32_mac mac32;
1422		error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1423		mac.m_buflen = mac32.m_buflen;
1424		mac.m_string = mac32.m_string;
1425	}
1426	if (error)
1427		return (error);
1428
1429	error = mac_check_structmac_consistent(&mac);
1430	if (error)
1431		return (error);
1432
1433	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1434	error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1435	if (error) {
1436		FREE(buffer, M_MACTEMP);
1437		return (error);
1438	}
1439	AUDIT_ARG(mac_string, buffer);
1440
1441	intlabel = mac_cred_label_alloc();
1442	error = mac_cred_label_internalize(intlabel, buffer);
1443	FREE(buffer, M_MACTEMP);
1444	if (error)
1445		goto out;
1446
1447	error = mac_cred_check_label_update(kauth_cred_get(), intlabel);
1448	if (error) {
1449		goto out;
1450	}
1451
1452	error = kauth_proc_label_update(p, intlabel);
1453	if (error)
1454		goto out;
1455
1456	newcred = kauth_cred_proc_ref(p);
1457	mac_task_label_update_cred(newcred, p->task);
1458
1459#if 0
1460	if (mac_vm_enforce) {
1461		mutex_lock(Giant);			/* XXX FUNNEL? */
1462		mac_cred_mmapped_drop_perms(p, newcred);
1463		mutex_unlock(Giant);			/* XXX FUNNEL? */
1464	}
1465#endif
1466
1467	kauth_cred_unref(&newcred);
1468out:
1469	mac_cred_label_free(intlabel);
1470	return (error);
1471}
1472
1473#if CONFIG_LCTX
1474/*
1475 * __mac_get_lcid:
1476 *	Get login context ID.  A login context associates a BSD process
1477 *	with an instance of a user.  For more information see getlcid(2) man page.
1478 *
1479 * Parameters:    p                        Process requesting the get
1480 *                uap                      User argument descriptor (see below)
1481 *                ret                      (ignored)
1482 *
1483 * Indirect:      uap->lcid                login context ID to search
1484 *                uap->mac_p.m_buflen      MAC info buffer size
1485 *                uap->mac_p.m_string      MAC info user address
1486 *
1487 * Returns:        0                       Success
1488 *                !0                       Not success
1489 */
1490int
1491__mac_get_lcid(proc_t p, struct __mac_get_lcid_args *uap, int *ret __unused)
1492{
1493	char *elements, *buffer;
1494	struct user_mac mac;
1495	struct lctx *l;
1496	int error;
1497	size_t ulen;
1498
1499	AUDIT_ARG(value32, uap->lcid);
1500	if (IS_64BIT_PROCESS(p)) {
1501		struct user64_mac mac64;
1502		error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1503		mac.m_buflen = mac64.m_buflen;
1504		mac.m_string = mac64.m_string;
1505	} else {
1506		struct user32_mac mac32;
1507		error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1508		mac.m_buflen = mac32.m_buflen;
1509		mac.m_string = mac32.m_string;
1510	}
1511
1512	if (error)
1513		return (error);
1514
1515	error = mac_check_structmac_consistent(&mac);
1516	if (error)
1517		return (error);
1518
1519	l = lcfind(uap->lcid);
1520	if (l == NULL)
1521		return (ESRCH);
1522
1523	MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1524	error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1525	if (error) {
1526		LCTX_UNLOCK(l);
1527		FREE(elements, M_MACTEMP);
1528		return (error);
1529	}
1530	AUDIT_ARG(mac_string, elements);
1531	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1532	error = mac_lctx_label_externalize(l->lc_label, elements,
1533					   buffer, mac.m_buflen);
1534	if (error == 0)
1535		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1536
1537	LCTX_UNLOCK(l);
1538	FREE(buffer, M_MACTEMP);
1539	FREE(elements, M_MACTEMP);
1540	return (error);
1541}
1542
1543/*
1544 * __mac_get_lctx:
1545 *	Get login context label.  A login context associates a BSD process
1546 *	associated with an instance of a user.
1547 *
1548 * Parameters:    p                        Process requesting the get
1549 *                uap                      User argument descriptor (see below)
1550 *                ret                      (ignored)
1551 *
1552 * Indirect:      uap->lcid                login context ID to search
1553 *                uap->mac_p               MAC info
1554 *
1555 * Returns:        0                       Success
1556 *                !0                       Not success
1557 *
1558 */
1559int
1560__mac_get_lctx(proc_t p, struct __mac_get_lctx_args *uap, int *ret __unused)
1561{
1562	char *elements, *buffer;
1563	struct user_mac mac;
1564	int error;
1565	size_t ulen;
1566
1567	if (IS_64BIT_PROCESS(p)) {
1568		struct user64_mac mac64;
1569		error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1570		mac.m_buflen = mac64.m_buflen;
1571		mac.m_string = mac64.m_string;
1572	} else {
1573		struct user32_mac mac32;
1574		error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1575		mac.m_buflen = mac32.m_buflen;
1576		mac.m_string = mac32.m_string;
1577	}
1578
1579	if (error)
1580		return (error);
1581
1582	error = mac_check_structmac_consistent(&mac);
1583	if (error)
1584		return (error);
1585
1586	MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1587	error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1588	if (error) {
1589		FREE(elements, M_MACTEMP);
1590		return (error);
1591	}
1592	AUDIT_ARG(mac_string, elements);
1593	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1594
1595	proc_lock(p);
1596	if (p->p_lctx == NULL) {
1597		proc_unlock(p);
1598		error = ENOENT;
1599		goto out;
1600	}
1601
1602	error = mac_lctx_label_externalize(p->p_lctx->lc_label,
1603					   elements, buffer, mac.m_buflen);
1604	proc_unlock(p);
1605	if (error == 0)
1606		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1607
1608out:
1609	FREE(buffer, M_MACTEMP);
1610	FREE(elements, M_MACTEMP);
1611	return (error);
1612}
1613
1614int
1615__mac_set_lctx(proc_t p, struct __mac_set_lctx_args *uap, int *ret __unused)
1616{
1617	struct user_mac mac;
1618	struct label *intlabel;
1619	char *buffer;
1620	int error;
1621	size_t ulen;
1622
1623	if (IS_64BIT_PROCESS(p)) {
1624		struct user64_mac mac64;
1625		error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1626		mac.m_buflen = mac64.m_buflen;
1627		mac.m_string = mac64.m_string;
1628	} else {
1629		struct user32_mac mac32;
1630		error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1631		mac.m_buflen = mac32.m_buflen;
1632		mac.m_string = mac32.m_string;
1633	}
1634	if (error)
1635		return (error);
1636
1637	error = mac_check_structmac_consistent(&mac);
1638	if (error)
1639		return (error);
1640
1641	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1642	error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1643	if (error) {
1644		FREE(buffer, M_MACTEMP);
1645		return (error);
1646	}
1647	AUDIT_ARG(mac_string, buffer);
1648
1649	intlabel = mac_lctx_label_alloc();
1650	error = mac_lctx_label_internalize(intlabel, buffer);
1651	FREE(buffer, M_MACTEMP);
1652	if (error)
1653		goto out;
1654
1655	proc_lock(p);
1656	if (p->p_lctx == NULL) {
1657		proc_unlock(p);
1658		error = ENOENT;
1659		goto out;
1660	}
1661
1662	error = mac_lctx_check_label_update(p->p_lctx, intlabel);
1663	if (error) {
1664		proc_unlock(p);
1665		goto out;
1666	}
1667	mac_lctx_label_update(p->p_lctx, intlabel);
1668	proc_unlock(p);
1669out:
1670	mac_lctx_label_free(intlabel);
1671	return (error);
1672}
1673
1674#else	/* LCTX */
1675
1676int
1677__mac_get_lcid(proc_t p __unused, struct __mac_get_lcid_args *uap __unused, int *ret __unused)
1678{
1679
1680	return (ENOSYS);
1681}
1682
1683int
1684__mac_get_lctx(proc_t p __unused, struct __mac_get_lctx_args *uap __unused, int *ret __unused)
1685{
1686
1687	return (ENOSYS);
1688}
1689
1690int
1691__mac_set_lctx(proc_t p __unused, struct __mac_set_lctx_args *uap __unused, int *ret __unused)
1692{
1693
1694	return (ENOSYS);
1695}
1696#endif	/* !LCTX */
1697
1698int
1699__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, int *ret __unused)
1700{
1701	struct fileproc *fp;
1702	struct vnode *vp;
1703	struct user_mac mac;
1704	char *elements, *buffer;
1705	int error;
1706	size_t ulen;
1707	kauth_cred_t my_cred;
1708#if CONFIG_MACF_SOCKET
1709	struct socket *so;
1710#endif	/* MAC_SOCKET */
1711	struct label *intlabel;
1712
1713	AUDIT_ARG(fd, uap->fd);
1714
1715	if (IS_64BIT_PROCESS(p)) {
1716		struct user64_mac mac64;
1717		error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1718		mac.m_buflen = mac64.m_buflen;
1719		mac.m_string = mac64.m_string;
1720	} else {
1721		struct user32_mac mac32;
1722		error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1723		mac.m_buflen = mac32.m_buflen;
1724		mac.m_string = mac32.m_string;
1725	}
1726
1727	if (error)
1728		return (error);
1729
1730	error = mac_check_structmac_consistent(&mac);
1731	if (error)
1732		return (error);
1733
1734	MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1735	error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1736	if (error) {
1737		FREE(elements, M_MACTEMP);
1738		return (error);
1739	}
1740	AUDIT_ARG(mac_string, elements);
1741
1742	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1743	error = fp_lookup(p, uap->fd, &fp, 0);
1744	if (error) {
1745		FREE(buffer, M_MACTEMP);
1746		FREE(elements, M_MACTEMP);
1747		return (error);
1748	}
1749
1750	my_cred = kauth_cred_proc_ref(p);
1751	error = mac_file_check_get(my_cred, fp->f_fglob, elements, mac.m_buflen);
1752	kauth_cred_unref(&my_cred);
1753	if (error) {
1754		fp_drop(p, uap->fd, fp, 0);
1755		FREE(buffer, M_MACTEMP);
1756		FREE(elements, M_MACTEMP);
1757		return (error);
1758	}
1759
1760	switch (FILEGLOB_DTYPE(fp->f_fglob)) {
1761		case DTYPE_VNODE:
1762			intlabel = mac_vnode_label_alloc();
1763			if (intlabel == NULL) {
1764				error = ENOMEM;
1765				break;
1766			}
1767			vp = (struct vnode *)fp->f_fglob->fg_data;
1768			error = vnode_getwithref(vp);
1769			if (error == 0) {
1770				mac_vnode_label_copy(vp->v_label, intlabel);
1771				error = mac_vnode_label_externalize(intlabel,
1772						elements, buffer,
1773						mac.m_buflen, M_WAITOK);
1774				vnode_put(vp);
1775			}
1776			mac_vnode_label_free(intlabel);
1777			break;
1778		case DTYPE_SOCKET:
1779#if CONFIG_MACF_SOCKET
1780			so = (struct socket *) fp->f_fglob->fg_data;
1781			intlabel = mac_socket_label_alloc(MAC_WAITOK);
1782			sock_lock(so, 1);
1783			mac_socket_label_copy(so->so_label, intlabel);
1784			sock_unlock(so, 1);
1785			error = mac_socket_label_externalize(intlabel, elements, buffer, mac.m_buflen);
1786			mac_socket_label_free(intlabel);
1787			break;
1788#endif
1789		case DTYPE_PSXSHM:
1790		case DTYPE_PSXSEM:
1791		case DTYPE_PIPE:
1792		case DTYPE_KQUEUE:
1793		case DTYPE_FSEVENTS:
1794		default:
1795			error = ENOSYS;   // only sockets/vnodes so far
1796			break;
1797	}
1798	fp_drop(p, uap->fd, fp, 0);
1799
1800	if (error == 0)
1801		error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1802
1803	FREE(buffer, M_MACTEMP);
1804	FREE(elements, M_MACTEMP);
1805	return (error);
1806}
1807
1808static int
1809mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow)
1810{
1811	struct vnode *vp;
1812	vfs_context_t ctx;
1813	char *elements, *buffer;
1814	struct nameidata nd;
1815	struct label *intlabel;
1816	struct user_mac mac;
1817	int error;
1818	size_t ulen;
1819
1820	if (IS_64BIT_PROCESS(p)) {
1821		struct user64_mac mac64;
1822		error = copyin(mac_p, &mac64, sizeof(mac64));
1823		mac.m_buflen = mac64.m_buflen;
1824		mac.m_string = mac64.m_string;
1825	} else {
1826		struct user32_mac mac32;
1827		error = copyin(mac_p, &mac32, sizeof(mac32));
1828		mac.m_buflen = mac32.m_buflen;
1829		mac.m_string = mac32.m_string;
1830	}
1831
1832	if (error)
1833		return (error);
1834
1835	error = mac_check_structmac_consistent(&mac);
1836	if (error)
1837		return (error);
1838
1839	MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1840	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1841
1842	error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1843	if (error) {
1844		FREE(buffer, M_MACTEMP);
1845		FREE(elements, M_MACTEMP);
1846		return (error);
1847	}
1848	AUDIT_ARG(mac_string, elements);
1849
1850	ctx = vfs_context_current();
1851
1852	NDINIT(&nd, LOOKUP, OP_LOOKUP,
1853		LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1854		UIO_USERSPACE, path_p, ctx);
1855	error = namei(&nd);
1856	if (error) {
1857		FREE(buffer, M_MACTEMP);
1858		FREE(elements, M_MACTEMP);
1859		return (error);
1860	}
1861	vp = nd.ni_vp;
1862
1863	nameidone(&nd);
1864
1865	intlabel = mac_vnode_label_alloc();
1866	mac_vnode_label_copy(vp->v_label, intlabel);
1867	error = mac_vnode_label_externalize(intlabel, elements, buffer,
1868				    	    mac.m_buflen, M_WAITOK);
1869	mac_vnode_label_free(intlabel);
1870	if (error == 0)
1871		error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1872
1873	vnode_put(vp);
1874
1875	FREE(buffer, M_MACTEMP);
1876	FREE(elements, M_MACTEMP);
1877
1878	return (error);
1879}
1880
1881int
1882__mac_get_file(proc_t p, struct __mac_get_file_args *uap,
1883	       int *ret __unused)
1884{
1885
1886	return (mac_get_filelink(p, uap->mac_p, uap->path_p, 1));
1887}
1888
1889int
1890__mac_get_link(proc_t p, struct __mac_get_link_args *uap,
1891	       int *ret __unused)
1892{
1893
1894	return (mac_get_filelink(p, uap->mac_p, uap->path_p, 0));
1895}
1896
1897int
1898__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, int *ret __unused)
1899{
1900
1901	struct fileproc *fp;
1902	struct user_mac mac;
1903	struct vfs_context *ctx = vfs_context_current();
1904	int error;
1905	size_t ulen;
1906	char *buffer;
1907	struct label *intlabel;
1908#if CONFIG_MACF_SOCKET
1909	struct socket *so;
1910#endif
1911	struct vnode *vp;
1912
1913	AUDIT_ARG(fd, uap->fd);
1914
1915	if (IS_64BIT_PROCESS(p)) {
1916		struct user64_mac mac64;
1917		error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1918		mac.m_buflen = mac64.m_buflen;
1919		mac.m_string = mac64.m_string;
1920	} else {
1921		struct user32_mac mac32;
1922		error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1923		mac.m_buflen = mac32.m_buflen;
1924		mac.m_string = mac32.m_string;
1925	}
1926	if (error)
1927		return (error);
1928
1929	error = mac_check_structmac_consistent(&mac);
1930	if (error)
1931		return (error);
1932
1933	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1934	error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1935	if (error) {
1936		FREE(buffer, M_MACTEMP);
1937		return (error);
1938	}
1939	AUDIT_ARG(mac_string, buffer);
1940
1941	error = fp_lookup(p, uap->fd, &fp, 0);
1942	if (error) {
1943		FREE(buffer, M_MACTEMP);
1944		return (error);
1945	}
1946
1947
1948	error = mac_file_check_set(vfs_context_ucred(ctx), fp->f_fglob, buffer, mac.m_buflen);
1949	if (error) {
1950		fp_drop(p, uap->fd, fp, 0);
1951		FREE(buffer, M_MACTEMP);
1952		return (error);
1953	}
1954
1955	switch (FILEGLOB_DTYPE(fp->f_fglob)) {
1956
1957		case DTYPE_VNODE:
1958			if (mac_label_vnodes == 0) {
1959				error = ENOSYS;
1960				break;
1961			}
1962
1963			intlabel = mac_vnode_label_alloc();
1964
1965			error = mac_vnode_label_internalize(intlabel, buffer);
1966			if (error) {
1967				mac_vnode_label_free(intlabel);
1968				break;
1969			}
1970
1971
1972			vp = (struct vnode *)fp->f_fglob->fg_data;
1973
1974			error = vnode_getwithref(vp);
1975			if (error == 0) {
1976				error = vn_setlabel(vp, intlabel, ctx);
1977				vnode_put(vp);
1978			}
1979			mac_vnode_label_free(intlabel);
1980			break;
1981
1982		case DTYPE_SOCKET:
1983#if CONFIG_MACF_SOCKET
1984			intlabel = mac_socket_label_alloc(MAC_WAITOK);
1985			error = mac_socket_label_internalize(intlabel, buffer);
1986			if (error == 0) {
1987				so = (struct socket *) fp->f_fglob->fg_data;
1988				SOCK_LOCK(so);
1989				error = mac_socket_label_update(vfs_context_ucred(ctx), so, intlabel);
1990				SOCK_UNLOCK(so);
1991			}
1992			mac_socket_label_free(intlabel);
1993			break;
1994#endif
1995		case DTYPE_PSXSHM:
1996		case DTYPE_PSXSEM:
1997		case DTYPE_PIPE:
1998		case DTYPE_KQUEUE:
1999		case DTYPE_FSEVENTS:
2000		default:
2001			error = ENOSYS;  // only sockets/vnodes so far
2002			break;
2003	}
2004
2005	fp_drop(p, uap->fd, fp, 0);
2006	FREE(buffer, M_MACTEMP);
2007	return (error);
2008}
2009
2010static int
2011mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p,
2012		 int follow)
2013{
2014	register struct vnode *vp;
2015	struct vfs_context *ctx = vfs_context_current();
2016	struct label *intlabel;
2017	struct nameidata nd;
2018	struct user_mac mac;
2019	char *buffer;
2020	int error;
2021	size_t ulen;
2022
2023	if (mac_label_vnodes == 0)
2024		return ENOSYS;
2025
2026	if (IS_64BIT_PROCESS(p)) {
2027		struct user64_mac mac64;
2028		error = copyin(mac_p, &mac64, sizeof(mac64));
2029		mac.m_buflen = mac64.m_buflen;
2030		mac.m_string = mac64.m_string;
2031	} else {
2032		struct user32_mac mac32;
2033		error = copyin(mac_p, &mac32, sizeof(mac32));
2034		mac.m_buflen = mac32.m_buflen;
2035		mac.m_string = mac32.m_string;
2036	}
2037	if (error)
2038		return (error);
2039
2040	error = mac_check_structmac_consistent(&mac);
2041	if (error) {
2042		printf("mac_set_file: failed structure consistency check\n");
2043		return (error);
2044	}
2045
2046	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
2047	error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
2048	if (error) {
2049		FREE(buffer, M_MACTEMP);
2050		return (error);
2051	}
2052	AUDIT_ARG(mac_string, buffer);
2053
2054	intlabel = mac_vnode_label_alloc();
2055	error = mac_vnode_label_internalize(intlabel, buffer);
2056	FREE(buffer, M_MACTEMP);
2057	if (error) {
2058		mac_vnode_label_free(intlabel);
2059		return (error);
2060	}
2061
2062	NDINIT(&nd, LOOKUP, OP_LOOKUP,
2063		LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
2064		UIO_USERSPACE, path_p, ctx);
2065	error = namei(&nd);
2066	if (error) {
2067		mac_vnode_label_free(intlabel);
2068		return (error);
2069	}
2070	vp = nd.ni_vp;
2071
2072	nameidone(&nd);
2073
2074	error = vn_setlabel(vp, intlabel, ctx);
2075	vnode_put(vp);
2076	mac_vnode_label_free(intlabel);
2077
2078	return (error);
2079}
2080
2081int
2082__mac_set_file(proc_t p, struct __mac_set_file_args *uap,
2083	       int *ret __unused)
2084{
2085
2086	return (mac_set_filelink(p, uap->mac_p, uap->path_p, 1));
2087}
2088
2089int
2090__mac_set_link(proc_t p, struct __mac_set_link_args *uap,
2091	       int *ret __unused)
2092{
2093
2094	return (mac_set_filelink(p, uap->mac_p, uap->path_p, 0));
2095}
2096
2097/*
2098 * __mac_syscall: Perform a MAC policy system call
2099 *
2100 * Parameters:    p                       Process calling this routine
2101 *                uap                     User argument descriptor (see below)
2102 *                retv                    (Unused)
2103 *
2104 * Indirect:      uap->policy             Name of target MAC policy
2105 *                uap->call               MAC policy-specific system call to perform
2106 *                uap->arg                MAC policy-specific system call arguments
2107 *
2108 * Returns:        0                      Success
2109 *                !0                      Not success
2110 *
2111 */
2112int
2113__mac_syscall(proc_t p, struct __mac_syscall_args *uap, int *retv __unused)
2114{
2115	struct mac_policy_conf *mpc;
2116	char target[MAC_MAX_POLICY_NAME];
2117	int error;
2118	u_int i;
2119	size_t ulen;
2120
2121	error = copyinstr(uap->policy, target, sizeof(target), &ulen);
2122	if (error)
2123		return (error);
2124	AUDIT_ARG(value32, uap->call);
2125	AUDIT_ARG(mac_string, target);
2126
2127	error = ENOPOLICY;
2128
2129	for (i = 0; i < mac_policy_list.staticmax; i++) {
2130		mpc = mac_policy_list.entries[i].mpc;
2131		if (mpc == NULL)
2132			continue;
2133
2134		if (strcmp(mpc->mpc_name, target) == 0 &&
2135		    mpc->mpc_ops->mpo_policy_syscall != NULL) {
2136			error = mpc->mpc_ops->mpo_policy_syscall(p,
2137			    uap->call, uap->arg);
2138			goto done;
2139 		}
2140	}
2141	if (mac_policy_list_conditional_busy() != 0) {
2142		for (; i <= mac_policy_list.maxindex; i++) {
2143			mpc = mac_policy_list.entries[i].mpc;
2144			if (mpc == NULL)
2145				continue;
2146
2147			if (strcmp(mpc->mpc_name, target) == 0 &&
2148			    mpc->mpc_ops->mpo_policy_syscall != NULL) {
2149				error = mpc->mpc_ops->mpo_policy_syscall(p,
2150				    uap->call, uap->arg);
2151				break;
2152			}
2153		}
2154		mac_policy_list_unbusy();
2155	}
2156
2157done:
2158	return (error);
2159}
2160
2161int
2162mac_mount_label_get(struct mount *mp, user_addr_t mac_p)
2163{
2164	char *elements, *buffer;
2165	struct label *label;
2166	struct user_mac mac;
2167	int error;
2168	size_t ulen;
2169
2170	if (IS_64BIT_PROCESS(current_proc())) {
2171		struct user64_mac mac64;
2172		error = copyin(mac_p, &mac64, sizeof(mac64));
2173		mac.m_buflen = mac64.m_buflen;
2174		mac.m_string = mac64.m_string;
2175	} else {
2176		struct user32_mac mac32;
2177		error = copyin(mac_p, &mac32, sizeof(mac32));
2178		mac.m_buflen = mac32.m_buflen;
2179		mac.m_string = mac32.m_string;
2180	}
2181	if (error)
2182		return (error);
2183
2184	error = mac_check_structmac_consistent(&mac);
2185	if (error)
2186		return (error);
2187
2188	MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
2189	error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
2190	if (error) {
2191		FREE(elements, M_MACTEMP);
2192		return (error);
2193	}
2194	AUDIT_ARG(mac_string, elements);
2195
2196	label = mp->mnt_mntlabel;
2197	MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
2198	error = mac_mount_label_externalize(label, elements, buffer,
2199	    mac.m_buflen);
2200	FREE(elements, M_MACTEMP);
2201
2202	if (error == 0)
2203		error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
2204	FREE(buffer, M_MACTEMP);
2205
2206	return (error);
2207}
2208
2209/*
2210 * __mac_get_mount: Get mount point label information for a given pathname
2211 *
2212 * Parameters:    p                        (ignored)
2213 *                uap                      User argument descriptor (see below)
2214 *                ret                      (ignored)
2215 *
2216 * Indirect:      uap->path                Pathname
2217 *                uap->mac_p               MAC info
2218 *
2219 * Returns:        0                       Success
2220 *                !0                       Not success
2221 */
2222int
2223__mac_get_mount(proc_t p __unused, struct __mac_get_mount_args *uap,
2224    int *ret __unused)
2225{
2226	struct nameidata nd;
2227	struct vfs_context *ctx = vfs_context_current();
2228	struct mount *mp;
2229	int error;
2230
2231	NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | AUDITVNPATH1,
2232		UIO_USERSPACE, uap->path, ctx);
2233	error = namei(&nd);
2234	if (error) {
2235		return (error);
2236	}
2237	mp = nd.ni_vp->v_mount;
2238	nameidone(&nd);
2239
2240	return mac_mount_label_get(mp, uap->mac_p);
2241}
2242
2243/*
2244 * mac_schedule_userret()
2245 *
2246 * Schedule a callback to the mpo_thread_userret hook. The mpo_thread_userret
2247 * hook is called just before the thread exit from the kernel in ast_taken().
2248 *
2249 * Returns:	 0		Success
2250 * 		!0		Not successful
2251 */
2252int
2253mac_schedule_userret(void)
2254{
2255
2256	act_set_astmacf(current_thread());
2257	return (0);
2258}
2259
2260/*
2261 * mac_do_machexc()
2262 *
2263 * Do a Mach exception.  This should only be done in the mpo_thread_userret
2264 * callback.
2265 *
2266 * params:	code		exception code
2267 * 		subcode		exception subcode
2268 * 		flags		flags:
2269 * 				MAC_DOEXCF_TRACED  Only do exception if being
2270 * 						   ptrace()'ed.
2271 *
2272 *
2273 * Returns:	 0		Success
2274 * 		!0		Not successful
2275 */
2276int
2277mac_do_machexc(int64_t code, int64_t subcode, uint32_t flags)
2278{
2279	mach_exception_data_type_t  codes[EXCEPTION_CODE_MAX];
2280	proc_t p = current_proc();
2281
2282	/* Only allow execption codes in MACF's reserved range. */
2283	if ((code < EXC_MACF_MIN) || (code > EXC_MACF_MAX))
2284		return (1);
2285
2286	if (flags & MAC_DOEXCF_TRACED &&
2287	    !(p->p_lflag & P_LTRACED && (p->p_lflag & P_LPPWAIT) == 0))
2288		return (0);
2289
2290
2291	/* Send the Mach exception */
2292	codes[0] = (mach_exception_data_type_t)code;
2293	codes[1] = (mach_exception_data_type_t)subcode;
2294
2295	return (bsd_exception(EXC_SOFTWARE, codes, 2) != KERN_SUCCESS);
2296}
2297
2298#else /* MAC */
2299
2300void (*load_security_extensions_function)(void) = 0;
2301
2302struct sysctl_oid_list sysctl__security_mac_children;
2303
2304int
2305mac_policy_register(struct mac_policy_conf *mpc __unused,
2306	mac_policy_handle_t *handlep __unused, void *xd __unused)
2307{
2308
2309	return (0);
2310}
2311
2312int
2313mac_policy_unregister(mac_policy_handle_t handle __unused)
2314{
2315
2316	return (0);
2317}
2318
2319int
2320mac_audit_text(char *text __unused, mac_policy_handle_t handle __unused)
2321{
2322
2323	return (0);
2324}
2325
2326int
2327mac_vnop_setxattr(struct vnode *vp __unused, const char *name __unused, char *buf __unused, size_t len __unused)
2328{
2329
2330	return (ENOENT);
2331}
2332
2333int
2334mac_vnop_getxattr(struct vnode *vp __unused, const char *name __unused,
2335	char *buf __unused, size_t len __unused, size_t *attrlen __unused)
2336{
2337
2338	return (ENOENT);
2339}
2340
2341int
2342mac_vnop_removexattr(struct vnode *vp __unused, const char *name __unused)
2343{
2344
2345	return (ENOENT);
2346}
2347
2348intptr_t mac_label_get(struct label *l __unused, int slot __unused)
2349{
2350        return 0;
2351}
2352
2353void mac_label_set(struct label *l __unused, int slot __unused, intptr_t v __unused)
2354{
2355		return;
2356}
2357
2358struct label *mac_thread_get_threadlabel(struct thread *thread __unused)
2359{
2360        return NULL;
2361}
2362
2363struct label *mac_thread_get_uthreadlabel(struct uthread *uthread __unused)
2364{
2365        return NULL;
2366}
2367
2368void mac_proc_set_enforce(proc_t p, int enforce_flags);
2369void mac_proc_set_enforce(proc_t p __unused, int enforce_flags __unused)
2370{
2371		return;
2372}
2373
2374int mac_iokit_check_hid_control(kauth_cred_t cred __unused);
2375int mac_iokit_check_hid_control(kauth_cred_t cred __unused)
2376{
2377        return 0;
2378}
2379
2380#endif /* !MAC */
2381