]> git.saurik.com Git - apple/xnu.git/blame - security/mac_base.c
xnu-7195.101.1.tar.gz
[apple/xnu.git] / security / mac_base.c
CommitLineData
2d21ac55 1/*
f427ee49 2 * Copyright (c) 2007-2020 Apple Inc. All rights reserved.
2d21ac55
A
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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.
0a7de745 25 *
2d21ac55
A
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>
b0d623f7 82#include <bsd/security/audit/audit.h>
f427ee49 83#include <bsd/security/audit/audit_private.h>
2d21ac55
A
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
316670eb 92#include <mach/exception_types.h>
2d21ac55
A
93#include <mach/vm_types.h>
94#include <mach/vm_prot.h>
95
f427ee49 96#include <kern/kalloc.h>
2d21ac55 97#include <kern/sched_prim.h>
f427ee49 98#include <kern/task.h>
2d21ac55
A
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
5ba3f43e 108#include <libkern/section_keywords.h>
b0d623f7 109
0a7de745 110/*
2d21ac55
A
111 * define MB_DEBUG to display run-time debugging information
112 * #define MB_DEBUG 1
113 */
114
115#ifdef MB_DEBUG
0a7de745 116#define DPRINTF(x) printf x
2d21ac55
A
117#else
118#define MB_DEBUG
119#define DPRINTF(x)
120#endif
121
122#if CONFIG_MACF
0a7de745 123SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
2d21ac55 124 "Security Controls");
c3c9b80d 125SYSCTL_EXTENSIBLE_NODE(_security, OID_AUTO, mac, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
2d21ac55
A
126 "TrustedBSD MAC policy controls");
127
2d21ac55
A
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;
6d2010ae 143SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD | CTLFLAG_LOCKED,
2d21ac55
A
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 */
0a7de745 151int mac_late = 0;
2d21ac55 152
b0d623f7
A
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 */
cb323159
A
164#if CONFIG_MACF_LAZY_VNODE_LABELS
165unsigned int mac_label_vnodes = 1;
166#else
0a7de745 167unsigned int mac_label_vnodes = 0;
cb323159
A
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");
b0d623f7 178
2d21ac55 179unsigned int mac_device_enforce = 1;
316670eb 180SYSCTL_UINT(_security_mac, OID_AUTO, device_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 181 &mac_device_enforce, 0, "Enforce MAC policy on device operations");
2d21ac55 182
0a7de745 183unsigned int mac_pipe_enforce = 1;
316670eb 184SYSCTL_UINT(_security_mac, OID_AUTO, pipe_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
185 &mac_pipe_enforce, 0, "Enforce MAC policy on pipe operations");
186
0a7de745 187unsigned int mac_posixsem_enforce = 1;
316670eb 188SYSCTL_UINT(_security_mac, OID_AUTO, posixsem_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
189 &mac_posixsem_enforce, 0, "Enforce MAC policy on POSIX semaphores");
190
191unsigned int mac_posixshm_enforce = 1;
316670eb 192SYSCTL_UINT(_security_mac, OID_AUTO, posixshm_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
193 &mac_posixshm_enforce, 0, "Enforce MAC policy on Posix Shared Memory");
194
0a7de745 195unsigned int mac_proc_enforce = 1;
316670eb 196SYSCTL_UINT(_security_mac, OID_AUTO, proc_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 197 &mac_proc_enforce, 0, "Enforce MAC policy on process operations");
2d21ac55
A
198
199unsigned int mac_socket_enforce = 1;
316670eb 200SYSCTL_UINT(_security_mac, OID_AUTO, socket_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 201 &mac_socket_enforce, 0, "Enforce MAC policy on socket operations");
2d21ac55 202
0a7de745 203unsigned int mac_system_enforce = 1;
316670eb 204SYSCTL_UINT(_security_mac, OID_AUTO, system_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
205 &mac_system_enforce, 0, "Enforce MAC policy on system-wide interfaces");
206
0a7de745 207unsigned int mac_sysvmsg_enforce = 1;
316670eb 208SYSCTL_UINT(_security_mac, OID_AUTO, sysvmsg_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
209 &mac_sysvmsg_enforce, 0, "Enforce MAC policy on System V IPC message queues");
210
0a7de745 211unsigned int mac_sysvsem_enforce = 1;
316670eb 212SYSCTL_UINT(_security_mac, OID_AUTO, sysvsem_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
213 &mac_sysvsem_enforce, 0, "Enforce MAC policy on System V IPC semaphores");
214
0a7de745 215unsigned int mac_sysvshm_enforce = 1;
316670eb 216SYSCTL_INT(_security_mac, OID_AUTO, sysvshm_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
217 &mac_sysvshm_enforce, 0, "Enforce MAC policy on System V Shared Memory");
218
0a7de745 219unsigned int mac_vm_enforce = 1;
316670eb 220SYSCTL_INT(_security_mac, OID_AUTO, vm_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 221 &mac_vm_enforce, 0, "Enforce MAC policy on VM operations");
2d21ac55 222
0a7de745 223unsigned int mac_vnode_enforce = 1;
316670eb 224SYSCTL_UINT(_security_mac, OID_AUTO, vnode_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 225 &mac_vnode_enforce, 0, "Enforce MAC policy on vnode operations");
2d21ac55 226
2d21ac55
A
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 */
c3c9b80d
A
243static LCK_GRP_DECLARE(mac_lck_grp, "MAC lock");
244static LCK_MTX_DECLARE(mac_policy_mtx, &mac_lck_grp);
2d21ac55
A
245
246/*
f427ee49 247 * Policy list array allocation chunk size. Each entry holds a pointer.
2d21ac55 248 */
f427ee49 249#define MAC_POLICY_LIST_CHUNKSIZE 8
2d21ac55
A
250
251static int mac_policy_busy;
252
f427ee49 253#if !XNU_TARGET_OS_OSX
5ba3f43e
A
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
2d21ac55 257mac_policy_list_t mac_policy_list;
5ba3f43e 258#endif
2d21ac55
A
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
0a7de745 264 * policy is unloaded, the namespace elements are removed if no other
2d21ac55
A
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
2d21ac55
A
270static __inline void
271mac_policy_grab_exclusive(void)
272{
c3c9b80d 273 lck_mtx_lock(&mac_policy_mtx);
2d21ac55 274 while (mac_policy_busy != 0) {
c3c9b80d 275 lck_mtx_sleep(&mac_policy_mtx, LCK_SLEEP_UNLOCK,
0a7de745 276 (event_t)&mac_policy_busy, THREAD_UNINT);
c3c9b80d 277 lck_mtx_lock(&mac_policy_mtx);
2d21ac55
A
278 }
279}
280
2d21ac55
A
281static __inline void
282mac_policy_release_exclusive(void)
283{
2d21ac55
A
284 KASSERT(mac_policy_busy == 0,
285 ("mac_policy_release_exclusive(): not exclusive"));
c3c9b80d 286 lck_mtx_unlock(&mac_policy_mtx);
2d21ac55
A
287 thread_wakeup((event_t) &mac_policy_busy);
288}
289
290void
291mac_policy_list_busy(void)
292{
c3c9b80d 293 lck_mtx_lock(&mac_policy_mtx);
2d21ac55 294 mac_policy_busy++;
c3c9b80d 295 lck_mtx_unlock(&mac_policy_mtx);
2d21ac55
A
296}
297
298int
299mac_policy_list_conditional_busy(void)
300{
301 int ret;
302
0a7de745
A
303 if (mac_policy_list.numloaded <= mac_policy_list.staticmax) {
304 return 0;
305 }
2d21ac55 306
c3c9b80d 307 lck_mtx_lock(&mac_policy_mtx);
2d21ac55
A
308 if (mac_policy_list.numloaded > mac_policy_list.staticmax) {
309 mac_policy_busy++;
310 ret = 1;
0a7de745 311 } else {
2d21ac55 312 ret = 0;
0a7de745 313 }
c3c9b80d 314 lck_mtx_unlock(&mac_policy_mtx);
0a7de745 315 return ret;
2d21ac55
A
316}
317
318void
319mac_policy_list_unbusy(void)
320{
c3c9b80d 321 lck_mtx_lock(&mac_policy_mtx);
2d21ac55
A
322 mac_policy_busy--;
323 KASSERT(mac_policy_busy >= 0, ("MAC_POLICY_LIST_LOCK"));
0a7de745 324 if (mac_policy_busy == 0) {
2d21ac55 325 thread_wakeup(&mac_policy_busy);
0a7de745 326 }
c3c9b80d 327 lck_mtx_unlock(&mac_policy_mtx);
2d21ac55
A
328}
329
330/*
331 * Early pre-malloc MAC initialization, including appropriate SMP locks.
332 */
333void
334mac_policy_init(void)
335{
2d21ac55
A
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
f427ee49 343#if !XNU_TARGET_OS_OSX
5ba3f43e
A
344 mac_policy_list.entries = mac_policy_static_entries;
345#else
f427ee49
A
346 mac_policy_list.entries = kalloc_flags(
347 sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE,
348 Z_WAITOK | Z_ZERO);
5ba3f43e 349#endif
4bd07ac2 350
2d21ac55
A
351 LIST_INIT(&mac_label_element_list);
352 LIST_INIT(&mac_static_label_element_list);
2d21ac55
A
353}
354
b0d623f7
A
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
2d21ac55
A
362/*
363 * Init after early Mach startup, but before BSD
364 */
365void
366mac_policy_initmach(void)
367{
2d21ac55
A
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
b0d623f7
A
375 if (load_security_extensions_function) {
376 load_security_extensions_function();
377 }
2d21ac55 378 mac_late = 1;
2d21ac55
A
379}
380
381/*
382 * BSD startup.
383 */
384void
385mac_policy_initbsd(void)
386{
387 struct mac_policy_conf *mpc;
388 u_int i;
389
2d21ac55
A
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);
0a7de745 403 if ((mpc != NULL) && (mpc->mpc_ops->mpo_policy_initbsd != NULL)) {
2d21ac55 404 (*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
0a7de745 405 }
2d21ac55
A
406 }
407
408 mac_policy_release_exclusive();
409}
410
411/*
412 * After a policy has been loaded, add the label namespaces managed by the
0a7de745
A
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
2d21ac55
A
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
0a7de745 429 if (mpc->mpc_labelnames == NULL) {
2d21ac55 430 return;
0a7de745 431 }
2d21ac55 432
0a7de745 433 if (mpc->mpc_labelname_count == 0) {
2d21ac55 434 return;
0a7de745 435 }
2d21ac55 436
0a7de745 437 if (static_entry) {
2d21ac55 438 list = &mac_static_label_element_list;
0a7de745 439 } else {
2d21ac55 440 list = &mac_label_element_list;
0a7de745 441 }
2d21ac55
A
442
443 /*
444 * Before we grab the policy list lock, allocate enough memory
0a7de745 445 * to contain the potential new elements so we don't have to
2d21ac55
A
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);
0a7de745
A
451 for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
452 MALLOC(new_mles[idx], struct mac_label_element *,
2d21ac55
A
453 sizeof(struct mac_label_element),
454 M_MACTEMP, M_WAITOK);
0a7de745 455 }
2d21ac55
A
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);
0a7de745 460 for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
2d21ac55
A
461 MALLOC(new_mlls[idx], struct mac_label_listener *,
462 sizeof(struct mac_label_listener), M_MACTEMP, M_WAITOK);
0a7de745 463 }
2d21ac55
A
464 mll_free = 0;
465
0a7de745 466 if (mac_late) {
2d21ac55 467 mac_policy_grab_exclusive();
0a7de745 468 }
2d21ac55 469 for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
0a7de745 470 if (*(name = mpc->mpc_labelnames[idx]) == '?') {
2d21ac55 471 name++;
0a7de745 472 }
2d21ac55 473 /*
0a7de745 474 * Check both label element lists and add to the
2d21ac55
A
475 * appropriate list only if not already on a list.
476 */
477 LIST_FOREACH(mle, &mac_static_label_element_list, mle_list) {
0a7de745 478 if (*(name2 = mle->mle_name) == '?') {
2d21ac55 479 name2++;
0a7de745
A
480 }
481 if (strcmp(name, name2) == 0) {
2d21ac55 482 break;
0a7de745 483 }
2d21ac55
A
484 }
485 if (mle == NULL) {
486 LIST_FOREACH(mle, &mac_label_element_list, mle_list) {
0a7de745 487 if (*(name2 = mle->mle_name) == '?') {
2d21ac55 488 name2++;
0a7de745
A
489 }
490 if (strcmp(name, name2) == 0) {
2d21ac55 491 break;
0a7de745 492 }
2d21ac55
A
493 }
494 }
495 if (mle == NULL) {
496 mle = new_mles[mle_free];
497 strlcpy(mle->mle_name, mpc->mpc_labelnames[idx],
0a7de745 498 MAC_MAX_LABEL_ELEMENT_NAME);
2d21ac55
A
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 }
0a7de745 509 if (mac_late) {
2d21ac55 510 mac_policy_release_exclusive();
0a7de745 511 }
2d21ac55
A
512
513 /* Free up any unused label elements and listeners */
0a7de745 514 for (idx = mle_free; idx < mpc->mpc_labelname_count; idx++) {
2d21ac55 515 FREE(new_mles[idx], M_MACTEMP);
0a7de745 516 }
2d21ac55 517 FREE(new_mles, M_MACTEMP);
0a7de745 518 for (idx = mll_free; idx < mpc->mpc_labelname_count; idx++) {
2d21ac55 519 FREE(new_mlls[idx], M_MACTEMP);
0a7de745 520 }
2d21ac55
A
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
0a7de745 541 if (mpc->mpc_labelnames == NULL) {
2d21ac55 542 return;
0a7de745 543 }
2d21ac55 544
0a7de745 545 if (mpc->mpc_labelname_count == 0) {
2d21ac55 546 return;
0a7de745 547 }
2d21ac55
A
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{
2d21ac55
A
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));
0a7de745 607 for (k = 0; k < dict->count; k++) {
2d21ac55
A
608 mmd_fixup_ele(old, new,
609 &(dict->list[k]));
0a7de745 610 }
2d21ac55
A
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{
f427ee49 622#if XNU_TARGET_OS_OSX
2d21ac55 623 struct mac_policy_list_element *tmac_policy_list_element;
5ba3f43e 624#endif
2d21ac55
A
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 */
0a7de745 632 if (mpc->mpc_name == NULL) {
2d21ac55 633 panic("policy's name is not set\n");
0a7de745 634 }
2d21ac55 635
0a7de745 636 if (mpc->mpc_fullname == NULL) {
2d21ac55 637 panic("policy's full name is not set\n");
0a7de745 638 }
2d21ac55 639
0a7de745 640 if (mpc->mpc_labelname_count > MAC_MAX_MANAGED_NAMESPACES) {
2d21ac55 641 panic("policy's managed label namespaces exceeds maximum\n");
0a7de745 642 }
2d21ac55 643
0a7de745 644 if (mpc->mpc_ops == NULL) {
2d21ac55 645 panic("policy's OPs field is NULL\n");
0a7de745 646 }
2d21ac55
A
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);
0a7de745 654 return EPERM;
2d21ac55
A
655 }
656 mac_policy_grab_exclusive();
657 }
658
659 if (mac_policy_list.numloaded >= mac_policy_list.max) {
f427ee49 660#if XNU_TARGET_OS_OSX
2d21ac55
A
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);
0a7de745 668
2d21ac55 669 /* copy old entries into new list */
0a7de745
A
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
2d21ac55
A
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);
0a7de745 678
2d21ac55
A
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++;
5ba3f43e
A
684#else
685 printf("out of space in mac_policy_list.\n");
0a7de745 686 return ENOMEM;
f427ee49 687#endif /* XNU_TARGET_OS_OSX */
2d21ac55
A
688 }
689
690 /* Check for policy with same name already loaded */
691 for (i = 0; i <= mac_policy_list.maxindex; i++) {
0a7de745
A
692 if (mac_policy_list.entries[i].mpc == NULL) {
693 continue;
694 }
2d21ac55
A
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 */
0a7de745 754 if (*handlep > mac_policy_list.maxindex) {
2d21ac55 755 mac_policy_list.maxindex = *handlep;
0a7de745 756 }
2d21ac55 757 mac_policy_list.numloaded++;
0a7de745 758
2d21ac55 759 /* Per-policy initialization. */
0a7de745
A
760 printf("calling mpo_policy_init for %s\n", mpc->mpc_name);
761 if (mpc->mpc_ops->mpo_policy_init != NULL) {
2d21ac55 762 (*(mpc->mpc_ops->mpo_policy_init))(mpc);
0a7de745 763 }
2d21ac55
A
764
765 if (mac_late && mpc->mpc_ops->mpo_policy_initbsd != NULL) {
0a7de745 766 printf("calling mpo_policy_initbsd for %s\n", mpc->mpc_name);
2d21ac55
A
767 (*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
768 }
769
770 mac_policy_updateflags();
771
0a7de745 772 if (mac_late) {
2d21ac55 773 mac_policy_release_exclusive();
0a7de745 774 }
2d21ac55
A
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
0a7de745 781 return 0;
2d21ac55
A
782
783out:
0a7de745 784 if (mac_late) {
2d21ac55 785 mac_policy_release_exclusive();
0a7de745 786 }
2d21ac55 787
0a7de745 788 return error;
2d21ac55
A
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();
0a7de745 805 return 0;
2d21ac55
A
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();
0a7de745 814 return EBUSY;
2d21ac55
A
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();
0a7de745 823 return EBUSY;
2d21ac55
A
824 }
825
826 mac_policy_removefrom_labellist(handle);
827
828 mac_get_mpc(handle) = NULL;
829 if (handle < mac_policy_list.freehint &&
0a7de745 830 handle >= mac_policy_list.staticmax) {
2d21ac55 831 mac_policy_list.freehint = handle;
0a7de745 832 }
2d21ac55 833
0a7de745 834 if (handle == mac_policy_list.maxindex) {
2d21ac55 835 mac_policy_list.maxindex--;
0a7de745 836 }
2d21ac55 837
0a7de745 838 mac_policy_list.numloaded--;
2d21ac55
A
839 if (mpc->mpc_field_off != NULL) {
840 mac_slot_offsets_free |= (1 << *mpc->mpc_field_off);
841 }
842
0a7de745 843 if (mpc->mpc_ops->mpo_policy_destroy != NULL) {
2d21ac55 844 (*(mpc->mpc_ops->mpo_policy_destroy))(mpc);
0a7de745 845 }
2d21ac55
A
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
0a7de745 861 return 0;
2d21ac55
A
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{
2d21ac55 871 /* Certain decision-making errors take top priority. */
0a7de745
A
872 if (error1 == EDEADLK || error2 == EDEADLK) {
873 return EDEADLK;
874 }
2d21ac55
A
875
876 /* Invalid arguments should be reported where possible. */
0a7de745
A
877 if (error1 == EINVAL || error2 == EINVAL) {
878 return EINVAL;
879 }
2d21ac55
A
880
881 /* Precedence goes to "visibility", with both process and file. */
0a7de745
A
882 if (error1 == ESRCH || error2 == ESRCH) {
883 return ESRCH;
884 }
2d21ac55 885
0a7de745
A
886 if (error1 == ENOENT || error2 == ENOENT) {
887 return ENOENT;
888 }
2d21ac55
A
889
890 /* Precedence goes to DAC/MAC protections. */
0a7de745
A
891 if (error1 == EACCES || error2 == EACCES) {
892 return EACCES;
893 }
2d21ac55
A
894
895 /* Precedence goes to privilege. */
0a7de745
A
896 if (error1 == EPERM || error2 == EPERM) {
897 return EPERM;
898 }
2d21ac55
A
899
900 /* Precedence goes to error over success; otherwise, arbitrary. */
0a7de745
A
901 if (error1 != 0) {
902 return error1;
903 }
904 return error2;
2d21ac55
A
905}
906
907void
908mac_label_init(struct label *label)
909{
2d21ac55
A
910 bzero(label, sizeof(*label));
911 label->l_flags = MAC_FLAG_INITIALIZED;
912}
913
914void
915mac_label_destroy(struct label *label)
916{
2d21ac55
A
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
2d21ac55
A
924int
925mac_check_structmac_consistent(struct user_mac *mac)
926{
0a7de745
A
927 if (mac->m_buflen > MAC_MAX_LABEL_BUF_LEN || mac->m_buflen == 0) {
928 return EINVAL;
929 }
2d21ac55 930
0a7de745 931 return 0;
2d21ac55
A
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;
f427ee49 950 int sb_pos;
2d21ac55
A
951 unsigned int count = 0;
952
953 if (element[0] == '?') {
954 element++;
955 ignorenotfound = 1;
0a7de745 956 } else if (element[0] == '*' && element[1] == '\0') {
2d21ac55 957 all_labels = 1;
0a7de745 958 }
2d21ac55
A
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) {
0a7de745
A
965 if (*name == '?') {
966 continue;
967 }
2d21ac55 968 } else {
0a7de745 969 if (*name == '?') {
2d21ac55 970 name++;
0a7de745
A
971 }
972 if (strcmp(name, element) != 0) {
2d21ac55 973 continue;
0a7de745 974 }
2d21ac55
A
975 }
976 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
977 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
0a7de745 978 if (mpc == NULL) {
2d21ac55 979 continue;
0a7de745 980 }
5ba3f43e
A
981 mpo_externalize = *(const typeof(mpo_externalize) *)
982 ((const char *)mpc->mpc_ops + mpo_externalize_off);
0a7de745 983 if (mpo_externalize == NULL) {
2d21ac55 984 continue;
0a7de745 985 }
f427ee49 986 sb_pos = sbuf_len(sb);
2d21ac55 987 error = sbuf_printf(sb, "%s/", name);
0a7de745 988 if (error) {
2d21ac55 989 goto done;
0a7de745 990 }
2d21ac55
A
991 error = mpo_externalize(label, mle->mle_name, sb);
992 if (error) {
0a7de745 993 if (error != ENOENT) {
2d21ac55 994 goto done;
0a7de745 995 }
2d21ac55
A
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 */
f427ee49 1003 sbuf_setpos(sb, sb_pos);
2d21ac55
A
1004 error = 0;
1005 continue;
1006 }
1007 error = sbuf_putc(sb, ',');
0a7de745 1008 if (error) {
2d21ac55 1009 goto done;
0a7de745 1010 }
2d21ac55
A
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:
0a7de745 1021 if (busy) {
2d21ac55 1022 mac_policy_list_unbusy();
0a7de745 1023 }
2d21ac55 1024 if (!error && count == 0) {
0a7de745
A
1025 if (!all_labels && !ignorenotfound) {
1026 error = ENOENT; /* XXX: ENOLABEL? */
1027 }
2d21ac55 1028 }
0a7de745 1029 return error;
2d21ac55
A
1030}
1031
1032/*
1033 * Get the external forms of labels from all policies, for all label
1034 * namespaces contained in a list.
b0d623f7
A
1035 *
1036 * XXX This may be leaking an sbuf.
2d21ac55
A
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;
b0d623f7
A
1043 char *scratch_base;
1044 char *scratch;
2d21ac55
A
1045 struct sbuf sb;
1046 int error = 0, len;
1047
b0d623f7 1048 /* allocate a scratch buffer the size of the string */
0a7de745 1049 MALLOC(scratch_base, char *, strlen(elementlist) + 1, M_MACTEMP, M_WAITOK);
b0d623f7
A
1050 if (scratch_base == NULL) {
1051 error = ENOMEM;
1052 goto out;
1053 }
1054
1055 /* copy the elementlist to the scratch buffer */
0a7de745 1056 strlcpy(scratch_base, elementlist, strlen(elementlist) + 1);
b0d623f7
A
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
f427ee49
A
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) {
b0d623f7
A
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) {
2d21ac55
A
1078 error = mac_label_externalize(mpo_externalize_off, label,
1079 element, &sb);
0a7de745 1080 if (error) {
2d21ac55 1081 break;
0a7de745
A
1082 }
1083 }
1084 if ((len = sbuf_len(&sb)) > 0) {
1085 sbuf_setpos(&sb, len - 1); /* trim trailing comma */
2d21ac55 1086 }
2d21ac55 1087 sbuf_finish(&sb);
b0d623f7
A
1088
1089out:
0a7de745 1090 if (scratch_base != NULL) {
b0d623f7 1091 FREE(scratch_base, M_MACTEMP);
0a7de745 1092 }
b0d623f7 1093
0a7de745 1094 return error;
2d21ac55
A
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) {
0a7de745 1117 if (*(name = mle->mle_name) == '?') {
2d21ac55 1118 name++;
0a7de745
A
1119 }
1120 if (strcmp(element_name, name) != 0) {
2d21ac55 1121 continue;
0a7de745 1122 }
2d21ac55
A
1123 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1124 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
0a7de745 1125 if (mpc == NULL) {
2d21ac55 1126 continue;
0a7de745 1127 }
5ba3f43e
A
1128 mpo_internalize = *(const typeof(mpo_internalize) *)
1129 ((const char *)mpc->mpc_ops + mpo_internalize_off);
0a7de745 1130 if (mpo_internalize == NULL) {
2d21ac55 1131 continue;
0a7de745 1132 }
2d21ac55
A
1133 error = mpo_internalize(label, element_name,
1134 element_data);
0a7de745 1135 if (error) {
2d21ac55 1136 goto done;
0a7de745 1137 }
2d21ac55
A
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:
0a7de745 1148 if (busy) {
2d21ac55 1149 mac_policy_list_unbusy();
0a7de745
A
1150 }
1151 if (!error && count == 0) {
2d21ac55 1152 error = ENOPOLICY;
0a7de745
A
1153 }
1154 return error;
2d21ac55
A
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 }
0a7de745 1174 return error;
2d21ac55
A
1175}
1176
1177/* system calls */
1178
1179int
b0d623f7 1180__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, int *ret __unused)
2d21ac55
A
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)) {
6d2010ae
A
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;
2d21ac55 1195 } else {
6d2010ae 1196 struct user32_mac mac32;
2d21ac55
A
1197 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1198 mac.m_buflen = mac32.m_buflen;
6d2010ae 1199 mac.m_string = mac32.m_string;
2d21ac55 1200 }
0a7de745
A
1201 if (error) {
1202 return error;
1203 }
2d21ac55
A
1204
1205 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1206 if (error) {
1207 return error;
1208 }
2d21ac55
A
1209
1210 tproc = proc_find(uap->pid);
0a7de745
A
1211 if (tproc == NULL) {
1212 return ESRCH;
1213 }
2d21ac55
A
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);
0a7de745 1222 return error;
2d21ac55
A
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);
0a7de745
A
1229 if (error == 0) {
1230 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1231 }
2d21ac55
A
1232
1233 FREE(buffer, M_MACTEMP);
1234 FREE(elements, M_MACTEMP);
1235 kauth_cred_unref(&tcred);
0a7de745 1236 return error;
2d21ac55
A
1237}
1238
1239int
b0d623f7 1240__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, int *ret __unused)
2d21ac55
A
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)) {
6d2010ae
A
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;
2d21ac55 1253 } else {
6d2010ae 1254 struct user32_mac mac32;
2d21ac55
A
1255 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1256 mac.m_buflen = mac32.m_buflen;
6d2010ae 1257 mac.m_string = mac32.m_string;
2d21ac55 1258 }
0a7de745
A
1259 if (error) {
1260 return error;
1261 }
2d21ac55
A
1262
1263 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1264 if (error) {
1265 return error;
1266 }
2d21ac55
A
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);
0a7de745 1272 return error;
2d21ac55
A
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);
0a7de745
A
1281 if (error == 0) {
1282 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1283 }
2d21ac55
A
1284
1285 FREE(buffer, M_MACTEMP);
1286 FREE(elements, M_MACTEMP);
1287 kauth_cred_unref(&cr);
0a7de745 1288 return error;
2d21ac55
A
1289}
1290
2d21ac55 1291int
b0d623f7 1292__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, int *ret __unused)
2d21ac55 1293{
2d21ac55
A
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)) {
6d2010ae
A
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;
2d21ac55 1305 } else {
6d2010ae 1306 struct user32_mac mac32;
2d21ac55
A
1307 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1308 mac.m_buflen = mac32.m_buflen;
6d2010ae 1309 mac.m_string = mac32.m_string;
2d21ac55 1310 }
0a7de745
A
1311 if (error) {
1312 return error;
1313 }
2d21ac55
A
1314
1315 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1316 if (error) {
1317 return error;
1318 }
2d21ac55
A
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);
0a7de745 1324 return error;
2d21ac55
A
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);
0a7de745 1331 if (error) {
2d21ac55 1332 goto out;
0a7de745 1333 }
2d21ac55
A
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);
0a7de745 1341 if (error) {
2d21ac55 1342 goto out;
0a7de745 1343 }
2d21ac55 1344
2d21ac55
A
1345out:
1346 mac_cred_label_free(intlabel);
0a7de745 1347 return error;
2d21ac55
A
1348}
1349
2d21ac55 1350int
b0d623f7 1351__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, int *ret __unused)
2d21ac55
A
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;
2d21ac55
A
1360 struct label *intlabel;
1361
1362 AUDIT_ARG(fd, uap->fd);
1363
1364 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
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;
2d21ac55 1369 } else {
6d2010ae 1370 struct user32_mac mac32;
2d21ac55
A
1371 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1372 mac.m_buflen = mac32.m_buflen;
6d2010ae 1373 mac.m_string = mac32.m_string;
2d21ac55
A
1374 }
1375
0a7de745
A
1376 if (error) {
1377 return error;
1378 }
2d21ac55
A
1379
1380 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1381 if (error) {
1382 return error;
1383 }
1384
2d21ac55
A
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);
0a7de745 1389 return error;
2d21ac55
A
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);
0a7de745 1398 return error;
2d21ac55 1399 }
0a7de745 1400
2d21ac55 1401 my_cred = kauth_cred_proc_ref(p);
f427ee49 1402 error = mac_file_check_get(my_cred, fp->fp_glob, elements, mac.m_buflen);
2d21ac55
A
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);
0a7de745 1408 return error;
2d21ac55 1409 }
0a7de745 1410
f427ee49 1411 switch (FILEGLOB_DTYPE(fp->fp_glob)) {
0a7de745
A
1412 case DTYPE_VNODE:
1413 intlabel = mac_vnode_label_alloc();
1414 if (intlabel == NULL) {
1415 error = ENOMEM;
2d21ac55 1416 break;
0a7de745 1417 }
f427ee49 1418 vp = (struct vnode *)fp->fp_glob->fg_data;
0a7de745
A
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:
0a7de745
A
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;
2d21ac55
A
1440 }
1441 fp_drop(p, uap->fd, fp, 0);
0a7de745
A
1442
1443 if (error == 0) {
1444 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1445 }
1446
2d21ac55
A
1447 FREE(buffer, M_MACTEMP);
1448 FREE(elements, M_MACTEMP);
0a7de745 1449 return error;
2d21ac55
A
1450}
1451
2d21ac55
A
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)) {
6d2010ae
A
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;
2d21ac55 1469 } else {
6d2010ae 1470 struct user32_mac mac32;
2d21ac55
A
1471 error = copyin(mac_p, &mac32, sizeof(mac32));
1472 mac.m_buflen = mac32.m_buflen;
6d2010ae 1473 mac.m_string = mac32.m_string;
2d21ac55
A
1474 }
1475
0a7de745
A
1476 if (error) {
1477 return error;
1478 }
2d21ac55
A
1479
1480 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1481 if (error) {
1482 return error;
1483 }
2d21ac55
A
1484
1485 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
b0d623f7
A
1486 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1487
2d21ac55
A
1488 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1489 if (error) {
b0d623f7 1490 FREE(buffer, M_MACTEMP);
2d21ac55 1491 FREE(elements, M_MACTEMP);
0a7de745 1492 return error;
2d21ac55
A
1493 }
1494 AUDIT_ARG(mac_string, elements);
1495
1496 ctx = vfs_context_current();
1497
6d2010ae 1498 NDINIT(&nd, LOOKUP, OP_LOOKUP,
0a7de745
A
1499 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1500 UIO_USERSPACE, path_p, ctx);
2d21ac55
A
1501 error = namei(&nd);
1502 if (error) {
b0d623f7 1503 FREE(buffer, M_MACTEMP);
2d21ac55 1504 FREE(elements, M_MACTEMP);
0a7de745 1505 return error;
2d21ac55
A
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);
2d21ac55 1513 error = mac_vnode_label_externalize(intlabel, elements, buffer,
0a7de745 1514 mac.m_buflen, M_WAITOK);
b0d623f7 1515 mac_vnode_label_free(intlabel);
0a7de745 1516 if (error == 0) {
2d21ac55 1517 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
0a7de745 1518 }
2d21ac55
A
1519
1520 vnode_put(vp);
b0d623f7
A
1521
1522 FREE(buffer, M_MACTEMP);
1523 FREE(elements, M_MACTEMP);
2d21ac55 1524
0a7de745 1525 return error;
2d21ac55
A
1526}
1527
1528int
1529__mac_get_file(proc_t p, struct __mac_get_file_args *uap,
0a7de745 1530 int *ret __unused)
2d21ac55 1531{
0a7de745 1532 return mac_get_filelink(p, uap->mac_p, uap->path_p, 1);
2d21ac55
A
1533}
1534
1535int
1536__mac_get_link(proc_t p, struct __mac_get_link_args *uap,
0a7de745 1537 int *ret __unused)
2d21ac55 1538{
0a7de745 1539 return mac_get_filelink(p, uap->mac_p, uap->path_p, 0);
2d21ac55
A
1540}
1541
1542int
b0d623f7 1543__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, int *ret __unused)
2d21ac55 1544{
2d21ac55
A
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;
2d21ac55
A
1552 struct vnode *vp;
1553
1554 AUDIT_ARG(fd, uap->fd);
1555
1556 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
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;
2d21ac55 1561 } else {
6d2010ae 1562 struct user32_mac mac32;
2d21ac55
A
1563 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1564 mac.m_buflen = mac32.m_buflen;
6d2010ae 1565 mac.m_string = mac32.m_string;
2d21ac55 1566 }
0a7de745
A
1567 if (error) {
1568 return error;
1569 }
1570
2d21ac55 1571 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1572 if (error) {
1573 return error;
1574 }
1575
2d21ac55
A
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);
0a7de745 1580 return error;
2d21ac55
A
1581 }
1582 AUDIT_ARG(mac_string, buffer);
0a7de745 1583
2d21ac55
A
1584 error = fp_lookup(p, uap->fd, &fp, 0);
1585 if (error) {
1586 FREE(buffer, M_MACTEMP);
0a7de745 1587 return error;
2d21ac55 1588 }
0a7de745 1589
2d21ac55 1590
f427ee49 1591 error = mac_file_check_set(vfs_context_ucred(ctx), fp->fp_glob, buffer, mac.m_buflen);
2d21ac55
A
1592 if (error) {
1593 fp_drop(p, uap->fd, fp, 0);
1594 FREE(buffer, M_MACTEMP);
0a7de745 1595 return error;
2d21ac55 1596 }
2d21ac55 1597
f427ee49 1598 switch (FILEGLOB_DTYPE(fp->fp_glob)) {
0a7de745
A
1599 case DTYPE_VNODE:
1600 if (mac_label_vnodes == 0) {
1601 error = ENOSYS;
1602 break;
1603 }
b0d623f7 1604
0a7de745 1605 intlabel = mac_vnode_label_alloc();
2d21ac55 1606
0a7de745
A
1607 error = mac_vnode_label_internalize(intlabel, buffer);
1608 if (error) {
1609 mac_vnode_label_free(intlabel);
1610 break;
1611 }
2d21ac55
A
1612
1613
f427ee49 1614 vp = (struct vnode *)fp->fp_glob->fg_data;
2d21ac55 1615
0a7de745
A
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;
2d21ac55 1623
0a7de745 1624 case DTYPE_SOCKET:
0a7de745
A
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;
2d21ac55
A
1635 }
1636
1637 fp_drop(p, uap->fd, fp, 0);
1638 FREE(buffer, M_MACTEMP);
0a7de745 1639 return error;
2d21ac55
A
1640}
1641
2d21ac55
A
1642static int
1643mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p,
0a7de745 1644 int follow)
2d21ac55 1645{
39037602 1646 struct vnode *vp;
2d21ac55
A
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
0a7de745 1655 if (mac_label_vnodes == 0) {
b0d623f7 1656 return ENOSYS;
0a7de745 1657 }
b0d623f7 1658
2d21ac55 1659 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
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;
2d21ac55 1664 } else {
6d2010ae 1665 struct user32_mac mac32;
2d21ac55
A
1666 error = copyin(mac_p, &mac32, sizeof(mac32));
1667 mac.m_buflen = mac32.m_buflen;
6d2010ae 1668 mac.m_string = mac32.m_string;
2d21ac55 1669 }
0a7de745
A
1670 if (error) {
1671 return error;
1672 }
2d21ac55
A
1673
1674 error = mac_check_structmac_consistent(&mac);
1675 if (error) {
1676 printf("mac_set_file: failed structure consistency check\n");
0a7de745 1677 return error;
2d21ac55
A
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);
0a7de745 1684 return error;
2d21ac55
A
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);
0a7de745 1693 return error;
2d21ac55
A
1694 }
1695
6d2010ae 1696 NDINIT(&nd, LOOKUP, OP_LOOKUP,
0a7de745
A
1697 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1698 UIO_USERSPACE, path_p, ctx);
2d21ac55
A
1699 error = namei(&nd);
1700 if (error) {
1701 mac_vnode_label_free(intlabel);
0a7de745 1702 return error;
2d21ac55
A
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
0a7de745 1712 return error;
2d21ac55
A
1713}
1714
1715int
1716__mac_set_file(proc_t p, struct __mac_set_file_args *uap,
0a7de745 1717 int *ret __unused)
2d21ac55 1718{
0a7de745 1719 return mac_set_filelink(p, uap->mac_p, uap->path_p, 1);
2d21ac55
A
1720}
1721
1722int
1723__mac_set_link(proc_t p, struct __mac_set_link_args *uap,
0a7de745 1724 int *ret __unused)
2d21ac55 1725{
0a7de745 1726 return mac_set_filelink(p, uap->mac_p, uap->path_p, 0);
2d21ac55
A
1727}
1728
1729/*
b0d623f7
A
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
0a7de745 1739 *
b0d623f7
A
1740 * Returns: 0 Success
1741 * !0 Not success
1742 *
2d21ac55 1743 */
2d21ac55 1744int
b0d623f7 1745__mac_syscall(proc_t p, struct __mac_syscall_args *uap, int *retv __unused)
2d21ac55
A
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);
0a7de745
A
1754 if (error) {
1755 return error;
1756 }
b0d623f7 1757 AUDIT_ARG(value32, uap->call);
2d21ac55
A
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;
0a7de745 1764 if (mpc == NULL) {
2d21ac55 1765 continue;
0a7de745 1766 }
2d21ac55
A
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;
0a7de745 1773 }
2d21ac55
A
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;
0a7de745 1778 if (mpc == NULL) {
2d21ac55 1779 continue;
0a7de745 1780 }
2d21ac55
A
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:
0a7de745 1793 return error;
2d21ac55
A
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())) {
6d2010ae
A
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;
2d21ac55 1810 } else {
6d2010ae 1811 struct user32_mac mac32;
2d21ac55
A
1812 error = copyin(mac_p, &mac32, sizeof(mac32));
1813 mac.m_buflen = mac32.m_buflen;
6d2010ae 1814 mac.m_string = mac32.m_string;
2d21ac55 1815 }
0a7de745
A
1816 if (error) {
1817 return error;
1818 }
2d21ac55
A
1819
1820 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1821 if (error) {
1822 return error;
1823 }
2d21ac55
A
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);
0a7de745 1829 return error;
2d21ac55
A
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
0a7de745 1839 if (error == 0) {
2d21ac55 1840 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
0a7de745 1841 }
2d21ac55
A
1842 FREE(buffer, M_MACTEMP);
1843
0a7de745 1844 return error;
2d21ac55
A
1845}
1846
b0d623f7
A
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
0a7de745 1855 * uap->mac_p MAC info
b0d623f7
A
1856 *
1857 * Returns: 0 Success
1858 * !0 Not success
1859 */
2d21ac55
A
1860int
1861__mac_get_mount(proc_t p __unused, struct __mac_get_mount_args *uap,
b0d623f7 1862 int *ret __unused)
2d21ac55
A
1863{
1864 struct nameidata nd;
1865 struct vfs_context *ctx = vfs_context_current();
1866 struct mount *mp;
1867 int error;
1868
6d2010ae 1869 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | AUDITVNPATH1,
0a7de745 1870 UIO_USERSPACE, uap->path, ctx);
2d21ac55
A
1871 error = namei(&nd);
1872 if (error) {
0a7de745 1873 return error;
2d21ac55
A
1874 }
1875 mp = nd.ni_vp->v_mount;
f427ee49 1876 mount_ref(mp, 0);
fe8ab488 1877 vnode_put(nd.ni_vp);
2d21ac55
A
1878 nameidone(&nd);
1879
f427ee49
A
1880 error = mac_mount_label_get(mp, uap->mac_p);
1881 mount_drop(mp, 0);
1882 return error;
2d21ac55
A
1883}
1884
316670eb
A
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
0a7de745 1892 * !0 Not successful
316670eb
A
1893 */
1894int
1895mac_schedule_userret(void)
1896{
316670eb 1897 act_set_astmacf(current_thread());
0a7de745 1898 return 0;
316670eb
A
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
0a7de745
A
1908 * subcode exception subcode
1909 * flags flags:
1910 * MAC_DOEXCF_TRACED Only do exception if being
1911 * ptrace()'ed.
316670eb
A
1912 *
1913 *
1914 * Returns: 0 Success
0a7de745 1915 * !0 Not successful
316670eb
A
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. */
0a7de745
A
1924 if ((code < EXC_MACF_MIN) || (code > EXC_MACF_MAX)) {
1925 return 1;
1926 }
316670eb
A
1927
1928 if (flags & MAC_DOEXCF_TRACED &&
0a7de745
A
1929 !(p->p_lflag & P_LTRACED && (p->p_lflag & P_LPPWAIT) == 0)) {
1930 return 0;
1931 }
316670eb
A
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
0a7de745 1938 return bsd_exception(EXC_SOFTWARE, codes, 2) != KERN_SUCCESS;
316670eb
A
1939}
1940
2d21ac55
A
1941#else /* MAC */
1942
39236c6e
A
1943void (*load_security_extensions_function)(void) = 0;
1944
1945struct sysctl_oid_list sysctl__security_mac_children;
1946
2d21ac55 1947int
0a7de745
A
1948mac_policy_register(struct mac_policy_conf *mpc __unused,
1949 mac_policy_handle_t *handlep __unused, void *xd __unused)
2d21ac55 1950{
0a7de745 1951 return 0;
2d21ac55
A
1952}
1953
1954int
1955mac_policy_unregister(mac_policy_handle_t handle __unused)
1956{
0a7de745 1957 return 0;
2d21ac55
A
1958}
1959
1960int
1961mac_audit_text(char *text __unused, mac_policy_handle_t handle __unused)
1962{
0a7de745 1963 return 0;
2d21ac55
A
1964}
1965
2d21ac55
A
1966int
1967mac_vnop_setxattr(struct vnode *vp __unused, const char *name __unused, char *buf __unused, size_t len __unused)
1968{
0a7de745 1969 return ENOENT;
2d21ac55
A
1970}
1971
1972int
0a7de745
A
1973mac_vnop_getxattr(struct vnode *vp __unused, const char *name __unused,
1974 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
2d21ac55 1975{
0a7de745 1976 return ENOENT;
2d21ac55
A
1977}
1978
1979int
1980mac_vnop_removexattr(struct vnode *vp __unused, const char *name __unused)
1981{
0a7de745 1982 return ENOENT;
2d21ac55
A
1983}
1984
39037602
A
1985int
1986mac_file_setxattr(struct fileglob *fg __unused, const char *name __unused, char *buf __unused, size_t len __unused)
1987{
0a7de745 1988 return ENOENT;
39037602
A
1989}
1990
1991int
1992mac_file_getxattr(struct fileglob *fg __unused, const char *name __unused,
0a7de745 1993 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
39037602 1994{
0a7de745 1995 return ENOENT;
39037602
A
1996}
1997
1998int
1999mac_file_removexattr(struct fileglob *fg __unused, const char *name __unused)
2000{
0a7de745 2001 return ENOENT;
39037602
A
2002}
2003
0a7de745
A
2004intptr_t
2005mac_label_get(struct label *l __unused, int slot __unused)
2d21ac55 2006{
0a7de745 2007 return 0;
2d21ac55
A
2008}
2009
0a7de745
A
2010void
2011mac_label_set(struct label *l __unused, int slot __unused, intptr_t v __unused)
2d21ac55 2012{
0a7de745 2013 return;
2d21ac55
A
2014}
2015
39236c6e 2016int mac_iokit_check_hid_control(kauth_cred_t cred __unused);
0a7de745
A
2017int
2018mac_iokit_check_hid_control(kauth_cred_t cred __unused)
316670eb 2019{
0a7de745 2020 return 0;
316670eb
A
2021}
2022
ea3f0419
A
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
527f9951 2032int mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused, struct vnode *dvp __unused, struct componentname *cnp __unused);
0a7de745
A
2033int
2034mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused, struct vnode *dvp __unused, struct componentname *cnp __unused)
527f9951
A
2035{
2036 return 0;
2037}
2038
2d21ac55 2039#endif /* !MAC */