ipc_host.c
1 /* 2 * Copyright (c) 2000-2009 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 * @OSF_COPYRIGHT@ 30 */ 31 /* 32 * Mach Operating System 33 * Copyright (c) 1991,1990,1989,1988 Carnegie Mellon University 34 * All Rights Reserved. 35 * 36 * Permission to use, copy, modify and distribute this software and its 37 * documentation is hereby granted, provided that both the copyright 38 * notice and this permission notice appear in all copies of the 39 * software, derivative works or modified versions, and any portions 40 * thereof, and that both notices appear in supporting documentation. 41 * 42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56 /* 57 */ 58 59 /* 60 * kern/ipc_host.c 61 * 62 * Routines to implement host ports. 63 */ 64 #include <mach/message.h> 65 #include <mach/mach_traps.h> 66 #include <mach/mach_host_server.h> 67 #include <mach/host_priv_server.h> 68 #include <kern/host.h> 69 #include <kern/processor.h> 70 #include <kern/task.h> 71 #include <kern/thread.h> 72 #include <kern/ipc_host.h> 73 #include <kern/ipc_kobject.h> 74 #include <kern/misc_protos.h> 75 #include <kern/spl.h> 76 #include <ipc/ipc_port.h> 77 #include <ipc/ipc_space.h> 78 79 #if CONFIG_MACF 80 #include <security/mac_mach_internal.h> 81 #endif 82 83 /* 84 * Forward declarations 85 */ 86 87 boolean_t 88 ref_pset_port_locked( 89 ipc_port_t port, boolean_t matchn, processor_set_t *ppset); 90 91 /* 92 * ipc_host_init: set up various things. 93 */ 94 95 extern lck_grp_t host_notify_lock_grp; 96 97 void 98 ipc_host_init(void) 99 { 100 ipc_port_t port; 101 int i; 102 103 lck_mtx_init(&realhost.lock, &host_notify_lock_grp, LCK_ATTR_NULL); 104 105 /* 106 * Allocate and set up the two host ports. 107 */ 108 port = ipc_kobject_alloc_port((ipc_kobject_t) &realhost, IKOT_HOST_SECURITY, 109 IPC_KOBJECT_ALLOC_MAKE_SEND); 110 kernel_set_special_port(&realhost, HOST_SECURITY_PORT, port); 111 112 port = ipc_kobject_alloc_port((ipc_kobject_t) &realhost, IKOT_HOST, 113 IPC_KOBJECT_ALLOC_MAKE_SEND); 114 kernel_set_special_port(&realhost, HOST_PORT, port); 115 116 port = ipc_kobject_alloc_port((ipc_kobject_t) &realhost, IKOT_HOST_PRIV, 117 IPC_KOBJECT_ALLOC_MAKE_SEND); 118 kernel_set_special_port(&realhost, HOST_PRIV_PORT, port); 119 120 /* the rest of the special ports will be set up later */ 121 122 bzero(&realhost.exc_actions[0], sizeof(realhost.exc_actions[0])); 123 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 124 realhost.exc_actions[i].port = IP_NULL; 125 /* The mac framework is not yet initialized, so we defer 126 * initializing the labels to later, when they are set 127 * for the first time. */ 128 realhost.exc_actions[i].label = NULL; 129 /* initialize the entire exception action struct */ 130 realhost.exc_actions[i].behavior = 0; 131 realhost.exc_actions[i].flavor = 0; 132 realhost.exc_actions[i].privileged = FALSE; 133 } /* for */ 134 135 /* 136 * Set up ipc for default processor set. 137 */ 138 ipc_pset_init(&pset0); 139 ipc_pset_enable(&pset0); 140 141 /* 142 * And for master processor 143 */ 144 ipc_processor_init(master_processor); 145 ipc_processor_enable(master_processor); 146 } 147 148 /* 149 * Routine: host_self_trap [mach trap] 150 * Purpose: 151 * Give the caller send rights for his own host port. 152 * Conditions: 153 * Nothing locked. 154 * Returns: 155 * MACH_PORT_NULL if there are any resource failures 156 * or other errors. 157 */ 158 159 mach_port_name_t 160 host_self_trap( 161 __unused struct host_self_trap_args *args) 162 { 163 task_t self = current_task(); 164 ipc_port_t sright; 165 mach_port_name_t name; 166 167 itk_lock(self); 168 sright = ipc_port_copy_send(self->itk_host); 169 itk_unlock(self); 170 name = ipc_port_copyout_send(sright, current_space()); 171 return name; 172 } 173 174 /* 175 * ipc_processor_init: 176 * 177 * Initialize ipc access to processor by allocating port. 178 */ 179 180 void 181 ipc_processor_init( 182 processor_t processor) 183 { 184 ipc_port_t port; 185 186 port = ipc_port_alloc_kernel(); 187 if (port == IP_NULL) { 188 panic("ipc_processor_init"); 189 } 190 processor->processor_self = port; 191 } 192 193 /* 194 * ipc_processor_enable: 195 * 196 * Enable ipc control of processor by setting port object. 197 */ 198 void 199 ipc_processor_enable( 200 processor_t processor) 201 { 202 ipc_port_t myport; 203 204 myport = processor->processor_self; 205 ipc_kobject_set(myport, (ipc_kobject_t) processor, IKOT_PROCESSOR); 206 } 207 208 /* 209 * ipc_pset_init: 210 * 211 * Initialize ipc control of a processor set by allocating its ports. 212 */ 213 214 void 215 ipc_pset_init( 216 processor_set_t pset) 217 { 218 ipc_port_t port; 219 220 port = ipc_port_alloc_kernel(); 221 if (port == IP_NULL) { 222 panic("ipc_pset_init"); 223 } 224 pset->pset_self = port; 225 226 port = ipc_port_alloc_kernel(); 227 if (port == IP_NULL) { 228 panic("ipc_pset_init"); 229 } 230 pset->pset_name_self = port; 231 } 232 233 /* 234 * ipc_pset_enable: 235 * 236 * Enable ipc access to a processor set. 237 */ 238 void 239 ipc_pset_enable( 240 processor_set_t pset) 241 { 242 ipc_kobject_set(pset->pset_self, (ipc_kobject_t) pset, IKOT_PSET); 243 ipc_kobject_set(pset->pset_name_self, (ipc_kobject_t) pset, IKOT_PSET_NAME); 244 } 245 246 /* 247 * processor_set_default: 248 * 249 * Return ports for manipulating default_processor set. 250 */ 251 kern_return_t 252 processor_set_default( 253 host_t host, 254 processor_set_t *pset) 255 { 256 if (host == HOST_NULL) { 257 return KERN_INVALID_ARGUMENT; 258 } 259 260 *pset = &pset0; 261 262 return KERN_SUCCESS; 263 } 264 265 /* 266 * Routine: convert_port_to_host 267 * Purpose: 268 * Convert from a port to a host. 269 * Doesn't consume the port ref; the host produced may be null. 270 * Conditions: 271 * Nothing locked. 272 */ 273 274 host_t 275 convert_port_to_host( 276 ipc_port_t port) 277 { 278 host_t host = HOST_NULL; 279 280 if (IP_VALID(port)) { 281 if (ip_kotype(port) == IKOT_HOST || 282 ip_kotype(port) == IKOT_HOST_PRIV) { 283 host = (host_t) ip_get_kobject(port); 284 require_ip_active(port); 285 } 286 } 287 return host; 288 } 289 290 /* 291 * Routine: convert_port_to_host_priv 292 * Purpose: 293 * Convert from a port to a host. 294 * Doesn't consume the port ref; the host produced may be null. 295 * Conditions: 296 * Nothing locked. 297 */ 298 299 host_t 300 convert_port_to_host_priv( 301 ipc_port_t port) 302 { 303 host_t host = HOST_NULL; 304 305 /* reject translation if itk_host is not host_priv */ 306 if (port != current_task()->itk_host) { 307 return HOST_NULL; 308 } 309 310 if (IP_VALID(port)) { 311 ip_lock(port); 312 if (ip_active(port) && 313 (ip_kotype(port) == IKOT_HOST_PRIV)) { 314 assert(ip_get_kobject(port) == &realhost); 315 host = &realhost; 316 } 317 ip_unlock(port); 318 } 319 320 return host; 321 } 322 323 /* 324 * Routine: convert_port_to_processor 325 * Purpose: 326 * Convert from a port to a processor. 327 * Doesn't consume the port ref; 328 * the processor produced may be null. 329 * Conditions: 330 * Nothing locked. 331 */ 332 333 processor_t 334 convert_port_to_processor( 335 ipc_port_t port) 336 { 337 processor_t processor = PROCESSOR_NULL; 338 339 if (IP_VALID(port)) { 340 ip_lock(port); 341 if (ip_active(port) && 342 (ip_kotype(port) == IKOT_PROCESSOR)) { 343 processor = (processor_t) ip_get_kobject(port); 344 } 345 ip_unlock(port); 346 } 347 348 return processor; 349 } 350 351 /* 352 * Routine: convert_port_to_pset 353 * Purpose: 354 * Convert from a port to a pset. 355 * Doesn't consume the port ref; produces a pset ref, 356 * which may be null. 357 * Conditions: 358 * Nothing locked. 359 */ 360 361 processor_set_t 362 convert_port_to_pset( 363 ipc_port_t port) 364 { 365 boolean_t r; 366 processor_set_t pset = PROCESSOR_SET_NULL; 367 368 r = FALSE; 369 while (!r && IP_VALID(port)) { 370 ip_lock(port); 371 r = ref_pset_port_locked(port, FALSE, &pset); 372 /* port unlocked */ 373 } 374 return pset; 375 } 376 377 /* 378 * Routine: convert_port_to_pset_name 379 * Purpose: 380 * Convert from a port to a pset. 381 * Doesn't consume the port ref; produces a pset ref, 382 * which may be null. 383 * Conditions: 384 * Nothing locked. 385 */ 386 387 processor_set_name_t 388 convert_port_to_pset_name( 389 ipc_port_t port) 390 { 391 boolean_t r; 392 processor_set_t pset = PROCESSOR_SET_NULL; 393 394 r = FALSE; 395 while (!r && IP_VALID(port)) { 396 ip_lock(port); 397 r = ref_pset_port_locked(port, TRUE, &pset); 398 /* port unlocked */ 399 } 400 return pset; 401 } 402 403 boolean_t 404 ref_pset_port_locked(ipc_port_t port, boolean_t matchn, processor_set_t *ppset) 405 { 406 processor_set_t pset; 407 408 pset = PROCESSOR_SET_NULL; 409 if (ip_active(port) && 410 ((ip_kotype(port) == IKOT_PSET) || 411 (matchn && (ip_kotype(port) == IKOT_PSET_NAME)))) { 412 pset = (processor_set_t) ip_get_kobject(port); 413 } 414 415 *ppset = pset; 416 ip_unlock(port); 417 418 return TRUE; 419 } 420 421 /* 422 * Routine: convert_host_to_port 423 * Purpose: 424 * Convert from a host to a port. 425 * Produces a naked send right which may be invalid. 426 * Conditions: 427 * Nothing locked. 428 */ 429 430 ipc_port_t 431 convert_host_to_port( 432 host_t host) 433 { 434 ipc_port_t port; 435 436 host_get_host_port(host, &port); 437 return port; 438 } 439 440 /* 441 * Routine: convert_processor_to_port 442 * Purpose: 443 * Convert from a processor to a port. 444 * Produces a naked send right which may be invalid. 445 * Processors are not reference counted, so nothing to release. 446 * Conditions: 447 * Nothing locked. 448 */ 449 450 ipc_port_t 451 convert_processor_to_port( 452 processor_t processor) 453 { 454 ipc_port_t port = processor->processor_self; 455 456 if (port != IP_NULL) { 457 port = ipc_port_make_send(port); 458 } 459 return port; 460 } 461 462 /* 463 * Routine: convert_pset_to_port 464 * Purpose: 465 * Convert from a pset to a port. 466 * Produces a naked send right which may be invalid. 467 * Processor sets are not reference counted, so nothing to release. 468 * Conditions: 469 * Nothing locked. 470 */ 471 472 ipc_port_t 473 convert_pset_to_port( 474 processor_set_t pset) 475 { 476 ipc_port_t port = pset->pset_self; 477 478 if (port != IP_NULL) { 479 port = ipc_port_make_send(port); 480 } 481 482 return port; 483 } 484 485 /* 486 * Routine: convert_pset_name_to_port 487 * Purpose: 488 * Convert from a pset to a port. 489 * Produces a naked send right which may be invalid. 490 * Processor sets are not reference counted, so nothing to release. 491 * Conditions: 492 * Nothing locked. 493 */ 494 495 ipc_port_t 496 convert_pset_name_to_port( 497 processor_set_name_t pset) 498 { 499 ipc_port_t port = pset->pset_name_self; 500 501 if (port != IP_NULL) { 502 port = ipc_port_make_send(port); 503 } 504 505 return port; 506 } 507 508 /* 509 * Routine: convert_port_to_host_security 510 * Purpose: 511 * Convert from a port to a host security. 512 * Doesn't consume the port ref; the port produced may be null. 513 * Conditions: 514 * Nothing locked. 515 */ 516 517 host_t 518 convert_port_to_host_security( 519 ipc_port_t port) 520 { 521 host_t host = HOST_NULL; 522 523 if (IP_VALID(port)) { 524 ip_lock(port); 525 if (ip_active(port) && 526 (ip_kotype(port) == IKOT_HOST_SECURITY)) { 527 host = (host_t) ip_get_kobject(port); 528 } 529 ip_unlock(port); 530 } 531 532 return host; 533 } 534 535 /* 536 * Routine: host_set_exception_ports [kernel call] 537 * Purpose: 538 * Sets the host exception port, flavor and 539 * behavior for the exception types specified by the mask. 540 * There will be one send right per exception per valid 541 * port. 542 * Conditions: 543 * Nothing locked. If successful, consumes 544 * the supplied send right. 545 * Returns: 546 * KERN_SUCCESS Changed the special port. 547 * KERN_INVALID_ARGUMENT The host_priv is not valid, 548 * Illegal mask bit set. 549 * Illegal exception behavior 550 */ 551 kern_return_t 552 host_set_exception_ports( 553 host_priv_t host_priv, 554 exception_mask_t exception_mask, 555 ipc_port_t new_port, 556 exception_behavior_t new_behavior, 557 thread_state_flavor_t new_flavor) 558 { 559 int i; 560 ipc_port_t old_port[EXC_TYPES_COUNT]; 561 562 #if CONFIG_MACF 563 struct label *deferred_labels[EXC_TYPES_COUNT]; 564 struct label *new_label; 565 #endif 566 567 if (host_priv == HOST_PRIV_NULL) { 568 return KERN_INVALID_ARGUMENT; 569 } 570 571 if (exception_mask & ~EXC_MASK_VALID) { 572 return KERN_INVALID_ARGUMENT; 573 } 574 575 if (IP_VALID(new_port)) { 576 switch (new_behavior & ~MACH_EXCEPTION_MASK) { 577 case EXCEPTION_DEFAULT: 578 case EXCEPTION_STATE: 579 case EXCEPTION_STATE_IDENTITY: 580 break; 581 default: 582 return KERN_INVALID_ARGUMENT; 583 } 584 } 585 586 /* 587 * Check the validity of the thread_state_flavor by calling the 588 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in 589 * osfmk/mach/ARCHITECTURE/thread_status.h 590 */ 591 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) { 592 return KERN_INVALID_ARGUMENT; 593 } 594 595 #if CONFIG_MACF 596 if (mac_task_check_set_host_exception_ports(current_task(), exception_mask) != 0) { 597 return KERN_NO_ACCESS; 598 } 599 600 new_label = mac_exc_create_label_for_current_proc(); 601 602 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 603 if (host_priv->exc_actions[i].label == NULL) { 604 deferred_labels[i] = mac_exc_create_label(); 605 } else { 606 deferred_labels[i] = NULL; 607 } 608 } 609 #endif 610 611 host_lock(host_priv); 612 613 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 614 #if CONFIG_MACF 615 if (host_priv->exc_actions[i].label == NULL) { 616 // Lazy initialization (see ipc_port_init). 617 mac_exc_associate_action_label(&host_priv->exc_actions[i], deferred_labels[i]); 618 deferred_labels[i] = NULL; // Label is used, do not free. 619 } 620 #endif 621 622 if ((exception_mask & (1 << i)) 623 #if CONFIG_MACF 624 && mac_exc_update_action_label(&host_priv->exc_actions[i], new_label) == 0 625 #endif 626 ) { 627 old_port[i] = host_priv->exc_actions[i].port; 628 629 host_priv->exc_actions[i].port = 630 ipc_port_copy_send(new_port); 631 host_priv->exc_actions[i].behavior = new_behavior; 632 host_priv->exc_actions[i].flavor = new_flavor; 633 } else { 634 old_port[i] = IP_NULL; 635 } 636 }/* for */ 637 638 /* 639 * Consume send rights without any lock held. 640 */ 641 host_unlock(host_priv); 642 643 #if CONFIG_MACF 644 mac_exc_free_label(new_label); 645 #endif 646 647 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 648 if (IP_VALID(old_port[i])) { 649 ipc_port_release_send(old_port[i]); 650 } 651 #if CONFIG_MACF 652 if (deferred_labels[i] != NULL) { 653 /* Deferred label went unused: Another thread has completed the lazy initialization. */ 654 mac_exc_free_label(deferred_labels[i]); 655 } 656 #endif 657 } 658 if (IP_VALID(new_port)) { /* consume send right */ 659 ipc_port_release_send(new_port); 660 } 661 662 return KERN_SUCCESS; 663 } 664 665 /* 666 * Routine: host_get_exception_ports [kernel call] 667 * Purpose: 668 * Clones a send right for each of the host's exception 669 * ports specified in the mask and returns the behaviour 670 * and flavor of said port. 671 * 672 * Returns upto [in} CountCnt elements. 673 * 674 * Conditions: 675 * Nothing locked. 676 * Returns: 677 * KERN_SUCCESS Extracted a send right. 678 * KERN_INVALID_ARGUMENT Invalid host_priv specified, 679 * Invalid special port, 680 * Illegal mask bit set. 681 * KERN_FAILURE The thread is dead. 682 */ 683 kern_return_t 684 host_get_exception_ports( 685 host_priv_t host_priv, 686 exception_mask_t exception_mask, 687 exception_mask_array_t masks, 688 mach_msg_type_number_t * CountCnt, 689 exception_port_array_t ports, 690 exception_behavior_array_t behaviors, 691 thread_state_flavor_array_t flavors ) 692 { 693 unsigned int i, j, count; 694 695 if (host_priv == HOST_PRIV_NULL) { 696 return KERN_INVALID_ARGUMENT; 697 } 698 699 if (exception_mask & ~EXC_MASK_VALID) { 700 return KERN_INVALID_ARGUMENT; 701 } 702 703 host_lock(host_priv); 704 705 count = 0; 706 707 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 708 if (exception_mask & (1 << i)) { 709 for (j = 0; j < count; j++) { 710 /* 711 * search for an identical entry, if found 712 * set corresponding mask for this exception. 713 */ 714 if (host_priv->exc_actions[i].port == ports[j] && 715 host_priv->exc_actions[i].behavior == behaviors[j] 716 && host_priv->exc_actions[i].flavor == flavors[j]) { 717 masks[j] |= (1 << i); 718 break; 719 } 720 }/* for */ 721 if (j == count && count < *CountCnt) { 722 masks[j] = (1 << i); 723 ports[j] = 724 ipc_port_copy_send(host_priv->exc_actions[i].port); 725 behaviors[j] = host_priv->exc_actions[i].behavior; 726 flavors[j] = host_priv->exc_actions[i].flavor; 727 count++; 728 } 729 } 730 }/* for */ 731 host_unlock(host_priv); 732 733 *CountCnt = count; 734 return KERN_SUCCESS; 735 } 736 737 kern_return_t 738 host_swap_exception_ports( 739 host_priv_t host_priv, 740 exception_mask_t exception_mask, 741 ipc_port_t new_port, 742 exception_behavior_t new_behavior, 743 thread_state_flavor_t new_flavor, 744 exception_mask_array_t masks, 745 mach_msg_type_number_t * CountCnt, 746 exception_port_array_t ports, 747 exception_behavior_array_t behaviors, 748 thread_state_flavor_array_t flavors ) 749 { 750 unsigned int i, 751 j, 752 count; 753 ipc_port_t old_port[EXC_TYPES_COUNT]; 754 755 #if CONFIG_MACF 756 struct label *deferred_labels[EXC_TYPES_COUNT]; 757 struct label *new_label; 758 #endif 759 760 if (host_priv == HOST_PRIV_NULL) { 761 return KERN_INVALID_ARGUMENT; 762 } 763 764 if (exception_mask & ~EXC_MASK_VALID) { 765 return KERN_INVALID_ARGUMENT; 766 } 767 768 if (IP_VALID(new_port)) { 769 switch (new_behavior) { 770 case EXCEPTION_DEFAULT: 771 case EXCEPTION_STATE: 772 case EXCEPTION_STATE_IDENTITY: 773 break; 774 default: 775 return KERN_INVALID_ARGUMENT; 776 } 777 } 778 779 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) { 780 return KERN_INVALID_ARGUMENT; 781 } 782 783 #if CONFIG_MACF 784 if (mac_task_check_set_host_exception_ports(current_task(), exception_mask) != 0) { 785 return KERN_NO_ACCESS; 786 } 787 788 new_label = mac_exc_create_label_for_current_proc(); 789 790 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 791 if (host_priv->exc_actions[i].label == NULL) { 792 deferred_labels[i] = mac_exc_create_label(); 793 } else { 794 deferred_labels[i] = NULL; 795 } 796 } 797 #endif /* CONFIG_MACF */ 798 799 host_lock(host_priv); 800 801 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION); 802 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; i++) { 803 #if CONFIG_MACF 804 if (host_priv->exc_actions[i].label == NULL) { 805 // Lazy initialization (see ipc_port_init). 806 mac_exc_associate_action_label(&host_priv->exc_actions[i], deferred_labels[i]); 807 deferred_labels[i] = NULL; // Label is used, do not free. 808 } 809 #endif 810 811 if ((exception_mask & (1 << i)) 812 #if CONFIG_MACF 813 && mac_exc_update_action_label(&host_priv->exc_actions[i], new_label) == 0 814 #endif 815 ) { 816 for (j = 0; j < count; j++) { 817 /* 818 * search for an identical entry, if found 819 * set corresponding mask for this exception. 820 */ 821 if (host_priv->exc_actions[i].port == ports[j] && 822 host_priv->exc_actions[i].behavior == behaviors[j] 823 && host_priv->exc_actions[i].flavor == flavors[j]) { 824 masks[j] |= (1 << i); 825 break; 826 } 827 }/* for */ 828 if (j == count) { 829 masks[j] = (1 << i); 830 ports[j] = 831 ipc_port_copy_send(host_priv->exc_actions[i].port); 832 behaviors[j] = host_priv->exc_actions[i].behavior; 833 flavors[j] = host_priv->exc_actions[i].flavor; 834 count++; 835 } 836 old_port[i] = host_priv->exc_actions[i].port; 837 host_priv->exc_actions[i].port = 838 ipc_port_copy_send(new_port); 839 host_priv->exc_actions[i].behavior = new_behavior; 840 host_priv->exc_actions[i].flavor = new_flavor; 841 } else { 842 old_port[i] = IP_NULL; 843 } 844 }/* for */ 845 host_unlock(host_priv); 846 847 #if CONFIG_MACF 848 mac_exc_free_label(new_label); 849 #endif 850 851 /* 852 * Consume send rights without any lock held. 853 */ 854 while (--i >= FIRST_EXCEPTION) { 855 if (IP_VALID(old_port[i])) { 856 ipc_port_release_send(old_port[i]); 857 } 858 #if CONFIG_MACF 859 if (deferred_labels[i] != NULL) { 860 mac_exc_free_label(deferred_labels[i]); // Label unused. 861 } 862 #endif 863 } 864 865 if (IP_VALID(new_port)) { /* consume send right */ 866 ipc_port_release_send(new_port); 867 } 868 *CountCnt = count; 869 870 return KERN_SUCCESS; 871 }