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 * Copyright (c) 2005-2006 SPARTA, Inc. 62 */ 63/* 64 */ 65/* 66 * File: ipc/ipc_right.c 67 * Author: Rich Draves 68 * Date: 1989 69 * 70 * Functions to manipulate IPC capabilities. 71 */ 72 73#include <mach/boolean.h> 74#include <mach/kern_return.h> 75#include <mach/port.h> 76#include <mach/message.h> 77#include <kern/assert.h> 78#include <kern/misc_protos.h> 79#include <ipc/port.h> 80#include <ipc/ipc_entry.h> 81#include <ipc/ipc_space.h> 82#include <ipc/ipc_object.h> 83#include <ipc/ipc_hash.h> 84#include <ipc/ipc_port.h> 85#include <ipc/ipc_pset.h> 86#include <ipc/ipc_right.h> 87#include <ipc/ipc_notify.h> 88#include <ipc/ipc_table.h> 89#include <security/mac_mach_internal.h> 90 91/* Allow IPC to generate mach port guard exceptions */ 92extern kern_return_t 93mach_port_guard_exception( 94 mach_port_name_t name, 95 uint64_t inguard, 96 uint64_t portguard, 97 unsigned reason); 98/* 99 * Routine: ipc_right_lookup_write 100 * Purpose: 101 * Finds an entry in a space, given the name. 102 * Conditions: 103 * Nothing locked. If successful, the space is write-locked. 104 * Returns: 105 * KERN_SUCCESS Found an entry. 106 * KERN_INVALID_TASK The space is dead. 107 * KERN_INVALID_NAME Name doesn't exist in space. 108 */ 109 110kern_return_t 111ipc_right_lookup_write( 112 ipc_space_t space, 113 mach_port_name_t name, 114 ipc_entry_t *entryp) 115{ 116 ipc_entry_t entry; 117 118 assert(space != IS_NULL); 119 120 is_write_lock(space); 121 122 if (!is_active(space)) { 123 is_write_unlock(space); 124 return KERN_INVALID_TASK; 125 } 126 127 if ((entry = ipc_entry_lookup(space, name)) == IE_NULL) { 128 is_write_unlock(space); 129 return KERN_INVALID_NAME; 130 } 131 132 *entryp = entry; 133 return KERN_SUCCESS; 134} 135 136/* 137 * Routine: ipc_right_lookup_two_write 138 * Purpose: 139 * Like ipc_right_lookup except that it returns two 140 * entries for two different names that were looked 141 * up under the same space lock. 142 * Conditions: 143 * Nothing locked. If successful, the space is write-locked. 144 * Returns: 145 * KERN_INVALID_TASK The space is dead. 146 * KERN_INVALID_NAME Name doesn't exist in space. 147 */ 148 149kern_return_t 150ipc_right_lookup_two_write( 151 ipc_space_t space, 152 mach_port_name_t name1, 153 ipc_entry_t *entryp1, 154 mach_port_name_t name2, 155 ipc_entry_t *entryp2) 156{ 157 ipc_entry_t entry1; 158 ipc_entry_t entry2; 159 160 assert(space != IS_NULL); 161 162 is_write_lock(space); 163 164 if (!is_active(space)) { 165 is_write_unlock(space); 166 return KERN_INVALID_TASK; 167 } 168 169 if ((entry1 = ipc_entry_lookup(space, name1)) == IE_NULL) { 170 is_write_unlock(space); 171 return KERN_INVALID_NAME; 172 } 173 if ((entry2 = ipc_entry_lookup(space, name2)) == IE_NULL) { 174 is_write_unlock(space); 175 return KERN_INVALID_NAME; 176 } 177 *entryp1 = entry1; 178 *entryp2 = entry2; 179 return KERN_SUCCESS; 180} 181 182/* 183 * Routine: ipc_right_reverse 184 * Purpose: 185 * Translate (space, object) -> (name, entry). 186 * Only finds send/receive rights. 187 * Returns TRUE if an entry is found; if so, 188 * the object is locked and active. 189 * Conditions: 190 * The space must be locked (read or write) and active. 191 * Nothing else locked. 192 */ 193 194boolean_t 195ipc_right_reverse( 196 ipc_space_t space, 197 ipc_object_t object, 198 mach_port_name_t *namep, 199 ipc_entry_t *entryp) 200{ 201 ipc_port_t port; 202 mach_port_name_t name; 203 ipc_entry_t entry; 204 205 /* would switch on io_otype to handle multiple types of object */ 206 207 assert(is_active(space)); 208 assert(io_otype(object) == IOT_PORT); 209 210 port = (ipc_port_t) object; 211 212 ip_lock(port); 213 if (!ip_active(port)) { 214 ip_unlock(port); 215 216 return FALSE; 217 } 218 219 if (port->ip_receiver == space) { 220 name = port->ip_receiver_name; 221 assert(name != MACH_PORT_NULL); 222 223 entry = ipc_entry_lookup(space, name); 224 225 assert(entry != IE_NULL); 226 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); 227 assert(port == (ipc_port_t) entry->ie_object); 228 229 *namep = name; 230 *entryp = entry; 231 return TRUE; 232 } 233 234 if (ipc_hash_lookup(space, (ipc_object_t) port, namep, entryp)) { 235 assert((entry = *entryp) != IE_NULL); 236 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_SEND); 237 assert(port == (ipc_port_t) entry->ie_object); 238 239 return TRUE; 240 } 241 242 ip_unlock(port); 243 return FALSE; 244} 245 246/* 247 * Routine: ipc_right_dnrequest 248 * Purpose: 249 * Make a dead-name request, returning the previously 250 * registered send-once right. If notify is IP_NULL, 251 * just cancels the previously registered request. 252 * 253 * Conditions: 254 * Nothing locked. May allocate memory. 255 * Only consumes/returns refs if successful. 256 * Returns: 257 * KERN_SUCCESS Made/canceled dead-name request. 258 * KERN_INVALID_TASK The space is dead. 259 * KERN_INVALID_NAME Name doesn't exist in space. 260 * KERN_INVALID_RIGHT Name doesn't denote port/dead rights. 261 * KERN_INVALID_ARGUMENT Name denotes dead name, but 262 * immediate is FALSE or notify is IP_NULL. 263 * KERN_UREFS_OVERFLOW Name denotes dead name, but 264 * generating immediate notif. would overflow urefs. 265 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 266 */ 267 268kern_return_t 269ipc_right_request_alloc( 270 ipc_space_t space, 271 mach_port_name_t name, 272 boolean_t immediate, 273 boolean_t send_possible, 274 ipc_port_t notify, 275 ipc_port_t *previousp) 276{ 277 ipc_port_request_index_t prev_request; 278 ipc_port_t previous = IP_NULL; 279 ipc_entry_t entry; 280 kern_return_t kr; 281 282#if IMPORTANCE_INHERITANCE 283 boolean_t needboost = FALSE; 284#endif /* IMPORTANCE_INHERITANCE */ 285 286 for (;;) { 287 ipc_port_t port = IP_NULL; 288 289 kr = ipc_right_lookup_write(space, name, &entry); 290 if (kr != KERN_SUCCESS) 291 return kr; 292 293 /* space is write-locked and active */ 294 295 prev_request = entry->ie_request; 296 297 /* if nothing to do or undo, we're done */ 298 if (notify == IP_NULL && prev_request == IE_REQ_NONE) { 299 is_write_unlock(space); 300 *previousp = IP_NULL; 301 return KERN_SUCCESS; 302 } 303 304 /* see if the entry is of proper type for requests */ 305 if (entry->ie_bits & MACH_PORT_TYPE_PORT_RIGHTS) { 306 ipc_port_request_index_t new_request; 307 308 port = (ipc_port_t) entry->ie_object; 309 assert(port != IP_NULL); 310 311 if (!ipc_right_check(space, port, name, entry)) { 312 /* port is locked and active */ 313 314 /* if no new request, just cancel previous */ 315 if (notify == IP_NULL) { 316 if (prev_request != IE_REQ_NONE) 317 previous = ipc_port_request_cancel(port, name, prev_request); 318 ip_unlock(port); 319 entry->ie_request = IE_REQ_NONE; 320 ipc_entry_modified(space, name, entry); 321 is_write_unlock(space); 322 break; 323 } 324 325 /* 326 * send-once rights, kernel objects, and non-full other queues 327 * fire immediately (if immediate specified). 328 */ 329 if (send_possible && immediate && 330 ((entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE) || 331 port->ip_receiver == ipc_space_kernel || !ip_full(port))) { 332 if (prev_request != IE_REQ_NONE) 333 previous = ipc_port_request_cancel(port, name, prev_request); 334 ip_unlock(port); 335 entry->ie_request = IE_REQ_NONE; 336 ipc_entry_modified(space, name, entry); 337 is_write_unlock(space); 338 339 ipc_notify_send_possible(notify, name); 340 break; 341 } 342 343 /* 344 * If there is a previous request, free it. Any subsequent 345 * allocation cannot fail, thus assuring an atomic swap. 346 */ 347 if (prev_request != IE_REQ_NONE) 348 previous = ipc_port_request_cancel(port, name, prev_request); 349 350#if IMPORTANCE_INHERITANCE 351 kr = ipc_port_request_alloc(port, name, notify, 352 send_possible, immediate, 353 &new_request, &needboost); 354#else 355 kr = ipc_port_request_alloc(port, name, notify, 356 send_possible, immediate, 357 &new_request); 358#endif /* IMPORTANCE_INHERITANCE */ 359 if (kr != KERN_SUCCESS) { 360 assert(previous == IP_NULL); 361 is_write_unlock(space); 362 363 kr = ipc_port_request_grow(port, ITS_SIZE_NONE); 364 /* port is unlocked */ 365 366 if (kr != KERN_SUCCESS) 367 return kr; 368 369 continue; 370 } 371 372 373 assert(new_request != IE_REQ_NONE); 374 entry->ie_request = new_request; 375 ipc_entry_modified(space, name, entry); 376 is_write_unlock(space); 377 378#if IMPORTANCE_INHERITANCE 379 if (needboost == TRUE) { 380 if (ipc_port_importance_delta(port, 1) == FALSE) 381 ip_unlock(port); 382 } else 383#endif /* IMPORTANCE_INHERITANCE */ 384 ip_unlock(port); 385 386 break; 387 } 388 /* entry may have changed to dead-name by ipc_right_check() */ 389 390 } 391 392 /* treat send_possible requests as immediate w.r.t. dead-name */ 393 if ((send_possible || immediate) && notify != IP_NULL && 394 (entry->ie_bits & MACH_PORT_TYPE_DEAD_NAME)) { 395 mach_port_urefs_t urefs = IE_BITS_UREFS(entry->ie_bits); 396 397 assert(urefs > 0); 398 399 if (MACH_PORT_UREFS_OVERFLOW(urefs, 1)) { 400 is_write_unlock(space); 401 if (port != IP_NULL) 402 ip_release(port); 403 return KERN_UREFS_OVERFLOW; 404 } 405 406 (entry->ie_bits)++; /* increment urefs */ 407 ipc_entry_modified(space, name, entry); 408 is_write_unlock(space); 409 410 if (port != IP_NULL) 411 ip_release(port); 412 413 ipc_notify_dead_name(notify, name); 414 previous = IP_NULL; 415 break; 416 } 417 418 is_write_unlock(space); 419 420 if (port != IP_NULL) 421 ip_release(port); 422 423 if (entry->ie_bits & MACH_PORT_TYPE_PORT_OR_DEAD) 424 return KERN_INVALID_ARGUMENT; 425 else 426 return KERN_INVALID_RIGHT; 427 } 428 429 *previousp = previous; 430 return KERN_SUCCESS; 431} 432 433/* 434 * Routine: ipc_right_request_cancel 435 * Purpose: 436 * Cancel a notification request and return the send-once right. 437 * Afterwards, entry->ie_request == 0. 438 * Conditions: 439 * The space must be write-locked; the port must be locked. 440 * The port must be active; the space doesn't have to be. 441 */ 442 443ipc_port_t 444ipc_right_request_cancel( 445 __unused ipc_space_t space, 446 ipc_port_t port, 447 mach_port_name_t name, 448 ipc_entry_t entry) 449{ 450 ipc_port_t previous; 451 452 assert(ip_active(port)); 453 assert(port == (ipc_port_t) entry->ie_object); 454 455 if (entry->ie_request == IE_REQ_NONE) 456 return IP_NULL; 457 458 previous = ipc_port_request_cancel(port, name, entry->ie_request); 459 entry->ie_request = IE_REQ_NONE; 460 ipc_entry_modified(space, name, entry); 461 return previous; 462} 463 464/* 465 * Routine: ipc_right_inuse 466 * Purpose: 467 * Check if an entry is being used. 468 * Returns TRUE if it is. 469 * Conditions: 470 * The space is write-locked and active. 471 * It is unlocked if the entry is inuse. 472 */ 473 474boolean_t 475ipc_right_inuse( 476 ipc_space_t space, 477 __unused mach_port_name_t name, 478 ipc_entry_t entry) 479{ 480 if (IE_BITS_TYPE(entry->ie_bits) != MACH_PORT_TYPE_NONE) { 481 is_write_unlock(space); 482 return TRUE; 483 } 484 return FALSE; 485} 486 487/* 488 * Routine: ipc_right_check 489 * Purpose: 490 * Check if the port has died. If it has, 491 * clean up the entry and return TRUE. 492 * Conditions: 493 * The space is write-locked; the port is not locked. 494 * If returns FALSE, the port is also locked and active. 495 * Otherwise, entry is converted to a dead name. 496 * 497 * Caller is responsible for a reference to port if it 498 * had died (returns TRUE). 499 */ 500 501boolean_t 502ipc_right_check( 503 ipc_space_t space, 504 ipc_port_t port, 505 mach_port_name_t name, 506 ipc_entry_t entry) 507{ 508 ipc_entry_bits_t bits; 509 510 assert(is_active(space)); 511 assert(port == (ipc_port_t) entry->ie_object); 512 513 ip_lock(port); 514 if (ip_active(port)) 515 return FALSE; 516 517 /* this was either a pure send right or a send-once right */ 518 519 bits = entry->ie_bits; 520 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0); 521 assert(IE_BITS_UREFS(bits) > 0); 522 523 if (bits & MACH_PORT_TYPE_SEND) { 524 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); 525 assert(IE_BITS_UREFS(bits) > 0); 526 assert(port->ip_srights > 0); 527 port->ip_srights--; 528 } else { 529 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); 530 assert(IE_BITS_UREFS(bits) == 1); 531 assert(port->ip_sorights > 0); 532 port->ip_sorights--; 533 } 534 ip_unlock(port); 535 536 /* 537 * delete SEND rights from ipc hash. 538 */ 539 540 if ((bits & MACH_PORT_TYPE_SEND) != 0) { 541 ipc_hash_delete(space, (ipc_object_t)port, name, entry); 542 } 543 544 /* convert entry to dead name */ 545 bits = (bits &~ IE_BITS_TYPE_MASK) | MACH_PORT_TYPE_DEAD_NAME; 546 547 /* 548 * If there was a notification request outstanding on this 549 * name, and the port went dead, that notification 550 * must already be on its way up from the port layer. 551 * 552 * Add the reference that the notification carries. It 553 * is done here, and not in the notification delivery, 554 * because the latter doesn't have a space reference and 555 * trying to actually move a send-right reference would 556 * get short-circuited into a MACH_PORT_DEAD by IPC. Since 557 * all calls that deal with the right eventually come 558 * through here, it has the same result. 559 * 560 * Once done, clear the request index so we only account 561 * for it once. 562 */ 563 if (entry->ie_request != IE_REQ_NONE) { 564 if (ipc_port_request_type(port, name, entry->ie_request) != 0) { 565 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX); 566 bits++; 567 } 568 entry->ie_request = IE_REQ_NONE; 569 } 570 entry->ie_bits = bits; 571 entry->ie_object = IO_NULL; 572 ipc_entry_modified(space, name, entry); 573 return TRUE; 574} 575 576/* 577 * Routine: ipc_right_terminate 578 * Purpose: 579 * Cleans up an entry in a terminated space. 580 * The entry isn't deallocated or removed 581 * from reverse hash tables. 582 * Conditions: 583 * The space is dead and unlocked. 584 */ 585 586void 587ipc_right_terminate( 588 ipc_space_t space, 589 mach_port_name_t name, 590 ipc_entry_t entry) 591{ 592 ipc_entry_bits_t bits; 593 mach_port_type_t type; 594 595 bits = entry->ie_bits; 596 type = IE_BITS_TYPE(bits); 597 598 assert(!is_active(space)); 599 600 /* 601 * IE_BITS_COMPAT/ipc_right_dncancel doesn't have this 602 * problem, because we check that the port is active. If 603 * we didn't cancel IE_BITS_COMPAT, ipc_port_destroy 604 * would still work, but dead space refs would accumulate 605 * in ip_dnrequests. They would use up slots in 606 * ip_dnrequests and keep the spaces from being freed. 607 */ 608 609 switch (type) { 610 case MACH_PORT_TYPE_DEAD_NAME: 611 assert(entry->ie_request == IE_REQ_NONE); 612 assert(entry->ie_object == IO_NULL); 613 break; 614 615 case MACH_PORT_TYPE_PORT_SET: { 616 ipc_pset_t pset = (ipc_pset_t) entry->ie_object; 617 618 assert(entry->ie_request == IE_REQ_NONE); 619 assert(pset != IPS_NULL); 620 621 ips_lock(pset); 622 assert(ips_active(pset)); 623 ipc_pset_destroy(pset); /* consumes ref, unlocks */ 624 break; 625 } 626 627 case MACH_PORT_TYPE_SEND: 628 case MACH_PORT_TYPE_RECEIVE: 629 case MACH_PORT_TYPE_SEND_RECEIVE: 630 case MACH_PORT_TYPE_SEND_ONCE: { 631 ipc_port_t port = (ipc_port_t) entry->ie_object; 632 ipc_port_t request; 633 ipc_port_t nsrequest = IP_NULL; 634 mach_port_mscount_t mscount = 0; 635 636 assert(port != IP_NULL); 637 ip_lock(port); 638 639 if (!ip_active(port)) { 640 ip_unlock(port); 641 ip_release(port); 642 break; 643 } 644 645 request = ipc_right_request_cancel_macro(space, port, 646 name, entry); 647 648 if (type & MACH_PORT_TYPE_SEND) { 649 assert(port->ip_srights > 0); 650 if (--port->ip_srights == 0 651 ) { 652 nsrequest = port->ip_nsrequest; 653 if (nsrequest != IP_NULL) { 654 port->ip_nsrequest = IP_NULL; 655 mscount = port->ip_mscount; 656 } 657 } 658 } 659 660 if (type & MACH_PORT_TYPE_RECEIVE) { 661 wait_queue_link_t wql; 662 queue_head_t links_data; 663 queue_t links = &links_data; 664 665 assert(port->ip_receiver_name == name); 666 assert(port->ip_receiver == space); 667 668 queue_init(links); 669 ipc_port_clear_receiver(port, links); 670 ipc_port_destroy(port); /* consumes our ref, unlocks */ 671 while(!queue_empty(links)) { 672 wql = (wait_queue_link_t) dequeue(links); 673 wait_queue_link_free(wql); 674 } 675 676 } else if (type & MACH_PORT_TYPE_SEND_ONCE) { 677 assert(port->ip_sorights > 0); 678 ip_unlock(port); 679 680 ipc_notify_send_once(port); /* consumes our ref */ 681 } else { 682 assert(port->ip_receiver != space); 683 684 ip_unlock(port); 685 ip_release(port); 686 } 687 688 if (nsrequest != IP_NULL) 689 ipc_notify_no_senders(nsrequest, mscount); 690 691 if (request != IP_NULL) 692 ipc_notify_port_deleted(request, name); 693 break; 694 } 695 696 default: 697 panic("ipc_right_terminate: strange type - 0x%x", type); 698 } 699} 700 701/* 702 * Routine: ipc_right_destroy 703 * Purpose: 704 * Destroys an entry in a space. 705 * Conditions: 706 * The space is write-locked (returns unlocked). 707 * The space must be active. 708 * Returns: 709 * KERN_SUCCESS The entry was destroyed. 710 */ 711 712kern_return_t 713ipc_right_destroy( 714 ipc_space_t space, 715 mach_port_name_t name, 716 ipc_entry_t entry, 717 boolean_t check_guard, 718 uint64_t guard) 719{ 720 ipc_entry_bits_t bits; 721 mach_port_type_t type; 722 723 bits = entry->ie_bits; 724 entry->ie_bits &= ~IE_BITS_TYPE_MASK; 725 type = IE_BITS_TYPE(bits); 726 727 assert(is_active(space)); 728 729 switch (type) { 730 case MACH_PORT_TYPE_DEAD_NAME: 731 assert(entry->ie_request == IE_REQ_NONE); 732 assert(entry->ie_object == IO_NULL); 733 734 ipc_entry_dealloc(space, name, entry); 735 is_write_unlock(space); 736 break; 737 738 case MACH_PORT_TYPE_PORT_SET: { 739 ipc_pset_t pset = (ipc_pset_t) entry->ie_object; 740 741 assert(entry->ie_request == IE_REQ_NONE); 742 assert(pset != IPS_NULL); 743 744 entry->ie_object = IO_NULL; 745 ipc_entry_dealloc(space, name, entry); 746 747 ips_lock(pset); 748 is_write_unlock(space); 749 750 assert(ips_active(pset)); 751 ipc_pset_destroy(pset); /* consumes ref, unlocks */ 752 break; 753 } 754 755 case MACH_PORT_TYPE_SEND: 756 case MACH_PORT_TYPE_RECEIVE: 757 case MACH_PORT_TYPE_SEND_RECEIVE: 758 case MACH_PORT_TYPE_SEND_ONCE: { 759 ipc_port_t port = (ipc_port_t) entry->ie_object; 760 ipc_port_t nsrequest = IP_NULL; 761 mach_port_mscount_t mscount = 0; 762 ipc_port_t request; 763 764 assert(port != IP_NULL); 765 766 if (type == MACH_PORT_TYPE_SEND) 767 ipc_hash_delete(space, (ipc_object_t) port, 768 name, entry); 769 770 ip_lock(port); 771 772 if (!ip_active(port)) { 773 assert((type & MACH_PORT_TYPE_RECEIVE) == 0); 774 ip_unlock(port); 775 entry->ie_request = IE_REQ_NONE; 776 entry->ie_object = IO_NULL; 777 ipc_entry_dealloc(space, name, entry); 778 is_write_unlock(space); 779 ip_release(port); 780 break; 781 } 782 783 /* For receive rights, check for guarding */ 784 if ((type & MACH_PORT_TYPE_RECEIVE) && 785 (check_guard) && (port->ip_guarded) && 786 (guard != port->ip_context)) { 787 /* Guard Violation */ 788 uint64_t portguard = port->ip_context; 789 ip_unlock(port); 790 is_write_unlock(space); 791 /* Raise mach port guard exception */ 792 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY); 793 return KERN_INVALID_RIGHT; 794 } 795 796 797 request = ipc_right_request_cancel_macro(space, port, name, entry); 798 799 entry->ie_object = IO_NULL; 800 ipc_entry_dealloc(space, name, entry); 801 is_write_unlock(space); 802 803 if (type & MACH_PORT_TYPE_SEND) { 804 assert(port->ip_srights > 0); 805 if (--port->ip_srights == 0) { 806 nsrequest = port->ip_nsrequest; 807 if (nsrequest != IP_NULL) { 808 port->ip_nsrequest = IP_NULL; 809 mscount = port->ip_mscount; 810 } 811 } 812 } 813 814 if (type & MACH_PORT_TYPE_RECEIVE) { 815 queue_head_t links_data; 816 queue_t links = &links_data; 817 wait_queue_link_t wql; 818 819 assert(ip_active(port)); 820 assert(port->ip_receiver == space); 821 822 queue_init(links); 823 824 ipc_port_clear_receiver(port, links); 825 ipc_port_destroy(port); /* consumes our ref, unlocks */ 826 827 while(!queue_empty(links)) { 828 wql = (wait_queue_link_t) dequeue(links); 829 wait_queue_link_free(wql); 830 } 831 832 } else if (type & MACH_PORT_TYPE_SEND_ONCE) { 833 assert(port->ip_sorights > 0); 834 ip_unlock(port); 835 836 ipc_notify_send_once(port); /* consumes our ref */ 837 } else { 838 assert(port->ip_receiver != space); 839 840 ip_unlock(port); 841 ip_release(port); 842 } 843 844 if (nsrequest != IP_NULL) 845 ipc_notify_no_senders(nsrequest, mscount); 846 847 if (request != IP_NULL) 848 ipc_notify_port_deleted(request, name); 849 850 851 break; 852 } 853 854 default: 855 panic("ipc_right_destroy: strange type"); 856 } 857 858 return KERN_SUCCESS; 859} 860 861/* 862 * Routine: ipc_right_dealloc 863 * Purpose: 864 * Releases a send/send-once/dead-name user ref. 865 * Like ipc_right_delta with a delta of -1, 866 * but looks at the entry to determine the right. 867 * Conditions: 868 * The space is write-locked, and is unlocked upon return. 869 * The space must be active. 870 * Returns: 871 * KERN_SUCCESS A user ref was released. 872 * KERN_INVALID_RIGHT Entry has wrong type. 873 */ 874 875kern_return_t 876ipc_right_dealloc( 877 ipc_space_t space, 878 mach_port_name_t name, 879 ipc_entry_t entry) 880{ 881 ipc_port_t port = IP_NULL; 882 ipc_entry_bits_t bits; 883 mach_port_type_t type; 884 885 bits = entry->ie_bits; 886 type = IE_BITS_TYPE(bits); 887 888 889 assert(is_active(space)); 890 891 switch (type) { 892 case MACH_PORT_TYPE_DEAD_NAME: { 893 dead_name: 894 895 assert(IE_BITS_UREFS(bits) > 0); 896 assert(entry->ie_request == IE_REQ_NONE); 897 assert(entry->ie_object == IO_NULL); 898 899 if (IE_BITS_UREFS(bits) == 1) { 900 ipc_entry_dealloc(space, name, entry); 901 } else { 902 entry->ie_bits = bits-1; /* decrement urefs */ 903 ipc_entry_modified(space, name, entry); 904 } 905 is_write_unlock(space); 906 907 /* release any port that got converted to dead name below */ 908 if (port != IP_NULL) 909 ip_release(port); 910 break; 911 } 912 913 case MACH_PORT_TYPE_SEND_ONCE: { 914 ipc_port_t request; 915 916 assert(IE_BITS_UREFS(bits) == 1); 917 918 port = (ipc_port_t) entry->ie_object; 919 assert(port != IP_NULL); 920 921 if (ipc_right_check(space, port, name, entry)) { 922 923 bits = entry->ie_bits; 924 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); 925 goto dead_name; /* it will release port */ 926 } 927 /* port is locked and active */ 928 929 assert(port->ip_sorights > 0); 930 931 request = ipc_right_request_cancel_macro(space, port, name, entry); 932 ip_unlock(port); 933 934 entry->ie_object = IO_NULL; 935 ipc_entry_dealloc(space, name, entry); 936 937 is_write_unlock(space); 938 939 ipc_notify_send_once(port); 940 941 if (request != IP_NULL) 942 ipc_notify_port_deleted(request, name); 943 break; 944 } 945 946 case MACH_PORT_TYPE_SEND: { 947 ipc_port_t request = IP_NULL; 948 ipc_port_t nsrequest = IP_NULL; 949 mach_port_mscount_t mscount = 0; 950 951 952 assert(IE_BITS_UREFS(bits) > 0); 953 954 port = (ipc_port_t) entry->ie_object; 955 assert(port != IP_NULL); 956 957 if (ipc_right_check(space, port, name, entry)) { 958 bits = entry->ie_bits; 959 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); 960 goto dead_name; /* it will release port */ 961 } 962 /* port is locked and active */ 963 964 assert(port->ip_srights > 0); 965 966 if (IE_BITS_UREFS(bits) == 1) { 967 if (--port->ip_srights == 0) { 968 nsrequest = port->ip_nsrequest; 969 if (nsrequest != IP_NULL) { 970 port->ip_nsrequest = IP_NULL; 971 mscount = port->ip_mscount; 972 } 973 } 974 975 request = ipc_right_request_cancel_macro(space, port, 976 name, entry); 977 ipc_hash_delete(space, (ipc_object_t) port, 978 name, entry); 979 980 ip_unlock(port); 981 entry->ie_object = IO_NULL; 982 ipc_entry_dealloc(space, name, entry); 983 is_write_unlock(space); 984 ip_release(port); 985 986 } else { 987 ip_unlock(port); 988 entry->ie_bits = bits-1; /* decrement urefs */ 989 ipc_entry_modified(space, name, entry); 990 is_write_unlock(space); 991 } 992 993 994 if (nsrequest != IP_NULL) 995 ipc_notify_no_senders(nsrequest, mscount); 996 997 if (request != IP_NULL) 998 ipc_notify_port_deleted(request, name); 999 break; 1000 } 1001 1002 case MACH_PORT_TYPE_SEND_RECEIVE: { 1003 ipc_port_t nsrequest = IP_NULL; 1004 mach_port_mscount_t mscount = 0; 1005 1006 assert(IE_BITS_UREFS(bits) > 0); 1007 1008 port = (ipc_port_t) entry->ie_object; 1009 assert(port != IP_NULL); 1010 1011 ip_lock(port); 1012 assert(ip_active(port)); 1013 assert(port->ip_receiver_name == name); 1014 assert(port->ip_receiver == space); 1015 assert(port->ip_srights > 0); 1016 1017 if (IE_BITS_UREFS(bits) == 1) { 1018 if (--port->ip_srights == 0) { 1019 nsrequest = port->ip_nsrequest; 1020 if (nsrequest != IP_NULL) { 1021 port->ip_nsrequest = IP_NULL; 1022 mscount = port->ip_mscount; 1023 } 1024 } 1025 1026 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK | 1027 MACH_PORT_TYPE_SEND); 1028 } else 1029 entry->ie_bits = bits-1; /* decrement urefs */ 1030 1031 ip_unlock(port); 1032 1033 ipc_entry_modified(space, name, entry); 1034 is_write_unlock(space); 1035 1036 if (nsrequest != IP_NULL) 1037 ipc_notify_no_senders(nsrequest, mscount); 1038 break; 1039 } 1040 1041 default: 1042 is_write_unlock(space); 1043 return KERN_INVALID_RIGHT; 1044 } 1045 1046 return KERN_SUCCESS; 1047} 1048 1049/* 1050 * Routine: ipc_right_delta 1051 * Purpose: 1052 * Modifies the user-reference count for a right. 1053 * May deallocate the right, if the count goes to zero. 1054 * Conditions: 1055 * The space is write-locked, and is unlocked upon return. 1056 * The space must be active. 1057 * Returns: 1058 * KERN_SUCCESS Count was modified. 1059 * KERN_INVALID_RIGHT Entry has wrong type. 1060 * KERN_INVALID_VALUE Bad delta for the right. 1061 * KERN_UREFS_OVERFLOW OK delta, except would overflow. 1062 */ 1063 1064kern_return_t 1065ipc_right_delta( 1066 ipc_space_t space, 1067 mach_port_name_t name, 1068 ipc_entry_t entry, 1069 mach_port_right_t right, 1070 mach_port_delta_t delta) 1071{ 1072 ipc_port_t port = IP_NULL; 1073 ipc_entry_bits_t bits; 1074 1075 bits = entry->ie_bits; 1076 1077 1078/* 1079 * The following is used (for case MACH_PORT_RIGHT_DEAD_NAME) in the 1080 * switch below. It is used to keep track of those cases (in DIPC) 1081 * where we have postponed the dropping of a port reference. Since 1082 * the dropping of the reference could cause the port to disappear 1083 * we postpone doing so when we are holding the space lock. 1084 */ 1085 1086 assert(is_active(space)); 1087 assert(right < MACH_PORT_RIGHT_NUMBER); 1088 1089 /* Rights-specific restrictions and operations. */ 1090 1091 switch (right) { 1092 case MACH_PORT_RIGHT_PORT_SET: { 1093 ipc_pset_t pset; 1094 1095 if ((bits & MACH_PORT_TYPE_PORT_SET) == 0) 1096 goto invalid_right; 1097 1098 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_PORT_SET); 1099 assert(IE_BITS_UREFS(bits) == 0); 1100 assert(entry->ie_request == IE_REQ_NONE); 1101 1102 if (delta == 0) 1103 goto success; 1104 1105 if (delta != -1) 1106 goto invalid_value; 1107 1108 pset = (ipc_pset_t) entry->ie_object; 1109 assert(pset != IPS_NULL); 1110 1111 entry->ie_object = IO_NULL; 1112 ipc_entry_dealloc(space, name, entry); 1113 1114 ips_lock(pset); 1115 assert(ips_active(pset)); 1116 is_write_unlock(space); 1117 1118 ipc_pset_destroy(pset); /* consumes ref, unlocks */ 1119 break; 1120 } 1121 1122 case MACH_PORT_RIGHT_RECEIVE: { 1123 ipc_port_t request = IP_NULL; 1124 queue_head_t links_data; 1125 queue_t links = &links_data; 1126 wait_queue_link_t wql; 1127 1128 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) 1129 goto invalid_right; 1130 1131 if (delta == 0) 1132 goto success; 1133 1134 if (delta != -1) 1135 goto invalid_value; 1136 1137 port = (ipc_port_t) entry->ie_object; 1138 assert(port != IP_NULL); 1139 1140 /* 1141 * The port lock is needed for ipc_right_dncancel; 1142 * otherwise, we wouldn't have to take the lock 1143 * until just before dropping the space lock. 1144 */ 1145 1146 ip_lock(port); 1147 assert(ip_active(port)); 1148 assert(port->ip_receiver_name == name); 1149 assert(port->ip_receiver == space); 1150 1151 /* Mach Port Guard Checking */ 1152 if(port->ip_guarded) { 1153 uint64_t portguard = port->ip_context; 1154 ip_unlock(port); 1155 is_write_unlock(space); 1156 /* Raise mach port guard exception */ 1157 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_MOD_REFS); 1158 goto guard_failure; 1159 } 1160 1161 if (bits & MACH_PORT_TYPE_SEND) { 1162 assert(IE_BITS_TYPE(bits) == 1163 MACH_PORT_TYPE_SEND_RECEIVE); 1164 assert(IE_BITS_UREFS(bits) > 0); 1165 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX); 1166 assert(port->ip_srights > 0); 1167 1168 if (port->ip_pdrequest != NULL) { 1169 /* 1170 * Since another task has requested a 1171 * destroy notification for this port, it 1172 * isn't actually being destroyed - the receive 1173 * right is just being moved to another task. 1174 * Since we still have one or more send rights, 1175 * we need to record the loss of the receive 1176 * right and enter the remaining send right 1177 * into the hash table. 1178 */ 1179 ipc_entry_modified(space, name, entry); 1180 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE; 1181 ipc_hash_insert(space, (ipc_object_t) port, 1182 name, entry); 1183 ip_reference(port); 1184 } else { 1185 /* 1186 * The remaining send right turns into a 1187 * dead name. Notice we don't decrement 1188 * ip_srights, generate a no-senders notif, 1189 * or use ipc_right_dncancel, because the 1190 * port is destroyed "first". 1191 */ 1192 bits &= ~IE_BITS_TYPE_MASK; 1193 bits |= MACH_PORT_TYPE_DEAD_NAME; 1194 if (entry->ie_request) { 1195 entry->ie_request = IE_REQ_NONE; 1196 bits++; 1197 } 1198 entry->ie_bits = bits; 1199 entry->ie_object = IO_NULL; 1200 ipc_entry_modified(space, name, entry); 1201 } 1202 } else { 1203 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE); 1204 assert(IE_BITS_UREFS(bits) == 0); 1205 1206 request = ipc_right_request_cancel_macro(space, port, 1207 name, entry); 1208 entry->ie_object = IO_NULL; 1209 ipc_entry_dealloc(space, name, entry); 1210 } 1211 is_write_unlock(space); 1212 1213 queue_init(links); 1214 ipc_port_clear_receiver(port, links); 1215 ipc_port_destroy(port); /* consumes ref, unlocks */ 1216 1217 while(!queue_empty(links)) { 1218 wql = (wait_queue_link_t) dequeue(links); 1219 wait_queue_link_free(wql); 1220 } 1221 1222 if (request != IP_NULL) 1223 ipc_notify_port_deleted(request, name); 1224 break; 1225 } 1226 1227 case MACH_PORT_RIGHT_SEND_ONCE: { 1228 ipc_port_t request; 1229 1230 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) 1231 goto invalid_right; 1232 1233 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); 1234 assert(IE_BITS_UREFS(bits) == 1); 1235 1236 port = (ipc_port_t) entry->ie_object; 1237 assert(port != IP_NULL); 1238 1239 if (ipc_right_check(space, port, name, entry)) { 1240 assert(!(entry->ie_bits & MACH_PORT_TYPE_SEND_ONCE)); 1241 goto invalid_right; 1242 } 1243 /* port is locked and active */ 1244 1245 assert(port->ip_sorights > 0); 1246 1247 if ((delta > 0) || (delta < -1)) { 1248 ip_unlock(port); 1249 goto invalid_value; 1250 } 1251 1252 if (delta == 0) { 1253 ip_unlock(port); 1254 goto success; 1255 } 1256 1257 request = ipc_right_request_cancel_macro(space, port, name, entry); 1258 ip_unlock(port); 1259 1260 entry->ie_object = IO_NULL; 1261 ipc_entry_dealloc(space, name, entry); 1262 1263 is_write_unlock(space); 1264 1265 ipc_notify_send_once(port); 1266 1267 if (request != IP_NULL) 1268 ipc_notify_port_deleted(request, name); 1269 break; 1270 } 1271 1272 case MACH_PORT_RIGHT_DEAD_NAME: { 1273 ipc_port_t relport = IP_NULL; 1274 mach_port_urefs_t urefs; 1275 1276 if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { 1277 1278 port = (ipc_port_t) entry->ie_object; 1279 assert(port != IP_NULL); 1280 1281 if (!ipc_right_check(space, port, name, entry)) { 1282 /* port is locked and active */ 1283 ip_unlock(port); 1284 port = IP_NULL; 1285 goto invalid_right; 1286 } 1287 bits = entry->ie_bits; 1288 relport = port; 1289 port = IP_NULL; 1290 } else if ((bits & MACH_PORT_TYPE_DEAD_NAME) == 0) 1291 goto invalid_right; 1292 1293 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); 1294 assert(IE_BITS_UREFS(bits) > 0); 1295 assert(entry->ie_object == IO_NULL); 1296 assert(entry->ie_request == IE_REQ_NONE); 1297 1298 urefs = IE_BITS_UREFS(bits); 1299 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) 1300 goto invalid_value; 1301 if (MACH_PORT_UREFS_OVERFLOW(urefs, delta)) 1302 goto urefs_overflow; 1303 1304 if ((urefs + delta) == 0) { 1305 ipc_entry_dealloc(space, name, entry); 1306 } else { 1307 entry->ie_bits = bits + delta; 1308 ipc_entry_modified(space, name, entry); 1309 } 1310 is_write_unlock(space); 1311 1312 if (relport != IP_NULL) 1313 ip_release(relport); 1314 1315 break; 1316 } 1317 1318 case MACH_PORT_RIGHT_SEND: { 1319 mach_port_urefs_t urefs; 1320 ipc_port_t request = IP_NULL; 1321 ipc_port_t nsrequest = IP_NULL; 1322 mach_port_mscount_t mscount = 0; 1323 1324 if ((bits & MACH_PORT_TYPE_SEND) == 0) 1325 goto invalid_right; 1326 1327 /* maximum urefs for send is MACH_PORT_UREFS_MAX-1 */ 1328 1329 port = (ipc_port_t) entry->ie_object; 1330 assert(port != IP_NULL); 1331 1332 if (ipc_right_check(space, port, name, entry)) { 1333 assert((entry->ie_bits & MACH_PORT_TYPE_SEND) == 0); 1334 goto invalid_right; 1335 } 1336 /* port is locked and active */ 1337 1338 assert(port->ip_srights > 0); 1339 1340 urefs = IE_BITS_UREFS(bits); 1341 if (MACH_PORT_UREFS_UNDERFLOW(urefs, delta)) { 1342 ip_unlock(port); 1343 goto invalid_value; 1344 } 1345 if (MACH_PORT_UREFS_OVERFLOW(urefs+1, delta)) { 1346 ip_unlock(port); 1347 goto urefs_overflow; 1348 } 1349 1350 if ((urefs + delta) == 0) { 1351 if (--port->ip_srights == 0) { 1352 nsrequest = port->ip_nsrequest; 1353 if (nsrequest != IP_NULL) { 1354 port->ip_nsrequest = IP_NULL; 1355 mscount = port->ip_mscount; 1356 } 1357 } 1358 1359 if (bits & MACH_PORT_TYPE_RECEIVE) { 1360 assert(port->ip_receiver_name == name); 1361 assert(port->ip_receiver == space); 1362 ip_unlock(port); 1363 assert(IE_BITS_TYPE(bits) == 1364 MACH_PORT_TYPE_SEND_RECEIVE); 1365 1366 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK| 1367 MACH_PORT_TYPE_SEND); 1368 ipc_entry_modified(space, name, entry); 1369 } else { 1370 assert(IE_BITS_TYPE(bits) == 1371 MACH_PORT_TYPE_SEND); 1372 1373 request = ipc_right_request_cancel_macro(space, port, 1374 name, entry); 1375 ipc_hash_delete(space, (ipc_object_t) port, 1376 name, entry); 1377 1378 ip_unlock(port); 1379 ip_release(port); 1380 1381 entry->ie_object = IO_NULL; 1382 ipc_entry_dealloc(space, name, entry); 1383 } 1384 } else { 1385 ip_unlock(port); 1386 entry->ie_bits = bits + delta; 1387 ipc_entry_modified(space, name, entry); 1388 } 1389 1390 is_write_unlock(space); 1391 1392 if (nsrequest != IP_NULL) 1393 ipc_notify_no_senders(nsrequest, mscount); 1394 1395 if (request != IP_NULL) 1396 ipc_notify_port_deleted(request, name); 1397 break; 1398 } 1399 1400 default: 1401 panic("ipc_right_delta: strange right"); 1402 } 1403 1404 return KERN_SUCCESS; 1405 1406 success: 1407 is_write_unlock(space); 1408 return KERN_SUCCESS; 1409 1410 invalid_right: 1411 is_write_unlock(space); 1412 if (port != IP_NULL) 1413 ip_release(port); 1414 return KERN_INVALID_RIGHT; 1415 1416 invalid_value: 1417 is_write_unlock(space); 1418 return KERN_INVALID_VALUE; 1419 1420 urefs_overflow: 1421 is_write_unlock(space); 1422 return KERN_UREFS_OVERFLOW; 1423 1424 guard_failure: 1425 return KERN_INVALID_RIGHT; 1426} 1427 1428/* 1429 * Routine: ipc_right_destruct 1430 * Purpose: 1431 * Deallocates the receive right and modifies the 1432 * user-reference count for the send rights as requested. 1433 * Conditions: 1434 * The space is write-locked, and is unlocked upon return. 1435 * The space must be active. 1436 * Returns: 1437 * KERN_SUCCESS Count was modified. 1438 * KERN_INVALID_RIGHT Entry has wrong type. 1439 * KERN_INVALID_VALUE Bad delta for the right. 1440 */ 1441 1442kern_return_t 1443ipc_right_destruct( 1444 ipc_space_t space, 1445 mach_port_name_t name, 1446 ipc_entry_t entry, 1447 mach_port_delta_t srdelta, 1448 uint64_t guard) 1449{ 1450 ipc_port_t port = IP_NULL; 1451 ipc_entry_bits_t bits; 1452 1453 queue_head_t links_data; 1454 queue_t links = &links_data; 1455 wait_queue_link_t wql; 1456 1457 mach_port_urefs_t urefs; 1458 ipc_port_t request = IP_NULL; 1459 ipc_port_t nsrequest = IP_NULL; 1460 mach_port_mscount_t mscount = 0; 1461 1462 bits = entry->ie_bits; 1463 1464 assert(is_active(space)); 1465 1466 if (((bits & MACH_PORT_TYPE_RECEIVE) == 0) || 1467 (srdelta && ((bits & MACH_PORT_TYPE_SEND) == 0))) { 1468 is_write_unlock(space); 1469 return KERN_INVALID_RIGHT; 1470 } 1471 1472 if (srdelta > 0) 1473 goto invalid_value; 1474 1475 port = (ipc_port_t) entry->ie_object; 1476 assert(port != IP_NULL); 1477 1478 ip_lock(port); 1479 assert(ip_active(port)); 1480 assert(port->ip_receiver_name == name); 1481 assert(port->ip_receiver == space); 1482 1483 /* Mach Port Guard Checking */ 1484 if(port->ip_guarded && (guard != port->ip_context)) { 1485 uint64_t portguard = port->ip_context; 1486 ip_unlock(port); 1487 is_write_unlock(space); 1488 mach_port_guard_exception(name, 0, portguard, kGUARD_EXC_DESTROY); 1489 return KERN_INVALID_ARGUMENT; 1490 } 1491 1492 /* 1493 * First reduce the send rights as requested and 1494 * adjust the entry->ie_bits accordingly. The 1495 * ipc_entry_modified() call is made once the receive 1496 * right is destroyed too. 1497 */ 1498 1499 if (srdelta) { 1500 1501 assert(port->ip_srights > 0); 1502 1503 urefs = IE_BITS_UREFS(bits); 1504 /* 1505 * Since we made sure that srdelta is negative, 1506 * the check for urefs overflow is not required. 1507 */ 1508 if (MACH_PORT_UREFS_UNDERFLOW(urefs, srdelta)) { 1509 ip_unlock(port); 1510 goto invalid_value; 1511 } 1512 if ((urefs + srdelta) == 0) { 1513 if (--port->ip_srights == 0) { 1514 nsrequest = port->ip_nsrequest; 1515 if (nsrequest != IP_NULL) { 1516 port->ip_nsrequest = IP_NULL; 1517 mscount = port->ip_mscount; 1518 } 1519 } 1520 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_RECEIVE); 1521 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK| 1522 MACH_PORT_TYPE_SEND); 1523 } else { 1524 entry->ie_bits = bits + srdelta; 1525 } 1526 } 1527 1528 /* 1529 * Now destroy the receive right. Update space and 1530 * entry accordingly. 1531 */ 1532 1533 bits = entry->ie_bits; 1534 if (bits & MACH_PORT_TYPE_SEND) { 1535 assert(IE_BITS_UREFS(bits) > 0); 1536 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX); 1537 1538 if (port->ip_pdrequest != NULL) { 1539 /* 1540 * Since another task has requested a 1541 * destroy notification for this port, it 1542 * isn't actually being destroyed - the receive 1543 * right is just being moved to another task. 1544 * Since we still have one or more send rights, 1545 * we need to record the loss of the receive 1546 * right and enter the remaining send right 1547 * into the hash table. 1548 */ 1549 ipc_entry_modified(space, name, entry); 1550 entry->ie_bits &= ~MACH_PORT_TYPE_RECEIVE; 1551 ipc_hash_insert(space, (ipc_object_t) port, 1552 name, entry); 1553 ip_reference(port); 1554 } else { 1555 /* 1556 * The remaining send right turns into a 1557 * dead name. Notice we don't decrement 1558 * ip_srights, generate a no-senders notif, 1559 * or use ipc_right_dncancel, because the 1560 * port is destroyed "first". 1561 */ 1562 bits &= ~IE_BITS_TYPE_MASK; 1563 bits |= MACH_PORT_TYPE_DEAD_NAME; 1564 if (entry->ie_request) { 1565 entry->ie_request = IE_REQ_NONE; 1566 bits++; 1567 } 1568 entry->ie_bits = bits; 1569 entry->ie_object = IO_NULL; 1570 ipc_entry_modified(space, name, entry); 1571 } 1572 } else { 1573 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE); 1574 assert(IE_BITS_UREFS(bits) == 0); 1575 request = ipc_right_request_cancel_macro(space, port, 1576 name, entry); 1577 entry->ie_object = IO_NULL; 1578 ipc_entry_dealloc(space, name, entry); 1579 } 1580 1581 /* Unlock space */ 1582 is_write_unlock(space); 1583 1584 if (nsrequest != IP_NULL) 1585 ipc_notify_no_senders(nsrequest, mscount); 1586 1587 queue_init(links); 1588 ipc_port_clear_receiver(port, links); 1589 ipc_port_destroy(port); /* consumes ref, unlocks */ 1590 1591 while(!queue_empty(links)) { 1592 wql = (wait_queue_link_t) dequeue(links); 1593 wait_queue_link_free(wql); 1594 } 1595 1596 if (request != IP_NULL) 1597 ipc_notify_port_deleted(request, name); 1598 1599 return KERN_SUCCESS; 1600 1601 invalid_value: 1602 is_write_unlock(space); 1603 return KERN_INVALID_VALUE; 1604 1605} 1606 1607 1608/* 1609 * Routine: ipc_right_info 1610 * Purpose: 1611 * Retrieves information about the right. 1612 * Conditions: 1613 * The space is active and write-locked. 1614 * The space is unlocked upon return. 1615 * Returns: 1616 * KERN_SUCCESS Retrieved info 1617 */ 1618 1619kern_return_t 1620ipc_right_info( 1621 ipc_space_t space, 1622 mach_port_name_t name, 1623 ipc_entry_t entry, 1624 mach_port_type_t *typep, 1625 mach_port_urefs_t *urefsp) 1626{ 1627 ipc_port_t port; 1628 ipc_entry_bits_t bits; 1629 mach_port_type_t type = 0; 1630 ipc_port_request_index_t request; 1631 1632 bits = entry->ie_bits; 1633 request = entry->ie_request; 1634 port = (ipc_port_t) entry->ie_object; 1635 1636 if (bits & MACH_PORT_TYPE_RECEIVE) { 1637 assert(IP_VALID(port)); 1638 1639 if (request != IE_REQ_NONE) { 1640 ip_lock(port); 1641 assert(ip_active(port)); 1642 type |= ipc_port_request_type(port, name, request); 1643 ip_unlock(port); 1644 } 1645 is_write_unlock(space); 1646 1647 } else if (bits & MACH_PORT_TYPE_SEND_RIGHTS) { 1648 /* 1649 * validate port is still alive - if so, get request 1650 * types while we still have it locked. Otherwise, 1651 * recapture the (now dead) bits. 1652 */ 1653 if (!ipc_right_check(space, port, name, entry)) { 1654 if (request != IE_REQ_NONE) 1655 type |= ipc_port_request_type(port, name, request); 1656 ip_unlock(port); 1657 is_write_unlock(space); 1658 } else { 1659 bits = entry->ie_bits; 1660 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); 1661 is_write_unlock(space); 1662 ip_release(port); 1663 } 1664 } else { 1665 is_write_unlock(space); 1666 } 1667 1668 type |= IE_BITS_TYPE(bits); 1669 1670 *typep = type; 1671 *urefsp = IE_BITS_UREFS(bits); 1672 return KERN_SUCCESS; 1673} 1674 1675/* 1676 * Routine: ipc_right_copyin_check 1677 * Purpose: 1678 * Check if a subsequent ipc_right_copyin would succeed. 1679 * Conditions: 1680 * The space is locked (read or write) and active. 1681 */ 1682 1683boolean_t 1684ipc_right_copyin_check( 1685 __assert_only ipc_space_t space, 1686 __unused mach_port_name_t name, 1687 ipc_entry_t entry, 1688 mach_msg_type_name_t msgt_name) 1689{ 1690 ipc_entry_bits_t bits; 1691 ipc_port_t port; 1692#if CONFIG_MACF_MACH 1693 task_t self = current_task(); 1694 int rc = 0; 1695#endif 1696 1697 bits= entry->ie_bits; 1698 assert(is_active(space)); 1699 1700 switch (msgt_name) { 1701 case MACH_MSG_TYPE_MAKE_SEND: 1702 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) 1703 return FALSE; 1704 1705#if CONFIG_MACF_MACH 1706 port = (ipc_port_t) entry->ie_object; 1707 ip_lock(port); 1708 tasklabel_lock(self); 1709 rc = mac_port_check_make_send(&self->maclabel, &port->ip_label); tasklabel_unlock(self); 1710 ip_unlock(port); 1711 if (rc) 1712 return FALSE; 1713#endif 1714 break; 1715 1716 case MACH_MSG_TYPE_MAKE_SEND_ONCE: 1717 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) 1718 return FALSE; 1719 1720#if CONFIG_MACF_MACH 1721 port = (ipc_port_t) entry->ie_object; 1722 ip_lock(port); 1723 tasklabel_lock(self); 1724 rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label); 1725 tasklabel_unlock(self); 1726 ip_unlock(port); 1727 if (rc) 1728 return FALSE; 1729#endif 1730 break; 1731 1732 case MACH_MSG_TYPE_MOVE_RECEIVE: 1733 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) 1734 return FALSE; 1735 1736#if CONFIG_MACF_MACH 1737 port = (ipc_port_t) entry->ie_object; 1738 ip_lock(port); 1739 tasklabel_lock(self); 1740 rc = mac_port_check_move_receive(&self->maclabel, &port->ip_label); 1741 tasklabel_unlock(self); 1742 ip_unlock(port); 1743 if (rc) 1744 return FALSE; 1745#endif 1746 break; 1747 1748 case MACH_MSG_TYPE_COPY_SEND: 1749 case MACH_MSG_TYPE_MOVE_SEND: 1750 case MACH_MSG_TYPE_MOVE_SEND_ONCE: { 1751 boolean_t active; 1752 1753 if (bits & MACH_PORT_TYPE_DEAD_NAME) 1754 break; 1755 1756 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) 1757 return FALSE; 1758 1759 port = (ipc_port_t) entry->ie_object; 1760 assert(port != IP_NULL); 1761 1762 ip_lock(port); 1763 active = ip_active(port); 1764#if CONFIG_MACF_MACH 1765 tasklabel_lock(self); 1766 switch (msgt_name) { 1767 case MACH_MSG_TYPE_COPY_SEND: 1768 rc = mac_port_check_copy_send(&self->maclabel, 1769 &port->ip_label); 1770 break; 1771 case MACH_MSG_TYPE_MOVE_SEND: 1772 rc = mac_port_check_move_send(&self->maclabel, 1773 &port->ip_label); 1774 break; 1775 case MACH_MSG_TYPE_MOVE_SEND_ONCE: 1776 rc = mac_port_check_move_send_once(&self->maclabel, 1777 &port->ip_label); 1778 break; 1779 default: 1780 panic("ipc_right_copyin_check: strange rights"); 1781 } 1782 tasklabel_unlock(self); 1783 if (rc) { 1784 ip_unlock(port); 1785 return FALSE; 1786 } 1787#endif 1788 ip_unlock(port); 1789 1790 if (!active) { 1791 break; 1792 } 1793 1794 if (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE) { 1795 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) 1796 return FALSE; 1797 } else { 1798 if ((bits & MACH_PORT_TYPE_SEND) == 0) 1799 return FALSE; 1800 } 1801 1802 break; 1803 } 1804 1805 default: 1806 panic("ipc_right_copyin_check: strange rights"); 1807 } 1808 1809 return TRUE; 1810} 1811 1812/* 1813 * Routine: ipc_right_copyin 1814 * Purpose: 1815 * Copyin a capability from a space. 1816 * If successful, the caller gets a ref 1817 * for the resulting object, unless it is IO_DEAD, 1818 * and possibly a send-once right which should 1819 * be used in a port-deleted notification. 1820 * 1821 * If deadok is not TRUE, the copyin operation 1822 * will fail instead of producing IO_DEAD. 1823 * 1824 * The entry is never deallocated (except 1825 * when KERN_INVALID_NAME), so the caller 1826 * should deallocate the entry if its type 1827 * is MACH_PORT_TYPE_NONE. 1828 * Conditions: 1829 * The space is write-locked and active. 1830 * Returns: 1831 * KERN_SUCCESS Acquired an object, possibly IO_DEAD. 1832 * KERN_INVALID_RIGHT Name doesn't denote correct right. 1833 */ 1834 1835kern_return_t 1836ipc_right_copyin( 1837 ipc_space_t space, 1838 mach_port_name_t name, 1839 ipc_entry_t entry, 1840 mach_msg_type_name_t msgt_name, 1841 boolean_t deadok, 1842 ipc_object_t *objectp, 1843 ipc_port_t *sorightp, 1844 ipc_port_t *releasep, 1845#if IMPORTANCE_INHERITANCE 1846 int *assertcntp, 1847#endif /* IMPORTANCE_INHERITANCE */ 1848 queue_t links) 1849{ 1850 ipc_entry_bits_t bits; 1851 ipc_port_t port; 1852#if CONFIG_MACF_MACH 1853 task_t self = current_task(); 1854 int rc; 1855#endif 1856 1857 *releasep = IP_NULL; 1858 1859#if IMPORTANCE_INHERITANCE 1860 *assertcntp = 0; 1861#endif 1862 1863 bits = entry->ie_bits; 1864 1865 assert(is_active(space)); 1866 1867 switch (msgt_name) { 1868 case MACH_MSG_TYPE_MAKE_SEND: { 1869 1870 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) 1871 goto invalid_right; 1872 1873 port = (ipc_port_t) entry->ie_object; 1874 assert(port != IP_NULL); 1875 1876 ip_lock(port); 1877 assert(ip_active(port)); 1878 assert(port->ip_receiver_name == name); 1879 assert(port->ip_receiver == space); 1880 1881#if CONFIG_MACF_MACH 1882 tasklabel_lock(self); 1883 rc = mac_port_check_make_send(&self->maclabel, &port->ip_label); 1884 tasklabel_unlock(self); 1885 if (rc) { 1886 ip_unlock(port); 1887 return KERN_NO_ACCESS; 1888 } 1889#endif 1890 1891 port->ip_mscount++; 1892 port->ip_srights++; 1893 ip_reference(port); 1894 ip_unlock(port); 1895 1896 *objectp = (ipc_object_t) port; 1897 *sorightp = IP_NULL; 1898 break; 1899 } 1900 1901 case MACH_MSG_TYPE_MAKE_SEND_ONCE: { 1902 1903 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) 1904 goto invalid_right; 1905 1906 port = (ipc_port_t) entry->ie_object; 1907 assert(port != IP_NULL); 1908 1909 ip_lock(port); 1910 assert(ip_active(port)); 1911 assert(port->ip_receiver_name == name); 1912 assert(port->ip_receiver == space); 1913 1914#if CONFIG_MACF_MACH 1915 tasklabel_lock(self); 1916 rc = mac_port_check_make_send_once(&self->maclabel, &port->ip_label); 1917 tasklabel_unlock(self); 1918 if (rc) { 1919 ip_unlock(port); 1920 return KERN_NO_ACCESS; 1921 } 1922#endif 1923 1924 port->ip_sorights++; 1925 ip_reference(port); 1926 ip_unlock(port); 1927 1928 *objectp = (ipc_object_t) port; 1929 *sorightp = IP_NULL; 1930 break; 1931 } 1932 1933 case MACH_MSG_TYPE_MOVE_RECEIVE: { 1934 ipc_port_t request = IP_NULL; 1935 1936 if ((bits & MACH_PORT_TYPE_RECEIVE) == 0) 1937 goto invalid_right; 1938 1939 port = (ipc_port_t) entry->ie_object; 1940 assert(port != IP_NULL); 1941 1942 ip_lock(port); 1943 assert(ip_active(port)); 1944 assert(port->ip_receiver_name == name); 1945 assert(port->ip_receiver == space); 1946 1947#if CONFIG_MACF_MACH 1948 tasklabel_lock(self); 1949 rc = mac_port_check_move_receive(&self->maclabel, 1950 &port->ip_label); 1951 tasklabel_unlock(self); 1952 if (rc) { 1953 ip_unlock(port); 1954 return KERN_NO_ACCESS; 1955 } 1956#endif 1957 1958 if (bits & MACH_PORT_TYPE_SEND) { 1959 assert(IE_BITS_TYPE(bits) == 1960 MACH_PORT_TYPE_SEND_RECEIVE); 1961 assert(IE_BITS_UREFS(bits) > 0); 1962 assert(port->ip_srights > 0); 1963 1964 ipc_hash_insert(space, (ipc_object_t) port, 1965 name, entry); 1966 ip_reference(port); 1967 } else { 1968 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE); 1969 assert(IE_BITS_UREFS(bits) == 0); 1970 1971 request = ipc_right_request_cancel_macro(space, port, 1972 name, entry); 1973 entry->ie_object = IO_NULL; 1974 } 1975 entry->ie_bits = bits &~ MACH_PORT_TYPE_RECEIVE; 1976 ipc_entry_modified(space, name, entry); 1977 1978 ipc_port_clear_receiver(port, links); 1979 port->ip_receiver_name = MACH_PORT_NULL; 1980 port->ip_destination = IP_NULL; 1981 1982#if IMPORTANCE_INHERITANCE 1983 /* 1984 * Account for boosts the current task is going to lose when 1985 * copying this right in. Tempowner ports have either not 1986 * been accounting to any task (and therefore are already in 1987 * "limbo" state w.r.t. assertions) or to some other specific 1988 * task. As we have no way to drop the latter task's assertions 1989 * here, We'll deduct those when we enqueue it on its 1990 * destination port (see ipc_port_check_circularity()). 1991 */ 1992 if (port->ip_tempowner == 0) { 1993 assert(port->ip_taskptr == 0); 1994 1995 /* ports in limbo have to be tempowner */ 1996 port->ip_tempowner = 1; 1997 *assertcntp = port->ip_impcount; 1998 } 1999#endif /* IMPORTANCE_INHERITANCE */ 2000 2001 ip_unlock(port); 2002 2003 *objectp = (ipc_object_t) port; 2004 *sorightp = request; 2005 break; 2006 } 2007 2008 case MACH_MSG_TYPE_COPY_SEND: { 2009 2010 if (bits & MACH_PORT_TYPE_DEAD_NAME) 2011 goto copy_dead; 2012 2013 /* allow for dead send-once rights */ 2014 2015 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) 2016 goto invalid_right; 2017 2018 assert(IE_BITS_UREFS(bits) > 0); 2019 2020 port = (ipc_port_t) entry->ie_object; 2021 assert(port != IP_NULL); 2022 2023 if (ipc_right_check(space, port, name, entry)) { 2024 bits = entry->ie_bits; 2025 *releasep = port; 2026 goto copy_dead; 2027 } 2028 /* port is locked and active */ 2029 2030#if CONFIG_MACF_MACH 2031 tasklabel_lock(self); 2032 rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label); 2033 tasklabel_unlock(self); 2034 if (rc) { 2035 ip_unlock(port); 2036 return KERN_NO_ACCESS; 2037 } 2038#endif 2039 2040 if ((bits & MACH_PORT_TYPE_SEND) == 0) { 2041 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); 2042 assert(port->ip_sorights > 0); 2043 2044 ip_unlock(port); 2045 goto invalid_right; 2046 } 2047 2048 assert(port->ip_srights > 0); 2049 2050 port->ip_srights++; 2051 ip_reference(port); 2052 ip_unlock(port); 2053 2054 *objectp = (ipc_object_t) port; 2055 *sorightp = IP_NULL; 2056 break; 2057 } 2058 2059 case MACH_MSG_TYPE_MOVE_SEND: { 2060 ipc_port_t request = IP_NULL; 2061 2062 if (bits & MACH_PORT_TYPE_DEAD_NAME) 2063 goto move_dead; 2064 2065 /* allow for dead send-once rights */ 2066 2067 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) 2068 goto invalid_right; 2069 2070 assert(IE_BITS_UREFS(bits) > 0); 2071 2072 port = (ipc_port_t) entry->ie_object; 2073 assert(port != IP_NULL); 2074 2075 if (ipc_right_check(space, port, name, entry)) { 2076 bits = entry->ie_bits; 2077 *releasep = port; 2078 goto move_dead; 2079 } 2080 /* port is locked and active */ 2081 2082#if CONFIG_MACF_MACH 2083 tasklabel_lock (self); 2084 rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label); 2085 tasklabel_unlock (self); 2086 if (rc) 2087 { 2088 ip_unlock (port); 2089 return KERN_NO_ACCESS; 2090 } 2091#endif 2092 2093 if ((bits & MACH_PORT_TYPE_SEND) == 0) { 2094 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); 2095 assert(port->ip_sorights > 0); 2096 2097 ip_unlock(port); 2098 goto invalid_right; 2099 } 2100 2101 assert(port->ip_srights > 0); 2102 2103 if (IE_BITS_UREFS(bits) == 1) { 2104 if (bits & MACH_PORT_TYPE_RECEIVE) { 2105 assert(port->ip_receiver_name == name); 2106 assert(port->ip_receiver == space); 2107 assert(IE_BITS_TYPE(bits) == 2108 MACH_PORT_TYPE_SEND_RECEIVE); 2109 2110 ip_reference(port); 2111 } else { 2112 assert(IE_BITS_TYPE(bits) == 2113 MACH_PORT_TYPE_SEND); 2114 2115 request = ipc_right_request_cancel_macro(space, port, 2116 name, entry); 2117 ipc_hash_delete(space, (ipc_object_t) port, 2118 name, entry); 2119 entry->ie_object = IO_NULL; 2120 } 2121 entry->ie_bits = bits &~ 2122 (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND); 2123 } else { 2124 port->ip_srights++; 2125 ip_reference(port); 2126 entry->ie_bits = bits-1; /* decrement urefs */ 2127 } 2128 ipc_entry_modified(space, name, entry); 2129 ip_unlock(port); 2130 2131 *objectp = (ipc_object_t) port; 2132 *sorightp = request; 2133 break; 2134 } 2135 2136 case MACH_MSG_TYPE_MOVE_SEND_ONCE: { 2137 ipc_port_t request; 2138 2139 if (bits & MACH_PORT_TYPE_DEAD_NAME) 2140 goto move_dead; 2141 2142 /* allow for dead send rights */ 2143 2144 if ((bits & MACH_PORT_TYPE_SEND_RIGHTS) == 0) 2145 goto invalid_right; 2146 2147 assert(IE_BITS_UREFS(bits) > 0); 2148 2149 port = (ipc_port_t) entry->ie_object; 2150 assert(port != IP_NULL); 2151 2152 if (ipc_right_check(space, port, name, entry)) { 2153 bits = entry->ie_bits; 2154 goto move_dead; 2155 } 2156 /* port is locked and active */ 2157 2158#if CONFIG_MACF_MACH 2159 tasklabel_lock (self); 2160 rc = mac_port_check_copy_send (&self->maclabel, &port->ip_label); 2161 tasklabel_unlock (self); 2162 if (rc) 2163 { 2164 ip_unlock (port); 2165 return KERN_NO_ACCESS; 2166 } 2167#endif 2168 2169 if ((bits & MACH_PORT_TYPE_SEND_ONCE) == 0) { 2170 assert(bits & MACH_PORT_TYPE_SEND); 2171 assert(port->ip_srights > 0); 2172 2173 ip_unlock(port); 2174 goto invalid_right; 2175 } 2176 2177 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); 2178 assert(IE_BITS_UREFS(bits) == 1); 2179 assert(port->ip_sorights > 0); 2180 2181 request = ipc_right_request_cancel_macro(space, port, name, entry); 2182 ip_unlock(port); 2183 2184 entry->ie_object = IO_NULL; 2185 entry->ie_bits = bits &~ 2186 (IE_BITS_UREFS_MASK | MACH_PORT_TYPE_SEND_ONCE); 2187 ipc_entry_modified(space, name, entry); 2188 *objectp = (ipc_object_t) port; 2189 *sorightp = request; 2190 break; 2191 } 2192 2193 default: 2194 invalid_right: 2195 return KERN_INVALID_RIGHT; 2196 } 2197 2198 return KERN_SUCCESS; 2199 2200 copy_dead: 2201 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); 2202 assert(IE_BITS_UREFS(bits) > 0); 2203 assert(entry->ie_request == IE_REQ_NONE); 2204 assert(entry->ie_object == 0); 2205 2206 if (!deadok) 2207 goto invalid_right; 2208 2209 *objectp = IO_DEAD; 2210 *sorightp = IP_NULL; 2211 return KERN_SUCCESS; 2212 2213 move_dead: 2214 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); 2215 assert(IE_BITS_UREFS(bits) > 0); 2216 assert(entry->ie_request == IE_REQ_NONE); 2217 assert(entry->ie_object == 0); 2218 2219 if (!deadok) 2220 goto invalid_right; 2221 2222 if (IE_BITS_UREFS(bits) == 1) { 2223 bits &= ~MACH_PORT_TYPE_DEAD_NAME; 2224 } 2225 entry->ie_bits = bits-1; /* decrement urefs */ 2226 ipc_entry_modified(space, name, entry); 2227 *objectp = IO_DEAD; 2228 *sorightp = IP_NULL; 2229 return KERN_SUCCESS; 2230 2231} 2232 2233/* 2234 * Routine: ipc_right_copyin_undo 2235 * Purpose: 2236 * Undoes the effects of an ipc_right_copyin 2237 * of a send/send-once right that is dead. 2238 * (Object is either IO_DEAD or a dead port.) 2239 * Conditions: 2240 * The space is write-locked and active. 2241 */ 2242 2243void 2244ipc_right_copyin_undo( 2245 ipc_space_t space, 2246 mach_port_name_t name, 2247 ipc_entry_t entry, 2248 mach_msg_type_name_t msgt_name, 2249 ipc_object_t object, 2250 ipc_port_t soright) 2251{ 2252 ipc_entry_bits_t bits; 2253 2254 bits = entry->ie_bits; 2255 2256 assert(is_active(space)); 2257 2258 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) || 2259 (msgt_name == MACH_MSG_TYPE_COPY_SEND) || 2260 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE)); 2261 2262 if (soright != IP_NULL) { 2263 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) || 2264 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE)); 2265 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); 2266 assert(object != IO_DEAD); 2267 2268 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) | 2269 MACH_PORT_TYPE_DEAD_NAME | 2); 2270 2271 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE) { 2272 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) || 2273 (msgt_name == MACH_MSG_TYPE_MOVE_SEND_ONCE)); 2274 2275 entry->ie_bits = ((bits &~ IE_BITS_RIGHT_MASK) | 2276 MACH_PORT_TYPE_DEAD_NAME | 1); 2277 } else if (IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME) { 2278 assert(object == IO_DEAD); 2279 assert(IE_BITS_UREFS(bits) > 0); 2280 2281 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) { 2282 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX); 2283 entry->ie_bits = bits+1; /* increment urefs */ 2284 } 2285 } else { 2286 assert((msgt_name == MACH_MSG_TYPE_MOVE_SEND) || 2287 (msgt_name == MACH_MSG_TYPE_COPY_SEND)); 2288 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); 2289 assert(object != IO_DEAD); 2290 assert(entry->ie_object == object); 2291 assert(IE_BITS_UREFS(bits) > 0); 2292 2293 if (msgt_name != MACH_MSG_TYPE_COPY_SEND) { 2294 assert(IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX-1); 2295 entry->ie_bits = bits+1; /* increment urefs */ 2296 } 2297 2298 /* 2299 * May as well convert the entry to a dead name. 2300 * (Or if it is a compat entry, destroy it.) 2301 */ 2302 2303 (void) ipc_right_check(space, (ipc_port_t) object, 2304 name, entry); 2305 /* object is dead so it is not locked */ 2306 } 2307 ipc_entry_modified(space, name, entry); 2308 /* release the reference acquired by copyin */ 2309 2310 if (object != IO_DEAD) 2311 io_release(object); 2312} 2313 2314/* 2315 * Routine: ipc_right_copyin_two 2316 * Purpose: 2317 * Like ipc_right_copyin with MACH_MSG_TYPE_MOVE_SEND 2318 * and deadok == FALSE, except that this moves two 2319 * send rights at once. 2320 * Conditions: 2321 * The space is write-locked and active. 2322 * The object is returned with two refs/send rights. 2323 * Returns: 2324 * KERN_SUCCESS Acquired an object. 2325 * KERN_INVALID_RIGHT Name doesn't denote correct right. 2326 */ 2327 2328kern_return_t 2329ipc_right_copyin_two( 2330 ipc_space_t space, 2331 mach_port_name_t name, 2332 ipc_entry_t entry, 2333 ipc_object_t *objectp, 2334 ipc_port_t *sorightp, 2335 ipc_port_t *releasep) 2336{ 2337 ipc_entry_bits_t bits; 2338 mach_port_urefs_t urefs; 2339 ipc_port_t port; 2340 ipc_port_t request = IP_NULL; 2341#if CONFIG_MACF_MACH 2342 task_t self = current_task(); 2343 int rc; 2344#endif 2345 2346 *releasep = IP_NULL; 2347 2348 assert(is_active(space)); 2349 2350 bits = entry->ie_bits; 2351 2352 if ((bits & MACH_PORT_TYPE_SEND) == 0) 2353 goto invalid_right; 2354 2355 urefs = IE_BITS_UREFS(bits); 2356 if (urefs < 2) 2357 goto invalid_right; 2358 2359 port = (ipc_port_t) entry->ie_object; 2360 assert(port != IP_NULL); 2361 2362 if (ipc_right_check(space, port, name, entry)) { 2363 *releasep = port; 2364 goto invalid_right; 2365 } 2366 /* port is locked and active */ 2367 2368#if CONFIG_MACF_MACH 2369 tasklabel_lock(self); 2370 rc = mac_port_check_copy_send(&self->maclabel, &port->ip_label); 2371 tasklabel_unlock(self); 2372 if (rc) { 2373 ip_unlock(port); 2374 return KERN_NO_ACCESS; 2375 } 2376#endif 2377 2378 assert(port->ip_srights > 0); 2379 2380 if (urefs == 2) { 2381 if (bits & MACH_PORT_TYPE_RECEIVE) { 2382 assert(port->ip_receiver_name == name); 2383 assert(port->ip_receiver == space); 2384 assert(IE_BITS_TYPE(bits) == 2385 MACH_PORT_TYPE_SEND_RECEIVE); 2386 2387 port->ip_srights++; 2388 ip_reference(port); 2389 ip_reference(port); 2390 } else { 2391 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); 2392 2393 request = ipc_right_request_cancel_macro(space, port, 2394 name, entry); 2395 2396 port->ip_srights++; 2397 ip_reference(port); 2398 ipc_hash_delete(space, (ipc_object_t) port, 2399 name, entry); 2400 entry->ie_object = IO_NULL; 2401 } 2402 entry->ie_bits = bits &~ (IE_BITS_UREFS_MASK|MACH_PORT_TYPE_SEND); 2403 } else { 2404 port->ip_srights += 2; 2405 ip_reference(port); 2406 ip_reference(port); 2407 entry->ie_bits = bits-2; /* decrement urefs */ 2408 } 2409 ipc_entry_modified(space, name, entry); 2410 2411 ip_unlock(port); 2412 2413 *objectp = (ipc_object_t) port; 2414 *sorightp = request; 2415 return KERN_SUCCESS; 2416 2417 invalid_right: 2418 return KERN_INVALID_RIGHT; 2419} 2420 2421/* 2422 * Routine: ipc_right_copyout 2423 * Purpose: 2424 * Copyout a capability to a space. 2425 * If successful, consumes a ref for the object. 2426 * 2427 * Always succeeds when given a newly-allocated entry, 2428 * because user-reference overflow isn't a possibility. 2429 * 2430 * If copying out the object would cause the user-reference 2431 * count in the entry to overflow, and overflow is TRUE, 2432 * then instead the user-reference count is left pegged 2433 * to its maximum value and the copyout succeeds anyway. 2434 * Conditions: 2435 * The space is write-locked and active. 2436 * The object is locked and active. 2437 * The object is unlocked; the space isn't. 2438 * Returns: 2439 * KERN_SUCCESS Copied out capability. 2440 * KERN_UREFS_OVERFLOW User-refs would overflow; 2441 * guaranteed not to happen with a fresh entry 2442 * or if overflow=TRUE was specified. 2443 */ 2444 2445kern_return_t 2446ipc_right_copyout( 2447 ipc_space_t space, 2448 mach_port_name_t name, 2449 ipc_entry_t entry, 2450 mach_msg_type_name_t msgt_name, 2451 boolean_t overflow, 2452 ipc_object_t object) 2453{ 2454 ipc_entry_bits_t bits; 2455 ipc_port_t port; 2456#if CONFIG_MACF_MACH 2457 int rc; 2458#endif 2459 2460 bits = entry->ie_bits; 2461 2462 assert(IO_VALID(object)); 2463 assert(io_otype(object) == IOT_PORT); 2464 assert(io_active(object)); 2465 assert(entry->ie_object == object); 2466 2467 port = (ipc_port_t) object; 2468 2469 switch (msgt_name) { 2470 case MACH_MSG_TYPE_PORT_SEND_ONCE: 2471 2472 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); 2473 assert(port->ip_sorights > 0); 2474 2475#if CONFIG_MACF_MACH 2476 if (space->is_task) { 2477 tasklabel_lock(space->is_task); 2478 rc = mac_port_check_hold_send_once(&space->is_task->maclabel, 2479 &port->ip_label); 2480 tasklabel_unlock(space->is_task); 2481 2482 if (rc) { 2483 ip_unlock(port); 2484 return KERN_NO_ACCESS; 2485 } 2486 } 2487#endif 2488 /* transfer send-once right and ref to entry */ 2489 ip_unlock(port); 2490 2491 entry->ie_bits = bits | (MACH_PORT_TYPE_SEND_ONCE | 1); 2492 ipc_entry_modified(space, name, entry); 2493 break; 2494 2495 case MACH_MSG_TYPE_PORT_SEND: 2496 assert(port->ip_srights > 0); 2497 2498#if CONFIG_MACF_MACH 2499 if (space->is_task) { 2500 tasklabel_lock(space->is_task); 2501 rc = mac_port_check_hold_send(&space->is_task->maclabel, 2502 &port->ip_label); 2503 tasklabel_unlock(space->is_task); 2504 2505 if (rc) { 2506 ip_unlock(port); 2507 return KERN_NO_ACCESS; 2508 } 2509 } 2510#endif 2511 2512 if (bits & MACH_PORT_TYPE_SEND) { 2513 mach_port_urefs_t urefs = IE_BITS_UREFS(bits); 2514 2515 assert(port->ip_srights > 1); 2516 assert(urefs > 0); 2517 assert(urefs < MACH_PORT_UREFS_MAX); 2518 2519 if (urefs+1 == MACH_PORT_UREFS_MAX) { 2520 if (overflow) { 2521 /* leave urefs pegged to maximum */ 2522 2523 port->ip_srights--; 2524 ip_unlock(port); 2525 ip_release(port); 2526 return KERN_SUCCESS; 2527 } 2528 2529 ip_unlock(port); 2530 return KERN_UREFS_OVERFLOW; 2531 } 2532 port->ip_srights--; 2533 ip_unlock(port); 2534 ip_release(port); 2535 2536 } else if (bits & MACH_PORT_TYPE_RECEIVE) { 2537 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_RECEIVE); 2538 assert(IE_BITS_UREFS(bits) == 0); 2539 2540 /* transfer send right to entry */ 2541 ip_unlock(port); 2542 ip_release(port); 2543 2544 } else { 2545 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); 2546 assert(IE_BITS_UREFS(bits) == 0); 2547 2548 /* transfer send right and ref to entry */ 2549 ip_unlock(port); 2550 2551 /* entry is locked holding ref, so can use port */ 2552 2553 ipc_hash_insert(space, (ipc_object_t) port, 2554 name, entry); 2555 } 2556 2557 entry->ie_bits = (bits | MACH_PORT_TYPE_SEND) + 1; 2558 ipc_entry_modified(space, name, entry); 2559 break; 2560 2561 case MACH_MSG_TYPE_PORT_RECEIVE: { 2562 ipc_port_t dest; 2563 2564#if IMPORTANCE_INHERITANCE 2565 natural_t assertcnt = port->ip_impcount; 2566#endif /* IMPORTANCE_INHERITANCE */ 2567 2568 assert(port->ip_mscount == 0); 2569 assert(port->ip_receiver_name == MACH_PORT_NULL); 2570 dest = port->ip_destination; 2571 2572#if CONFIG_MACF_MACH 2573 if (space->is_task) { 2574 tasklabel_lock(space->is_task); 2575 rc = mac_port_check_hold_receive(&space->is_task->maclabel, 2576 &port->ip_label); 2577 tasklabel_unlock(space->is_task); 2578 2579 if (rc) { 2580 ip_unlock(port); 2581 return KERN_NO_ACCESS; 2582 } 2583 } 2584#endif 2585 2586 port->ip_receiver_name = name; 2587 port->ip_receiver = space; 2588 2589 assert((bits & MACH_PORT_TYPE_RECEIVE) == 0); 2590 2591 if (bits & MACH_PORT_TYPE_SEND) { 2592 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND); 2593 assert(IE_BITS_UREFS(bits) > 0); 2594 assert(port->ip_srights > 0); 2595 2596 ip_unlock(port); 2597 ip_release(port); 2598 2599 /* entry is locked holding ref, so can use port */ 2600 2601 ipc_hash_delete(space, (ipc_object_t) port, 2602 name, entry); 2603 } else { 2604 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_NONE); 2605 assert(IE_BITS_UREFS(bits) == 0); 2606 2607 /* transfer ref to entry */ 2608 ip_unlock(port); 2609 } 2610 entry->ie_bits = bits | MACH_PORT_TYPE_RECEIVE; 2611 ipc_entry_modified(space, name, entry); 2612 2613 if (dest != IP_NULL) { 2614#if IMPORTANCE_INHERITANCE 2615 /* 2616 * Deduct the assertion counts we contributed to 2617 * the old destination port. They've already 2618 * been reflected into the task as a result of 2619 * getting enqueued. 2620 */ 2621 ip_lock(dest); 2622 assert(dest->ip_impcount >= assertcnt); 2623 dest->ip_impcount -= assertcnt; 2624 ip_unlock(dest); 2625#endif /* IMPORTANCE_INHERITANCE */ 2626 ip_release(dest); 2627 } 2628 break; 2629 } 2630 2631 default: 2632 panic("ipc_right_copyout: strange rights"); 2633 } 2634 return KERN_SUCCESS; 2635} 2636 2637/* 2638 * Routine: ipc_right_rename 2639 * Purpose: 2640 * Transfer an entry from one name to another. 2641 * The old entry is deallocated. 2642 * Conditions: 2643 * The space is write-locked and active. 2644 * The new entry is unused. Upon return, 2645 * the space is unlocked. 2646 * Returns: 2647 * KERN_SUCCESS Moved entry to new name. 2648 */ 2649 2650kern_return_t 2651ipc_right_rename( 2652 ipc_space_t space, 2653 mach_port_name_t oname, 2654 ipc_entry_t oentry, 2655 mach_port_name_t nname, 2656 ipc_entry_t nentry) 2657{ 2658 ipc_port_request_index_t request = oentry->ie_request; 2659 ipc_entry_bits_t bits = oentry->ie_bits; 2660 ipc_object_t object = oentry->ie_object; 2661 ipc_port_t release_port = IP_NULL; 2662 2663 assert(is_active(space)); 2664 assert(oname != nname); 2665 2666 /* 2667 * If IE_BITS_COMPAT, we can't allow the entry to be renamed 2668 * if the port is dead. (This would foil ipc_port_destroy.) 2669 * Instead we should fail because oentry shouldn't exist. 2670 * Note IE_BITS_COMPAT implies ie_request != 0. 2671 */ 2672 2673 if (request != IE_REQ_NONE) { 2674 ipc_port_t port; 2675 2676 assert(bits & MACH_PORT_TYPE_PORT_RIGHTS); 2677 port = (ipc_port_t) object; 2678 assert(port != IP_NULL); 2679 2680 if (ipc_right_check(space, port, oname, oentry)) { 2681 request = IE_REQ_NONE; 2682 object = IO_NULL; 2683 bits = oentry->ie_bits; 2684 release_port = port; 2685 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_DEAD_NAME); 2686 assert(oentry->ie_request == IE_REQ_NONE); 2687 } else { 2688 /* port is locked and active */ 2689 2690 ipc_port_request_rename(port, request, oname, nname); 2691 ip_unlock(port); 2692 oentry->ie_request = IE_REQ_NONE; 2693 } 2694 } 2695 2696 /* initialize nentry before letting ipc_hash_insert see it */ 2697 2698 assert((nentry->ie_bits & IE_BITS_RIGHT_MASK) == 0); 2699 nentry->ie_bits |= bits & IE_BITS_RIGHT_MASK; 2700 nentry->ie_request = request; 2701 nentry->ie_object = object; 2702 2703 switch (IE_BITS_TYPE(bits)) { 2704 case MACH_PORT_TYPE_SEND: { 2705 ipc_port_t port; 2706 2707 port = (ipc_port_t) object; 2708 assert(port != IP_NULL); 2709 2710 /* remember, there are no other share entries possible */ 2711 /* or we can't do the rename. Therefore we do not need */ 2712 /* to check the other subspaces */ 2713 ipc_hash_delete(space, (ipc_object_t) port, oname, oentry); 2714 ipc_hash_insert(space, (ipc_object_t) port, nname, nentry); 2715 break; 2716 } 2717 2718 case MACH_PORT_TYPE_RECEIVE: 2719 case MACH_PORT_TYPE_SEND_RECEIVE: { 2720 ipc_port_t port; 2721 2722 port = (ipc_port_t) object; 2723 assert(port != IP_NULL); 2724 2725 ip_lock(port); 2726 assert(ip_active(port)); 2727 assert(port->ip_receiver_name == oname); 2728 assert(port->ip_receiver == space); 2729 2730 port->ip_receiver_name = nname; 2731 ip_unlock(port); 2732 break; 2733 } 2734 2735 case MACH_PORT_TYPE_PORT_SET: { 2736 ipc_pset_t pset; 2737 2738 pset = (ipc_pset_t) object; 2739 assert(pset != IPS_NULL); 2740 2741 ips_lock(pset); 2742 assert(ips_active(pset)); 2743 assert(pset->ips_local_name == oname); 2744 2745 pset->ips_local_name = nname; 2746 ips_unlock(pset); 2747 break; 2748 } 2749 2750 case MACH_PORT_TYPE_SEND_ONCE: 2751 case MACH_PORT_TYPE_DEAD_NAME: 2752 break; 2753 2754 default: 2755 panic("ipc_right_rename: strange rights"); 2756 } 2757 2758 assert(oentry->ie_request == IE_REQ_NONE); 2759 oentry->ie_object = IO_NULL; 2760 ipc_entry_dealloc(space, oname, oentry); 2761 ipc_entry_modified(space, nname, nentry); 2762 is_write_unlock(space); 2763 2764 if (release_port != IP_NULL) 2765 ip_release(release_port); 2766 2767 return KERN_SUCCESS; 2768} 2769