]> git.saurik.com Git - apple/xnu.git/blame - security/mac_base.c
xnu-2422.90.20.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
297/*
298 * Journal of label operations that occur before policies are loaded.
299 */
300struct mac_label_journal_list_t mac_label_journal_list;
301
302int
303mac_label_journal_add (struct label *l, int type)
304{
305 struct mac_label_journal *mlj;
306
307 if (mac_label_journal_find(l))
308 return (0);
309
310 MALLOC(mlj, struct mac_label_journal *,
311 sizeof(struct mac_label_journal), M_MACTEMP, M_WAITOK);
312 mlj->l = l;
313 mlj->type = type;
314 TAILQ_INSERT_TAIL(&mac_label_journal_list, mlj, link);
315
316 return (0);
317}
318
319int
320mac_label_journal_remove (struct label *l)
321{
322 struct mac_label_journal *mlj;
323
324 mlj = mac_label_journal_find(l);
325 if (mlj == NULL)
326 return (-1);
327
328 TAILQ_REMOVE(&mac_label_journal_list, mlj, link);
329 FREE(mlj, M_MACTEMP);
330 return (0);
331}
332
333struct mac_label_journal *
334mac_label_journal_find (struct label *l)
335{
336 struct mac_label_journal *mlj;
337
338 TAILQ_FOREACH(mlj, &mac_label_journal_list, link) {
339 if (l == mlj->l)
340 return (mlj);
341 }
342
343 return (NULL);
344}
345
346int
347mac_label_journal (struct label *l, int op, ...)
348{
349 struct mac_label_journal *mlj;
350 va_list ap;
351
352 mlj = mac_label_journal_find(l);
353 if (mlj == NULL) {
354 printf("%s(): Label not in list!\n", __func__);
355 return (-1);
356 }
357
358 if (op == MLJ_PORT_OP_UPDATE) {
359 va_start(ap, op);
360 mlj->kotype = va_arg(ap, int);
361 va_end(ap);
362 }
363
364 mlj->ops |= op;
365 return (0);
366}
367
368/*
369 * The assumption during replay is that the system is totally
370 * serialized and no additional tasks/ports will be created.
371 */
372void
373mac_label_journal_replay (void)
374{
375 struct mac_label_journal *mlj;
376
377 TAILQ_FOREACH(mlj, &mac_label_journal_list, link) {
378 switch (mlj->type) {
379 case MLJ_TYPE_PORT:
380 if (mlj->ops & MLJ_PORT_OP_INIT)
381 MAC_PERFORM(port_label_init, mlj->l);
382 if (mlj->ops & MLJ_PORT_OP_CREATE_K)
383 MAC_PERFORM(port_label_associate_kernel, mlj->l, 0);
384 if (mlj->ops & MLJ_PORT_OP_UPDATE)
385 MAC_PERFORM(port_label_update_kobject, mlj->l,
386 mlj->kotype);
387 break;
388 case MLJ_TYPE_TASK:
389 if (mlj->ops & MLJ_TASK_OP_INIT)
390 MAC_PERFORM(task_label_init, mlj->l);
391#if 0
392 /* Not enough context to replay. */
393 if (mlj->ops & MLJ_TASK_OP_CREATE_K)
394 ;
395#endif
396 break;
397 default:
398 break;
399 }
400 }
401
402 /* Free list */
403 while (!TAILQ_EMPTY(&mac_label_journal_list)) {
404 mlj = TAILQ_FIRST(&mac_label_journal_list);
405 TAILQ_REMOVE(&mac_label_journal_list, mlj, link);
406 FREE(mlj, M_MACTEMP);
407 }
408 return;
409}
410
411static __inline void
412mac_policy_grab_exclusive(void)
413{
414 lck_mtx_lock(mac_policy_mtx);
415 while (mac_policy_busy != 0) {
416 lck_mtx_sleep(mac_policy_mtx, LCK_SLEEP_UNLOCK,
417 (event_t)&mac_policy_busy, THREAD_UNINT);
418 lck_mtx_lock(mac_policy_mtx);
419 }
420}
421
422static __inline void
423mac_policy_assert_exclusive(void)
424{
425 lck_mtx_assert(mac_policy_mtx, LCK_MTX_ASSERT_OWNED);
426 KASSERT(mac_policy_busy == 0,
427 ("mac_policy_assert_exclusive(): not exclusive"));
428}
429
430static __inline void
431mac_policy_release_exclusive(void)
432{
433
434 KASSERT(mac_policy_busy == 0,
435 ("mac_policy_release_exclusive(): not exclusive"));
436 lck_mtx_unlock(mac_policy_mtx);
437 thread_wakeup((event_t) &mac_policy_busy);
438}
439
440void
441mac_policy_list_busy(void)
442{
443 lck_mtx_lock(mac_policy_mtx);
444 mac_policy_busy++;
445 lck_mtx_unlock(mac_policy_mtx);
446}
447
448int
449mac_policy_list_conditional_busy(void)
450{
451 int ret;
452
453 if (mac_policy_list.numloaded <= mac_policy_list.staticmax)
454 return(0);
455
456 lck_mtx_lock(mac_policy_mtx);
457 if (mac_policy_list.numloaded > mac_policy_list.staticmax) {
458 mac_policy_busy++;
459 ret = 1;
460 } else
461 ret = 0;
462 lck_mtx_unlock(mac_policy_mtx);
463 return (ret);
464}
465
466void
467mac_policy_list_unbusy(void)
468{
469 lck_mtx_lock(mac_policy_mtx);
470 mac_policy_busy--;
471 KASSERT(mac_policy_busy >= 0, ("MAC_POLICY_LIST_LOCK"));
472 if (mac_policy_busy == 0)
473 thread_wakeup(&mac_policy_busy);
474 lck_mtx_unlock(mac_policy_mtx);
475}
476
477/*
478 * Early pre-malloc MAC initialization, including appropriate SMP locks.
479 */
480void
481mac_policy_init(void)
482{
483 lck_grp_attr_t *mac_lck_grp_attr;
484 lck_attr_t *mac_lck_attr;
485 lck_grp_t *mac_lck_grp;
486
487 mac_policy_list.numloaded = 0;
488 mac_policy_list.max = MAC_POLICY_LIST_CHUNKSIZE;
489 mac_policy_list.maxindex = 0;
490 mac_policy_list.staticmax = 0;
491 mac_policy_list.freehint = 0;
492 mac_policy_list.chunks = 1;
493
494 mac_policy_list.entries = kalloc(sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE);
495 bzero(mac_policy_list.entries, sizeof(struct mac_policy_list_element) * MAC_POLICY_LIST_CHUNKSIZE);
496
497 LIST_INIT(&mac_label_element_list);
498 LIST_INIT(&mac_static_label_element_list);
499 TAILQ_INIT(&mac_label_journal_list);
500
501 mac_lck_grp_attr = lck_grp_attr_alloc_init();
502 lck_grp_attr_setstat(mac_lck_grp_attr);
503 mac_lck_grp = lck_grp_alloc_init("MAC lock", mac_lck_grp_attr);
504 mac_lck_attr = lck_attr_alloc_init();
505 lck_attr_setdefault(mac_lck_attr);
506 mac_policy_mtx = lck_mtx_alloc_init(mac_lck_grp, mac_lck_attr);
507 lck_attr_free(mac_lck_attr);
508 lck_grp_attr_free(mac_lck_grp_attr);
509 lck_grp_free(mac_lck_grp);
510
511 mac_labelzone_init();
512}
513
b0d623f7
A
514/* Function pointer set up for loading security extensions.
515 * It is set to an actual function after OSlibkernInit()
516 * has been called, and is set back to 0 by OSKextRemoveKextBootstrap()
517 * after bsd_init().
518 */
519void (*load_security_extensions_function)(void) = 0;
520
2d21ac55
A
521/*
522 * Init after early Mach startup, but before BSD
523 */
524void
525mac_policy_initmach(void)
526{
527
528 /*
529 * For the purposes of modules that want to know if they were
530 * loaded "early", set the mac_late flag once we've processed
531 * modules either linked into the kernel, or loaded before the
532 * kernel startup.
533 */
534
b0d623f7
A
535 if (load_security_extensions_function) {
536 load_security_extensions_function();
537 }
2d21ac55
A
538 mac_late = 1;
539#if CONFIG_MACF_MACH
540 mac_label_journal_replay();
541#endif
542}
543
544/*
545 * BSD startup.
546 */
547void
548mac_policy_initbsd(void)
549{
550 struct mac_policy_conf *mpc;
551 u_int i;
552
b0d623f7 553#if CONFIG_AUDIT
2d21ac55
A
554 mac_audit_data_zone = zinit(MAC_AUDIT_DATA_LIMIT,
555 AQ_HIWATER * MAC_AUDIT_DATA_LIMIT,
556 8192, "mac_audit_data_zone");
4a3eedf9 557#endif
2d21ac55
A
558
559 printf("MAC Framework successfully initialized\n");
560
561 /* Call bsd init functions of already loaded policies */
562
563 /*
564 * Using the exclusive lock means no other framework entry
565 * points can proceed while initializations are running.
566 * This may not be necessary.
567 */
568 mac_policy_grab_exclusive();
569
570 for (i = 0; i <= mac_policy_list.maxindex; i++) {
571 mpc = mac_get_mpc(i);
572 if ((mpc != NULL) && (mpc->mpc_ops->mpo_policy_initbsd != NULL))
573 (*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
574 }
575
576 mac_policy_release_exclusive();
577}
578
579/*
580 * After a policy has been loaded, add the label namespaces managed by the
581 * policy to either the static or non-static label namespace list.
582 * A namespace is added to the the list only if it is not already on one of
583 * the lists.
584 */
585void
586mac_policy_addto_labellist(mac_policy_handle_t handle, int static_entry)
587{
588 struct mac_label_listener **new_mlls;
589 struct mac_label_element *mle, **new_mles;
590 struct mac_label_element_list_t *list;
591 struct mac_policy_conf *mpc;
592 const char *name, *name2;
593 u_int idx, mle_free, mll_free;
594
595 mpc = mac_get_mpc(handle);
596
597 if (mpc->mpc_labelnames == NULL)
598 return;
599
600 if (mpc->mpc_labelname_count == 0)
601 return;
602
603 if (static_entry)
604 list = &mac_static_label_element_list;
605 else
606 list = &mac_label_element_list;
607
608 /*
609 * Before we grab the policy list lock, allocate enough memory
610 * to contain the potential new elements so we don't have to
611 * give up the lock, or allocate with the lock held.
612 */
613 MALLOC(new_mles, struct mac_label_element **,
614 sizeof(struct mac_label_element *) *
615 mpc->mpc_labelname_count, M_MACTEMP, M_WAITOK | M_ZERO);
616 for (idx = 0; idx < mpc->mpc_labelname_count; idx++)
617 MALLOC(new_mles[idx], struct mac_label_element *,
618 sizeof(struct mac_label_element),
619 M_MACTEMP, M_WAITOK);
620 mle_free = 0;
621 MALLOC(new_mlls, struct mac_label_listener **,
622 sizeof(struct mac_label_listener *) *
623 mpc->mpc_labelname_count, M_MACTEMP, M_WAITOK);
624 for (idx = 0; idx < mpc->mpc_labelname_count; idx++)
625 MALLOC(new_mlls[idx], struct mac_label_listener *,
626 sizeof(struct mac_label_listener), M_MACTEMP, M_WAITOK);
627 mll_free = 0;
628
629 if (mac_late)
630 mac_policy_grab_exclusive();
631 for (idx = 0; idx < mpc->mpc_labelname_count; idx++) {
632
633 if (*(name = mpc->mpc_labelnames[idx]) == '?')
634 name++;
635 /*
636 * Check both label element lists and add to the
637 * appropriate list only if not already on a list.
638 */
639 LIST_FOREACH(mle, &mac_static_label_element_list, mle_list) {
640 if (*(name2 = mle->mle_name) == '?')
641 name2++;
642 if (strcmp(name, name2) == 0)
643 break;
644 }
645 if (mle == NULL) {
646 LIST_FOREACH(mle, &mac_label_element_list, mle_list) {
647 if (*(name2 = mle->mle_name) == '?')
648 name2++;
649 if (strcmp(name, name2) == 0)
650 break;
651 }
652 }
653 if (mle == NULL) {
654 mle = new_mles[mle_free];
655 strlcpy(mle->mle_name, mpc->mpc_labelnames[idx],
656 MAC_MAX_LABEL_ELEMENT_NAME);
657 LIST_INIT(&mle->mle_listeners);
658 LIST_INSERT_HEAD(list, mle, mle_list);
659 mle_free++;
660 }
661 /* Add policy handler as a listener. */
662 new_mlls[mll_free]->mll_handle = handle;
663 LIST_INSERT_HEAD(&mle->mle_listeners, new_mlls[mll_free],
664 mll_list);
665 mll_free++;
666 }
667 if (mac_late)
668 mac_policy_release_exclusive();
669
670 /* Free up any unused label elements and listeners */
671 for (idx = mle_free; idx < mpc->mpc_labelname_count; idx++)
672 FREE(new_mles[idx], M_MACTEMP);
673 FREE(new_mles, M_MACTEMP);
674 for (idx = mll_free; idx < mpc->mpc_labelname_count; idx++)
675 FREE(new_mlls[idx], M_MACTEMP);
676 FREE(new_mlls, M_MACTEMP);
677}
678
679/*
680 * After a policy has been unloaded, remove the label namespaces that the
681 * the policy manages from the non-static list of namespaces.
682 * The removal only takes place when no other policy is interested in the
683 * namespace.
684 *
685 * Must be called with the policy exclusive lock held.
686 */
687void
688mac_policy_removefrom_labellist(mac_policy_handle_t handle)
689{
690 struct mac_label_listener *mll;
691 struct mac_label_element *mle;
692 struct mac_policy_conf *mpc;
693
694 mpc = mac_get_mpc(handle);
695
696 if (mpc->mpc_labelnames == NULL)
697 return;
698
699 if (mpc->mpc_labelname_count == 0)
700 return;
701
702 /*
703 * Unregister policy as being interested in any label
704 * namespaces. If no other policy is listening, remove
705 * that label element from the list. Note that we only
706 * have to worry about the non-static list.
707 */
708 LIST_FOREACH(mle, &mac_label_element_list, mle_list) {
709 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
710 if (mll->mll_handle == handle) {
711 LIST_REMOVE(mll, mll_list);
712 FREE(mll, M_MACTEMP);
713 if (LIST_EMPTY(&mle->mle_listeners)) {
714 LIST_REMOVE(mle, mle_list);
715 FREE(mle, M_MACTEMP);
716 }
717 return;
718 }
719 }
720 }
721}
722
723/*
724 * After the policy list has changed, walk the list to update any global
725 * flags.
726 */
727static void
728mac_policy_updateflags(void)
729{
2d21ac55
A
730}
731
732static __inline void
733mac_policy_fixup_mmd_list(struct mac_module_data *new)
734{
735 struct mac_module_data *old;
736 struct mac_module_data_element *ele, *aele;
737 struct mac_module_data_list *arr, *dict;
738 unsigned int i, j, k;
739
740 old = new->base_addr;
741 DPRINTF(("fixup_mmd: old %p new %p\n", old, new));
742 for (i = 0; i < new->count; i++) {
743 ele = &(new->data[i]);
744 DPRINTF(("fixup_mmd: ele %p\n", ele));
745 DPRINTF((" key %p value %p\n", ele->key, ele->value));
746 mmd_fixup_ele(old, new, ele); /* Fix up key/value ptrs. */
747 DPRINTF((" key %p value %p\n", ele->key, ele->value));
748 if (ele->value_type == MAC_DATA_TYPE_ARRAY) {
749 arr = (struct mac_module_data_list *)ele->value;
750 DPRINTF(("fixup_mmd: array @%p\n", arr));
751 for (j = 0; j < arr->count; j++) {
752 aele = &(arr->list[j]);
753 DPRINTF(("fixup_mmd: aele %p\n", aele));
754 DPRINTF((" key %p value %p\n", aele->key, aele->value));
755 mmd_fixup_ele(old, new, aele);
756 DPRINTF((" key %p value %p\n", aele->key, aele->value));
757 if (arr->type == MAC_DATA_TYPE_DICT) {
758 dict = (struct mac_module_data_list *)aele->value;
759 DPRINTF(("fixup_mmd: dict @%p\n", dict));
760 for (k = 0; k < dict->count; k++)
761 mmd_fixup_ele(old, new,
762 &(dict->list[k]));
763 }
764 }
765 }
766 }
767 new->base_addr = new;
768}
769
770int
771mac_policy_register(struct mac_policy_conf *mpc, mac_policy_handle_t *handlep,
772 void *xd)
773{
774 struct mac_policy_list_element *tmac_policy_list_element;
775 int error, slot, static_entry = 0;
776 u_int i;
777
778 /*
779 * Some preliminary checks to make sure the policy's conf structure
780 * contains the required fields.
781 */
782 if (mpc->mpc_name == NULL)
783 panic("policy's name is not set\n");
784
785 if (mpc->mpc_fullname == NULL)
786 panic("policy's full name is not set\n");
787
788 if (mpc->mpc_labelname_count > MAC_MAX_MANAGED_NAMESPACES)
789 panic("policy's managed label namespaces exceeds maximum\n");
790
791 if (mpc->mpc_ops == NULL)
792 panic("policy's OPs field is NULL\n");
793
794 error = 0;
795
796 if (mac_late) {
797 if (mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_NOTLATE) {
798 printf("Module %s does not support late loading.\n",
799 mpc->mpc_name);
800 return (EPERM);
801 }
802 mac_policy_grab_exclusive();
803 }
804
805 if (mac_policy_list.numloaded >= mac_policy_list.max) {
806 /* allocate new policy list array, zero new chunk */
807 tmac_policy_list_element =
808 kalloc((sizeof(struct mac_policy_list_element) *
809 MAC_POLICY_LIST_CHUNKSIZE) * (mac_policy_list.chunks + 1));
810 bzero(&tmac_policy_list_element[mac_policy_list.max],
811 sizeof(struct mac_policy_list_element) *
812 MAC_POLICY_LIST_CHUNKSIZE);
813
814 /* copy old entries into new list */
815 memcpy(tmac_policy_list_element, mac_policy_list.entries,
816 sizeof(struct mac_policy_list_element) *
817 MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks);
818
819 /* free old array */
820 kfree(mac_policy_list.entries,
821 sizeof(struct mac_policy_list_element) *
822 MAC_POLICY_LIST_CHUNKSIZE * mac_policy_list.chunks);
823
824 mac_policy_list.entries = tmac_policy_list_element;
825
826 /* Update maximums, etc */
827 mac_policy_list.max += MAC_POLICY_LIST_CHUNKSIZE;
828 mac_policy_list.chunks++;
829 }
830
831 /* Check for policy with same name already loaded */
832 for (i = 0; i <= mac_policy_list.maxindex; i++) {
833 if (mac_policy_list.entries[i].mpc == NULL)
834 continue;
835
836 if (strcmp(mac_policy_list.entries[i].mpc->mpc_name,
837 mpc->mpc_name) == 0) {
838 error = EEXIST;
839 goto out;
840 }
841 }
842
843 if (mpc->mpc_field_off != NULL) {
844 slot = ffs(mac_slot_offsets_free);
845 if (slot == 0) {
846 error = ENOMEM;
847 goto out;
848 }
849 slot--;
850 mac_slot_offsets_free &= ~(1 << slot);
851 *mpc->mpc_field_off = slot;
852 }
853 mpc->mpc_runtime_flags |= MPC_RUNTIME_FLAG_REGISTERED;
854
855 if (xd) {
856 struct mac_module_data *mmd = xd; /* module data from plist */
857
858 /* Make a copy of the data. */
859 mpc->mpc_data = (void *)kalloc(mmd->size);
860 if (mpc->mpc_data != NULL) {
861 memcpy(mpc->mpc_data, mmd, mmd->size);
862
863 /* Fix up pointers after copy. */
864 mac_policy_fixup_mmd_list(mpc->mpc_data);
865 }
866 }
867
868 /* Find the first free handle in the list (using our hint). */
869 for (i = mac_policy_list.freehint; i < mac_policy_list.max; i++) {
870 if (mac_policy_list.entries[i].mpc == NULL) {
871 *handlep = i;
872 mac_policy_list.freehint = ++i;
873 break;
874 }
875 }
876
877 /*
878 * If we are loading a MAC module before the framework has
879 * finished initializing or the module is not unloadable and
880 * we can place its handle adjacent to the last static entry,
881 * bump the static policy high water mark.
882 * Static policies can get by with weaker locking requirements.
883 */
884 if (!mac_late ||
885 ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0 &&
886 *handlep == mac_policy_list.staticmax)) {
887 static_entry = 1;
888 mac_policy_list.staticmax++;
889 }
890
891 mac_policy_list.entries[*handlep].mpc = mpc;
892
893 /* Update counters, etc */
894 if (*handlep > mac_policy_list.maxindex)
895 mac_policy_list.maxindex = *handlep;
896 mac_policy_list.numloaded++;
897
898 /* Per-policy initialization. */
899 printf ("calling mpo_policy_init for %s\n", mpc->mpc_name);
900 if (mpc->mpc_ops->mpo_policy_init != NULL)
901 (*(mpc->mpc_ops->mpo_policy_init))(mpc);
902
903 if (mac_late && mpc->mpc_ops->mpo_policy_initbsd != NULL) {
904 printf ("calling mpo_policy_initbsd for %s\n", mpc->mpc_name);
905 (*(mpc->mpc_ops->mpo_policy_initbsd))(mpc);
906 }
907
908 mac_policy_updateflags();
909
910 if (mac_late)
911 mac_policy_release_exclusive();
912
913 mac_policy_addto_labellist(*handlep, static_entry);
914
915 printf("Security policy loaded: %s (%s)\n", mpc->mpc_fullname,
916 mpc->mpc_name);
917
918 return (0);
919
920out:
921 if (mac_late)
922 mac_policy_release_exclusive();
923
924 return (error);
925}
926
927int
928mac_policy_unregister(mac_policy_handle_t handle)
929{
930 struct mac_policy_conf *mpc;
931
932 /*
933 * If we fail the load, we may get a request to unload. Check
934 * to see if we did the run-time registration, and if not,
935 * silently succeed.
936 */
937 mac_policy_grab_exclusive();
938 mpc = mac_get_mpc(handle);
939 if ((mpc->mpc_runtime_flags & MPC_RUNTIME_FLAG_REGISTERED) == 0) {
940 mac_policy_release_exclusive();
941 return (0);
942 }
943
944#if 0
945 /*
946 * Don't allow unloading modules with private data.
947 */
948 if (mpc->mpc_field_off != NULL) {
949 MAC_POLICY_LIST_UNLOCK();
950 return (EBUSY);
951 }
952#endif
953 /*
954 * Only allow the unload to proceed if the module is unloadable
955 * by its own definition.
956 */
957 if ((mpc->mpc_loadtime_flags & MPC_LOADTIME_FLAG_UNLOADOK) == 0) {
958 mac_policy_release_exclusive();
959 return (EBUSY);
960 }
961
962 mac_policy_removefrom_labellist(handle);
963
964 mac_get_mpc(handle) = NULL;
965 if (handle < mac_policy_list.freehint &&
966 handle >= mac_policy_list.staticmax)
967 mac_policy_list.freehint = handle;
968
969 if (handle == mac_policy_list.maxindex)
970 mac_policy_list.maxindex--;
971
972 mac_policy_list.numloaded--;
973 if (mpc->mpc_field_off != NULL) {
974 mac_slot_offsets_free |= (1 << *mpc->mpc_field_off);
975 }
976
977 if (mpc->mpc_ops->mpo_policy_destroy != NULL)
978 (*(mpc->mpc_ops->mpo_policy_destroy))(mpc);
979
980 mpc->mpc_runtime_flags &= ~MPC_RUNTIME_FLAG_REGISTERED;
981 mac_policy_updateflags();
982
983 mac_policy_release_exclusive();
984
985 if (mpc->mpc_data) {
986 struct mac_module_data *mmd = mpc->mpc_data;
987 kfree(mmd, mmd->size);
988 mpc->mpc_data = NULL;
989 }
990
991 printf("Security policy unload: %s (%s)\n", mpc->mpc_fullname,
992 mpc->mpc_name);
993
994 return (0);
995}
996
997/*
998 * Define an error value precedence, and given two arguments, selects the
999 * value with the higher precedence.
1000 */
1001int
1002mac_error_select(int error1, int error2)
1003{
1004
1005 /* Certain decision-making errors take top priority. */
1006 if (error1 == EDEADLK || error2 == EDEADLK)
1007 return (EDEADLK);
1008
1009 /* Invalid arguments should be reported where possible. */
1010 if (error1 == EINVAL || error2 == EINVAL)
1011 return (EINVAL);
1012
1013 /* Precedence goes to "visibility", with both process and file. */
1014 if (error1 == ESRCH || error2 == ESRCH)
1015 return (ESRCH);
1016
1017 if (error1 == ENOENT || error2 == ENOENT)
1018 return (ENOENT);
1019
1020 /* Precedence goes to DAC/MAC protections. */
1021 if (error1 == EACCES || error2 == EACCES)
1022 return (EACCES);
1023
1024 /* Precedence goes to privilege. */
1025 if (error1 == EPERM || error2 == EPERM)
1026 return (EPERM);
1027
1028 /* Precedence goes to error over success; otherwise, arbitrary. */
1029 if (error1 != 0)
1030 return (error1);
1031 return (error2);
1032}
1033
1034void
1035mac_label_init(struct label *label)
1036{
1037
1038 bzero(label, sizeof(*label));
1039 label->l_flags = MAC_FLAG_INITIALIZED;
1040}
1041
1042void
1043mac_label_destroy(struct label *label)
1044{
1045
1046 KASSERT(label->l_flags & MAC_FLAG_INITIALIZED,
1047 ("destroying uninitialized label"));
1048
1049 bzero(label, sizeof(*label));
1050 /* implicit: label->l_flags &= ~MAC_FLAG_INITIALIZED; */
1051}
1052
1053int
1054mac_port_check_service (struct label *subj, struct label *obj,
1055 const char *s, const char *p)
1056{
1057 int error;
1058
1059 MAC_CHECK(port_check_service, subj, obj, s, p);
1060 return (error);
1061}
1062
1063int
1064mac_port_label_compute(struct label *subj, struct label *obj,
1065 const char *s, struct label *out)
1066{
1067 int error;
1068
1069 MAC_CHECK(port_label_compute, subj, obj, s, out);
1070 return error;
1071}
1072
1073int
1074mac_check_structmac_consistent(struct user_mac *mac)
1075{
1076
1077 if (mac->m_buflen > MAC_MAX_LABEL_BUF_LEN || mac->m_buflen == 0)
1078 return (EINVAL);
1079
1080 return (0);
1081}
1082
1083/*
1084 * Get the external forms of labels from all policies, for a single
1085 * label namespace or "*" for all namespaces. Returns ENOENT if no policy
1086 * is registered for the namespace, unless the namespace begins with a '?'.
1087 */
1088static int
1089mac_label_externalize(size_t mpo_externalize_off, struct label *label,
1090 const char *element, struct sbuf *sb)
1091{
1092 struct mac_policy_conf *mpc;
1093 struct mac_label_listener *mll;
1094 struct mac_label_element *mle;
1095 struct mac_label_element_list_t *element_list;
1096 const char *name;
1097 int (*mpo_externalize)(struct label *, char *, struct sbuf *);
1098 int all_labels = 0, ignorenotfound = 0, error = 0, busy = FALSE;
1099 unsigned int count = 0;
1100
1101 if (element[0] == '?') {
1102 element++;
1103 ignorenotfound = 1;
1104 } else if (element[0] == '*' && element[1] == '\0')
1105 all_labels = 1;
1106
1107 element_list = &mac_static_label_element_list;
1108element_loop:
1109 LIST_FOREACH(mle, element_list, mle_list) {
1110 name = mle->mle_name;
1111 if (all_labels) {
1112 if (*name == '?')
1113 continue;
1114 } else {
1115 if (*name == '?')
1116 name++;
1117 if (strcmp(name, element) != 0)
1118 continue;
1119 }
1120 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1121 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
1122 if (mpc == NULL)
1123 continue;
1124 mpo_externalize = *(typeof(mpo_externalize) *)
1125 ((char *)mpc->mpc_ops + mpo_externalize_off);
1126 if (mpo_externalize == NULL)
1127 continue;
1128 error = sbuf_printf(sb, "%s/", name);
1129 if (error)
1130 goto done;
1131 error = mpo_externalize(label, mle->mle_name, sb);
1132 if (error) {
1133 if (error != ENOENT)
1134 goto done;
1135 /*
1136 * If a policy doesn't have a label to
1137 * externalize it returns ENOENT. This
1138 * may occur for policies that support
1139 * multiple label elements for some
1140 * (but not all) object types.
1141 */
1142 sbuf_setpos(sb, sbuf_len(sb) -
1143 (strlen(name) + 1));
1144 error = 0;
1145 continue;
1146 }
1147 error = sbuf_putc(sb, ',');
1148 if (error)
1149 goto done;
1150 count++;
1151 }
1152 }
1153 /* If there are dynamic policies present, check their elements too. */
1154 if (!busy && mac_policy_list_conditional_busy() == 1) {
1155 element_list = &mac_label_element_list;
1156 busy = TRUE;
1157 goto element_loop;
1158 }
1159done:
1160 if (busy)
1161 mac_policy_list_unbusy();
1162 if (!error && count == 0) {
1163 if (!all_labels && !ignorenotfound)
1164 error = ENOENT; /* XXX: ENOLABEL? */
1165 }
1166 return (error);
1167}
1168
1169/*
1170 * Get the external forms of labels from all policies, for all label
1171 * namespaces contained in a list.
b0d623f7
A
1172 *
1173 * XXX This may be leaking an sbuf.
2d21ac55
A
1174 */
1175int
1176mac_externalize(size_t mpo_externalize_off, struct label *label,
1177 const char *elementlist, char *outbuf, size_t outbuflen)
1178{
1179 char *element;
b0d623f7
A
1180 char *scratch_base;
1181 char *scratch;
2d21ac55
A
1182 struct sbuf sb;
1183 int error = 0, len;
1184
b0d623f7
A
1185 /* allocate a scratch buffer the size of the string */
1186 MALLOC(scratch_base, char *, strlen(elementlist)+1, M_MACTEMP, M_WAITOK);
1187 if (scratch_base == NULL) {
1188 error = ENOMEM;
1189 goto out;
1190 }
1191
1192 /* copy the elementlist to the scratch buffer */
1193 strlcpy(scratch_base, elementlist, strlen(elementlist)+1);
1194
1195 /*
1196 * set up a temporary pointer that can be used to iterate the
1197 * scratch buffer without losing the allocation address
1198 */
1199 scratch = scratch_base;
1200
1201 /* get an sbuf */
1202 if (sbuf_new(&sb, outbuf, outbuflen, SBUF_FIXEDLEN) == NULL) {
1203 /* could not allocate interior buffer */
1204 error = ENOMEM;
1205 goto out;
1206 }
1207 /* iterate the scratch buffer; NOTE: buffer contents modified! */
1208 while ((element = strsep(&scratch, ",")) != NULL) {
2d21ac55
A
1209 error = mac_label_externalize(mpo_externalize_off, label,
1210 element, &sb);
1211 if (error)
1212 break;
1213 }
1214 if ((len = sbuf_len(&sb)) > 0)
1215 sbuf_setpos(&sb, len - 1); /* trim trailing comma */
1216 sbuf_finish(&sb);
b0d623f7
A
1217
1218out:
1219 if (scratch_base != NULL)
1220 FREE(scratch_base, M_MACTEMP);
1221
2d21ac55
A
1222 return (error);
1223}
1224
1225/*
1226 * Have all policies set the internal form of a label, for a single
1227 * label namespace.
1228 */
1229static int
1230mac_label_internalize(size_t mpo_internalize_off, struct label *label,
1231 char *element_name, char *element_data)
1232{
1233 struct mac_policy_conf *mpc;
1234 struct mac_label_listener *mll;
1235 struct mac_label_element *mle;
1236 struct mac_label_element_list_t *element_list;
1237 int (*mpo_internalize)(struct label *, char *, char *);
1238 int error = 0, busy = FALSE;
1239 unsigned int count = 0;
1240 const char *name;
1241
1242 element_list = &mac_static_label_element_list;
1243element_loop:
1244 LIST_FOREACH(mle, element_list, mle_list) {
1245 if (*(name = mle->mle_name) == '?')
1246 name++;
1247 if (strcmp(element_name, name) != 0)
1248 continue;
1249 LIST_FOREACH(mll, &mle->mle_listeners, mll_list) {
1250 mpc = mac_policy_list.entries[mll->mll_handle].mpc;
1251 if (mpc == NULL)
1252 continue;
1253 mpo_internalize = *(typeof(mpo_internalize) *)
1254 ((char *)mpc->mpc_ops + mpo_internalize_off);
1255 if (mpo_internalize == NULL)
1256 continue;
1257 error = mpo_internalize(label, element_name,
1258 element_data);
1259 if (error)
1260 goto done;
1261 count++;
1262 }
1263 }
1264 /* If there are dynamic policies present, check their elements too. */
1265 if (!busy && mac_policy_list_conditional_busy() == 1) {
1266 element_list = &mac_label_element_list;
1267 busy = TRUE;
1268 goto element_loop;
1269 }
1270done:
1271 if (busy)
1272 mac_policy_list_unbusy();
1273 if (!error && count == 0)
1274 error = ENOPOLICY;
1275 return (error);
1276}
1277
1278int
1279mac_internalize(size_t mpo_internalize_off, struct label *label,
1280 char *textlabels)
1281{
1282 char *element_name, *element_data;
1283 int error = 0;
1284
1285 while (!error && (element_name = strsep(&textlabels, ",")) != NULL) {
1286 element_data = strchr(element_name, '/');
1287 if (element_data == NULL) {
1288 error = EINVAL;
1289 break;
1290 }
1291 *element_data++ = '\0';
1292 error = mac_label_internalize(mpo_internalize_off, label,
1293 element_name, element_data);
1294 }
1295 return (error);
1296}
1297
1298/* system calls */
1299
1300int
b0d623f7 1301__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, int *ret __unused)
2d21ac55
A
1302{
1303 char *elements, *buffer;
1304 struct user_mac mac;
1305 struct proc *tproc;
1306 struct ucred *tcred;
1307 int error;
1308 size_t ulen;
1309
1310 AUDIT_ARG(pid, uap->pid);
1311 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1312 struct user64_mac mac64;
1313 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1314 mac.m_buflen = mac64.m_buflen;
1315 mac.m_string = mac64.m_string;
2d21ac55 1316 } else {
6d2010ae 1317 struct user32_mac mac32;
2d21ac55
A
1318 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1319 mac.m_buflen = mac32.m_buflen;
6d2010ae 1320 mac.m_string = mac32.m_string;
2d21ac55
A
1321 }
1322 if (error)
1323 return (error);
1324
1325 error = mac_check_structmac_consistent(&mac);
1326 if (error)
1327 return (error);
1328
1329 tproc = proc_find(uap->pid);
1330 if (tproc == NULL)
1331 return (ESRCH);
1332 tcred = kauth_cred_proc_ref(tproc);
1333 proc_rele(tproc);
1334
1335 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1336 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1337 if (error) {
1338 FREE(elements, M_MACTEMP);
1339 kauth_cred_unref(&tcred);
1340 return (error);
1341 }
1342 AUDIT_ARG(mac_string, elements);
1343
1344 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1345 error = mac_cred_label_externalize(tcred->cr_label, elements,
1346 buffer, mac.m_buflen, M_WAITOK);
1347 if (error == 0)
1348 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1349
1350 FREE(buffer, M_MACTEMP);
1351 FREE(elements, M_MACTEMP);
1352 kauth_cred_unref(&tcred);
1353 return (error);
1354}
1355
1356int
b0d623f7 1357__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, int *ret __unused)
2d21ac55
A
1358{
1359 char *elements, *buffer;
1360 struct user_mac mac;
1361 kauth_cred_t cr;
1362 int error;
1363 size_t ulen;
1364
1365 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1366 struct user64_mac mac64;
1367 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1368 mac.m_buflen = mac64.m_buflen;
1369 mac.m_string = mac64.m_string;
2d21ac55 1370 } else {
6d2010ae 1371 struct user32_mac mac32;
2d21ac55
A
1372 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1373 mac.m_buflen = mac32.m_buflen;
6d2010ae 1374 mac.m_string = mac32.m_string;
2d21ac55
A
1375 }
1376 if (error)
1377 return (error);
1378
1379 error = mac_check_structmac_consistent(&mac);
1380 if (error)
1381 return (error);
1382
1383 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1384 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1385 if (error) {
1386 FREE(elements, M_MACTEMP);
1387 return (error);
1388 }
1389 AUDIT_ARG(mac_string, elements);
1390
1391 cr = kauth_cred_proc_ref(p);
1392
1393 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1394 error = mac_cred_label_externalize(cr->cr_label,
1395 elements, buffer, mac.m_buflen, M_WAITOK);
1396 if (error == 0)
1397 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1398
1399 FREE(buffer, M_MACTEMP);
1400 FREE(elements, M_MACTEMP);
1401 kauth_cred_unref(&cr);
1402 return (error);
1403}
1404
2d21ac55 1405int
b0d623f7 1406__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, int *ret __unused)
2d21ac55 1407{
b0d623f7 1408 kauth_cred_t newcred;
2d21ac55
A
1409 struct label *intlabel;
1410 struct user_mac mac;
1411 char *buffer;
1412 int error;
1413 size_t ulen;
1414
1415 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1416 struct user64_mac mac64;
1417 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1418 mac.m_buflen = mac64.m_buflen;
1419 mac.m_string = mac64.m_string;
2d21ac55 1420 } else {
6d2010ae 1421 struct user32_mac mac32;
2d21ac55
A
1422 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1423 mac.m_buflen = mac32.m_buflen;
6d2010ae 1424 mac.m_string = mac32.m_string;
2d21ac55
A
1425 }
1426 if (error)
1427 return (error);
1428
1429 error = mac_check_structmac_consistent(&mac);
1430 if (error)
1431 return (error);
1432
1433 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1434 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1435 if (error) {
1436 FREE(buffer, M_MACTEMP);
1437 return (error);
1438 }
1439 AUDIT_ARG(mac_string, buffer);
1440
1441 intlabel = mac_cred_label_alloc();
1442 error = mac_cred_label_internalize(intlabel, buffer);
1443 FREE(buffer, M_MACTEMP);
1444 if (error)
1445 goto out;
1446
1447 error = mac_cred_check_label_update(kauth_cred_get(), intlabel);
1448 if (error) {
1449 goto out;
1450 }
1451
1452 error = kauth_proc_label_update(p, intlabel);
1453 if (error)
1454 goto out;
1455
1456 newcred = kauth_cred_proc_ref(p);
1457 mac_task_label_update_cred(newcred, p->task);
1458
1459#if 0
1460 if (mac_vm_enforce) {
1461 mutex_lock(Giant); /* XXX FUNNEL? */
1462 mac_cred_mmapped_drop_perms(p, newcred);
1463 mutex_unlock(Giant); /* XXX FUNNEL? */
1464 }
1465#endif
1466
1467 kauth_cred_unref(&newcred);
1468out:
1469 mac_cred_label_free(intlabel);
1470 return (error);
1471}
1472
1473#if CONFIG_LCTX
b0d623f7
A
1474/*
1475 * __mac_get_lcid:
1476 * Get login context ID. A login context associates a BSD process
1477 * with an instance of a user. For more information see getlcid(2) man page.
1478 *
1479 * Parameters: p Process requesting the get
1480 * uap User argument descriptor (see below)
1481 * ret (ignored)
1482 *
1483 * Indirect: uap->lcid login context ID to search
1484 * uap->mac_p.m_buflen MAC info buffer size
1485 * uap->mac_p.m_string MAC info user address
1486 *
1487 * Returns: 0 Success
1488 * !0 Not success
1489 */
2d21ac55 1490int
b0d623f7 1491__mac_get_lcid(proc_t p, struct __mac_get_lcid_args *uap, int *ret __unused)
2d21ac55
A
1492{
1493 char *elements, *buffer;
1494 struct user_mac mac;
1495 struct lctx *l;
1496 int error;
1497 size_t ulen;
1498
b0d623f7 1499 AUDIT_ARG(value32, uap->lcid);
2d21ac55 1500 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1501 struct user64_mac mac64;
1502 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1503 mac.m_buflen = mac64.m_buflen;
1504 mac.m_string = mac64.m_string;
2d21ac55 1505 } else {
6d2010ae 1506 struct user32_mac mac32;
2d21ac55
A
1507 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1508 mac.m_buflen = mac32.m_buflen;
6d2010ae 1509 mac.m_string = mac32.m_string;
2d21ac55
A
1510 }
1511
1512 if (error)
1513 return (error);
1514
1515 error = mac_check_structmac_consistent(&mac);
1516 if (error)
1517 return (error);
1518
1519 l = lcfind(uap->lcid);
1520 if (l == NULL)
1521 return (ESRCH);
1522
1523 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1524 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1525 if (error) {
1526 LCTX_UNLOCK(l);
1527 FREE(elements, M_MACTEMP);
1528 return (error);
1529 }
1530 AUDIT_ARG(mac_string, elements);
1531 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1532 error = mac_lctx_label_externalize(l->lc_label, elements,
1533 buffer, mac.m_buflen);
1534 if (error == 0)
1535 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1536
1537 LCTX_UNLOCK(l);
1538 FREE(buffer, M_MACTEMP);
1539 FREE(elements, M_MACTEMP);
1540 return (error);
1541}
1542
b0d623f7
A
1543/*
1544 * __mac_get_lctx:
1545 * Get login context label. A login context associates a BSD process
1546 * associated with an instance of a user.
1547 *
1548 * Parameters: p Process requesting the get
1549 * uap User argument descriptor (see below)
1550 * ret (ignored)
1551 *
1552 * Indirect: uap->lcid login context ID to search
1553 * uap->mac_p MAC info
1554 *
1555 * Returns: 0 Success
1556 * !0 Not success
1557 *
1558 */
2d21ac55 1559int
b0d623f7 1560__mac_get_lctx(proc_t p, struct __mac_get_lctx_args *uap, int *ret __unused)
2d21ac55
A
1561{
1562 char *elements, *buffer;
1563 struct user_mac mac;
1564 int error;
1565 size_t ulen;
1566
1567 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1568 struct user64_mac mac64;
1569 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1570 mac.m_buflen = mac64.m_buflen;
1571 mac.m_string = mac64.m_string;
2d21ac55 1572 } else {
6d2010ae 1573 struct user32_mac mac32;
2d21ac55
A
1574 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1575 mac.m_buflen = mac32.m_buflen;
6d2010ae 1576 mac.m_string = mac32.m_string;
2d21ac55
A
1577 }
1578
1579 if (error)
1580 return (error);
1581
1582 error = mac_check_structmac_consistent(&mac);
1583 if (error)
1584 return (error);
1585
1586 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1587 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1588 if (error) {
1589 FREE(elements, M_MACTEMP);
1590 return (error);
1591 }
1592 AUDIT_ARG(mac_string, elements);
1593 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1594
1595 proc_lock(p);
1596 if (p->p_lctx == NULL) {
1597 proc_unlock(p);
1598 error = ENOENT;
1599 goto out;
1600 }
1601
1602 error = mac_lctx_label_externalize(p->p_lctx->lc_label,
1603 elements, buffer, mac.m_buflen);
1604 proc_unlock(p);
1605 if (error == 0)
1606 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1607
1608out:
1609 FREE(buffer, M_MACTEMP);
1610 FREE(elements, M_MACTEMP);
1611 return (error);
1612}
1613
1614int
b0d623f7 1615__mac_set_lctx(proc_t p, struct __mac_set_lctx_args *uap, int *ret __unused)
2d21ac55
A
1616{
1617 struct user_mac mac;
1618 struct label *intlabel;
1619 char *buffer;
1620 int error;
1621 size_t ulen;
1622
1623 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1624 struct user64_mac mac64;
1625 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1626 mac.m_buflen = mac64.m_buflen;
1627 mac.m_string = mac64.m_string;
2d21ac55 1628 } else {
6d2010ae 1629 struct user32_mac mac32;
2d21ac55
A
1630 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1631 mac.m_buflen = mac32.m_buflen;
6d2010ae 1632 mac.m_string = mac32.m_string;
2d21ac55
A
1633 }
1634 if (error)
1635 return (error);
1636
1637 error = mac_check_structmac_consistent(&mac);
1638 if (error)
1639 return (error);
1640
1641 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1642 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1643 if (error) {
1644 FREE(buffer, M_MACTEMP);
1645 return (error);
1646 }
1647 AUDIT_ARG(mac_string, buffer);
1648
1649 intlabel = mac_lctx_label_alloc();
1650 error = mac_lctx_label_internalize(intlabel, buffer);
1651 FREE(buffer, M_MACTEMP);
1652 if (error)
1653 goto out;
1654
1655 proc_lock(p);
1656 if (p->p_lctx == NULL) {
1657 proc_unlock(p);
1658 error = ENOENT;
1659 goto out;
1660 }
1661
1662 error = mac_lctx_check_label_update(p->p_lctx, intlabel);
1663 if (error) {
1664 proc_unlock(p);
1665 goto out;
1666 }
1667 mac_lctx_label_update(p->p_lctx, intlabel);
1668 proc_unlock(p);
1669out:
1670 mac_lctx_label_free(intlabel);
1671 return (error);
1672}
1673
1674#else /* LCTX */
1675
1676int
b0d623f7 1677__mac_get_lcid(proc_t p __unused, struct __mac_get_lcid_args *uap __unused, int *ret __unused)
2d21ac55
A
1678{
1679
1680 return (ENOSYS);
1681}
1682
1683int
b0d623f7 1684__mac_get_lctx(proc_t p __unused, struct __mac_get_lctx_args *uap __unused, int *ret __unused)
2d21ac55
A
1685{
1686
1687 return (ENOSYS);
1688}
1689
1690int
b0d623f7 1691__mac_set_lctx(proc_t p __unused, struct __mac_set_lctx_args *uap __unused, int *ret __unused)
2d21ac55
A
1692{
1693
1694 return (ENOSYS);
1695}
1696#endif /* !LCTX */
1697
1698int
b0d623f7 1699__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, int *ret __unused)
2d21ac55
A
1700{
1701 struct fileproc *fp;
1702 struct vnode *vp;
1703 struct user_mac mac;
1704 char *elements, *buffer;
1705 int error;
1706 size_t ulen;
1707 kauth_cred_t my_cred;
1708#if CONFIG_MACF_SOCKET
1709 struct socket *so;
1710#endif /* MAC_SOCKET */
1711 struct label *intlabel;
1712
1713 AUDIT_ARG(fd, uap->fd);
1714
1715 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1716 struct user64_mac mac64;
1717 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1718 mac.m_buflen = mac64.m_buflen;
1719 mac.m_string = mac64.m_string;
2d21ac55 1720 } else {
6d2010ae 1721 struct user32_mac mac32;
2d21ac55
A
1722 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1723 mac.m_buflen = mac32.m_buflen;
6d2010ae 1724 mac.m_string = mac32.m_string;
2d21ac55
A
1725 }
1726
1727 if (error)
1728 return (error);
1729
1730 error = mac_check_structmac_consistent(&mac);
1731 if (error)
1732 return (error);
1733
1734 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1735 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1736 if (error) {
1737 FREE(elements, M_MACTEMP);
1738 return (error);
1739 }
1740 AUDIT_ARG(mac_string, elements);
1741
1742 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1743 error = fp_lookup(p, uap->fd, &fp, 0);
1744 if (error) {
1745 FREE(buffer, M_MACTEMP);
1746 FREE(elements, M_MACTEMP);
1747 return (error);
1748 }
1749
1750 my_cred = kauth_cred_proc_ref(p);
1751 error = mac_file_check_get(my_cred, fp->f_fglob, elements, mac.m_buflen);
1752 kauth_cred_unref(&my_cred);
1753 if (error) {
1754 fp_drop(p, uap->fd, fp, 0);
1755 FREE(buffer, M_MACTEMP);
1756 FREE(elements, M_MACTEMP);
1757 return (error);
1758 }
1759
39236c6e 1760 switch (FILEGLOB_DTYPE(fp->f_fglob)) {
2d21ac55 1761 case DTYPE_VNODE:
2d21ac55 1762 intlabel = mac_vnode_label_alloc();
b0d623f7
A
1763 if (intlabel == NULL) {
1764 error = ENOMEM;
1765 break;
1766 }
2d21ac55 1767 vp = (struct vnode *)fp->f_fglob->fg_data;
2d21ac55
A
1768 error = vnode_getwithref(vp);
1769 if (error == 0) {
1770 mac_vnode_label_copy(vp->v_label, intlabel);
1771 error = mac_vnode_label_externalize(intlabel,
1772 elements, buffer,
1773 mac.m_buflen, M_WAITOK);
1774 vnode_put(vp);
1775 }
1776 mac_vnode_label_free(intlabel);
1777 break;
1778 case DTYPE_SOCKET:
1779#if CONFIG_MACF_SOCKET
1780 so = (struct socket *) fp->f_fglob->fg_data;
1781 intlabel = mac_socket_label_alloc(MAC_WAITOK);
1782 sock_lock(so, 1);
1783 mac_socket_label_copy(so->so_label, intlabel);
1784 sock_unlock(so, 1);
1785 error = mac_socket_label_externalize(intlabel, elements, buffer, mac.m_buflen);
1786 mac_socket_label_free(intlabel);
1787 break;
1788#endif
1789 case DTYPE_PSXSHM:
1790 case DTYPE_PSXSEM:
1791 case DTYPE_PIPE:
1792 case DTYPE_KQUEUE:
1793 case DTYPE_FSEVENTS:
1794 default:
1795 error = ENOSYS; // only sockets/vnodes so far
1796 break;
1797 }
1798 fp_drop(p, uap->fd, fp, 0);
1799
1800 if (error == 0)
1801 error = copyout(buffer, mac.m_string, strlen(buffer)+1);
1802
1803 FREE(buffer, M_MACTEMP);
1804 FREE(elements, M_MACTEMP);
1805 return (error);
1806}
1807
2d21ac55
A
1808static int
1809mac_get_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p, int follow)
1810{
1811 struct vnode *vp;
1812 vfs_context_t ctx;
1813 char *elements, *buffer;
1814 struct nameidata nd;
1815 struct label *intlabel;
1816 struct user_mac mac;
1817 int error;
1818 size_t ulen;
1819
1820 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1821 struct user64_mac mac64;
1822 error = copyin(mac_p, &mac64, sizeof(mac64));
1823 mac.m_buflen = mac64.m_buflen;
1824 mac.m_string = mac64.m_string;
2d21ac55 1825 } else {
6d2010ae 1826 struct user32_mac mac32;
2d21ac55
A
1827 error = copyin(mac_p, &mac32, sizeof(mac32));
1828 mac.m_buflen = mac32.m_buflen;
6d2010ae 1829 mac.m_string = mac32.m_string;
2d21ac55
A
1830 }
1831
1832 if (error)
1833 return (error);
1834
1835 error = mac_check_structmac_consistent(&mac);
1836 if (error)
1837 return (error);
1838
1839 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
b0d623f7
A
1840 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
1841
2d21ac55
A
1842 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
1843 if (error) {
b0d623f7 1844 FREE(buffer, M_MACTEMP);
2d21ac55
A
1845 FREE(elements, M_MACTEMP);
1846 return (error);
1847 }
1848 AUDIT_ARG(mac_string, elements);
1849
1850 ctx = vfs_context_current();
1851
6d2010ae 1852 NDINIT(&nd, LOOKUP, OP_LOOKUP,
2d21ac55
A
1853 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
1854 UIO_USERSPACE, path_p, ctx);
1855 error = namei(&nd);
1856 if (error) {
b0d623f7 1857 FREE(buffer, M_MACTEMP);
2d21ac55
A
1858 FREE(elements, M_MACTEMP);
1859 return (error);
1860 }
1861 vp = nd.ni_vp;
1862
1863 nameidone(&nd);
1864
1865 intlabel = mac_vnode_label_alloc();
1866 mac_vnode_label_copy(vp->v_label, intlabel);
2d21ac55 1867 error = mac_vnode_label_externalize(intlabel, elements, buffer,
b0d623f7
A
1868 mac.m_buflen, M_WAITOK);
1869 mac_vnode_label_free(intlabel);
2d21ac55
A
1870 if (error == 0)
1871 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
2d21ac55
A
1872
1873 vnode_put(vp);
b0d623f7
A
1874
1875 FREE(buffer, M_MACTEMP);
1876 FREE(elements, M_MACTEMP);
2d21ac55
A
1877
1878 return (error);
1879}
1880
1881int
1882__mac_get_file(proc_t p, struct __mac_get_file_args *uap,
b0d623f7 1883 int *ret __unused)
2d21ac55
A
1884{
1885
1886 return (mac_get_filelink(p, uap->mac_p, uap->path_p, 1));
1887}
1888
1889int
1890__mac_get_link(proc_t p, struct __mac_get_link_args *uap,
b0d623f7 1891 int *ret __unused)
2d21ac55
A
1892{
1893
1894 return (mac_get_filelink(p, uap->mac_p, uap->path_p, 0));
1895}
1896
1897int
b0d623f7 1898__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, int *ret __unused)
2d21ac55
A
1899{
1900
1901 struct fileproc *fp;
1902 struct user_mac mac;
1903 struct vfs_context *ctx = vfs_context_current();
1904 int error;
1905 size_t ulen;
1906 char *buffer;
1907 struct label *intlabel;
1908#if CONFIG_MACF_SOCKET
1909 struct socket *so;
1910#endif
1911 struct vnode *vp;
1912
1913 AUDIT_ARG(fd, uap->fd);
1914
1915 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
1916 struct user64_mac mac64;
1917 error = copyin(uap->mac_p, &mac64, sizeof(mac64));
1918 mac.m_buflen = mac64.m_buflen;
1919 mac.m_string = mac64.m_string;
2d21ac55 1920 } else {
6d2010ae 1921 struct user32_mac mac32;
2d21ac55
A
1922 error = copyin(uap->mac_p, &mac32, sizeof(mac32));
1923 mac.m_buflen = mac32.m_buflen;
6d2010ae 1924 mac.m_string = mac32.m_string;
2d21ac55
A
1925 }
1926 if (error)
1927 return (error);
1928
1929 error = mac_check_structmac_consistent(&mac);
1930 if (error)
1931 return (error);
1932
1933 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
1934 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
1935 if (error) {
1936 FREE(buffer, M_MACTEMP);
1937 return (error);
1938 }
1939 AUDIT_ARG(mac_string, buffer);
1940
1941 error = fp_lookup(p, uap->fd, &fp, 0);
1942 if (error) {
1943 FREE(buffer, M_MACTEMP);
1944 return (error);
1945 }
1946
1947
1948 error = mac_file_check_set(vfs_context_ucred(ctx), fp->f_fglob, buffer, mac.m_buflen);
1949 if (error) {
1950 fp_drop(p, uap->fd, fp, 0);
1951 FREE(buffer, M_MACTEMP);
1952 return (error);
1953 }
1954
39236c6e 1955 switch (FILEGLOB_DTYPE(fp->f_fglob)) {
2d21ac55
A
1956
1957 case DTYPE_VNODE:
b0d623f7
A
1958 if (mac_label_vnodes == 0) {
1959 error = ENOSYS;
1960 break;
1961 }
1962
2d21ac55
A
1963 intlabel = mac_vnode_label_alloc();
1964
1965 error = mac_vnode_label_internalize(intlabel, buffer);
1966 if (error) {
1967 mac_vnode_label_free(intlabel);
1968 break;
1969 }
1970
1971
1972 vp = (struct vnode *)fp->f_fglob->fg_data;
1973
1974 error = vnode_getwithref(vp);
1975 if (error == 0) {
1976 error = vn_setlabel(vp, intlabel, ctx);
1977 vnode_put(vp);
1978 }
1979 mac_vnode_label_free(intlabel);
1980 break;
1981
1982 case DTYPE_SOCKET:
1983#if CONFIG_MACF_SOCKET
1984 intlabel = mac_socket_label_alloc(MAC_WAITOK);
1985 error = mac_socket_label_internalize(intlabel, buffer);
1986 if (error == 0) {
1987 so = (struct socket *) fp->f_fglob->fg_data;
1988 SOCK_LOCK(so);
1989 error = mac_socket_label_update(vfs_context_ucred(ctx), so, intlabel);
1990 SOCK_UNLOCK(so);
1991 }
1992 mac_socket_label_free(intlabel);
1993 break;
1994#endif
1995 case DTYPE_PSXSHM:
1996 case DTYPE_PSXSEM:
1997 case DTYPE_PIPE:
1998 case DTYPE_KQUEUE:
1999 case DTYPE_FSEVENTS:
2000 default:
2001 error = ENOSYS; // only sockets/vnodes so far
2002 break;
2003 }
2004
2005 fp_drop(p, uap->fd, fp, 0);
2006 FREE(buffer, M_MACTEMP);
2007 return (error);
2008}
2009
2d21ac55
A
2010static int
2011mac_set_filelink(proc_t p, user_addr_t mac_p, user_addr_t path_p,
2012 int follow)
2013{
2014 register struct vnode *vp;
2015 struct vfs_context *ctx = vfs_context_current();
2016 struct label *intlabel;
2017 struct nameidata nd;
2018 struct user_mac mac;
2019 char *buffer;
2020 int error;
2021 size_t ulen;
2022
b0d623f7
A
2023 if (mac_label_vnodes == 0)
2024 return ENOSYS;
2025
2d21ac55 2026 if (IS_64BIT_PROCESS(p)) {
6d2010ae
A
2027 struct user64_mac mac64;
2028 error = copyin(mac_p, &mac64, sizeof(mac64));
2029 mac.m_buflen = mac64.m_buflen;
2030 mac.m_string = mac64.m_string;
2d21ac55 2031 } else {
6d2010ae 2032 struct user32_mac mac32;
2d21ac55
A
2033 error = copyin(mac_p, &mac32, sizeof(mac32));
2034 mac.m_buflen = mac32.m_buflen;
6d2010ae 2035 mac.m_string = mac32.m_string;
2d21ac55
A
2036 }
2037 if (error)
2038 return (error);
2039
2040 error = mac_check_structmac_consistent(&mac);
2041 if (error) {
2042 printf("mac_set_file: failed structure consistency check\n");
2043 return (error);
2044 }
2045
2046 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
2047 error = copyinstr(mac.m_string, buffer, mac.m_buflen, &ulen);
2048 if (error) {
2049 FREE(buffer, M_MACTEMP);
2050 return (error);
2051 }
2052 AUDIT_ARG(mac_string, buffer);
2053
2054 intlabel = mac_vnode_label_alloc();
2055 error = mac_vnode_label_internalize(intlabel, buffer);
2056 FREE(buffer, M_MACTEMP);
2057 if (error) {
2058 mac_vnode_label_free(intlabel);
2059 return (error);
2060 }
2061
6d2010ae 2062 NDINIT(&nd, LOOKUP, OP_LOOKUP,
2d21ac55
A
2063 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1,
2064 UIO_USERSPACE, path_p, ctx);
2065 error = namei(&nd);
2066 if (error) {
2067 mac_vnode_label_free(intlabel);
2068 return (error);
2069 }
2070 vp = nd.ni_vp;
2071
2072 nameidone(&nd);
2073
2074 error = vn_setlabel(vp, intlabel, ctx);
2075 vnode_put(vp);
2076 mac_vnode_label_free(intlabel);
2077
2078 return (error);
2079}
2080
2081int
2082__mac_set_file(proc_t p, struct __mac_set_file_args *uap,
b0d623f7 2083 int *ret __unused)
2d21ac55
A
2084{
2085
2086 return (mac_set_filelink(p, uap->mac_p, uap->path_p, 1));
2087}
2088
2089int
2090__mac_set_link(proc_t p, struct __mac_set_link_args *uap,
b0d623f7 2091 int *ret __unused)
2d21ac55
A
2092{
2093
2094 return (mac_set_filelink(p, uap->mac_p, uap->path_p, 0));
2095}
2096
2097/*
b0d623f7
A
2098 * __mac_syscall: Perform a MAC policy system call
2099 *
2100 * Parameters: p Process calling this routine
2101 * uap User argument descriptor (see below)
2102 * retv (Unused)
2103 *
2104 * Indirect: uap->policy Name of target MAC policy
2105 * uap->call MAC policy-specific system call to perform
2106 * uap->arg MAC policy-specific system call arguments
2107 *
2108 * Returns: 0 Success
2109 * !0 Not success
2110 *
2d21ac55 2111 */
2d21ac55 2112int
b0d623f7 2113__mac_syscall(proc_t p, struct __mac_syscall_args *uap, int *retv __unused)
2d21ac55
A
2114{
2115 struct mac_policy_conf *mpc;
2116 char target[MAC_MAX_POLICY_NAME];
2117 int error;
2118 u_int i;
2119 size_t ulen;
2120
2121 error = copyinstr(uap->policy, target, sizeof(target), &ulen);
2122 if (error)
2123 return (error);
b0d623f7 2124 AUDIT_ARG(value32, uap->call);
2d21ac55
A
2125 AUDIT_ARG(mac_string, target);
2126
2127 error = ENOPOLICY;
2128
2129 for (i = 0; i < mac_policy_list.staticmax; i++) {
2130 mpc = mac_policy_list.entries[i].mpc;
2131 if (mpc == NULL)
2132 continue;
2133
2134 if (strcmp(mpc->mpc_name, target) == 0 &&
2135 mpc->mpc_ops->mpo_policy_syscall != NULL) {
2136 error = mpc->mpc_ops->mpo_policy_syscall(p,
2137 uap->call, uap->arg);
2138 goto done;
2139 }
2140 }
2141 if (mac_policy_list_conditional_busy() != 0) {
2142 for (; i <= mac_policy_list.maxindex; i++) {
2143 mpc = mac_policy_list.entries[i].mpc;
2144 if (mpc == NULL)
2145 continue;
2146
2147 if (strcmp(mpc->mpc_name, target) == 0 &&
2148 mpc->mpc_ops->mpo_policy_syscall != NULL) {
2149 error = mpc->mpc_ops->mpo_policy_syscall(p,
2150 uap->call, uap->arg);
2151 break;
2152 }
2153 }
2154 mac_policy_list_unbusy();
2155 }
2156
2157done:
2158 return (error);
2159}
2160
2161int
2162mac_mount_label_get(struct mount *mp, user_addr_t mac_p)
2163{
2164 char *elements, *buffer;
2165 struct label *label;
2166 struct user_mac mac;
2167 int error;
2168 size_t ulen;
2169
2170 if (IS_64BIT_PROCESS(current_proc())) {
6d2010ae
A
2171 struct user64_mac mac64;
2172 error = copyin(mac_p, &mac64, sizeof(mac64));
2173 mac.m_buflen = mac64.m_buflen;
2174 mac.m_string = mac64.m_string;
2d21ac55 2175 } else {
6d2010ae 2176 struct user32_mac mac32;
2d21ac55
A
2177 error = copyin(mac_p, &mac32, sizeof(mac32));
2178 mac.m_buflen = mac32.m_buflen;
6d2010ae 2179 mac.m_string = mac32.m_string;
2d21ac55
A
2180 }
2181 if (error)
2182 return (error);
2183
2184 error = mac_check_structmac_consistent(&mac);
2185 if (error)
2186 return (error);
2187
2188 MALLOC(elements, char *, mac.m_buflen, M_MACTEMP, M_WAITOK);
2189 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen);
2190 if (error) {
2191 FREE(elements, M_MACTEMP);
2192 return (error);
2193 }
2194 AUDIT_ARG(mac_string, elements);
2195
2196 label = mp->mnt_mntlabel;
2197 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO);
2198 error = mac_mount_label_externalize(label, elements, buffer,
2199 mac.m_buflen);
2200 FREE(elements, M_MACTEMP);
2201
2202 if (error == 0)
2203 error = copyout(buffer, mac.m_string, strlen(buffer) + 1);
2204 FREE(buffer, M_MACTEMP);
2205
2206 return (error);
2207}
2208
b0d623f7
A
2209/*
2210 * __mac_get_mount: Get mount point label information for a given pathname
2211 *
2212 * Parameters: p (ignored)
2213 * uap User argument descriptor (see below)
2214 * ret (ignored)
2215 *
2216 * Indirect: uap->path Pathname
2217 * uap->mac_p MAC info
2218 *
2219 * Returns: 0 Success
2220 * !0 Not success
2221 */
2d21ac55
A
2222int
2223__mac_get_mount(proc_t p __unused, struct __mac_get_mount_args *uap,
b0d623f7 2224 int *ret __unused)
2d21ac55
A
2225{
2226 struct nameidata nd;
2227 struct vfs_context *ctx = vfs_context_current();
2228 struct mount *mp;
2229 int error;
2230
6d2010ae 2231 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | AUDITVNPATH1,
2d21ac55
A
2232 UIO_USERSPACE, uap->path, ctx);
2233 error = namei(&nd);
2234 if (error) {
2235 return (error);
2236 }
2237 mp = nd.ni_vp->v_mount;
2238 nameidone(&nd);
2239
2240 return mac_mount_label_get(mp, uap->mac_p);
2241}
2242
316670eb
A
2243/*
2244 * mac_schedule_userret()
2245 *
2246 * Schedule a callback to the mpo_thread_userret hook. The mpo_thread_userret
2247 * hook is called just before the thread exit from the kernel in ast_taken().
2248 *
2249 * Returns: 0 Success
2250 * !0 Not successful
2251 */
2252int
2253mac_schedule_userret(void)
2254{
2255
2256 act_set_astmacf(current_thread());
2257 return (0);
2258}
2259
2260/*
2261 * mac_do_machexc()
2262 *
2263 * Do a Mach exception. This should only be done in the mpo_thread_userret
2264 * callback.
2265 *
2266 * params: code exception code
2267 * subcode exception subcode
2268 * flags flags:
2269 * MAC_DOEXCF_TRACED Only do exception if being
2270 * ptrace()'ed.
2271 *
2272 *
2273 * Returns: 0 Success
2274 * !0 Not successful
2275 */
2276int
2277mac_do_machexc(int64_t code, int64_t subcode, uint32_t flags)
2278{
2279 mach_exception_data_type_t codes[EXCEPTION_CODE_MAX];
2280 proc_t p = current_proc();
2281
2282 /* Only allow execption codes in MACF's reserved range. */
2283 if ((code < EXC_MACF_MIN) || (code > EXC_MACF_MAX))
2284 return (1);
2285
2286 if (flags & MAC_DOEXCF_TRACED &&
2287 !(p->p_lflag & P_LTRACED && (p->p_lflag & P_LPPWAIT) == 0))
2288 return (0);
2289
2290
2291 /* Send the Mach exception */
2292 codes[0] = (mach_exception_data_type_t)code;
2293 codes[1] = (mach_exception_data_type_t)subcode;
2294
2295 return (bsd_exception(EXC_SOFTWARE, codes, 2) != KERN_SUCCESS);
2296}
2297
2d21ac55
A
2298#else /* MAC */
2299
39236c6e
A
2300void (*load_security_extensions_function)(void) = 0;
2301
2302struct sysctl_oid_list sysctl__security_mac_children;
2303
2d21ac55
A
2304int
2305mac_policy_register(struct mac_policy_conf *mpc __unused,
2306 mac_policy_handle_t *handlep __unused, void *xd __unused)
2307{
2308
2309 return (0);
2310}
2311
2312int
2313mac_policy_unregister(mac_policy_handle_t handle __unused)
2314{
2315
2316 return (0);
2317}
2318
2319int
2320mac_audit_text(char *text __unused, mac_policy_handle_t handle __unused)
2321{
2322
2323 return (0);
2324}
2325
2d21ac55
A
2326int
2327mac_vnop_setxattr(struct vnode *vp __unused, const char *name __unused, char *buf __unused, size_t len __unused)
2328{
2329
2330 return (ENOENT);
2331}
2332
2333int
2334mac_vnop_getxattr(struct vnode *vp __unused, const char *name __unused,
2335 char *buf __unused, size_t len __unused, size_t *attrlen __unused)
2336{
2337
2338 return (ENOENT);
2339}
2340
2341int
2342mac_vnop_removexattr(struct vnode *vp __unused, const char *name __unused)
2343{
2344
2345 return (ENOENT);
2346}
2347
39236c6e 2348intptr_t mac_label_get(struct label *l __unused, int slot __unused)
2d21ac55 2349{
39236c6e 2350 return 0;
2d21ac55
A
2351}
2352
39236c6e 2353void mac_label_set(struct label *l __unused, int slot __unused, intptr_t v __unused)
2d21ac55 2354{
39236c6e 2355 return;
2d21ac55
A
2356}
2357
39236c6e 2358struct label *mac_thread_get_threadlabel(struct thread *thread __unused)
2d21ac55 2359{
39236c6e 2360 return NULL;
2d21ac55
A
2361}
2362
39236c6e 2363struct label *mac_thread_get_uthreadlabel(struct uthread *uthread __unused)
2d21ac55 2364{
39236c6e 2365 return NULL;
2d21ac55
A
2366}
2367
39236c6e
A
2368void mac_proc_set_enforce(proc_t p, int enforce_flags);
2369void mac_proc_set_enforce(proc_t p __unused, int enforce_flags __unused)
2d21ac55 2370{
39236c6e 2371 return;
2d21ac55 2372}
316670eb 2373
39236c6e
A
2374int mac_iokit_check_hid_control(kauth_cred_t cred __unused);
2375int mac_iokit_check_hid_control(kauth_cred_t cred __unused)
316670eb 2376{
39236c6e 2377 return 0;
316670eb
A
2378}
2379
2d21ac55 2380#endif /* !MAC */