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