2 * Copyright (c) 2007-2020 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>
83 #include <bsd/security/audit/audit_private.h>
85 #include <sys/file_internal.h>
86 #include <sys/filedesc.h>
88 #include <sys/proc_internal.h>
89 #include <sys/kauth.h>
90 #include <sys/sysproto.h>
92 #include <mach/exception_types.h>
93 #include <mach/vm_types.h>
94 #include <mach/vm_prot.h>
96 #include <kern/kalloc.h>
97 #include <kern/sched_prim.h>
98 #include <kern/task.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>
108 #include <libkern/section_keywords.h>
111 * define MB_DEBUG to display run-time debugging information
116 #define DPRINTF(x) printf x
123 SYSCTL_NODE(, OID_AUTO
, security
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0,
124 "Security Controls");
125 SYSCTL_EXTENSIBLE_NODE(_security
, OID_AUTO
, mac
, CTLFLAG_RW
| CTLFLAG_LOCKED
, 0,
126 "TrustedBSD MAC policy controls");
129 * Declare that the kernel provides MAC support, version 1. This permits
130 * modules to refuse to be loaded if the necessary support isn't present,
131 * even if it's pre-boot.
134 MODULE_VERSION(kernel_mac_support
, 1);
137 #if MAC_MAX_SLOTS > 32
138 #error "MAC_MAX_SLOTS too large"
141 static unsigned int mac_max_slots
= MAC_MAX_SLOTS
;
142 static unsigned int mac_slot_offsets_free
= (1 << MAC_MAX_SLOTS
) - 1;
143 SYSCTL_UINT(_security_mac
, OID_AUTO
, max_slots
, CTLFLAG_RD
| CTLFLAG_LOCKED
,
144 &mac_max_slots
, 0, "");
147 * Has the kernel started generating labeled objects yet? All read/write
148 * access to this variable is serialized during the boot process. Following
149 * the end of serialization, we don't update this flag; no locking.
154 * Flag to indicate whether or not we should allocate label storage for
155 * new vnodes. Since most dynamic policies we currently work with don't
156 * rely on vnode labeling, try to avoid paying the cost of mtag allocation
157 * unless specifically notified of interest. One result of this is
158 * that if a dynamically loaded policy requests vnode labels, it must
159 * be able to deal with a NULL label being returned on any vnodes that
160 * were already in flight when the policy was loaded. Since the policy
161 * already has to deal with uninitialized labels, this probably won't
164 #if CONFIG_MACF_LAZY_VNODE_LABELS
165 unsigned int mac_label_vnodes
= 1;
167 unsigned int mac_label_vnodes
= 0;
168 #endif /* CONFIG_MACF_LAZY_VNODE_LABELS */
169 SYSCTL_UINT(_security_mac
, OID_AUTO
, labelvnodes
, SECURITY_MAC_CTLFLAGS
170 #if CONFIG_MACF_LAZY_VNODE_LABELS
173 , &mac_label_vnodes
, 0, "Label all vnodes");
175 unsigned int mac_vnode_label_count
= 0;
176 SYSCTL_UINT(_security_mac
, OID_AUTO
, vnode_label_count
, SECURITY_MAC_CTLFLAGS
| CTLFLAG_RD
,
177 &mac_vnode_label_count
, 0, "Count of vnode labels");
179 unsigned int mac_device_enforce
= 1;
180 SYSCTL_UINT(_security_mac
, OID_AUTO
, device_enforce
, SECURITY_MAC_CTLFLAGS
,
181 &mac_device_enforce
, 0, "Enforce MAC policy on device operations");
183 unsigned int mac_pipe_enforce
= 1;
184 SYSCTL_UINT(_security_mac
, OID_AUTO
, pipe_enforce
, SECURITY_MAC_CTLFLAGS
,
185 &mac_pipe_enforce
, 0, "Enforce MAC policy on pipe operations");
187 unsigned int mac_posixsem_enforce
= 1;
188 SYSCTL_UINT(_security_mac
, OID_AUTO
, posixsem_enforce
, SECURITY_MAC_CTLFLAGS
,
189 &mac_posixsem_enforce
, 0, "Enforce MAC policy on POSIX semaphores");
191 unsigned int mac_posixshm_enforce
= 1;
192 SYSCTL_UINT(_security_mac
, OID_AUTO
, posixshm_enforce
, SECURITY_MAC_CTLFLAGS
,
193 &mac_posixshm_enforce
, 0, "Enforce MAC policy on Posix Shared Memory");
195 unsigned int mac_proc_enforce
= 1;
196 SYSCTL_UINT(_security_mac
, OID_AUTO
, proc_enforce
, SECURITY_MAC_CTLFLAGS
,
197 &mac_proc_enforce
, 0, "Enforce MAC policy on process operations");
199 unsigned int mac_socket_enforce
= 1;
200 SYSCTL_UINT(_security_mac
, OID_AUTO
, socket_enforce
, SECURITY_MAC_CTLFLAGS
,
201 &mac_socket_enforce
, 0, "Enforce MAC policy on socket operations");
203 unsigned int mac_system_enforce
= 1;
204 SYSCTL_UINT(_security_mac
, OID_AUTO
, system_enforce
, SECURITY_MAC_CTLFLAGS
,
205 &mac_system_enforce
, 0, "Enforce MAC policy on system-wide interfaces");
207 unsigned int mac_sysvmsg_enforce
= 1;
208 SYSCTL_UINT(_security_mac
, OID_AUTO
, sysvmsg_enforce
, SECURITY_MAC_CTLFLAGS
,
209 &mac_sysvmsg_enforce
, 0, "Enforce MAC policy on System V IPC message queues");
211 unsigned int mac_sysvsem_enforce
= 1;
212 SYSCTL_UINT(_security_mac
, OID_AUTO
, sysvsem_enforce
, SECURITY_MAC_CTLFLAGS
,
213 &mac_sysvsem_enforce
, 0, "Enforce MAC policy on System V IPC semaphores");
215 unsigned int mac_sysvshm_enforce
= 1;
216 SYSCTL_INT(_security_mac
, OID_AUTO
, sysvshm_enforce
, SECURITY_MAC_CTLFLAGS
,
217 &mac_sysvshm_enforce
, 0, "Enforce MAC policy on System V Shared Memory");
219 unsigned int mac_vm_enforce
= 1;
220 SYSCTL_INT(_security_mac
, OID_AUTO
, vm_enforce
, SECURITY_MAC_CTLFLAGS
,
221 &mac_vm_enforce
, 0, "Enforce MAC policy on VM operations");
223 unsigned int mac_vnode_enforce
= 1;
224 SYSCTL_UINT(_security_mac
, OID_AUTO
, vnode_enforce
, SECURITY_MAC_CTLFLAGS
,
225 &mac_vnode_enforce
, 0, "Enforce MAC policy on vnode operations");
228 * mac_policy_list holds the list of policy modules. Modules with a
229 * handle lower than staticmax are considered "static" and cannot be
230 * unloaded. Such policies can be invoked without holding the busy count.
232 * Modules with a handle at or above the staticmax high water mark
233 * are considered to be "dynamic" policies. A busy count is maintained
234 * for the list, stored in mac_policy_busy. The busy count is protected
235 * by mac_policy_mtx; the list may be modified only while the busy
236 * count is 0, requiring that the lock be held to prevent new references
237 * to the list from being acquired. For almost all operations,
238 * incrementing the busy count is sufficient to guarantee consistency,
239 * as the list cannot be modified while the busy count is elevated.
240 * For a few special operations involving a change to the list of
241 * active policies, the mtx itself must be held.
243 static LCK_GRP_DECLARE(mac_lck_grp
, "MAC lock");
244 static LCK_MTX_DECLARE(mac_policy_mtx
, &mac_lck_grp
);
247 * Policy list array allocation chunk size. Each entry holds a pointer.
249 #define MAC_POLICY_LIST_CHUNKSIZE 8
251 static int mac_policy_busy
;
253 #if !XNU_TARGET_OS_OSX
254 SECURITY_READ_ONLY_LATE(mac_policy_list_t
) mac_policy_list
;
255 SECURITY_READ_ONLY_LATE(static struct mac_policy_list_element
) mac_policy_static_entries
[MAC_POLICY_LIST_CHUNKSIZE
];
257 mac_policy_list_t mac_policy_list
;
261 * mac_label_element_list holds the master list of label namespaces for
262 * all the policies. When a policy is loaded, each of it's label namespace
263 * elements is added to the master list if not already present. When a
264 * policy is unloaded, the namespace elements are removed if no other
265 * policy is interested in that namespace element.
267 struct mac_label_element_list_t mac_label_element_list
;
268 struct mac_label_element_list_t mac_static_label_element_list
;
271 mac_policy_grab_exclusive(void)
273 lck_mtx_lock(&mac_policy_mtx
);
274 while (mac_policy_busy
!= 0) {
275 lck_mtx_sleep(&mac_policy_mtx
, LCK_SLEEP_UNLOCK
,
276 (event_t
)&mac_policy_busy
, THREAD_UNINT
);
277 lck_mtx_lock(&mac_policy_mtx
);
282 mac_policy_release_exclusive(void)
284 KASSERT(mac_policy_busy
== 0,
285 ("mac_policy_release_exclusive(): not exclusive"));
286 lck_mtx_unlock(&mac_policy_mtx
);
287 thread_wakeup((event_t
) &mac_policy_busy
);
291 mac_policy_list_busy(void)
293 lck_mtx_lock(&mac_policy_mtx
);
295 lck_mtx_unlock(&mac_policy_mtx
);
299 mac_policy_list_conditional_busy(void)
303 if (mac_policy_list
.numloaded
<= mac_policy_list
.staticmax
) {
307 lck_mtx_lock(&mac_policy_mtx
);
308 if (mac_policy_list
.numloaded
> mac_policy_list
.staticmax
) {
314 lck_mtx_unlock(&mac_policy_mtx
);
319 mac_policy_list_unbusy(void)
321 lck_mtx_lock(&mac_policy_mtx
);
323 KASSERT(mac_policy_busy
>= 0, ("MAC_POLICY_LIST_LOCK"));
324 if (mac_policy_busy
== 0) {
325 thread_wakeup(&mac_policy_busy
);
327 lck_mtx_unlock(&mac_policy_mtx
);
331 * Early pre-malloc MAC initialization, including appropriate SMP locks.
334 mac_policy_init(void)
336 mac_policy_list
.numloaded
= 0;
337 mac_policy_list
.max
= MAC_POLICY_LIST_CHUNKSIZE
;
338 mac_policy_list
.maxindex
= 0;
339 mac_policy_list
.staticmax
= 0;
340 mac_policy_list
.freehint
= 0;
341 mac_policy_list
.chunks
= 1;
343 #if !XNU_TARGET_OS_OSX
344 mac_policy_list
.entries
= mac_policy_static_entries
;
346 mac_policy_list
.entries
= kalloc_flags(
347 sizeof(struct mac_policy_list_element
) * MAC_POLICY_LIST_CHUNKSIZE
,
351 LIST_INIT(&mac_label_element_list
);
352 LIST_INIT(&mac_static_label_element_list
);
355 /* Function pointer set up for loading security extensions.
356 * It is set to an actual function after OSlibkernInit()
357 * has been called, and is set back to 0 by OSKextRemoveKextBootstrap()
360 void (*load_security_extensions_function
)(void) = 0;
363 * Init after early Mach startup, but before BSD
366 mac_policy_initmach(void)
369 * For the purposes of modules that want to know if they were
370 * loaded "early", set the mac_late flag once we've processed
371 * modules either linked into the kernel, or loaded before the
375 if (load_security_extensions_function
) {
376 load_security_extensions_function();
385 mac_policy_initbsd(void)
387 struct mac_policy_conf
*mpc
;
390 printf("MAC Framework successfully initialized\n");
392 /* Call bsd init functions of already loaded policies */
395 * Using the exclusive lock means no other framework entry
396 * points can proceed while initializations are running.
397 * This may not be necessary.
399 mac_policy_grab_exclusive();
401 for (i
= 0; i
<= mac_policy_list
.maxindex
; i
++) {
402 mpc
= mac_get_mpc(i
);
403 if ((mpc
!= NULL
) && (mpc
->mpc_ops
->mpo_policy_initbsd
!= NULL
)) {
404 (*(mpc
->mpc_ops
->mpo_policy_initbsd
))(mpc
);
408 mac_policy_release_exclusive();
412 * After a policy has been loaded, add the label namespaces managed by the
413 * policy to either the static or non-static label namespace list.
414 * A namespace is added to the the list only if it is not already on one of
418 mac_policy_addto_labellist(mac_policy_handle_t handle
, int static_entry
)
420 struct mac_label_listener
**new_mlls
;
421 struct mac_label_element
*mle
, **new_mles
;
422 struct mac_label_element_list_t
*list
;
423 struct mac_policy_conf
*mpc
;
424 const char *name
, *name2
;
425 u_int idx
, mle_free
, mll_free
;
427 mpc
= mac_get_mpc(handle
);
429 if (mpc
->mpc_labelnames
== NULL
) {
433 if (mpc
->mpc_labelname_count
== 0) {
438 list
= &mac_static_label_element_list
;
440 list
= &mac_label_element_list
;
444 * Before we grab the policy list lock, allocate enough memory
445 * to contain the potential new elements so we don't have to
446 * give up the lock, or allocate with the lock held.
448 MALLOC(new_mles
, struct mac_label_element
**,
449 sizeof(struct mac_label_element
*) *
450 mpc
->mpc_labelname_count
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
451 for (idx
= 0; idx
< mpc
->mpc_labelname_count
; idx
++) {
452 MALLOC(new_mles
[idx
], struct mac_label_element
*,
453 sizeof(struct mac_label_element
),
454 M_MACTEMP
, M_WAITOK
);
457 MALLOC(new_mlls
, struct mac_label_listener
**,
458 sizeof(struct mac_label_listener
*) *
459 mpc
->mpc_labelname_count
, M_MACTEMP
, M_WAITOK
);
460 for (idx
= 0; idx
< mpc
->mpc_labelname_count
; idx
++) {
461 MALLOC(new_mlls
[idx
], struct mac_label_listener
*,
462 sizeof(struct mac_label_listener
), M_MACTEMP
, M_WAITOK
);
467 mac_policy_grab_exclusive();
469 for (idx
= 0; idx
< mpc
->mpc_labelname_count
; idx
++) {
470 if (*(name
= mpc
->mpc_labelnames
[idx
]) == '?') {
474 * Check both label element lists and add to the
475 * appropriate list only if not already on a list.
477 LIST_FOREACH(mle
, &mac_static_label_element_list
, mle_list
) {
478 if (*(name2
= mle
->mle_name
) == '?') {
481 if (strcmp(name
, name2
) == 0) {
486 LIST_FOREACH(mle
, &mac_label_element_list
, mle_list
) {
487 if (*(name2
= mle
->mle_name
) == '?') {
490 if (strcmp(name
, name2
) == 0) {
496 mle
= new_mles
[mle_free
];
497 strlcpy(mle
->mle_name
, mpc
->mpc_labelnames
[idx
],
498 MAC_MAX_LABEL_ELEMENT_NAME
);
499 LIST_INIT(&mle
->mle_listeners
);
500 LIST_INSERT_HEAD(list
, mle
, mle_list
);
503 /* Add policy handler as a listener. */
504 new_mlls
[mll_free
]->mll_handle
= handle
;
505 LIST_INSERT_HEAD(&mle
->mle_listeners
, new_mlls
[mll_free
],
510 mac_policy_release_exclusive();
513 /* Free up any unused label elements and listeners */
514 for (idx
= mle_free
; idx
< mpc
->mpc_labelname_count
; idx
++) {
515 FREE(new_mles
[idx
], M_MACTEMP
);
517 FREE(new_mles
, M_MACTEMP
);
518 for (idx
= mll_free
; idx
< mpc
->mpc_labelname_count
; idx
++) {
519 FREE(new_mlls
[idx
], M_MACTEMP
);
521 FREE(new_mlls
, M_MACTEMP
);
525 * After a policy has been unloaded, remove the label namespaces that the
526 * the policy manages from the non-static list of namespaces.
527 * The removal only takes place when no other policy is interested in the
530 * Must be called with the policy exclusive lock held.
533 mac_policy_removefrom_labellist(mac_policy_handle_t handle
)
535 struct mac_label_listener
*mll
;
536 struct mac_label_element
*mle
;
537 struct mac_policy_conf
*mpc
;
539 mpc
= mac_get_mpc(handle
);
541 if (mpc
->mpc_labelnames
== NULL
) {
545 if (mpc
->mpc_labelname_count
== 0) {
550 * Unregister policy as being interested in any label
551 * namespaces. If no other policy is listening, remove
552 * that label element from the list. Note that we only
553 * have to worry about the non-static list.
555 LIST_FOREACH(mle
, &mac_label_element_list
, mle_list
) {
556 LIST_FOREACH(mll
, &mle
->mle_listeners
, mll_list
) {
557 if (mll
->mll_handle
== handle
) {
558 LIST_REMOVE(mll
, mll_list
);
559 FREE(mll
, M_MACTEMP
);
560 if (LIST_EMPTY(&mle
->mle_listeners
)) {
561 LIST_REMOVE(mle
, mle_list
);
562 FREE(mle
, M_MACTEMP
);
571 * After the policy list has changed, walk the list to update any global
575 mac_policy_updateflags(void)
580 mac_policy_fixup_mmd_list(struct mac_module_data
*new)
582 struct mac_module_data
*old
;
583 struct mac_module_data_element
*ele
, *aele
;
584 struct mac_module_data_list
*arr
, *dict
;
585 unsigned int i
, j
, k
;
587 old
= new->base_addr
;
588 DPRINTF(("fixup_mmd: old %p new %p\n", old
, new));
589 for (i
= 0; i
< new->count
; i
++) {
590 ele
= &(new->data
[i
]);
591 DPRINTF(("fixup_mmd: ele %p\n", ele
));
592 DPRINTF((" key %p value %p\n", ele
->key
, ele
->value
));
593 mmd_fixup_ele(old
, new, ele
); /* Fix up key/value ptrs. */
594 DPRINTF((" key %p value %p\n", ele
->key
, ele
->value
));
595 if (ele
->value_type
== MAC_DATA_TYPE_ARRAY
) {
596 arr
= (struct mac_module_data_list
*)ele
->value
;
597 DPRINTF(("fixup_mmd: array @%p\n", arr
));
598 for (j
= 0; j
< arr
->count
; j
++) {
599 aele
= &(arr
->list
[j
]);
600 DPRINTF(("fixup_mmd: aele %p\n", aele
));
601 DPRINTF((" key %p value %p\n", aele
->key
, aele
->value
));
602 mmd_fixup_ele(old
, new, aele
);
603 DPRINTF((" key %p value %p\n", aele
->key
, aele
->value
));
604 if (arr
->type
== MAC_DATA_TYPE_DICT
) {
605 dict
= (struct mac_module_data_list
*)aele
->value
;
606 DPRINTF(("fixup_mmd: dict @%p\n", dict
));
607 for (k
= 0; k
< dict
->count
; k
++) {
608 mmd_fixup_ele(old
, new,
615 new->base_addr
= new;
619 mac_policy_register(struct mac_policy_conf
*mpc
, mac_policy_handle_t
*handlep
,
622 #if XNU_TARGET_OS_OSX
623 struct mac_policy_list_element
*tmac_policy_list_element
;
625 int error
, slot
, static_entry
= 0;
629 * Some preliminary checks to make sure the policy's conf structure
630 * contains the required fields.
632 if (mpc
->mpc_name
== NULL
) {
633 panic("policy's name is not set\n");
636 if (mpc
->mpc_fullname
== NULL
) {
637 panic("policy's full name is not set\n");
640 if (mpc
->mpc_labelname_count
> MAC_MAX_MANAGED_NAMESPACES
) {
641 panic("policy's managed label namespaces exceeds maximum\n");
644 if (mpc
->mpc_ops
== NULL
) {
645 panic("policy's OPs field is NULL\n");
651 if (mpc
->mpc_loadtime_flags
& MPC_LOADTIME_FLAG_NOTLATE
) {
652 printf("Module %s does not support late loading.\n",
656 mac_policy_grab_exclusive();
659 if (mac_policy_list
.numloaded
>= mac_policy_list
.max
) {
660 #if XNU_TARGET_OS_OSX
661 /* allocate new policy list array, zero new chunk */
662 tmac_policy_list_element
=
663 kalloc((sizeof(struct mac_policy_list_element
) *
664 MAC_POLICY_LIST_CHUNKSIZE
) * (mac_policy_list
.chunks
+ 1));
665 bzero(&tmac_policy_list_element
[mac_policy_list
.max
],
666 sizeof(struct mac_policy_list_element
) *
667 MAC_POLICY_LIST_CHUNKSIZE
);
669 /* copy old entries into new list */
670 memcpy(tmac_policy_list_element
, mac_policy_list
.entries
,
671 sizeof(struct mac_policy_list_element
) *
672 MAC_POLICY_LIST_CHUNKSIZE
* mac_policy_list
.chunks
);
675 kfree(mac_policy_list
.entries
,
676 sizeof(struct mac_policy_list_element
) *
677 MAC_POLICY_LIST_CHUNKSIZE
* mac_policy_list
.chunks
);
679 mac_policy_list
.entries
= tmac_policy_list_element
;
681 /* Update maximums, etc */
682 mac_policy_list
.max
+= MAC_POLICY_LIST_CHUNKSIZE
;
683 mac_policy_list
.chunks
++;
685 printf("out of space in mac_policy_list.\n");
687 #endif /* XNU_TARGET_OS_OSX */
690 /* Check for policy with same name already loaded */
691 for (i
= 0; i
<= mac_policy_list
.maxindex
; i
++) {
692 if (mac_policy_list
.entries
[i
].mpc
== NULL
) {
696 if (strcmp(mac_policy_list
.entries
[i
].mpc
->mpc_name
,
697 mpc
->mpc_name
) == 0) {
703 if (mpc
->mpc_field_off
!= NULL
) {
704 slot
= ffs(mac_slot_offsets_free
);
710 mac_slot_offsets_free
&= ~(1 << slot
);
711 *mpc
->mpc_field_off
= slot
;
713 mpc
->mpc_runtime_flags
|= MPC_RUNTIME_FLAG_REGISTERED
;
716 struct mac_module_data
*mmd
= xd
; /* module data from plist */
718 /* Make a copy of the data. */
719 mpc
->mpc_data
= (void *)kalloc(mmd
->size
);
720 if (mpc
->mpc_data
!= NULL
) {
721 memcpy(mpc
->mpc_data
, mmd
, mmd
->size
);
723 /* Fix up pointers after copy. */
724 mac_policy_fixup_mmd_list(mpc
->mpc_data
);
728 /* Find the first free handle in the list (using our hint). */
729 for (i
= mac_policy_list
.freehint
; i
< mac_policy_list
.max
; i
++) {
730 if (mac_policy_list
.entries
[i
].mpc
== NULL
) {
732 mac_policy_list
.freehint
= ++i
;
738 * If we are loading a MAC module before the framework has
739 * finished initializing or the module is not unloadable and
740 * we can place its handle adjacent to the last static entry,
741 * bump the static policy high water mark.
742 * Static policies can get by with weaker locking requirements.
745 ((mpc
->mpc_loadtime_flags
& MPC_LOADTIME_FLAG_UNLOADOK
) == 0 &&
746 *handlep
== mac_policy_list
.staticmax
)) {
748 mac_policy_list
.staticmax
++;
751 mac_policy_list
.entries
[*handlep
].mpc
= mpc
;
753 /* Update counters, etc */
754 if (*handlep
> mac_policy_list
.maxindex
) {
755 mac_policy_list
.maxindex
= *handlep
;
757 mac_policy_list
.numloaded
++;
759 /* Per-policy initialization. */
760 printf("calling mpo_policy_init for %s\n", mpc
->mpc_name
);
761 if (mpc
->mpc_ops
->mpo_policy_init
!= NULL
) {
762 (*(mpc
->mpc_ops
->mpo_policy_init
))(mpc
);
765 if (mac_late
&& mpc
->mpc_ops
->mpo_policy_initbsd
!= NULL
) {
766 printf("calling mpo_policy_initbsd for %s\n", mpc
->mpc_name
);
767 (*(mpc
->mpc_ops
->mpo_policy_initbsd
))(mpc
);
770 mac_policy_updateflags();
773 mac_policy_release_exclusive();
776 mac_policy_addto_labellist(*handlep
, static_entry
);
778 printf("Security policy loaded: %s (%s)\n", mpc
->mpc_fullname
,
785 mac_policy_release_exclusive();
792 mac_policy_unregister(mac_policy_handle_t handle
)
794 struct mac_policy_conf
*mpc
;
797 * If we fail the load, we may get a request to unload. Check
798 * to see if we did the run-time registration, and if not,
801 mac_policy_grab_exclusive();
802 mpc
= mac_get_mpc(handle
);
803 if ((mpc
->mpc_runtime_flags
& MPC_RUNTIME_FLAG_REGISTERED
) == 0) {
804 mac_policy_release_exclusive();
810 * Don't allow unloading modules with private data.
812 if (mpc
->mpc_field_off
!= NULL
) {
813 MAC_POLICY_LIST_UNLOCK();
818 * Only allow the unload to proceed if the module is unloadable
819 * by its own definition.
821 if ((mpc
->mpc_loadtime_flags
& MPC_LOADTIME_FLAG_UNLOADOK
) == 0) {
822 mac_policy_release_exclusive();
826 mac_policy_removefrom_labellist(handle
);
828 mac_get_mpc(handle
) = NULL
;
829 if (handle
< mac_policy_list
.freehint
&&
830 handle
>= mac_policy_list
.staticmax
) {
831 mac_policy_list
.freehint
= handle
;
834 if (handle
== mac_policy_list
.maxindex
) {
835 mac_policy_list
.maxindex
--;
838 mac_policy_list
.numloaded
--;
839 if (mpc
->mpc_field_off
!= NULL
) {
840 mac_slot_offsets_free
|= (1 << *mpc
->mpc_field_off
);
843 if (mpc
->mpc_ops
->mpo_policy_destroy
!= NULL
) {
844 (*(mpc
->mpc_ops
->mpo_policy_destroy
))(mpc
);
847 mpc
->mpc_runtime_flags
&= ~MPC_RUNTIME_FLAG_REGISTERED
;
848 mac_policy_updateflags();
850 mac_policy_release_exclusive();
853 struct mac_module_data
*mmd
= mpc
->mpc_data
;
854 kfree(mmd
, mmd
->size
);
855 mpc
->mpc_data
= NULL
;
858 printf("Security policy unload: %s (%s)\n", mpc
->mpc_fullname
,
865 * Define an error value precedence, and given two arguments, selects the
866 * value with the higher precedence.
869 mac_error_select(int error1
, int error2
)
871 /* Certain decision-making errors take top priority. */
872 if (error1
== EDEADLK
|| error2
== EDEADLK
) {
876 /* Invalid arguments should be reported where possible. */
877 if (error1
== EINVAL
|| error2
== EINVAL
) {
881 /* Precedence goes to "visibility", with both process and file. */
882 if (error1
== ESRCH
|| error2
== ESRCH
) {
886 if (error1
== ENOENT
|| error2
== ENOENT
) {
890 /* Precedence goes to DAC/MAC protections. */
891 if (error1
== EACCES
|| error2
== EACCES
) {
895 /* Precedence goes to privilege. */
896 if (error1
== EPERM
|| error2
== EPERM
) {
900 /* Precedence goes to error over success; otherwise, arbitrary. */
908 mac_label_init(struct label
*label
)
910 bzero(label
, sizeof(*label
));
911 label
->l_flags
= MAC_FLAG_INITIALIZED
;
915 mac_label_destroy(struct label
*label
)
917 KASSERT(label
->l_flags
& MAC_FLAG_INITIALIZED
,
918 ("destroying uninitialized label"));
920 bzero(label
, sizeof(*label
));
921 /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
925 mac_check_structmac_consistent(struct user_mac
*mac
)
927 if (mac
->m_buflen
> MAC_MAX_LABEL_BUF_LEN
|| mac
->m_buflen
== 0) {
935 * Get the external forms of labels from all policies, for a single
936 * label namespace or "*" for all namespaces. Returns ENOENT if no policy
937 * is registered for the namespace, unless the namespace begins with a '?'.
940 mac_label_externalize(size_t mpo_externalize_off
, struct label
*label
,
941 const char *element
, struct sbuf
*sb
)
943 struct mac_policy_conf
*mpc
;
944 struct mac_label_listener
*mll
;
945 struct mac_label_element
*mle
;
946 struct mac_label_element_list_t
*element_list
;
948 int (*mpo_externalize
)(struct label
*, char *, struct sbuf
*);
949 int all_labels
= 0, ignorenotfound
= 0, error
= 0, busy
= FALSE
;
951 unsigned int count
= 0;
953 if (element
[0] == '?') {
956 } else if (element
[0] == '*' && element
[1] == '\0') {
960 element_list
= &mac_static_label_element_list
;
962 LIST_FOREACH(mle
, element_list
, mle_list
) {
963 name
= mle
->mle_name
;
972 if (strcmp(name
, element
) != 0) {
976 LIST_FOREACH(mll
, &mle
->mle_listeners
, mll_list
) {
977 mpc
= mac_policy_list
.entries
[mll
->mll_handle
].mpc
;
981 mpo_externalize
= *(const typeof(mpo_externalize
) *)
982 ((const char *)mpc
->mpc_ops
+ mpo_externalize_off
);
983 if (mpo_externalize
== NULL
) {
986 sb_pos
= sbuf_len(sb
);
987 error
= sbuf_printf(sb
, "%s/", name
);
991 error
= mpo_externalize(label
, mle
->mle_name
, sb
);
993 if (error
!= ENOENT
) {
997 * If a policy doesn't have a label to
998 * externalize it returns ENOENT. This
999 * may occur for policies that support
1000 * multiple label elements for some
1001 * (but not all) object types.
1003 sbuf_setpos(sb
, sb_pos
);
1007 error
= sbuf_putc(sb
, ',');
1014 /* If there are dynamic policies present, check their elements too. */
1015 if (!busy
&& mac_policy_list_conditional_busy() == 1) {
1016 element_list
= &mac_label_element_list
;
1022 mac_policy_list_unbusy();
1024 if (!error
&& count
== 0) {
1025 if (!all_labels
&& !ignorenotfound
) {
1026 error
= ENOENT
; /* XXX: ENOLABEL? */
1033 * Get the external forms of labels from all policies, for all label
1034 * namespaces contained in a list.
1036 * XXX This may be leaking an sbuf.
1039 mac_externalize(size_t mpo_externalize_off
, struct label
*label
,
1040 const char *elementlist
, char *outbuf
, size_t outbuflen
)
1048 /* allocate a scratch buffer the size of the string */
1049 MALLOC(scratch_base
, char *, strlen(elementlist
) + 1, M_MACTEMP
, M_WAITOK
);
1050 if (scratch_base
== NULL
) {
1055 /* copy the elementlist to the scratch buffer */
1056 strlcpy(scratch_base
, elementlist
, strlen(elementlist
) + 1);
1059 * set up a temporary pointer that can be used to iterate the
1060 * scratch buffer without losing the allocation address
1062 scratch
= scratch_base
;
1065 * initialize an sbuf mapping over the output buffer (or newly-allocated internal buffer, if
1066 * outbuf is NULL), up to sbuf's limit of INT_MAX.
1068 if (outbuflen
> INT_MAX
) {
1069 outbuflen
= INT_MAX
;
1071 if (sbuf_new(&sb
, outbuf
, (int)outbuflen
, SBUF_FIXEDLEN
) == NULL
) {
1072 /* could not allocate interior buffer */
1076 /* iterate the scratch buffer; NOTE: buffer contents modified! */
1077 while ((element
= strsep(&scratch
, ",")) != NULL
) {
1078 error
= mac_label_externalize(mpo_externalize_off
, label
,
1084 if ((len
= sbuf_len(&sb
)) > 0) {
1085 sbuf_setpos(&sb
, len
- 1); /* trim trailing comma */
1090 if (scratch_base
!= NULL
) {
1091 FREE(scratch_base
, M_MACTEMP
);
1098 * Have all policies set the internal form of a label, for a single
1102 mac_label_internalize(size_t mpo_internalize_off
, struct label
*label
,
1103 char *element_name
, char *element_data
)
1105 struct mac_policy_conf
*mpc
;
1106 struct mac_label_listener
*mll
;
1107 struct mac_label_element
*mle
;
1108 struct mac_label_element_list_t
*element_list
;
1109 int (*mpo_internalize
)(struct label
*, char *, char *);
1110 int error
= 0, busy
= FALSE
;
1111 unsigned int count
= 0;
1114 element_list
= &mac_static_label_element_list
;
1116 LIST_FOREACH(mle
, element_list
, mle_list
) {
1117 if (*(name
= mle
->mle_name
) == '?') {
1120 if (strcmp(element_name
, name
) != 0) {
1123 LIST_FOREACH(mll
, &mle
->mle_listeners
, mll_list
) {
1124 mpc
= mac_policy_list
.entries
[mll
->mll_handle
].mpc
;
1128 mpo_internalize
= *(const typeof(mpo_internalize
) *)
1129 ((const char *)mpc
->mpc_ops
+ mpo_internalize_off
);
1130 if (mpo_internalize
== NULL
) {
1133 error
= mpo_internalize(label
, element_name
,
1141 /* If there are dynamic policies present, check their elements too. */
1142 if (!busy
&& mac_policy_list_conditional_busy() == 1) {
1143 element_list
= &mac_label_element_list
;
1149 mac_policy_list_unbusy();
1151 if (!error
&& count
== 0) {
1158 mac_internalize(size_t mpo_internalize_off
, struct label
*label
,
1161 char *element_name
, *element_data
;
1164 while (!error
&& (element_name
= strsep(&textlabels
, ",")) != NULL
) {
1165 element_data
= strchr(element_name
, '/');
1166 if (element_data
== NULL
) {
1170 *element_data
++ = '\0';
1171 error
= mac_label_internalize(mpo_internalize_off
, label
,
1172 element_name
, element_data
);
1180 __mac_get_pid(struct proc
*p
, struct __mac_get_pid_args
*uap
, int *ret __unused
)
1182 char *elements
, *buffer
;
1183 struct user_mac mac
;
1185 struct ucred
*tcred
;
1189 AUDIT_ARG(pid
, uap
->pid
);
1190 if (IS_64BIT_PROCESS(p
)) {
1191 struct user64_mac mac64
;
1192 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1193 mac
.m_buflen
= mac64
.m_buflen
;
1194 mac
.m_string
= mac64
.m_string
;
1196 struct user32_mac mac32
;
1197 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1198 mac
.m_buflen
= mac32
.m_buflen
;
1199 mac
.m_string
= mac32
.m_string
;
1205 error
= mac_check_structmac_consistent(&mac
);
1210 tproc
= proc_find(uap
->pid
);
1211 if (tproc
== NULL
) {
1214 tcred
= kauth_cred_proc_ref(tproc
);
1217 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1218 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1220 FREE(elements
, M_MACTEMP
);
1221 kauth_cred_unref(&tcred
);
1224 AUDIT_ARG(mac_string
, elements
);
1226 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
1227 error
= mac_cred_label_externalize(tcred
->cr_label
, elements
,
1228 buffer
, mac
.m_buflen
, M_WAITOK
);
1230 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
) + 1);
1233 FREE(buffer
, M_MACTEMP
);
1234 FREE(elements
, M_MACTEMP
);
1235 kauth_cred_unref(&tcred
);
1240 __mac_get_proc(proc_t p
, struct __mac_get_proc_args
*uap
, int *ret __unused
)
1242 char *elements
, *buffer
;
1243 struct user_mac mac
;
1248 if (IS_64BIT_PROCESS(p
)) {
1249 struct user64_mac mac64
;
1250 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1251 mac
.m_buflen
= mac64
.m_buflen
;
1252 mac
.m_string
= mac64
.m_string
;
1254 struct user32_mac mac32
;
1255 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1256 mac
.m_buflen
= mac32
.m_buflen
;
1257 mac
.m_string
= mac32
.m_string
;
1263 error
= mac_check_structmac_consistent(&mac
);
1268 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1269 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1271 FREE(elements
, M_MACTEMP
);
1274 AUDIT_ARG(mac_string
, elements
);
1276 cr
= kauth_cred_proc_ref(p
);
1278 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
1279 error
= mac_cred_label_externalize(cr
->cr_label
,
1280 elements
, buffer
, mac
.m_buflen
, M_WAITOK
);
1282 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
) + 1);
1285 FREE(buffer
, M_MACTEMP
);
1286 FREE(elements
, M_MACTEMP
);
1287 kauth_cred_unref(&cr
);
1292 __mac_set_proc(proc_t p
, struct __mac_set_proc_args
*uap
, int *ret __unused
)
1294 struct label
*intlabel
;
1295 struct user_mac mac
;
1300 if (IS_64BIT_PROCESS(p
)) {
1301 struct user64_mac mac64
;
1302 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1303 mac
.m_buflen
= mac64
.m_buflen
;
1304 mac
.m_string
= mac64
.m_string
;
1306 struct user32_mac mac32
;
1307 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1308 mac
.m_buflen
= mac32
.m_buflen
;
1309 mac
.m_string
= mac32
.m_string
;
1315 error
= mac_check_structmac_consistent(&mac
);
1320 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1321 error
= copyinstr(mac
.m_string
, buffer
, mac
.m_buflen
, &ulen
);
1323 FREE(buffer
, M_MACTEMP
);
1326 AUDIT_ARG(mac_string
, buffer
);
1328 intlabel
= mac_cred_label_alloc();
1329 error
= mac_cred_label_internalize(intlabel
, buffer
);
1330 FREE(buffer
, M_MACTEMP
);
1335 error
= mac_cred_check_label_update(kauth_cred_get(), intlabel
);
1340 error
= kauth_proc_label_update(p
, intlabel
);
1346 mac_cred_label_free(intlabel
);
1351 __mac_get_fd(proc_t p
, struct __mac_get_fd_args
*uap
, int *ret __unused
)
1353 struct fileproc
*fp
;
1355 struct user_mac mac
;
1356 char *elements
, *buffer
;
1359 kauth_cred_t my_cred
;
1360 struct label
*intlabel
;
1362 AUDIT_ARG(fd
, uap
->fd
);
1364 if (IS_64BIT_PROCESS(p
)) {
1365 struct user64_mac mac64
;
1366 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1367 mac
.m_buflen
= mac64
.m_buflen
;
1368 mac
.m_string
= mac64
.m_string
;
1370 struct user32_mac mac32
;
1371 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1372 mac
.m_buflen
= mac32
.m_buflen
;
1373 mac
.m_string
= mac32
.m_string
;
1380 error
= mac_check_structmac_consistent(&mac
);
1385 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1386 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1388 FREE(elements
, M_MACTEMP
);
1391 AUDIT_ARG(mac_string
, elements
);
1393 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1394 error
= fp_lookup(p
, uap
->fd
, &fp
, 0);
1396 FREE(buffer
, M_MACTEMP
);
1397 FREE(elements
, M_MACTEMP
);
1401 my_cred
= kauth_cred_proc_ref(p
);
1402 error
= mac_file_check_get(my_cred
, fp
->fp_glob
, elements
, mac
.m_buflen
);
1403 kauth_cred_unref(&my_cred
);
1405 fp_drop(p
, uap
->fd
, fp
, 0);
1406 FREE(buffer
, M_MACTEMP
);
1407 FREE(elements
, M_MACTEMP
);
1411 switch (FILEGLOB_DTYPE(fp
->fp_glob
)) {
1413 intlabel
= mac_vnode_label_alloc();
1414 if (intlabel
== NULL
) {
1418 vp
= (struct vnode
*)fp
->fp_glob
->fg_data
;
1419 error
= vnode_getwithref(vp
);
1421 mac_vnode_label_copy(vp
->v_label
, intlabel
);
1422 error
= mac_vnode_label_externalize(intlabel
,
1424 mac
.m_buflen
, M_WAITOK
);
1427 mac_vnode_label_free(intlabel
);
1434 case DTYPE_FSEVENTS
:
1436 case DTYPE_NETPOLICY
:
1438 error
= ENOSYS
; // only sockets/vnodes so far
1441 fp_drop(p
, uap
->fd
, fp
, 0);
1444 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
) + 1);
1447 FREE(buffer
, M_MACTEMP
);
1448 FREE(elements
, M_MACTEMP
);
1453 mac_get_filelink(proc_t p
, user_addr_t mac_p
, user_addr_t path_p
, int follow
)
1457 char *elements
, *buffer
;
1458 struct nameidata nd
;
1459 struct label
*intlabel
;
1460 struct user_mac mac
;
1464 if (IS_64BIT_PROCESS(p
)) {
1465 struct user64_mac mac64
;
1466 error
= copyin(mac_p
, &mac64
, sizeof(mac64
));
1467 mac
.m_buflen
= mac64
.m_buflen
;
1468 mac
.m_string
= mac64
.m_string
;
1470 struct user32_mac mac32
;
1471 error
= copyin(mac_p
, &mac32
, sizeof(mac32
));
1472 mac
.m_buflen
= mac32
.m_buflen
;
1473 mac
.m_string
= mac32
.m_string
;
1480 error
= mac_check_structmac_consistent(&mac
);
1485 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1486 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
1488 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1490 FREE(buffer
, M_MACTEMP
);
1491 FREE(elements
, M_MACTEMP
);
1494 AUDIT_ARG(mac_string
, elements
);
1496 ctx
= vfs_context_current();
1498 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
,
1499 LOCKLEAF
| (follow
? FOLLOW
: NOFOLLOW
) | AUDITVNPATH1
,
1500 UIO_USERSPACE
, path_p
, ctx
);
1503 FREE(buffer
, M_MACTEMP
);
1504 FREE(elements
, M_MACTEMP
);
1511 intlabel
= mac_vnode_label_alloc();
1512 mac_vnode_label_copy(vp
->v_label
, intlabel
);
1513 error
= mac_vnode_label_externalize(intlabel
, elements
, buffer
,
1514 mac
.m_buflen
, M_WAITOK
);
1515 mac_vnode_label_free(intlabel
);
1517 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
) + 1);
1522 FREE(buffer
, M_MACTEMP
);
1523 FREE(elements
, M_MACTEMP
);
1529 __mac_get_file(proc_t p
, struct __mac_get_file_args
*uap
,
1532 return mac_get_filelink(p
, uap
->mac_p
, uap
->path_p
, 1);
1536 __mac_get_link(proc_t p
, struct __mac_get_link_args
*uap
,
1539 return mac_get_filelink(p
, uap
->mac_p
, uap
->path_p
, 0);
1543 __mac_set_fd(proc_t p
, struct __mac_set_fd_args
*uap
, int *ret __unused
)
1545 struct fileproc
*fp
;
1546 struct user_mac mac
;
1547 struct vfs_context
*ctx
= vfs_context_current();
1551 struct label
*intlabel
;
1554 AUDIT_ARG(fd
, uap
->fd
);
1556 if (IS_64BIT_PROCESS(p
)) {
1557 struct user64_mac mac64
;
1558 error
= copyin(uap
->mac_p
, &mac64
, sizeof(mac64
));
1559 mac
.m_buflen
= mac64
.m_buflen
;
1560 mac
.m_string
= mac64
.m_string
;
1562 struct user32_mac mac32
;
1563 error
= copyin(uap
->mac_p
, &mac32
, sizeof(mac32
));
1564 mac
.m_buflen
= mac32
.m_buflen
;
1565 mac
.m_string
= mac32
.m_string
;
1571 error
= mac_check_structmac_consistent(&mac
);
1576 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1577 error
= copyinstr(mac
.m_string
, buffer
, mac
.m_buflen
, &ulen
);
1579 FREE(buffer
, M_MACTEMP
);
1582 AUDIT_ARG(mac_string
, buffer
);
1584 error
= fp_lookup(p
, uap
->fd
, &fp
, 0);
1586 FREE(buffer
, M_MACTEMP
);
1591 error
= mac_file_check_set(vfs_context_ucred(ctx
), fp
->fp_glob
, buffer
, mac
.m_buflen
);
1593 fp_drop(p
, uap
->fd
, fp
, 0);
1594 FREE(buffer
, M_MACTEMP
);
1598 switch (FILEGLOB_DTYPE(fp
->fp_glob
)) {
1600 if (mac_label_vnodes
== 0) {
1605 intlabel
= mac_vnode_label_alloc();
1607 error
= mac_vnode_label_internalize(intlabel
, buffer
);
1609 mac_vnode_label_free(intlabel
);
1614 vp
= (struct vnode
*)fp
->fp_glob
->fg_data
;
1616 error
= vnode_getwithref(vp
);
1618 error
= vn_setlabel(vp
, intlabel
, ctx
);
1621 mac_vnode_label_free(intlabel
);
1629 case DTYPE_FSEVENTS
:
1631 case DTYPE_NETPOLICY
:
1633 error
= ENOSYS
; // only sockets/vnodes so far
1637 fp_drop(p
, uap
->fd
, fp
, 0);
1638 FREE(buffer
, M_MACTEMP
);
1643 mac_set_filelink(proc_t p
, user_addr_t mac_p
, user_addr_t path_p
,
1647 struct vfs_context
*ctx
= vfs_context_current();
1648 struct label
*intlabel
;
1649 struct nameidata nd
;
1650 struct user_mac mac
;
1655 if (mac_label_vnodes
== 0) {
1659 if (IS_64BIT_PROCESS(p
)) {
1660 struct user64_mac mac64
;
1661 error
= copyin(mac_p
, &mac64
, sizeof(mac64
));
1662 mac
.m_buflen
= mac64
.m_buflen
;
1663 mac
.m_string
= mac64
.m_string
;
1665 struct user32_mac mac32
;
1666 error
= copyin(mac_p
, &mac32
, sizeof(mac32
));
1667 mac
.m_buflen
= mac32
.m_buflen
;
1668 mac
.m_string
= mac32
.m_string
;
1674 error
= mac_check_structmac_consistent(&mac
);
1676 printf("mac_set_file: failed structure consistency check\n");
1680 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1681 error
= copyinstr(mac
.m_string
, buffer
, mac
.m_buflen
, &ulen
);
1683 FREE(buffer
, M_MACTEMP
);
1686 AUDIT_ARG(mac_string
, buffer
);
1688 intlabel
= mac_vnode_label_alloc();
1689 error
= mac_vnode_label_internalize(intlabel
, buffer
);
1690 FREE(buffer
, M_MACTEMP
);
1692 mac_vnode_label_free(intlabel
);
1696 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
,
1697 LOCKLEAF
| (follow
? FOLLOW
: NOFOLLOW
) | AUDITVNPATH1
,
1698 UIO_USERSPACE
, path_p
, ctx
);
1701 mac_vnode_label_free(intlabel
);
1708 error
= vn_setlabel(vp
, intlabel
, ctx
);
1710 mac_vnode_label_free(intlabel
);
1716 __mac_set_file(proc_t p
, struct __mac_set_file_args
*uap
,
1719 return mac_set_filelink(p
, uap
->mac_p
, uap
->path_p
, 1);
1723 __mac_set_link(proc_t p
, struct __mac_set_link_args
*uap
,
1726 return mac_set_filelink(p
, uap
->mac_p
, uap
->path_p
, 0);
1730 * __mac_syscall: Perform a MAC policy system call
1732 * Parameters: p Process calling this routine
1733 * uap User argument descriptor (see below)
1736 * Indirect: uap->policy Name of target MAC policy
1737 * uap->call MAC policy-specific system call to perform
1738 * uap->arg MAC policy-specific system call arguments
1740 * Returns: 0 Success
1745 __mac_syscall(proc_t p
, struct __mac_syscall_args
*uap
, int *retv __unused
)
1747 struct mac_policy_conf
*mpc
;
1748 char target
[MAC_MAX_POLICY_NAME
];
1753 error
= copyinstr(uap
->policy
, target
, sizeof(target
), &ulen
);
1757 AUDIT_ARG(value32
, uap
->call
);
1758 AUDIT_ARG(mac_string
, target
);
1762 for (i
= 0; i
< mac_policy_list
.staticmax
; i
++) {
1763 mpc
= mac_policy_list
.entries
[i
].mpc
;
1768 if (strcmp(mpc
->mpc_name
, target
) == 0 &&
1769 mpc
->mpc_ops
->mpo_policy_syscall
!= NULL
) {
1770 error
= mpc
->mpc_ops
->mpo_policy_syscall(p
,
1771 uap
->call
, uap
->arg
);
1775 if (mac_policy_list_conditional_busy() != 0) {
1776 for (; i
<= mac_policy_list
.maxindex
; i
++) {
1777 mpc
= mac_policy_list
.entries
[i
].mpc
;
1782 if (strcmp(mpc
->mpc_name
, target
) == 0 &&
1783 mpc
->mpc_ops
->mpo_policy_syscall
!= NULL
) {
1784 error
= mpc
->mpc_ops
->mpo_policy_syscall(p
,
1785 uap
->call
, uap
->arg
);
1789 mac_policy_list_unbusy();
1797 mac_mount_label_get(struct mount
*mp
, user_addr_t mac_p
)
1799 char *elements
, *buffer
;
1800 struct label
*label
;
1801 struct user_mac mac
;
1805 if (IS_64BIT_PROCESS(current_proc())) {
1806 struct user64_mac mac64
;
1807 error
= copyin(mac_p
, &mac64
, sizeof(mac64
));
1808 mac
.m_buflen
= mac64
.m_buflen
;
1809 mac
.m_string
= mac64
.m_string
;
1811 struct user32_mac mac32
;
1812 error
= copyin(mac_p
, &mac32
, sizeof(mac32
));
1813 mac
.m_buflen
= mac32
.m_buflen
;
1814 mac
.m_string
= mac32
.m_string
;
1820 error
= mac_check_structmac_consistent(&mac
);
1825 MALLOC(elements
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
);
1826 error
= copyinstr(mac
.m_string
, elements
, mac
.m_buflen
, &ulen
);
1828 FREE(elements
, M_MACTEMP
);
1831 AUDIT_ARG(mac_string
, elements
);
1833 label
= mp
->mnt_mntlabel
;
1834 MALLOC(buffer
, char *, mac
.m_buflen
, M_MACTEMP
, M_WAITOK
| M_ZERO
);
1835 error
= mac_mount_label_externalize(label
, elements
, buffer
,
1837 FREE(elements
, M_MACTEMP
);
1840 error
= copyout(buffer
, mac
.m_string
, strlen(buffer
) + 1);
1842 FREE(buffer
, M_MACTEMP
);
1848 * __mac_get_mount: Get mount point label information for a given pathname
1850 * Parameters: p (ignored)
1851 * uap User argument descriptor (see below)
1854 * Indirect: uap->path Pathname
1855 * uap->mac_p MAC info
1857 * Returns: 0 Success
1861 __mac_get_mount(proc_t p __unused
, struct __mac_get_mount_args
*uap
,
1864 struct nameidata nd
;
1865 struct vfs_context
*ctx
= vfs_context_current();
1869 NDINIT(&nd
, LOOKUP
, OP_LOOKUP
, FOLLOW
| AUDITVNPATH1
,
1870 UIO_USERSPACE
, uap
->path
, ctx
);
1875 mp
= nd
.ni_vp
->v_mount
;
1877 vnode_put(nd
.ni_vp
);
1880 error
= mac_mount_label_get(mp
, uap
->mac_p
);
1886 * mac_schedule_userret()
1888 * Schedule a callback to the mpo_thread_userret hook. The mpo_thread_userret
1889 * hook is called just before the thread exit from the kernel in ast_taken().
1891 * Returns: 0 Success
1895 mac_schedule_userret(void)
1897 act_set_astmacf(current_thread());
1904 * Do a Mach exception. This should only be done in the mpo_thread_userret
1907 * params: code exception code
1908 * subcode exception subcode
1910 * MAC_DOEXCF_TRACED Only do exception if being
1914 * Returns: 0 Success
1918 mac_do_machexc(int64_t code
, int64_t subcode
, uint32_t flags
)
1920 mach_exception_data_type_t codes
[EXCEPTION_CODE_MAX
];
1921 proc_t p
= current_proc();
1923 /* Only allow execption codes in MACF's reserved range. */
1924 if ((code
< EXC_MACF_MIN
) || (code
> EXC_MACF_MAX
)) {
1928 if (flags
& MAC_DOEXCF_TRACED
&&
1929 !(p
->p_lflag
& P_LTRACED
&& (p
->p_lflag
& P_LPPWAIT
) == 0)) {
1934 /* Send the Mach exception */
1935 codes
[0] = (mach_exception_data_type_t
)code
;
1936 codes
[1] = (mach_exception_data_type_t
)subcode
;
1938 return bsd_exception(EXC_SOFTWARE
, codes
, 2) != KERN_SUCCESS
;
1943 void (*load_security_extensions_function
)(void) = 0;
1945 struct sysctl_oid_list sysctl__security_mac_children
;
1948 mac_policy_register(struct mac_policy_conf
*mpc __unused
,
1949 mac_policy_handle_t
*handlep __unused
, void *xd __unused
)
1955 mac_policy_unregister(mac_policy_handle_t handle __unused
)
1961 mac_audit_text(char *text __unused
, mac_policy_handle_t handle __unused
)
1967 mac_vnop_setxattr(struct vnode
*vp __unused
, const char *name __unused
, char *buf __unused
, size_t len __unused
)
1973 mac_vnop_getxattr(struct vnode
*vp __unused
, const char *name __unused
,
1974 char *buf __unused
, size_t len __unused
, size_t *attrlen __unused
)
1980 mac_vnop_removexattr(struct vnode
*vp __unused
, const char *name __unused
)
1986 mac_file_setxattr(struct fileglob
*fg __unused
, const char *name __unused
, char *buf __unused
, size_t len __unused
)
1992 mac_file_getxattr(struct fileglob
*fg __unused
, const char *name __unused
,
1993 char *buf __unused
, size_t len __unused
, size_t *attrlen __unused
)
1999 mac_file_removexattr(struct fileglob
*fg __unused
, const char *name __unused
)
2005 mac_label_get(struct label
*l __unused
, int slot __unused
)
2011 mac_label_set(struct label
*l __unused
, int slot __unused
, intptr_t v __unused
)
2016 int mac_iokit_check_hid_control(kauth_cred_t cred __unused
);
2018 mac_iokit_check_hid_control(kauth_cred_t cred __unused
)
2023 int mac_mount_check_snapshot_mount(vfs_context_t ctx
, struct vnode
*rvp
, struct vnode
*vp
, struct componentname
*cnp
,
2024 const char *name
, const char *vfc_name
);
2026 mac_mount_check_snapshot_mount(vfs_context_t ctx __unused
, struct vnode
*rvp __unused
, struct vnode
*vp __unused
,
2027 struct componentname
*cnp __unused
, const char *name __unused
, const char *vfc_name __unused
)
2032 int mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused
, struct vnode
*dvp __unused
, struct componentname
*cnp __unused
);
2034 mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused
, struct vnode
*dvp __unused
, struct componentname
*cnp __unused
)