1/*
2 * Copyright (c) 2007-2020 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28/*-
29 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson
30 * Copyright (c) 2001 Ilmar S. Habibulin
31 * Copyright (c) 2001, 2002, 2003, 2004 Networks Associates Technology, Inc.
32 * Copyright (c) 2005-2006 SPARTA, Inc.
33 *
34 * This software was developed by Robert Watson and Ilmar Habibulin for the
35 * TrustedBSD Project.
36 *
37 * This software was developed for the FreeBSD Project in part by Network
38 * Associates Laboratories, the Security Research Division of Network
39 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"),
40 * as part of the DARPA CHATS research program.
41 *
42 * Redistribution and use in source and binary forms, with or without
43 * modification, are permitted provided that the following conditions
44 * are met:
45 * 1. Redistributions of source code must retain the above copyright
46 * notice, this list of conditions and the following disclaimer.
47 * 2. Redistributions in binary form must reproduce the above copyright
48 * notice, this list of conditions and the following disclaimer in the
49 * documentation and/or other materials provided with the distribution.
50 *
51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
61 * SUCH DAMAGE.
62 *
63 */
64
65/*-
66 * Framework for extensible kernel access control. This file contains
67 * Kernel and userland interface to the framework, policy registration
68 * and composition. Per-object interfaces, controls, and labeling may be
69 * found in src/sys/mac/. Sample policies may be found in src/sys/mac*.
70 */
71
72#include <stdarg.h>
73#include <string.h>
74#include <security/mac_internal.h>
75#include <security/mac_mach_internal.h>
76#include <sys/param.h>
77#include <sys/vnode.h>
78#include <sys/vnode_internal.h>
79#include <sys/vfs_context.h>
80#include <sys/namei.h>
81#include <bsd/bsm/audit.h>
82#include <bsd/security/audit/audit.h>
83#include <bsd/security/audit/audit_private.h>
84#include <sys/file.h>
85#include <sys/file_internal.h>
86#include <sys/filedesc.h>
87#include <sys/proc.h>
88#include <sys/proc_internal.h>
89#include <sys/kauth.h>
90#include <sys/sysproto.h>
91
92#include <mach/exception_types.h>
93#include <mach/vm_types.h>
94#include <mach/vm_prot.h>
95
96#include <kern/kalloc.h>
97#include <kern/sched_prim.h>
98#include <kern/task.h>
99
100#if CONFIG_MACF
101#include <security/mac.h>
102#include <security/mac_policy.h>
103#include <security/mac_framework.h>
104#include <security/mac_internal.h>
105#include <security/mac_mach_internal.h>
106#endif
107
108#include <libkern/section_keywords.h>
109
110/*
111 * define MB_DEBUG to display run-time debugging information
112 * #define MB_DEBUG 1
113 */
114
115#ifdef MB_DEBUG
116#define DPRINTF(x) printf x
117#else
118#define MB_DEBUG
119#define DPRINTF(x)
120#endif
121
122#if CONFIG_MACF
123SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
124 "Security Controls");
125SYSCTL_EXTENSIBLE_NODE(_security, OID_AUTO, mac, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
126 "TrustedBSD MAC policy controls");
127
128/*
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.
132 */
133#if 0
134MODULE_VERSION(kernel_mac_support, 1);
135#endif
136
137#if MAC_MAX_SLOTS > 32
138#error "MAC_MAX_SLOTS too large"
139#endif
140
141static unsigned int mac_max_slots = MAC_MAX_SLOTS;
142static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
143SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD | CTLFLAG_LOCKED,
144 &mac_max_slots, 0, "");
145
146/*
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.
150 */
151int mac_late = 0;
152
153/*
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
162 * be a problem.
163 */
164#if CONFIG_MACF_LAZY_VNODE_LABELS
165unsigned int mac_label_vnodes = 1;
166#else
167unsigned int mac_label_vnodes = 0;
168#endif /* CONFIG_MACF_LAZY_VNODE_LABELS */
169SYSCTL_UINT(_security_mac, OID_AUTO, labelvnodes, SECURITY_MAC_CTLFLAGS
170#if CONFIG_MACF_LAZY_VNODE_LABELS
171 | CTLFLAG_RD
172#endif
173 , &mac_label_vnodes, 0, "Label all vnodes");
174
175unsigned int mac_vnode_label_count = 0;
176SYSCTL_UINT(_security_mac, OID_AUTO, vnode_label_count, SECURITY_MAC_CTLFLAGS | CTLFLAG_RD,
177 &mac_vnode_label_count, 0, "Count of vnode labels");
178
179unsigned int mac_device_enforce = 1;
180SYSCTL_UINT(_security_mac, OID_AUTO, device_enforce, SECURITY_MAC_CTLFLAGS,
181 &mac_device_enforce, 0, "Enforce MAC policy on device operations");
182
183unsigned int mac_pipe_enforce = 1;
184SYSCTL_UINT(_security_mac, OID_AUTO, pipe_enforce, SECURITY_MAC_CTLFLAGS,
185 &mac_pipe_enforce, 0, "Enforce MAC policy on pipe operations");
186
187unsigned int mac_posixsem_enforce = 1;
188SYSCTL_UINT(_security_mac, OID_AUTO, posixsem_enforce, SECURITY_MAC_CTLFLAGS,
189 &mac_posixsem_enforce, 0, "Enforce MAC policy on POSIX semaphores");
190
191unsigned int mac_posixshm_enforce = 1;
192SYSCTL_UINT(_security_mac, OID_AUTO, posixshm_enforce, SECURITY_MAC_CTLFLAGS,
193 &mac_posixshm_enforce, 0, "Enforce MAC policy on Posix Shared Memory");
194
195unsigned int mac_proc_enforce = 1;
196SYSCTL_UINT(_security_mac, OID_AUTO, proc_enforce, SECURITY_MAC_CTLFLAGS,
197 &mac_proc_enforce, 0, "Enforce MAC policy on process operations");
198
199unsigned int mac_socket_enforce = 1;
200SYSCTL_UINT(_security_mac, OID_AUTO, socket_enforce, SECURITY_MAC_CTLFLAGS,
201 &mac_socket_enforce, 0, "Enforce MAC policy on socket operations");
202
203unsigned int mac_system_enforce = 1;
204SYSCTL_UINT(_security_mac, OID_AUTO, system_enforce, SECURITY_MAC_CTLFLAGS,
205 &mac_system_enforce, 0, "Enforce MAC policy on system-wide interfaces");
206
207unsigned int mac_sysvmsg_enforce = 1;
208SYSCTL_UINT(_security_mac, OID_AUTO, sysvmsg_enforce, SECURITY_MAC_CTLFLAGS,
209 &mac_sysvmsg_enforce, 0, "Enforce MAC policy on System V IPC message queues");
210
211unsigned int mac_sysvsem_enforce = 1;
212SYSCTL_UINT(_security_mac, OID_AUTO, sysvsem_enforce, SECURITY_MAC_CTLFLAGS,
213 &mac_sysvsem_enforce, 0, "Enforce MAC policy on System V IPC semaphores");
214
215unsigned int mac_sysvshm_enforce = 1;
216SYSCTL_INT(_security_mac, OID_AUTO, sysvshm_enforce, SECURITY_MAC_CTLFLAGS,
217 &mac_sysvshm_enforce, 0, "Enforce MAC policy on System V Shared Memory");
218
219unsigned int mac_vm_enforce = 1;
220SYSCTL_INT(_security_mac, OID_AUTO, vm_enforce, SECURITY_MAC_CTLFLAGS,
221 &mac_vm_enforce, 0, "Enforce MAC policy on VM operations");
222
223unsigned int mac_vnode_enforce = 1;
224SYSCTL_UINT(_security_mac, OID_AUTO, vnode_enforce, SECURITY_MAC_CTLFLAGS,
225 &mac_vnode_enforce, 0, "Enforce MAC policy on vnode operations");
226
227/*
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.
231 *
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.
242 */
243static LCK_GRP_DECLARE(mac_lck_grp, "MAC lock");
244static LCK_MTX_DECLARE(mac_policy_mtx, &mac_lck_grp);
245
246/*
247 * Policy list array allocation chunk size. Each entry holds a pointer.
248 */
249#define MAC_POLICY_LIST_CHUNKSIZE 8
250
251static int mac_policy_busy;
252
253#if !XNU_TARGET_OS_OSX
254SECURITY_READ_ONLY_LATE(mac_policy_list_t) mac_policy_list;
255SECURITY_READ_ONLY_LATE(static struct mac_policy_list_element) mac_policy_static_entries[MAC_POLICY_LIST_CHUNKSIZE];
256#else
257mac_policy_list_t mac_policy_list;
258#endif
259
260/*
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.
266 */
267struct mac_label_element_list_t mac_label_element_list;
268struct mac_label_element_list_t mac_static_label_element_list;
269
270static __inline void
271mac_policy_grab_exclusive(void)
272{
273 lck_mtx_lock(lck: &mac_policy_mtx);
274 while (mac_policy_busy != 0) {
275 lck_mtx_sleep(lck: &mac_policy_mtx, lck_sleep_action: LCK_SLEEP_UNLOCK,
276 event: (event_t)&mac_policy_busy, THREAD_UNINT);
277 lck_mtx_lock(lck: &mac_policy_mtx);
278 }
279}
280
281static __inline void
282mac_policy_release_exclusive(void)
283{
284 KASSERT(mac_policy_busy == 0,
285 ("mac_policy_release_exclusive(): not exclusive"));
286 lck_mtx_unlock(lck: &mac_policy_mtx);
287 thread_wakeup((event_t) &mac_policy_busy);
288}
289
290void
291mac_policy_list_busy(void)
292{
293 lck_mtx_lock(lck: &mac_policy_mtx);
294 mac_policy_busy++;
295 lck_mtx_unlock(lck: &mac_policy_mtx);
296}
297
298int
299mac_policy_list_conditional_busy(void)
300{
301 int ret;
302
303 if (mac_policy_list.numloaded <= mac_policy_list.staticmax) {
304 return 0;
305 }
306
307 lck_mtx_lock(lck: &mac_policy_mtx);
308 if (mac_policy_list.numloaded > mac_policy_list.staticmax) {
309 mac_policy_busy++;
310 ret = 1;
311 } else {
312 ret = 0;
313 }
314 lck_mtx_unlock(lck: &mac_policy_mtx);
315 return ret;
316}
317
318void
319mac_policy_list_unbusy(void)
320{
321 lck_mtx_lock(lck: &mac_policy_mtx);
322 mac_policy_busy--;
323 KASSERT(mac_policy_busy >= 0, ("MAC_POLICY_LIST_LOCK"));
324 if (mac_policy_busy == 0) {
325 thread_wakeup(&mac_policy_busy);
326 }
327 lck_mtx_unlock(lck: &mac_policy_mtx);
328}
329
330/*
331 * Early pre-malloc MAC initialization, including appropriate SMP locks.
332 */
333void
334mac_policy_init(void)
335{
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;
342
343#if !XNU_TARGET_OS_OSX
344 mac_policy_list.entries = mac_policy_static_entries;
345#else
346 mac_policy_list.entries = kalloc_type(struct mac_policy_list_element,
347 MAC_POLICY_LIST_CHUNKSIZE, Z_WAITOK | Z_ZERO);
348#endif
349
350 SLIST_INIT(&mac_label_element_list);
351 SLIST_INIT(&mac_static_label_element_list);
352}
353
354/* Function pointer set up for loading security extensions.
355 * It is set to an actual function after OSlibkernInit()
356 * has been called, and is set back to 0 by OSKextRemoveKextBootstrap()
357 * after bsd_init().
358 */
359void (*load_security_extensions_function)(void) = 0;
360
361/*
362 * Init after early Mach startup, but before BSD
363 */
364void
365mac_policy_initmach(void)
366{
367 /*
368 * For the purposes of modules that want to know if they were
369 * loaded "early", set the mac_late flag once we've processed
370 * modules either linked into the kernel, or loaded before the
371 * kernel startup.
372 */
373
374 if (load_security_extensions_function) {
375 load_security_extensions_function();
376 }
377 mac_late = 1;
378}
379
380/*
381 * BSD startup.
382 */
383void
384mac_policy_initbsd(void)
385{
386 struct mac_policy_conf *mpc;
387 u_int i;
388
389 printf("MAC Framework successfully initialized\n");
390
391 /* Call bsd init functions of already loaded policies */
392
393 /*
394 * Using the exclusive lock means no other framework entry
395 * points can proceed while initializations are running.
396 * This may not be necessary.
397 */
398 mac_policy_grab_exclusive();
399
400 for (i = 0; i <= mac_policy_list.maxindex; i++) {
401 mpc = mac_get_mpc(i);
402 if ((mpc != NULL) && (mpc->mpc_ops->mpo_policy_initbsd != NULL)) {
403 (*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
404 }
405 }
406
407 mac_policy_release_exclusive();
408}
409
410/*
411 * After a policy has been loaded, add the label namespaces managed by the
412 * policy to either the static or non-static label namespace list.
413 * A namespace is added to the the list only if it is not already on one of
414 * the lists.
415 */
416void
417mac_policy_addto_labellist(mac_policy_handle_t handle, int static_entry)
418{
419 struct mac_label_element *mle, *mle_tmp;
420 struct mac_label_listener *mll, *mll_tmp;
421 struct mac_label_element_list_t *list;
422 struct mac_policy_conf *mpc;
423 const char *name, *name2;
424 struct mac_label_element_list_t mles = SLIST_HEAD_INITIALIZER(mles);
425 struct mac_label_listeners_t mlls = SLIST_HEAD_INITIALIZER(mlls);
426
427 mpc = mac_get_mpc(handle);
428
429 if (mpc->mpc_labelnames == NULL) {
430 return;
431 }
432
433 if (mpc->mpc_labelname_count == 0) {
434 return;
435 }
436
437 if (static_entry) {
438 list = &mac_static_label_element_list;
439 } else {
440 list = &mac_label_element_list;
441 }
442
443 /*
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.
447 */
448 for (uint32_t idx = 0; idx < mpc->mpc_labelname_count; idx++) {
449 mle = kalloc_type(struct mac_label_element, Z_WAITOK_ZERO_NOFAIL);
450 SLIST_INSERT_HEAD(&mles, mle, mle_list);
451
452 mll = kalloc_type(struct mac_label_listener, Z_WAITOK);
453 SLIST_INSERT_HEAD(&mlls, mll, mll_list);
454 }
455
456 if (mac_late) {
457 mac_policy_grab_exclusive();
458 }
459 for (uint32_t idx = 0; idx < mpc->mpc_labelname_count; idx++) {
460 if (*(name = mpc->mpc_labelnames[idx]) == '?') {
461 name++;
462 }
463 /*
464 * Check both label element lists and add to the
465 * appropriate list only if not already on a list.
466 */
467 SLIST_FOREACH(mle, &mac_static_label_element_list, mle_list) {
468 if (*(name2 = mle->mle_name) == '?') {
469 name2++;
470 }
471 if (strcmp(s1: name, s2: name2) == 0) {
472 break;
473 }
474 }
475 if (mle == NULL) {
476 SLIST_FOREACH(mle, &mac_label_element_list, mle_list) {
477 if (*(name2 = mle->mle_name) == '?') {
478 name2++;
479 }
480 if (strcmp(s1: name, s2: name2) == 0) {
481 break;
482 }
483 }
484 }
485 if (mle == NULL) {
486 mle = SLIST_FIRST(&mles);
487 SLIST_REMOVE_HEAD(&mles, mle_list);
488 strlcpy(dst: mle->mle_name, src: mpc->mpc_labelnames[idx],
489 MAC_MAX_LABEL_ELEMENT_NAME);
490 SLIST_INIT(&mle->mle_listeners);
491 SLIST_INSERT_HEAD(list, mle, mle_list);
492 }
493
494 mll = SLIST_FIRST(&mlls);
495 SLIST_REMOVE_HEAD(&mlls, mll_list);
496 /* Add policy handler as a listener. */
497 mll->mll_handle = handle;
498 SLIST_INSERT_HEAD(&mle->mle_listeners, mll, mll_list);
499 }
500 if (mac_late) {
501 mac_policy_release_exclusive();
502 }
503
504 SLIST_FOREACH_SAFE(mle, &mles, mle_list, mle_tmp) {
505 kfree_type(struct mac_label_element, mle);
506 }
507 SLIST_FOREACH_SAFE(mll, &mlls, mll_list, mll_tmp) {
508 kfree_type(struct mac_label_listener, mll);
509 }
510}
511
512/*
513 * After a policy has been unloaded, remove the label namespaces that the
514 * the policy manages from the non-static list of namespaces.
515 * The removal only takes place when no other policy is interested in the
516 * namespace.
517 *
518 * Must be called with the policy exclusive lock held.
519 */
520void
521mac_policy_removefrom_labellist(mac_policy_handle_t handle)
522{
523 struct mac_label_listener *mll, **mllp;
524 struct mac_label_element *mle, **mlep;
525 struct mac_policy_conf *mpc;
526
527 mpc = mac_get_mpc(handle);
528
529 if (mpc->mpc_labelnames == NULL) {
530 return;
531 }
532
533 if (mpc->mpc_labelname_count == 0) {
534 return;
535 }
536
537 /*
538 * Unregister policy as being interested in any label
539 * namespaces. If no other policy is listening, remove
540 * that label element from the list. Note that we only
541 * have to worry about the non-static list.
542 */
543 SLIST_FOREACH_PREVPTR(mle, mlep, &mac_label_element_list, mle_list) {
544 SLIST_FOREACH_PREVPTR(mll, mllp, &mle->mle_listeners, mll_list) {
545 if (mll->mll_handle == handle) {
546 *mllp = SLIST_NEXT(mll, mll_list);
547 kfree_type(struct mac_label_listener, mll);
548 if (SLIST_EMPTY(&mle->mle_listeners)) {
549 *mlep = SLIST_NEXT(mle, mle_list);
550 kfree_type(struct mac_label_element, mle);
551 }
552 return;
553 }
554 }
555 }
556}
557
558/*
559 * After the policy list has changed, walk the list to update any global
560 * flags.
561 */
562static void
563mac_policy_updateflags(void)
564{
565}
566
567static __inline void
568mac_policy_fixup_mmd_list(struct mac_module_data *new)
569{
570 struct mac_module_data *old;
571 struct mac_module_data_element *ele, *aele;
572 struct mac_module_data_list *arr, *dict;
573 unsigned int i, j, k;
574
575 old = new->base_addr;
576 DPRINTF(("fixup_mmd: old %p new %p\n", old, new));
577 for (i = 0; i < new->count; i++) {
578 ele = &(new->data[i]);
579 DPRINTF(("fixup_mmd: ele %p\n", ele));
580 DPRINTF((" key %p value %p\n", ele->key, ele->value));
581 mmd_fixup_ele(oldbase: old, newbase: new, ele); /* Fix up key/value ptrs. */
582 DPRINTF((" key %p value %p\n", ele->key, ele->value));
583 if (ele->value_type == MAC_DATA_TYPE_ARRAY) {
584 arr = (struct mac_module_data_list *)ele->value;
585 DPRINTF(("fixup_mmd: array @%p\n", arr));
586 for (j = 0; j < arr->count; j++) {
587 aele = &(arr->list[j]);
588 DPRINTF(("fixup_mmd: aele %p\n", aele));
589 DPRINTF((" key %p value %p\n", aele->key, aele->value));
590 mmd_fixup_ele(oldbase: old, newbase: new, ele: aele);
591 DPRINTF((" key %p value %p\n", aele->key, aele->value));
592 if (arr->type == MAC_DATA_TYPE_DICT) {
593 dict = (struct mac_module_data_list *)aele->value;
594 DPRINTF(("fixup_mmd: dict @%p\n", dict));
595 for (k = 0; k < dict->count; k++) {
596 mmd_fixup_ele(oldbase: old, newbase: new,
597 ele: &(dict->list[k]));
598 }
599 }
600 }
601 }
602 }
603 new->base_addr = new;
604}
605
606int
607mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep,
608 void *xd)
609{
610#if XNU_TARGET_OS_OSX
611 struct mac_policy_list_element *tmac_policy_list_element;
612#endif
613 int error, slot, static_entry = 0;
614 u_int i;
615
616
617 /*
618 * Some preliminary checks to make sure the policy's conf structure
619 * contains the required fields.
620 */
621 if (mpc->mpc_name == NULL) {
622 panic("policy's name is not set");
623 }
624
625 if (mpc->mpc_fullname == NULL) {
626 panic("policy's full name is not set");
627 }
628
629 if (mpc->mpc_labelname_count > MAC_MAX_MANAGED_NAMESPACES) {
630 panic("policy's managed label namespaces exceeds maximum");
631 }
632
633 if (mpc->mpc_ops == NULL) {
634 panic("policy's OPs field is NULL");
635 }
636
637 error = 0;
638
639 if (mac_late) {
640 if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE) {
641 printf("Module %s does not support late loading.\n",
642 mpc->mpc_name);
643 return EPERM;
644 }
645 mac_policy_grab_exclusive();
646 }
647
648 if (mac_policy_list.numloaded >= mac_policy_list.max) {
649#if XNU_TARGET_OS_OSX
650 /* allocate new policy list array, zero new chunk */
651 tmac_policy_list_element =
652 kalloc_type(struct mac_policy_list_element,
653 MAC_POLICY_LIST_CHUNKSIZE * (mac_policy_list.chunks + 1),
654 Z_WAITOK | Z_ZERO);
655
656 /* copy old entries into new list */
657 memcpy(dst: tmac_policy_list_element, src: mac_policy_list.entries,
658 n: sizeof(struct mac_policy_list_element) *
659 MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks);
660
661 /* free old array */
662 kfree_type(struct mac_policy_list_element,
663 MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks,
664 mac_policy_list.entries);
665
666 mac_policy_list.entries = tmac_policy_list_element;
667
668 /* Update maximums, etc */
669 mac_policy_list.max += MAC_POLICY_LIST_CHUNKSIZE;
670 mac_policy_list.chunks++;
671#else
672 printf("out of space in mac_policy_list.\n");
673 return ENOMEM;
674#endif /* XNU_TARGET_OS_OSX */
675 }
676
677 /* Check for policy with same name already loaded */
678 for (i = 0; i <= mac_policy_list.maxindex; i++) {
679 if (mac_policy_list.entries[i].mpc == NULL) {
680 continue;
681 }
682
683 if (strcmp(s1: mac_policy_list.entries[i].mpc->mpc_name,
684 s2: mpc->mpc_name) == 0) {
685 error = EEXIST;
686 goto out;
687 }
688 }
689
690 if (mpc->mpc_field_off != NULL) {
691 slot = ffs(mac_slot_offsets_free);
692 if (slot == 0) {
693 error = ENOMEM;
694 goto out;
695 }
696 slot--;
697 mac_slot_offsets_free &= ~(1 << slot);
698 *mpc->mpc_field_off = slot;
699 }
700 mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
701
702 if (xd) {
703 struct mac_module_data *mmd = xd; /* module data from plist */
704
705 /* Make a copy of the data. */
706 mpc->mpc_data = (void *)kalloc_data(mmd->size, Z_WAITOK);
707 if (mpc->mpc_data != NULL) {
708 memcpy(dst: mpc->mpc_data, src: mmd, n: mmd->size);
709
710 /* Fix up pointers after copy. */
711 mac_policy_fixup_mmd_list(new: mpc->mpc_data);
712 }
713 }
714
715 /* Find the first free handle in the list (using our hint). */
716 for (i = mac_policy_list.freehint; i < mac_policy_list.max; i++) {
717 if (mac_policy_list.entries[i].mpc == NULL) {
718 *handlep = i;
719 mac_policy_list.freehint = ++i;
720 break;
721 }
722 }
723
724 /*
725 * If we are loading a MAC module before the framework has
726 * finished initializing or the module is not unloadable and
727 * we can place its handle adjacent to the last static entry,
728 * bump the static policy high water mark.
729 * Static policies can get by with weaker locking requirements.
730 */
731 if (!mac_late ||
732 ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0 &&
733 *handlep == mac_policy_list.staticmax)) {
734 static_entry = 1;
735 mac_policy_list.staticmax++;
736 }
737
738 mac_policy_list.entries[*handlep].mpc = mpc;
739
740 /* Update counters, etc */
741 if (*handlep > mac_policy_list.maxindex) {
742 mac_policy_list.maxindex = *handlep;
743 }
744 mac_policy_list.numloaded++;
745
746 /* Per-policy initialization. */
747 printf("calling mpo_policy_init for %s\n", mpc->mpc_name);
748 if (mpc->mpc_ops->mpo_policy_init != NULL) {
749 (*(mpc->mpc_ops->mpo_policy_init))(mpc);
750 }
751
752 if (mac_late && mpc->mpc_ops->mpo_policy_initbsd != NULL) {
753 printf("calling mpo_policy_initbsd for %s\n", mpc->mpc_name);
754 (*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
755 }
756
757 mac_policy_updateflags();
758
759 if (mac_late) {
760 mac_policy_release_exclusive();
761 }
762
763 mac_policy_addto_labellist(handle: *handlep, static_entry);
764
765 printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
766 mpc->mpc_name);
767
768 return 0;
769
770out:
771 if (mac_late) {
772 mac_policy_release_exclusive();
773 }
774
775 return error;
776}
777
778int
779mac_policy_unregister(mac_policy_handle_t handle)
780{
781 struct mac_policy_conf *mpc;
782
783 /*
784 * If we fail the load, we may get a request to unload. Check
785 * to see if we did the run-time registration, and if not,
786 * silently succeed.
787 */
788 mac_policy_grab_exclusive();
789 mpc = mac_get_mpc(handle);
790 if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
791 mac_policy_release_exclusive();
792 return 0;
793 }
794
795#if 0
796 /*
797 * Don't allow unloading modules with private data.
798 */
799 if (mpc->mpc_field_off != NULL) {
800 MAC_POLICY_LIST_UNLOCK();
801 return EBUSY;
802 }
803#endif
804 /*
805 * Only allow the unload to proceed if the module is unloadable
806 * by its own definition.
807 */
808 if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
809 mac_policy_release_exclusive();
810 return EBUSY;
811 }
812
813 mac_policy_removefrom_labellist(handle);
814
815 mac_get_mpc(handle) = NULL;
816 if (handle < mac_policy_list.freehint &&
817 handle >= mac_policy_list.staticmax) {
818 mac_policy_list.freehint = handle;
819 }
820
821 if (handle == mac_policy_list.maxindex) {
822 mac_policy_list.maxindex--;
823 }
824
825 mac_policy_list.numloaded--;
826 if (mpc->mpc_field_off != NULL) {
827 mac_slot_offsets_free |= (1 << *mpc->mpc_field_off);
828 }
829
830 if (mpc->mpc_ops->mpo_policy_destroy != NULL) {
831 (*(mpc->mpc_ops->mpo_policy_destroy))(mpc);
832 }
833
834 mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
835 mac_policy_updateflags();
836
837 mac_policy_release_exclusive();
838
839 if (mpc->mpc_data) {
840 struct mac_module_data *mmd = mpc->mpc_data;
841 __typed_allocators_ignore(kfree_data(mmd, mmd->size)); // rdar://87952845
842 mpc->mpc_data = NULL;
843 }
844
845 printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
846 mpc->mpc_name);
847
848 return 0;
849}
850
851/*
852 * Define an error value precedence, and given two arguments, selects the
853 * value with the higher precedence.
854 */
855int
856mac_error_select(int error1, int error2)
857{
858 /* Certain decision-making errors take top priority. */
859 if (error1 == EDEADLK || error2 == EDEADLK) {
860 return EDEADLK;
861 }
862
863 /* Invalid arguments should be reported where possible. */
864 if (error1 == EINVAL || error2 == EINVAL) {
865 return EINVAL;
866 }
867
868 /* Precedence goes to "visibility", with both process and file. */
869 if (error1 == ESRCH || error2 == ESRCH) {
870 return ESRCH;
871 }
872
873 if (error1 == ENOENT || error2 == ENOENT) {
874 return ENOENT;
875 }
876
877 /* Precedence goes to DAC/MAC protections. */
878 if (error1 == EACCES || error2 == EACCES) {
879 return EACCES;
880 }
881
882 /* Precedence goes to privilege. */
883 if (error1 == EPERM || error2 == EPERM) {
884 return EPERM;
885 }
886
887 /* Precedence goes to error over success; otherwise, arbitrary. */
888 if (error1 != 0) {
889 return error1;
890 }
891 return error2;
892}
893
894int
895mac_check_structmac_consistent(struct user_mac *mac)
896{
897 if (mac->m_buflen > MAC_MAX_LABEL_BUF_LEN || mac->m_buflen == 0) {
898 return EINVAL;
899 }
900
901 return 0;
902}
903
904/*
905 * Get the external forms of labels from all policies, for a single
906 * label namespace or "*" for all namespaces. Returns ENOENT if no policy
907 * is registered for the namespace, unless the namespace begins with a '?'.
908 */
909static int
910mac_label_externalize(size_t mpo_externalize_off, struct label *label,
911 const char *element, struct sbuf *sb)
912{
913 struct mac_policy_conf *mpc;
914 struct mac_label_listener *mll;
915 struct mac_label_element *mle;
916 struct mac_label_element_list_t *element_list;
917 const char *name;
918 int (*mpo_externalize)(struct label *, char *, struct sbuf *);
919 int all_labels = 0, ignorenotfound = 0, error = 0, busy = FALSE;
920 int sb_pos;
921 unsigned int count = 0;
922
923 if (element[0] == '?') {
924 element++;
925 ignorenotfound = 1;
926 } else if (element[0] == '*' && element[1] == '\0') {
927 all_labels = 1;
928 }
929
930 element_list = &mac_static_label_element_list;
931element_loop:
932 SLIST_FOREACH(mle, element_list, mle_list) {
933 name = mle->mle_name;
934 if (all_labels) {
935 if (*name == '?') {
936 continue;
937 }
938 } else {
939 if (*name == '?') {
940 name++;
941 }
942 if (strcmp(s1: name, s2: element) != 0) {
943 continue;
944 }
945 }
946 SLIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
947 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
948 if (mpc == NULL) {
949 continue;
950 }
951 mpo_externalize = *(const typeof(mpo_externalize) *)
952 ((const char *)mpc->mpc_ops + mpo_externalize_off);
953 if (mpo_externalize == NULL) {
954 continue;
955 }
956 sb_pos = sbuf_len(sb);
957 error = sbuf_printf(sb, "%s/", name);
958 if (error) {
959 goto done;
960 }
961 error = mpo_externalize(label, mle->mle_name, sb);
962 if (error) {
963 if (error != ENOENT) {
964 goto done;
965 }
966 /*
967 * If a policy doesn't have a label to
968 * externalize it returns ENOENT. This
969 * may occur for policies that support
970 * multiple label elements for some
971 * (but not all) object types.
972 */
973 sbuf_setpos(sb, sb_pos);
974 error = 0;
975 continue;
976 }
977 error = sbuf_putc(sb, ',');
978 if (error) {
979 goto done;
980 }
981 count++;
982 }
983 }
984 /* If there are dynamic policies present, check their elements too. */
985 if (!busy && mac_policy_list_conditional_busy() == 1) {
986 element_list = &mac_label_element_list;
987 busy = TRUE;
988 goto element_loop;
989 }
990done:
991 if (busy) {
992 mac_policy_list_unbusy();
993 }
994 if (!error && count == 0) {
995 if (!all_labels && !ignorenotfound) {
996 error = ENOENT; /* XXX: ENOLABEL? */
997 }
998 }
999 return error;
1000}
1001
1002/*
1003 * Get the external forms of labels from all policies, for all label
1004 * namespaces contained in a list.
1005 *
1006 * XXX This may be leaking an sbuf.
1007 */
1008int
1009mac_externalize(size_t mpo_externalize_off, struct label *label,
1010 const char *elementlist, char *outbuf, size_t outbuflen)
1011{
1012 char *element;
1013 char *scratch_base;
1014 char *scratch;
1015 struct sbuf sb;
1016 int error = 0, len;
1017 size_t buf_len = strlen(s: elementlist) + 1;
1018
1019 /* allocate a scratch buffer the size of the string */
1020 scratch_base = kalloc_data(buf_len, Z_WAITOK);
1021 if (scratch_base == NULL) {
1022 error = ENOMEM;
1023 goto out;
1024 }
1025
1026 /* copy the elementlist to the scratch buffer */
1027 strlcpy(dst: scratch_base, src: elementlist, n: buf_len);
1028
1029 /*
1030 * set up a temporary pointer that can be used to iterate the
1031 * scratch buffer without losing the allocation address
1032 */
1033 scratch = scratch_base;
1034
1035 /*
1036 * initialize an sbuf mapping over the output buffer (or newly-allocated internal buffer, if
1037 * outbuf is NULL), up to sbuf's limit of INT_MAX.
1038 */
1039 if (outbuflen > INT_MAX) {
1040 outbuflen = INT_MAX;
1041 }
1042 if (sbuf_new(&sb, outbuf, (int)outbuflen, SBUF_FIXEDLEN) == NULL) {
1043 /* could not allocate interior buffer */
1044 error = ENOMEM;
1045 goto out;
1046 }
1047 /* iterate the scratch buffer; NOTE: buffer contents modified! */
1048 while ((element = strsep(&scratch, ",")) != NULL) {
1049 error = mac_label_externalize(mpo_externalize_off, label,
1050 element, sb: &sb);
1051 if (error) {
1052 break;
1053 }
1054 }
1055 if ((len = sbuf_len(&sb)) > 0) {
1056 sbuf_setpos(&sb, len - 1); /* trim trailing comma */
1057 }
1058 sbuf_finish(&sb);
1059
1060out:
1061 if (scratch_base != NULL) {
1062 kfree_data(scratch_base, buf_len);
1063 }
1064
1065 return error;
1066}
1067
1068/*
1069 * Have all policies set the internal form of a label, for a single
1070 * label namespace.
1071 */
1072static int
1073mac_label_internalize(size_t mpo_internalize_off, struct label *label,
1074 char *element_name, char *element_data)
1075{
1076 struct mac_policy_conf *mpc;
1077 struct mac_label_listener *mll;
1078 struct mac_label_element *mle;
1079 struct mac_label_element_list_t *element_list;
1080 int (*mpo_internalize)(struct label *, char *, char *);
1081 int error = 0, busy = FALSE;
1082 unsigned int count = 0;
1083 const char *name;
1084
1085 element_list = &mac_static_label_element_list;
1086element_loop:
1087 SLIST_FOREACH(mle, element_list, mle_list) {
1088 if (*(name = mle->mle_name) == '?') {
1089 name++;
1090 }
1091 if (strcmp(s1: element_name, s2: name) != 0) {
1092 continue;
1093 }
1094 SLIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1095 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
1096 if (mpc == NULL) {
1097 continue;
1098 }
1099 mpo_internalize = *(const typeof(mpo_internalize) *)
1100 ((const char *)mpc->mpc_ops + mpo_internalize_off);
1101 if (mpo_internalize == NULL) {
1102 continue;
1103 }
1104 error = mpo_internalize(label, element_name,
1105 element_data);
1106 if (error) {
1107 goto done;
1108 }
1109 count++;
1110 }
1111 }
1112 /* If there are dynamic policies present, check their elements too. */
1113 if (!busy && mac_policy_list_conditional_busy() == 1) {
1114 element_list = &mac_label_element_list;
1115 busy = TRUE;
1116 goto element_loop;
1117 }
1118done:
1119 if (busy) {
1120 mac_policy_list_unbusy();
1121 }
1122 if (!error && count == 0) {
1123 error = ENOPOLICY;
1124 }
1125 return error;
1126}
1127
1128int
1129mac_internalize(size_t mpo_internalize_off, struct label *label,
1130 char *textlabels)
1131{
1132 char *element_name, *element_data;
1133 int error = 0;
1134
1135 while (!error && (element_name = strsep(&textlabels, ",")) != NULL) {
1136 element_data = strchr(s: element_name, c: '/');
1137 if (element_data == NULL) {
1138 error = EINVAL;
1139 break;
1140 }
1141 *element_data++ = '\0';
1142 error = mac_label_internalize(mpo_internalize_off, label,
1143 element_name, element_data);
1144 }
1145 return error;
1146}
1147
1148static int
1149user_mac_copyin(struct proc *p, user_addr_t mac_p, struct user_mac *mac)
1150{
1151 int error;
1152
1153 if (IS_64BIT_PROCESS(p)) {
1154 struct user64_mac mac64;
1155 if ((error = copyin(mac_p, &mac64, sizeof(mac64)))) {
1156 return error;
1157 }
1158
1159 mac->m_buflen = mac64.m_buflen;
1160 mac->m_string = mac64.m_string;
1161 } else {
1162 struct user32_mac mac32;
1163 if ((error = copyin(mac_p, &mac32, sizeof(mac32)))) {
1164 return error;
1165 }
1166
1167 mac->m_buflen = mac32.m_buflen;
1168 mac->m_string = mac32.m_string;
1169 }
1170
1171 return mac_check_structmac_consistent(mac);
1172}
1173
1174int
1175mac_do_get(struct proc *p, user_addr_t mac_p, mac_getter_t getter)
1176{
1177 struct user_mac mac;
1178 char *input;
1179 char *output;
1180 size_t len;
1181 size_t ulen;
1182 int error;
1183
1184 if ((error = user_mac_copyin(p, mac_p, mac: &mac))) {
1185 return error;
1186 }
1187
1188 len = mac.m_buflen;
1189 input = kalloc_data(len, Z_WAITOK);
1190 if ((error = copyinstr(uaddr: mac.m_string, kaddr: input, len, done: &ulen))) {
1191 kfree_data(input, len);
1192 return error;
1193 }
1194
1195 AUDIT_ARG(mac_string, input);
1196
1197 output = kalloc_data(len, Z_WAITOK | Z_ZERO);
1198
1199 error = getter(input, output, len);
1200 if (error == 0) {
1201 /* mac_check_structmac_consistent => len > 0 */
1202 output[len - 1] = '\0';
1203 error = copyout(output, mac.m_string, strlen(output) + 1);
1204 }
1205
1206 kfree_data(output, len);
1207 kfree_data(input, len);
1208 return error;
1209}
1210
1211int
1212mac_do_set(struct proc *p, user_addr_t mac_p, mac_setter_t setter)
1213{
1214 struct user_mac mac;
1215 char *input;
1216 size_t len;
1217 size_t ulen;
1218 int error;
1219
1220 if ((error = user_mac_copyin(p, mac_p, mac: &mac))) {
1221 return error;
1222 }
1223
1224 len = mac.m_buflen;
1225 input = kalloc_data(len, Z_WAITOK);
1226 if ((error = copyinstr(uaddr: mac.m_string, kaddr: input, len, done: &ulen))) {
1227 kfree_data(input, len);
1228 return error;
1229 }
1230
1231 AUDIT_ARG(mac_string, input);
1232
1233 error = setter(input, len);
1234
1235 kfree_data(input, len);
1236 return error;
1237}
1238
1239/* system calls */
1240
1241int
1242__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, int *ret __unused)
1243{
1244 return mac_do_get(p, mac_p: uap->mac_p,
1245 getter: ^(char *input, char *output, size_t len) {
1246 struct ucred *tcred;
1247 int error;
1248
1249 AUDIT_ARG(pid, uap->pid);
1250
1251 tcred = kauth_cred_proc_ref_for_pid(pid: uap->pid);
1252 if (tcred == NOCRED) {
1253 return ESRCH;
1254 }
1255
1256 error = mac_cred_label_externalize(mac_cred_label(cred: tcred),
1257 e: input, out: output, olen: len, M_WAITOK);
1258
1259 kauth_cred_unref(&tcred);
1260 return error;
1261 });
1262}
1263
1264int
1265__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, int *ret __unused)
1266{
1267 return mac_do_get(p, mac_p: uap->mac_p,
1268 getter: ^(char *input, char *output, size_t len) {
1269 struct label *label;
1270
1271 label = mac_cred_label(cred: kauth_cred_get());
1272
1273 return mac_cred_label_externalize(label, e: input, out: output, olen: len, M_WAITOK);
1274 });
1275}
1276
1277int
1278__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, int *ret __unused)
1279{
1280 return mac_do_set(p, mac_p: uap->mac_p,
1281 setter: ^(char *input, __unused size_t len) {
1282 struct label *intlabel;
1283 int error;
1284
1285 intlabel = mac_cred_label_alloc();
1286 if ((error = mac_cred_label_internalize(label: intlabel, string: input))) {
1287 goto out;
1288 }
1289
1290 if ((error = mac_cred_check_label_update(cred: kauth_cred_get(), newlabel: intlabel))) {
1291 goto out;
1292 }
1293
1294 error = kauth_proc_label_update(proc: p, label: intlabel);
1295
1296 out:
1297 mac_cred_label_free(label: intlabel);
1298 return error;
1299 });
1300}
1301
1302int
1303__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, int *ret __unused)
1304{
1305 return mac_do_get(p, mac_p: uap->mac_p,
1306 getter: ^(char *input, char *output, size_t len) {
1307 struct fileproc *fp;
1308 struct vnode *vp;
1309 int error;
1310 struct label *intlabel;
1311
1312 AUDIT_ARG(fd, uap->fd);
1313
1314 if ((error = fp_lookup(p, fd: uap->fd, resultfp: &fp, locked: 0))) {
1315 return error;
1316 }
1317
1318 error = mac_file_check_get(cred: kauth_cred_get(), fg: fp->fp_glob, elements: input, len);
1319 if (error) {
1320 fp_drop(p, fd: uap->fd, fp, locked: 0);
1321 return error;
1322 }
1323
1324 switch (FILEGLOB_DTYPE(fp->fp_glob)) {
1325 case DTYPE_VNODE:
1326 intlabel = mac_vnode_label_alloc(NULL);
1327 if (intlabel == NULL) {
1328 error = ENOMEM;
1329 break;
1330 }
1331 vp = (struct vnode *)fp_get_data(fp);
1332 error = vnode_getwithref(vp);
1333 if (error == 0) {
1334 mac_vnode_label_copy(l1: mac_vnode_label(vp), l2: intlabel);
1335 error = mac_vnode_label_externalize(intlabel,
1336 e: input, out: output, olen: len, M_WAITOK);
1337 vnode_put(vp);
1338 }
1339 mac_vnode_label_free(label: intlabel);
1340 break;
1341 case DTYPE_SOCKET:
1342 case DTYPE_PSXSHM:
1343 case DTYPE_PSXSEM:
1344 case DTYPE_PIPE:
1345 case DTYPE_KQUEUE:
1346 case DTYPE_FSEVENTS:
1347 case DTYPE_ATALK:
1348 case DTYPE_NETPOLICY:
1349 case DTYPE_CHANNEL:
1350 case DTYPE_NEXUS:
1351 default:
1352 error = ENOSYS; // only sockets/vnodes so far
1353 break;
1354 }
1355 fp_drop(p, fd: uap->fd, fp, locked: 0);
1356 return error;
1357 });
1358}
1359
1360static int
1361mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow)
1362{
1363 return mac_do_get(p, mac_p,
1364 getter: ^(char *input, char *output, size_t len) {
1365 struct vnode *vp;
1366 struct nameidata nd;
1367 struct label *intlabel;
1368 int error;
1369
1370 NDINIT(&nd, LOOKUP, OP_LOOKUP,
1371 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1372 UIO_USERSPACE, path_p,
1373 vfs_context_current());
1374 if ((error = namei(ndp: &nd))) {
1375 return error;
1376 }
1377 vp = nd.ni_vp;
1378
1379 nameidone(&nd);
1380
1381 intlabel = mac_vnode_label_alloc(NULL);
1382 mac_vnode_label_copy(l1: mac_vnode_label(vp), l2: intlabel);
1383 error = mac_vnode_label_externalize(intlabel, e: input, out: output,
1384 olen: len, M_WAITOK);
1385 mac_vnode_label_free(label: intlabel);
1386
1387 vnode_put(vp);
1388 return error;
1389 });
1390}
1391
1392int
1393__mac_get_file(proc_t p, struct __mac_get_file_args *uap,
1394 int *ret __unused)
1395{
1396 return mac_get_filelink(p, mac_p: uap->mac_p, path_p: uap->path_p, follow: 1);
1397}
1398
1399int
1400__mac_get_link(proc_t p, struct __mac_get_link_args *uap,
1401 int *ret __unused)
1402{
1403 return mac_get_filelink(p, mac_p: uap->mac_p, path_p: uap->path_p, follow: 0);
1404}
1405
1406int
1407__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, int *ret __unused)
1408{
1409 return mac_do_set(p, mac_p: uap->mac_p,
1410 setter: ^(char *input, size_t len) {
1411 struct fileproc *fp;
1412 struct vfs_context *ctx = vfs_context_current();
1413 int error;
1414 struct label *intlabel;
1415 struct vnode *vp;
1416
1417 AUDIT_ARG(fd, uap->fd);
1418
1419 if ((error = fp_lookup(p, fd: uap->fd, resultfp: &fp, locked: 0))) {
1420 return error;
1421 }
1422
1423 error = mac_file_check_set(cred: vfs_context_ucred(ctx), fg: fp->fp_glob, bufp: input, buflen: len);
1424 if (error) {
1425 fp_drop(p, fd: uap->fd, fp, locked: 0);
1426 return error;
1427 }
1428
1429 switch (FILEGLOB_DTYPE(fp->fp_glob)) {
1430 case DTYPE_VNODE:
1431 if (mac_label_vnodes == 0) {
1432 error = ENOSYS;
1433 break;
1434 }
1435
1436 intlabel = mac_vnode_label_alloc(NULL);
1437
1438 error = mac_vnode_label_internalize(label: intlabel, string: input);
1439 if (error) {
1440 mac_vnode_label_free(label: intlabel);
1441 break;
1442 }
1443
1444 vp = (struct vnode *)fp_get_data(fp);
1445
1446 error = vnode_getwithref(vp);
1447 if (error == 0) {
1448 error = vn_setlabel(vp, intlabel, context: ctx);
1449 vnode_put(vp);
1450 }
1451 mac_vnode_label_free(label: intlabel);
1452 break;
1453
1454 case DTYPE_SOCKET:
1455 case DTYPE_PSXSHM:
1456 case DTYPE_PSXSEM:
1457 case DTYPE_PIPE:
1458 case DTYPE_KQUEUE:
1459 case DTYPE_FSEVENTS:
1460 case DTYPE_ATALK:
1461 case DTYPE_NETPOLICY:
1462 case DTYPE_CHANNEL:
1463 case DTYPE_NEXUS:
1464 default:
1465 error = ENOSYS; // only sockets/vnodes so far
1466 break;
1467 }
1468
1469 fp_drop(p, fd: uap->fd, fp, locked: 0);
1470 return error;
1471 });
1472}
1473
1474static int
1475mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p,
1476 int follow)
1477{
1478 return mac_do_set(p, mac_p,
1479 setter: ^(char *input, __unused size_t len) {
1480 struct vnode *vp;
1481 struct vfs_context *ctx = vfs_context_current();
1482 struct label *intlabel;
1483 struct nameidata nd;
1484 int error;
1485
1486 if (mac_label_vnodes == 0) {
1487 return ENOSYS;
1488 }
1489
1490 intlabel = mac_vnode_label_alloc(NULL);
1491 error = mac_vnode_label_internalize(label: intlabel, string: input);
1492 if (error) {
1493 mac_vnode_label_free(label: intlabel);
1494 return error;
1495 }
1496
1497 NDINIT(&nd, LOOKUP, OP_LOOKUP,
1498 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1499 UIO_USERSPACE, path_p, ctx);
1500 error = namei(ndp: &nd);
1501 if (error) {
1502 mac_vnode_label_free(label: intlabel);
1503 return error;
1504 }
1505 vp = nd.ni_vp;
1506
1507 nameidone(&nd);
1508
1509 error = vn_setlabel(vp, intlabel, context: ctx);
1510 vnode_put(vp);
1511 mac_vnode_label_free(label: intlabel);
1512
1513 return error;
1514 });
1515}
1516
1517int
1518__mac_set_file(proc_t p, struct __mac_set_file_args *uap,
1519 int *ret __unused)
1520{
1521 return mac_set_filelink(p, mac_p: uap->mac_p, path_p: uap->path_p, follow: 1);
1522}
1523
1524int
1525__mac_set_link(proc_t p, struct __mac_set_link_args *uap,
1526 int *ret __unused)
1527{
1528 return mac_set_filelink(p, mac_p: uap->mac_p, path_p: uap->path_p, follow: 0);
1529}
1530
1531static int
1532mac_proc_check_mac_syscall(proc_t p, const char *target, int callnum)
1533{
1534 int error;
1535
1536#if SECURITY_MAC_CHECK_ENFORCE
1537 /* 21167099 - only check if we allow write */
1538 if (!mac_proc_enforce) {
1539 return 0;
1540 }
1541#endif
1542
1543 MAC_CHECK(proc_check_syscall_mac, p, target, callnum);
1544
1545 return error;
1546}
1547
1548/*
1549 * __mac_syscall: Perform a MAC policy system call
1550 *
1551 * Parameters: p Process calling this routine
1552 * uap User argument descriptor (see below)
1553 * retv (Unused)
1554 *
1555 * Indirect: uap->policy Name of target MAC policy
1556 * uap->call MAC policy-specific system call to perform
1557 * uap->arg MAC policy-specific system call arguments
1558 *
1559 * Returns: 0 Success
1560 * !0 Not success
1561 *
1562 */
1563int
1564__mac_syscall(proc_t p, struct __mac_syscall_args *uap, int *retv __unused)
1565{
1566 struct mac_policy_conf *mpc;
1567 char target[MAC_MAX_POLICY_NAME];
1568 int error;
1569 u_int i;
1570 size_t ulen;
1571
1572 error = copyinstr(uaddr: uap->policy, kaddr: target, len: sizeof(target), done: &ulen);
1573 if (error) {
1574 return error;
1575 }
1576 AUDIT_ARG(value32, uap->call);
1577 AUDIT_ARG(mac_string, target);
1578
1579 error = mac_proc_check_mac_syscall(p, target, callnum: uap->call);
1580 if (error) {
1581 return error;
1582 }
1583
1584 error = ENOPOLICY;
1585
1586 for (i = 0; i < mac_policy_list.staticmax; i++) {
1587 mpc = mac_policy_list.entries[i].mpc;
1588 if (mpc == NULL) {
1589 continue;
1590 }
1591
1592 if (strcmp(s1: mpc->mpc_name, s2: target) == 0 &&
1593 mpc->mpc_ops->mpo_policy_syscall != NULL) {
1594 error = mpc->mpc_ops->mpo_policy_syscall(p,
1595 uap->call, uap->arg);
1596 goto done;
1597 }
1598 }
1599 if (mac_policy_list_conditional_busy() != 0) {
1600 for (; i <= mac_policy_list.maxindex; i++) {
1601 mpc = mac_policy_list.entries[i].mpc;
1602 if (mpc == NULL) {
1603 continue;
1604 }
1605
1606 if (strcmp(s1: mpc->mpc_name, s2: target) == 0 &&
1607 mpc->mpc_ops->mpo_policy_syscall != NULL) {
1608 error = mpc->mpc_ops->mpo_policy_syscall(p,
1609 uap->call, uap->arg);
1610 break;
1611 }
1612 }
1613 mac_policy_list_unbusy();
1614 }
1615
1616done:
1617 return error;
1618}
1619
1620int
1621mac_mount_label_get(struct mount *mp, user_addr_t mac_p)
1622{
1623 return mac_do_get(p: current_proc(), mac_p,
1624 getter: ^(char *input, char *output, size_t len) {
1625 return mac_mount_label_externalize(label: mac_mount_label(mp), elements: input,
1626 outbuf: output, outbuflen: len);
1627 });
1628}
1629
1630/*
1631 * __mac_get_mount: Get mount point label information for a given pathname
1632 *
1633 * Parameters: p (ignored)
1634 * uap User argument descriptor (see below)
1635 * ret (ignored)
1636 *
1637 * Indirect: uap->path Pathname
1638 * uap->mac_p MAC info
1639 *
1640 * Returns: 0 Success
1641 * !0 Not success
1642 */
1643int
1644__mac_get_mount(proc_t p __unused, struct __mac_get_mount_args *uap,
1645 int *ret __unused)
1646{
1647 struct nameidata nd;
1648 struct vfs_context *ctx = vfs_context_current();
1649 struct mount *mp;
1650 int error;
1651
1652 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | AUDITVNPATH1,
1653 UIO_USERSPACE, uap->path, ctx);
1654 error = namei(ndp: &nd);
1655 if (error) {
1656 return error;
1657 }
1658 mp = nd.ni_vp->v_mount;
1659 mount_ref(mp, 0);
1660 vnode_put(vp: nd.ni_vp);
1661 nameidone(&nd);
1662
1663 error = mac_mount_label_get(mp, mac_p: uap->mac_p);
1664 mount_drop(mp, 0);
1665 return error;
1666}
1667
1668/*
1669 * mac_schedule_userret()
1670 *
1671 * Schedule a callback to the mpo_thread_userret hook. The mpo_thread_userret
1672 * hook is called just before the thread exit from the kernel in ast_taken().
1673 *
1674 * Returns: 0 Success
1675 * !0 Not successful
1676 */
1677int
1678mac_schedule_userret(void)
1679{
1680 act_set_astmacf(current_thread());
1681 return 0;
1682}
1683
1684/*
1685 * mac_do_machexc()
1686 *
1687 * Do a Mach exception. This should only be done in the mpo_thread_userret
1688 * callback.
1689 *
1690 * params: code exception code
1691 * subcode exception subcode
1692 * flags flags:
1693 * MAC_DOEXCF_TRACED Only do exception if being
1694 * ptrace()'ed.
1695 *
1696 *
1697 * Returns: 0 Success
1698 * !0 Not successful
1699 */
1700int
1701mac_do_machexc(int64_t code, int64_t subcode, uint32_t flags)
1702{
1703 mach_exception_data_type_t codes[EXCEPTION_CODE_MAX];
1704 proc_t p = current_proc();
1705
1706 /* Only allow execption codes in MACF's reserved range. */
1707 if ((code < EXC_MACF_MIN) || (code > EXC_MACF_MAX)) {
1708 return 1;
1709 }
1710
1711 if (flags & MAC_DOEXCF_TRACED &&
1712 !(p->p_lflag & P_LTRACED && (p->p_lflag & P_LPPWAIT) == 0)) {
1713 return 0;
1714 }
1715
1716
1717 /* Send the Mach exception */
1718 codes[0] = (mach_exception_data_type_t)code;
1719 codes[1] = (mach_exception_data_type_t)subcode;
1720
1721 return bsd_exception(EXC_SOFTWARE, codes, 2) != KERN_SUCCESS;
1722}
1723
1724#else /* MAC */
1725
1726void (*load_security_extensions_function)(void) = 0;
1727
1728struct sysctl_oid_list sysctl__security_mac_children;
1729
1730int
1731mac_policy_register(struct mac_policy_conf *mpc __unused,
1732 mac_policy_handle_t *handlep __unused, void *xd __unused)
1733{
1734 return 0;
1735}
1736
1737int
1738mac_policy_unregister(mac_policy_handle_t handle __unused)
1739{
1740 return 0;
1741}
1742
1743int
1744mac_audit_text(char *text __unused, mac_policy_handle_t handle __unused)
1745{
1746 return 0;
1747}
1748
1749int
1750mac_vnop_setxattr(struct vnode *vp __unused, const char *name __unused, char *buf __unused, size_t len __unused)
1751{
1752 return ENOENT;
1753}
1754
1755int
1756mac_vnop_getxattr(struct vnode *vp __unused, const char *name __unused,
1757 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
1758{
1759 return ENOENT;
1760}
1761
1762int
1763mac_vnop_removexattr(struct vnode *vp __unused, const char *name __unused)
1764{
1765 return ENOENT;
1766}
1767
1768int
1769mac_file_setxattr(struct fileglob *fg __unused, const char *name __unused, char *buf __unused, size_t len __unused)
1770{
1771 return ENOENT;
1772}
1773
1774int
1775mac_file_getxattr(struct fileglob *fg __unused, const char *name __unused,
1776 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
1777{
1778 return ENOENT;
1779}
1780
1781int
1782mac_file_removexattr(struct fileglob *fg __unused, const char *name __unused)
1783{
1784 return ENOENT;
1785}
1786
1787intptr_t
1788mac_label_get(struct label *l __unused, int slot __unused)
1789{
1790 return 0;
1791}
1792
1793void
1794mac_label_set(struct label *l __unused, int slot __unused, intptr_t v __unused)
1795{
1796 return;
1797}
1798
1799int mac_iokit_check_hid_control(kauth_cred_t cred __unused);
1800int
1801mac_iokit_check_hid_control(kauth_cred_t cred __unused)
1802{
1803 return 0;
1804}
1805
1806int mac_vnode_check_open(vfs_context_t ctx, struct vnode *vp, int acc_mode);
1807int
1808mac_vnode_check_open(vfs_context_t ctx __unused, struct vnode *vp __unused, int acc_mode __unused)
1809{
1810 return 0;
1811}
1812
1813int mac_mount_check_snapshot_mount(vfs_context_t ctx, struct vnode *rvp, struct vnode *vp, struct componentname *cnp,
1814 const char *name, const char *vfc_name);
1815int
1816mac_mount_check_snapshot_mount(vfs_context_t ctx __unused, struct vnode *rvp __unused, struct vnode *vp __unused,
1817 struct componentname *cnp __unused, const char *name __unused, const char *vfc_name __unused)
1818{
1819 return 0;
1820}
1821
1822int mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused, struct vnode *dvp __unused, struct componentname *cnp __unused);
1823int
1824mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused, struct vnode *dvp __unused, struct componentname *cnp __unused)
1825{
1826 return 0;
1827}
1828
1829#endif /* !MAC */
1830