]> git.saurik.com Git - apple/xnu.git/blame - security/mac_base.c
xnu-6153.11.26.tar.gz
[apple/xnu.git] / security / mac_base.c
CommitLineData
2d21ac55 1/*
39037602 2 * Copyright (c) 2007-2016 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>
2d21ac55
A
83#include <sys/file.h>
84#include <sys/file_internal.h>
85#include <sys/filedesc.h>
86#include <sys/proc.h>
87#include <sys/proc_internal.h>
88#include <sys/kauth.h>
89#include <sys/sysproto.h>
90
316670eb 91#include <mach/exception_types.h>
2d21ac55
A
92#include <mach/vm_types.h>
93#include <mach/vm_prot.h>
94
95#include <kern/zalloc.h>
96#include <kern/sched_prim.h>
97#include <osfmk/kern/task.h>
98#include <osfmk/kern/kalloc.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
A
108#if CONFIG_EMBEDDED
109#include <libkern/section_keywords.h>
110#endif
b0d623f7 111
0a7de745 112/*
2d21ac55
A
113 * define MB_DEBUG to display run-time debugging information
114 * #define MB_DEBUG 1
115 */
116
117#ifdef MB_DEBUG
0a7de745 118#define DPRINTF(x) printf x
2d21ac55
A
119#else
120#define MB_DEBUG
121#define DPRINTF(x)
122#endif
123
124#if CONFIG_MACF
0a7de745 125SYSCTL_NODE(, OID_AUTO, security, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
2d21ac55 126 "Security Controls");
0a7de745 127SYSCTL_NODE(_security, OID_AUTO, mac, CTLFLAG_RW | CTLFLAG_LOCKED, 0,
2d21ac55
A
128 "TrustedBSD MAC policy controls");
129
2d21ac55
A
130/*
131 * Declare that the kernel provides MAC support, version 1. This permits
132 * modules to refuse to be loaded if the necessary support isn't present,
133 * even if it's pre-boot.
134 */
135#if 0
136MODULE_VERSION(kernel_mac_support, 1);
137#endif
138
139#if MAC_MAX_SLOTS > 32
140#error "MAC_MAX_SLOTS too large"
141#endif
142
143static unsigned int mac_max_slots = MAC_MAX_SLOTS;
144static unsigned int mac_slot_offsets_free = (1 << MAC_MAX_SLOTS) - 1;
6d2010ae 145SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD | CTLFLAG_LOCKED,
2d21ac55
A
146 &mac_max_slots, 0, "");
147
148/*
149 * Has the kernel started generating labeled objects yet? All read/write
150 * access to this variable is serialized during the boot process. Following
151 * the end of serialization, we don't update this flag; no locking.
152 */
0a7de745 153int mac_late = 0;
2d21ac55
A
154
155/*
156 * Flag to indicate whether or not we should allocate label storage for
157 * new mbufs. Since most dynamic policies we currently work with don't
158 * rely on mbuf labeling, try to avoid paying the cost of mtag allocation
159 * unless specifically notified of interest. One result of this is
160 * that if a dynamically loaded policy requests mbuf labels, it must
161 * be able to deal with a NULL label being returned on any mbufs that
162 * were already in flight when the policy was loaded. Since the policy
163 * already has to deal with uninitialized labels, this probably won't
164 * be a problem. Note: currently no locking. Will this be a problem?
165 */
b0d623f7 166#if CONFIG_MACF_NET
0a7de745 167unsigned int mac_label_mbufs = 1;
316670eb 168SYSCTL_UINT(_security_mac, OID_AUTO, label_mbufs, SECURITY_MAC_CTLFLAGS,
0a7de745 169 &mac_label_mbufs, 0, "Label all MBUFs");
b0d623f7
A
170#endif
171
2d21ac55 172
b0d623f7
A
173/*
174 * Flag to indicate whether or not we should allocate label storage for
175 * new vnodes. Since most dynamic policies we currently work with don't
176 * rely on vnode labeling, try to avoid paying the cost of mtag allocation
177 * unless specifically notified of interest. One result of this is
178 * that if a dynamically loaded policy requests vnode labels, it must
179 * be able to deal with a NULL label being returned on any vnodes that
180 * were already in flight when the policy was loaded. Since the policy
181 * already has to deal with uninitialized labels, this probably won't
182 * be a problem.
183 */
cb323159
A
184#if CONFIG_MACF_LAZY_VNODE_LABELS
185unsigned int mac_label_vnodes = 1;
186#else
0a7de745 187unsigned int mac_label_vnodes = 0;
cb323159
A
188#endif /* CONFIG_MACF_LAZY_VNODE_LABELS */
189SYSCTL_UINT(_security_mac, OID_AUTO, labelvnodes, SECURITY_MAC_CTLFLAGS
190#if CONFIG_MACF_LAZY_VNODE_LABELS
191 | CTLFLAG_RD
192#endif
193 , &mac_label_vnodes, 0, "Label all vnodes");
194
195unsigned int mac_vnode_label_count = 0;
196SYSCTL_UINT(_security_mac, OID_AUTO, vnode_label_count, SECURITY_MAC_CTLFLAGS | CTLFLAG_RD,
197 &mac_vnode_label_count, 0, "Count of vnode labels");
b0d623f7 198
2d21ac55 199unsigned int mac_device_enforce = 1;
316670eb 200SYSCTL_UINT(_security_mac, OID_AUTO, device_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 201 &mac_device_enforce, 0, "Enforce MAC policy on device operations");
2d21ac55 202
0a7de745 203unsigned int mac_pipe_enforce = 1;
316670eb 204SYSCTL_UINT(_security_mac, OID_AUTO, pipe_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
205 &mac_pipe_enforce, 0, "Enforce MAC policy on pipe operations");
206
0a7de745 207unsigned int mac_posixsem_enforce = 1;
316670eb 208SYSCTL_UINT(_security_mac, OID_AUTO, posixsem_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
209 &mac_posixsem_enforce, 0, "Enforce MAC policy on POSIX semaphores");
210
211unsigned int mac_posixshm_enforce = 1;
316670eb 212SYSCTL_UINT(_security_mac, OID_AUTO, posixshm_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
213 &mac_posixshm_enforce, 0, "Enforce MAC policy on Posix Shared Memory");
214
0a7de745 215unsigned int mac_proc_enforce = 1;
316670eb 216SYSCTL_UINT(_security_mac, OID_AUTO, proc_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 217 &mac_proc_enforce, 0, "Enforce MAC policy on process operations");
2d21ac55
A
218
219unsigned int mac_socket_enforce = 1;
316670eb 220SYSCTL_UINT(_security_mac, OID_AUTO, socket_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 221 &mac_socket_enforce, 0, "Enforce MAC policy on socket operations");
2d21ac55 222
0a7de745 223unsigned int mac_system_enforce = 1;
316670eb 224SYSCTL_UINT(_security_mac, OID_AUTO, system_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
225 &mac_system_enforce, 0, "Enforce MAC policy on system-wide interfaces");
226
0a7de745 227unsigned int mac_sysvmsg_enforce = 1;
316670eb 228SYSCTL_UINT(_security_mac, OID_AUTO, sysvmsg_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
229 &mac_sysvmsg_enforce, 0, "Enforce MAC policy on System V IPC message queues");
230
0a7de745 231unsigned int mac_sysvsem_enforce = 1;
316670eb 232SYSCTL_UINT(_security_mac, OID_AUTO, sysvsem_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
233 &mac_sysvsem_enforce, 0, "Enforce MAC policy on System V IPC semaphores");
234
0a7de745 235unsigned int mac_sysvshm_enforce = 1;
316670eb 236SYSCTL_INT(_security_mac, OID_AUTO, sysvshm_enforce, SECURITY_MAC_CTLFLAGS,
2d21ac55
A
237 &mac_sysvshm_enforce, 0, "Enforce MAC policy on System V Shared Memory");
238
0a7de745 239unsigned int mac_vm_enforce = 1;
316670eb 240SYSCTL_INT(_security_mac, OID_AUTO, vm_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 241 &mac_vm_enforce, 0, "Enforce MAC policy on VM operations");
2d21ac55 242
0a7de745 243unsigned int mac_vnode_enforce = 1;
316670eb 244SYSCTL_UINT(_security_mac, OID_AUTO, vnode_enforce, SECURITY_MAC_CTLFLAGS,
0a7de745 245 &mac_vnode_enforce, 0, "Enforce MAC policy on vnode operations");
2d21ac55 246
b0d623f7 247#if CONFIG_AUDIT
2d21ac55
A
248/*
249 * mac_audit_data_zone is the zone used for data pushed into the audit
250 * record by policies. Using a zone simplifies memory management of this
251 * data, and allows tracking of the amount of data in flight.
252 */
253extern zone_t mac_audit_data_zone;
4a3eedf9 254#endif
2d21ac55
A
255
256/*
257 * mac_policy_list holds the list of policy modules. Modules with a
258 * handle lower than staticmax are considered "static" and cannot be
259 * unloaded. Such policies can be invoked without holding the busy count.
260 *
261 * Modules with a handle at or above the staticmax high water mark
262 * are considered to be "dynamic" policies. A busy count is maintained
263 * for the list, stored in mac_policy_busy. The busy count is protected
264 * by mac_policy_mtx; the list may be modified only while the busy
265 * count is 0, requiring that the lock be held to prevent new references
266 * to the list from being acquired. For almost all operations,
267 * incrementing the busy count is sufficient to guarantee consistency,
268 * as the list cannot be modified while the busy count is elevated.
269 * For a few special operations involving a change to the list of
270 * active policies, the mtx itself must be held.
271 */
272static lck_mtx_t *mac_policy_mtx;
273
274/*
275 * Policy list array allocation chunk size. Trying to set this so that we
276 * allocate a page at a time.
277 */
278#define MAC_POLICY_LIST_CHUNKSIZE 512
279
280static int mac_policy_busy;
281
5ba3f43e
A
282#if CONFIG_EMBEDDED
283SECURITY_READ_ONLY_LATE(mac_policy_list_t) mac_policy_list;
284SECURITY_READ_ONLY_LATE(static struct mac_policy_list_element) mac_policy_static_entries[MAC_POLICY_LIST_CHUNKSIZE];
285#else
2d21ac55 286mac_policy_list_t mac_policy_list;
5ba3f43e 287#endif
2d21ac55
A
288
289/*
290 * mac_label_element_list holds the master list of label namespaces for
291 * all the policies. When a policy is loaded, each of it's label namespace
292 * elements is added to the master list if not already present. When a
0a7de745 293 * policy is unloaded, the namespace elements are removed if no other
2d21ac55
A
294 * policy is interested in that namespace element.
295 */
296struct mac_label_element_list_t mac_label_element_list;
297struct mac_label_element_list_t mac_static_label_element_list;
298
2d21ac55
A
299static __inline void
300mac_policy_grab_exclusive(void)
301{
302 lck_mtx_lock(mac_policy_mtx);
303 while (mac_policy_busy != 0) {
304 lck_mtx_sleep(mac_policy_mtx, LCK_SLEEP_UNLOCK,
0a7de745 305 (event_t)&mac_policy_busy, THREAD_UNINT);
2d21ac55
A
306 lck_mtx_lock(mac_policy_mtx);
307 }
308}
309
2d21ac55
A
310static __inline void
311mac_policy_release_exclusive(void)
312{
2d21ac55
A
313 KASSERT(mac_policy_busy == 0,
314 ("mac_policy_release_exclusive(): not exclusive"));
315 lck_mtx_unlock(mac_policy_mtx);
316 thread_wakeup((event_t) &mac_policy_busy);
317}
318
319void
320mac_policy_list_busy(void)
321{
0a7de745 322 lck_mtx_lock(mac_policy_mtx);
2d21ac55
A
323 mac_policy_busy++;
324 lck_mtx_unlock(mac_policy_mtx);
325}
326
327int
328mac_policy_list_conditional_busy(void)
329{
330 int ret;
331
0a7de745
A
332 if (mac_policy_list.numloaded <= mac_policy_list.staticmax) {
333 return 0;
334 }
2d21ac55
A
335
336 lck_mtx_lock(mac_policy_mtx);
337 if (mac_policy_list.numloaded > mac_policy_list.staticmax) {
338 mac_policy_busy++;
339 ret = 1;
0a7de745 340 } else {
2d21ac55 341 ret = 0;
0a7de745 342 }
2d21ac55 343 lck_mtx_unlock(mac_policy_mtx);
0a7de745 344 return ret;
2d21ac55
A
345}
346
347void
348mac_policy_list_unbusy(void)
349{
350 lck_mtx_lock(mac_policy_mtx);
351 mac_policy_busy--;
352 KASSERT(mac_policy_busy >= 0, ("MAC_POLICY_LIST_LOCK"));
0a7de745 353 if (mac_policy_busy == 0) {
2d21ac55 354 thread_wakeup(&mac_policy_busy);
0a7de745 355 }
2d21ac55
A
356 lck_mtx_unlock(mac_policy_mtx);
357}
358
359/*
360 * Early pre-malloc MAC initialization, including appropriate SMP locks.
361 */
362void
363mac_policy_init(void)
364{
365 lck_grp_attr_t *mac_lck_grp_attr;
366 lck_attr_t *mac_lck_attr;
367 lck_grp_t *mac_lck_grp;
368
369 mac_policy_list.numloaded = 0;
370 mac_policy_list.max = MAC_POLICY_LIST_CHUNKSIZE;
371 mac_policy_list.maxindex = 0;
372 mac_policy_list.staticmax = 0;
373 mac_policy_list.freehint = 0;
374 mac_policy_list.chunks = 1;
375
5ba3f43e
A
376#if CONFIG_EMBEDDED
377 mac_policy_list.entries = mac_policy_static_entries;
378#else
2d21ac55 379 mac_policy_list.entries = kalloc(sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE);
5ba3f43e 380#endif
4bd07ac2 381
0a7de745 382 bzero(mac_policy_list.entries, sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE);
2d21ac55
A
383
384 LIST_INIT(&mac_label_element_list);
385 LIST_INIT(&mac_static_label_element_list);
2d21ac55
A
386
387 mac_lck_grp_attr = lck_grp_attr_alloc_init();
2d21ac55
A
388 mac_lck_grp = lck_grp_alloc_init("MAC lock", mac_lck_grp_attr);
389 mac_lck_attr = lck_attr_alloc_init();
390 lck_attr_setdefault(mac_lck_attr);
391 mac_policy_mtx = lck_mtx_alloc_init(mac_lck_grp, mac_lck_attr);
392 lck_attr_free(mac_lck_attr);
393 lck_grp_attr_free(mac_lck_grp_attr);
394 lck_grp_free(mac_lck_grp);
0a7de745 395
2d21ac55
A
396 mac_labelzone_init();
397}
398
b0d623f7
A
399/* Function pointer set up for loading security extensions.
400 * It is set to an actual function after OSlibkernInit()
401 * has been called, and is set back to 0 by OSKextRemoveKextBootstrap()
402 * after bsd_init().
403 */
404void (*load_security_extensions_function)(void) = 0;
405
2d21ac55
A
406/*
407 * Init after early Mach startup, but before BSD
408 */
409void
410mac_policy_initmach(void)
411{
2d21ac55
A
412 /*
413 * For the purposes of modules that want to know if they were
414 * loaded "early", set the mac_late flag once we've processed
415 * modules either linked into the kernel, or loaded before the
416 * kernel startup.
417 */
418
b0d623f7
A
419 if (load_security_extensions_function) {
420 load_security_extensions_function();
421 }
2d21ac55 422 mac_late = 1;
2d21ac55
A
423}
424
425/*
426 * BSD startup.
427 */
428void
429mac_policy_initbsd(void)
430{
431 struct mac_policy_conf *mpc;
432 u_int i;
433
b0d623f7 434#if CONFIG_AUDIT
2d21ac55 435 mac_audit_data_zone = zinit(MAC_AUDIT_DATA_LIMIT,
0a7de745
A
436 AQ_HIWATER * MAC_AUDIT_DATA_LIMIT,
437 8192, "mac_audit_data_zone");
4a3eedf9 438#endif
2d21ac55
A
439
440 printf("MAC Framework successfully initialized\n");
441
442 /* Call bsd init functions of already loaded policies */
443
444 /*
445 * Using the exclusive lock means no other framework entry
446 * points can proceed while initializations are running.
447 * This may not be necessary.
448 */
449 mac_policy_grab_exclusive();
450
451 for (i = 0; i <= mac_policy_list.maxindex; i++) {
452 mpc = mac_get_mpc(i);
0a7de745 453 if ((mpc != NULL) && (mpc->mpc_ops->mpo_policy_initbsd != NULL)) {
2d21ac55 454 (*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
0a7de745 455 }
2d21ac55
A
456 }
457
458 mac_policy_release_exclusive();
459}
460
461/*
462 * After a policy has been loaded, add the label namespaces managed by the
0a7de745
A
463 * policy to either the static or non-static label namespace list.
464 * A namespace is added to the the list only if it is not already on one of
2d21ac55
A
465 * the lists.
466 */
467void
468mac_policy_addto_labellist(mac_policy_handle_t handle, int static_entry)
469{
470 struct mac_label_listener **new_mlls;
471 struct mac_label_element *mle, **new_mles;
472 struct mac_label_element_list_t *list;
473 struct mac_policy_conf *mpc;
474 const char *name, *name2;
475 u_int idx, mle_free, mll_free;
476
477 mpc = mac_get_mpc(handle);
478
0a7de745 479 if (mpc->mpc_labelnames == NULL) {
2d21ac55 480 return;
0a7de745 481 }
2d21ac55 482
0a7de745 483 if (mpc->mpc_labelname_count == 0) {
2d21ac55 484 return;
0a7de745 485 }
2d21ac55 486
0a7de745 487 if (static_entry) {
2d21ac55 488 list = &mac_static_label_element_list;
0a7de745 489 } else {
2d21ac55 490 list = &mac_label_element_list;
0a7de745 491 }
2d21ac55
A
492
493 /*
494 * Before we grab the policy list lock, allocate enough memory
0a7de745 495 * to contain the potential new elements so we don't have to
2d21ac55
A
496 * give up the lock, or allocate with the lock held.
497 */
498 MALLOC(new_mles, struct mac_label_element **,
499 sizeof(struct mac_label_element *) *
500 mpc->mpc_labelname_count, M_MACTEMP, M_WAITOK | M_ZERO);
0a7de745
A
501 for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
502 MALLOC(new_mles[idx], struct mac_label_element *,
2d21ac55
A
503 sizeof(struct mac_label_element),
504 M_MACTEMP, M_WAITOK);
0a7de745 505 }
2d21ac55
A
506 mle_free = 0;
507 MALLOC(new_mlls, struct mac_label_listener **,
508 sizeof(struct mac_label_listener *) *
509 mpc->mpc_labelname_count, M_MACTEMP, M_WAITOK);
0a7de745 510 for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
2d21ac55
A
511 MALLOC(new_mlls[idx], struct mac_label_listener *,
512 sizeof(struct mac_label_listener), M_MACTEMP, M_WAITOK);
0a7de745 513 }
2d21ac55
A
514 mll_free = 0;
515
0a7de745 516 if (mac_late) {
2d21ac55 517 mac_policy_grab_exclusive();
0a7de745 518 }
2d21ac55 519 for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
0a7de745 520 if (*(name = mpc->mpc_labelnames[idx]) == '?') {
2d21ac55 521 name++;
0a7de745 522 }
2d21ac55 523 /*
0a7de745 524 * Check both label element lists and add to the
2d21ac55
A
525 * appropriate list only if not already on a list.
526 */
527 LIST_FOREACH(mle, &mac_static_label_element_list, mle_list) {
0a7de745 528 if (*(name2 = mle->mle_name) == '?') {
2d21ac55 529 name2++;
0a7de745
A
530 }
531 if (strcmp(name, name2) == 0) {
2d21ac55 532 break;
0a7de745 533 }
2d21ac55
A
534 }
535 if (mle == NULL) {
536 LIST_FOREACH(mle, &mac_label_element_list, mle_list) {
0a7de745 537 if (*(name2 = mle->mle_name) == '?') {
2d21ac55 538 name2++;
0a7de745
A
539 }
540 if (strcmp(name, name2) == 0) {
2d21ac55 541 break;
0a7de745 542 }
2d21ac55
A
543 }
544 }
545 if (mle == NULL) {
546 mle = new_mles[mle_free];
547 strlcpy(mle->mle_name, mpc->mpc_labelnames[idx],
0a7de745 548 MAC_MAX_LABEL_ELEMENT_NAME);
2d21ac55
A
549 LIST_INIT(&mle->mle_listeners);
550 LIST_INSERT_HEAD(list, mle, mle_list);
551 mle_free++;
552 }
553 /* Add policy handler as a listener. */
554 new_mlls[mll_free]->mll_handle = handle;
555 LIST_INSERT_HEAD(&mle->mle_listeners, new_mlls[mll_free],
556 mll_list);
557 mll_free++;
558 }
0a7de745 559 if (mac_late) {
2d21ac55 560 mac_policy_release_exclusive();
0a7de745 561 }
2d21ac55
A
562
563 /* Free up any unused label elements and listeners */
0a7de745 564 for (idx = mle_free; idx < mpc->mpc_labelname_count; idx++) {
2d21ac55 565 FREE(new_mles[idx], M_MACTEMP);
0a7de745 566 }
2d21ac55 567 FREE(new_mles, M_MACTEMP);
0a7de745 568 for (idx = mll_free; idx < mpc->mpc_labelname_count; idx++) {
2d21ac55 569 FREE(new_mlls[idx], M_MACTEMP);
0a7de745 570 }
2d21ac55
A
571 FREE(new_mlls, M_MACTEMP);
572}
573
574/*
575 * After a policy has been unloaded, remove the label namespaces that the
576 * the policy manages from the non-static list of namespaces.
577 * The removal only takes place when no other policy is interested in the
578 * namespace.
579 *
580 * Must be called with the policy exclusive lock held.
581 */
582void
583mac_policy_removefrom_labellist(mac_policy_handle_t handle)
584{
585 struct mac_label_listener *mll;
586 struct mac_label_element *mle;
587 struct mac_policy_conf *mpc;
588
589 mpc = mac_get_mpc(handle);
590
0a7de745 591 if (mpc->mpc_labelnames == NULL) {
2d21ac55 592 return;
0a7de745 593 }
2d21ac55 594
0a7de745 595 if (mpc->mpc_labelname_count == 0) {
2d21ac55 596 return;
0a7de745 597 }
2d21ac55
A
598
599 /*
600 * Unregister policy as being interested in any label
601 * namespaces. If no other policy is listening, remove
602 * that label element from the list. Note that we only
603 * have to worry about the non-static list.
604 */
605 LIST_FOREACH(mle, &mac_label_element_list, mle_list) {
606 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
607 if (mll->mll_handle == handle) {
608 LIST_REMOVE(mll, mll_list);
609 FREE(mll, M_MACTEMP);
610 if (LIST_EMPTY(&mle->mle_listeners)) {
611 LIST_REMOVE(mle, mle_list);
612 FREE(mle, M_MACTEMP);
613 }
614 return;
615 }
616 }
617 }
618}
619
620/*
621 * After the policy list has changed, walk the list to update any global
622 * flags.
623 */
624static void
625mac_policy_updateflags(void)
626{
2d21ac55
A
627}
628
629static __inline void
630mac_policy_fixup_mmd_list(struct mac_module_data *new)
631{
632 struct mac_module_data *old;
633 struct mac_module_data_element *ele, *aele;
634 struct mac_module_data_list *arr, *dict;
635 unsigned int i, j, k;
636
637 old = new->base_addr;
638 DPRINTF(("fixup_mmd: old %p new %p\n", old, new));
639 for (i = 0; i < new->count; i++) {
640 ele = &(new->data[i]);
641 DPRINTF(("fixup_mmd: ele %p\n", ele));
642 DPRINTF((" key %p value %p\n", ele->key, ele->value));
643 mmd_fixup_ele(old, new, ele); /* Fix up key/value ptrs. */
644 DPRINTF((" key %p value %p\n", ele->key, ele->value));
645 if (ele->value_type == MAC_DATA_TYPE_ARRAY) {
646 arr = (struct mac_module_data_list *)ele->value;
647 DPRINTF(("fixup_mmd: array @%p\n", arr));
648 for (j = 0; j < arr->count; j++) {
649 aele = &(arr->list[j]);
650 DPRINTF(("fixup_mmd: aele %p\n", aele));
651 DPRINTF((" key %p value %p\n", aele->key, aele->value));
652 mmd_fixup_ele(old, new, aele);
653 DPRINTF((" key %p value %p\n", aele->key, aele->value));
654 if (arr->type == MAC_DATA_TYPE_DICT) {
655 dict = (struct mac_module_data_list *)aele->value;
656 DPRINTF(("fixup_mmd: dict @%p\n", dict));
0a7de745 657 for (k = 0; k < dict->count; k++) {
2d21ac55
A
658 mmd_fixup_ele(old, new,
659 &(dict->list[k]));
0a7de745 660 }
2d21ac55
A
661 }
662 }
663 }
664 }
665 new->base_addr = new;
666}
667
668int
669mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep,
670 void *xd)
671{
5ba3f43e 672#if !CONFIG_EMBEDDED
2d21ac55 673 struct mac_policy_list_element *tmac_policy_list_element;
5ba3f43e 674#endif
2d21ac55
A
675 int error, slot, static_entry = 0;
676 u_int i;
677
678 /*
679 * Some preliminary checks to make sure the policy's conf structure
680 * contains the required fields.
681 */
0a7de745 682 if (mpc->mpc_name == NULL) {
2d21ac55 683 panic("policy's name is not set\n");
0a7de745 684 }
2d21ac55 685
0a7de745 686 if (mpc->mpc_fullname == NULL) {
2d21ac55 687 panic("policy's full name is not set\n");
0a7de745 688 }
2d21ac55 689
0a7de745 690 if (mpc->mpc_labelname_count > MAC_MAX_MANAGED_NAMESPACES) {
2d21ac55 691 panic("policy's managed label namespaces exceeds maximum\n");
0a7de745 692 }
2d21ac55 693
0a7de745 694 if (mpc->mpc_ops == NULL) {
2d21ac55 695 panic("policy's OPs field is NULL\n");
0a7de745 696 }
2d21ac55
A
697
698 error = 0;
699
700 if (mac_late) {
701 if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE) {
702 printf("Module %s does not support late loading.\n",
703 mpc->mpc_name);
0a7de745 704 return EPERM;
2d21ac55
A
705 }
706 mac_policy_grab_exclusive();
707 }
708
709 if (mac_policy_list.numloaded >= mac_policy_list.max) {
5ba3f43e 710#if !CONFIG_EMBEDDED
2d21ac55
A
711 /* allocate new policy list array, zero new chunk */
712 tmac_policy_list_element =
713 kalloc((sizeof(struct mac_policy_list_element) *
714 MAC_POLICY_LIST_CHUNKSIZE) * (mac_policy_list.chunks + 1));
715 bzero(&tmac_policy_list_element[mac_policy_list.max],
716 sizeof(struct mac_policy_list_element) *
717 MAC_POLICY_LIST_CHUNKSIZE);
0a7de745 718
2d21ac55 719 /* copy old entries into new list */
0a7de745
A
720 memcpy(tmac_policy_list_element, mac_policy_list.entries,
721 sizeof(struct mac_policy_list_element) *
722 MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks);
723
2d21ac55
A
724 /* free old array */
725 kfree(mac_policy_list.entries,
726 sizeof(struct mac_policy_list_element) *
727 MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks);
0a7de745 728
2d21ac55
A
729 mac_policy_list.entries = tmac_policy_list_element;
730
731 /* Update maximums, etc */
732 mac_policy_list.max += MAC_POLICY_LIST_CHUNKSIZE;
733 mac_policy_list.chunks++;
5ba3f43e
A
734#else
735 printf("out of space in mac_policy_list.\n");
0a7de745 736 return ENOMEM;
5ba3f43e 737#endif /* CONFIG_EMBEDDED */
2d21ac55
A
738 }
739
740 /* Check for policy with same name already loaded */
741 for (i = 0; i <= mac_policy_list.maxindex; i++) {
0a7de745
A
742 if (mac_policy_list.entries[i].mpc == NULL) {
743 continue;
744 }
2d21ac55
A
745
746 if (strcmp(mac_policy_list.entries[i].mpc->mpc_name,
747 mpc->mpc_name) == 0) {
748 error = EEXIST;
749 goto out;
750 }
751 }
752
753 if (mpc->mpc_field_off != NULL) {
754 slot = ffs(mac_slot_offsets_free);
755 if (slot == 0) {
756 error = ENOMEM;
757 goto out;
758 }
759 slot--;
760 mac_slot_offsets_free &= ~(1 << slot);
761 *mpc->mpc_field_off = slot;
762 }
763 mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
764
765 if (xd) {
766 struct mac_module_data *mmd = xd; /* module data from plist */
767
768 /* Make a copy of the data. */
769 mpc->mpc_data = (void *)kalloc(mmd->size);
770 if (mpc->mpc_data != NULL) {
771 memcpy(mpc->mpc_data, mmd, mmd->size);
772
773 /* Fix up pointers after copy. */
774 mac_policy_fixup_mmd_list(mpc->mpc_data);
775 }
776 }
777
778 /* Find the first free handle in the list (using our hint). */
779 for (i = mac_policy_list.freehint; i < mac_policy_list.max; i++) {
780 if (mac_policy_list.entries[i].mpc == NULL) {
781 *handlep = i;
782 mac_policy_list.freehint = ++i;
783 break;
784 }
785 }
786
787 /*
788 * If we are loading a MAC module before the framework has
789 * finished initializing or the module is not unloadable and
790 * we can place its handle adjacent to the last static entry,
791 * bump the static policy high water mark.
792 * Static policies can get by with weaker locking requirements.
793 */
794 if (!mac_late ||
795 ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0 &&
796 *handlep == mac_policy_list.staticmax)) {
797 static_entry = 1;
798 mac_policy_list.staticmax++;
799 }
800
801 mac_policy_list.entries[*handlep].mpc = mpc;
802
803 /* Update counters, etc */
0a7de745 804 if (*handlep > mac_policy_list.maxindex) {
2d21ac55 805 mac_policy_list.maxindex = *handlep;
0a7de745 806 }
2d21ac55 807 mac_policy_list.numloaded++;
0a7de745 808
2d21ac55 809 /* Per-policy initialization. */
0a7de745
A
810 printf("calling mpo_policy_init for %s\n", mpc->mpc_name);
811 if (mpc->mpc_ops->mpo_policy_init != NULL) {
2d21ac55 812 (*(mpc->mpc_ops->mpo_policy_init))(mpc);
0a7de745 813 }
2d21ac55
A
814
815 if (mac_late && mpc->mpc_ops->mpo_policy_initbsd != NULL) {
0a7de745 816 printf("calling mpo_policy_initbsd for %s\n", mpc->mpc_name);
2d21ac55
A
817 (*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
818 }
819
820 mac_policy_updateflags();
821
0a7de745 822 if (mac_late) {
2d21ac55 823 mac_policy_release_exclusive();
0a7de745 824 }
2d21ac55
A
825
826 mac_policy_addto_labellist(*handlep, static_entry);
827
828 printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
829 mpc->mpc_name);
830
0a7de745 831 return 0;
2d21ac55
A
832
833out:
0a7de745 834 if (mac_late) {
2d21ac55 835 mac_policy_release_exclusive();
0a7de745 836 }
2d21ac55 837
0a7de745 838 return error;
2d21ac55
A
839}
840
841int
842mac_policy_unregister(mac_policy_handle_t handle)
843{
844 struct mac_policy_conf *mpc;
845
846 /*
847 * If we fail the load, we may get a request to unload. Check
848 * to see if we did the run-time registration, and if not,
849 * silently succeed.
850 */
851 mac_policy_grab_exclusive();
852 mpc = mac_get_mpc(handle);
853 if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
854 mac_policy_release_exclusive();
0a7de745 855 return 0;
2d21ac55
A
856 }
857
858#if 0
859 /*
860 * Don't allow unloading modules with private data.
861 */
862 if (mpc->mpc_field_off != NULL) {
863 MAC_POLICY_LIST_UNLOCK();
0a7de745 864 return EBUSY;
2d21ac55
A
865 }
866#endif
867 /*
868 * Only allow the unload to proceed if the module is unloadable
869 * by its own definition.
870 */
871 if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
872 mac_policy_release_exclusive();
0a7de745 873 return EBUSY;
2d21ac55
A
874 }
875
876 mac_policy_removefrom_labellist(handle);
877
878 mac_get_mpc(handle) = NULL;
879 if (handle < mac_policy_list.freehint &&
0a7de745 880 handle >= mac_policy_list.staticmax) {
2d21ac55 881 mac_policy_list.freehint = handle;
0a7de745 882 }
2d21ac55 883
0a7de745 884 if (handle == mac_policy_list.maxindex) {
2d21ac55 885 mac_policy_list.maxindex--;
0a7de745 886 }
2d21ac55 887
0a7de745 888 mac_policy_list.numloaded--;
2d21ac55
A
889 if (mpc->mpc_field_off != NULL) {
890 mac_slot_offsets_free |= (1 << *mpc->mpc_field_off);
891 }
892
0a7de745 893 if (mpc->mpc_ops->mpo_policy_destroy != NULL) {
2d21ac55 894 (*(mpc->mpc_ops->mpo_policy_destroy))(mpc);
0a7de745 895 }
2d21ac55
A
896
897 mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
898 mac_policy_updateflags();
899
900 mac_policy_release_exclusive();
901
902 if (mpc->mpc_data) {
903 struct mac_module_data *mmd = mpc->mpc_data;
904 kfree(mmd, mmd->size);
905 mpc->mpc_data = NULL;
906 }
907
908 printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
909 mpc->mpc_name);
910
0a7de745 911 return 0;
2d21ac55
A
912}
913
914/*
915 * Define an error value precedence, and given two arguments, selects the
916 * value with the higher precedence.
917 */
918int
919mac_error_select(int error1, int error2)
920{
2d21ac55 921 /* Certain decision-making errors take top priority. */
0a7de745
A
922 if (error1 == EDEADLK || error2 == EDEADLK) {
923 return EDEADLK;
924 }
2d21ac55
A
925
926 /* Invalid arguments should be reported where possible. */
0a7de745
A
927 if (error1 == EINVAL || error2 == EINVAL) {
928 return EINVAL;
929 }
2d21ac55
A
930
931 /* Precedence goes to "visibility", with both process and file. */
0a7de745
A
932 if (error1 == ESRCH || error2 == ESRCH) {
933 return ESRCH;
934 }
2d21ac55 935
0a7de745
A
936 if (error1 == ENOENT || error2 == ENOENT) {
937 return ENOENT;
938 }
2d21ac55
A
939
940 /* Precedence goes to DAC/MAC protections. */
0a7de745
A
941 if (error1 == EACCES || error2 == EACCES) {
942 return EACCES;
943 }
2d21ac55
A
944
945 /* Precedence goes to privilege. */
0a7de745
A
946 if (error1 == EPERM || error2 == EPERM) {
947 return EPERM;
948 }
2d21ac55
A
949
950 /* Precedence goes to error over success; otherwise, arbitrary. */
0a7de745
A
951 if (error1 != 0) {
952 return error1;
953 }
954 return error2;
2d21ac55
A
955}
956
957void
958mac_label_init(struct label *label)
959{
2d21ac55
A
960 bzero(label, sizeof(*label));
961 label->l_flags = MAC_FLAG_INITIALIZED;
962}
963
964void
965mac_label_destroy(struct label *label)
966{
2d21ac55
A
967 KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
968 ("destroying uninitialized label"));
969
970 bzero(label, sizeof(*label));
971 /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
972}
973
2d21ac55
A
974int
975mac_check_structmac_consistent(struct user_mac *mac)
976{
0a7de745
A
977 if (mac->m_buflen > MAC_MAX_LABEL_BUF_LEN || mac->m_buflen == 0) {
978 return EINVAL;
979 }
2d21ac55 980
0a7de745 981 return 0;
2d21ac55
A
982}
983
984/*
985 * Get the external forms of labels from all policies, for a single
986 * label namespace or "*" for all namespaces. Returns ENOENT if no policy
987 * is registered for the namespace, unless the namespace begins with a '?'.
988 */
989static int
990mac_label_externalize(size_t mpo_externalize_off, struct label *label,
991 const char *element, struct sbuf *sb)
992{
993 struct mac_policy_conf *mpc;
994 struct mac_label_listener *mll;
995 struct mac_label_element *mle;
996 struct mac_label_element_list_t *element_list;
997 const char *name;
998 int (*mpo_externalize)(struct label *, char *, struct sbuf *);
999 int all_labels = 0, ignorenotfound = 0, error = 0, busy = FALSE;
1000 unsigned int count = 0;
1001
1002 if (element[0] == '?') {
1003 element++;
1004 ignorenotfound = 1;
0a7de745 1005 } else if (element[0] == '*' && element[1] == '\0') {
2d21ac55 1006 all_labels = 1;
0a7de745 1007 }
2d21ac55
A
1008
1009 element_list = &mac_static_label_element_list;
1010element_loop:
1011 LIST_FOREACH(mle, element_list, mle_list) {
1012 name = mle->mle_name;
1013 if (all_labels) {
0a7de745
A
1014 if (*name == '?') {
1015 continue;
1016 }
2d21ac55 1017 } else {
0a7de745 1018 if (*name == '?') {
2d21ac55 1019 name++;
0a7de745
A
1020 }
1021 if (strcmp(name, element) != 0) {
2d21ac55 1022 continue;
0a7de745 1023 }
2d21ac55
A
1024 }
1025 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1026 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
0a7de745 1027 if (mpc == NULL) {
2d21ac55 1028 continue;
0a7de745 1029 }
5ba3f43e
A
1030 mpo_externalize = *(const typeof(mpo_externalize) *)
1031 ((const char *)mpc->mpc_ops + mpo_externalize_off);
0a7de745 1032 if (mpo_externalize == NULL) {
2d21ac55 1033 continue;
0a7de745 1034 }
2d21ac55 1035 error = sbuf_printf(sb, "%s/", name);
0a7de745 1036 if (error) {
2d21ac55 1037 goto done;
0a7de745 1038 }
2d21ac55
A
1039 error = mpo_externalize(label, mle->mle_name, sb);
1040 if (error) {
0a7de745 1041 if (error != ENOENT) {
2d21ac55 1042 goto done;
0a7de745 1043 }
2d21ac55
A
1044 /*
1045 * If a policy doesn't have a label to
1046 * externalize it returns ENOENT. This
1047 * may occur for policies that support
1048 * multiple label elements for some
1049 * (but not all) object types.
1050 */
1051 sbuf_setpos(sb, sbuf_len(sb) -
1052 (strlen(name) + 1));
1053 error = 0;
1054 continue;
1055 }
1056 error = sbuf_putc(sb, ',');
0a7de745 1057 if (error) {
2d21ac55 1058 goto done;
0a7de745 1059 }
2d21ac55
A
1060 count++;
1061 }
1062 }
1063 /* If there are dynamic policies present, check their elements too. */
1064 if (!busy && mac_policy_list_conditional_busy() == 1) {
1065 element_list = &mac_label_element_list;
1066 busy = TRUE;
1067 goto element_loop;
1068 }
1069done:
0a7de745 1070 if (busy) {
2d21ac55 1071 mac_policy_list_unbusy();
0a7de745 1072 }
2d21ac55 1073 if (!error && count == 0) {
0a7de745
A
1074 if (!all_labels && !ignorenotfound) {
1075 error = ENOENT; /* XXX: ENOLABEL? */
1076 }
2d21ac55 1077 }
0a7de745 1078 return error;
2d21ac55
A
1079}
1080
1081/*
1082 * Get the external forms of labels from all policies, for all label
1083 * namespaces contained in a list.
b0d623f7
A
1084 *
1085 * XXX This may be leaking an sbuf.
2d21ac55
A
1086 */
1087int
1088mac_externalize(size_t mpo_externalize_off, struct label *label,
1089 const char *elementlist, char *outbuf, size_t outbuflen)
1090{
1091 char *element;
b0d623f7
A
1092 char *scratch_base;
1093 char *scratch;
2d21ac55
A
1094 struct sbuf sb;
1095 int error = 0, len;
1096
b0d623f7 1097 /* allocate a scratch buffer the size of the string */
0a7de745 1098 MALLOC(scratch_base, char *, strlen(elementlist) + 1, M_MACTEMP, M_WAITOK);
b0d623f7
A
1099 if (scratch_base == NULL) {
1100 error = ENOMEM;
1101 goto out;
1102 }
1103
1104 /* copy the elementlist to the scratch buffer */
0a7de745 1105 strlcpy(scratch_base, elementlist, strlen(elementlist) + 1);
b0d623f7
A
1106
1107 /*
1108 * set up a temporary pointer that can be used to iterate the
1109 * scratch buffer without losing the allocation address
1110 */
1111 scratch = scratch_base;
1112
1113 /* get an sbuf */
1114 if (sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN) == NULL) {
1115 /* could not allocate interior buffer */
1116 error = ENOMEM;
1117 goto out;
1118 }
1119 /* iterate the scratch buffer; NOTE: buffer contents modified! */
1120 while ((element = strsep(&scratch, ",")) != NULL) {
2d21ac55
A
1121 error = mac_label_externalize(mpo_externalize_off, label,
1122 element, &sb);
0a7de745 1123 if (error) {
2d21ac55 1124 break;
0a7de745
A
1125 }
1126 }
1127 if ((len = sbuf_len(&sb)) > 0) {
1128 sbuf_setpos(&sb, len - 1); /* trim trailing comma */
2d21ac55 1129 }
2d21ac55 1130 sbuf_finish(&sb);
b0d623f7
A
1131
1132out:
0a7de745 1133 if (scratch_base != NULL) {
b0d623f7 1134 FREE(scratch_base, M_MACTEMP);
0a7de745 1135 }
b0d623f7 1136
0a7de745 1137 return error;
2d21ac55
A
1138}
1139
1140/*
1141 * Have all policies set the internal form of a label, for a single
1142 * label namespace.
1143 */
1144static int
1145mac_label_internalize(size_t mpo_internalize_off, struct label *label,
1146 char *element_name, char *element_data)
1147{
1148 struct mac_policy_conf *mpc;
1149 struct mac_label_listener *mll;
1150 struct mac_label_element *mle;
1151 struct mac_label_element_list_t *element_list;
1152 int (*mpo_internalize)(struct label *, char *, char *);
1153 int error = 0, busy = FALSE;
1154 unsigned int count = 0;
1155 const char *name;
1156
1157 element_list = &mac_static_label_element_list;
1158element_loop:
1159 LIST_FOREACH(mle, element_list, mle_list) {
0a7de745 1160 if (*(name = mle->mle_name) == '?') {
2d21ac55 1161 name++;
0a7de745
A
1162 }
1163 if (strcmp(element_name, name) != 0) {
2d21ac55 1164 continue;
0a7de745 1165 }
2d21ac55
A
1166 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1167 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
0a7de745 1168 if (mpc == NULL) {
2d21ac55 1169 continue;
0a7de745 1170 }
5ba3f43e
A
1171 mpo_internalize = *(const typeof(mpo_internalize) *)
1172 ((const char *)mpc->mpc_ops + mpo_internalize_off);
0a7de745 1173 if (mpo_internalize == NULL) {
2d21ac55 1174 continue;
0a7de745 1175 }
2d21ac55
A
1176 error = mpo_internalize(label, element_name,
1177 element_data);
0a7de745 1178 if (error) {
2d21ac55 1179 goto done;
0a7de745 1180 }
2d21ac55
A
1181 count++;
1182 }
1183 }
1184 /* If there are dynamic policies present, check their elements too. */
1185 if (!busy && mac_policy_list_conditional_busy() == 1) {
1186 element_list = &mac_label_element_list;
1187 busy = TRUE;
1188 goto element_loop;
1189 }
1190done:
0a7de745 1191 if (busy) {
2d21ac55 1192 mac_policy_list_unbusy();
0a7de745
A
1193 }
1194 if (!error && count == 0) {
2d21ac55 1195 error = ENOPOLICY;
0a7de745
A
1196 }
1197 return error;
2d21ac55
A
1198}
1199
1200int
1201mac_internalize(size_t mpo_internalize_off, struct label *label,
1202 char *textlabels)
1203{
1204 char *element_name, *element_data;
1205 int error = 0;
1206
1207 while (!error && (element_name = strsep(&textlabels, ",")) != NULL) {
1208 element_data = strchr(element_name, '/');
1209 if (element_data == NULL) {
1210 error = EINVAL;
1211 break;
1212 }
1213 *element_data++ = '\0';
1214 error = mac_label_internalize(mpo_internalize_off, label,
1215 element_name, element_data);
1216 }
0a7de745 1217 return error;
2d21ac55
A
1218}
1219
1220/* system calls */
1221
1222int
b0d623f7 1223__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, int *ret __unused)
2d21ac55
A
1224{
1225 char *elements, *buffer;
1226 struct user_mac mac;
1227 struct proc *tproc;
1228 struct ucred *tcred;
1229 int error;
1230 size_t ulen;
1231
1232 AUDIT_ARG(pid, uap->pid);
1233 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1234 struct user64_mac mac64;
1235 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1236 mac.m_buflen = mac64.m_buflen;
1237 mac.m_string = mac64.m_string;
2d21ac55 1238 } else {
6d2010ae 1239 struct user32_mac mac32;
2d21ac55
A
1240 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1241 mac.m_buflen = mac32.m_buflen;
6d2010ae 1242 mac.m_string = mac32.m_string;
2d21ac55 1243 }
0a7de745
A
1244 if (error) {
1245 return error;
1246 }
2d21ac55
A
1247
1248 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1249 if (error) {
1250 return error;
1251 }
2d21ac55
A
1252
1253 tproc = proc_find(uap->pid);
0a7de745
A
1254 if (tproc == NULL) {
1255 return ESRCH;
1256 }
2d21ac55
A
1257 tcred = kauth_cred_proc_ref(tproc);
1258 proc_rele(tproc);
1259
1260 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1261 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1262 if (error) {
1263 FREE(elements, M_MACTEMP);
1264 kauth_cred_unref(&tcred);
0a7de745 1265 return error;
2d21ac55
A
1266 }
1267 AUDIT_ARG(mac_string, elements);
1268
1269 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1270 error = mac_cred_label_externalize(tcred->cr_label, elements,
1271 buffer, mac.m_buflen, M_WAITOK);
0a7de745
A
1272 if (error == 0) {
1273 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1274 }
2d21ac55
A
1275
1276 FREE(buffer, M_MACTEMP);
1277 FREE(elements, M_MACTEMP);
1278 kauth_cred_unref(&tcred);
0a7de745 1279 return error;
2d21ac55
A
1280}
1281
1282int
b0d623f7 1283__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, int *ret __unused)
2d21ac55
A
1284{
1285 char *elements, *buffer;
1286 struct user_mac mac;
1287 kauth_cred_t cr;
1288 int error;
1289 size_t ulen;
1290
1291 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1292 struct user64_mac mac64;
1293 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1294 mac.m_buflen = mac64.m_buflen;
1295 mac.m_string = mac64.m_string;
2d21ac55 1296 } else {
6d2010ae 1297 struct user32_mac mac32;
2d21ac55
A
1298 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1299 mac.m_buflen = mac32.m_buflen;
6d2010ae 1300 mac.m_string = mac32.m_string;
2d21ac55 1301 }
0a7de745
A
1302 if (error) {
1303 return error;
1304 }
2d21ac55
A
1305
1306 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1307 if (error) {
1308 return error;
1309 }
2d21ac55
A
1310
1311 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1312 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1313 if (error) {
1314 FREE(elements, M_MACTEMP);
0a7de745 1315 return error;
2d21ac55
A
1316 }
1317 AUDIT_ARG(mac_string, elements);
1318
1319 cr = kauth_cred_proc_ref(p);
1320
1321 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1322 error = mac_cred_label_externalize(cr->cr_label,
1323 elements, buffer, mac.m_buflen, M_WAITOK);
0a7de745
A
1324 if (error == 0) {
1325 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1326 }
2d21ac55
A
1327
1328 FREE(buffer, M_MACTEMP);
1329 FREE(elements, M_MACTEMP);
1330 kauth_cred_unref(&cr);
0a7de745 1331 return error;
2d21ac55
A
1332}
1333
2d21ac55 1334int
b0d623f7 1335__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, int *ret __unused)
2d21ac55 1336{
2d21ac55
A
1337 struct label *intlabel;
1338 struct user_mac mac;
1339 char *buffer;
1340 int error;
1341 size_t ulen;
1342
1343 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1344 struct user64_mac mac64;
1345 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1346 mac.m_buflen = mac64.m_buflen;
1347 mac.m_string = mac64.m_string;
2d21ac55 1348 } else {
6d2010ae 1349 struct user32_mac mac32;
2d21ac55
A
1350 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1351 mac.m_buflen = mac32.m_buflen;
6d2010ae 1352 mac.m_string = mac32.m_string;
2d21ac55 1353 }
0a7de745
A
1354 if (error) {
1355 return error;
1356 }
2d21ac55
A
1357
1358 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1359 if (error) {
1360 return error;
1361 }
2d21ac55
A
1362
1363 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1364 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1365 if (error) {
1366 FREE(buffer, M_MACTEMP);
0a7de745 1367 return error;
2d21ac55
A
1368 }
1369 AUDIT_ARG(mac_string, buffer);
1370
1371 intlabel = mac_cred_label_alloc();
1372 error = mac_cred_label_internalize(intlabel, buffer);
1373 FREE(buffer, M_MACTEMP);
0a7de745 1374 if (error) {
2d21ac55 1375 goto out;
0a7de745 1376 }
2d21ac55
A
1377
1378 error = mac_cred_check_label_update(kauth_cred_get(), intlabel);
1379 if (error) {
1380 goto out;
1381 }
1382
1383 error = kauth_proc_label_update(p, intlabel);
0a7de745 1384 if (error) {
2d21ac55 1385 goto out;
0a7de745 1386 }
2d21ac55 1387
2d21ac55
A
1388out:
1389 mac_cred_label_free(intlabel);
0a7de745 1390 return error;
2d21ac55
A
1391}
1392
2d21ac55 1393int
b0d623f7 1394__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, int *ret __unused)
2d21ac55
A
1395{
1396 struct fileproc *fp;
1397 struct vnode *vp;
1398 struct user_mac mac;
1399 char *elements, *buffer;
1400 int error;
1401 size_t ulen;
1402 kauth_cred_t my_cred;
1403#if CONFIG_MACF_SOCKET
1404 struct socket *so;
0a7de745 1405#endif /* MAC_SOCKET */
2d21ac55
A
1406 struct label *intlabel;
1407
1408 AUDIT_ARG(fd, uap->fd);
1409
1410 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1411 struct user64_mac mac64;
1412 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1413 mac.m_buflen = mac64.m_buflen;
1414 mac.m_string = mac64.m_string;
2d21ac55 1415 } else {
6d2010ae 1416 struct user32_mac mac32;
2d21ac55
A
1417 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1418 mac.m_buflen = mac32.m_buflen;
6d2010ae 1419 mac.m_string = mac32.m_string;
2d21ac55
A
1420 }
1421
0a7de745
A
1422 if (error) {
1423 return error;
1424 }
2d21ac55
A
1425
1426 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1427 if (error) {
1428 return error;
1429 }
1430
2d21ac55
A
1431 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1432 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1433 if (error) {
1434 FREE(elements, M_MACTEMP);
0a7de745 1435 return error;
2d21ac55
A
1436 }
1437 AUDIT_ARG(mac_string, elements);
1438
1439 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1440 error = fp_lookup(p, uap->fd, &fp, 0);
1441 if (error) {
1442 FREE(buffer, M_MACTEMP);
1443 FREE(elements, M_MACTEMP);
0a7de745 1444 return error;
2d21ac55 1445 }
0a7de745 1446
2d21ac55
A
1447 my_cred = kauth_cred_proc_ref(p);
1448 error = mac_file_check_get(my_cred, fp->f_fglob, elements, mac.m_buflen);
1449 kauth_cred_unref(&my_cred);
1450 if (error) {
1451 fp_drop(p, uap->fd, fp, 0);
1452 FREE(buffer, M_MACTEMP);
1453 FREE(elements, M_MACTEMP);
0a7de745 1454 return error;
2d21ac55 1455 }
0a7de745 1456
39236c6e 1457 switch (FILEGLOB_DTYPE(fp->f_fglob)) {
0a7de745
A
1458 case DTYPE_VNODE:
1459 intlabel = mac_vnode_label_alloc();
1460 if (intlabel == NULL) {
1461 error = ENOMEM;
2d21ac55 1462 break;
0a7de745
A
1463 }
1464 vp = (struct vnode *)fp->f_fglob->fg_data;
1465 error = vnode_getwithref(vp);
1466 if (error == 0) {
1467 mac_vnode_label_copy(vp->v_label, intlabel);
1468 error = mac_vnode_label_externalize(intlabel,
1469 elements, buffer,
1470 mac.m_buflen, M_WAITOK);
1471 vnode_put(vp);
1472 }
1473 mac_vnode_label_free(intlabel);
1474 break;
1475 case DTYPE_SOCKET:
2d21ac55 1476#if CONFIG_MACF_SOCKET
0a7de745
A
1477 so = (struct socket *) fp->f_fglob->fg_data;
1478 intlabel = mac_socket_label_alloc(MAC_WAITOK);
1479 sock_lock(so, 1);
1480 mac_socket_label_copy(so->so_label, intlabel);
1481 sock_unlock(so, 1);
1482 error = mac_socket_label_externalize(intlabel, elements, buffer, mac.m_buflen);
1483 mac_socket_label_free(intlabel);
1484 break;
2d21ac55 1485#endif
0a7de745
A
1486 case DTYPE_PSXSHM:
1487 case DTYPE_PSXSEM:
1488 case DTYPE_PIPE:
1489 case DTYPE_KQUEUE:
1490 case DTYPE_FSEVENTS:
1491 case DTYPE_ATALK:
1492 case DTYPE_NETPOLICY:
1493 default:
1494 error = ENOSYS; // only sockets/vnodes so far
1495 break;
2d21ac55
A
1496 }
1497 fp_drop(p, uap->fd, fp, 0);
0a7de745
A
1498
1499 if (error == 0) {
1500 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
1501 }
1502
2d21ac55
A
1503 FREE(buffer, M_MACTEMP);
1504 FREE(elements, M_MACTEMP);
0a7de745 1505 return error;
2d21ac55
A
1506}
1507
2d21ac55
A
1508static int
1509mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow)
1510{
1511 struct vnode *vp;
1512 vfs_context_t ctx;
1513 char *elements, *buffer;
1514 struct nameidata nd;
1515 struct label *intlabel;
1516 struct user_mac mac;
1517 int error;
1518 size_t ulen;
1519
1520 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1521 struct user64_mac mac64;
1522 error = copyin(mac_p, &mac64, sizeof(mac64));
1523 mac.m_buflen = mac64.m_buflen;
1524 mac.m_string = mac64.m_string;
2d21ac55 1525 } else {
6d2010ae 1526 struct user32_mac mac32;
2d21ac55
A
1527 error = copyin(mac_p, &mac32, sizeof(mac32));
1528 mac.m_buflen = mac32.m_buflen;
6d2010ae 1529 mac.m_string = mac32.m_string;
2d21ac55
A
1530 }
1531
0a7de745
A
1532 if (error) {
1533 return error;
1534 }
2d21ac55
A
1535
1536 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1537 if (error) {
1538 return error;
1539 }
2d21ac55
A
1540
1541 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
b0d623f7
A
1542 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1543
2d21ac55
A
1544 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1545 if (error) {
b0d623f7 1546 FREE(buffer, M_MACTEMP);
2d21ac55 1547 FREE(elements, M_MACTEMP);
0a7de745 1548 return error;
2d21ac55
A
1549 }
1550 AUDIT_ARG(mac_string, elements);
1551
1552 ctx = vfs_context_current();
1553
6d2010ae 1554 NDINIT(&nd, LOOKUP, OP_LOOKUP,
0a7de745
A
1555 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1556 UIO_USERSPACE, path_p, ctx);
2d21ac55
A
1557 error = namei(&nd);
1558 if (error) {
b0d623f7 1559 FREE(buffer, M_MACTEMP);
2d21ac55 1560 FREE(elements, M_MACTEMP);
0a7de745 1561 return error;
2d21ac55
A
1562 }
1563 vp = nd.ni_vp;
1564
1565 nameidone(&nd);
1566
1567 intlabel = mac_vnode_label_alloc();
1568 mac_vnode_label_copy(vp->v_label, intlabel);
2d21ac55 1569 error = mac_vnode_label_externalize(intlabel, elements, buffer,
0a7de745 1570 mac.m_buflen, M_WAITOK);
b0d623f7 1571 mac_vnode_label_free(intlabel);
0a7de745 1572 if (error == 0) {
2d21ac55 1573 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
0a7de745 1574 }
2d21ac55
A
1575
1576 vnode_put(vp);
b0d623f7
A
1577
1578 FREE(buffer, M_MACTEMP);
1579 FREE(elements, M_MACTEMP);
2d21ac55 1580
0a7de745 1581 return error;
2d21ac55
A
1582}
1583
1584int
1585__mac_get_file(proc_t p, struct __mac_get_file_args *uap,
0a7de745 1586 int *ret __unused)
2d21ac55 1587{
0a7de745 1588 return mac_get_filelink(p, uap->mac_p, uap->path_p, 1);
2d21ac55
A
1589}
1590
1591int
1592__mac_get_link(proc_t p, struct __mac_get_link_args *uap,
0a7de745 1593 int *ret __unused)
2d21ac55 1594{
0a7de745 1595 return mac_get_filelink(p, uap->mac_p, uap->path_p, 0);
2d21ac55
A
1596}
1597
1598int
b0d623f7 1599__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, int *ret __unused)
2d21ac55 1600{
2d21ac55
A
1601 struct fileproc *fp;
1602 struct user_mac mac;
1603 struct vfs_context *ctx = vfs_context_current();
1604 int error;
1605 size_t ulen;
1606 char *buffer;
1607 struct label *intlabel;
1608#if CONFIG_MACF_SOCKET
1609 struct socket *so;
1610#endif
1611 struct vnode *vp;
1612
1613 AUDIT_ARG(fd, uap->fd);
1614
1615 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1616 struct user64_mac mac64;
1617 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1618 mac.m_buflen = mac64.m_buflen;
1619 mac.m_string = mac64.m_string;
2d21ac55 1620 } else {
6d2010ae 1621 struct user32_mac mac32;
2d21ac55
A
1622 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1623 mac.m_buflen = mac32.m_buflen;
6d2010ae 1624 mac.m_string = mac32.m_string;
2d21ac55 1625 }
0a7de745
A
1626 if (error) {
1627 return error;
1628 }
1629
2d21ac55 1630 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1631 if (error) {
1632 return error;
1633 }
1634
2d21ac55
A
1635 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1636 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1637 if (error) {
1638 FREE(buffer, M_MACTEMP);
0a7de745 1639 return error;
2d21ac55
A
1640 }
1641 AUDIT_ARG(mac_string, buffer);
0a7de745 1642
2d21ac55
A
1643 error = fp_lookup(p, uap->fd, &fp, 0);
1644 if (error) {
1645 FREE(buffer, M_MACTEMP);
0a7de745 1646 return error;
2d21ac55 1647 }
0a7de745 1648
2d21ac55
A
1649
1650 error = mac_file_check_set(vfs_context_ucred(ctx), fp->f_fglob, buffer, mac.m_buflen);
1651 if (error) {
1652 fp_drop(p, uap->fd, fp, 0);
1653 FREE(buffer, M_MACTEMP);
0a7de745 1654 return error;
2d21ac55 1655 }
2d21ac55 1656
0a7de745
A
1657 switch (FILEGLOB_DTYPE(fp->f_fglob)) {
1658 case DTYPE_VNODE:
1659 if (mac_label_vnodes == 0) {
1660 error = ENOSYS;
1661 break;
1662 }
b0d623f7 1663
0a7de745 1664 intlabel = mac_vnode_label_alloc();
2d21ac55 1665
0a7de745
A
1666 error = mac_vnode_label_internalize(intlabel, buffer);
1667 if (error) {
1668 mac_vnode_label_free(intlabel);
1669 break;
1670 }
2d21ac55
A
1671
1672
0a7de745 1673 vp = (struct vnode *)fp->f_fglob->fg_data;
2d21ac55 1674
0a7de745
A
1675 error = vnode_getwithref(vp);
1676 if (error == 0) {
1677 error = vn_setlabel(vp, intlabel, ctx);
1678 vnode_put(vp);
1679 }
1680 mac_vnode_label_free(intlabel);
1681 break;
2d21ac55 1682
0a7de745 1683 case DTYPE_SOCKET:
2d21ac55 1684#if CONFIG_MACF_SOCKET
0a7de745
A
1685 intlabel = mac_socket_label_alloc(MAC_WAITOK);
1686 error = mac_socket_label_internalize(intlabel, buffer);
1687 if (error == 0) {
1688 so = (struct socket *) fp->f_fglob->fg_data;
1689 SOCK_LOCK(so);
1690 error = mac_socket_label_update(vfs_context_ucred(ctx), so, intlabel);
1691 SOCK_UNLOCK(so);
1692 }
1693 mac_socket_label_free(intlabel);
1694 break;
2d21ac55 1695#endif
0a7de745
A
1696 case DTYPE_PSXSHM:
1697 case DTYPE_PSXSEM:
1698 case DTYPE_PIPE:
1699 case DTYPE_KQUEUE:
1700 case DTYPE_FSEVENTS:
1701 case DTYPE_ATALK:
1702 case DTYPE_NETPOLICY:
1703 default:
1704 error = ENOSYS; // only sockets/vnodes so far
1705 break;
2d21ac55
A
1706 }
1707
1708 fp_drop(p, uap->fd, fp, 0);
1709 FREE(buffer, M_MACTEMP);
0a7de745 1710 return error;
2d21ac55
A
1711}
1712
2d21ac55
A
1713static int
1714mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p,
0a7de745 1715 int follow)
2d21ac55 1716{
39037602 1717 struct vnode *vp;
2d21ac55
A
1718 struct vfs_context *ctx = vfs_context_current();
1719 struct label *intlabel;
1720 struct nameidata nd;
1721 struct user_mac mac;
1722 char *buffer;
1723 int error;
1724 size_t ulen;
1725
0a7de745 1726 if (mac_label_vnodes == 0) {
b0d623f7 1727 return ENOSYS;
0a7de745 1728 }
b0d623f7 1729
2d21ac55 1730 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1731 struct user64_mac mac64;
1732 error = copyin(mac_p, &mac64, sizeof(mac64));
1733 mac.m_buflen = mac64.m_buflen;
1734 mac.m_string = mac64.m_string;
2d21ac55 1735 } else {
6d2010ae 1736 struct user32_mac mac32;
2d21ac55
A
1737 error = copyin(mac_p, &mac32, sizeof(mac32));
1738 mac.m_buflen = mac32.m_buflen;
6d2010ae 1739 mac.m_string = mac32.m_string;
2d21ac55 1740 }
0a7de745
A
1741 if (error) {
1742 return error;
1743 }
2d21ac55
A
1744
1745 error = mac_check_structmac_consistent(&mac);
1746 if (error) {
1747 printf("mac_set_file: failed structure consistency check\n");
0a7de745 1748 return error;
2d21ac55
A
1749 }
1750
1751 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1752 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1753 if (error) {
1754 FREE(buffer, M_MACTEMP);
0a7de745 1755 return error;
2d21ac55
A
1756 }
1757 AUDIT_ARG(mac_string, buffer);
1758
1759 intlabel = mac_vnode_label_alloc();
1760 error = mac_vnode_label_internalize(intlabel, buffer);
1761 FREE(buffer, M_MACTEMP);
1762 if (error) {
1763 mac_vnode_label_free(intlabel);
0a7de745 1764 return error;
2d21ac55
A
1765 }
1766
6d2010ae 1767 NDINIT(&nd, LOOKUP, OP_LOOKUP,
0a7de745
A
1768 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1769 UIO_USERSPACE, path_p, ctx);
2d21ac55
A
1770 error = namei(&nd);
1771 if (error) {
1772 mac_vnode_label_free(intlabel);
0a7de745 1773 return error;
2d21ac55
A
1774 }
1775 vp = nd.ni_vp;
1776
1777 nameidone(&nd);
1778
1779 error = vn_setlabel(vp, intlabel, ctx);
1780 vnode_put(vp);
1781 mac_vnode_label_free(intlabel);
1782
0a7de745 1783 return error;
2d21ac55
A
1784}
1785
1786int
1787__mac_set_file(proc_t p, struct __mac_set_file_args *uap,
0a7de745 1788 int *ret __unused)
2d21ac55 1789{
0a7de745 1790 return mac_set_filelink(p, uap->mac_p, uap->path_p, 1);
2d21ac55
A
1791}
1792
1793int
1794__mac_set_link(proc_t p, struct __mac_set_link_args *uap,
0a7de745 1795 int *ret __unused)
2d21ac55 1796{
0a7de745 1797 return mac_set_filelink(p, uap->mac_p, uap->path_p, 0);
2d21ac55
A
1798}
1799
1800/*
b0d623f7
A
1801 * __mac_syscall: Perform a MAC policy system call
1802 *
1803 * Parameters: p Process calling this routine
1804 * uap User argument descriptor (see below)
1805 * retv (Unused)
1806 *
1807 * Indirect: uap->policy Name of target MAC policy
1808 * uap->call MAC policy-specific system call to perform
1809 * uap->arg MAC policy-specific system call arguments
0a7de745 1810 *
b0d623f7
A
1811 * Returns: 0 Success
1812 * !0 Not success
1813 *
2d21ac55 1814 */
2d21ac55 1815int
b0d623f7 1816__mac_syscall(proc_t p, struct __mac_syscall_args *uap, int *retv __unused)
2d21ac55
A
1817{
1818 struct mac_policy_conf *mpc;
1819 char target[MAC_MAX_POLICY_NAME];
1820 int error;
1821 u_int i;
1822 size_t ulen;
1823
1824 error = copyinstr(uap->policy, target, sizeof(target), &ulen);
0a7de745
A
1825 if (error) {
1826 return error;
1827 }
b0d623f7 1828 AUDIT_ARG(value32, uap->call);
2d21ac55
A
1829 AUDIT_ARG(mac_string, target);
1830
1831 error = ENOPOLICY;
1832
1833 for (i = 0; i < mac_policy_list.staticmax; i++) {
1834 mpc = mac_policy_list.entries[i].mpc;
0a7de745 1835 if (mpc == NULL) {
2d21ac55 1836 continue;
0a7de745 1837 }
2d21ac55
A
1838
1839 if (strcmp(mpc->mpc_name, target) == 0 &&
1840 mpc->mpc_ops->mpo_policy_syscall != NULL) {
1841 error = mpc->mpc_ops->mpo_policy_syscall(p,
1842 uap->call, uap->arg);
1843 goto done;
0a7de745 1844 }
2d21ac55
A
1845 }
1846 if (mac_policy_list_conditional_busy() != 0) {
1847 for (; i <= mac_policy_list.maxindex; i++) {
1848 mpc = mac_policy_list.entries[i].mpc;
0a7de745 1849 if (mpc == NULL) {
2d21ac55 1850 continue;
0a7de745 1851 }
2d21ac55
A
1852
1853 if (strcmp(mpc->mpc_name, target) == 0 &&
1854 mpc->mpc_ops->mpo_policy_syscall != NULL) {
1855 error = mpc->mpc_ops->mpo_policy_syscall(p,
1856 uap->call, uap->arg);
1857 break;
1858 }
1859 }
1860 mac_policy_list_unbusy();
1861 }
1862
1863done:
0a7de745 1864 return error;
2d21ac55
A
1865}
1866
1867int
1868mac_mount_label_get(struct mount *mp, user_addr_t mac_p)
1869{
1870 char *elements, *buffer;
1871 struct label *label;
1872 struct user_mac mac;
1873 int error;
1874 size_t ulen;
1875
1876 if (IS_64BIT_PROCESS(current_proc())) {
6d2010ae
A
1877 struct user64_mac mac64;
1878 error = copyin(mac_p, &mac64, sizeof(mac64));
1879 mac.m_buflen = mac64.m_buflen;
1880 mac.m_string = mac64.m_string;
2d21ac55 1881 } else {
6d2010ae 1882 struct user32_mac mac32;
2d21ac55
A
1883 error = copyin(mac_p, &mac32, sizeof(mac32));
1884 mac.m_buflen = mac32.m_buflen;
6d2010ae 1885 mac.m_string = mac32.m_string;
2d21ac55 1886 }
0a7de745
A
1887 if (error) {
1888 return error;
1889 }
2d21ac55
A
1890
1891 error = mac_check_structmac_consistent(&mac);
0a7de745
A
1892 if (error) {
1893 return error;
1894 }
2d21ac55
A
1895
1896 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1897 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1898 if (error) {
1899 FREE(elements, M_MACTEMP);
0a7de745 1900 return error;
2d21ac55
A
1901 }
1902 AUDIT_ARG(mac_string, elements);
1903
1904 label = mp->mnt_mntlabel;
1905 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1906 error = mac_mount_label_externalize(label, elements, buffer,
1907 mac.m_buflen);
1908 FREE(elements, M_MACTEMP);
1909
0a7de745 1910 if (error == 0) {
2d21ac55 1911 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
0a7de745 1912 }
2d21ac55
A
1913 FREE(buffer, M_MACTEMP);
1914
0a7de745 1915 return error;
2d21ac55
A
1916}
1917
b0d623f7
A
1918/*
1919 * __mac_get_mount: Get mount point label information for a given pathname
1920 *
1921 * Parameters: p (ignored)
1922 * uap User argument descriptor (see below)
1923 * ret (ignored)
1924 *
1925 * Indirect: uap->path Pathname
0a7de745 1926 * uap->mac_p MAC info
b0d623f7
A
1927 *
1928 * Returns: 0 Success
1929 * !0 Not success
1930 */
2d21ac55
A
1931int
1932__mac_get_mount(proc_t p __unused, struct __mac_get_mount_args *uap,
b0d623f7 1933 int *ret __unused)
2d21ac55
A
1934{
1935 struct nameidata nd;
1936 struct vfs_context *ctx = vfs_context_current();
1937 struct mount *mp;
1938 int error;
1939
6d2010ae 1940 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | AUDITVNPATH1,
0a7de745 1941 UIO_USERSPACE, uap->path, ctx);
2d21ac55
A
1942 error = namei(&nd);
1943 if (error) {
0a7de745 1944 return error;
2d21ac55
A
1945 }
1946 mp = nd.ni_vp->v_mount;
fe8ab488 1947 vnode_put(nd.ni_vp);
2d21ac55
A
1948 nameidone(&nd);
1949
1950 return mac_mount_label_get(mp, uap->mac_p);
1951}
1952
316670eb
A
1953/*
1954 * mac_schedule_userret()
1955 *
1956 * Schedule a callback to the mpo_thread_userret hook. The mpo_thread_userret
1957 * hook is called just before the thread exit from the kernel in ast_taken().
1958 *
1959 * Returns: 0 Success
0a7de745 1960 * !0 Not successful
316670eb
A
1961 */
1962int
1963mac_schedule_userret(void)
1964{
316670eb 1965 act_set_astmacf(current_thread());
0a7de745 1966 return 0;
316670eb
A
1967}
1968
1969/*
1970 * mac_do_machexc()
1971 *
1972 * Do a Mach exception. This should only be done in the mpo_thread_userret
1973 * callback.
1974 *
1975 * params: code exception code
0a7de745
A
1976 * subcode exception subcode
1977 * flags flags:
1978 * MAC_DOEXCF_TRACED Only do exception if being
1979 * ptrace()'ed.
316670eb
A
1980 *
1981 *
1982 * Returns: 0 Success
0a7de745 1983 * !0 Not successful
316670eb
A
1984 */
1985int
1986mac_do_machexc(int64_t code, int64_t subcode, uint32_t flags)
1987{
1988 mach_exception_data_type_t codes[EXCEPTION_CODE_MAX];
1989 proc_t p = current_proc();
1990
1991 /* Only allow execption codes in MACF's reserved range. */
0a7de745
A
1992 if ((code < EXC_MACF_MIN) || (code > EXC_MACF_MAX)) {
1993 return 1;
1994 }
316670eb
A
1995
1996 if (flags & MAC_DOEXCF_TRACED &&
0a7de745
A
1997 !(p->p_lflag & P_LTRACED && (p->p_lflag & P_LPPWAIT) == 0)) {
1998 return 0;
1999 }
316670eb
A
2000
2001
2002 /* Send the Mach exception */
2003 codes[0] = (mach_exception_data_type_t)code;
2004 codes[1] = (mach_exception_data_type_t)subcode;
2005
0a7de745 2006 return bsd_exception(EXC_SOFTWARE, codes, 2) != KERN_SUCCESS;
316670eb
A
2007}
2008
2d21ac55
A
2009#else /* MAC */
2010
39236c6e
A
2011void (*load_security_extensions_function)(void) = 0;
2012
2013struct sysctl_oid_list sysctl__security_mac_children;
2014
2d21ac55 2015int
0a7de745
A
2016mac_policy_register(struct mac_policy_conf *mpc __unused,
2017 mac_policy_handle_t *handlep __unused, void *xd __unused)
2d21ac55 2018{
0a7de745 2019 return 0;
2d21ac55
A
2020}
2021
2022int
2023mac_policy_unregister(mac_policy_handle_t handle __unused)
2024{
0a7de745 2025 return 0;
2d21ac55
A
2026}
2027
2028int
2029mac_audit_text(char *text __unused, mac_policy_handle_t handle __unused)
2030{
0a7de745 2031 return 0;
2d21ac55
A
2032}
2033
2d21ac55
A
2034int
2035mac_vnop_setxattr(struct vnode *vp __unused, const char *name __unused, char *buf __unused, size_t len __unused)
2036{
0a7de745 2037 return ENOENT;
2d21ac55
A
2038}
2039
2040int
0a7de745
A
2041mac_vnop_getxattr(struct vnode *vp __unused, const char *name __unused,
2042 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
2d21ac55 2043{
0a7de745 2044 return ENOENT;
2d21ac55
A
2045}
2046
2047int
2048mac_vnop_removexattr(struct vnode *vp __unused, const char *name __unused)
2049{
0a7de745 2050 return ENOENT;
2d21ac55
A
2051}
2052
39037602
A
2053int
2054mac_file_setxattr(struct fileglob *fg __unused, const char *name __unused, char *buf __unused, size_t len __unused)
2055{
0a7de745 2056 return ENOENT;
39037602
A
2057}
2058
2059int
2060mac_file_getxattr(struct fileglob *fg __unused, const char *name __unused,
0a7de745 2061 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
39037602 2062{
0a7de745 2063 return ENOENT;
39037602
A
2064}
2065
2066int
2067mac_file_removexattr(struct fileglob *fg __unused, const char *name __unused)
2068{
0a7de745 2069 return ENOENT;
39037602
A
2070}
2071
0a7de745
A
2072intptr_t
2073mac_label_get(struct label *l __unused, int slot __unused)
2d21ac55 2074{
0a7de745 2075 return 0;
2d21ac55
A
2076}
2077
0a7de745
A
2078void
2079mac_label_set(struct label *l __unused, int slot __unused, intptr_t v __unused)
2d21ac55 2080{
0a7de745 2081 return;
2d21ac55
A
2082}
2083
39236c6e 2084int mac_iokit_check_hid_control(kauth_cred_t cred __unused);
0a7de745
A
2085int
2086mac_iokit_check_hid_control(kauth_cred_t cred __unused)
316670eb 2087{
0a7de745 2088 return 0;
316670eb
A
2089}
2090
527f9951 2091int mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused, struct vnode *dvp __unused, struct componentname *cnp __unused);
0a7de745
A
2092int
2093mac_vnode_check_trigger_resolve(vfs_context_t ctx __unused, struct vnode *dvp __unused, struct componentname *cnp __unused)
527f9951
A
2094{
2095 return 0;
2096}
2097
2d21ac55 2098#endif /* !MAC */