|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990 ! 27: * Open Software Foundation, Inc. ! 28: * ! 29: * Permission to use, copy, modify, and distribute this software and ! 30: * its documentation for any purpose and without fee is hereby granted, ! 31: * provided that the above copyright notice appears in all copies and ! 32: * that both the copyright notice and this permission notice appear in ! 33: * supporting documentation, and that the name of ("OSF") or Open Software ! 34: * Foundation not be used in advertising or publicity pertaining to ! 35: * distribution of the software without specific, written prior permission. ! 36: * ! 37: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 38: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ! 39: * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY ! 40: * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! 41: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ! 42: * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING ! 43: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! 44: */ ! 45: /* ! 46: * OSF Research Institute MK6.1 (unencumbered) 1/31/1995 ! 47: */ ! 48: /* ! 49: * Mach Operating System ! 50: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 51: * All Rights Reserved. ! 52: * ! 53: * Permission to use, copy, modify and distribute this software and its ! 54: * documentation is hereby granted, provided that both the copyright ! 55: * notice and this permission notice appear in all copies of the ! 56: * software, derivative works or modified versions, and any portions ! 57: * thereof, and that both notices appear in supporting documentation. ! 58: * ! 59: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 60: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 61: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 62: * ! 63: * Carnegie Mellon requests users of this software to return to ! 64: * ! 65: * Software Distribution Coordinator or [email protected] ! 66: * School of Computer Science ! 67: * Carnegie Mellon University ! 68: * Pittsburgh PA 15213-3890 ! 69: * ! 70: * any improvements or extensions that they make and grant Carnegie Mellon ! 71: * the rights to redistribute these changes. ! 72: */ ! 73: /* ! 74: * File: ipc/ipc_object.c ! 75: * Author: Rich Draves ! 76: * Date: 1989 ! 77: * ! 78: * Functions to manipulate IPC objects. ! 79: */ ! 80: ! 81: #import <mach/features.h> ! 82: ! 83: #include <mach/boolean.h> ! 84: #include <mach/kern_return.h> ! 85: #include <mach/port.h> ! 86: #include <mach/message.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: ! 95: zone_t ipc_object_zones[IOT_NUMBER]; ! 96: ! 97: /* ! 98: * Routine: ipc_object_reference ! 99: * Purpose: ! 100: * Take a reference to an object. ! 101: */ ! 102: ! 103: void ! 104: ipc_object_reference( ! 105: ipc_object_t object) ! 106: { ! 107: io_lock(object); ! 108: assert(object->io_references > 0); ! 109: io_reference(object); ! 110: io_unlock(object); ! 111: } ! 112: ! 113: /* ! 114: * Routine: ipc_object_release ! 115: * Purpose: ! 116: * Release a reference to an object. ! 117: */ ! 118: ! 119: void ! 120: ipc_object_release( ! 121: ipc_object_t object) ! 122: { ! 123: io_lock(object); ! 124: assert(object->io_references > 0); ! 125: io_release(object); ! 126: io_check_unlock(object); ! 127: } ! 128: ! 129: /* ! 130: * Routine: ipc_object_translate ! 131: * Purpose: ! 132: * Look up an object in a space. ! 133: * Conditions: ! 134: * Nothing locked before. If successful, the object ! 135: * is returned locked. The caller doesn't get a ref. ! 136: * Returns: ! 137: * KERN_SUCCESS Objected returned locked. ! 138: * KERN_INVALID_TASK The space is dead. ! 139: * KERN_INVALID_NAME The name doesn't denote a right. ! 140: * KERN_INVALID_RIGHT Name doesn't denote the correct right. ! 141: */ ! 142: ! 143: kern_return_t ! 144: ipc_object_translate( ! 145: ipc_space_t space, ! 146: mach_port_t name, ! 147: mach_port_right_t right, ! 148: ipc_object_t *objectp) ! 149: { ! 150: ipc_entry_t entry; ! 151: ipc_object_t object; ! 152: kern_return_t kr; ! 153: ! 154: kr = ipc_right_lookup_read(space, name, &entry); ! 155: if (kr != KERN_SUCCESS) ! 156: return kr; ! 157: /* space is read-locked and active */ ! 158: ! 159: if ((entry->ie_bits & MACH_PORT_TYPE(right)) == 0) { ! 160: is_read_unlock(space); ! 161: return KERN_INVALID_RIGHT; ! 162: } ! 163: ! 164: object = entry->ie_object; ! 165: assert(object != IO_NULL); ! 166: ! 167: io_lock(object); ! 168: is_read_unlock(space); ! 169: ! 170: *objectp = object; ! 171: return KERN_SUCCESS; ! 172: } ! 173: ! 174: /* ! 175: * Routine: ipc_object_alloc_dead ! 176: * Purpose: ! 177: * Allocate a dead-name entry. ! 178: * Conditions: ! 179: * Nothing locked. ! 180: * Returns: ! 181: * KERN_SUCCESS The dead name is allocated. ! 182: * KERN_INVALID_TASK The space is dead. ! 183: * KERN_NO_SPACE No room for an entry in the space. ! 184: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 185: */ ! 186: ! 187: kern_return_t ! 188: ipc_object_alloc_dead( ! 189: ipc_space_t space, ! 190: mach_port_t *namep) ! 191: { ! 192: ipc_entry_t entry; ! 193: kern_return_t kr; ! 194: ! 195: kr = ipc_entry_alloc(space, namep, &entry); ! 196: if (kr != KERN_SUCCESS) ! 197: return kr; ! 198: /* space is write-locked */ ! 199: ! 200: /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */ ! 201: ! 202: assert(entry->ie_object == IO_NULL); ! 203: entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1; ! 204: ! 205: is_write_unlock(space); ! 206: return KERN_SUCCESS; ! 207: } ! 208: ! 209: /* ! 210: * Routine: ipc_object_alloc_dead_name ! 211: * Purpose: ! 212: * Allocate a dead-name entry, with a specific name. ! 213: * Conditions: ! 214: * Nothing locked. ! 215: * Returns: ! 216: * KERN_SUCCESS The dead name is allocated. ! 217: * KERN_INVALID_TASK The space is dead. ! 218: * KERN_NAME_EXISTS The name already denotes a right. ! 219: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 220: */ ! 221: ! 222: kern_return_t ! 223: ipc_object_alloc_dead_name( ! 224: ipc_space_t space, ! 225: mach_port_t name) ! 226: { ! 227: ipc_entry_t entry; ! 228: kern_return_t kr; ! 229: ! 230: kr = ipc_entry_alloc_name(space, name, &entry); ! 231: if (kr != KERN_SUCCESS) ! 232: return kr; ! 233: /* space is write-locked */ ! 234: ! 235: if (ipc_right_inuse(space, name, entry)) ! 236: return KERN_NAME_EXISTS; ! 237: ! 238: /* null object, MACH_PORT_TYPE_DEAD_NAME, 1 uref */ ! 239: ! 240: assert(entry->ie_object == IO_NULL); ! 241: entry->ie_bits |= MACH_PORT_TYPE_DEAD_NAME | 1; ! 242: ! 243: is_write_unlock(space); ! 244: return KERN_SUCCESS; ! 245: } ! 246: ! 247: /* ! 248: * Routine: ipc_object_alloc ! 249: * Purpose: ! 250: * Allocate an object. ! 251: * Conditions: ! 252: * Nothing locked. If successful, the object is returned locked. ! 253: * The caller doesn't get a reference for the object. ! 254: * Returns: ! 255: * KERN_SUCCESS The object is allocated. ! 256: * KERN_INVALID_TASK The space is dead. ! 257: * KERN_NO_SPACE No room for an entry in the space. ! 258: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 259: */ ! 260: ! 261: kern_return_t ! 262: ipc_object_alloc( ! 263: ipc_space_t space, ! 264: ipc_object_type_t otype, ! 265: mach_port_type_t type, ! 266: mach_port_urefs_t urefs, ! 267: mach_port_t *namep, ! 268: ipc_object_t *objectp) ! 269: { ! 270: ipc_object_t object; ! 271: ipc_entry_t entry; ! 272: kern_return_t kr; ! 273: ! 274: assert(otype < IOT_NUMBER); ! 275: assert((type & MACH_PORT_TYPE_ALL_RIGHTS) == type); ! 276: assert(type != MACH_PORT_TYPE_NONE); ! 277: assert(urefs <= MACH_PORT_UREFS_MAX); ! 278: ! 279: object = io_alloc(otype); ! 280: if (object == IO_NULL) ! 281: return KERN_RESOURCE_SHORTAGE; ! 282: ! 283: kr = ipc_entry_alloc(space, namep, &entry); ! 284: if (kr != KERN_SUCCESS) { ! 285: io_free(otype, object); ! 286: return kr; ! 287: } ! 288: /* space is write-locked */ ! 289: ! 290: entry->ie_bits |= type | urefs; ! 291: entry->ie_object = object; ! 292: ! 293: io_lock_init(object); ! 294: io_lock(object); ! 295: is_write_unlock(space); ! 296: ! 297: object->io_references = 1; /* for entry, not caller */ ! 298: object->io_bits = io_makebits(TRUE, otype, 0); ! 299: ! 300: *objectp = object; ! 301: return KERN_SUCCESS; ! 302: } ! 303: ! 304: /* ! 305: * Routine: ipc_object_alloc_name ! 306: * Purpose: ! 307: * Allocate an object, with a specific name. ! 308: * Conditions: ! 309: * Nothing locked. If successful, the object is returned locked. ! 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_NAME_EXISTS The name already denotes a right. ! 315: * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. ! 316: */ ! 317: ! 318: kern_return_t ! 319: ipc_object_alloc_name( ! 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_t name, ! 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: kr = ipc_entry_alloc_name(space, name, &entry); ! 341: if (kr != KERN_SUCCESS) { ! 342: io_free(otype, object); ! 343: return kr; ! 344: } ! 345: /* space is write-locked */ ! 346: ! 347: if (ipc_right_inuse(space, name, entry)) { ! 348: io_free(otype, object); ! 349: return KERN_NAME_EXISTS; ! 350: } ! 351: ! 352: entry->ie_bits |= type | urefs; ! 353: entry->ie_object = object; ! 354: ! 355: io_lock_init(object); ! 356: io_lock(object); ! 357: is_write_unlock(space); ! 358: ! 359: object->io_references = 1; /* for entry, not caller */ ! 360: object->io_bits = io_makebits(TRUE, otype, 0); ! 361: ! 362: *objectp = object; ! 363: return KERN_SUCCESS; ! 364: } ! 365: ! 366: /* ! 367: * Routine: ipc_object_copyin_type ! 368: * Purpose: ! 369: * Convert a send type name to a received type name. ! 370: */ ! 371: mach_msg_type_name_t ! 372: ipc_object_copyin_type( ! 373: mach_msg_type_name_t msgt_name) ! 374: { ! 375: switch (msgt_name) { ! 376: case 0: ! 377: return 0; ! 378: ! 379: case MACH_MSG_TYPE_MOVE_RECEIVE: ! 380: return MACH_MSG_TYPE_PORT_RECEIVE; ! 381: ! 382: case MACH_MSG_TYPE_MOVE_SEND_ONCE: ! 383: case MACH_MSG_TYPE_MAKE_SEND_ONCE: ! 384: return MACH_MSG_TYPE_PORT_SEND_ONCE; ! 385: ! 386: case MACH_MSG_TYPE_MOVE_SEND: ! 387: case MACH_MSG_TYPE_MAKE_SEND: ! 388: case MACH_MSG_TYPE_COPY_SEND: ! 389: return MACH_MSG_TYPE_PORT_SEND; ! 390: ! 391: #if MACH_IPC_COMPAT ! 392: case MSG_TYPE_PORT: ! 393: return MACH_MSG_TYPE_PORT_SEND; ! 394: ! 395: case MSG_TYPE_PORT_ALL: ! 396: return MACH_MSG_TYPE_PORT_RECEIVE; ! 397: #endif MACH_IPC_COMPAT ! 398: ! 399: default: ! 400: panic("ipc_object_copyin_type: strange rights"); ! 401: } ! 402: } ! 403: ! 404: /* ! 405: * Routine: ipc_object_copyin ! 406: * Purpose: ! 407: * Copyin a capability from a space. ! 408: * If successful, the caller gets a ref ! 409: * for the resulting object, unless it is IO_DEAD. ! 410: * Conditions: ! 411: * Nothing locked. ! 412: * Returns: ! 413: * KERN_SUCCESS Acquired an object, possibly IO_DEAD. ! 414: * KERN_INVALID_TASK The space is dead. ! 415: * KERN_INVALID_NAME Name doesn't exist in space. ! 416: * KERN_INVALID_RIGHT Name doesn't denote correct right. ! 417: */ ! 418: ! 419: kern_return_t ! 420: ipc_object_copyin( ! 421: ipc_space_t space, ! 422: mach_port_t name, ! 423: mach_msg_type_name_t msgt_name, ! 424: ipc_object_t *objectp) ! 425: { ! 426: ipc_entry_t entry; ! 427: ipc_port_t soright; ! 428: kern_return_t kr; ! 429: ! 430: /* ! 431: * Could first try a read lock when doing ! 432: * MACH_MSG_TYPE_COPY_SEND, MACH_MSG_TYPE_MAKE_SEND, ! 433: * and MACH_MSG_TYPE_MAKE_SEND_ONCE. ! 434: */ ! 435: ! 436: kr = ipc_right_lookup_write(space, name, &entry); ! 437: if (kr != KERN_SUCCESS) ! 438: return kr; ! 439: /* space is write-locked and active */ ! 440: ! 441: kr = ipc_right_copyin(space, name, entry, ! 442: msgt_name, TRUE, ! 443: objectp, &soright); ! 444: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 445: ipc_entry_dealloc(space, name, entry); ! 446: is_write_unlock(space); ! 447: ! 448: if ((kr == KERN_SUCCESS) && (soright != IP_NULL)) ! 449: ipc_notify_port_deleted(soright, name); ! 450: ! 451: return kr; ! 452: } ! 453: ! 454: /* ! 455: * Routine: ipc_object_copyin_from_kernel ! 456: * Purpose: ! 457: * Copyin a naked capability from the kernel. ! 458: * ! 459: * MACH_MSG_TYPE_MOVE_RECEIVE ! 460: * The receiver must be ipc_space_kernel. ! 461: * Consumes the naked receive right. ! 462: * MACH_MSG_TYPE_COPY_SEND ! 463: * A naked send right must be supplied. ! 464: * The port gains a reference, and a send right ! 465: * if the port is still active. ! 466: * MACH_MSG_TYPE_MAKE_SEND ! 467: * The receiver must be ipc_space_kernel. ! 468: * The port gains a reference and a send right. ! 469: * MACH_MSG_TYPE_MOVE_SEND ! 470: * Consumes a naked send right. ! 471: * MACH_MSG_TYPE_MAKE_SEND_ONCE ! 472: * The receiver must be ipc_space_kernel. ! 473: * The port gains a reference and a send-once right. ! 474: * MACH_MSG_TYPE_MOVE_SEND_ONCE ! 475: * Consumes a naked send-once right. ! 476: * Conditions: ! 477: * Nothing locked. ! 478: */ ! 479: ! 480: void ! 481: ipc_object_copyin_from_kernel( ! 482: ipc_object_t object, ! 483: mach_msg_type_name_t msgt_name) ! 484: { ! 485: assert(IO_VALID(object)); ! 486: ! 487: switch (msgt_name) { ! 488: #if MACH_IPC_COMPAT ! 489: case MSG_TYPE_PORT_ALL: ! 490: #endif ! 491: case MACH_MSG_TYPE_MOVE_RECEIVE: { ! 492: ipc_port_t port = (ipc_port_t) object; ! 493: ! 494: ip_lock(port); ! 495: assert(ip_active(port)); ! 496: assert(port->ip_receiver_name != MACH_PORT_NULL); ! 497: assert(port->ip_receiver == ipc_space_kernel); ! 498: ! 499: /* relevant part of ipc_port_clear_receiver */ ! 500: ipc_port_set_mscount(port, 0); ! 501: ! 502: port->ip_receiver_name = MACH_PORT_NULL; ! 503: port->ip_destination = IP_NULL; ! 504: ip_unlock(port); ! 505: break; ! 506: } ! 507: ! 508: #if MACH_IPC_COMPAT ! 509: case MSG_TYPE_PORT: ! 510: #endif ! 511: case MACH_MSG_TYPE_COPY_SEND: { ! 512: ipc_port_t port = (ipc_port_t) object; ! 513: ! 514: ip_lock(port); ! 515: if (ip_active(port)) { ! 516: assert(port->ip_srights > 0); ! 517: port->ip_srights++; ! 518: } ! 519: ip_reference(port); ! 520: ip_unlock(port); ! 521: break; ! 522: } ! 523: ! 524: case MACH_MSG_TYPE_MAKE_SEND: { ! 525: ipc_port_t port = (ipc_port_t) object; ! 526: ! 527: ip_lock(port); ! 528: assert(ip_active(port)); ! 529: assert(port->ip_receiver_name != MACH_PORT_NULL); ! 530: assert(port->ip_receiver == ipc_space_kernel); ! 531: ! 532: ip_reference(port); ! 533: port->ip_mscount++; ! 534: port->ip_srights++; ! 535: ip_unlock(port); ! 536: break; ! 537: } ! 538: ! 539: case MACH_MSG_TYPE_MOVE_SEND: ! 540: /* move naked send right into the message */ ! 541: break; ! 542: ! 543: case MACH_MSG_TYPE_MAKE_SEND_ONCE: { ! 544: ipc_port_t port = (ipc_port_t) object; ! 545: ! 546: ip_lock(port); ! 547: assert(ip_active(port)); ! 548: assert(port->ip_receiver_name != MACH_PORT_NULL); ! 549: assert(port->ip_receiver == ipc_space_kernel); ! 550: ! 551: ip_reference(port); ! 552: port->ip_sorights++; ! 553: ip_unlock(port); ! 554: break; ! 555: } ! 556: ! 557: case MACH_MSG_TYPE_MOVE_SEND_ONCE: ! 558: /* move naked send-once right into the message */ ! 559: break; ! 560: ! 561: default: ! 562: panic("ipc_object_copyin_from_kernel: strange rights"); ! 563: } ! 564: } ! 565: ! 566: /* ! 567: * Routine: ipc_object_destroy ! 568: * Purpose: ! 569: * Destroys a naked capability. ! 570: * Consumes a ref for the object. ! 571: * ! 572: * A receive right should be in limbo or in transit. ! 573: * Conditions: ! 574: * Nothing locked. ! 575: */ ! 576: ! 577: void ! 578: ipc_object_destroy( ! 579: ipc_object_t object, ! 580: mach_msg_type_name_t msgt_name) ! 581: { ! 582: assert(IO_VALID(object)); ! 583: ! 584: switch (msgt_name) { ! 585: case MACH_MSG_TYPE_PORT_SEND: ! 586: assert(io_otype(object) == IOT_PORT); ! 587: ipc_port_release_send((ipc_port_t) object); ! 588: break; ! 589: ! 590: case MACH_MSG_TYPE_PORT_SEND_ONCE: ! 591: assert(io_otype(object) == IOT_PORT); ! 592: ipc_notify_send_once((ipc_port_t) object); ! 593: break; ! 594: ! 595: case MACH_MSG_TYPE_PORT_RECEIVE: ! 596: assert(io_otype(object) == IOT_PORT); ! 597: ipc_port_release_receive((ipc_port_t) object); ! 598: break; ! 599: ! 600: default: ! 601: panic("ipc_object_copyout_dest: strange rights"); ! 602: } ! 603: } ! 604: ! 605: /* ! 606: * Routine: ipc_object_copyout ! 607: * Purpose: ! 608: * Copyout a capability, placing it into a space. ! 609: * If successful, consumes a ref for the object. ! 610: * Conditions: ! 611: * Nothing locked. ! 612: * Returns: ! 613: * KERN_SUCCESS Copied out object, consumed ref. ! 614: * KERN_INVALID_TASK The space is dead. ! 615: * KERN_INVALID_CAPABILITY The object is dead. ! 616: * KERN_NO_SPACE No room in space for another right. ! 617: * KERN_RESOURCE_SHORTAGE No memory available. ! 618: * KERN_UREFS_OVERFLOW Urefs limit exceeded ! 619: * and overflow wasn't specified. ! 620: */ ! 621: ! 622: kern_return_t ! 623: ipc_object_copyout( ! 624: ipc_space_t space, ! 625: ipc_object_t object, ! 626: mach_msg_type_name_t msgt_name, ! 627: boolean_t overflow, ! 628: mach_port_t *namep) ! 629: { ! 630: mach_port_t name; ! 631: ipc_entry_t entry; ! 632: kern_return_t kr; ! 633: ! 634: assert(IO_VALID(object)); ! 635: assert(io_otype(object) == IOT_PORT); ! 636: ! 637: is_write_lock(space); ! 638: ! 639: for (;;) { ! 640: if (!space->is_active) { ! 641: is_write_unlock(space); ! 642: return KERN_INVALID_TASK; ! 643: } ! 644: ! 645: if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && ! 646: ipc_right_reverse(space, object, &name, &entry)) { ! 647: /* object is locked and active */ ! 648: ! 649: assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); ! 650: break; ! 651: } ! 652: ! 653: kr = ipc_entry_get(space, &name, &entry); ! 654: if (kr != KERN_SUCCESS) { ! 655: /* unlocks/locks space, so must start again */ ! 656: ! 657: kr = ipc_entry_grow_table(space, ITS_SIZE_NONE); ! 658: if (kr != KERN_SUCCESS) ! 659: return kr; /* space is unlocked */ ! 660: ! 661: continue; ! 662: } ! 663: ! 664: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); ! 665: assert(entry->ie_object == IO_NULL); ! 666: ! 667: io_lock(object); ! 668: if (!io_active(object)) { ! 669: io_unlock(object); ! 670: ipc_entry_dealloc(space, name, entry); ! 671: is_write_unlock(space); ! 672: return KERN_INVALID_CAPABILITY; ! 673: } ! 674: ! 675: entry->ie_object = object; ! 676: break; ! 677: } ! 678: ! 679: /* space is write-locked and active, object is locked and active */ ! 680: ! 681: kr = ipc_right_copyout(space, name, entry, ! 682: msgt_name, overflow, object); ! 683: /* object is unlocked */ ! 684: is_write_unlock(space); ! 685: ! 686: if (kr == KERN_SUCCESS) ! 687: *namep = name; ! 688: return kr; ! 689: } ! 690: ! 691: /* ! 692: * Routine: ipc_object_copyout_name ! 693: * Purpose: ! 694: * Copyout a capability, placing it into a space. ! 695: * The specified name is used for the capability. ! 696: * If successful, consumes a ref for the object. ! 697: * Conditions: ! 698: * Nothing locked. ! 699: * Returns: ! 700: * KERN_SUCCESS Copied out object, consumed ref. ! 701: * KERN_INVALID_TASK The space is dead. ! 702: * KERN_INVALID_CAPABILITY The object is dead. ! 703: * KERN_RESOURCE_SHORTAGE No memory available. ! 704: * KERN_UREFS_OVERFLOW Urefs limit exceeded ! 705: * and overflow wasn't specified. ! 706: * KERN_RIGHT_EXISTS Space has rights under another name. ! 707: * KERN_NAME_EXISTS Name is already used. ! 708: */ ! 709: ! 710: kern_return_t ! 711: ipc_object_copyout_name( ! 712: ipc_space_t space, ! 713: ipc_object_t object, ! 714: mach_msg_type_name_t msgt_name, ! 715: boolean_t overflow, ! 716: mach_port_t name) ! 717: { ! 718: mach_port_t oname; ! 719: ipc_entry_t oentry; ! 720: ipc_entry_t entry; ! 721: kern_return_t kr; ! 722: ! 723: assert(IO_VALID(object)); ! 724: assert(io_otype(object) == IOT_PORT); ! 725: ! 726: kr = ipc_entry_alloc_name(space, name, &entry); ! 727: if (kr != KERN_SUCCESS) ! 728: return kr; ! 729: /* space is write-locked and active */ ! 730: ! 731: if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && ! 732: ipc_right_reverse(space, object, &oname, &oentry)) { ! 733: /* object is locked and active */ ! 734: ! 735: if (name != oname) { ! 736: io_unlock(object); ! 737: ! 738: if (IE_BITS_TYPE(entry->ie_bits) ! 739: == MACH_PORT_TYPE_NONE) ! 740: ipc_entry_dealloc(space, name, entry); ! 741: ! 742: is_write_unlock(space); ! 743: return KERN_RIGHT_EXISTS; ! 744: } ! 745: ! 746: assert(entry == oentry); ! 747: assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); ! 748: } else { ! 749: if (ipc_right_inuse(space, name, entry)) ! 750: return KERN_NAME_EXISTS; ! 751: ! 752: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); ! 753: assert(entry->ie_object == IO_NULL); ! 754: ! 755: io_lock(object); ! 756: if (!io_active(object)) { ! 757: io_unlock(object); ! 758: ipc_entry_dealloc(space, name, entry); ! 759: is_write_unlock(space); ! 760: return KERN_INVALID_CAPABILITY; ! 761: } ! 762: ! 763: entry->ie_object = object; ! 764: } ! 765: ! 766: /* space is write-locked and active, object is locked and active */ ! 767: ! 768: kr = ipc_right_copyout(space, name, entry, ! 769: msgt_name, overflow, object); ! 770: /* object is unlocked */ ! 771: is_write_unlock(space); ! 772: return kr; ! 773: } ! 774: ! 775: /* ! 776: * Routine: ipc_object_copyout_dest ! 777: * Purpose: ! 778: * Translates/consumes the destination right of a message. ! 779: * This is unlike normal copyout because the right is consumed ! 780: * in a funny way instead of being given to the receiving space. ! 781: * The receiver gets his name for the port, if he has receive ! 782: * rights, otherwise MACH_PORT_NULL. ! 783: * Conditions: ! 784: * The object is locked and active. Nothing else locked. ! 785: * The object is unlocked and loses a reference. ! 786: */ ! 787: ! 788: void ! 789: ipc_object_copyout_dest( ! 790: ipc_space_t space, ! 791: ipc_object_t object, ! 792: mach_msg_type_name_t msgt_name, ! 793: mach_port_t *namep) ! 794: { ! 795: mach_port_t name; ! 796: ! 797: assert(IO_VALID(object)); ! 798: assert(io_active(object)); ! 799: ! 800: io_release(object); ! 801: ! 802: /* ! 803: * If the space is the receiver/owner of the object, ! 804: * then we quietly consume the right and return ! 805: * the space's name for the object. Otherwise ! 806: * we destroy the right and return MACH_PORT_NULL. ! 807: */ ! 808: ! 809: switch (msgt_name) { ! 810: case MACH_MSG_TYPE_PORT_SEND: { ! 811: ipc_port_t port = (ipc_port_t) object; ! 812: ipc_port_t nsrequest = IP_NULL; ! 813: mach_port_mscount_t mscount; ! 814: ! 815: assert(port->ip_srights > 0); ! 816: if (--port->ip_srights == 0) { ! 817: nsrequest = port->ip_nsrequest; ! 818: if (nsrequest != IP_NULL) { ! 819: port->ip_nsrequest = IP_NULL; ! 820: mscount = port->ip_mscount; ! 821: } ! 822: } ! 823: ! 824: if (port->ip_receiver == space) ! 825: name = port->ip_receiver_name; ! 826: else ! 827: name = MACH_PORT_NULL; ! 828: ! 829: ip_unlock(port); ! 830: ! 831: if (nsrequest != IP_NULL) ! 832: ipc_notify_no_senders(nsrequest, mscount); ! 833: ! 834: break; ! 835: } ! 836: ! 837: case MACH_MSG_TYPE_PORT_SEND_ONCE: { ! 838: ipc_port_t port = (ipc_port_t) object; ! 839: ! 840: assert(port->ip_sorights > 0); ! 841: ! 842: if (port->ip_receiver == space) { ! 843: /* quietly consume the send-once right */ ! 844: ! 845: port->ip_sorights--; ! 846: name = port->ip_receiver_name; ! 847: ip_unlock(port); ! 848: } else { ! 849: /* ! 850: * A very bizarre case. The message ! 851: * was received, but before this copyout ! 852: * happened the space lost receive rights. ! 853: * We can't quietly consume the soright ! 854: * out from underneath some other task, ! 855: * so generate a send-once notification. ! 856: */ ! 857: ! 858: ip_reference(port); /* restore ref */ ! 859: ip_unlock(port); ! 860: ! 861: ipc_notify_send_once(port); ! 862: name = MACH_PORT_NULL; ! 863: } ! 864: ! 865: break; ! 866: } ! 867: ! 868: default: ! 869: panic("ipc_object_copyout_dest: strange rights"); ! 870: } ! 871: ! 872: *namep = name; ! 873: } ! 874: ! 875: /* ! 876: * Routine: ipc_object_rename ! 877: * Purpose: ! 878: * Rename an entry in a space. ! 879: * Conditions: ! 880: * Nothing locked. ! 881: * Returns: ! 882: * KERN_SUCCESS Renamed the entry. ! 883: * KERN_INVALID_TASK The space was dead. ! 884: * KERN_INVALID_NAME oname didn't denote an entry. ! 885: * KERN_NAME_EXISTS nname already denoted an entry. ! 886: * KERN_RESOURCE_SHORTAGE Couldn't allocate new entry. ! 887: */ ! 888: ! 889: kern_return_t ! 890: ipc_object_rename( ! 891: ipc_space_t space, ! 892: mach_port_t oname, ! 893: mach_port_t nname) ! 894: { ! 895: ipc_entry_t oentry, nentry; ! 896: kern_return_t kr; ! 897: ! 898: kr = ipc_entry_alloc_name(space, nname, &nentry); ! 899: if (kr != KERN_SUCCESS) ! 900: return kr; ! 901: /* space is write-locked and active */ ! 902: ! 903: if (ipc_right_inuse(space, nname, nentry)) { ! 904: /* space is unlocked */ ! 905: return KERN_NAME_EXISTS; ! 906: } ! 907: ! 908: /* don't let ipc_entry_lookup see the uninitialized new entry */ ! 909: ! 910: if ((oname == nname) || ! 911: ((oentry = ipc_entry_lookup(space, oname)) == IE_NULL)) { ! 912: ipc_entry_dealloc(space, nname, nentry); ! 913: is_write_unlock(space); ! 914: return KERN_INVALID_NAME; ! 915: } ! 916: ! 917: kr = ipc_right_rename(space, oname, oentry, nname, nentry); ! 918: /* space is unlocked */ ! 919: return kr; ! 920: } ! 921: ! 922: #if MACH_IPC_COMPAT ! 923: ! 924: /* ! 925: * Routine: ipc_object_copyout_type_compat ! 926: * Purpose: ! 927: * Convert a carried type name to an old type name. ! 928: */ ! 929: ! 930: mach_msg_type_name_t ! 931: ipc_object_copyout_type_compat( ! 932: mach_msg_type_name_t msgt_name) ! 933: { ! 934: switch (msgt_name) { ! 935: case MACH_MSG_TYPE_PORT_SEND: ! 936: case MACH_MSG_TYPE_PORT_SEND_ONCE: ! 937: return MSG_TYPE_PORT; ! 938: ! 939: case MACH_MSG_TYPE_PORT_RECEIVE: ! 940: return MSG_TYPE_PORT_ALL; ! 941: ! 942: default: ! 943: panic("ipc_object_copyout_type_compat: strange rights"); ! 944: } ! 945: } ! 946: ! 947: /* ! 948: * Routine: ipc_object_copyin_compat ! 949: * Purpose: ! 950: * Copyin a capability from a space. ! 951: * If successful, the caller gets a ref ! 952: * for the resulting object, which is always valid. ! 953: * Conditions: ! 954: * Nothing locked. ! 955: * Returns: ! 956: * KERN_SUCCESS Acquired a valid object. ! 957: * KERN_INVALID_TASK The space is dead. ! 958: * KERN_INVALID_NAME Name doesn't exist in space. ! 959: * KERN_INVALID_RIGHT Name doesn't denote correct right. ! 960: */ ! 961: ! 962: kern_return_t ! 963: ipc_object_copyin_compat( ! 964: ipc_space_t space, ! 965: mach_port_t name, ! 966: mach_msg_type_name_t msgt_name, ! 967: boolean_t dealloc, ! 968: ipc_object_t *objectp) ! 969: { ! 970: ipc_entry_t entry; ! 971: kern_return_t kr; ! 972: ! 973: kr = ipc_right_lookup_write(space, name, &entry); ! 974: if (kr != KERN_SUCCESS) ! 975: return kr; ! 976: /* space is write-locked and active */ ! 977: ! 978: kr = ipc_right_copyin_compat(space, name, entry, ! 979: msgt_name, dealloc, objectp); ! 980: /* space is unlocked */ ! 981: return kr; ! 982: } ! 983: ! 984: /* ! 985: * Routine: ipc_object_copyin_header ! 986: * Purpose: ! 987: * Copyin a capability from a space. ! 988: * If successful, the caller gets a ref ! 989: * for the resulting object, which is always valid. ! 990: * The type of the acquired capability is returned. ! 991: * Conditions: ! 992: * Nothing locked. ! 993: * Returns: ! 994: * KERN_SUCCESS Acquired a valid object. ! 995: * KERN_INVALID_TASK The space is dead. ! 996: * KERN_INVALID_NAME Name doesn't exist in space. ! 997: * KERN_INVALID_RIGHT Name doesn't denote correct right. ! 998: */ ! 999: ! 1000: kern_return_t ! 1001: ipc_object_copyin_header( ! 1002: ipc_space_t space, ! 1003: mach_port_t name, ! 1004: ipc_object_t *objectp, ! 1005: mach_msg_type_name_t *msgt_namep) ! 1006: { ! 1007: ipc_entry_t entry; ! 1008: kern_return_t kr; ! 1009: ! 1010: kr = ipc_right_lookup_write(space, name, &entry); ! 1011: if (kr != KERN_SUCCESS) ! 1012: return kr; ! 1013: /* space is write-locked and active */ ! 1014: ! 1015: kr = ipc_right_copyin_header(space, name, entry, ! 1016: objectp, msgt_namep); ! 1017: /* space is unlocked */ ! 1018: return kr; ! 1019: } ! 1020: ! 1021: /* ! 1022: * Routine: ipc_object_copyout_compat ! 1023: * Purpose: ! 1024: * Copyout a capability, placing it into a space. ! 1025: * If successful, consumes a ref for the object. ! 1026: * ! 1027: * Marks new entries with IE_BITS_COMPAT. ! 1028: * Conditions: ! 1029: * Nothing locked. ! 1030: * Returns: ! 1031: * KERN_SUCCESS Copied out object, consumed ref. ! 1032: * KERN_INVALID_TASK The space is dead. ! 1033: * KERN_INVALID_CAPABILITY The object is dead. ! 1034: * KERN_NO_SPACE No room in space for another right. ! 1035: * KERN_RESOURCE_SHORTAGE No memory available. ! 1036: */ ! 1037: ! 1038: kern_return_t ! 1039: ipc_object_copyout_compat( ! 1040: ipc_space_t space, ! 1041: ipc_object_t object, ! 1042: mach_msg_type_name_t msgt_name, ! 1043: mach_port_t *namep) ! 1044: { ! 1045: mach_port_t name; ! 1046: ipc_entry_t entry; ! 1047: ipc_port_t port; ! 1048: kern_return_t kr; ! 1049: ! 1050: assert(IO_VALID(object)); ! 1051: assert(io_otype(object) == IOT_PORT); ! 1052: port = (ipc_port_t) object; ! 1053: ! 1054: is_write_lock(space); ! 1055: ! 1056: for (;;) { ! 1057: ipc_port_request_index_t request; ! 1058: ! 1059: if (!space->is_active) { ! 1060: is_write_unlock(space); ! 1061: return KERN_INVALID_TASK; ! 1062: } ! 1063: ! 1064: if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && ! 1065: ipc_right_reverse(space, (ipc_object_t) port, ! 1066: &name, &entry)) { ! 1067: /* port is locked and active */ ! 1068: ! 1069: assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE); ! 1070: break; ! 1071: } ! 1072: ! 1073: kr = ipc_entry_get(space, &name, &entry); ! 1074: if (kr != KERN_SUCCESS) { ! 1075: /* unlocks/locks space, so must start again */ ! 1076: ! 1077: kr = ipc_entry_grow_table(space, ITS_SIZE_NONE); ! 1078: if (kr != KERN_SUCCESS) ! 1079: return kr; /* space is unlocked */ ! 1080: ! 1081: continue; ! 1082: } ! 1083: ! 1084: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); ! 1085: assert(entry->ie_object == IO_NULL); ! 1086: ! 1087: ip_lock(port); ! 1088: if (!ip_active(port)) { ! 1089: ip_unlock(port); ! 1090: ipc_entry_dealloc(space, name, entry); ! 1091: is_write_unlock(space); ! 1092: return KERN_INVALID_CAPABILITY; ! 1093: } ! 1094: ! 1095: kr = ipc_port_dnrequest(port, name, ipr_spacem(space), ! 1096: &request); ! 1097: if (kr != KERN_SUCCESS) { ! 1098: ipc_entry_dealloc(space, name, entry); ! 1099: is_write_unlock(space); ! 1100: ! 1101: kr = ipc_port_dngrow(port, ITS_SIZE_NONE); ! 1102: /* port is unlocked */ ! 1103: if (kr != KERN_SUCCESS) ! 1104: return kr; ! 1105: ! 1106: is_write_lock(space); ! 1107: continue; ! 1108: } ! 1109: ! 1110: is_reference(space); /* for dnrequest */ ! 1111: entry->ie_object = (ipc_object_t) port; ! 1112: entry->ie_request = request; ! 1113: entry->ie_bits |= IE_BITS_COMPAT; ! 1114: break; ! 1115: } ! 1116: ! 1117: /* space is write-locked and active, port is locked and active */ ! 1118: ! 1119: kr = ipc_right_copyout(space, name, entry, ! 1120: msgt_name, TRUE, (ipc_object_t) port); ! 1121: /* object is unlocked */ ! 1122: is_write_unlock(space); ! 1123: ! 1124: if (kr == KERN_SUCCESS) ! 1125: *namep = name; ! 1126: return kr; ! 1127: } ! 1128: ! 1129: /* ! 1130: * Routine: ipc_object_copyout_name_compat ! 1131: * Purpose: ! 1132: * Copyout a capability, placing it into a space. ! 1133: * The specified name is used for the capability. ! 1134: * If successful, consumes a ref for the object. ! 1135: * ! 1136: * Like ipc_object_copyout_name, except that ! 1137: * the name can't be in use at all, even for the same ! 1138: * port, and IE_BITS_COMPAT gets turned on. ! 1139: * Conditions: ! 1140: * Nothing locked. ! 1141: * Returns: ! 1142: * KERN_SUCCESS Copied out object, consumed ref. ! 1143: * KERN_INVALID_TASK The space is dead. ! 1144: * KERN_INVALID_CAPABILITY The object is dead. ! 1145: * KERN_RESOURCE_SHORTAGE No memory available. ! 1146: * KERN_RIGHT_EXISTS Space has rights under another name. ! 1147: * KERN_NAME_EXISTS Name is already used. ! 1148: */ ! 1149: ! 1150: kern_return_t ! 1151: ipc_object_copyout_name_compat( ! 1152: ipc_space_t space, ! 1153: ipc_object_t object, ! 1154: mach_msg_type_name_t msgt_name, ! 1155: mach_port_t name) ! 1156: { ! 1157: ipc_entry_t entry; ! 1158: ipc_port_t port; ! 1159: kern_return_t kr; ! 1160: ! 1161: assert(IO_VALID(object)); ! 1162: assert(io_otype(object) == IOT_PORT); ! 1163: port = (ipc_port_t) object; ! 1164: ! 1165: for (;;) { ! 1166: mach_port_t oname; ! 1167: ipc_entry_t oentry; ! 1168: ipc_port_request_index_t request; ! 1169: ! 1170: kr = ipc_entry_alloc_name(space, name, &entry); ! 1171: if (kr != KERN_SUCCESS) ! 1172: return kr; ! 1173: /* space is write-locked and active */ ! 1174: ! 1175: if (ipc_right_inuse(space, name, entry)) ! 1176: return KERN_NAME_EXISTS; /* space is unlocked */ ! 1177: ! 1178: assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE); ! 1179: assert(entry->ie_object == IO_NULL); ! 1180: ! 1181: if ((msgt_name != MACH_MSG_TYPE_PORT_SEND_ONCE) && ! 1182: ipc_right_reverse(space, (ipc_object_t) port, ! 1183: &oname, &oentry)) { ! 1184: /* port is locked and active */ ! 1185: ! 1186: ip_unlock(port); ! 1187: ipc_entry_dealloc(space, name, entry); ! 1188: is_write_unlock(space); ! 1189: return KERN_RIGHT_EXISTS; ! 1190: } ! 1191: ! 1192: ip_lock(port); ! 1193: if (!ip_active(port)) { ! 1194: ip_unlock(port); ! 1195: ipc_entry_dealloc(space, name, entry); ! 1196: is_write_unlock(space); ! 1197: return KERN_INVALID_CAPABILITY; ! 1198: } ! 1199: ! 1200: kr = ipc_port_dnrequest(port, name, ipr_spacem(space), ! 1201: &request); ! 1202: if (kr != KERN_SUCCESS) { ! 1203: ipc_entry_dealloc(space, name, entry); ! 1204: is_write_unlock(space); ! 1205: ! 1206: kr = ipc_port_dngrow(port, ITS_SIZE_NONE); ! 1207: /* port is unlocked */ ! 1208: if (kr != KERN_SUCCESS) ! 1209: return kr; ! 1210: ! 1211: continue; ! 1212: } ! 1213: ! 1214: is_reference(space); /* for dnrequest */ ! 1215: entry->ie_object = (ipc_object_t) port; ! 1216: entry->ie_request = request; ! 1217: entry->ie_bits |= IE_BITS_COMPAT; ! 1218: break; ! 1219: } ! 1220: ! 1221: /* space is write-locked and active, port is locked and active */ ! 1222: ! 1223: kr = ipc_right_copyout(space, name, entry, ! 1224: msgt_name, TRUE, (ipc_object_t) port); ! 1225: /* object is unlocked */ ! 1226: is_write_unlock(space); ! 1227: ! 1228: assert(kr == KERN_SUCCESS); ! 1229: return kr; ! 1230: } ! 1231: ! 1232: #endif /* MACH_IPC_COMPAT */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.