]> git.saurik.com Git - apple/xnu.git/blame_incremental - security/mac_base.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / security / mac_base.c
... / ...
CommitLineData
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(&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);
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(&mac_policy_mtx);
287 thread_wakeup((event_t) &mac_policy_busy);
288}
289
290void
291mac_policy_list_busy(void)
292{
293 lck_mtx_lock(&mac_policy_mtx);
294 mac_policy_busy++;
295 lck_mtx_unlock(&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(&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(&mac_policy_mtx);
315 return ret;
316}
317
318void
319mac_policy_list_unbusy(void)
320{
321 lck_mtx_lock(&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(&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_flags(
347 sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE,
348 Z_WAITOK | Z_ZERO);
349#endif
350
351 LIST_INIT(&mac_label_element_list);
352 LIST_INIT(&mac_static_label_element_list);
353}
354
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()
358 * after bsd_init().
359 */
360void (*load_security_extensions_function)(void) = 0;
361
362/*
363 * Init after early Mach startup, but before BSD
364 */
365void
366mac_policy_initmach(void)
367{
368 /*
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
372 * kernel startup.
373 */
374
375 if (load_security_extensions_function) {
376 load_security_extensions_function();
377 }
378 mac_late = 1;
379}
380
381/*
382 * BSD startup.
383 */
384void
385mac_policy_initbsd(void)
386{
387 struct mac_policy_conf *mpc;
388 u_int i;
389
390 printf("MAC Framework successfully initialized\n");
391
392 /* Call bsd init functions of already loaded policies */
393
394 /*
395 * Using the exclusive lock means no other framework entry
396 * points can proceed while initializations are running.
397 * This may not be necessary.
398 */
399 mac_policy_grab_exclusive();
400
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);
405 }
406 }
407
408 mac_policy_release_exclusive();
409}
410
411/*
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
415 * the lists.
416 */
417void
418mac_policy_addto_labellist(mac_policy_handle_t handle, int static_entry)
419{
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;
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 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);
455 }
456 mle_free = 0;
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);
463 }
464 mll_free = 0;
465
466 if (mac_late) {
467 mac_policy_grab_exclusive();
468 }
469 for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
470 if (*(name = mpc->mpc_labelnames[idx]) == '?') {
471 name++;
472 }
473 /*
474 * Check both label element lists and add to the
475 * appropriate list only if not already on a list.
476 */
477 LIST_FOREACH(mle, &mac_static_label_element_list, mle_list) {
478 if (*(name2 = mle->mle_name) == '?') {
479 name2++;
480 }
481 if (strcmp(name, name2) == 0) {
482 break;
483 }
484 }
485 if (mle == NULL) {
486 LIST_FOREACH(mle, &mac_label_element_list, mle_list) {
487 if (*(name2 = mle->mle_name) == '?') {
488 name2++;
489 }
490 if (strcmp(name, name2) == 0) {
491 break;
492 }
493 }
494 }
495 if (mle == NULL) {
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);
501 mle_free++;
502 }
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],
506 mll_list);
507 mll_free++;
508 }
509 if (mac_late) {
510 mac_policy_release_exclusive();
511 }
512
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);
516 }
517 FREE(new_mles, M_MACTEMP);
518 for (idx = mll_free; idx < mpc->mpc_labelname_count; idx++) {
519 FREE(new_mlls[idx], M_MACTEMP);
520 }
521 FREE(new_mlls, M_MACTEMP);
522}
523
524/*
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
528 * namespace.
529 *
530 * Must be called with the policy exclusive lock held.
531 */
532void
533mac_policy_removefrom_labellist(mac_policy_handle_t handle)
534{
535 struct mac_label_listener *mll;
536 struct mac_label_element *mle;
537 struct mac_policy_conf *mpc;
538
539 mpc = mac_get_mpc(handle);
540
541 if (mpc->mpc_labelnames == NULL) {
542 return;
543 }
544
545 if (mpc->mpc_labelname_count == 0) {
546 return;
547 }
548
549 /*
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.
554 */
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);
563 }
564 return;
565 }
566 }
567 }
568}
569
570/*
571 * After the policy list has changed, walk the list to update any global
572 * flags.
573 */
574static void
575mac_policy_updateflags(void)
576{
577}
578
579static __inline void
580mac_policy_fixup_mmd_list(struct mac_module_data *new)
581{
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;
586
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,
609 &(dict->list[k]));
610 }
611 }
612 }
613 }
614 }
615 new->base_addr = new;
616}
617
618int
619mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep,
620 void *xd)
621{
622#if XNU_TARGET_OS_OSX
623 struct mac_policy_list_element *tmac_policy_list_element;
624#endif
625 int error, slot, static_entry = 0;
626 u_int i;
627
628 /*
629 * Some preliminary checks to make sure the policy's conf structure
630 * contains the required fields.
631 */
632 if (mpc->mpc_name == NULL) {
633 panic("policy's name is not set\n");
634 }
635
636 if (mpc->mpc_fullname == NULL) {
637 panic("policy's full name is not set\n");
638 }
639
640 if (mpc->mpc_labelname_count > MAC_MAX_MANAGED_NAMESPACES) {
641 panic("policy's managed label namespaces exceeds maximum\n");
642 }
643
644 if (mpc->mpc_ops == NULL) {
645 panic("policy's OPs field is NULL\n");
646 }
647
648 error = 0;
649
650 if (mac_late) {
651 if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE) {
652 printf("Module %s does not support late loading.\n",
653 mpc->mpc_name);
654 return EPERM;
655 }
656 mac_policy_grab_exclusive();
657 }
658
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);
668
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);
673
674 /* free old array */
675 kfree(mac_policy_list.entries,
676 sizeof(struct mac_policy_list_element) *
677 MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks);
678
679 mac_policy_list.entries = tmac_policy_list_element;
680
681 /* Update maximums, etc */
682 mac_policy_list.max += MAC_POLICY_LIST_CHUNKSIZE;
683 mac_policy_list.chunks++;
684#else
685 printf("out of space in mac_policy_list.\n");
686 return ENOMEM;
687#endif /* XNU_TARGET_OS_OSX */
688 }
689
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) {
693 continue;
694 }
695
696 if (strcmp(mac_policy_list.entries[i].mpc->mpc_name,
697 mpc->mpc_name) == 0) {
698 error = EEXIST;
699 goto out;
700 }
701 }
702
703 if (mpc->mpc_field_off != NULL) {
704 slot = ffs(mac_slot_offsets_free);
705 if (slot == 0) {
706 error = ENOMEM;
707 goto out;
708 }
709 slot--;
710 mac_slot_offsets_free &= ~(1 << slot);
711 *mpc->mpc_field_off = slot;
712 }
713 mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
714
715 if (xd) {
716 struct mac_module_data *mmd = xd; /* module data from plist */
717
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);
722
723 /* Fix up pointers after copy. */
724 mac_policy_fixup_mmd_list(mpc->mpc_data);
725 }
726 }
727
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) {
731 *handlep = i;
732 mac_policy_list.freehint = ++i;
733 break;
734 }
735 }
736
737 /*
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.
743 */
744 if (!mac_late ||
745 ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0 &&
746 *handlep == mac_policy_list.staticmax)) {
747 static_entry = 1;
748 mac_policy_list.staticmax++;
749 }
750
751 mac_policy_list.entries[*handlep].mpc = mpc;
752
753 /* Update counters, etc */
754 if (*handlep > mac_policy_list.maxindex) {
755 mac_policy_list.maxindex = *handlep;
756 }
757 mac_policy_list.numloaded++;
758
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);
763 }
764
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);
768 }
769
770 mac_policy_updateflags();
771
772 if (mac_late) {
773 mac_policy_release_exclusive();
774 }
775
776 mac_policy_addto_labellist(*handlep, static_entry);
777
778 printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
779 mpc->mpc_name);
780
781 return 0;
782
783out:
784 if (mac_late) {
785 mac_policy_release_exclusive();
786 }
787
788 return error;
789}
790
791int
792mac_policy_unregister(mac_policy_handle_t handle)
793{
794 struct mac_policy_conf *mpc;
795
796 /*
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,
799 * silently succeed.
800 */
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();
805 return 0;
806 }
807
808#if 0
809 /*
810 * Don't allow unloading modules with private data.
811 */
812 if (mpc->mpc_field_off != NULL) {
813 MAC_POLICY_LIST_UNLOCK();
814 return EBUSY;
815 }
816#endif
817 /*
818 * Only allow the unload to proceed if the module is unloadable
819 * by its own definition.
820 */
821 if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
822 mac_policy_release_exclusive();
823 return EBUSY;
824 }
825
826 mac_policy_removefrom_labellist(handle);
827
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;
832 }
833
834 if (handle == mac_policy_list.maxindex) {
835 mac_policy_list.maxindex--;
836 }
837
838 mac_policy_list.numloaded--;
839 if (mpc->mpc_field_off != NULL) {
840 mac_slot_offsets_free |= (1 << *mpc->mpc_field_off);
841 }
842
843 if (mpc->mpc_ops->mpo_policy_destroy != NULL) {
844 (*(mpc->mpc_ops->mpo_policy_destroy))(mpc);
845 }
846
847 mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
848 mac_policy_updateflags();
849
850 mac_policy_release_exclusive();
851
852 if (mpc->mpc_data) {
853 struct mac_module_data *mmd = mpc->mpc_data;
854 kfree(mmd, mmd->size);
855 mpc->mpc_data = NULL;
856 }
857
858 printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
859 mpc->mpc_name);
860
861 return 0;
862}
863
864/*
865 * Define an error value precedence, and given two arguments, selects the
866 * value with the higher precedence.
867 */
868int
869mac_error_select(int error1, int error2)
870{
871 /* Certain decision-making errors take top priority. */
872 if (error1 == EDEADLK || error2 == EDEADLK) {
873 return EDEADLK;
874 }
875
876 /* Invalid arguments should be reported where possible. */
877 if (error1 == EINVAL || error2 == EINVAL) {
878 return EINVAL;
879 }
880
881 /* Precedence goes to "visibility", with both process and file. */
882 if (error1 == ESRCH || error2 == ESRCH) {
883 return ESRCH;
884 }
885
886 if (error1 == ENOENT || error2 == ENOENT) {
887 return ENOENT;
888 }
889
890 /* Precedence goes to DAC/MAC protections. */
891 if (error1 == EACCES || error2 == EACCES) {
892 return EACCES;
893 }
894
895 /* Precedence goes to privilege. */
896 if (error1 == EPERM || error2 == EPERM) {
897 return EPERM;
898 }
899
900 /* Precedence goes to error over success; otherwise, arbitrary. */
901 if (error1 != 0) {
902 return error1;
903 }
904 return error2;
905}
906
907void
908mac_label_init(struct label *label)
909{
910 bzero(label, sizeof(*label));
911 label->l_flags = MAC_FLAG_INITIALIZED;
912}
913
914void
915mac_label_destroy(struct label *label)
916{
917 KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
918 ("destroying uninitialized label"));
919
920 bzero(label, sizeof(*label));
921 /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
922}
923
924int
925mac_check_structmac_consistent(struct user_mac *mac)
926{
927 if (mac->m_buflen > MAC_MAX_LABEL_BUF_LEN || mac->m_buflen == 0) {
928 return EINVAL;
929 }
930
931 return 0;
932}
933
934/*
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 '?'.
938 */
939static int
940mac_label_externalize(size_t mpo_externalize_off, struct label *label,
941 const char *element, struct sbuf *sb)
942{
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;
947 const char *name;
948 int (*mpo_externalize)(struct label *, char *, struct sbuf *);
949 int all_labels = 0, ignorenotfound = 0, error = 0, busy = FALSE;
950 int sb_pos;
951 unsigned int count = 0;
952
953 if (element[0] == '?') {
954 element++;
955 ignorenotfound = 1;
956 } else if (element[0] == '*' && element[1] == '\0') {
957 all_labels = 1;
958 }
959
960 element_list = &mac_static_label_element_list;
961element_loop:
962 LIST_FOREACH(mle, element_list, mle_list) {
963 name = mle->mle_name;
964 if (all_labels) {
965 if (*name == '?') {
966 continue;
967 }
968 } else {
969 if (*name == '?') {
970 name++;
971 }
972 if (strcmp(name, element) != 0) {
973 continue;
974 }
975 }
976 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
977 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
978 if (mpc == NULL) {
979 continue;
980 }
981 mpo_externalize = *(const typeof(mpo_externalize) *)
982 ((const char *)mpc->mpc_ops + mpo_externalize_off);
983 if (mpo_externalize == NULL) {
984 continue;
985 }
986 sb_pos = sbuf_len(sb);
987 error = sbuf_printf(sb, "%s/", name);
988 if (error) {
989 goto done;
990 }
991 error = mpo_externalize(label, mle->mle_name, sb);
992 if (error) {
993 if (error != ENOENT) {
994 goto done;
995 }
996 /*
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.
1002 */
1003 sbuf_setpos(sb, sb_pos);
1004 error = 0;
1005 continue;
1006 }
1007 error = sbuf_putc(sb, ',');
1008 if (error) {
1009 goto done;
1010 }
1011 count++;
1012 }
1013 }
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;
1017 busy = TRUE;
1018 goto element_loop;
1019 }
1020done:
1021 if (busy) {
1022 mac_policy_list_unbusy();
1023 }
1024 if (!error && count == 0) {
1025 if (!all_labels && !ignorenotfound) {
1026 error = ENOENT; /* XXX: ENOLABEL? */
1027 }
1028 }
1029 return error;
1030}
1031
1032/*
1033 * Get the external forms of labels from all policies, for all label
1034 * namespaces contained in a list.
1035 *
1036 * XXX This may be leaking an sbuf.
1037 */
1038int
1039mac_externalize(size_t mpo_externalize_off, struct label *label,
1040 const char *elementlist, char *outbuf, size_t outbuflen)
1041{
1042 char *element;
1043 char *scratch_base;
1044 char *scratch;
1045 struct sbuf sb;
1046 int error = 0, len;
1047
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) {
1051 error = ENOMEM;
1052 goto out;
1053 }
1054
1055 /* copy the elementlist to the scratch buffer */
1056 strlcpy(scratch_base, elementlist, strlen(elementlist) + 1);
1057
1058 /*
1059 * set up a temporary pointer that can be used to iterate the
1060 * scratch buffer without losing the allocation address
1061 */
1062 scratch = scratch_base;
1063
1064 /*
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.
1067 */
1068 if (outbuflen > INT_MAX) {
1069 outbuflen = INT_MAX;
1070 }
1071 if (sbuf_new(&sb, outbuf, (int)outbuflen, SBUF_FIXEDLEN) == NULL) {
1072 /* could not allocate interior buffer */
1073 error = ENOMEM;
1074 goto out;
1075 }
1076 /* iterate the scratch buffer; NOTE: buffer contents modified! */
1077 while ((element = strsep(&scratch, ",")) != NULL) {
1078 error = mac_label_externalize(mpo_externalize_off, label,
1079 element, &sb);
1080 if (error) {
1081 break;
1082 }
1083 }
1084 if ((len = sbuf_len(&sb)) > 0) {
1085 sbuf_setpos(&sb, len - 1); /* trim trailing comma */
1086 }
1087 sbuf_finish(&sb);
1088
1089out:
1090 if (scratch_base != NULL) {
1091 FREE(scratch_base, M_MACTEMP);
1092 }
1093
1094 return error;
1095}
1096
1097/*
1098 * Have all policies set the internal form of a label, for a single
1099 * label namespace.
1100 */
1101static int
1102mac_label_internalize(size_t mpo_internalize_off, struct label *label,
1103 char *element_name, char *element_data)
1104{
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;
1112 const char *name;
1113
1114 element_list = &mac_static_label_element_list;
1115element_loop:
1116 LIST_FOREACH(mle, element_list, mle_list) {
1117 if (*(name = mle->mle_name) == '?') {
1118 name++;
1119 }
1120 if (strcmp(element_name, name) != 0) {
1121 continue;
1122 }
1123 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1124 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
1125 if (mpc == NULL) {
1126 continue;
1127 }
1128 mpo_internalize = *(const typeof(mpo_internalize) *)
1129 ((const char *)mpc->mpc_ops + mpo_internalize_off);
1130 if (mpo_internalize == NULL) {
1131 continue;
1132 }
1133 error = mpo_internalize(label, element_name,
1134 element_data);
1135 if (error) {
1136 goto done;
1137 }
1138 count++;
1139 }
1140 }
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;
1144 busy = TRUE;
1145 goto element_loop;
1146 }
1147done:
1148 if (busy) {
1149 mac_policy_list_unbusy();
1150 }
1151 if (!error && count == 0) {
1152 error = ENOPOLICY;
1153 }
1154 return error;
1155}
1156
1157int
1158mac_internalize(size_t mpo_internalize_off, struct label *label,
1159 char *textlabels)
1160{
1161 char *element_name, *element_data;
1162 int error = 0;
1163
1164 while (!error && (element_name = strsep(&textlabels, ",")) != NULL) {
1165 element_data = strchr(element_name, '/');
1166 if (element_data == NULL) {
1167 error = EINVAL;
1168 break;
1169 }
1170 *element_data++ = '\0';
1171 error = mac_label_internalize(mpo_internalize_off, label,
1172 element_name, element_data);
1173 }
1174 return error;
1175}
1176
1177/* system calls */
1178
1179int
1180__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, int *ret __unused)
1181{
1182 char *elements, *buffer;
1183 struct user_mac mac;
1184 struct proc *tproc;
1185 struct ucred *tcred;
1186 int error;
1187 size_t ulen;
1188
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;
1195 } else {
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;
1200 }
1201 if (error) {
1202 return error;
1203 }
1204
1205 error = mac_check_structmac_consistent(&mac);
1206 if (error) {
1207 return error;
1208 }
1209
1210 tproc = proc_find(uap->pid);
1211 if (tproc == NULL) {
1212 return ESRCH;
1213 }
1214 tcred = kauth_cred_proc_ref(tproc);
1215 proc_rele(tproc);
1216
1217 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1218 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1219 if (error) {
1220 FREE(elements, M_MACTEMP);
1221 kauth_cred_unref(&tcred);
1222 return error;
1223 }
1224 AUDIT_ARG(mac_string, elements);
1225
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);
1229 if (error == 0) {
1230 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1231 }
1232
1233 FREE(buffer, M_MACTEMP);
1234 FREE(elements, M_MACTEMP);
1235 kauth_cred_unref(&tcred);
1236 return error;
1237}
1238
1239int
1240__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, int *ret __unused)
1241{
1242 char *elements, *buffer;
1243 struct user_mac mac;
1244 kauth_cred_t cr;
1245 int error;
1246 size_t ulen;
1247
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;
1253 } else {
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;
1258 }
1259 if (error) {
1260 return error;
1261 }
1262
1263 error = mac_check_structmac_consistent(&mac);
1264 if (error) {
1265 return error;
1266 }
1267
1268 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1269 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1270 if (error) {
1271 FREE(elements, M_MACTEMP);
1272 return error;
1273 }
1274 AUDIT_ARG(mac_string, elements);
1275
1276 cr = kauth_cred_proc_ref(p);
1277
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);
1281 if (error == 0) {
1282 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1283 }
1284
1285 FREE(buffer, M_MACTEMP);
1286 FREE(elements, M_MACTEMP);
1287 kauth_cred_unref(&cr);
1288 return error;
1289}
1290
1291int
1292__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, int *ret __unused)
1293{
1294 struct label *intlabel;
1295 struct user_mac mac;
1296 char *buffer;
1297 int error;
1298 size_t ulen;
1299
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;
1305 } else {
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;
1310 }
1311 if (error) {
1312 return error;
1313 }
1314
1315 error = mac_check_structmac_consistent(&mac);
1316 if (error) {
1317 return error;
1318 }
1319
1320 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1321 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1322 if (error) {
1323 FREE(buffer, M_MACTEMP);
1324 return error;
1325 }
1326 AUDIT_ARG(mac_string, buffer);
1327
1328 intlabel = mac_cred_label_alloc();
1329 error = mac_cred_label_internalize(intlabel, buffer);
1330 FREE(buffer, M_MACTEMP);
1331 if (error) {
1332 goto out;
1333 }
1334
1335 error = mac_cred_check_label_update(kauth_cred_get(), intlabel);
1336 if (error) {
1337 goto out;
1338 }
1339
1340 error = kauth_proc_label_update(p, intlabel);
1341 if (error) {
1342 goto out;
1343 }
1344
1345out:
1346 mac_cred_label_free(intlabel);
1347 return error;
1348}
1349
1350int
1351__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, int *ret __unused)
1352{
1353 struct fileproc *fp;
1354 struct vnode *vp;
1355 struct user_mac mac;
1356 char *elements, *buffer;
1357 int error;
1358 size_t ulen;
1359 kauth_cred_t my_cred;
1360 struct label *intlabel;
1361
1362 AUDIT_ARG(fd, uap->fd);
1363
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;
1369 } else {
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;
1374 }
1375
1376 if (error) {
1377 return error;
1378 }
1379
1380 error = mac_check_structmac_consistent(&mac);
1381 if (error) {
1382 return error;
1383 }
1384
1385 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1386 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1387 if (error) {
1388 FREE(elements, M_MACTEMP);
1389 return error;
1390 }
1391 AUDIT_ARG(mac_string, elements);
1392
1393 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1394 error = fp_lookup(p, uap->fd, &fp, 0);
1395 if (error) {
1396 FREE(buffer, M_MACTEMP);
1397 FREE(elements, M_MACTEMP);
1398 return error;
1399 }
1400
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);
1404 if (error) {
1405 fp_drop(p, uap->fd, fp, 0);
1406 FREE(buffer, M_MACTEMP);
1407 FREE(elements, M_MACTEMP);
1408 return error;
1409 }
1410
1411 switch (FILEGLOB_DTYPE(fp->fp_glob)) {
1412 case DTYPE_VNODE:
1413 intlabel = mac_vnode_label_alloc();
1414 if (intlabel == NULL) {
1415 error = ENOMEM;
1416 break;
1417 }
1418 vp = (struct vnode *)fp->fp_glob->fg_data;
1419 error = vnode_getwithref(vp);
1420 if (error == 0) {
1421 mac_vnode_label_copy(vp->v_label, intlabel);
1422 error = mac_vnode_label_externalize(intlabel,
1423 elements, buffer,
1424 mac.m_buflen, M_WAITOK);
1425 vnode_put(vp);
1426 }
1427 mac_vnode_label_free(intlabel);
1428 break;
1429 case DTYPE_SOCKET:
1430 case DTYPE_PSXSHM:
1431 case DTYPE_PSXSEM:
1432 case DTYPE_PIPE:
1433 case DTYPE_KQUEUE:
1434 case DTYPE_FSEVENTS:
1435 case DTYPE_ATALK:
1436 case DTYPE_NETPOLICY:
1437 default:
1438 error = ENOSYS; // only sockets/vnodes so far
1439 break;
1440 }
1441 fp_drop(p, uap->fd, fp, 0);
1442
1443 if (error == 0) {
1444 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1445 }
1446
1447 FREE(buffer, M_MACTEMP);
1448 FREE(elements, M_MACTEMP);
1449 return error;
1450}
1451
1452static int
1453mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow)
1454{
1455 struct vnode *vp;
1456 vfs_context_t ctx;
1457 char *elements, *buffer;
1458 struct nameidata nd;
1459 struct label *intlabel;
1460 struct user_mac mac;
1461 int error;
1462 size_t ulen;
1463
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;
1469 } else {
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;
1474 }
1475
1476 if (error) {
1477 return error;
1478 }
1479
1480 error = mac_check_structmac_consistent(&mac);
1481 if (error) {
1482 return error;
1483 }
1484
1485 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1486 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1487
1488 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1489 if (error) {
1490 FREE(buffer, M_MACTEMP);
1491 FREE(elements, M_MACTEMP);
1492 return error;
1493 }
1494 AUDIT_ARG(mac_string, elements);
1495
1496 ctx = vfs_context_current();
1497
1498 NDINIT(&nd, LOOKUP, OP_LOOKUP,
1499 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1500 UIO_USERSPACE, path_p, ctx);
1501 error = namei(&nd);
1502 if (error) {
1503 FREE(buffer, M_MACTEMP);
1504 FREE(elements, M_MACTEMP);
1505 return error;
1506 }
1507 vp = nd.ni_vp;
1508
1509 nameidone(&nd);
1510
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);
1516 if (error == 0) {
1517 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1518 }
1519
1520 vnode_put(vp);
1521
1522 FREE(buffer, M_MACTEMP);
1523 FREE(elements, M_MACTEMP);
1524
1525 return error;
1526}
1527
1528int
1529__mac_get_file(proc_t p, struct __mac_get_file_args *uap,
1530 int *ret __unused)
1531{
1532 return mac_get_filelink(p, uap->mac_p, uap->path_p, 1);
1533}
1534
1535int
1536__mac_get_link(proc_t p, struct __mac_get_link_args *uap,
1537 int *ret __unused)
1538{
1539 return mac_get_filelink(p, uap->mac_p, uap->path_p, 0);
1540}
1541
1542int
1543__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, int *ret __unused)
1544{
1545 struct fileproc *fp;
1546 struct user_mac mac;
1547 struct vfs_context *ctx = vfs_context_current();
1548 int error;
1549 size_t ulen;
1550 char *buffer;
1551 struct label *intlabel;
1552 struct vnode *vp;
1553
1554 AUDIT_ARG(fd, uap->fd);
1555
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;
1561 } else {
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;
1566 }
1567 if (error) {
1568 return error;
1569 }
1570
1571 error = mac_check_structmac_consistent(&mac);
1572 if (error) {
1573 return error;
1574 }
1575
1576 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1577 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1578 if (error) {
1579 FREE(buffer, M_MACTEMP);
1580 return error;
1581 }
1582 AUDIT_ARG(mac_string, buffer);
1583
1584 error = fp_lookup(p, uap->fd, &fp, 0);
1585 if (error) {
1586 FREE(buffer, M_MACTEMP);
1587 return error;
1588 }
1589
1590
1591 error = mac_file_check_set(vfs_context_ucred(ctx), fp->fp_glob, buffer, mac.m_buflen);
1592 if (error) {
1593 fp_drop(p, uap->fd, fp, 0);
1594 FREE(buffer, M_MACTEMP);
1595 return error;
1596 }
1597
1598 switch (FILEGLOB_DTYPE(fp->fp_glob)) {
1599 case DTYPE_VNODE:
1600 if (mac_label_vnodes == 0) {
1601 error = ENOSYS;
1602 break;
1603 }
1604
1605 intlabel = mac_vnode_label_alloc();
1606
1607 error = mac_vnode_label_internalize(intlabel, buffer);
1608 if (error) {
1609 mac_vnode_label_free(intlabel);
1610 break;
1611 }
1612
1613
1614 vp = (struct vnode *)fp->fp_glob->fg_data;
1615
1616 error = vnode_getwithref(vp);
1617 if (error == 0) {
1618 error = vn_setlabel(vp, intlabel, ctx);
1619 vnode_put(vp);
1620 }
1621 mac_vnode_label_free(intlabel);
1622 break;
1623
1624 case DTYPE_SOCKET:
1625 case DTYPE_PSXSHM:
1626 case DTYPE_PSXSEM:
1627 case DTYPE_PIPE:
1628 case DTYPE_KQUEUE:
1629 case DTYPE_FSEVENTS:
1630 case DTYPE_ATALK:
1631 case DTYPE_NETPOLICY:
1632 default:
1633 error = ENOSYS; // only sockets/vnodes so far
1634 break;
1635 }
1636
1637 fp_drop(p, uap->fd, fp, 0);
1638 FREE(buffer, M_MACTEMP);
1639 return error;
1640}
1641
1642static int
1643mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p,
1644 int follow)
1645{
1646 struct vnode *vp;
1647 struct vfs_context *ctx = vfs_context_current();
1648 struct label *intlabel;
1649 struct nameidata nd;
1650 struct user_mac mac;
1651 char *buffer;
1652 int error;
1653 size_t ulen;
1654
1655 if (mac_label_vnodes == 0) {
1656 return ENOSYS;
1657 }
1658
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;
1664 } else {
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;
1669 }
1670 if (error) {
1671 return error;
1672 }
1673
1674 error = mac_check_structmac_consistent(&mac);
1675 if (error) {
1676 printf("mac_set_file: failed structure consistency check\n");
1677 return error;
1678 }
1679
1680 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1681 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1682 if (error) {
1683 FREE(buffer, M_MACTEMP);
1684 return error;
1685 }
1686 AUDIT_ARG(mac_string, buffer);
1687
1688 intlabel = mac_vnode_label_alloc();
1689 error = mac_vnode_label_internalize(intlabel, buffer);
1690 FREE(buffer, M_MACTEMP);
1691 if (error) {
1692 mac_vnode_label_free(intlabel);
1693 return error;
1694 }
1695
1696 NDINIT(&nd, LOOKUP, OP_LOOKUP,
1697 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1698 UIO_USERSPACE, path_p, ctx);
1699 error = namei(&nd);
1700 if (error) {
1701 mac_vnode_label_free(intlabel);
1702 return error;
1703 }
1704 vp = nd.ni_vp;
1705
1706 nameidone(&nd);
1707
1708 error = vn_setlabel(vp, intlabel, ctx);
1709 vnode_put(vp);
1710 mac_vnode_label_free(intlabel);
1711
1712 return error;
1713}
1714
1715int
1716__mac_set_file(proc_t p, struct __mac_set_file_args *uap,
1717 int *ret __unused)
1718{
1719 return mac_set_filelink(p, uap->mac_p, uap->path_p, 1);
1720}
1721
1722int
1723__mac_set_link(proc_t p, struct __mac_set_link_args *uap,
1724 int *ret __unused)
1725{
1726 return mac_set_filelink(p, uap->mac_p, uap->path_p, 0);
1727}
1728
1729/*
1730 * __mac_syscall: Perform a MAC policy system call
1731 *
1732 * Parameters: p Process calling this routine
1733 * uap User argument descriptor (see below)
1734 * retv (Unused)
1735 *
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
1739 *
1740 * Returns: 0 Success
1741 * !0 Not success
1742 *
1743 */
1744int
1745__mac_syscall(proc_t p, struct __mac_syscall_args *uap, int *retv __unused)
1746{
1747 struct mac_policy_conf *mpc;
1748 char target[MAC_MAX_POLICY_NAME];
1749 int error;
1750 u_int i;
1751 size_t ulen;
1752
1753 error = copyinstr(uap->policy, target, sizeof(target), &ulen);
1754 if (error) {
1755 return error;
1756 }
1757 AUDIT_ARG(value32, uap->call);
1758 AUDIT_ARG(mac_string, target);
1759
1760 error = ENOPOLICY;
1761
1762 for (i = 0; i < mac_policy_list.staticmax; i++) {
1763 mpc = mac_policy_list.entries[i].mpc;
1764 if (mpc == NULL) {
1765 continue;
1766 }
1767
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);
1772 goto done;
1773 }
1774 }
1775 if (mac_policy_list_conditional_busy() != 0) {
1776 for (; i <= mac_policy_list.maxindex; i++) {
1777 mpc = mac_policy_list.entries[i].mpc;
1778 if (mpc == NULL) {
1779 continue;
1780 }
1781
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);
1786 break;
1787 }
1788 }
1789 mac_policy_list_unbusy();
1790 }
1791
1792done:
1793 return error;
1794}
1795
1796int
1797mac_mount_label_get(struct mount *mp, user_addr_t mac_p)
1798{
1799 char *elements, *buffer;
1800 struct label *label;
1801 struct user_mac mac;
1802 int error;
1803 size_t ulen;
1804
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;
1810 } else {
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;
1815 }
1816 if (error) {
1817 return error;
1818 }
1819
1820 error = mac_check_structmac_consistent(&mac);
1821 if (error) {
1822 return error;
1823 }
1824
1825 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1826 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1827 if (error) {
1828 FREE(elements, M_MACTEMP);
1829 return error;
1830 }
1831 AUDIT_ARG(mac_string, elements);
1832
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,
1836 mac.m_buflen);
1837 FREE(elements, M_MACTEMP);
1838
1839 if (error == 0) {
1840 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1841 }
1842 FREE(buffer, M_MACTEMP);
1843
1844 return error;
1845}
1846
1847/*
1848 * __mac_get_mount: Get mount point label information for a given pathname
1849 *
1850 * Parameters: p (ignored)
1851 * uap User argument descriptor (see below)
1852 * ret (ignored)
1853 *
1854 * Indirect: uap->path Pathname
1855 * uap->mac_p MAC info
1856 *
1857 * Returns: 0 Success
1858 * !0 Not success
1859 */
1860int
1861__mac_get_mount(proc_t p __unused, struct __mac_get_mount_args *uap,
1862 int *ret __unused)
1863{
1864 struct nameidata nd;
1865 struct vfs_context *ctx = vfs_context_current();
1866 struct mount *mp;
1867 int error;
1868
1869 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | AUDITVNPATH1,
1870 UIO_USERSPACE, uap->path, ctx);
1871 error = namei(&nd);
1872 if (error) {
1873 return error;
1874 }
1875 mp = nd.ni_vp->v_mount;
1876 mount_ref(mp, 0);
1877 vnode_put(nd.ni_vp);
1878 nameidone(&nd);
1879
1880 error = mac_mount_label_get(mp, uap->mac_p);
1881 mount_drop(mp, 0);
1882 return error;
1883}
1884
1885/*
1886 * mac_schedule_userret()
1887 *
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().
1890 *
1891 * Returns: 0 Success
1892 * !0 Not successful
1893 */
1894int
1895mac_schedule_userret(void)
1896{
1897 act_set_astmacf(current_thread());
1898 return 0;
1899}
1900
1901/*
1902 * mac_do_machexc()
1903 *
1904 * Do a Mach exception. This should only be done in the mpo_thread_userret
1905 * callback.
1906 *
1907 * params: code exception code
1908 * subcode exception subcode
1909 * flags flags:
1910 * MAC_DOEXCF_TRACED Only do exception if being
1911 * ptrace()'ed.
1912 *
1913 *
1914 * Returns: 0 Success
1915 * !0 Not successful
1916 */
1917int
1918mac_do_machexc(int64_t code, int64_t subcode, uint32_t flags)
1919{
1920 mach_exception_data_type_t codes[EXCEPTION_CODE_MAX];
1921 proc_t p = current_proc();
1922
1923 /* Only allow execption codes in MACF's reserved range. */
1924 if ((code < EXC_MACF_MIN) || (code > EXC_MACF_MAX)) {
1925 return 1;
1926 }
1927
1928 if (flags & MAC_DOEXCF_TRACED &&
1929 !(p->p_lflag & P_LTRACED && (p->p_lflag & P_LPPWAIT) == 0)) {
1930 return 0;
1931 }
1932
1933
1934 /* Send the Mach exception */
1935 codes[0] = (mach_exception_data_type_t)code;
1936 codes[1] = (mach_exception_data_type_t)subcode;
1937
1938 return bsd_exception(EXC_SOFTWARE, codes, 2) != KERN_SUCCESS;
1939}
1940
1941#else /* MAC */
1942
1943void (*load_security_extensions_function)(void) = 0;
1944
1945struct sysctl_oid_list sysctl__security_mac_children;
1946
1947int
1948mac_policy_register(struct mac_policy_conf *mpc __unused,
1949 mac_policy_handle_t *handlep __unused, void *xd __unused)
1950{
1951 return 0;
1952}
1953
1954int
1955mac_policy_unregister(mac_policy_handle_t handle __unused)
1956{
1957 return 0;
1958}
1959
1960int
1961mac_audit_text(char *text __unused, mac_policy_handle_t handle __unused)
1962{
1963 return 0;
1964}
1965
1966int
1967mac_vnop_setxattr(struct vnode *vp __unused, const char *name __unused, char *buf __unused, size_t len __unused)
1968{
1969 return ENOENT;
1970}
1971
1972int
1973mac_vnop_getxattr(struct vnode *vp __unused, const char *name __unused,
1974 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
1975{
1976 return ENOENT;
1977}
1978
1979int
1980mac_vnop_removexattr(struct vnode *vp __unused, const char *name __unused)
1981{
1982 return ENOENT;
1983}
1984
1985int
1986mac_file_setxattr(struct fileglob *fg __unused, const char *name __unused, char *buf __unused, size_t len __unused)
1987{
1988 return ENOENT;
1989}
1990
1991int
1992mac_file_getxattr(struct fileglob *fg __unused, const char *name __unused,
1993 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
1994{
1995 return ENOENT;
1996}
1997
1998int
1999mac_file_removexattr(struct fileglob *fg __unused, const char *name __unused)
2000{
2001 return ENOENT;
2002}
2003
2004intptr_t
2005mac_label_get(struct label *l __unused, int slot __unused)
2006{
2007 return 0;
2008}
2009
2010void
2011mac_label_set(struct label *l __unused, int slot __unused, intptr_t v __unused)
2012{
2013 return;
2014}
2015
2016int mac_iokit_check_hid_control(kauth_cred_t cred __unused);
2017int
2018mac_iokit_check_hid_control(kauth_cred_t cred __unused)
2019{
2020 return 0;
2021}
2022
2023int 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);
2025int
2026mac_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)
2028{
2029 return 0;
2030}
2031
2032int mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused, struct vnode *dvp __unused, struct componentname *cnp __unused);
2033int
2034mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused, struct vnode *dvp __unused, struct componentname *cnp __unused)
2035{
2036 return 0;
2037}
2038
2039#endif /* !MAC */