1/* 2 * Copyright (c) 2000-2007 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_FREE_COPYRIGHT@ 30 */ 31/* 32 * Mach Operating System 33 * Copyright (c) 1991,1990,1989 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 * NOTICE: This file was modified by McAfee Research in 2004 to introduce 58 * support for mandatory and extensible security protections. This notice 59 * is included in support of clause 2.2 (b) of the Apple Public License, 60 * Version 2.0. 61 */ 62/* 63 */ 64/* 65 * File: ipc/ipc_port.c 66 * Author: Rich Draves 67 * Date: 1989 68 * 69 * Functions to manipulate IPC ports. 70 */ 71 72#include <zone_debug.h> 73#include <mach_assert.h> 74 75#include <mach/port.h> 76#include <mach/kern_return.h> 77#include <kern/ipc_kobject.h> 78#include <kern/thread.h> 79#include <kern/misc_protos.h> 80#include <kern/wait_queue.h> 81#include <ipc/ipc_entry.h> 82#include <ipc/ipc_space.h> 83#include <ipc/ipc_object.h> 84#include <ipc/ipc_port.h> 85#include <ipc/ipc_pset.h> 86#include <ipc/ipc_kmsg.h> 87#include <ipc/ipc_mqueue.h> 88#include <ipc/ipc_notify.h> 89#include <ipc/ipc_table.h> 90#include <ipc/ipc_importance.h> 91 92#include <security/mac_mach_internal.h> 93 94#include <string.h> 95 96decl_lck_spin_data(, ipc_port_multiple_lock_data) 97ipc_port_timestamp_t ipc_port_timestamp_data; 98int ipc_portbt; 99 100#if MACH_ASSERT 101void ipc_port_init_debug( 102 ipc_port_t port, 103 uintptr_t *callstack, 104 unsigned int callstack_max); 105 106void ipc_port_callstack_init_debug( 107 uintptr_t *callstack, 108 unsigned int callstack_max); 109 110#endif /* MACH_ASSERT */ 111 112void 113ipc_port_release(ipc_port_t port) 114{ 115 ip_release(port); 116} 117 118void 119ipc_port_reference(ipc_port_t port) 120{ 121 ip_reference(port); 122} 123 124/* 125 * Routine: ipc_port_timestamp 126 * Purpose: 127 * Retrieve a timestamp value. 128 */ 129 130ipc_port_timestamp_t 131ipc_port_timestamp(void) 132{ 133 return OSIncrementAtomic(&ipc_port_timestamp_data); 134} 135 136/* 137 * Routine: ipc_port_request_alloc 138 * Purpose: 139 * Try to allocate a request slot. 140 * If successful, returns the request index. 141 * Otherwise returns zero. 142 * Conditions: 143 * The port is locked and active. 144 * Returns: 145 * KERN_SUCCESS A request index was found. 146 * KERN_NO_SPACE No index allocated. 147 */ 148 149#if IMPORTANCE_INHERITANCE 150kern_return_t 151ipc_port_request_alloc( 152 ipc_port_t port, 153 mach_port_name_t name, 154 ipc_port_t soright, 155 boolean_t send_possible, 156 boolean_t immediate, 157 ipc_port_request_index_t *indexp, 158 boolean_t *importantp) 159#else 160kern_return_t 161ipc_port_request_alloc( 162 ipc_port_t port, 163 mach_port_name_t name, 164 ipc_port_t soright, 165 boolean_t send_possible, 166 boolean_t immediate, 167 ipc_port_request_index_t *indexp) 168#endif /* IMPORTANCE_INHERITANCE */ 169{ 170 ipc_port_request_t ipr, table; 171 ipc_port_request_index_t index; 172 uintptr_t mask = 0; 173 174#if IMPORTANCE_INHERITANCE 175 *importantp = FALSE; 176#endif /* IMPORTANCE_INHERITANCE */ 177 178 assert(ip_active(port)); 179 assert(name != MACH_PORT_NULL); 180 assert(soright != IP_NULL); 181 182 table = port->ip_requests; 183 184 if (table == IPR_NULL) 185 return KERN_NO_SPACE; 186 187 index = table->ipr_next; 188 if (index == 0) 189 return KERN_NO_SPACE; 190 191 ipr = &table[index]; 192 assert(ipr->ipr_name == MACH_PORT_NULL); 193 194 table->ipr_next = ipr->ipr_next; 195 ipr->ipr_name = name; 196 197 if (send_possible) { 198 mask |= IPR_SOR_SPREQ_MASK; 199 if (immediate) { 200 mask |= IPR_SOR_SPARM_MASK; 201 if (port->ip_sprequests == 0) { 202 port->ip_sprequests = 1; 203#if IMPORTANCE_INHERITANCE 204 /* TODO: Live importance support in send-possible */ 205 if (port->ip_impdonation != 0 && 206 port->ip_spimportant == 0 && 207 (task_is_importance_donor(current_task()))) { 208 port->ip_spimportant = 1; 209 *importantp = TRUE; 210 } 211#endif /* IMPORTANCE_INHERTANCE */ 212 } 213 } 214 } 215 ipr->ipr_soright = IPR_SOR_MAKE(soright, mask); 216 217 *indexp = index; 218 219 return KERN_SUCCESS; 220} 221 222/* 223 * Routine: ipc_port_request_grow 224 * Purpose: 225 * Grow a port's table of requests. 226 * Conditions: 227 * The port must be locked and active. 228 * Nothing else locked; will allocate memory. 229 * Upon return the port is unlocked. 230 * Returns: 231 * KERN_SUCCESS Grew the table. 232 * KERN_SUCCESS Somebody else grew the table. 233 * KERN_SUCCESS The port died. 234 * KERN_RESOURCE_SHORTAGE Couldn't allocate new table. 235 * KERN_NO_SPACE Couldn't grow to desired size 236 */ 237 238kern_return_t 239ipc_port_request_grow( 240 ipc_port_t port, 241 ipc_table_elems_t target_size) 242{ 243 ipc_table_size_t its; 244 ipc_port_request_t otable, ntable; 245 246 assert(ip_active(port)); 247 248 otable = port->ip_requests; 249 if (otable == IPR_NULL) 250 its = &ipc_table_requests[0]; 251 else 252 its = otable->ipr_size + 1; 253 254 if (target_size != ITS_SIZE_NONE) { 255 if ((otable != IPR_NULL) && 256 (target_size <= otable->ipr_size->its_size)) { 257 ip_unlock(port); 258 return KERN_SUCCESS; 259 } 260 while ((its->its_size) && (its->its_size < target_size)) { 261 its++; 262 } 263 if (its->its_size == 0) { 264 ip_unlock(port); 265 return KERN_NO_SPACE; 266 } 267 } 268 269 ip_reference(port); 270 ip_unlock(port); 271 272 if ((its->its_size == 0) || 273 ((ntable = it_requests_alloc(its)) == IPR_NULL)) { 274 ip_release(port); 275 return KERN_RESOURCE_SHORTAGE; 276 } 277 278 ip_lock(port); 279 280 /* 281 * Check that port is still active and that nobody else 282 * has slipped in and grown the table on us. Note that 283 * just checking if the current table pointer == otable 284 * isn't sufficient; must check ipr_size. 285 */ 286 287 if (ip_active(port) && (port->ip_requests == otable) && 288 ((otable == IPR_NULL) || (otable->ipr_size+1 == its))) { 289 ipc_table_size_t oits; 290 ipc_table_elems_t osize, nsize; 291 ipc_port_request_index_t free, i; 292 293 /* copy old table to new table */ 294 295 if (otable != IPR_NULL) { 296 oits = otable->ipr_size; 297 osize = oits->its_size; 298 free = otable->ipr_next; 299 300 (void) memcpy((void *)(ntable + 1), 301 (const void *)(otable + 1), 302 (osize - 1) * sizeof(struct ipc_port_request)); 303 } else { 304 osize = 1; 305 oits = 0; 306 free = 0; 307 } 308 309 nsize = its->its_size; 310 assert(nsize > osize); 311 312 /* add new elements to the new table's free list */ 313 314 for (i = osize; i < nsize; i++) { 315 ipc_port_request_t ipr = &ntable[i]; 316 317 ipr->ipr_name = MACH_PORT_NULL; 318 ipr->ipr_next = free; 319 free = i; 320 } 321 322 ntable->ipr_next = free; 323 ntable->ipr_size = its; 324 port->ip_requests = ntable; 325 ip_unlock(port); 326 ip_release(port); 327 328 if (otable != IPR_NULL) { 329 it_requests_free(oits, otable); 330 } 331 } else { 332 ip_unlock(port); 333 ip_release(port); 334 it_requests_free(its, ntable); 335 } 336 337 return KERN_SUCCESS; 338} 339 340/* 341 * Routine: ipc_port_request_sparm 342 * Purpose: 343 * Arm delayed send-possible request. 344 * Conditions: 345 * The port must be locked and active. 346 * 347 * Returns TRUE if the request was armed 348 * (or armed with importance in that version). 349 */ 350 351#if IMPORTANCE_INHERITANCE 352boolean_t 353ipc_port_request_sparm( 354 ipc_port_t port, 355 __assert_only mach_port_name_t name, 356 ipc_port_request_index_t index, 357 mach_msg_option_t option) 358#else 359boolean_t 360ipc_port_request_sparm( 361 ipc_port_t port, 362 __assert_only mach_port_name_t name, 363 ipc_port_request_index_t index) 364#endif /* IMPORTANCE_INHERITANCE */ 365{ 366 if (index != IE_REQ_NONE) { 367 ipc_port_request_t ipr, table; 368 369 assert(ip_active(port)); 370 371 table = port->ip_requests; 372 assert(table != IPR_NULL); 373 374 ipr = &table[index]; 375 assert(ipr->ipr_name == name); 376 377 if (IPR_SOR_SPREQ(ipr->ipr_soright)) { 378 ipr->ipr_soright = IPR_SOR_MAKE(ipr->ipr_soright, IPR_SOR_SPARM_MASK); 379 port->ip_sprequests = 1; 380#if IMPORTANCE_INHERITANCE 381 if (((option & MACH_SEND_NOIMPORTANCE) == 0) && 382 (port->ip_impdonation != 0) && 383 (port->ip_spimportant == 0) && 384 (((option & MACH_SEND_IMPORTANCE) != 0) || 385 (task_is_importance_donor(current_task())))) { 386 port->ip_spimportant = 1; 387 return TRUE; 388 } 389#else 390 return TRUE; 391#endif /* IMPORTANCE_INHERITANCE */ 392 } 393 } 394 return FALSE; 395} 396 397/* 398 * Routine: ipc_port_request_type 399 * Purpose: 400 * Determine the type(s) of port requests enabled for a name. 401 * Conditions: 402 * The port must be locked or inactive (to avoid table growth). 403 * The index must not be IE_REQ_NONE and for the name in question. 404 */ 405mach_port_type_t 406ipc_port_request_type( 407 ipc_port_t port, 408 __assert_only mach_port_name_t name, 409 ipc_port_request_index_t index) 410{ 411 ipc_port_request_t ipr, table; 412 mach_port_type_t type = 0; 413 414 table = port->ip_requests; 415 assert (table != IPR_NULL); 416 417 assert(index != IE_REQ_NONE); 418 ipr = &table[index]; 419 assert(ipr->ipr_name == name); 420 421 if (IP_VALID(IPR_SOR_PORT(ipr->ipr_soright))) { 422 type |= MACH_PORT_TYPE_DNREQUEST; 423 424 if (IPR_SOR_SPREQ(ipr->ipr_soright)) { 425 type |= MACH_PORT_TYPE_SPREQUEST; 426 427 if (!IPR_SOR_SPARMED(ipr->ipr_soright)) { 428 type |= MACH_PORT_TYPE_SPREQUEST_DELAYED; 429 } 430 } 431 } 432 return type; 433} 434 435/* 436 * Routine: ipc_port_request_cancel 437 * Purpose: 438 * Cancel a dead-name/send-possible request and return the send-once right. 439 * Conditions: 440 * The port must be locked and active. 441 * The index must not be IPR_REQ_NONE and must correspond with name. 442 */ 443 444ipc_port_t 445ipc_port_request_cancel( 446 ipc_port_t port, 447 __assert_only mach_port_name_t name, 448 ipc_port_request_index_t index) 449{ 450 ipc_port_request_t ipr, table; 451 ipc_port_t request = IP_NULL; 452 453 assert(ip_active(port)); 454 table = port->ip_requests; 455 assert(table != IPR_NULL); 456 457 assert (index != IE_REQ_NONE); 458 ipr = &table[index]; 459 assert(ipr->ipr_name == name); 460 request = IPR_SOR_PORT(ipr->ipr_soright); 461 462 /* return ipr to the free list inside the table */ 463 ipr->ipr_name = MACH_PORT_NULL; 464 ipr->ipr_next = table->ipr_next; 465 table->ipr_next = index; 466 467 return request; 468} 469 470/* 471 * Routine: ipc_port_pdrequest 472 * Purpose: 473 * Make a port-deleted request, returning the 474 * previously registered send-once right. 475 * Just cancels the previous request if notify is IP_NULL. 476 * Conditions: 477 * The port is locked and active. It is unlocked. 478 * Consumes a ref for notify (if non-null), and 479 * returns previous with a ref (if non-null). 480 */ 481 482void 483ipc_port_pdrequest( 484 ipc_port_t port, 485 ipc_port_t notify, 486 ipc_port_t *previousp) 487{ 488 ipc_port_t previous; 489 490 assert(ip_active(port)); 491 492 previous = port->ip_pdrequest; 493 port->ip_pdrequest = notify; 494 ip_unlock(port); 495 496 *previousp = previous; 497} 498 499/* 500 * Routine: ipc_port_nsrequest 501 * Purpose: 502 * Make a no-senders request, returning the 503 * previously registered send-once right. 504 * Just cancels the previous request if notify is IP_NULL. 505 * Conditions: 506 * The port is locked and active. It is unlocked. 507 * Consumes a ref for notify (if non-null), and 508 * returns previous with a ref (if non-null). 509 */ 510 511void 512ipc_port_nsrequest( 513 ipc_port_t port, 514 mach_port_mscount_t sync, 515 ipc_port_t notify, 516 ipc_port_t *previousp) 517{ 518 ipc_port_t previous; 519 mach_port_mscount_t mscount; 520 521 assert(ip_active(port)); 522 523 previous = port->ip_nsrequest; 524 mscount = port->ip_mscount; 525 526 if ((port->ip_srights == 0) && (sync <= mscount) && 527 (notify != IP_NULL)) { 528 port->ip_nsrequest = IP_NULL; 529 ip_unlock(port); 530 ipc_notify_no_senders(notify, mscount); 531 } else { 532 port->ip_nsrequest = notify; 533 ip_unlock(port); 534 } 535 536 *previousp = previous; 537} 538 539 540/* 541 * Routine: ipc_port_clear_receiver 542 * Purpose: 543 * Prepares a receive right for transmission/destruction. 544 * Conditions: 545 * The port is locked and active. 546 */ 547 548void 549ipc_port_clear_receiver( 550 ipc_port_t port, 551 queue_t links) 552{ 553 spl_t s; 554 555 assert(ip_active(port)); 556 557 /* 558 * pull ourselves from any sets. 559 */ 560 if (port->ip_pset_count != 0) { 561 ipc_pset_remove_from_all(port, links); 562 assert(port->ip_pset_count == 0); 563 } 564 565 /* 566 * Send anyone waiting on the port's queue directly away. 567 * Also clear the mscount and seqno. 568 */ 569 s = splsched(); 570 imq_lock(&port->ip_messages); 571 ipc_mqueue_changed(&port->ip_messages); 572 ipc_port_set_mscount(port, 0); 573 port->ip_messages.imq_seqno = 0; 574 port->ip_context = port->ip_guarded = port->ip_strict_guard = 0; 575 imq_unlock(&port->ip_messages); 576 splx(s); 577} 578 579/* 580 * Routine: ipc_port_init 581 * Purpose: 582 * Initializes a newly-allocated port. 583 * Doesn't touch the ip_object fields. 584 */ 585 586void 587ipc_port_init( 588 ipc_port_t port, 589 ipc_space_t space, 590 mach_port_name_t name) 591{ 592 /* port->ip_kobject doesn't have to be initialized */ 593 594 port->ip_receiver = space; 595 port->ip_receiver_name = name; 596 597 port->ip_mscount = 0; 598 port->ip_srights = 0; 599 port->ip_sorights = 0; 600 601 port->ip_nsrequest = IP_NULL; 602 port->ip_pdrequest = IP_NULL; 603 port->ip_requests = IPR_NULL; 604 605 port->ip_pset_count = 0; 606 port->ip_premsg = IKM_NULL; 607 port->ip_context = 0; 608 609 port->ip_sprequests = 0; 610 port->ip_spimportant = 0; 611 port->ip_impdonation = 0; 612 port->ip_tempowner = 0; 613 614 port->ip_guarded = 0; 615 port->ip_strict_guard = 0; 616 port->ip_impcount = 0; 617 618 port->ip_reserved = 0; 619 620 ipc_mqueue_init(&port->ip_messages, FALSE /* set */); 621} 622 623/* 624 * Routine: ipc_port_alloc 625 * Purpose: 626 * Allocate a port. 627 * Conditions: 628 * Nothing locked. If successful, the port is returned 629 * locked. (The caller doesn't have a reference.) 630 * Returns: 631 * KERN_SUCCESS The port is allocated. 632 * KERN_INVALID_TASK The space is dead. 633 * KERN_NO_SPACE No room for an entry in the space. 634 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 635 */ 636 637kern_return_t 638ipc_port_alloc( 639 ipc_space_t space, 640 mach_port_name_t *namep, 641 ipc_port_t *portp) 642{ 643 ipc_port_t port; 644 mach_port_name_t name; 645 kern_return_t kr; 646 647#if MACH_ASSERT 648 uintptr_t buf[IP_CALLSTACK_MAX]; 649 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX); 650#endif /* MACH_ASSERT */ 651 652 kr = ipc_object_alloc(space, IOT_PORT, 653 MACH_PORT_TYPE_RECEIVE, 0, 654 &name, (ipc_object_t *) &port); 655 if (kr != KERN_SUCCESS) 656 return kr; 657 658 /* port and space are locked */ 659 ipc_port_init(port, space, name); 660 661#if MACH_ASSERT 662 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX); 663#endif /* MACH_ASSERT */ 664 665 /* unlock space after init */ 666 is_write_unlock(space); 667 668 *namep = name; 669 *portp = port; 670 671 return KERN_SUCCESS; 672} 673 674/* 675 * Routine: ipc_port_alloc_name 676 * Purpose: 677 * Allocate a port, with a specific name. 678 * Conditions: 679 * Nothing locked. If successful, the port is returned 680 * locked. (The caller doesn't have a reference.) 681 * Returns: 682 * KERN_SUCCESS The port is allocated. 683 * KERN_INVALID_TASK The space is dead. 684 * KERN_NAME_EXISTS The name already denotes a right. 685 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 686 */ 687 688kern_return_t 689ipc_port_alloc_name( 690 ipc_space_t space, 691 mach_port_name_t name, 692 ipc_port_t *portp) 693{ 694 ipc_port_t port; 695 kern_return_t kr; 696 697#if MACH_ASSERT 698 uintptr_t buf[IP_CALLSTACK_MAX]; 699 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX); 700#endif /* MACH_ASSERT */ 701 702 kr = ipc_object_alloc_name(space, IOT_PORT, 703 MACH_PORT_TYPE_RECEIVE, 0, 704 name, (ipc_object_t *) &port); 705 if (kr != KERN_SUCCESS) 706 return kr; 707 708 /* port is locked */ 709 710 ipc_port_init(port, space, name); 711 712#if MACH_ASSERT 713 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX); 714#endif /* MACH_ASSERT */ 715 716 *portp = port; 717 718 return KERN_SUCCESS; 719} 720 721/* 722 * Routine: ipc_port_spnotify 723 * Purpose: 724 * Generate send-possible port notifications. 725 * Conditions: 726 * Nothing locked, reference held on port. 727 */ 728void 729ipc_port_spnotify( 730 ipc_port_t port) 731{ 732 ipc_port_request_index_t index = 0; 733 ipc_table_elems_t size = 0; 734#if IMPORTANCE_INHERITANCE 735 boolean_t dropassert = FALSE; 736#endif /* IMPORTANCE_INHERITANCE */ 737 738 /* 739 * If the port has no send-possible request 740 * armed, don't bother to lock the port. 741 */ 742 if (port->ip_sprequests == 0) 743 return; 744 745 ip_lock(port); 746 747#if IMPORTANCE_INHERITANCE 748 if (port->ip_spimportant != 0) { 749 port->ip_spimportant = 0; 750 if (ipc_port_impcount_delta(port, -1, IP_NULL) == -1) { 751 dropassert = TRUE; 752 } 753 } 754#endif /* IMPORTANCE_INHERITANCE */ 755 756 if (port->ip_sprequests == 0) { 757 ip_unlock(port); 758 goto out; 759 } 760 port->ip_sprequests = 0; 761 762revalidate: 763 if (ip_active(port)) { 764 ipc_port_request_t requests; 765 766 /* table may change each time port unlocked (reload) */ 767 requests = port->ip_requests; 768 assert(requests != IPR_NULL); 769 770 /* 771 * no need to go beyond table size when first 772 * we entered - those are future notifications. 773 */ 774 if (size == 0) 775 size = requests->ipr_size->its_size; 776 777 /* no need to backtrack either */ 778 while (++index < size) { 779 ipc_port_request_t ipr = &requests[index]; 780 mach_port_name_t name = ipr->ipr_name; 781 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright); 782 boolean_t armed = IPR_SOR_SPARMED(ipr->ipr_soright); 783 784 if (MACH_PORT_VALID(name) && armed && IP_VALID(soright)) { 785 /* claim send-once right - slot still inuse */ 786 ipr->ipr_soright = IP_NULL; 787 ip_unlock(port); 788 789 ipc_notify_send_possible(soright, name); 790 791 ip_lock(port); 792 goto revalidate; 793 } 794 } 795 } 796 ip_unlock(port); 797out: 798#if IMPORTANCE_INHERITANCE 799 if (dropassert == TRUE && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) { 800 /* drop internal assertion */ 801 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, 1); 802 } 803#endif /* IMPORTANCE_INHERITANCE */ 804 return; 805} 806 807/* 808 * Routine: ipc_port_dnnotify 809 * Purpose: 810 * Generate dead name notifications for 811 * all outstanding dead-name and send- 812 * possible requests. 813 * Conditions: 814 * Nothing locked. 815 * Port must be inactive. 816 * Reference held on port. 817 */ 818void 819ipc_port_dnnotify( 820 ipc_port_t port) 821{ 822 ipc_port_request_t requests = port->ip_requests; 823 824 assert(!ip_active(port)); 825 if (requests != IPR_NULL) { 826 ipc_table_size_t its = requests->ipr_size; 827 ipc_table_elems_t size = its->its_size; 828 ipc_port_request_index_t index; 829 for (index = 1; index < size; index++) { 830 ipc_port_request_t ipr = &requests[index]; 831 mach_port_name_t name = ipr->ipr_name; 832 ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright); 833 834 if (MACH_PORT_VALID(name) && IP_VALID(soright)) { 835 ipc_notify_dead_name(soright, name); 836 } 837 } 838 } 839} 840 841 842/* 843 * Routine: ipc_port_destroy 844 * Purpose: 845 * Destroys a port. Cleans up queued messages. 846 * 847 * If the port has a backup, it doesn't get destroyed, 848 * but is sent in a port-destroyed notification to the backup. 849 * Conditions: 850 * The port is locked and alive; nothing else locked. 851 * The caller has a reference, which is consumed. 852 * Afterwards, the port is unlocked and dead. 853 */ 854 855void 856ipc_port_destroy( 857 ipc_port_t port) 858{ 859 ipc_port_t pdrequest, nsrequest; 860 ipc_mqueue_t mqueue; 861 ipc_kmsg_t kmsg; 862 863#if IMPORTANCE_INHERITANCE 864 ipc_importance_task_t release_imp_task = IIT_NULL; 865 thread_t self = current_thread(); 866 boolean_t top = (self->ith_assertions == 0); 867 natural_t assertcnt = 0; 868#endif /* IMPORTANCE_INHERITANCE */ 869 870 assert(ip_active(port)); 871 /* port->ip_receiver_name is garbage */ 872 /* port->ip_receiver/port->ip_destination is garbage */ 873 assert(port->ip_pset_count == 0); 874 assert(port->ip_mscount == 0); 875 876 /* check for a backup port */ 877 pdrequest = port->ip_pdrequest; 878 879#if IMPORTANCE_INHERITANCE 880 /* determine how many assertions to drop and from whom */ 881 if (port->ip_tempowner != 0) { 882 assert(top); 883 release_imp_task = port->ip_imp_task; 884 if (IIT_NULL != release_imp_task) { 885 port->ip_imp_task = IIT_NULL; 886 assertcnt = port->ip_impcount; 887 } 888 /* Otherwise, nothing to drop */ 889 } else { 890 assertcnt = port->ip_impcount; 891 if (pdrequest != IP_NULL) 892 /* mark in limbo for the journey */ 893 port->ip_tempowner = 1; 894 } 895 896 if (top) 897 self->ith_assertions = assertcnt; 898#endif /* IMPORTANCE_INHERITANCE */ 899 900 if (pdrequest != IP_NULL) { 901 /* we assume the ref for pdrequest */ 902 port->ip_pdrequest = IP_NULL; 903 904 /* make port be in limbo */ 905 port->ip_receiver_name = MACH_PORT_NULL; 906 port->ip_destination = IP_NULL; 907 ip_unlock(port); 908 909 /* consumes our refs for port and pdrequest */ 910 ipc_notify_port_destroyed(pdrequest, port); 911 912 goto drop_assertions; 913 } 914 915 /* once port is dead, we don't need to keep it locked */ 916 917 port->ip_object.io_bits &= ~IO_BITS_ACTIVE; 918 port->ip_timestamp = ipc_port_timestamp(); 919 nsrequest = port->ip_nsrequest; 920 921 /* 922 * If the port has a preallocated message buffer and that buffer 923 * is not inuse, free it. If it has an inuse one, then the kmsg 924 * free will detect that we freed the association and it can free it 925 * like a normal buffer. 926 */ 927 if (IP_PREALLOC(port)) { 928 ipc_port_t inuse_port; 929 930 kmsg = port->ip_premsg; 931 assert(kmsg != IKM_NULL); 932 inuse_port = ikm_prealloc_inuse_port(kmsg); 933 IP_CLEAR_PREALLOC(port, kmsg); 934 ip_unlock(port); 935 if (inuse_port != IP_NULL) { 936 assert(inuse_port == port); 937 } else { 938 ipc_kmsg_free(kmsg); 939 } 940 } else { 941 ip_unlock(port); 942 } 943 944 /* throw away no-senders request */ 945 if (nsrequest != IP_NULL) 946 ipc_notify_send_once(nsrequest); /* consumes ref */ 947 948 /* destroy any queued messages */ 949 mqueue = &port->ip_messages; 950 ipc_mqueue_destroy(mqueue); 951 952 /* generate dead-name notifications */ 953 ipc_port_dnnotify(port); 954 955 ipc_kobject_destroy(port); 956 957 ip_release(port); /* consume caller's ref */ 958 959 drop_assertions: 960#if IMPORTANCE_INHERITANCE 961 if (release_imp_task != IIT_NULL) { 962 if (assertcnt > 0) { 963 assert(top); 964 self->ith_assertions = 0; 965 assert(ipc_importance_task_is_any_receiver_type(release_imp_task)); 966 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt); 967 } 968 ipc_importance_task_release(release_imp_task); 969 970 } else if (assertcnt > 0) { 971 if (top) { 972 self->ith_assertions = 0; 973 release_imp_task = current_task()->task_imp_base; 974 if (ipc_importance_task_is_any_receiver_type(release_imp_task)) { 975 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt); 976 } 977 } 978 } 979#endif /* IMPORTANCE_INHERITANCE */ 980} 981 982/* 983 * Routine: ipc_port_check_circularity 984 * Purpose: 985 * Check if queueing "port" in a message for "dest" 986 * would create a circular group of ports and messages. 987 * 988 * If no circularity (FALSE returned), then "port" 989 * is changed from "in limbo" to "in transit". 990 * 991 * That is, we want to set port->ip_destination == dest, 992 * but guaranteeing that this doesn't create a circle 993 * port->ip_destination->ip_destination->... == port 994 * 995 * Additionally, if port was successfully changed to "in transit", 996 * propagate boost assertions from the "in limbo" port to all 997 * the ports in the chain, and, if the destination task accepts 998 * boosts, to the destination task. 999 * 1000 * Conditions: 1001 * No ports locked. References held for "port" and "dest". 1002 */ 1003 1004boolean_t 1005ipc_port_check_circularity( 1006 ipc_port_t port, 1007 ipc_port_t dest) 1008{ 1009 ipc_port_t base; 1010 1011#if IMPORTANCE_INHERITANCE 1012 ipc_importance_task_t imp_task = IIT_NULL; 1013 ipc_importance_task_t release_imp_task = IIT_NULL; 1014 int assertcnt = 0; 1015#endif /* IMPORTANCE_INHERITANCE */ 1016 1017 assert(port != IP_NULL); 1018 assert(dest != IP_NULL); 1019 1020 if (port == dest) 1021 return TRUE; 1022 base = dest; 1023 1024 /* 1025 * First try a quick check that can run in parallel. 1026 * No circularity if dest is not in transit. 1027 */ 1028 1029 ip_lock(port); 1030 if (ip_lock_try(dest)) { 1031 if (!ip_active(dest) || 1032 (dest->ip_receiver_name != MACH_PORT_NULL) || 1033 (dest->ip_destination == IP_NULL)) 1034 goto not_circular; 1035 1036 /* dest is in transit; further checking necessary */ 1037 1038 ip_unlock(dest); 1039 } 1040 ip_unlock(port); 1041 1042 ipc_port_multiple_lock(); /* massive serialization */ 1043 1044 /* 1045 * Search for the end of the chain (a port not in transit), 1046 * acquiring locks along the way. 1047 */ 1048 1049 for (;;) { 1050 ip_lock(base); 1051 1052 if (!ip_active(base) || 1053 (base->ip_receiver_name != MACH_PORT_NULL) || 1054 (base->ip_destination == IP_NULL)) 1055 break; 1056 1057 base = base->ip_destination; 1058 } 1059 1060 /* all ports in chain from dest to base, inclusive, are locked */ 1061 1062 if (port == base) { 1063 /* circularity detected! */ 1064 1065 ipc_port_multiple_unlock(); 1066 1067 /* port (== base) is in limbo */ 1068 1069 assert(ip_active(port)); 1070 assert(port->ip_receiver_name == MACH_PORT_NULL); 1071 assert(port->ip_destination == IP_NULL); 1072 1073 while (dest != IP_NULL) { 1074 ipc_port_t next; 1075 1076 /* dest is in transit or in limbo */ 1077 1078 assert(ip_active(dest)); 1079 assert(dest->ip_receiver_name == MACH_PORT_NULL); 1080 1081 next = dest->ip_destination; 1082 ip_unlock(dest); 1083 dest = next; 1084 } 1085 1086 return TRUE; 1087 } 1088 1089 /* 1090 * The guarantee: lock port while the entire chain is locked. 1091 * Once port is locked, we can take a reference to dest, 1092 * add port to the chain, and unlock everything. 1093 */ 1094 1095 ip_lock(port); 1096 ipc_port_multiple_unlock(); 1097 1098 not_circular: 1099 1100 /* port is in limbo */ 1101 1102 assert(ip_active(port)); 1103 assert(port->ip_receiver_name == MACH_PORT_NULL); 1104 assert(port->ip_destination == IP_NULL); 1105 1106 ip_reference(dest); 1107 port->ip_destination = dest; 1108 1109#if IMPORTANCE_INHERITANCE 1110 /* must have been in limbo or still bound to a task */ 1111 assert(port->ip_tempowner != 0); 1112 1113 /* 1114 * We delayed dropping assertions from a specific task. 1115 * Cache that info now (we'll drop assertions and the 1116 * task reference below). 1117 */ 1118 release_imp_task = port->ip_imp_task; 1119 if (IIT_NULL != release_imp_task) { 1120 port->ip_imp_task = IIT_NULL; 1121 } 1122 assertcnt = port->ip_impcount; 1123 1124 /* take the port out of limbo w.r.t. assertions */ 1125 port->ip_tempowner = 0; 1126 1127#endif /* IMPORTANCE_INHERITANCE */ 1128 1129 /* now unlock chain */ 1130 1131 ip_unlock(port); 1132 1133 for (;;) { 1134 1135#if IMPORTANCE_INHERITANCE 1136 /* every port along chain track assertions behind it */ 1137 dest->ip_impcount += assertcnt; 1138#endif /* IMPORTANCE_INHERITANCE */ 1139 1140 if (dest == base) 1141 break; 1142 1143 /* port is in transit */ 1144 1145 assert(ip_active(dest)); 1146 assert(dest->ip_receiver_name == MACH_PORT_NULL); 1147 assert(dest->ip_destination != IP_NULL); 1148 1149#if IMPORTANCE_INHERITANCE 1150 assert(dest->ip_tempowner == 0); 1151#endif /* IMPORTANCE_INHERITANCE */ 1152 1153 port = dest->ip_destination; 1154 ip_unlock(dest); 1155 dest = port; 1156 } 1157 1158 /* base is not in transit */ 1159 assert(!ip_active(base) || 1160 (base->ip_receiver_name != MACH_PORT_NULL) || 1161 (base->ip_destination == IP_NULL)); 1162 1163#if IMPORTANCE_INHERITANCE 1164 /* 1165 * Find the task to boost (if any). 1166 * We will boost "through" ports that don't know 1167 * about inheritance to deliver receive rights that 1168 * do. 1169 */ 1170 if (ip_active(base) && (assertcnt > 0)) { 1171 if (base->ip_tempowner != 0) { 1172 if (IIT_NULL != base->ip_imp_task) { 1173 /* specified tempowner task */ 1174 imp_task = base->ip_imp_task; 1175 assert(ipc_importance_task_is_any_receiver_type(imp_task)); 1176 } 1177 /* otherwise don't boost current task */ 1178 1179 } else if (base->ip_receiver_name != MACH_PORT_NULL) { 1180 ipc_space_t space = base->ip_receiver; 1181 1182 /* only spaces with boost-accepting tasks */ 1183 if (space->is_task != TASK_NULL && 1184 ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base)) 1185 imp_task = space->is_task->task_imp_base; 1186 } 1187 1188 /* take reference before unlocking base */ 1189 if (imp_task != IIT_NULL) { 1190 ipc_importance_task_reference(imp_task); 1191 } 1192 } 1193#endif /* IMPORTANCE_INHERITANCE */ 1194 1195 ip_unlock(base); 1196 1197#if IMPORTANCE_INHERITANCE 1198 /* 1199 * Transfer assertions now that the ports are unlocked. 1200 * Avoid extra overhead if transferring to/from the same task. 1201 */ 1202 boolean_t transfer_assertions = (imp_task != release_imp_task) ? TRUE : FALSE; 1203 1204 if (imp_task != IIT_NULL) { 1205 if (transfer_assertions) 1206 ipc_importance_task_hold_internal_assertion(imp_task, assertcnt); 1207 ipc_importance_task_release(imp_task); 1208 imp_task = IIT_NULL; 1209 } 1210 1211 if (release_imp_task != IIT_NULL) { 1212 if (transfer_assertions) 1213 ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt); 1214 ipc_importance_task_release(release_imp_task); 1215 release_imp_task = IIT_NULL; 1216 } 1217#endif /* IMPORTANCE_INHERITANCE */ 1218 1219 return FALSE; 1220} 1221 1222/* 1223 * Routine: ipc_port_impcount_delta 1224 * Purpose: 1225 * Adjust only the importance count associated with a port. 1226 * If there are any adjustments to be made to receiver task, 1227 * those are handled elsewhere. 1228 * 1229 * For now, be defensive during deductions to make sure the 1230 * impcount for the port doesn't underflow zero. This will 1231 * go away when the port boost addition is made atomic (see 1232 * note in ipc_port_importance_delta()). 1233 * Conditions: 1234 * The port is referenced and locked. 1235 * Nothing else is locked. 1236 */ 1237mach_port_delta_t 1238ipc_port_impcount_delta( 1239 ipc_port_t port, 1240 mach_port_delta_t delta, 1241 ipc_port_t __unused base) 1242{ 1243 mach_port_delta_t absdelta; 1244 1245 if (!ip_active(port)) { 1246 return 0; 1247 } 1248 1249 /* adding/doing nothing is easy */ 1250 if (delta >= 0) { 1251 port->ip_impcount += delta; 1252 return delta; 1253 } 1254 1255 absdelta = 0 - delta; 1256 //assert(port->ip_impcount >= absdelta); 1257 /* if we have enough to deduct, we're done */ 1258 if (port->ip_impcount >= absdelta) { 1259 port->ip_impcount -= absdelta; 1260 return delta; 1261 } 1262 1263#if DEVELOPMENT || DEBUG 1264 if (port->ip_receiver_name != MACH_PORT_NULL) { 1265 task_t target_task = port->ip_receiver->is_task; 1266 ipc_importance_task_t target_imp = target_task->task_imp_base; 1267 const char *target_procname; 1268 int target_pid; 1269 1270 if (target_imp != IIT_NULL) { 1271 target_procname = target_imp->iit_procname; 1272 target_pid = target_imp->iit_bsd_pid; 1273 } else { 1274 target_procname = "unknown"; 1275 target_pid = -1; 1276 } 1277 printf("Over-release of importance assertions for port 0x%x receiver pid %d (%s), " 1278 "dropping %d assertion(s) but port only has %d remaining.\n", 1279 port->ip_receiver_name, 1280 target_imp->iit_bsd_pid, target_imp->iit_procname, 1281 absdelta, port->ip_impcount); 1282 1283 } else if (base != IP_NULL) { 1284 task_t target_task = base->ip_receiver->is_task; 1285 ipc_importance_task_t target_imp = target_task->task_imp_base; 1286 const char *target_procname; 1287 int target_pid; 1288 1289 if (target_imp != IIT_NULL) { 1290 target_procname = target_imp->iit_procname; 1291 target_pid = target_imp->iit_bsd_pid; 1292 } else { 1293 target_procname = "unknown"; 1294 target_pid = -1; 1295 } 1296 printf("Over-release of importance assertions for port %p " 1297 "enqueued on port 0x%x with receiver pid %d (%s), " 1298 "dropping %d assertion(s) but port only has %d remaining.\n", 1299 port, base->ip_receiver_name, 1300 target_imp->iit_bsd_pid, target_imp->iit_procname, 1301 absdelta, port->ip_impcount); 1302 } 1303#endif 1304 delta = 0 - port->ip_impcount; 1305 port->ip_impcount = 0; 1306 return delta; 1307} 1308 1309/* 1310 * Routine: ipc_port_importance_delta_internal 1311 * Purpose: 1312 * Adjust the importance count through the given port. 1313 * If the port is in transit, apply the delta throughout 1314 * the chain. Determine if the there is a task at the 1315 * base of the chain that wants/needs to be adjusted, 1316 * and if so, apply the delta. 1317 * Conditions: 1318 * The port is referenced and locked on entry. 1319 * Nothing else is locked. 1320 * The lock may be dropped on exit. 1321 * Returns TRUE if lock was dropped. 1322 */ 1323#if IMPORTANCE_INHERITANCE 1324 1325boolean_t 1326ipc_port_importance_delta_internal( 1327 ipc_port_t port, 1328 mach_port_delta_t *deltap, 1329 ipc_importance_task_t *imp_task) 1330{ 1331 ipc_port_t next, base; 1332 boolean_t dropped = FALSE; 1333 1334 *imp_task = IIT_NULL; 1335 1336 if (*deltap == 0) 1337 return FALSE; 1338 1339 base = port; 1340 1341 /* if port is in transit, have to search for end of chain */ 1342 if (ip_active(port) && 1343 port->ip_destination != IP_NULL && 1344 port->ip_receiver_name == MACH_PORT_NULL) { 1345 1346 dropped = TRUE; 1347 1348 ip_unlock(port); 1349 ipc_port_multiple_lock(); /* massive serialization */ 1350 ip_lock(base); 1351 1352 while(ip_active(base) && 1353 base->ip_destination != IP_NULL && 1354 base->ip_receiver_name == MACH_PORT_NULL) { 1355 1356 base = base->ip_destination; 1357 ip_lock(base); 1358 } 1359 ipc_port_multiple_unlock(); 1360 } 1361 1362 /* unlock down to the base, adding a boost at each level */ 1363 for (;;) { 1364 /* 1365 * JMM TODO - because of the port unlock to grab the multiple lock 1366 * above, a subsequent drop of importance could race and beat 1367 * the "previous" increase - causing the port impcount to go 1368 * negative briefly. The defensive deduction performed by 1369 * ipc_port_impcount_delta() defeats that, and therefore can 1370 * cause an importance leak once the increase finally arrives. 1371 * 1372 * Need to rework the importance delta logic to be more like 1373 * ipc_importance_inherit_from() where it locks all it needs in 1374 * one pass to avoid any lock drops - to keep that race from 1375 * ever occuring. 1376 */ 1377 *deltap = ipc_port_impcount_delta(port, *deltap, base); 1378 1379 if (port == base) { 1380 break; 1381 } 1382 1383 /* port is in transit */ 1384 assert(port->ip_tempowner == 0); 1385 next = port->ip_destination; 1386 ip_unlock(port); 1387 port = next; 1388 } 1389 1390 /* find the task (if any) to boost according to the base */ 1391 if (ip_active(base)) { 1392 if (base->ip_tempowner != 0) { 1393 if (IIT_NULL != base->ip_imp_task) 1394 *imp_task = base->ip_imp_task; 1395 /* otherwise don't boost */ 1396 1397 } else if (base->ip_receiver_name != MACH_PORT_NULL) { 1398 ipc_space_t space = base->ip_receiver; 1399 1400 /* only spaces with boost-accepting tasks */ 1401 if (space->is_task != TASK_NULL && 1402 ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base)) { 1403 *imp_task = space->is_task->task_imp_base; 1404 } 1405 } 1406 } 1407 1408 /* 1409 * Only the base is locked. If we have to hold or drop task 1410 * importance assertions, we'll have to drop that lock as well. 1411 */ 1412 if (*imp_task != IIT_NULL) { 1413 /* take a reference before unlocking base */ 1414 ipc_importance_task_reference(*imp_task); 1415 } 1416 1417 if (dropped == TRUE) { 1418 ip_unlock(base); 1419 } 1420 1421 return dropped; 1422} 1423#endif /* IMPORTANCE_INHERITANCE */ 1424 1425/* 1426 * Routine: ipc_port_importance_delta 1427 * Purpose: 1428 * Adjust the importance count through the given port. 1429 * If the port is in transit, apply the delta throughout 1430 * the chain. 1431 * 1432 * If there is a task at the base of the chain that wants/needs 1433 * to be adjusted, apply the delta. 1434 * Conditions: 1435 * The port is referenced and locked on entry. 1436 * Nothing else is locked. 1437 * The lock may be dropped on exit. 1438 * Returns TRUE if lock was dropped. 1439 */ 1440#if IMPORTANCE_INHERITANCE 1441 1442boolean_t 1443ipc_port_importance_delta( 1444 ipc_port_t port, 1445 mach_port_delta_t delta) 1446{ 1447 ipc_importance_task_t imp_task = IIT_NULL; 1448 boolean_t dropped; 1449 1450 dropped = ipc_port_importance_delta_internal(port, &delta, &imp_task); 1451 1452 if (IIT_NULL == imp_task) 1453 return dropped; 1454 1455 if (!dropped) { 1456 dropped = TRUE; 1457 ip_unlock(port); 1458 } 1459 1460 assert(ipc_importance_task_is_any_receiver_type(imp_task)); 1461 1462 if (delta > 0) 1463 ipc_importance_task_hold_internal_assertion(imp_task, delta); 1464 else 1465 ipc_importance_task_drop_internal_assertion(imp_task, -delta); 1466 1467 ipc_importance_task_release(imp_task); 1468 return dropped; 1469} 1470#endif /* IMPORTANCE_INHERITANCE */ 1471 1472/* 1473 * Routine: ipc_port_lookup_notify 1474 * Purpose: 1475 * Make a send-once notify port from a receive right. 1476 * Returns IP_NULL if name doesn't denote a receive right. 1477 * Conditions: 1478 * The space must be locked (read or write) and active. 1479 * Being the active space, we can rely on thread server_id 1480 * context to give us the proper server level sub-order 1481 * within the space. 1482 */ 1483 1484ipc_port_t 1485ipc_port_lookup_notify( 1486 ipc_space_t space, 1487 mach_port_name_t name) 1488{ 1489 ipc_port_t port; 1490 ipc_entry_t entry; 1491 1492 assert(is_active(space)); 1493 1494 entry = ipc_entry_lookup(space, name); 1495 if (entry == IE_NULL) 1496 return IP_NULL; 1497 if ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0) 1498 return IP_NULL; 1499 1500 port = (ipc_port_t) entry->ie_object; 1501 assert(port != IP_NULL); 1502 1503 ip_lock(port); 1504 assert(ip_active(port)); 1505 assert(port->ip_receiver_name == name); 1506 assert(port->ip_receiver == space); 1507 1508 ip_reference(port); 1509 port->ip_sorights++; 1510 ip_unlock(port); 1511 1512 return port; 1513} 1514 1515/* 1516 * Routine: ipc_port_make_send_locked 1517 * Purpose: 1518 * Make a naked send right from a receive right. 1519 * 1520 * Conditions: 1521 * port locked and active. 1522 */ 1523ipc_port_t 1524ipc_port_make_send_locked( 1525 ipc_port_t port) 1526{ 1527 assert(ip_active(port)); 1528 port->ip_mscount++; 1529 port->ip_srights++; 1530 ip_reference(port); 1531 return port; 1532} 1533 1534/* 1535 * Routine: ipc_port_make_send 1536 * Purpose: 1537 * Make a naked send right from a receive right. 1538 */ 1539 1540ipc_port_t 1541ipc_port_make_send( 1542 ipc_port_t port) 1543{ 1544 1545 if (!IP_VALID(port)) 1546 return port; 1547 1548 ip_lock(port); 1549 if (ip_active(port)) { 1550 port->ip_mscount++; 1551 port->ip_srights++; 1552 ip_reference(port); 1553 ip_unlock(port); 1554 return port; 1555 } 1556 ip_unlock(port); 1557 return IP_DEAD; 1558} 1559 1560/* 1561 * Routine: ipc_port_copy_send 1562 * Purpose: 1563 * Make a naked send right from another naked send right. 1564 * IP_NULL -> IP_NULL 1565 * IP_DEAD -> IP_DEAD 1566 * dead port -> IP_DEAD 1567 * live port -> port + ref 1568 * Conditions: 1569 * Nothing locked except possibly a space. 1570 */ 1571 1572ipc_port_t 1573ipc_port_copy_send( 1574 ipc_port_t port) 1575{ 1576 ipc_port_t sright; 1577 1578 if (!IP_VALID(port)) 1579 return port; 1580 1581 ip_lock(port); 1582 if (ip_active(port)) { 1583 assert(port->ip_srights > 0); 1584 1585 ip_reference(port); 1586 port->ip_srights++; 1587 sright = port; 1588 } else 1589 sright = IP_DEAD; 1590 ip_unlock(port); 1591 1592 return sright; 1593} 1594 1595/* 1596 * Routine: ipc_port_copyout_send 1597 * Purpose: 1598 * Copyout a naked send right (possibly null/dead), 1599 * or if that fails, destroy the right. 1600 * Conditions: 1601 * Nothing locked. 1602 */ 1603 1604mach_port_name_t 1605ipc_port_copyout_send( 1606 ipc_port_t sright, 1607 ipc_space_t space) 1608{ 1609 mach_port_name_t name; 1610 1611 if (IP_VALID(sright)) { 1612 kern_return_t kr; 1613 1614 kr = ipc_object_copyout(space, (ipc_object_t) sright, 1615 MACH_MSG_TYPE_PORT_SEND, TRUE, &name); 1616 if (kr != KERN_SUCCESS) { 1617 ipc_port_release_send(sright); 1618 1619 if (kr == KERN_INVALID_CAPABILITY) 1620 name = MACH_PORT_DEAD; 1621 else 1622 name = MACH_PORT_NULL; 1623 } 1624 } else 1625 name = CAST_MACH_PORT_TO_NAME(sright); 1626 1627 return name; 1628} 1629 1630/* 1631 * Routine: ipc_port_release_send 1632 * Purpose: 1633 * Release a naked send right. 1634 * Consumes a ref for the port. 1635 * Conditions: 1636 * Nothing locked. 1637 */ 1638 1639void 1640ipc_port_release_send( 1641 ipc_port_t port) 1642{ 1643 ipc_port_t nsrequest = IP_NULL; 1644 mach_port_mscount_t mscount; 1645 1646 if (!IP_VALID(port)) 1647 return; 1648 1649 ip_lock(port); 1650 1651 assert(port->ip_srights > 0); 1652 port->ip_srights--; 1653 1654 if (!ip_active(port)) { 1655 ip_unlock(port); 1656 ip_release(port); 1657 return; 1658 } 1659 1660 if (port->ip_srights == 0 && 1661 port->ip_nsrequest != IP_NULL) { 1662 nsrequest = port->ip_nsrequest; 1663 port->ip_nsrequest = IP_NULL; 1664 mscount = port->ip_mscount; 1665 ip_unlock(port); 1666 ip_release(port); 1667 ipc_notify_no_senders(nsrequest, mscount); 1668 } else { 1669 ip_unlock(port); 1670 ip_release(port); 1671 } 1672} 1673 1674/* 1675 * Routine: ipc_port_make_sonce_locked 1676 * Purpose: 1677 * Make a naked send-once right from a receive right. 1678 * Conditions: 1679 * The port is locked and active. 1680 */ 1681 1682ipc_port_t 1683ipc_port_make_sonce_locked( 1684 ipc_port_t port) 1685{ 1686 assert(ip_active(port)); 1687 port->ip_sorights++; 1688 ip_reference(port); 1689 return port; 1690} 1691 1692/* 1693 * Routine: ipc_port_make_sonce 1694 * Purpose: 1695 * Make a naked send-once right from a receive right. 1696 * Conditions: 1697 * The port is not locked. 1698 */ 1699 1700ipc_port_t 1701ipc_port_make_sonce( 1702 ipc_port_t port) 1703{ 1704 if (!IP_VALID(port)) 1705 return port; 1706 1707 ip_lock(port); 1708 if (ip_active(port)) { 1709 port->ip_sorights++; 1710 ip_reference(port); 1711 ip_unlock(port); 1712 return port; 1713 } 1714 ip_unlock(port); 1715 return IP_DEAD; 1716} 1717 1718/* 1719 * Routine: ipc_port_release_sonce 1720 * Purpose: 1721 * Release a naked send-once right. 1722 * Consumes a ref for the port. 1723 * 1724 * In normal situations, this is never used. 1725 * Send-once rights are only consumed when 1726 * a message (possibly a send-once notification) 1727 * is sent to them. 1728 * Conditions: 1729 * Nothing locked except possibly a space. 1730 */ 1731 1732void 1733ipc_port_release_sonce( 1734 ipc_port_t port) 1735{ 1736 if (!IP_VALID(port)) 1737 return; 1738 1739 ip_lock(port); 1740 1741 assert(port->ip_sorights > 0); 1742 1743 port->ip_sorights--; 1744 1745 ip_unlock(port); 1746 ip_release(port); 1747} 1748 1749/* 1750 * Routine: ipc_port_release_receive 1751 * Purpose: 1752 * Release a naked (in limbo or in transit) receive right. 1753 * Consumes a ref for the port; destroys the port. 1754 * Conditions: 1755 * Nothing locked. 1756 */ 1757 1758void 1759ipc_port_release_receive( 1760 ipc_port_t port) 1761{ 1762 ipc_port_t dest; 1763 1764 if (!IP_VALID(port)) 1765 return; 1766 1767 ip_lock(port); 1768 assert(ip_active(port)); 1769 assert(port->ip_receiver_name == MACH_PORT_NULL); 1770 dest = port->ip_destination; 1771 1772 ipc_port_destroy(port); /* consumes ref, unlocks */ 1773 1774 if (dest != IP_NULL) 1775 ip_release(dest); 1776} 1777 1778/* 1779 * Routine: ipc_port_alloc_special 1780 * Purpose: 1781 * Allocate a port in a special space. 1782 * The new port is returned with one ref. 1783 * If unsuccessful, IP_NULL is returned. 1784 * Conditions: 1785 * Nothing locked. 1786 */ 1787 1788ipc_port_t 1789ipc_port_alloc_special( 1790 ipc_space_t space) 1791{ 1792 ipc_port_t port; 1793 1794 port = (ipc_port_t) io_alloc(IOT_PORT); 1795 if (port == IP_NULL) 1796 return IP_NULL; 1797 1798#if MACH_ASSERT 1799 uintptr_t buf[IP_CALLSTACK_MAX]; 1800 ipc_port_callstack_init_debug(&buf[0], IP_CALLSTACK_MAX); 1801#endif /* MACH_ASSERT */ 1802 1803 bzero((char *)port, sizeof(*port)); 1804 io_lock_init(&port->ip_object); 1805 port->ip_references = 1; 1806 port->ip_object.io_bits = io_makebits(TRUE, IOT_PORT, 0); 1807 1808 ipc_port_init(port, space, 1); 1809 1810#if MACH_ASSERT 1811 ipc_port_init_debug(port, &buf[0], IP_CALLSTACK_MAX); 1812#endif /* MACH_ASSERT */ 1813 1814 return port; 1815} 1816 1817/* 1818 * Routine: ipc_port_dealloc_special 1819 * Purpose: 1820 * Deallocate a port in a special space. 1821 * Consumes one ref for the port. 1822 * Conditions: 1823 * Nothing locked. 1824 */ 1825 1826void 1827ipc_port_dealloc_special( 1828 ipc_port_t port, 1829 __assert_only ipc_space_t space) 1830{ 1831 ip_lock(port); 1832 assert(ip_active(port)); 1833// assert(port->ip_receiver_name != MACH_PORT_NULL); 1834 assert(port->ip_receiver == space); 1835 1836 /* 1837 * We clear ip_receiver_name and ip_receiver to simplify 1838 * the ipc_space_kernel check in ipc_mqueue_send. 1839 */ 1840 1841 port->ip_receiver_name = MACH_PORT_NULL; 1842 port->ip_receiver = IS_NULL; 1843 1844 /* relevant part of ipc_port_clear_receiver */ 1845 ipc_port_set_mscount(port, 0); 1846 port->ip_messages.imq_seqno = 0; 1847 1848 ipc_port_destroy(port); 1849} 1850 1851/* 1852 * Routine: ipc_port_finalize 1853 * Purpose: 1854 * Called on last reference deallocate to 1855 * free any remaining data associated with the 1856 * port. 1857 * Conditions: 1858 * Nothing locked. 1859 */ 1860void 1861ipc_port_finalize( 1862 ipc_port_t port) 1863{ 1864 ipc_port_request_t requests = port->ip_requests; 1865 1866 assert(!ip_active(port)); 1867 if (requests != IPR_NULL) { 1868 ipc_table_size_t its = requests->ipr_size; 1869 it_requests_free(its, requests); 1870 port->ip_requests = IPR_NULL; 1871 } 1872 1873#if MACH_ASSERT 1874 ipc_port_track_dealloc(port); 1875#endif /* MACH_ASSERT */ 1876} 1877 1878#if MACH_ASSERT 1879#include <kern/machine.h> 1880 1881/* 1882 * Keep a list of all allocated ports. 1883 * Allocation is intercepted via ipc_port_init; 1884 * deallocation is intercepted via io_free. 1885 */ 1886queue_head_t port_alloc_queue; 1887lck_spin_t port_alloc_queue_lock; 1888 1889unsigned long port_count = 0; 1890unsigned long port_count_warning = 20000; 1891unsigned long port_timestamp = 0; 1892 1893void db_port_stack_trace( 1894 ipc_port_t port); 1895void db_ref( 1896 int refs); 1897int db_port_walk( 1898 unsigned int verbose, 1899 unsigned int display, 1900 unsigned int ref_search, 1901 unsigned int ref_target); 1902 1903/* 1904 * Initialize global state needed for run-time 1905 * port debugging. 1906 */ 1907void 1908ipc_port_debug_init(void) 1909{ 1910 queue_init(&port_alloc_queue); 1911 1912 lck_spin_init(&port_alloc_queue_lock, &ipc_lck_grp, &ipc_lck_attr); 1913 1914 if (!PE_parse_boot_argn("ipc_portbt", &ipc_portbt, sizeof (ipc_portbt))) 1915 ipc_portbt = 0; 1916} 1917 1918#ifdef MACH_BSD 1919extern int proc_pid(struct proc*); 1920#endif /* MACH_BSD */ 1921 1922/* 1923 * Initialize all of the debugging state in a port. 1924 * Insert the port into a global list of all allocated ports. 1925 */ 1926void 1927ipc_port_init_debug( 1928 ipc_port_t port, 1929 uintptr_t *callstack, 1930 unsigned int callstack_max) 1931{ 1932 unsigned int i; 1933 1934 port->ip_thread = current_thread(); 1935 port->ip_timetrack = port_timestamp++; 1936 for (i = 0; i < callstack_max; ++i) 1937 port->ip_callstack[i] = callstack[i]; 1938 for (i = 0; i < IP_NSPARES; ++i) 1939 port->ip_spares[i] = 0; 1940 1941#ifdef MACH_BSD 1942 task_t task = current_task(); 1943 if (task != TASK_NULL) { 1944 struct proc* proc = (struct proc*) get_bsdtask_info(task); 1945 if (proc) 1946 port->ip_spares[0] = proc_pid(proc); 1947 } 1948#endif /* MACH_BSD */ 1949 1950#if 0 1951 lck_spin_lock(&port_alloc_queue_lock); 1952 ++port_count; 1953 if (port_count_warning > 0 && port_count >= port_count_warning) 1954 assert(port_count < port_count_warning); 1955 queue_enter(&port_alloc_queue, port, ipc_port_t, ip_port_links); 1956 lck_spin_unlock(&port_alloc_queue_lock); 1957#endif 1958} 1959 1960/* 1961 * Routine: ipc_port_callstack_init_debug 1962 * Purpose: 1963 * Calls the machine-dependent routine to 1964 * fill in an array with up to IP_CALLSTACK_MAX 1965 * levels of return pc information 1966 * Conditions: 1967 * May block (via copyin) 1968 */ 1969void 1970ipc_port_callstack_init_debug( 1971 uintptr_t *callstack, 1972 unsigned int callstack_max) 1973{ 1974 unsigned int i; 1975 1976 /* guarantee the callstack is initialized */ 1977 for (i=0; i < callstack_max; i++) 1978 callstack[i] = 0; 1979 1980 if (ipc_portbt) 1981 machine_callstack(callstack, callstack_max); 1982} 1983 1984/* 1985 * Remove a port from the queue of allocated ports. 1986 * This routine should be invoked JUST prior to 1987 * deallocating the actual memory occupied by the port. 1988 */ 1989#if 1 1990void 1991ipc_port_track_dealloc( 1992 __unused ipc_port_t port) 1993{ 1994} 1995#else 1996void 1997ipc_port_track_dealloc( 1998 ipc_port_t port) 1999{ 2000 lck_spin_lock(&port_alloc_queue_lock); 2001 assert(port_count > 0); 2002 --port_count; 2003 queue_remove(&port_alloc_queue, port, ipc_port_t, ip_port_links); 2004 lck_spin_unlock(&port_alloc_queue_lock); 2005} 2006#endif 2007 2008 2009#endif /* MACH_ASSERT */ 2010