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_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_object.c 67 * Author: Rich Draves 68 * Date: 1989 69 * 70 * Functions to manipulate IPC objects. 71 */ 72 73#include <mach_rt.h> 74 75#include <mach/mach_types.h> 76#include <mach/boolean.h> 77#include <mach/kern_return.h> 78#include <mach/port.h> 79#include <mach/message.h> 80 81#include <kern/kern_types.h> 82#include <kern/misc_protos.h> 83#include <kern/ipc_kobject.h> 84 85#include <ipc/ipc_types.h> 86#include <ipc/ipc_importance.h> 87#include <ipc/port.h> 88#include <ipc/ipc_space.h> 89#include <ipc/ipc_entry.h> 90#include <ipc/ipc_object.h> 91#include <ipc/ipc_hash.h> 92#include <ipc/ipc_right.h> 93#include <ipc/ipc_notify.h> 94#include <ipc/ipc_port.h> 95#include <ipc/ipc_pset.h> 96 97#include <security/mac_mach_internal.h> 98 99zone_t ipc_object_zones[IOT_NUMBER]; 100 101/* 102 * Routine: ipc_object_reference 103 * Purpose: 104 * Take a reference to an object. 105 */ 106 107void 108ipc_object_reference( 109 ipc_object_t object) 110{ 111 io_reference(object); 112} 113 114/* 115 * Routine: ipc_object_release 116 * Purpose: 117 * Release a reference to an object. 118 */ 119 120void 121ipc_object_release( 122 ipc_object_t object) 123{ 124 io_release(object); 125} 126 127/* 128 * Routine: ipc_object_translate 129 * Purpose: 130 * Look up an object in a space. 131 * Conditions: 132 * Nothing locked before. If successful, the object 133 * is returned locked. The caller doesn't get a ref. 134 * Returns: 135 * KERN_SUCCESS Object returned locked. 136 * KERN_INVALID_TASK The space is dead. 137 * KERN_INVALID_NAME The name doesn't denote a right. 138 * KERN_INVALID_RIGHT Name doesn't denote the correct right. 139 */ 140 141kern_return_t 142ipc_object_translate( 143 ipc_space_t space, 144 mach_port_name_t name, 145 mach_port_right_t right, 146 ipc_object_t *objectp) 147{ 148 ipc_entry_t entry; 149 ipc_object_t object; 150 kern_return_t kr; 151 152 kr = ipc_right_lookup_read(space, name, &entry); 153 if (kr != KERN_SUCCESS) 154 return kr; 155 /* space is read-locked and active */ 156 157 if ((entry->ie_bits & MACH_PORT_TYPE(right)) == MACH_PORT_TYPE_NONE) { 158 is_read_unlock(space); 159 return KERN_INVALID_RIGHT; 160 } 161 162 object = entry->ie_object; 163 assert(object != IO_NULL); 164 165 io_lock(object); 166 is_read_unlock(space); 167 168 *objectp = object; 169 return KERN_SUCCESS; 170} 171 172/* 173 * Routine: ipc_object_translate_two 174 * Purpose: 175 * Look up two objects in a space. 176 * Conditions: 177 * Nothing locked before. If successful, the objects 178 * are returned locked. The caller doesn't get a ref. 179 * Returns: 180 * KERN_SUCCESS Objects returned locked. 181 * KERN_INVALID_TASK The space is dead. 182 * KERN_INVALID_NAME A name doesn't denote a right. 183 * KERN_INVALID_RIGHT A name doesn't denote the correct right. 184 */ 185 186kern_return_t 187ipc_object_translate_two( 188 ipc_space_t space, 189 mach_port_name_t name1, 190 mach_port_right_t right1, 191 ipc_object_t *objectp1, 192 mach_port_name_t name2, 193 mach_port_right_t right2, 194 ipc_object_t *objectp2) 195{ 196 ipc_entry_t entry1; 197 ipc_entry_t entry2; 198 ipc_object_t object; 199 kern_return_t kr; 200 201 kr = ipc_right_lookup_two_read(space, name1, &entry1, name2, &entry2); 202 if (kr != KERN_SUCCESS) 203 return kr; 204 /* space is read-locked and active */ 205 206 if ((entry1->ie_bits & MACH_PORT_TYPE(right1)) == MACH_PORT_TYPE_NONE) { 207 is_read_unlock(space); 208 return KERN_INVALID_RIGHT; 209 } 210 211 if ((entry2->ie_bits & MACH_PORT_TYPE(right2)) == MACH_PORT_TYPE_NONE) { 212 is_read_unlock(space); 213 return KERN_INVALID_RIGHT; 214 } 215 216 object = entry1->ie_object; 217 assert(object != IO_NULL); 218 io_lock(object); 219 *objectp1 = object; 220 221 object = entry2->ie_object; 222 assert(object != IO_NULL); 223 io_lock(object); 224 *objectp2 = object; 225 226 is_read_unlock(space); 227 return KERN_SUCCESS; 228} 229 230/* 231 * Routine: ipc_object_alloc_dead 232 * Purpose: 233 * Allocate a dead-name entry. 234 * Conditions: 235 * Nothing locked. 236 * Returns: 237 * KERN_SUCCESS The dead name is allocated. 238 * KERN_INVALID_TASK The space is dead. 239 * KERN_NO_SPACE No room for an entry in the space. 240 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 241 */ 242 243kern_return_t 244ipc_object_alloc_dead( 245 ipc_space_t space, 246 mach_port_name_t *namep) 247{ 248 ipc_entry_t entry; 249 kern_return_t kr; 250 251 kr = ipc_entry_alloc(space, namep, &entry); 252 if (kr != KERN_SUCCESS) 253 return kr; 254 /* space is write-locked */ 255 256 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */ 257 258 assert(entry->ie_object == IO_NULL); 259 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1; 260 ipc_entry_modified(space, *namep, entry); 261 is_write_unlock(space); 262 return KERN_SUCCESS; 263} 264 265/* 266 * Routine: ipc_object_alloc_dead_name 267 * Purpose: 268 * Allocate a dead-name entry, with a specific name. 269 * Conditions: 270 * Nothing locked. 271 * Returns: 272 * KERN_SUCCESS The dead name is allocated. 273 * KERN_INVALID_TASK The space is dead. 274 * KERN_NAME_EXISTS The name already denotes a right. 275 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 276 */ 277 278kern_return_t 279ipc_object_alloc_dead_name( 280 ipc_space_t space, 281 mach_port_name_t name) 282{ 283 ipc_entry_t entry; 284 kern_return_t kr; 285 286 kr = ipc_entry_alloc_name(space, name, &entry); 287 if (kr != KERN_SUCCESS) 288 return kr; 289 /* space is write-locked */ 290 291 if (ipc_right_inuse(space, name, entry)) 292 return KERN_NAME_EXISTS; 293 294 /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */ 295 296 assert(entry->ie_object == IO_NULL); 297 entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1; 298 ipc_entry_modified(space, name, entry); 299 is_write_unlock(space); 300 return KERN_SUCCESS; 301} 302 303/* 304 * Routine: ipc_object_alloc 305 * Purpose: 306 * Allocate an object. 307 * Conditions: 308 * Nothing locked. If successful, the object is returned locked. 309 * The space is write locked on successful return. 310 * The caller doesn't get a reference for the object. 311 * Returns: 312 * KERN_SUCCESS The object is allocated. 313 * KERN_INVALID_TASK The space is dead. 314 * KERN_NO_SPACE No room for an entry in the space. 315 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 316 */ 317 318kern_return_t 319ipc_object_alloc( 320 ipc_space_t space, 321 ipc_object_type_t otype, 322 mach_port_type_t type, 323 mach_port_urefs_t urefs, 324 mach_port_name_t *namep, 325 ipc_object_t *objectp) 326{ 327 ipc_object_t object; 328 ipc_entry_t entry; 329 kern_return_t kr; 330 331 assert(otype < IOT_NUMBER); 332 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type); 333 assert(type != MACH_PORT_TYPE_NONE); 334 assert(urefs <= MACH_PORT_UREFS_MAX); 335 336 object = io_alloc(otype); 337 if (object == IO_NULL) 338 return KERN_RESOURCE_SHORTAGE; 339 340 if (otype == IOT_PORT) { 341 ipc_port_t port = (ipc_port_t)object; 342 343 bzero((char *)port, sizeof(*port)); 344 } else if (otype == IOT_PORT_SET) { 345 ipc_pset_t pset = (ipc_pset_t)object; 346 347 bzero((char *)pset, sizeof(*pset)); 348 } 349 350 io_lock_init(object); 351 *namep = CAST_MACH_PORT_TO_NAME(object); 352 kr = ipc_entry_alloc(space, namep, &entry); 353 if (kr != KERN_SUCCESS) { 354 io_free(otype, object); 355 return kr; 356 } 357 /* space is write-locked */ 358 359 entry->ie_bits |= type | urefs; 360 entry->ie_object = object; 361 ipc_entry_modified(space, *namep, entry); 362 363 io_lock(object); 364 365 object->io_references = 1; /* for entry, not caller */ 366 object->io_bits = io_makebits(TRUE, otype, 0); 367 368 *objectp = object; 369 return KERN_SUCCESS; 370} 371 372/* 373 * Routine: ipc_object_alloc_name 374 * Purpose: 375 * Allocate an object, with a specific name. 376 * Conditions: 377 * Nothing locked. If successful, the object is returned locked. 378 * The caller doesn't get a reference for the object. 379 * Returns: 380 * KERN_SUCCESS The object is allocated. 381 * KERN_INVALID_TASK The space is dead. 382 * KERN_NAME_EXISTS The name already denotes a right. 383 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 384 */ 385 386kern_return_t 387ipc_object_alloc_name( 388 ipc_space_t space, 389 ipc_object_type_t otype, 390 mach_port_type_t type, 391 mach_port_urefs_t urefs, 392 mach_port_name_t name, 393 ipc_object_t *objectp) 394{ 395 ipc_object_t object; 396 ipc_entry_t entry; 397 kern_return_t kr; 398 399 assert(otype < IOT_NUMBER); 400 assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type); 401 assert(type != MACH_PORT_TYPE_NONE); 402 assert(urefs <= MACH_PORT_UREFS_MAX); 403 404 object = io_alloc(otype); 405 if (object == IO_NULL) 406 return KERN_RESOURCE_SHORTAGE; 407 408 if (otype == IOT_PORT) { 409 ipc_port_t port = (ipc_port_t)object; 410 411 bzero((char *)port, sizeof(*port)); 412 } else if (otype == IOT_PORT_SET) { 413 ipc_pset_t pset = (ipc_pset_t)object; 414 415 bzero((char *)pset, sizeof(*pset)); 416 } 417 418 io_lock_init(object); 419 kr = ipc_entry_alloc_name(space, name, &entry); 420 if (kr != KERN_SUCCESS) { 421 io_free(otype, object); 422 return kr; 423 } 424 /* space is write-locked */ 425 426 if (ipc_right_inuse(space, name, entry)) { 427 io_free(otype, object); 428 return KERN_NAME_EXISTS; 429 } 430 431 entry->ie_bits |= type | urefs; 432 entry->ie_object = object; 433 ipc_entry_modified(space, name, entry); 434 435 io_lock(object); 436 is_write_unlock(space); 437 438 object->io_references = 1; /* for entry, not caller */ 439 object->io_bits = io_makebits(TRUE, otype, 0); 440 441 *objectp = object; 442 return KERN_SUCCESS; 443} 444 445/* 446 * Routine: ipc_object_copyin_type 447 * Purpose: 448 * Convert a send type name to a received type name. 449 */ 450 451mach_msg_type_name_t 452ipc_object_copyin_type( 453 mach_msg_type_name_t msgt_name) 454{ 455 switch (msgt_name) { 456 457 case MACH_MSG_TYPE_MOVE_RECEIVE: 458 return MACH_MSG_TYPE_PORT_RECEIVE; 459 460 case MACH_MSG_TYPE_MOVE_SEND_ONCE: 461 case MACH_MSG_TYPE_MAKE_SEND_ONCE: 462 return MACH_MSG_TYPE_PORT_SEND_ONCE; 463 464 case MACH_MSG_TYPE_MOVE_SEND: 465 case MACH_MSG_TYPE_MAKE_SEND: 466 case MACH_MSG_TYPE_COPY_SEND: 467 return MACH_MSG_TYPE_PORT_SEND; 468 469 case MACH_MSG_TYPE_DISPOSE_RECEIVE: 470 case MACH_MSG_TYPE_DISPOSE_SEND: 471 case MACH_MSG_TYPE_DISPOSE_SEND_ONCE: 472 /* fall thru */ 473 default: 474 return MACH_MSG_TYPE_PORT_NONE; 475 } 476} 477 478/* 479 * Routine: ipc_object_copyin 480 * Purpose: 481 * Copyin a capability from a space. 482 * If successful, the caller gets a ref 483 * for the resulting object, unless it is IO_DEAD. 484 * Conditions: 485 * Nothing locked. 486 * Returns: 487 * KERN_SUCCESS Acquired an object, possibly IO_DEAD. 488 * KERN_INVALID_TASK The space is dead. 489 * KERN_INVALID_NAME Name doesn't exist in space. 490 * KERN_INVALID_RIGHT Name doesn't denote correct right. 491 */ 492 493kern_return_t 494ipc_object_copyin( 495 ipc_space_t space, 496 mach_port_name_t name, 497 mach_msg_type_name_t msgt_name, 498 ipc_object_t *objectp) 499{ 500 ipc_entry_t entry; 501 ipc_port_t soright; 502 ipc_port_t release_port; 503 kern_return_t kr; 504 queue_head_t links_data; 505 queue_t links = &links_data; 506 wait_queue_link_t wql; 507 508#if IMPORTANCE_INHERITANCE 509 int assertcnt = 0; 510#endif 511 512 queue_init(links); 513 514 /* 515 * Could first try a read lock when doing 516 * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND, 517 * and MACH_MSG_TYPE_MAKE_SEND_ONCE. 518 */ 519 520 kr = ipc_right_lookup_write(space, name, &entry); 521 if (kr != KERN_SUCCESS) 522 return kr; 523 /* space is write-locked and active */ 524 525 release_port = IP_NULL; 526 kr = ipc_right_copyin(space, name, entry, 527 msgt_name, TRUE, 528 objectp, &soright, 529 &release_port, 530#if IMPORTANCE_INHERITANCE 531 &assertcnt, 532#endif /* IMPORTANCE_INHERITANCE */ 533 links); 534 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) 535 ipc_entry_dealloc(space, name, entry); 536 is_write_unlock(space); 537 538 while(!queue_empty(links)) { 539 wql = (wait_queue_link_t) dequeue(links); 540 wait_queue_link_free(wql); 541 } 542 543#if IMPORTANCE_INHERITANCE 544 if (0 < assertcnt && ipc_importance_task_is_any_receiver_type(current_task()->task_imp_base)) { 545 ipc_importance_task_drop_internal_assertion(current_task()->task_imp_base, assertcnt); 546 } 547#endif /* IMPORTANCE_INHERITANCE */ 548 549 if (release_port != IP_NULL) 550 ip_release(release_port); 551 552 if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) 553 ipc_notify_port_deleted(soright, name); 554 555 return kr; 556} 557 558/* 559 * Routine: ipc_object_copyin_from_kernel 560 * Purpose: 561 * Copyin a naked capability from the kernel. 562 * 563 * MACH_MSG_TYPE_MOVE_RECEIVE 564 * The receiver must be ipc_space_kernel 565 * or the receive right must already be in limbo. 566 * Consumes the naked receive right. 567 * MACH_MSG_TYPE_COPY_SEND 568 * A naked send right must be supplied. 569 * The port gains a reference, and a send right 570 * if the port is still active. 571 * MACH_MSG_TYPE_MAKE_SEND 572 * The receiver must be ipc_space_kernel. 573 * The port gains a reference and a send right. 574 * MACH_MSG_TYPE_MOVE_SEND 575 * Consumes a naked send right. 576 * MACH_MSG_TYPE_MAKE_SEND_ONCE 577 * The port gains a reference and a send-once right. 578 * Receiver also be the caller of device subsystem, 579 * so no assertion. 580 * MACH_MSG_TYPE_MOVE_SEND_ONCE 581 * Consumes a naked send-once right. 582 * Conditions: 583 * Nothing locked. 584 */ 585 586void 587ipc_object_copyin_from_kernel( 588 ipc_object_t object, 589 mach_msg_type_name_t msgt_name) 590{ 591 assert(IO_VALID(object)); 592 593 switch (msgt_name) { 594 case MACH_MSG_TYPE_MOVE_RECEIVE: { 595 ipc_port_t port = (ipc_port_t) object; 596 597 ip_lock(port); 598 assert(ip_active(port)); 599 if (port->ip_destination != IP_NULL) { 600 assert(port->ip_receiver == ipc_space_kernel); 601 602 /* relevant part of ipc_port_clear_receiver */ 603 ipc_port_set_mscount(port, 0); 604 605 port->ip_receiver_name = MACH_PORT_NULL; 606 port->ip_destination = IP_NULL; 607 } 608 ip_unlock(port); 609 break; 610 } 611 612 case MACH_MSG_TYPE_COPY_SEND: { 613 ipc_port_t port = (ipc_port_t) object; 614 615 ip_lock(port); 616 if (ip_active(port)) { 617 assert(port->ip_srights > 0); 618 port->ip_srights++; 619 } 620 ip_reference(port); 621 ip_unlock(port); 622 break; 623 } 624 625 case MACH_MSG_TYPE_MAKE_SEND: { 626 ipc_port_t port = (ipc_port_t) object; 627 628 ip_lock(port); 629 if (ip_active(port)) { 630 assert(port->ip_receiver_name != MACH_PORT_NULL); 631 assert(port->ip_receiver == ipc_space_kernel); 632 port->ip_mscount++; 633 } 634 635 port->ip_srights++; 636 ip_reference(port); 637 ip_unlock(port); 638 break; 639 } 640 641 case MACH_MSG_TYPE_MOVE_SEND: { 642 /* move naked send right into the message */ 643 assert(((ipc_port_t)object)->ip_srights); 644 break; 645 } 646 647 case MACH_MSG_TYPE_MAKE_SEND_ONCE: { 648 ipc_port_t port = (ipc_port_t) object; 649 650 ip_lock(port); 651 if (ip_active(port)) { 652 assert(port->ip_receiver_name != MACH_PORT_NULL); 653 } 654 port->ip_sorights++; 655 ip_reference(port); 656 ip_unlock(port); 657 break; 658 } 659 660 case MACH_MSG_TYPE_MOVE_SEND_ONCE: { 661 /* move naked send-once right into the message */ 662 assert(((ipc_port_t)object)->ip_sorights); 663 break; 664 } 665 666 default: 667 panic("ipc_object_copyin_from_kernel: strange rights"); 668 } 669} 670 671/* 672 * Routine: ipc_object_destroy 673 * Purpose: 674 * Destroys a naked capability. 675 * Consumes a ref for the object. 676 * 677 * A receive right should be in limbo or in transit. 678 * Conditions: 679 * Nothing locked. 680 */ 681 682void 683ipc_object_destroy( 684 ipc_object_t object, 685 mach_msg_type_name_t msgt_name) 686{ 687 assert(IO_VALID(object)); 688 assert(io_otype(object) == IOT_PORT); 689 690 switch (msgt_name) { 691 case MACH_MSG_TYPE_PORT_SEND: 692 ipc_port_release_send((ipc_port_t) object); 693 break; 694 695 case MACH_MSG_TYPE_PORT_SEND_ONCE: 696 ipc_notify_send_once((ipc_port_t) object); 697 break; 698 699 case MACH_MSG_TYPE_PORT_RECEIVE: 700 ipc_port_release_receive((ipc_port_t) object); 701 break; 702 703 default: 704 panic("ipc_object_destroy: strange rights"); 705 } 706} 707 708/* 709 * Routine: ipc_object_destroy_dest 710 * Purpose: 711 * Destroys a naked capability for the destination of 712 * of a message. Consumes a ref for the object. 713 * 714 * Conditions: 715 * Nothing locked. 716 */ 717 718void 719ipc_object_destroy_dest( 720 ipc_object_t object, 721 mach_msg_type_name_t msgt_name) 722{ 723 assert(IO_VALID(object)); 724 assert(io_otype(object) == IOT_PORT); 725 726 switch (msgt_name) { 727 case MACH_MSG_TYPE_PORT_SEND: 728 ipc_port_release_send((ipc_port_t) object); 729 break; 730 731 case MACH_MSG_TYPE_PORT_SEND_ONCE: 732 if (io_active(object) && 733 !ip_full_kernel((ipc_port_t) object)) 734 ipc_notify_send_once((ipc_port_t) object); 735 else 736 ipc_port_release_sonce((ipc_port_t) object); 737 break; 738 739 default: 740 panic("ipc_object_destroy_dest: strange rights"); 741 } 742} 743 744/* 745 * Routine: ipc_object_copyout 746 * Purpose: 747 * Copyout a capability, placing it into a space. 748 * If successful, consumes a ref for the object. 749 * Conditions: 750 * Nothing locked. 751 * Returns: 752 * KERN_SUCCESS Copied out object, consumed ref. 753 * KERN_INVALID_TASK The space is dead. 754 * KERN_INVALID_CAPABILITY The object is dead. 755 * KERN_NO_SPACE No room in space for another right. 756 * KERN_RESOURCE_SHORTAGE No memory available. 757 * KERN_UREFS_OVERFLOW Urefs limit exceeded 758 * and overflow wasn't specified. 759 */ 760 761kern_return_t 762ipc_object_copyout( 763 ipc_space_t space, 764 ipc_object_t object, 765 mach_msg_type_name_t msgt_name, 766 boolean_t overflow, 767 mach_port_name_t *namep) 768{ 769 mach_port_name_t name; 770 ipc_entry_t entry; 771 kern_return_t kr; 772 773 assert(IO_VALID(object)); 774 assert(io_otype(object) == IOT_PORT); 775 776 is_write_lock(space); 777 778 for (;;) { 779 if (!is_active(space)) { 780 is_write_unlock(space); 781 return KERN_INVALID_TASK; 782 } 783 784 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && 785 ipc_right_reverse(space, object, &name, &entry)) { 786 /* object is locked and active */ 787 788 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); 789 break; 790 } 791 792 name = CAST_MACH_PORT_TO_NAME(object); 793 kr = ipc_entry_get(space, &name, &entry); 794 if (kr != KERN_SUCCESS) { 795 /* unlocks/locks space, so must start again */ 796 797 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE); 798 if (kr != KERN_SUCCESS) 799 return kr; /* space is unlocked */ 800 801 continue; 802 } 803 804 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); 805 assert(entry->ie_object == IO_NULL); 806 807 io_lock(object); 808 if (!io_active(object)) { 809 io_unlock(object); 810 ipc_entry_dealloc(space, name, entry); 811 is_write_unlock(space); 812 return KERN_INVALID_CAPABILITY; 813 } 814 815 entry->ie_object = object; 816 break; 817 } 818 819 /* space is write-locked and active, object is locked and active */ 820 821 kr = ipc_right_copyout(space, name, entry, 822 msgt_name, overflow, object); 823 824 /* object is unlocked */ 825 is_write_unlock(space); 826 827 if (kr == KERN_SUCCESS) 828 *namep = name; 829 return kr; 830} 831 832/* 833 * Routine: ipc_object_copyout_name 834 * Purpose: 835 * Copyout a capability, placing it into a space. 836 * The specified name is used for the capability. 837 * If successful, consumes a ref for the object. 838 * Conditions: 839 * Nothing locked. 840 * Returns: 841 * KERN_SUCCESS Copied out object, consumed ref. 842 * KERN_INVALID_TASK The space is dead. 843 * KERN_INVALID_CAPABILITY The object is dead. 844 * KERN_RESOURCE_SHORTAGE No memory available. 845 * KERN_UREFS_OVERFLOW Urefs limit exceeded 846 * and overflow wasn't specified. 847 * KERN_RIGHT_EXISTS Space has rights under another name. 848 * KERN_NAME_EXISTS Name is already used. 849 */ 850 851kern_return_t 852ipc_object_copyout_name( 853 ipc_space_t space, 854 ipc_object_t object, 855 mach_msg_type_name_t msgt_name, 856 boolean_t overflow, 857 mach_port_name_t name) 858{ 859 mach_port_name_t oname; 860 ipc_entry_t oentry; 861 ipc_entry_t entry; 862 kern_return_t kr; 863 864#if IMPORTANCE_INHERITANCE 865 int assertcnt = 0; 866 ipc_importance_task_t task_imp = IIT_NULL; 867#endif /* IMPORTANCE_INHERITANCE */ 868 869 assert(IO_VALID(object)); 870 assert(io_otype(object) == IOT_PORT); 871 872 kr = ipc_entry_alloc_name(space, name, &entry); 873 if (kr != KERN_SUCCESS) 874 return kr; 875 /* space is write-locked and active */ 876 877 if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && 878 ipc_right_reverse(space, object, &oname, &oentry)) { 879 /* object is locked and active */ 880 881 if (name != oname) { 882 io_unlock(object); 883 884 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) 885 ipc_entry_dealloc(space, name, entry); 886 887 is_write_unlock(space); 888 return KERN_RIGHT_EXISTS; 889 } 890 891 assert(entry == oentry); 892 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); 893 } else { 894 if (ipc_right_inuse(space, name, entry)) 895 return KERN_NAME_EXISTS; 896 897 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); 898 assert(entry->ie_object == IO_NULL); 899 900 io_lock(object); 901 if (!io_active(object)) { 902 io_unlock(object); 903 ipc_entry_dealloc(space, name, entry); 904 is_write_unlock(space); 905 return KERN_INVALID_CAPABILITY; 906 } 907 908 entry->ie_object = object; 909 } 910 911 /* space is write-locked and active, object is locked and active */ 912 913#if IMPORTANCE_INHERITANCE 914 /* 915 * We are slamming a receive right into the space, without 916 * first having been enqueued on a port destined there. So, 917 * we have to arrange to boost the task appropriately if this 918 * port has assertions (and the task wants them). 919 */ 920 if (msgt_name == MACH_MSG_TYPE_PORT_RECEIVE) { 921 ipc_port_t port = (ipc_port_t)object; 922 923 if (space->is_task != TASK_NULL) { 924 task_imp = space->is_task->task_imp_base; 925 if (ipc_importance_task_is_any_receiver_type(task_imp)) { 926 assertcnt = port->ip_impcount; 927 ipc_importance_task_reference(task_imp); 928 } 929 } 930 931 /* take port out of limbo */ 932 assert(port->ip_tempowner != 0); 933 port->ip_tempowner = 0; 934 } 935 936#endif /* IMPORTANCE_INHERITANCE */ 937 938 kr = ipc_right_copyout(space, name, entry, 939 msgt_name, overflow, object); 940 941 /* object is unlocked */ 942 is_write_unlock(space); 943 944#if IMPORTANCE_INHERITANCE 945 /* 946 * Add the assertions to the task that we captured before 947 */ 948 if (task_imp != IIT_NULL) { 949 ipc_importance_task_hold_internal_assertion(task_imp, assertcnt); 950 ipc_importance_task_release(task_imp); 951 } 952#endif /* IMPORTANCE_INHERITANCE */ 953 954 return kr; 955} 956 957/* 958 * Routine: ipc_object_copyout_dest 959 * Purpose: 960 * Translates/consumes the destination right of a message. 961 * This is unlike normal copyout because the right is consumed 962 * in a funny way instead of being given to the receiving space. 963 * The receiver gets his name for the port, if he has receive 964 * rights, otherwise MACH_PORT_NULL. 965 * Conditions: 966 * The object is locked and active. Nothing else locked. 967 * The object is unlocked and loses a reference. 968 */ 969 970void 971ipc_object_copyout_dest( 972 ipc_space_t space, 973 ipc_object_t object, 974 mach_msg_type_name_t msgt_name, 975 mach_port_name_t *namep) 976{ 977 mach_port_name_t name; 978 979 assert(IO_VALID(object)); 980 assert(io_active(object)); 981 982 io_release(object); 983 984 /* 985 * If the space is the receiver/owner of the object, 986 * then we quietly consume the right and return 987 * the space's name for the object. Otherwise 988 * we destroy the right and return MACH_PORT_NULL. 989 */ 990 991 switch (msgt_name) { 992 case MACH_MSG_TYPE_PORT_SEND: { 993 ipc_port_t port = (ipc_port_t) object; 994 ipc_port_t nsrequest = IP_NULL; 995 mach_port_mscount_t mscount; 996 997 if (port->ip_receiver == space) 998 name = port->ip_receiver_name; 999 else 1000 name = MACH_PORT_NULL; 1001 1002 assert(port->ip_srights > 0); 1003 if (--port->ip_srights == 0 && 1004 port->ip_nsrequest != IP_NULL) { 1005 nsrequest = port->ip_nsrequest; 1006 port->ip_nsrequest = IP_NULL; 1007 mscount = port->ip_mscount; 1008 ip_unlock(port); 1009 ipc_notify_no_senders(nsrequest, mscount); 1010 } else 1011 ip_unlock(port); 1012 break; 1013 } 1014 1015 case MACH_MSG_TYPE_PORT_SEND_ONCE: { 1016 ipc_port_t port = (ipc_port_t) object; 1017 1018 assert(port->ip_sorights > 0); 1019 1020 if (port->ip_receiver == space) { 1021 /* quietly consume the send-once right */ 1022 1023 port->ip_sorights--; 1024 name = port->ip_receiver_name; 1025 ip_unlock(port); 1026 } else { 1027 /* 1028 * A very bizarre case. The message 1029 * was received, but before this copyout 1030 * happened the space lost receive rights. 1031 * We can't quietly consume the soright 1032 * out from underneath some other task, 1033 * so generate a send-once notification. 1034 */ 1035 1036 ip_reference(port); /* restore ref */ 1037 ip_unlock(port); 1038 1039 ipc_notify_send_once(port); 1040 name = MACH_PORT_NULL; 1041 } 1042 1043 break; 1044 } 1045 1046 default: 1047 panic("ipc_object_copyout_dest: strange rights"); 1048 name = MACH_PORT_DEAD; 1049 } 1050 1051 *namep = name; 1052} 1053 1054/* 1055 * Routine: ipc_object_rename 1056 * Purpose: 1057 * Rename an entry in a space. 1058 * Conditions: 1059 * Nothing locked. 1060 * Returns: 1061 * KERN_SUCCESS Renamed the entry. 1062 * KERN_INVALID_TASK The space was dead. 1063 * KERN_INVALID_NAME oname didn't denote an entry. 1064 * KERN_NAME_EXISTS nname already denoted an entry. 1065 * KERN_RESOURCE_SHORTAGE Couldn't allocate new entry. 1066 */ 1067 1068kern_return_t 1069ipc_object_rename( 1070 ipc_space_t space, 1071 mach_port_name_t oname, 1072 mach_port_name_t nname) 1073{ 1074 ipc_entry_t oentry, nentry; 1075 kern_return_t kr; 1076 1077 kr = ipc_entry_alloc_name(space, nname, &nentry); 1078 if (kr != KERN_SUCCESS) 1079 return kr; 1080 1081 /* space is write-locked and active */ 1082 1083 if (ipc_right_inuse(space, nname, nentry)) { 1084 /* space is unlocked */ 1085 return KERN_NAME_EXISTS; 1086 } 1087 1088 /* don't let ipc_entry_lookup see the uninitialized new entry */ 1089 1090 if ((oname == nname) || 1091 ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) { 1092 ipc_entry_dealloc(space, nname, nentry); 1093 is_write_unlock(space); 1094 return KERN_INVALID_NAME; 1095 } 1096 1097 kr = ipc_right_rename(space, oname, oentry, nname, nentry); 1098 /* space is unlocked */ 1099 return kr; 1100} 1101 1102/* 1103 * Check whether the object is a port if so, free it. But 1104 * keep track of that fact. 1105 */ 1106void 1107io_free( 1108 unsigned int otype, 1109 ipc_object_t object) 1110{ 1111 ipc_port_t port; 1112 1113 if (otype == IOT_PORT) { 1114 port = (ipc_port_t) object; 1115 ipc_port_finalize(port); 1116 } 1117 io_lock_destroy(object); 1118 zfree(ipc_object_zones[otype], object); 1119} 1120