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