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