1/* 2 * Copyright (c) 2007-2012 Apple Inc. All rights reserved. 3 * 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ 5 * 6 * This file contains Original Code and/or Modifications of Original Code 7 * as defined in and that are subject to the Apple Public Source License 8 * Version 2.0 (the 'License'). You may not use this file except in 9 * compliance with the License. The rights granted to you under the License 10 * may not be used to create, or enable the creation or redistribution of, 11 * unlawful or unlicensed copies of an Apple operating system, or to 12 * circumvent, violate, or enable the circumvention or violation of, any 13 * terms of an Apple operating system software license agreement. 14 * 15 * Please obtain a copy of the License at 16 * http://www.opensource.apple.com/apsl/ and read it before using this file. 17 * 18 * The Original Code and all software distributed under the License are 19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER 20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, 21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, 22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT. 23 * Please see the License for the specific language governing rights and 24 * limitations under the License. 25 * 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@ 27 */ 28/*- 29 * Copyright (c) 1999, 2000, 2001, 2002 Robert N. M. Watson 30 * Copyright (c) 2001 Ilmar S. Habibulin 31 * Copyright (c) 2001, 2002, 2003, 2004 Networks Associates Technology, Inc. 32 * Copyright (c) 2005-2006 SPARTA, Inc. 33 * 34 * This software was developed by Robert Watson and Ilmar Habibulin for the 35 * TrustedBSD Project. 36 * 37 * This software was developed for the FreeBSD Project in part by Network 38 * Associates Laboratories, the Security Research Division of Network 39 * Associates, Inc. under DARPA/SPAWAR contract N66001-01-C-8035 ("CBOSS"), 40 * as part of the DARPA CHATS research program. 41 * 42 * Redistribution and use in source and binary forms, with or without 43 * modification, are permitted provided that the following conditions 44 * are met: 45 * 1. Redistributions of source code must retain the above copyright 46 * notice, this list of conditions and the following disclaimer. 47 * 2. Redistributions in binary form must reproduce the above copyright 48 * notice, this list of conditions and the following disclaimer in the 49 * documentation and/or other materials provided with the distribution. 50 * 51 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND 52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 54 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE 55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 61 * SUCH DAMAGE. 62 * 63 */ 64 65/*- 66 * Framework for extensible kernel access control. This file contains 67 * Kernel and userland interface to the framework, policy registration 68 * and composition. Per-object interfaces, controls, and labeling may be 69 * found in src/sys/mac/. Sample policies may be found in src/sys/mac*. 70 */ 71 72#include <stdarg.h> 73#include <string.h> 74#include <security/mac_internal.h> 75#include <security/mac_mach_internal.h> 76#include <sys/param.h> 77#include <sys/vnode.h> 78#include <sys/vnode_internal.h> 79#include <sys/vfs_context.h> 80#include <sys/namei.h> 81#include <bsd/bsm/audit.h> 82#include <bsd/security/audit/audit.h> 83#include <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 91#include <mach/exception_types.h> 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> 99 100#if CONFIG_MACF 101#include <security/mac.h> 102#include <security/mac_policy.h> 103#include <security/mac_framework.h> 104#include <security/mac_internal.h> 105#include <security/mac_mach_internal.h> 106#endif 107 108 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 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 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; 148SYSCTL_UINT(_security_mac, OID_AUTO, max_slots, CTLFLAG_RD | CTLFLAG_LOCKED, 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 */ 169#if CONFIG_MACF_NET 170unsigned int mac_label_mbufs = 1; 171SYSCTL_UINT(_security_mac, OID_AUTO, label_mbufs, SECURITY_MAC_CTLFLAGS, 172 &mac_label_mbufs, 0, "Label all MBUFs"); 173#endif 174 175 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; 188SYSCTL_UINT(_security_mac, OID_AUTO, labelvnodes, SECURITY_MAC_CTLFLAGS, 189 &mac_label_vnodes, 0, "Label all vnodes"); 190 191 192unsigned int mac_mmap_revocation = 0; 193SYSCTL_UINT(_security_mac, OID_AUTO, mmap_revocation, SECURITY_MAC_CTLFLAGS, 194 &mac_mmap_revocation, 0, "Revoke mmap access to files on subject " 195 "relabel"); 196 197unsigned int mac_mmap_revocation_via_cow = 0; 198SYSCTL_UINT(_security_mac, OID_AUTO, mmap_revocation_via_cow, SECURITY_MAC_CTLFLAGS, 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; 203SYSCTL_UINT(_security_mac, OID_AUTO, device_enforce, SECURITY_MAC_CTLFLAGS, 204 &mac_device_enforce, 0, "Enforce MAC policy on device operations"); 205 206unsigned int mac_pipe_enforce = 1; 207SYSCTL_UINT(_security_mac, OID_AUTO, pipe_enforce, SECURITY_MAC_CTLFLAGS, 208 &mac_pipe_enforce, 0, "Enforce MAC policy on pipe operations"); 209 210unsigned int mac_posixsem_enforce = 1; 211SYSCTL_UINT(_security_mac, OID_AUTO, posixsem_enforce, SECURITY_MAC_CTLFLAGS, 212 &mac_posixsem_enforce, 0, "Enforce MAC policy on POSIX semaphores"); 213 214unsigned int mac_posixshm_enforce = 1; 215SYSCTL_UINT(_security_mac, OID_AUTO, posixshm_enforce, SECURITY_MAC_CTLFLAGS, 216 &mac_posixshm_enforce, 0, "Enforce MAC policy on Posix Shared Memory"); 217 218unsigned int mac_proc_enforce = 1; 219SYSCTL_UINT(_security_mac, OID_AUTO, proc_enforce, SECURITY_MAC_CTLFLAGS, 220 &mac_proc_enforce, 0, "Enforce MAC policy on process operations"); 221 222unsigned int mac_socket_enforce = 1; 223SYSCTL_UINT(_security_mac, OID_AUTO, socket_enforce, SECURITY_MAC_CTLFLAGS, 224 &mac_socket_enforce, 0, "Enforce MAC policy on socket operations"); 225 226unsigned int mac_system_enforce = 1; 227SYSCTL_UINT(_security_mac, OID_AUTO, system_enforce, SECURITY_MAC_CTLFLAGS, 228 &mac_system_enforce, 0, "Enforce MAC policy on system-wide interfaces"); 229 230unsigned int mac_sysvmsg_enforce = 1; 231SYSCTL_UINT(_security_mac, OID_AUTO, sysvmsg_enforce, SECURITY_MAC_CTLFLAGS, 232 &mac_sysvmsg_enforce, 0, "Enforce MAC policy on System V IPC message queues"); 233 234unsigned int mac_sysvsem_enforce = 1; 235SYSCTL_UINT(_security_mac, OID_AUTO, sysvsem_enforce, SECURITY_MAC_CTLFLAGS, 236 &mac_sysvsem_enforce, 0, "Enforce MAC policy on System V IPC semaphores"); 237 238unsigned int mac_sysvshm_enforce = 1; 239SYSCTL_INT(_security_mac, OID_AUTO, sysvshm_enforce, SECURITY_MAC_CTLFLAGS, 240 &mac_sysvshm_enforce, 0, "Enforce MAC policy on System V Shared Memory"); 241 242unsigned int mac_vm_enforce = 1; 243SYSCTL_INT(_security_mac, OID_AUTO, vm_enforce, SECURITY_MAC_CTLFLAGS, 244 &mac_vm_enforce, 0, "Enforce MAC policy on VM operations"); 245 246unsigned int mac_vnode_enforce = 1; 247SYSCTL_UINT(_security_mac, OID_AUTO, vnode_enforce, SECURITY_MAC_CTLFLAGS, 248 &mac_vnode_enforce, 0, "Enforce MAC policy on vnode operations"); 249 250#if CONFIG_AUDIT 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; 257#endif 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 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 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 535 if (load_security_extensions_function) { 536 load_security_extensions_function(); 537 } 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 553#if CONFIG_AUDIT 554 mac_audit_data_zone = zinit(MAC_AUDIT_DATA_LIMIT, 555 AQ_HIWATER * MAC_AUDIT_DATA_LIMIT, 556 8192, "mac_audit_data_zone"); 557#endif 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{ 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. 1172 * 1173 * XXX This may be leaking an sbuf. 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; 1180 char *scratch_base; 1181 char *scratch; 1182 struct sbuf sb; 1183 int error = 0, len; 1184 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) { 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); 1217 1218out: 1219 if (scratch_base != NULL) 1220 FREE(scratch_base, M_MACTEMP); 1221 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 1301__mac_get_pid(struct proc *p, struct __mac_get_pid_args *uap, int *ret __unused) 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)) { 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; 1316 } else { 1317 struct user32_mac mac32; 1318 error = copyin(uap->mac_p, &mac32, sizeof(mac32)); 1319 mac.m_buflen = mac32.m_buflen; 1320 mac.m_string = mac32.m_string; 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 1357__mac_get_proc(proc_t p, struct __mac_get_proc_args *uap, int *ret __unused) 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)) { 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; 1370 } else { 1371 struct user32_mac mac32; 1372 error = copyin(uap->mac_p, &mac32, sizeof(mac32)); 1373 mac.m_buflen = mac32.m_buflen; 1374 mac.m_string = mac32.m_string; 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 1405int 1406__mac_set_proc(proc_t p, struct __mac_set_proc_args *uap, int *ret __unused) 1407{ 1408 kauth_cred_t newcred; 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)) { 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; 1420 } else { 1421 struct user32_mac mac32; 1422 error = copyin(uap->mac_p, &mac32, sizeof(mac32)); 1423 mac.m_buflen = mac32.m_buflen; 1424 mac.m_string = mac32.m_string; 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 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 */ 1490int 1491__mac_get_lcid(proc_t p, struct __mac_get_lcid_args *uap, int *ret __unused) 1492{ 1493 char *elements, *buffer; 1494 struct user_mac mac; 1495 struct lctx *l; 1496 int error; 1497 size_t ulen; 1498 1499 AUDIT_ARG(value32, uap->lcid); 1500 if (IS_64BIT_PROCESS(p)) { 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; 1505 } else { 1506 struct user32_mac mac32; 1507 error = copyin(uap->mac_p, &mac32, sizeof(mac32)); 1508 mac.m_buflen = mac32.m_buflen; 1509 mac.m_string = mac32.m_string; 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 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 */ 1559int 1560__mac_get_lctx(proc_t p, struct __mac_get_lctx_args *uap, int *ret __unused) 1561{ 1562 char *elements, *buffer; 1563 struct user_mac mac; 1564 int error; 1565 size_t ulen; 1566 1567 if (IS_64BIT_PROCESS(p)) { 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; 1572 } else { 1573 struct user32_mac mac32; 1574 error = copyin(uap->mac_p, &mac32, sizeof(mac32)); 1575 mac.m_buflen = mac32.m_buflen; 1576 mac.m_string = mac32.m_string; 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 1615__mac_set_lctx(proc_t p, struct __mac_set_lctx_args *uap, int *ret __unused) 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)) { 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; 1628 } else { 1629 struct user32_mac mac32; 1630 error = copyin(uap->mac_p, &mac32, sizeof(mac32)); 1631 mac.m_buflen = mac32.m_buflen; 1632 mac.m_string = mac32.m_string; 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 1677__mac_get_lcid(proc_t p __unused, struct __mac_get_lcid_args *uap __unused, int *ret __unused) 1678{ 1679 1680 return (ENOSYS); 1681} 1682 1683int 1684__mac_get_lctx(proc_t p __unused, struct __mac_get_lctx_args *uap __unused, int *ret __unused) 1685{ 1686 1687 return (ENOSYS); 1688} 1689 1690int 1691__mac_set_lctx(proc_t p __unused, struct __mac_set_lctx_args *uap __unused, int *ret __unused) 1692{ 1693 1694 return (ENOSYS); 1695} 1696#endif /* !LCTX */ 1697 1698int 1699__mac_get_fd(proc_t p, struct __mac_get_fd_args *uap, int *ret __unused) 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)) { 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; 1720 } else { 1721 struct user32_mac mac32; 1722 error = copyin(uap->mac_p, &mac32, sizeof(mac32)); 1723 mac.m_buflen = mac32.m_buflen; 1724 mac.m_string = mac32.m_string; 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 1760 switch (FILEGLOB_DTYPE(fp->f_fglob)) { 1761 case DTYPE_VNODE: 1762 intlabel = mac_vnode_label_alloc(); 1763 if (intlabel == NULL) { 1764 error = ENOMEM; 1765 break; 1766 } 1767 vp = (struct vnode *)fp->f_fglob->fg_data; 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 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)) { 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; 1825 } else { 1826 struct user32_mac mac32; 1827 error = copyin(mac_p, &mac32, sizeof(mac32)); 1828 mac.m_buflen = mac32.m_buflen; 1829 mac.m_string = mac32.m_string; 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); 1840 MALLOC(buffer, char *, mac.m_buflen, M_MACTEMP, M_WAITOK | M_ZERO); 1841 1842 error = copyinstr(mac.m_string, elements, mac.m_buflen, &ulen); 1843 if (error) { 1844 FREE(buffer, M_MACTEMP); 1845 FREE(elements, M_MACTEMP); 1846 return (error); 1847 } 1848 AUDIT_ARG(mac_string, elements); 1849 1850 ctx = vfs_context_current(); 1851 1852 NDINIT(&nd, LOOKUP, OP_LOOKUP, 1853 LOCKLEAF | (follow ? FOLLOW : NOFOLLOW) | AUDITVNPATH1, 1854 UIO_USERSPACE, path_p, ctx); 1855 error = namei(&nd); 1856 if (error) { 1857 FREE(buffer, M_MACTEMP); 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); 1867 error = mac_vnode_label_externalize(intlabel, elements, buffer, 1868 mac.m_buflen, M_WAITOK); 1869 mac_vnode_label_free(intlabel); 1870 if (error == 0) 1871 error = copyout(buffer, mac.m_string, strlen(buffer) + 1); 1872 1873 vnode_put(vp); 1874 1875 FREE(buffer, M_MACTEMP); 1876 FREE(elements, M_MACTEMP); 1877 1878 return (error); 1879} 1880 1881int 1882__mac_get_file(proc_t p, struct __mac_get_file_args *uap, 1883 int *ret __unused) 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, 1891 int *ret __unused) 1892{ 1893 1894 return (mac_get_filelink(p, uap->mac_p, uap->path_p, 0)); 1895} 1896 1897int 1898__mac_set_fd(proc_t p, struct __mac_set_fd_args *uap, int *ret __unused) 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)) { 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; 1920 } else { 1921 struct user32_mac mac32; 1922 error = copyin(uap->mac_p, &mac32, sizeof(mac32)); 1923 mac.m_buflen = mac32.m_buflen; 1924 mac.m_string = mac32.m_string; 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 1955 switch (FILEGLOB_DTYPE(fp->f_fglob)) { 1956 1957 case DTYPE_VNODE: 1958 if (mac_label_vnodes == 0) { 1959 error = ENOSYS; 1960 break; 1961 } 1962 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 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 2023 if (mac_label_vnodes == 0) 2024 return ENOSYS; 2025 2026 if (IS_64BIT_PROCESS(p)) { 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; 2031 } else { 2032 struct user32_mac mac32; 2033 error = copyin(mac_p, &mac32, sizeof(mac32)); 2034 mac.m_buflen = mac32.m_buflen; 2035 mac.m_string = mac32.m_string; 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 2062 NDINIT(&nd, LOOKUP, OP_LOOKUP, 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, 2083 int *ret __unused) 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, 2091 int *ret __unused) 2092{ 2093 2094 return (mac_set_filelink(p, uap->mac_p, uap->path_p, 0)); 2095} 2096 2097/* 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 * 2111 */ 2112int 2113__mac_syscall(proc_t p, struct __mac_syscall_args *uap, int *retv __unused) 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); 2124 AUDIT_ARG(value32, uap->call); 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())) { 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; 2175 } else { 2176 struct user32_mac mac32; 2177 error = copyin(mac_p, &mac32, sizeof(mac32)); 2178 mac.m_buflen = mac32.m_buflen; 2179 mac.m_string = mac32.m_string; 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 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 */ 2222int 2223__mac_get_mount(proc_t p __unused, struct __mac_get_mount_args *uap, 2224 int *ret __unused) 2225{ 2226 struct nameidata nd; 2227 struct vfs_context *ctx = vfs_context_current(); 2228 struct mount *mp; 2229 int error; 2230 2231 NDINIT(&nd, LOOKUP, OP_LOOKUP, FOLLOW | AUDITVNPATH1, 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 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 2298#else /* MAC */ 2299 2300void (*load_security_extensions_function)(void) = 0; 2301 2302struct sysctl_oid_list sysctl__security_mac_children; 2303 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 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 2348intptr_t mac_label_get(struct label *l __unused, int slot __unused) 2349{ 2350 return 0; 2351} 2352 2353void mac_label_set(struct label *l __unused, int slot __unused, intptr_t v __unused) 2354{ 2355 return; 2356} 2357 2358struct label *mac_thread_get_threadlabel(struct thread *thread __unused) 2359{ 2360 return NULL; 2361} 2362 2363struct label *mac_thread_get_uthreadlabel(struct uthread *uthread __unused) 2364{ 2365 return NULL; 2366} 2367 2368void mac_proc_set_enforce(proc_t p, int enforce_flags); 2369void mac_proc_set_enforce(proc_t p __unused, int enforce_flags __unused) 2370{ 2371 return; 2372} 2373 2374int mac_iokit_check_hid_control(kauth_cred_t cred __unused); 2375int mac_iokit_check_hid_control(kauth_cred_t cred __unused) 2376{ 2377 return 0; 2378} 2379 2380#endif /* !MAC */ 2381