2 * Copyright (c) 2007-2012 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
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.
34 * This software was developed by Robert Watson and Ilmar Habibulin for the
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.
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
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.
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
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*.
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>
84 #include <sys/file_internal.h>
85 #include <sys/filedesc.h>
87 #include <sys/proc_internal.h>
88 #include <sys/kauth.h>
89 #include <sys/sysproto.h>
91 #include <mach/exception_types.h>
92 #include <mach/vm_types.h>
93 #include <mach/vm_prot.h>
95 #include <kern/zalloc.h>
96 #include <kern/sched_prim.h>
97 #include <osfmk/kern/task.h>
98 #include <osfmk/kern/kalloc.h>
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>
110 * define MB_DEBUG to display run-time debugging information
115 #define DPRINTF(x) printf x
122 SYSCTL_NODE(, OID_AUTO
, security
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
123 "Security Controls");
124 SYSCTL_NODE(_security
, OID_AUTO
, mac
, CTLFLAG_RW
|CTLFLAG_LOCKED
, 0,
125 "TrustedBSD MAC policy controls");
128 * Declare that the kernel provides MAC support, version 1. This permits
129 * modules to refuse to be loaded if the necessary support isn't present,
130 * even if it's pre-boot.
133 MODULE_VERSION(kernel_mac_support
, 1);
136 #if MAC_MAX_SLOTS > 32
137 #error "MAC_MAX_SLOTS too large"
140 static unsigned int mac_max_slots
= MAC_MAX_SLOTS
;
141 static unsigned int mac_slot_offsets_free
= (1 << MAC_MAX_SLOTS
) - 1;
142 SYSCTL_UINT(_security_mac
, OID_AUTO
, max_slots
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
143 &mac_max_slots
, 0, "");
146 * Has the kernel started generating labeled objects yet? All read/write
147 * access to this variable is serialized during the boot process. Following
148 * the end of serialization, we don't update this flag; no locking.
153 * Flag to indicate whether or not we should allocate label storage for
154 * new mbufs. Since most dynamic policies we currently work with don't
155 * rely on mbuf labeling, try to avoid paying the cost of mtag allocation
156 * unless specifically notified of interest. One result of this is
157 * that if a dynamically loaded policy requests mbuf labels, it must
158 * be able to deal with a NULL label being returned on any mbufs that
159 * were already in flight when the policy was loaded. Since the policy
160 * already has to deal with uninitialized labels, this probably won't
161 * be a problem. Note: currently no locking. Will this be a problem?
164 unsigned int mac_label_mbufs
= 1;
165 SYSCTL_UINT(_security_mac
, OID_AUTO
, label_mbufs
, SECURITY_MAC_CTLFLAGS
,
166 &mac_label_mbufs
, 0, "Label all MBUFs");
171 * Flag to indicate whether or not we should allocate label storage for
172 * new vnodes. Since most dynamic policies we currently work with don't
173 * rely on vnode labeling, try to avoid paying the cost of mtag allocation
174 * unless specifically notified of interest. One result of this is
175 * that if a dynamically loaded policy requests vnode labels, it must
176 * be able to deal with a NULL label being returned on any vnodes that
177 * were already in flight when the policy was loaded. Since the policy
178 * already has to deal with uninitialized labels, this probably won't
181 unsigned int mac_label_vnodes
= 0;
182 SYSCTL_UINT(_security_mac
, OID_AUTO
, labelvnodes
, SECURITY_MAC_CTLFLAGS
,
183 &mac_label_vnodes
, 0, "Label all vnodes");
186 unsigned int mac_mmap_revocation
= 0;
187 SYSCTL_UINT(_security_mac
, OID_AUTO
, mmap_revocation
, SECURITY_MAC_CTLFLAGS
,
188 &mac_mmap_revocation
, 0, "Revoke mmap access to files on subject "
191 unsigned int mac_mmap_revocation_via_cow
= 0;
192 SYSCTL_UINT(_security_mac
, OID_AUTO
, mmap_revocation_via_cow
, SECURITY_MAC_CTLFLAGS
,
193 &mac_mmap_revocation_via_cow
, 0, "Revoke mmap access to files via "
194 "copy-on-write semantics, or by removing all write access");
196 unsigned int mac_device_enforce
= 1;
197 SYSCTL_UINT(_security_mac
, OID_AUTO
, device_enforce
, SECURITY_MAC_CTLFLAGS
,
198 &mac_device_enforce
, 0, "Enforce MAC policy on device operations");
200 unsigned int mac_pipe_enforce
= 1;
201 SYSCTL_UINT(_security_mac
, OID_AUTO
, pipe_enforce
, SECURITY_MAC_CTLFLAGS
,
202 &mac_pipe_enforce
, 0, "Enforce MAC policy on pipe operations");
204 unsigned int mac_posixsem_enforce
= 1;
205 SYSCTL_UINT(_security_mac
, OID_AUTO
, posixsem_enforce
, SECURITY_MAC_CTLFLAGS
,
206 &mac_posixsem_enforce
, 0, "Enforce MAC policy on POSIX semaphores");
208 unsigned int mac_posixshm_enforce
= 1;
209 SYSCTL_UINT(_security_mac
, OID_AUTO
, posixshm_enforce
, SECURITY_MAC_CTLFLAGS
,
210 &mac_posixshm_enforce
, 0, "Enforce MAC policy on Posix Shared Memory");
212 unsigned int mac_proc_enforce
= 1;
213 SYSCTL_UINT(_security_mac
, OID_AUTO
, proc_enforce
, SECURITY_MAC_CTLFLAGS
,
214 &mac_proc_enforce
, 0, "Enforce MAC policy on process operations");
216 unsigned int mac_socket_enforce
= 1;
217 SYSCTL_UINT(_security_mac
, OID_AUTO
, socket_enforce
, SECURITY_MAC_CTLFLAGS
,
218 &mac_socket_enforce
, 0, "Enforce MAC policy on socket operations");
220 unsigned int mac_system_enforce
= 1;
221 SYSCTL_UINT(_security_mac
, OID_AUTO
, system_enforce
, SECURITY_MAC_CTLFLAGS
,
222 &mac_system_enforce
, 0, "Enforce MAC policy on system-wide interfaces");
224 unsigned int mac_sysvmsg_enforce
= 1;
225 SYSCTL_UINT(_security_mac
, OID_AUTO
, sysvmsg_enforce
, SECURITY_MAC_CTLFLAGS
,
226 &mac_sysvmsg_enforce
, 0, "Enforce MAC policy on System V IPC message queues");
228 unsigned int mac_sysvsem_enforce
= 1;
229 SYSCTL_UINT(_security_mac
, OID_AUTO
, sysvsem_enforce
, SECURITY_MAC_CTLFLAGS
,
230 &mac_sysvsem_enforce
, 0, "Enforce MAC policy on System V IPC semaphores");
232 unsigned int mac_sysvshm_enforce
= 1;
233 SYSCTL_INT(_security_mac
, OID_AUTO
, sysvshm_enforce
, SECURITY_MAC_CTLFLAGS
,
234 &mac_sysvshm_enforce
, 0, "Enforce MAC policy on System V Shared Memory");
236 unsigned int mac_vm_enforce
= 1;
237 SYSCTL_INT(_security_mac
, OID_AUTO
, vm_enforce
, SECURITY_MAC_CTLFLAGS
,
238 &mac_vm_enforce
, 0, "Enforce MAC policy on VM operations");
240 unsigned int mac_vnode_enforce
= 1;
241 SYSCTL_UINT(_security_mac
, OID_AUTO
, vnode_enforce
, SECURITY_MAC_CTLFLAGS
,
242 &mac_vnode_enforce
, 0, "Enforce MAC policy on vnode operations");
246 * mac_audit_data_zone is the zone used for data pushed into the audit
247 * record by policies. Using a zone simplifies memory management of this
248 * data, and allows tracking of the amount of data in flight.
250 extern zone_t mac_audit_data_zone
;
254 * mac_policy_list holds the list of policy modules. Modules with a
255 * handle lower than staticmax are considered "static" and cannot be
256 * unloaded. Such policies can be invoked without holding the busy count.
258 * Modules with a handle at or above the staticmax high water mark
259 * are considered to be "dynamic" policies. A busy count is maintained
260 * for the list, stored in mac_policy_busy. The busy count is protected
261 * by mac_policy_mtx; the list may be modified only while the busy
262 * count is 0, requiring that the lock be held to prevent new references
263 * to the list from being acquired. For almost all operations,
264 * incrementing the busy count is sufficient to guarantee consistency,
265 * as the list cannot be modified while the busy count is elevated.
266 * For a few special operations involving a change to the list of
267 * active policies, the mtx itself must be held.
269 static lck_mtx_t
*mac_policy_mtx
;
272 * Policy list array allocation chunk size. Trying to set this so that we
273 * allocate a page at a time.
275 #define MAC_POLICY_LIST_CHUNKSIZE 512
277 static int mac_policy_busy
;
279 mac_policy_list_t mac_policy_list
;
282 * mac_label_element_list holds the master list of label namespaces for
283 * all the policies. When a policy is loaded, each of it's label namespace
284 * elements is added to the master list if not already present. When a
285 * policy is unloaded, the namespace elements are removed if no other
286 * policy is interested in that namespace element.
288 struct mac_label_element_list_t mac_label_element_list
;
289 struct mac_label_element_list_t mac_static_label_element_list
;
292 mac_policy_grab_exclusive(void)
294 lck_mtx_lock(mac_policy_mtx
);
295 while (mac_policy_busy
!= 0) {
296 lck_mtx_sleep(mac_policy_mtx
, LCK_SLEEP_UNLOCK
,
297 (event_t
)&mac_policy_busy
, THREAD_UNINT
);
298 lck_mtx_lock(mac_policy_mtx
);
303 mac_policy_release_exclusive(void)
306 KASSERT(mac_policy_busy
== 0,
307 ("mac_policy_release_exclusive(): not exclusive"));
308 lck_mtx_unlock(mac_policy_mtx
);
309 thread_wakeup((event_t
) &mac_policy_busy
);
313 mac_policy_list_busy(void)
315 lck_mtx_lock(mac_policy_mtx
);
317 lck_mtx_unlock(mac_policy_mtx
);
321 mac_policy_list_conditional_busy(void)
325 if (mac_policy_list
.numloaded
<= mac_policy_list
.staticmax
)
328 lck_mtx_lock(mac_policy_mtx
);
329 if (mac_policy_list
.numloaded
> mac_policy_list
.staticmax
) {
334 lck_mtx_unlock(mac_policy_mtx
);
339 mac_policy_list_unbusy(void)
341 lck_mtx_lock(mac_policy_mtx
);
343 KASSERT(mac_policy_busy
>= 0, ("MAC_POLICY_LIST_LOCK"));
344 if (mac_policy_busy
== 0)
345 thread_wakeup(&mac_policy_busy
);
346 lck_mtx_unlock(mac_policy_mtx
);
350 * Early pre-malloc MAC initialization, including appropriate SMP locks.
353 mac_policy_init(void)
355 lck_grp_attr_t
*mac_lck_grp_attr
;
356 lck_attr_t
*mac_lck_attr
;
357 lck_grp_t
*mac_lck_grp
;
359 mac_policy_list
.numloaded
= 0;
360 mac_policy_list
.max
= MAC_POLICY_LIST_CHUNKSIZE
;
361 mac_policy_list
.maxindex
= 0;
362 mac_policy_list
.staticmax
= 0;
363 mac_policy_list
.freehint
= 0;
364 mac_policy_list
.chunks
= 1;
366 mac_policy_list
.entries
= kalloc(sizeof(struct mac_policy_list_element
) * MAC_POLICY_LIST_CHUNKSIZE
);
368 bzero(mac_policy_list
.entries
, sizeof(struct mac_policy_list_element
) * MAC_POLICY_LIST_CHUNKSIZE
);
370 LIST_INIT(&mac_label_element_list
);
371 LIST_INIT(&mac_static_label_element_list
);
373 mac_lck_grp_attr
= lck_grp_attr_alloc_init();
374 lck_grp_attr_setstat(mac_lck_grp_attr
);
375 mac_lck_grp
= lck_grp_alloc_init("MAC lock", mac_lck_grp_attr
);
376 mac_lck_attr
= lck_attr_alloc_init();
377 lck_attr_setdefault(mac_lck_attr
);
378 mac_policy_mtx
= lck_mtx_alloc_init(mac_lck_grp
, mac_lck_attr
);
379 lck_attr_free(mac_lck_attr
);
380 lck_grp_attr_free(mac_lck_grp_attr
);
381 lck_grp_free(mac_lck_grp
);
383 mac_labelzone_init();
386 /* Function pointer set up for loading security extensions.
387 * It is set to an actual function after OSlibkernInit()
388 * has been called, and is set back to 0 by OSKextRemoveKextBootstrap()
391 void (*load_security_extensions_function
)(void) = 0;
394 * Init after early Mach startup, but before BSD
397 mac_policy_initmach(void)
401 * For the purposes of modules that want to know if they were
402 * loaded "early", set the mac_late flag once we've processed
403 * modules either linked into the kernel, or loaded before the
407 if (load_security_extensions_function
) {
408 load_security_extensions_function();
417 mac_policy_initbsd(void)
419 struct mac_policy_conf
*mpc
;
423 mac_audit_data_zone
= zinit(MAC_AUDIT_DATA_LIMIT
,
424 AQ_HIWATER
* MAC_AUDIT_DATA_LIMIT
,
425 8192, "mac_audit_data_zone");
428 printf("MAC Framework successfully initialized\n");
430 /* Call bsd init functions of already loaded policies */
433 * Using the exclusive lock means no other framework entry
434 * points can proceed while initializations are running.
435 * This may not be necessary.
437 mac_policy_grab_exclusive();
439 for (i
= 0; i
<= mac_policy_list
.maxindex
; i
++) {
440 mpc
= mac_get_mpc(i
);
441 if ((mpc
!= NULL
) && (mpc
->mpc_ops
->mpo_policy_initbsd
!= NULL
))
442 (*(mpc
->mpc_ops
->mpo_policy_initbsd
))(mpc
);
445 mac_policy_release_exclusive();
449 * After a policy has been loaded, add the label namespaces managed by the
450 * policy to either the static or non-static label namespace list.
451 * A namespace is added to the the list only if it is not already on one of
455 mac_policy_addto_labellist(mac_policy_handle_t handle
, int static_entry
)
457 struct mac_label_listener
**new_mlls
;
458 struct mac_label_element
*mle
, **new_mles
;
459 struct mac_label_element_list_t
*list
;
460 struct mac_policy_conf
*mpc
;
461 const char *name
, *name2
;
462 u_int idx
, mle_free
, mll_free
;
464 mpc
= mac_get_mpc(handle
);
466 if (mpc
->mpc_labelnames
== NULL
)
469 if (mpc
->mpc_labelname_count
== 0)
473 list
= &mac_static_label_element_list
;
475 list
= &mac_label_element_list
;
478 * Before we grab the policy list lock, allocate enough memory
479 * to contain the potential new elements so we don't have to
480 * give up the lock, or allocate with the lock held.
482 MALLOC(new_mles
, struct mac_label_element
**,
483 sizeof(struct mac_label_element
*) *
484 mpc
->mpc_labelname_count
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
485 for (idx
= 0; idx
< mpc
->mpc_labelname_count
; idx
++)
486 MALLOC(new_mles
[idx
], struct mac_label_element
*,
487 sizeof(struct mac_label_element
),
488 M_MACTEMP
, M_WAITOK
);
490 MALLOC(new_mlls
, struct mac_label_listener
**,
491 sizeof(struct mac_label_listener
*) *
492 mpc
->mpc_labelname_count
, M_MACTEMP
, M_WAITOK
);
493 for (idx
= 0; idx
< mpc
->mpc_labelname_count
; idx
++)
494 MALLOC(new_mlls
[idx
], struct mac_label_listener
*,
495 sizeof(struct mac_label_listener
), M_MACTEMP
, M_WAITOK
);
499 mac_policy_grab_exclusive();
500 for (idx
= 0; idx
< mpc
->mpc_labelname_count
; idx
++) {
502 if (*(name
= mpc
->mpc_labelnames
[idx
]) == '?')
505 * Check both label element lists and add to the
506 * appropriate list only if not already on a list.
508 LIST_FOREACH(mle
, &mac_static_label_element_list
, mle_list
) {
509 if (*(name2
= mle
->mle_name
) == '?')
511 if (strcmp(name
, name2
) == 0)
515 LIST_FOREACH(mle
, &mac_label_element_list
, mle_list
) {
516 if (*(name2
= mle
->mle_name
) == '?')
518 if (strcmp(name
, name2
) == 0)
523 mle
= new_mles
[mle_free
];
524 strlcpy(mle
->mle_name
, mpc
->mpc_labelnames
[idx
],
525 MAC_MAX_LABEL_ELEMENT_NAME
);
526 LIST_INIT(&mle
->mle_listeners
);
527 LIST_INSERT_HEAD(list
, mle
, mle_list
);
530 /* Add policy handler as a listener. */
531 new_mlls
[mll_free
]->mll_handle
= handle
;
532 LIST_INSERT_HEAD(&mle
->mle_listeners
, new_mlls
[mll_free
],
537 mac_policy_release_exclusive();
539 /* Free up any unused label elements and listeners */
540 for (idx
= mle_free
; idx
< mpc
->mpc_labelname_count
; idx
++)
541 FREE(new_mles
[idx
], M_MACTEMP
);
542 FREE(new_mles
, M_MACTEMP
);
543 for (idx
= mll_free
; idx
< mpc
->mpc_labelname_count
; idx
++)
544 FREE(new_mlls
[idx
], M_MACTEMP
);
545 FREE(new_mlls
, M_MACTEMP
);
549 * After a policy has been unloaded, remove the label namespaces that the
550 * the policy manages from the non-static list of namespaces.
551 * The removal only takes place when no other policy is interested in the
554 * Must be called with the policy exclusive lock held.
557 mac_policy_removefrom_labellist(mac_policy_handle_t handle
)
559 struct mac_label_listener
*mll
;
560 struct mac_label_element
*mle
;
561 struct mac_policy_conf
*mpc
;
563 mpc
= mac_get_mpc(handle
);
565 if (mpc
->mpc_labelnames
== NULL
)
568 if (mpc
->mpc_labelname_count
== 0)
572 * Unregister policy as being interested in any label
573 * namespaces. If no other policy is listening, remove
574 * that label element from the list. Note that we only
575 * have to worry about the non-static list.
577 LIST_FOREACH(mle
, &mac_label_element_list
, mle_list
) {
578 LIST_FOREACH(mll
, &mle
->mle_listeners
, mll_list
) {
579 if (mll
->mll_handle
== handle
) {
580 LIST_REMOVE(mll
, mll_list
);
581 FREE(mll
, M_MACTEMP
);
582 if (LIST_EMPTY(&mle
->mle_listeners
)) {
583 LIST_REMOVE(mle
, mle_list
);
584 FREE(mle
, M_MACTEMP
);
593 * After the policy list has changed, walk the list to update any global
597 mac_policy_updateflags(void)
602 mac_policy_fixup_mmd_list(struct mac_module_data
*new)
604 struct mac_module_data
*old
;
605 struct mac_module_data_element
*ele
, *aele
;
606 struct mac_module_data_list
*arr
, *dict
;
607 unsigned int i
, j
, k
;
609 old
= new->base_addr
;
610 DPRINTF(("fixup_mmd: old %p new %p\n", old
, new));
611 for (i
= 0; i
< new->count
; i
++) {
612 ele
= &(new->data
[i
]);
613 DPRINTF(("fixup_mmd: ele %p\n", ele
));
614 DPRINTF((" key %p value %p\n", ele
->key
, ele
->value
));
615 mmd_fixup_ele(old
, new, ele
); /* Fix up key/value ptrs. */
616 DPRINTF((" key %p value %p\n", ele
->key
, ele
->value
));
617 if (ele
->value_type
== MAC_DATA_TYPE_ARRAY
) {
618 arr
= (struct mac_module_data_list
*)ele
->value
;
619 DPRINTF(("fixup_mmd: array @%p\n", arr
));
620 for (j
= 0; j
< arr
->count
; j
++) {
621 aele
= &(arr
->list
[j
]);
622 DPRINTF(("fixup_mmd: aele %p\n", aele
));
623 DPRINTF((" key %p value %p\n", aele
->key
, aele
->value
));
624 mmd_fixup_ele(old
, new, aele
);
625 DPRINTF((" key %p value %p\n", aele
->key
, aele
->value
));
626 if (arr
->type
== MAC_DATA_TYPE_DICT
) {
627 dict
= (struct mac_module_data_list
*)aele
->value
;
628 DPRINTF(("fixup_mmd: dict @%p\n", dict
));
629 for (k
= 0; k
< dict
->count
; k
++)
630 mmd_fixup_ele(old
, new,
636 new->base_addr
= new;
640 mac_policy_register(struct mac_policy_conf
*mpc
, mac_policy_handle_t
*handlep
,
643 struct mac_policy_list_element
*tmac_policy_list_element
;
644 int error
, slot
, static_entry
= 0;
648 * Some preliminary checks to make sure the policy's conf structure
649 * contains the required fields.
651 if (mpc
->mpc_name
== NULL
)
652 panic("policy's name is not set\n");
654 if (mpc
->mpc_fullname
== NULL
)
655 panic("policy's full name is not set\n");
657 if (mpc
->mpc_labelname_count
> MAC_MAX_MANAGED_NAMESPACES
)
658 panic("policy's managed label namespaces exceeds maximum\n");
660 if (mpc
->mpc_ops
== NULL
)
661 panic("policy's OPs field is NULL\n");
666 if (mpc
->mpc_loadtime_flags
& MPC_LOADTIME_FLAG_NOTLATE
) {
667 printf("Module %s does not support late loading.\n",
671 mac_policy_grab_exclusive();
674 if (mac_policy_list
.numloaded
>= mac_policy_list
.max
) {
675 /* allocate new policy list array, zero new chunk */
676 tmac_policy_list_element
=
677 kalloc((sizeof(struct mac_policy_list_element
) *
678 MAC_POLICY_LIST_CHUNKSIZE
) * (mac_policy_list
.chunks
+ 1));
679 bzero(&tmac_policy_list_element
[mac_policy_list
.max
],
680 sizeof(struct mac_policy_list_element
) *
681 MAC_POLICY_LIST_CHUNKSIZE
);
683 /* copy old entries into new list */
684 memcpy(tmac_policy_list_element
, mac_policy_list
.entries
,
685 sizeof(struct mac_policy_list_element
) *
686 MAC_POLICY_LIST_CHUNKSIZE
* mac_policy_list
.chunks
);
689 kfree(mac_policy_list
.entries
,
690 sizeof(struct mac_policy_list_element
) *
691 MAC_POLICY_LIST_CHUNKSIZE
* mac_policy_list
.chunks
);
693 mac_policy_list
.entries
= tmac_policy_list_element
;
695 /* Update maximums, etc */
696 mac_policy_list
.max
+= MAC_POLICY_LIST_CHUNKSIZE
;
697 mac_policy_list
.chunks
++;
700 /* Check for policy with same name already loaded */
701 for (i
= 0; i
<= mac_policy_list
.maxindex
; i
++) {
702 if (mac_policy_list
.entries
[i
].mpc
== NULL
)
705 if (strcmp(mac_policy_list
.entries
[i
].mpc
->mpc_name
,
706 mpc
->mpc_name
) == 0) {
712 if (mpc
->mpc_field_off
!= NULL
) {
713 slot
= ffs(mac_slot_offsets_free
);
719 mac_slot_offsets_free
&= ~(1 << slot
);
720 *mpc
->mpc_field_off
= slot
;
722 mpc
->mpc_runtime_flags
|= MPC_RUNTIME_FLAG_REGISTERED
;
725 struct mac_module_data
*mmd
= xd
; /* module data from plist */
727 /* Make a copy of the data. */
728 mpc
->mpc_data
= (void *)kalloc(mmd
->size
);
729 if (mpc
->mpc_data
!= NULL
) {
730 memcpy(mpc
->mpc_data
, mmd
, mmd
->size
);
732 /* Fix up pointers after copy. */
733 mac_policy_fixup_mmd_list(mpc
->mpc_data
);
737 /* Find the first free handle in the list (using our hint). */
738 for (i
= mac_policy_list
.freehint
; i
< mac_policy_list
.max
; i
++) {
739 if (mac_policy_list
.entries
[i
].mpc
== NULL
) {
741 mac_policy_list
.freehint
= ++i
;
747 * If we are loading a MAC module before the framework has
748 * finished initializing or the module is not unloadable and
749 * we can place its handle adjacent to the last static entry,
750 * bump the static policy high water mark.
751 * Static policies can get by with weaker locking requirements.
754 ((mpc
->mpc_loadtime_flags
& MPC_LOADTIME_FLAG_UNLOADOK
) == 0 &&
755 *handlep
== mac_policy_list
.staticmax
)) {
757 mac_policy_list
.staticmax
++;
760 mac_policy_list
.entries
[*handlep
].mpc
= mpc
;
762 /* Update counters, etc */
763 if (*handlep
> mac_policy_list
.maxindex
)
764 mac_policy_list
.maxindex
= *handlep
;
765 mac_policy_list
.numloaded
++;
767 /* Per-policy initialization. */
768 printf ("calling mpo_policy_init for %s\n", mpc
->mpc_name
);
769 if (mpc
->mpc_ops
->mpo_policy_init
!= NULL
)
770 (*(mpc
->mpc_ops
->mpo_policy_init
))(mpc
);
772 if (mac_late
&& mpc
->mpc_ops
->mpo_policy_initbsd
!= NULL
) {
773 printf ("calling mpo_policy_initbsd for %s\n", mpc
->mpc_name
);
774 (*(mpc
->mpc_ops
->mpo_policy_initbsd
))(mpc
);
777 mac_policy_updateflags();
780 mac_policy_release_exclusive();
782 mac_policy_addto_labellist(*handlep
, static_entry
);
784 printf("Security policy loaded: %s (%s)\n", mpc
->mpc_fullname
,
791 mac_policy_release_exclusive();
797 mac_policy_unregister(mac_policy_handle_t handle
)
799 struct mac_policy_conf
*mpc
;
802 * If we fail the load, we may get a request to unload. Check
803 * to see if we did the run-time registration, and if not,
806 mac_policy_grab_exclusive();
807 mpc
= mac_get_mpc(handle
);
808 if ((mpc
->mpc_runtime_flags
& MPC_RUNTIME_FLAG_REGISTERED
) == 0) {
809 mac_policy_release_exclusive();
815 * Don't allow unloading modules with private data.
817 if (mpc
->mpc_field_off
!= NULL
) {
818 MAC_POLICY_LIST_UNLOCK();
823 * Only allow the unload to proceed if the module is unloadable
824 * by its own definition.
826 if ((mpc
->mpc_loadtime_flags
& MPC_LOADTIME_FLAG_UNLOADOK
) == 0) {
827 mac_policy_release_exclusive();
831 mac_policy_removefrom_labellist(handle
);
833 mac_get_mpc(handle
) = NULL
;
834 if (handle
< mac_policy_list
.freehint
&&
835 handle
>= mac_policy_list
.staticmax
)
836 mac_policy_list
.freehint
= handle
;
838 if (handle
== mac_policy_list
.maxindex
)
839 mac_policy_list
.maxindex
--;
841 mac_policy_list
.numloaded
--;
842 if (mpc
->mpc_field_off
!= NULL
) {
843 mac_slot_offsets_free
|= (1 << *mpc
->mpc_field_off
);
846 if (mpc
->mpc_ops
->mpo_policy_destroy
!= NULL
)
847 (*(mpc
->mpc_ops
->mpo_policy_destroy
))(mpc
);
849 mpc
->mpc_runtime_flags
&= ~MPC_RUNTIME_FLAG_REGISTERED
;
850 mac_policy_updateflags();
852 mac_policy_release_exclusive();
855 struct mac_module_data
*mmd
= mpc
->mpc_data
;
856 kfree(mmd
, mmd
->size
);
857 mpc
->mpc_data
= NULL
;
860 printf("Security policy unload: %s (%s)\n", mpc
->mpc_fullname
,
867 * Define an error value precedence, and given two arguments, selects the
868 * value with the higher precedence.
871 mac_error_select(int error1
, int error2
)
874 /* Certain decision-making errors take top priority. */
875 if (error1
== EDEADLK
|| error2
== EDEADLK
)
878 /* Invalid arguments should be reported where possible. */
879 if (error1
== EINVAL
|| error2
== EINVAL
)
882 /* Precedence goes to "visibility", with both process and file. */
883 if (error1
== ESRCH
|| error2
== ESRCH
)
886 if (error1
== ENOENT
|| error2
== ENOENT
)
889 /* Precedence goes to DAC/MAC protections. */
890 if (error1
== EACCES
|| error2
== EACCES
)
893 /* Precedence goes to privilege. */
894 if (error1
== EPERM
|| error2
== EPERM
)
897 /* Precedence goes to error over success; otherwise, arbitrary. */
904 mac_label_init(struct label
*label
)
907 bzero(label
, sizeof(*label
));
908 label
->l_flags
= MAC_FLAG_INITIALIZED
;
912 mac_label_destroy(struct label
*label
)
915 KASSERT(label
->l_flags
& MAC_FLAG_INITIALIZED
,
916 ("destroying uninitialized label"));
918 bzero(label
, sizeof(*label
));
919 /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
923 mac_check_structmac_consistent(struct user_mac
*mac
)
926 if (mac
->m_buflen
> MAC_MAX_LABEL_BUF_LEN
|| mac
->m_buflen
== 0)
933 * Get the external forms of labels from all policies, for a single
934 * label namespace or "*" for all namespaces. Returns ENOENT if no policy
935 * is registered for the namespace, unless the namespace begins with a '?'.
938 mac_label_externalize(size_t mpo_externalize_off
, struct label
*label
,
939 const char *element
, struct sbuf
*sb
)
941 struct mac_policy_conf
*mpc
;
942 struct mac_label_listener
*mll
;
943 struct mac_label_element
*mle
;
944 struct mac_label_element_list_t
*element_list
;
946 int (*mpo_externalize
)(struct label
*, char *, struct sbuf
*);
947 int all_labels
= 0, ignorenotfound
= 0, error
= 0, busy
= FALSE
;
948 unsigned int count
= 0;
950 if (element
[0] == '?') {
953 } else if (element
[0] == '*' && element
[1] == '\0')
956 element_list
= &mac_static_label_element_list
;
958 LIST_FOREACH(mle
, element_list
, mle_list
) {
959 name
= mle
->mle_name
;
966 if (strcmp(name
, element
) != 0)
969 LIST_FOREACH(mll
, &mle
->mle_listeners
, mll_list
) {
970 mpc
= mac_policy_list
.entries
[mll
->mll_handle
].mpc
;
973 mpo_externalize
= *(typeof(mpo_externalize
) *)
974 ((char *)mpc
->mpc_ops
+ mpo_externalize_off
);
975 if (mpo_externalize
== NULL
)
977 error
= sbuf_printf(sb
, "%s/", name
);
980 error
= mpo_externalize(label
, mle
->mle_name
, sb
);
985 * If a policy doesn't have a label to
986 * externalize it returns ENOENT. This
987 * may occur for policies that support
988 * multiple label elements for some
989 * (but not all) object types.
991 sbuf_setpos(sb
, sbuf_len(sb
) -
996 error
= sbuf_putc(sb
, ',');
1002 /* If there are dynamic policies present, check their elements too. */
1003 if (!busy
&& mac_policy_list_conditional_busy() == 1) {
1004 element_list
= &mac_label_element_list
;
1010 mac_policy_list_unbusy();
1011 if (!error
&& count
== 0) {
1012 if (!all_labels
&& !ignorenotfound
)
1013 error
= ENOENT
; /* XXX: ENOLABEL? */
1019 * Get the external forms of labels from all policies, for all label
1020 * namespaces contained in a list.
1022 * XXX This may be leaking an sbuf.
1025 mac_externalize(size_t mpo_externalize_off
, struct label
*label
,
1026 const char *elementlist
, char *outbuf
, size_t outbuflen
)
1034 /* allocate a scratch buffer the size of the string */
1035 MALLOC(scratch_base
, char *, strlen(elementlist
)+1, M_MACTEMP
, M_WAITOK
);
1036 if (scratch_base
== NULL
) {
1041 /* copy the elementlist to the scratch buffer */
1042 strlcpy(scratch_base
, elementlist
, strlen(elementlist
)+1);
1045 * set up a temporary pointer that can be used to iterate the
1046 * scratch buffer without losing the allocation address
1048 scratch
= scratch_base
;
1051 if (sbuf_new(&sb
, outbuf
, outbuflen
, SBUF_FIXEDLEN
) == NULL
) {
1052 /* could not allocate interior buffer */
1056 /* iterate the scratch buffer; NOTE: buffer contents modified! */
1057 while ((element
= strsep(&scratch
, ",")) != NULL
) {
1058 error
= mac_label_externalize(mpo_externalize_off
, label
,
1063 if ((len
= sbuf_len(&sb
)) > 0)
1064 sbuf_setpos(&sb
, len
- 1); /* trim trailing comma */
1068 if (scratch_base
!= NULL
)
1069 FREE(scratch_base
, M_MACTEMP
);
1075 * Have all policies set the internal form of a label, for a single
1079 mac_label_internalize(size_t mpo_internalize_off
, struct label
*label
,
1080 char *element_name
, char *element_data
)
1082 struct mac_policy_conf
*mpc
;
1083 struct mac_label_listener
*mll
;
1084 struct mac_label_element
*mle
;
1085 struct mac_label_element_list_t
*element_list
;
1086 int (*mpo_internalize
)(struct label
*, char *, char *);
1087 int error
= 0, busy
= FALSE
;
1088 unsigned int count
= 0;
1091 element_list
= &mac_static_label_element_list
;
1093 LIST_FOREACH(mle
, element_list
, mle_list
) {
1094 if (*(name
= mle
->mle_name
) == '?')
1096 if (strcmp(element_name
, name
) != 0)
1098 LIST_FOREACH(mll
, &mle
->mle_listeners
, mll_list
) {
1099 mpc
= mac_policy_list
.entries
[mll
->mll_handle
].mpc
;
1102 mpo_internalize
= *(typeof(mpo_internalize
) *)
1103 ((char *)mpc
->mpc_ops
+ mpo_internalize_off
);
1104 if (mpo_internalize
== NULL
)
1106 error
= mpo_internalize(label
, element_name
,
1113 /* If there are dynamic policies present, check their elements too. */
1114 if (!busy
&& mac_policy_list_conditional_busy() == 1) {
1115 element_list
= &mac_label_element_list
;
1121 mac_policy_list_unbusy();
1122 if (!error
&& count
== 0)
1128 mac_internalize(size_t mpo_internalize_off
, struct label
*label
,
1131 char *element_name
, *element_data
;
1134 while (!error
&& (element_name
= strsep(&textlabels
, ",")) != NULL
) {
1135 element_data
= strchr(element_name
, '/');
1136 if (element_data
== NULL
) {
1140 *element_data
++ = '\0';
1141 error
= mac_label_internalize(mpo_internalize_off
, label
,
1142 element_name
, element_data
);
1150 __mac_get_pid(struct proc
*p
, struct __mac_get_pid_args
*uap
, int *ret __unused
)
1152 char *elements
, *buffer
;
1153 struct user_mac mac
;
1155 struct ucred
*tcred
;
1159 AUDIT_ARG(pid
, uap
->pid
);
1160 if (IS_64BIT_PROCESS(p
)) {
1161 struct user64_mac mac64
;
1162 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1163 mac
.m_buflen
= mac64
.m_buflen
;
1164 mac
.m_string
= mac64
.m_string
;
1166 struct user32_mac mac32
;
1167 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1168 mac
.m_buflen
= mac32
.m_buflen
;
1169 mac
.m_string
= mac32
.m_string
;
1174 error
= mac_check_structmac_consistent(&mac
);
1178 tproc
= proc_find(uap
->pid
);
1181 tcred
= kauth_cred_proc_ref(tproc
);
1184 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1185 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1187 FREE(elements
, M_MACTEMP
);
1188 kauth_cred_unref(&tcred
);
1191 AUDIT_ARG(mac_string
, elements
);
1193 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
1194 error
= mac_cred_label_externalize(tcred
->cr_label
, elements
,
1195 buffer
, mac
.m_buflen
, M_WAITOK
);
1197 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
)+1);
1199 FREE(buffer
, M_MACTEMP
);
1200 FREE(elements
, M_MACTEMP
);
1201 kauth_cred_unref(&tcred
);
1206 __mac_get_proc(proc_t p
, struct __mac_get_proc_args
*uap
, int *ret __unused
)
1208 char *elements
, *buffer
;
1209 struct user_mac mac
;
1214 if (IS_64BIT_PROCESS(p
)) {
1215 struct user64_mac mac64
;
1216 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1217 mac
.m_buflen
= mac64
.m_buflen
;
1218 mac
.m_string
= mac64
.m_string
;
1220 struct user32_mac mac32
;
1221 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1222 mac
.m_buflen
= mac32
.m_buflen
;
1223 mac
.m_string
= mac32
.m_string
;
1228 error
= mac_check_structmac_consistent(&mac
);
1232 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1233 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1235 FREE(elements
, M_MACTEMP
);
1238 AUDIT_ARG(mac_string
, elements
);
1240 cr
= kauth_cred_proc_ref(p
);
1242 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
1243 error
= mac_cred_label_externalize(cr
->cr_label
,
1244 elements
, buffer
, mac
.m_buflen
, M_WAITOK
);
1246 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
)+1);
1248 FREE(buffer
, M_MACTEMP
);
1249 FREE(elements
, M_MACTEMP
);
1250 kauth_cred_unref(&cr
);
1255 __mac_set_proc(proc_t p
, struct __mac_set_proc_args
*uap
, int *ret __unused
)
1257 struct label
*intlabel
;
1258 struct user_mac mac
;
1263 if (IS_64BIT_PROCESS(p
)) {
1264 struct user64_mac mac64
;
1265 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1266 mac
.m_buflen
= mac64
.m_buflen
;
1267 mac
.m_string
= mac64
.m_string
;
1269 struct user32_mac mac32
;
1270 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1271 mac
.m_buflen
= mac32
.m_buflen
;
1272 mac
.m_string
= mac32
.m_string
;
1277 error
= mac_check_structmac_consistent(&mac
);
1281 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1282 error
= copyinstr(mac
.m_string
, buffer
, mac
.m_buflen
, &ulen
);
1284 FREE(buffer
, M_MACTEMP
);
1287 AUDIT_ARG(mac_string
, buffer
);
1289 intlabel
= mac_cred_label_alloc();
1290 error
= mac_cred_label_internalize(intlabel
, buffer
);
1291 FREE(buffer
, M_MACTEMP
);
1295 error
= mac_cred_check_label_update(kauth_cred_get(), intlabel
);
1300 error
= kauth_proc_label_update(p
, intlabel
);
1305 mac_cred_label_free(intlabel
);
1310 __mac_get_fd(proc_t p
, struct __mac_get_fd_args
*uap
, int *ret __unused
)
1312 struct fileproc
*fp
;
1314 struct user_mac mac
;
1315 char *elements
, *buffer
;
1318 kauth_cred_t my_cred
;
1319 #if CONFIG_MACF_SOCKET
1321 #endif /* MAC_SOCKET */
1322 struct label
*intlabel
;
1324 AUDIT_ARG(fd
, uap
->fd
);
1326 if (IS_64BIT_PROCESS(p
)) {
1327 struct user64_mac mac64
;
1328 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1329 mac
.m_buflen
= mac64
.m_buflen
;
1330 mac
.m_string
= mac64
.m_string
;
1332 struct user32_mac mac32
;
1333 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1334 mac
.m_buflen
= mac32
.m_buflen
;
1335 mac
.m_string
= mac32
.m_string
;
1341 error
= mac_check_structmac_consistent(&mac
);
1345 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1346 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1348 FREE(elements
, M_MACTEMP
);
1351 AUDIT_ARG(mac_string
, elements
);
1353 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1354 error
= fp_lookup(p
, uap
->fd
, &fp
, 0);
1356 FREE(buffer
, M_MACTEMP
);
1357 FREE(elements
, M_MACTEMP
);
1361 my_cred
= kauth_cred_proc_ref(p
);
1362 error
= mac_file_check_get(my_cred
, fp
->f_fglob
, elements
, mac
.m_buflen
);
1363 kauth_cred_unref(&my_cred
);
1365 fp_drop(p
, uap
->fd
, fp
, 0);
1366 FREE(buffer
, M_MACTEMP
);
1367 FREE(elements
, M_MACTEMP
);
1371 switch (FILEGLOB_DTYPE(fp
->f_fglob
)) {
1373 intlabel
= mac_vnode_label_alloc();
1374 if (intlabel
== NULL
) {
1378 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
1379 error
= vnode_getwithref(vp
);
1381 mac_vnode_label_copy(vp
->v_label
, intlabel
);
1382 error
= mac_vnode_label_externalize(intlabel
,
1384 mac
.m_buflen
, M_WAITOK
);
1387 mac_vnode_label_free(intlabel
);
1390 #if CONFIG_MACF_SOCKET
1391 so
= (struct socket
*) fp
->f_fglob
->fg_data
;
1392 intlabel
= mac_socket_label_alloc(MAC_WAITOK
);
1394 mac_socket_label_copy(so
->so_label
, intlabel
);
1396 error
= mac_socket_label_externalize(intlabel
, elements
, buffer
, mac
.m_buflen
);
1397 mac_socket_label_free(intlabel
);
1404 case DTYPE_FSEVENTS
:
1406 error
= ENOSYS
; // only sockets/vnodes so far
1409 fp_drop(p
, uap
->fd
, fp
, 0);
1412 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
)+1);
1414 FREE(buffer
, M_MACTEMP
);
1415 FREE(elements
, M_MACTEMP
);
1420 mac_get_filelink(proc_t p
, user_addr_t mac_p
, user_addr_t path_p
, int follow
)
1424 char *elements
, *buffer
;
1425 struct nameidata nd
;
1426 struct label
*intlabel
;
1427 struct user_mac mac
;
1431 if (IS_64BIT_PROCESS(p
)) {
1432 struct user64_mac mac64
;
1433 error
= copyin(mac_p
, &mac64
, sizeof(mac64
));
1434 mac
.m_buflen
= mac64
.m_buflen
;
1435 mac
.m_string
= mac64
.m_string
;
1437 struct user32_mac mac32
;
1438 error
= copyin(mac_p
, &mac32
, sizeof(mac32
));
1439 mac
.m_buflen
= mac32
.m_buflen
;
1440 mac
.m_string
= mac32
.m_string
;
1446 error
= mac_check_structmac_consistent(&mac
);
1450 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1451 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
1453 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1455 FREE(buffer
, M_MACTEMP
);
1456 FREE(elements
, M_MACTEMP
);
1459 AUDIT_ARG(mac_string
, elements
);
1461 ctx
= vfs_context_current();
1463 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
,
1464 LOCKLEAF
| (follow
? FOLLOW
: NOFOLLOW
) | AUDITVNPATH1
,
1465 UIO_USERSPACE
, path_p
, ctx
);
1468 FREE(buffer
, M_MACTEMP
);
1469 FREE(elements
, M_MACTEMP
);
1476 intlabel
= mac_vnode_label_alloc();
1477 mac_vnode_label_copy(vp
->v_label
, intlabel
);
1478 error
= mac_vnode_label_externalize(intlabel
, elements
, buffer
,
1479 mac
.m_buflen
, M_WAITOK
);
1480 mac_vnode_label_free(intlabel
);
1482 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
) + 1);
1486 FREE(buffer
, M_MACTEMP
);
1487 FREE(elements
, M_MACTEMP
);
1493 __mac_get_file(proc_t p
, struct __mac_get_file_args
*uap
,
1497 return (mac_get_filelink(p
, uap
->mac_p
, uap
->path_p
, 1));
1501 __mac_get_link(proc_t p
, struct __mac_get_link_args
*uap
,
1505 return (mac_get_filelink(p
, uap
->mac_p
, uap
->path_p
, 0));
1509 __mac_set_fd(proc_t p
, struct __mac_set_fd_args
*uap
, int *ret __unused
)
1512 struct fileproc
*fp
;
1513 struct user_mac mac
;
1514 struct vfs_context
*ctx
= vfs_context_current();
1518 struct label
*intlabel
;
1519 #if CONFIG_MACF_SOCKET
1524 AUDIT_ARG(fd
, uap
->fd
);
1526 if (IS_64BIT_PROCESS(p
)) {
1527 struct user64_mac mac64
;
1528 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1529 mac
.m_buflen
= mac64
.m_buflen
;
1530 mac
.m_string
= mac64
.m_string
;
1532 struct user32_mac mac32
;
1533 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1534 mac
.m_buflen
= mac32
.m_buflen
;
1535 mac
.m_string
= mac32
.m_string
;
1540 error
= mac_check_structmac_consistent(&mac
);
1544 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1545 error
= copyinstr(mac
.m_string
, buffer
, mac
.m_buflen
, &ulen
);
1547 FREE(buffer
, M_MACTEMP
);
1550 AUDIT_ARG(mac_string
, buffer
);
1552 error
= fp_lookup(p
, uap
->fd
, &fp
, 0);
1554 FREE(buffer
, M_MACTEMP
);
1559 error
= mac_file_check_set(vfs_context_ucred(ctx
), fp
->f_fglob
, buffer
, mac
.m_buflen
);
1561 fp_drop(p
, uap
->fd
, fp
, 0);
1562 FREE(buffer
, M_MACTEMP
);
1566 switch (FILEGLOB_DTYPE(fp
->f_fglob
)) {
1569 if (mac_label_vnodes
== 0) {
1574 intlabel
= mac_vnode_label_alloc();
1576 error
= mac_vnode_label_internalize(intlabel
, buffer
);
1578 mac_vnode_label_free(intlabel
);
1583 vp
= (struct vnode
*)fp
->f_fglob
->fg_data
;
1585 error
= vnode_getwithref(vp
);
1587 error
= vn_setlabel(vp
, intlabel
, ctx
);
1590 mac_vnode_label_free(intlabel
);
1594 #if CONFIG_MACF_SOCKET
1595 intlabel
= mac_socket_label_alloc(MAC_WAITOK
);
1596 error
= mac_socket_label_internalize(intlabel
, buffer
);
1598 so
= (struct socket
*) fp
->f_fglob
->fg_data
;
1600 error
= mac_socket_label_update(vfs_context_ucred(ctx
), so
, intlabel
);
1603 mac_socket_label_free(intlabel
);
1610 case DTYPE_FSEVENTS
:
1612 error
= ENOSYS
; // only sockets/vnodes so far
1616 fp_drop(p
, uap
->fd
, fp
, 0);
1617 FREE(buffer
, M_MACTEMP
);
1622 mac_set_filelink(proc_t p
, user_addr_t mac_p
, user_addr_t path_p
,
1625 register struct vnode
*vp
;
1626 struct vfs_context
*ctx
= vfs_context_current();
1627 struct label
*intlabel
;
1628 struct nameidata nd
;
1629 struct user_mac mac
;
1634 if (mac_label_vnodes
== 0)
1637 if (IS_64BIT_PROCESS(p
)) {
1638 struct user64_mac mac64
;
1639 error
= copyin(mac_p
, &mac64
, sizeof(mac64
));
1640 mac
.m_buflen
= mac64
.m_buflen
;
1641 mac
.m_string
= mac64
.m_string
;
1643 struct user32_mac mac32
;
1644 error
= copyin(mac_p
, &mac32
, sizeof(mac32
));
1645 mac
.m_buflen
= mac32
.m_buflen
;
1646 mac
.m_string
= mac32
.m_string
;
1651 error
= mac_check_structmac_consistent(&mac
);
1653 printf("mac_set_file: failed structure consistency check\n");
1657 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1658 error
= copyinstr(mac
.m_string
, buffer
, mac
.m_buflen
, &ulen
);
1660 FREE(buffer
, M_MACTEMP
);
1663 AUDIT_ARG(mac_string
, buffer
);
1665 intlabel
= mac_vnode_label_alloc();
1666 error
= mac_vnode_label_internalize(intlabel
, buffer
);
1667 FREE(buffer
, M_MACTEMP
);
1669 mac_vnode_label_free(intlabel
);
1673 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
,
1674 LOCKLEAF
| (follow
? FOLLOW
: NOFOLLOW
) | AUDITVNPATH1
,
1675 UIO_USERSPACE
, path_p
, ctx
);
1678 mac_vnode_label_free(intlabel
);
1685 error
= vn_setlabel(vp
, intlabel
, ctx
);
1687 mac_vnode_label_free(intlabel
);
1693 __mac_set_file(proc_t p
, struct __mac_set_file_args
*uap
,
1697 return (mac_set_filelink(p
, uap
->mac_p
, uap
->path_p
, 1));
1701 __mac_set_link(proc_t p
, struct __mac_set_link_args
*uap
,
1705 return (mac_set_filelink(p
, uap
->mac_p
, uap
->path_p
, 0));
1709 * __mac_syscall: Perform a MAC policy system call
1711 * Parameters: p Process calling this routine
1712 * uap User argument descriptor (see below)
1715 * Indirect: uap->policy Name of target MAC policy
1716 * uap->call MAC policy-specific system call to perform
1717 * uap->arg MAC policy-specific system call arguments
1719 * Returns: 0 Success
1724 __mac_syscall(proc_t p
, struct __mac_syscall_args
*uap
, int *retv __unused
)
1726 struct mac_policy_conf
*mpc
;
1727 char target
[MAC_MAX_POLICY_NAME
];
1732 error
= copyinstr(uap
->policy
, target
, sizeof(target
), &ulen
);
1735 AUDIT_ARG(value32
, uap
->call
);
1736 AUDIT_ARG(mac_string
, target
);
1740 for (i
= 0; i
< mac_policy_list
.staticmax
; i
++) {
1741 mpc
= mac_policy_list
.entries
[i
].mpc
;
1745 if (strcmp(mpc
->mpc_name
, target
) == 0 &&
1746 mpc
->mpc_ops
->mpo_policy_syscall
!= NULL
) {
1747 error
= mpc
->mpc_ops
->mpo_policy_syscall(p
,
1748 uap
->call
, uap
->arg
);
1752 if (mac_policy_list_conditional_busy() != 0) {
1753 for (; i
<= mac_policy_list
.maxindex
; i
++) {
1754 mpc
= mac_policy_list
.entries
[i
].mpc
;
1758 if (strcmp(mpc
->mpc_name
, target
) == 0 &&
1759 mpc
->mpc_ops
->mpo_policy_syscall
!= NULL
) {
1760 error
= mpc
->mpc_ops
->mpo_policy_syscall(p
,
1761 uap
->call
, uap
->arg
);
1765 mac_policy_list_unbusy();
1773 mac_mount_label_get(struct mount
*mp
, user_addr_t mac_p
)
1775 char *elements
, *buffer
;
1776 struct label
*label
;
1777 struct user_mac mac
;
1781 if (IS_64BIT_PROCESS(current_proc())) {
1782 struct user64_mac mac64
;
1783 error
= copyin(mac_p
, &mac64
, sizeof(mac64
));
1784 mac
.m_buflen
= mac64
.m_buflen
;
1785 mac
.m_string
= mac64
.m_string
;
1787 struct user32_mac mac32
;
1788 error
= copyin(mac_p
, &mac32
, sizeof(mac32
));
1789 mac
.m_buflen
= mac32
.m_buflen
;
1790 mac
.m_string
= mac32
.m_string
;
1795 error
= mac_check_structmac_consistent(&mac
);
1799 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1800 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1802 FREE(elements
, M_MACTEMP
);
1805 AUDIT_ARG(mac_string
, elements
);
1807 label
= mp
->mnt_mntlabel
;
1808 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
1809 error
= mac_mount_label_externalize(label
, elements
, buffer
,
1811 FREE(elements
, M_MACTEMP
);
1814 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
) + 1);
1815 FREE(buffer
, M_MACTEMP
);
1821 * __mac_get_mount: Get mount point label information for a given pathname
1823 * Parameters: p (ignored)
1824 * uap User argument descriptor (see below)
1827 * Indirect: uap->path Pathname
1828 * uap->mac_p MAC info
1830 * Returns: 0 Success
1834 __mac_get_mount(proc_t p __unused
, struct __mac_get_mount_args
*uap
,
1837 struct nameidata nd
;
1838 struct vfs_context
*ctx
= vfs_context_current();
1842 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1843 UIO_USERSPACE
, uap
->path
, ctx
);
1848 mp
= nd
.ni_vp
->v_mount
;
1849 vnode_put(nd
.ni_vp
);
1852 return mac_mount_label_get(mp
, uap
->mac_p
);
1856 * mac_schedule_userret()
1858 * Schedule a callback to the mpo_thread_userret hook. The mpo_thread_userret
1859 * hook is called just before the thread exit from the kernel in ast_taken().
1861 * Returns: 0 Success
1865 mac_schedule_userret(void)
1868 act_set_astmacf(current_thread());
1875 * Do a Mach exception. This should only be done in the mpo_thread_userret
1878 * params: code exception code
1879 * subcode exception subcode
1881 * MAC_DOEXCF_TRACED Only do exception if being
1885 * Returns: 0 Success
1889 mac_do_machexc(int64_t code
, int64_t subcode
, uint32_t flags
)
1891 mach_exception_data_type_t codes
[EXCEPTION_CODE_MAX
];
1892 proc_t p
= current_proc();
1894 /* Only allow execption codes in MACF's reserved range. */
1895 if ((code
< EXC_MACF_MIN
) || (code
> EXC_MACF_MAX
))
1898 if (flags
& MAC_DOEXCF_TRACED
&&
1899 !(p
->p_lflag
& P_LTRACED
&& (p
->p_lflag
& P_LPPWAIT
) == 0))
1903 /* Send the Mach exception */
1904 codes
[0] = (mach_exception_data_type_t
)code
;
1905 codes
[1] = (mach_exception_data_type_t
)subcode
;
1907 return (bsd_exception(EXC_SOFTWARE
, codes
, 2) != KERN_SUCCESS
);
1912 void (*load_security_extensions_function
)(void) = 0;
1914 struct sysctl_oid_list sysctl__security_mac_children
;
1917 mac_policy_register(struct mac_policy_conf
*mpc __unused
,
1918 mac_policy_handle_t
*handlep __unused
, void *xd __unused
)
1925 mac_policy_unregister(mac_policy_handle_t handle __unused
)
1932 mac_audit_text(char *text __unused
, mac_policy_handle_t handle __unused
)
1939 mac_vnop_setxattr(struct vnode
*vp __unused
, const char *name __unused
, char *buf __unused
, size_t len __unused
)
1946 mac_vnop_getxattr(struct vnode
*vp __unused
, const char *name __unused
,
1947 char *buf __unused
, size_t len __unused
, size_t *attrlen __unused
)
1954 mac_vnop_removexattr(struct vnode
*vp __unused
, const char *name __unused
)
1960 intptr_t mac_label_get(struct label
*l __unused
, int slot __unused
)
1965 void mac_label_set(struct label
*l __unused
, int slot __unused
, intptr_t v __unused
)
1970 void mac_proc_set_enforce(proc_t p
, int enforce_flags
);
1971 void mac_proc_set_enforce(proc_t p __unused
, int enforce_flags __unused
)
1976 int mac_iokit_check_hid_control(kauth_cred_t cred __unused
);
1977 int mac_iokit_check_hid_control(kauth_cred_t cred __unused
)