|
|
1.1 ! root 1: /* ! 2: * Mach Operating System ! 3: * Copyright (c) 1991,1990,1989 Carnegie Mellon University. ! 4: * Copyright (c) 1993,1994 The University of Utah and ! 5: * the Computer Systems Laboratory (CSL). ! 6: * All rights reserved. ! 7: * ! 8: * Permission to use, copy, modify and distribute this software and its ! 9: * documentation is hereby granted, provided that both the copyright ! 10: * notice and this permission notice appear in all copies of the ! 11: * software, derivative works or modified versions, and any portions ! 12: * thereof, and that both notices appear in supporting documentation. ! 13: * ! 14: * CARNEGIE MELLON, THE UNIVERSITY OF UTAH AND CSL ALLOW FREE USE OF ! 15: * THIS SOFTWARE IN ITS "AS IS" CONDITION, AND DISCLAIM ANY LIABILITY ! 16: * OF ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF ! 17: * THIS SOFTWARE. ! 18: * ! 19: * Carnegie Mellon requests users of this software to return to ! 20: * ! 21: * Software Distribution Coordinator or [email protected] ! 22: * School of Computer Science ! 23: * Carnegie Mellon University ! 24: * Pittsburgh PA 15213-3890 ! 25: * ! 26: * any improvements or extensions that they make and grant Carnegie Mellon ! 27: * the rights to redistribute these changes. ! 28: */ ! 29: /* ! 30: * File: ipc/ipc_kmsg.c ! 31: * Author: Rich Draves ! 32: * Date: 1989 ! 33: * ! 34: * Operations on kernel messages. ! 35: */ ! 36: ! 37: #include <cpus.h> ! 38: #include <mach_ipc_compat.h> ! 39: #include <norma_ipc.h> ! 40: #include <norma_vm.h> ! 41: ! 42: #include <mach/boolean.h> ! 43: #include <mach/kern_return.h> ! 44: #include <mach/message.h> ! 45: #include <mach/port.h> ! 46: #include <kern/assert.h> ! 47: #include <kern/kalloc.h> ! 48: #include <vm/vm_map.h> ! 49: #include <vm/vm_object.h> ! 50: #include <vm/vm_kern.h> ! 51: #include <ipc/port.h> ! 52: #include <ipc/ipc_entry.h> ! 53: #include <ipc/ipc_kmsg.h> ! 54: #include <ipc/ipc_thread.h> ! 55: #include <ipc/ipc_marequest.h> ! 56: #include <ipc/ipc_notify.h> ! 57: #include <ipc/ipc_object.h> ! 58: #include <ipc/ipc_space.h> ! 59: #include <ipc/ipc_port.h> ! 60: #include <ipc/ipc_right.h> ! 61: ! 62: #include <ipc/ipc_machdep.h> ! 63: ! 64: extern int copyinmap(); ! 65: extern int copyoutmap(); ! 66: void ipc_msg_print(); /* forward */ ! 67: ! 68: #define is_misaligned(x) ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) ) ! 69: #define ptr_align(x) \ ! 70: ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) ) ! 71: ! 72: ipc_kmsg_t ipc_kmsg_cache[NCPUS]; ! 73: ! 74: /* ! 75: * Routine: ipc_kmsg_enqueue ! 76: * Purpose: ! 77: * Enqueue a kmsg. ! 78: */ ! 79: ! 80: void ! 81: ipc_kmsg_enqueue( ! 82: ipc_kmsg_queue_t queue, ! 83: ipc_kmsg_t kmsg) ! 84: { ! 85: ipc_kmsg_enqueue_macro(queue, kmsg); ! 86: } ! 87: ! 88: /* ! 89: * Routine: ipc_kmsg_dequeue ! 90: * Purpose: ! 91: * Dequeue and return a kmsg. ! 92: */ ! 93: ! 94: ipc_kmsg_t ! 95: ipc_kmsg_dequeue( ! 96: ipc_kmsg_queue_t queue) ! 97: { ! 98: ipc_kmsg_t first; ! 99: ! 100: first = ipc_kmsg_queue_first(queue); ! 101: ! 102: if (first != IKM_NULL) ! 103: ipc_kmsg_rmqueue_first_macro(queue, first); ! 104: ! 105: return first; ! 106: } ! 107: ! 108: /* ! 109: * Routine: ipc_kmsg_rmqueue ! 110: * Purpose: ! 111: * Pull a kmsg out of a queue. ! 112: */ ! 113: ! 114: void ! 115: ipc_kmsg_rmqueue( ! 116: ipc_kmsg_queue_t queue, ! 117: ipc_kmsg_t kmsg) ! 118: { ! 119: ipc_kmsg_t next, prev; ! 120: ! 121: assert(queue->ikmq_base != IKM_NULL); ! 122: ! 123: next = kmsg->ikm_next; ! 124: prev = kmsg->ikm_prev; ! 125: ! 126: if (next == kmsg) { ! 127: assert(prev == kmsg); ! 128: assert(queue->ikmq_base == kmsg); ! 129: ! 130: queue->ikmq_base = IKM_NULL; ! 131: } else { ! 132: if (queue->ikmq_base == kmsg) ! 133: queue->ikmq_base = next; ! 134: ! 135: next->ikm_prev = prev; ! 136: prev->ikm_next = next; ! 137: } ! 138: /* XXX Temporary debug logic */ ! 139: kmsg->ikm_next = IKM_BOGUS; ! 140: kmsg->ikm_prev = IKM_BOGUS; ! 141: } ! 142: ! 143: /* ! 144: * Routine: ipc_kmsg_queue_next ! 145: * Purpose: ! 146: * Return the kmsg following the given kmsg. ! 147: * (Or IKM_NULL if it is the last one in the queue.) ! 148: */ ! 149: ! 150: ipc_kmsg_t ! 151: ipc_kmsg_queue_next( ! 152: ipc_kmsg_queue_t queue, ! 153: ipc_kmsg_t kmsg) ! 154: { ! 155: ipc_kmsg_t next; ! 156: ! 157: assert(queue->ikmq_base != IKM_NULL); ! 158: ! 159: next = kmsg->ikm_next; ! 160: if (queue->ikmq_base == next) ! 161: next = IKM_NULL; ! 162: ! 163: return next; ! 164: } ! 165: ! 166: /* ! 167: * Routine: ipc_kmsg_destroy ! 168: * Purpose: ! 169: * Destroys a kernel message. Releases all rights, ! 170: * references, and memory held by the message. ! 171: * Frees the message. ! 172: * Conditions: ! 173: * No locks held. ! 174: */ ! 175: ! 176: void ! 177: ipc_kmsg_destroy( ! 178: ipc_kmsg_t kmsg) ! 179: { ! 180: ipc_kmsg_queue_t queue; ! 181: boolean_t empty; ! 182: ! 183: /* ! 184: * ipc_kmsg_clean can cause more messages to be destroyed. ! 185: * Curtail recursion by queueing messages. If a message ! 186: * is already queued, then this is a recursive call. ! 187: */ ! 188: ! 189: queue = ¤t_thread()->ith_messages; ! 190: empty = ipc_kmsg_queue_empty(queue); ! 191: ipc_kmsg_enqueue(queue, kmsg); ! 192: ! 193: if (empty) { ! 194: /* must leave kmsg in queue while cleaning it */ ! 195: ! 196: while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) { ! 197: ipc_kmsg_clean(kmsg); ! 198: ipc_kmsg_rmqueue(queue, kmsg); ! 199: ikm_free(kmsg); ! 200: } ! 201: } ! 202: } ! 203: ! 204: /* ! 205: * Routine: ipc_kmsg_clean_body ! 206: * Purpose: ! 207: * Cleans the body of a kernel message. ! 208: * Releases all rights, references, and memory. ! 209: * ! 210: * The last type/data pair might stretch past eaddr. ! 211: * (See the usage in ipc_kmsg_copyout.) ! 212: * Conditions: ! 213: * No locks held. ! 214: */ ! 215: ! 216: void ! 217: ipc_kmsg_clean_body(saddr, eaddr) ! 218: vm_offset_t saddr; ! 219: vm_offset_t eaddr; ! 220: { ! 221: while (saddr < eaddr) { ! 222: mach_msg_type_long_t *type; ! 223: mach_msg_type_name_t name; ! 224: mach_msg_type_size_t size; ! 225: mach_msg_type_number_t number; ! 226: boolean_t is_inline, is_port; ! 227: vm_size_t length; ! 228: ! 229: type = (mach_msg_type_long_t *) saddr; ! 230: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 231: if (((mach_msg_type_t*)type)->msgt_longform) { ! 232: /* This must be aligned */ ! 233: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 234: (is_misaligned(type))) { ! 235: saddr = ptr_align(saddr); ! 236: continue; ! 237: } ! 238: name = type->msgtl_name; ! 239: size = type->msgtl_size; ! 240: number = type->msgtl_number; ! 241: saddr += sizeof(mach_msg_type_long_t); ! 242: } else { ! 243: name = ((mach_msg_type_t*)type)->msgt_name; ! 244: size = ((mach_msg_type_t*)type)->msgt_size; ! 245: number = ((mach_msg_type_t*)type)->msgt_number; ! 246: saddr += sizeof(mach_msg_type_t); ! 247: } ! 248: ! 249: /* padding (ptrs and ports) ? */ ! 250: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 251: ((size >> 3) == sizeof(natural_t))) ! 252: saddr = ptr_align(saddr); ! 253: ! 254: /* calculate length of data in bytes, rounding up */ ! 255: ! 256: length = ((number * size) + 7) >> 3; ! 257: ! 258: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 259: ! 260: if (is_port) { ! 261: ipc_object_t *objects; ! 262: mach_msg_type_number_t i; ! 263: ! 264: if (is_inline) { ! 265: objects = (ipc_object_t *) saddr; ! 266: /* sanity check */ ! 267: while (eaddr < (vm_offset_t)&objects[number]) number--; ! 268: } else { ! 269: objects = (ipc_object_t *) ! 270: * (vm_offset_t *) saddr; ! 271: } ! 272: ! 273: /* destroy port rights carried in the message */ ! 274: ! 275: for (i = 0; i < number; i++) { ! 276: ipc_object_t object = objects[i]; ! 277: ! 278: if (!IO_VALID(object)) ! 279: continue; ! 280: ! 281: ipc_object_destroy(object, name); ! 282: } ! 283: } ! 284: ! 285: if (is_inline) { ! 286: /* inline data sizes round up to int boundaries */ ! 287: ! 288: saddr += (length + 3) &~ 3; ! 289: } else { ! 290: vm_offset_t data = * (vm_offset_t *) saddr; ! 291: ! 292: /* destroy memory carried in the message */ ! 293: ! 294: if (length == 0) ! 295: assert(data == 0); ! 296: else if (is_port) ! 297: kfree(data, length); ! 298: else ! 299: vm_map_copy_discard((vm_map_copy_t) data); ! 300: ! 301: saddr += sizeof(vm_offset_t); ! 302: } ! 303: } ! 304: } ! 305: ! 306: /* ! 307: * Routine: ipc_kmsg_clean ! 308: * Purpose: ! 309: * Cleans a kernel message. Releases all rights, ! 310: * references, and memory held by the message. ! 311: * Conditions: ! 312: * No locks held. ! 313: */ ! 314: ! 315: void ! 316: ipc_kmsg_clean(kmsg) ! 317: ipc_kmsg_t kmsg; ! 318: { ! 319: ipc_marequest_t marequest; ! 320: ipc_object_t object; ! 321: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 322: ! 323: marequest = kmsg->ikm_marequest; ! 324: if (marequest != IMAR_NULL) ! 325: ipc_marequest_destroy(marequest); ! 326: ! 327: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 328: if (IO_VALID(object)) ! 329: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits)); ! 330: ! 331: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 332: if (IO_VALID(object)) ! 333: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits)); ! 334: ! 335: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 336: vm_offset_t saddr, eaddr; ! 337: ! 338: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 339: eaddr = (vm_offset_t) &kmsg->ikm_header + ! 340: kmsg->ikm_header.msgh_size; ! 341: ! 342: ipc_kmsg_clean_body(saddr, eaddr); ! 343: } ! 344: } ! 345: ! 346: /* ! 347: * Routine: ipc_kmsg_clean_partial ! 348: * Purpose: ! 349: * Cleans a partially-acquired kernel message. ! 350: * eaddr is the address of the type specification ! 351: * in the body of the message that contained the error. ! 352: * If dolast, the memory and port rights in this last ! 353: * type spec are also cleaned. In that case, number ! 354: * specifies the number of port rights to clean. ! 355: * Conditions: ! 356: * Nothing locked. ! 357: */ ! 358: ! 359: void ! 360: ipc_kmsg_clean_partial(kmsg, eaddr, dolast, number) ! 361: ipc_kmsg_t kmsg; ! 362: vm_offset_t eaddr; ! 363: boolean_t dolast; ! 364: mach_msg_type_number_t number; ! 365: { ! 366: ipc_object_t object; ! 367: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 368: vm_offset_t saddr; ! 369: ! 370: assert(kmsg->ikm_marequest == IMAR_NULL); ! 371: ! 372: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 373: assert(IO_VALID(object)); ! 374: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits)); ! 375: ! 376: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 377: if (IO_VALID(object)) ! 378: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits)); ! 379: ! 380: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 381: ipc_kmsg_clean_body(saddr, eaddr); ! 382: ! 383: if (dolast) { ! 384: mach_msg_type_long_t *type; ! 385: mach_msg_type_name_t name; ! 386: mach_msg_type_size_t size; ! 387: mach_msg_type_number_t rnumber; ! 388: boolean_t is_inline, is_port; ! 389: vm_size_t length; ! 390: ! 391: xxx: type = (mach_msg_type_long_t *) eaddr; ! 392: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 393: if (((mach_msg_type_t*)type)->msgt_longform) { ! 394: /* This must be aligned */ ! 395: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 396: (is_misaligned(type))) { ! 397: eaddr = ptr_align(eaddr); ! 398: goto xxx; ! 399: } ! 400: name = type->msgtl_name; ! 401: size = type->msgtl_size; ! 402: rnumber = type->msgtl_number; ! 403: eaddr += sizeof(mach_msg_type_long_t); ! 404: } else { ! 405: name = ((mach_msg_type_t*)type)->msgt_name; ! 406: size = ((mach_msg_type_t*)type)->msgt_size; ! 407: rnumber = ((mach_msg_type_t*)type)->msgt_number; ! 408: eaddr += sizeof(mach_msg_type_t); ! 409: } ! 410: ! 411: /* padding (ptrs and ports) ? */ ! 412: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 413: ((size >> 3) == sizeof(natural_t))) ! 414: eaddr = ptr_align(eaddr); ! 415: ! 416: /* calculate length of data in bytes, rounding up */ ! 417: ! 418: length = ((rnumber * size) + 7) >> 3; ! 419: ! 420: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 421: ! 422: if (is_port) { ! 423: ipc_object_t *objects; ! 424: mach_msg_type_number_t i; ! 425: ! 426: objects = (ipc_object_t *) ! 427: (is_inline ? eaddr : * (vm_offset_t *) eaddr); ! 428: ! 429: /* destroy port rights carried in the message */ ! 430: ! 431: for (i = 0; i < number; i++) { ! 432: ipc_object_t obj = objects[i]; ! 433: ! 434: if (!IO_VALID(obj)) ! 435: continue; ! 436: ! 437: ipc_object_destroy(obj, name); ! 438: } ! 439: } ! 440: ! 441: if (!is_inline) { ! 442: vm_offset_t data = * (vm_offset_t *) eaddr; ! 443: ! 444: /* destroy memory carried in the message */ ! 445: ! 446: if (length == 0) ! 447: assert(data == 0); ! 448: else if (is_port) ! 449: kfree(data, length); ! 450: else ! 451: vm_map_copy_discard((vm_map_copy_t) data); ! 452: } ! 453: } ! 454: } ! 455: ! 456: /* ! 457: * Routine: ipc_kmsg_free ! 458: * Purpose: ! 459: * Free a kernel message buffer. ! 460: * Conditions: ! 461: * Nothing locked. ! 462: */ ! 463: ! 464: void ! 465: ipc_kmsg_free(kmsg) ! 466: ipc_kmsg_t kmsg; ! 467: { ! 468: vm_size_t size = kmsg->ikm_size; ! 469: ! 470: switch (size) { ! 471: #if NORMA_IPC ! 472: case IKM_SIZE_NORMA: ! 473: /* return it to the norma ipc code */ ! 474: norma_kmsg_put(kmsg); ! 475: break; ! 476: #endif /* NORMA_IPC */ ! 477: ! 478: case IKM_SIZE_NETWORK: ! 479: /* return it to the network code */ ! 480: net_kmsg_put(kmsg); ! 481: break; ! 482: ! 483: default: ! 484: kfree((vm_offset_t) kmsg, size); ! 485: break; ! 486: } ! 487: } ! 488: ! 489: /* ! 490: * Routine: ipc_kmsg_get ! 491: * Purpose: ! 492: * Allocates a kernel message buffer. ! 493: * Copies a user message to the message buffer. ! 494: * Conditions: ! 495: * Nothing locked. ! 496: * Returns: ! 497: * MACH_MSG_SUCCESS Acquired a message buffer. ! 498: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header. ! 499: * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple. ! 500: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer. ! 501: * MACH_SEND_INVALID_DATA Couldn't copy message data. ! 502: */ ! 503: ! 504: mach_msg_return_t ! 505: ipc_kmsg_get(msg, size, kmsgp) ! 506: mach_msg_header_t *msg; ! 507: mach_msg_size_t size; ! 508: ipc_kmsg_t *kmsgp; ! 509: { ! 510: ipc_kmsg_t kmsg; ! 511: ! 512: if ((size < sizeof(mach_msg_header_t)) || (size & 3)) ! 513: return MACH_SEND_MSG_TOO_SMALL; ! 514: ! 515: if (size <= IKM_SAVED_MSG_SIZE) { ! 516: kmsg = ikm_cache(); ! 517: if (kmsg != IKM_NULL) { ! 518: ikm_cache() = IKM_NULL; ! 519: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE); ! 520: } else { ! 521: kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE); ! 522: if (kmsg == IKM_NULL) ! 523: return MACH_SEND_NO_BUFFER; ! 524: ikm_init(kmsg, IKM_SAVED_MSG_SIZE); ! 525: } ! 526: } else { ! 527: kmsg = ikm_alloc(size); ! 528: if (kmsg == IKM_NULL) ! 529: return MACH_SEND_NO_BUFFER; ! 530: ikm_init(kmsg, size); ! 531: } ! 532: ! 533: if (copyinmsg((char *) msg, (char *) &kmsg->ikm_header, size)) { ! 534: ikm_free(kmsg); ! 535: return MACH_SEND_INVALID_DATA; ! 536: } ! 537: ! 538: kmsg->ikm_header.msgh_size = size; ! 539: *kmsgp = kmsg; ! 540: return MACH_MSG_SUCCESS; ! 541: } ! 542: ! 543: /* ! 544: * Routine: ipc_kmsg_get_from_kernel ! 545: * Purpose: ! 546: * Allocates a kernel message buffer. ! 547: * Copies a kernel message to the message buffer. ! 548: * Only resource errors are allowed. ! 549: * Conditions: ! 550: * Nothing locked. ! 551: * Returns: ! 552: * MACH_MSG_SUCCESS Acquired a message buffer. ! 553: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer. ! 554: */ ! 555: ! 556: extern mach_msg_return_t ! 557: ipc_kmsg_get_from_kernel(msg, size, kmsgp) ! 558: mach_msg_header_t *msg; ! 559: mach_msg_size_t size; ! 560: ipc_kmsg_t *kmsgp; ! 561: { ! 562: ipc_kmsg_t kmsg; ! 563: ! 564: assert(size >= sizeof(mach_msg_header_t)); ! 565: assert((size & 3) == 0); ! 566: ! 567: kmsg = ikm_alloc(size); ! 568: if (kmsg == IKM_NULL) ! 569: return MACH_SEND_NO_BUFFER; ! 570: ikm_init(kmsg, size); ! 571: ! 572: bcopy((char *) msg, (char *) &kmsg->ikm_header, size); ! 573: ! 574: kmsg->ikm_header.msgh_size = size; ! 575: *kmsgp = kmsg; ! 576: return MACH_MSG_SUCCESS; ! 577: } ! 578: ! 579: /* ! 580: * Routine: ipc_kmsg_put ! 581: * Purpose: ! 582: * Copies a message buffer to a user message. ! 583: * Copies only the specified number of bytes. ! 584: * Frees the message buffer. ! 585: * Conditions: ! 586: * Nothing locked. The message buffer must have clean ! 587: * header (ikm_marequest) fields. ! 588: * Returns: ! 589: * MACH_MSG_SUCCESS Copied data out of message buffer. ! 590: * MACH_RCV_INVALID_DATA Couldn't copy to user message. ! 591: */ ! 592: ! 593: mach_msg_return_t ! 594: ipc_kmsg_put(msg, kmsg, size) ! 595: mach_msg_header_t *msg; ! 596: ipc_kmsg_t kmsg; ! 597: mach_msg_size_t size; ! 598: { ! 599: mach_msg_return_t mr; ! 600: ! 601: ikm_check_initialized(kmsg, kmsg->ikm_size); ! 602: ! 603: if (copyoutmsg((char *) &kmsg->ikm_header, (char *) msg, size)) ! 604: mr = MACH_RCV_INVALID_DATA; ! 605: else ! 606: mr = MACH_MSG_SUCCESS; ! 607: ! 608: if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) && ! 609: (ikm_cache() == IKM_NULL)) ! 610: ikm_cache() = kmsg; ! 611: else ! 612: ikm_free(kmsg); ! 613: ! 614: return mr; ! 615: } ! 616: ! 617: /* ! 618: * Routine: ipc_kmsg_put_to_kernel ! 619: * Purpose: ! 620: * Copies a message buffer to a kernel message. ! 621: * Frees the message buffer. ! 622: * No errors allowed. ! 623: * Conditions: ! 624: * Nothing locked. ! 625: */ ! 626: ! 627: void ! 628: ipc_kmsg_put_to_kernel( ! 629: mach_msg_header_t *msg, ! 630: ipc_kmsg_t kmsg, ! 631: mach_msg_size_t size) ! 632: { ! 633: #if DIPC ! 634: assert(!KMSG_IN_DIPC(kmsg)); ! 635: #endif /* DIPC */ ! 636: ! 637: (void) memcpy((void *) msg, (const void *) &kmsg->ikm_header, size); ! 638: ! 639: ikm_free(kmsg); ! 640: } ! 641: ! 642: /* ! 643: * Routine: ipc_kmsg_copyin_header ! 644: * Purpose: ! 645: * "Copy-in" port rights in the header of a message. ! 646: * Operates atomically; if it doesn't succeed the ! 647: * message header and the space are left untouched. ! 648: * If it does succeed the remote/local port fields ! 649: * contain object pointers instead of port names, ! 650: * and the bits field is updated. The destination port ! 651: * will be a valid port pointer. ! 652: * ! 653: * The notify argument implements the MACH_SEND_CANCEL option. ! 654: * If it is not MACH_PORT_NULL, it should name a receive right. ! 655: * If the processing of the destination port would generate ! 656: * a port-deleted notification (because the right for the ! 657: * destination port is destroyed and it had a request for ! 658: * a dead-name notification registered), and the port-deleted ! 659: * notification would be sent to the named receive right, ! 660: * then it isn't sent and the send-once right for the notify ! 661: * port is quietly destroyed. ! 662: * ! 663: * [MACH_IPC_COMPAT] There is an atomicity problem if the ! 664: * reply port is a compat entry and dies at an inopportune ! 665: * time. This doesn't have any serious consequences ! 666: * (an observant user task might conceivably notice that ! 667: * the destination and reply ports were handled inconsistently), ! 668: * only happens in compat mode, and is extremely unlikely. ! 669: * Conditions: ! 670: * Nothing locked. ! 671: * Returns: ! 672: * MACH_MSG_SUCCESS Successful copyin. ! 673: * MACH_SEND_INVALID_HEADER ! 674: * Illegal value in the message header bits. ! 675: * MACH_SEND_INVALID_DEST The space is dead. ! 676: * MACH_SEND_INVALID_NOTIFY ! 677: * Notify is non-null and doesn't name a receive right. ! 678: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 679: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 680: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 681: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 682: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 683: */ ! 684: ! 685: mach_msg_return_t ! 686: ipc_kmsg_copyin_header(msg, space, notify) ! 687: mach_msg_header_t *msg; ! 688: ipc_space_t space; ! 689: mach_port_t notify; ! 690: { ! 691: mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR; ! 692: mach_port_t dest_name = msg->msgh_remote_port; ! 693: mach_port_t reply_name = msg->msgh_local_port; ! 694: kern_return_t kr; ! 695: ! 696: #ifndef MIGRATING_THREADS ! 697: /* first check for common cases */ ! 698: ! 699: if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) { ! 700: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): { ! 701: ipc_entry_t entry; ! 702: ipc_entry_bits_t bits; ! 703: ipc_port_t dest_port; ! 704: ! 705: /* sending an asynchronous message */ ! 706: ! 707: if (reply_name != MACH_PORT_NULL) ! 708: break; ! 709: ! 710: is_read_lock(space); ! 711: if (!space->is_active) ! 712: goto abort_async; ! 713: ! 714: /* optimized ipc_entry_lookup */ ! 715: ! 716: { ! 717: mach_port_index_t index = MACH_PORT_INDEX(dest_name); ! 718: mach_port_gen_t gen = MACH_PORT_GEN(dest_name); ! 719: ! 720: if (index >= space->is_table_size) ! 721: goto abort_async; ! 722: ! 723: entry = &space->is_table[index]; ! 724: bits = entry->ie_bits; ! 725: ! 726: /* check generation number and type bit */ ! 727: ! 728: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != ! 729: (gen | MACH_PORT_TYPE_SEND)) ! 730: goto abort_async; ! 731: } ! 732: ! 733: /* optimized ipc_right_copyin */ ! 734: ! 735: assert(IE_BITS_UREFS(bits) > 0); ! 736: ! 737: dest_port = (ipc_port_t) entry->ie_object; ! 738: assert(dest_port != IP_NULL); ! 739: ! 740: ip_lock(dest_port); ! 741: /* can unlock space now without compromising atomicity */ ! 742: is_read_unlock(space); ! 743: ! 744: if (!ip_active(dest_port)) { ! 745: ip_unlock(dest_port); ! 746: break; ! 747: } ! 748: ! 749: assert(dest_port->ip_srights > 0); ! 750: dest_port->ip_srights++; ! 751: ip_reference(dest_port); ! 752: ip_unlock(dest_port); ! 753: ! 754: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 755: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0)); ! 756: msg->msgh_remote_port = (mach_port_t) dest_port; ! 757: return MACH_MSG_SUCCESS; ! 758: ! 759: abort_async: ! 760: is_read_unlock(space); ! 761: break; ! 762: } ! 763: ! 764: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, ! 765: MACH_MSG_TYPE_MAKE_SEND_ONCE): { ! 766: ipc_entry_num_t size; ! 767: ipc_entry_t table; ! 768: ipc_entry_t entry; ! 769: ipc_entry_bits_t bits; ! 770: ipc_port_t dest_port, reply_port; ! 771: ! 772: /* sending a request message */ ! 773: ! 774: is_read_lock(space); ! 775: if (!space->is_active) ! 776: goto abort_request; ! 777: ! 778: size = space->is_table_size; ! 779: table = space->is_table; ! 780: ! 781: /* optimized ipc_entry_lookup of dest_name */ ! 782: ! 783: { ! 784: mach_port_index_t index = MACH_PORT_INDEX(dest_name); ! 785: mach_port_gen_t gen = MACH_PORT_GEN(dest_name); ! 786: ! 787: if (index >= size) ! 788: goto abort_request; ! 789: ! 790: entry = &table[index]; ! 791: bits = entry->ie_bits; ! 792: ! 793: /* check generation number and type bit */ ! 794: ! 795: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != ! 796: (gen | MACH_PORT_TYPE_SEND)) ! 797: goto abort_request; ! 798: } ! 799: ! 800: assert(IE_BITS_UREFS(bits) > 0); ! 801: ! 802: dest_port = (ipc_port_t) entry->ie_object; ! 803: assert(dest_port != IP_NULL); ! 804: ! 805: /* optimized ipc_entry_lookup of reply_name */ ! 806: ! 807: { ! 808: mach_port_index_t index = MACH_PORT_INDEX(reply_name); ! 809: mach_port_gen_t gen = MACH_PORT_GEN(reply_name); ! 810: ! 811: if (index >= size) ! 812: goto abort_request; ! 813: ! 814: entry = &table[index]; ! 815: bits = entry->ie_bits; ! 816: ! 817: /* check generation number and type bit */ ! 818: ! 819: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_RECEIVE)) != ! 820: (gen | MACH_PORT_TYPE_RECEIVE)) ! 821: goto abort_request; ! 822: } ! 823: ! 824: reply_port = (ipc_port_t) entry->ie_object; ! 825: assert(reply_port != IP_NULL); ! 826: ! 827: /* ! 828: * To do an atomic copyin, need simultaneous ! 829: * locks on both ports and the space. If ! 830: * dest_port == reply_port, and simple locking is ! 831: * enabled, then we will abort. Otherwise it's ! 832: * OK to unlock twice. ! 833: */ ! 834: ! 835: ip_lock(dest_port); ! 836: if (!ip_active(dest_port) || !ip_lock_try(reply_port)) { ! 837: ip_unlock(dest_port); ! 838: goto abort_request; ! 839: } ! 840: /* can unlock space now without compromising atomicity */ ! 841: is_read_unlock(space); ! 842: ! 843: assert(dest_port->ip_srights > 0); ! 844: dest_port->ip_srights++; ! 845: ip_reference(dest_port); ! 846: ip_unlock(dest_port); ! 847: ! 848: assert(ip_active(reply_port)); ! 849: assert(reply_port->ip_receiver_name == reply_name); ! 850: assert(reply_port->ip_receiver == space); ! 851: ! 852: reply_port->ip_sorights++; ! 853: ip_reference(reply_port); ! 854: ip_unlock(reply_port); ! 855: ! 856: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 857: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, ! 858: MACH_MSG_TYPE_PORT_SEND_ONCE)); ! 859: msg->msgh_remote_port = (mach_port_t) dest_port; ! 860: msg->msgh_local_port = (mach_port_t) reply_port; ! 861: return MACH_MSG_SUCCESS; ! 862: ! 863: abort_request: ! 864: is_read_unlock(space); ! 865: break; ! 866: } ! 867: ! 868: case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): { ! 869: mach_port_index_t index; ! 870: mach_port_gen_t gen; ! 871: ipc_entry_t table; ! 872: ipc_entry_t entry; ! 873: ipc_entry_bits_t bits; ! 874: ipc_port_t dest_port; ! 875: ! 876: /* sending a reply message */ ! 877: ! 878: if (reply_name != MACH_PORT_NULL) ! 879: break; ! 880: ! 881: is_write_lock(space); ! 882: if (!space->is_active) ! 883: goto abort_reply; ! 884: ! 885: /* optimized ipc_entry_lookup */ ! 886: ! 887: table = space->is_table; ! 888: ! 889: index = MACH_PORT_INDEX(dest_name); ! 890: gen = MACH_PORT_GEN(dest_name); ! 891: ! 892: if (index >= space->is_table_size) ! 893: goto abort_reply; ! 894: ! 895: entry = &table[index]; ! 896: bits = entry->ie_bits; ! 897: ! 898: /* check generation number, collision bit, and type bit */ ! 899: ! 900: if ((bits & (IE_BITS_GEN_MASK|IE_BITS_COLLISION| ! 901: MACH_PORT_TYPE_SEND_ONCE)) != ! 902: (gen | MACH_PORT_TYPE_SEND_ONCE)) ! 903: goto abort_reply; ! 904: ! 905: /* optimized ipc_right_copyin */ ! 906: ! 907: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); ! 908: assert(IE_BITS_UREFS(bits) == 1); ! 909: assert((bits & IE_BITS_MAREQUEST) == 0); ! 910: ! 911: if (entry->ie_request != 0) ! 912: goto abort_reply; ! 913: ! 914: dest_port = (ipc_port_t) entry->ie_object; ! 915: assert(dest_port != IP_NULL); ! 916: ! 917: ip_lock(dest_port); ! 918: if (!ip_active(dest_port)) { ! 919: ip_unlock(dest_port); ! 920: goto abort_reply; ! 921: } ! 922: ! 923: assert(dest_port->ip_sorights > 0); ! 924: ip_unlock(dest_port); ! 925: ! 926: /* optimized ipc_entry_dealloc */ ! 927: ! 928: entry->ie_next = table->ie_next; ! 929: table->ie_next = index; ! 930: entry->ie_bits = gen; ! 931: entry->ie_object = IO_NULL; ! 932: is_write_unlock(space); ! 933: ! 934: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 935: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, ! 936: 0)); ! 937: msg->msgh_remote_port = (mach_port_t) dest_port; ! 938: return MACH_MSG_SUCCESS; ! 939: ! 940: abort_reply: ! 941: is_write_unlock(space); ! 942: break; ! 943: } ! 944: ! 945: default: ! 946: /* don't bother optimizing */ ! 947: break; ! 948: } ! 949: #endif /* MIGRATING_THREADS */ ! 950: ! 951: { ! 952: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 953: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 954: ipc_object_t dest_port, reply_port; ! 955: ipc_port_t dest_soright, reply_soright; ! 956: ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */ ! 957: ! 958: if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type)) ! 959: return MACH_SEND_INVALID_HEADER; ! 960: ! 961: if ((reply_type == 0) ? ! 962: (reply_name != MACH_PORT_NULL) : ! 963: !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type)) ! 964: return MACH_SEND_INVALID_HEADER; ! 965: ! 966: is_write_lock(space); ! 967: if (!space->is_active) ! 968: goto invalid_dest; ! 969: ! 970: if (notify != MACH_PORT_NULL) { ! 971: ipc_entry_t entry; ! 972: ! 973: if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) || ! 974: ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) { ! 975: is_write_unlock(space); ! 976: return MACH_SEND_INVALID_NOTIFY; ! 977: } ! 978: ! 979: notify_port = (ipc_port_t) entry->ie_object; ! 980: } ! 981: ! 982: if (dest_name == reply_name) { ! 983: ipc_entry_t entry; ! 984: mach_port_t name = dest_name; ! 985: ! 986: /* ! 987: * Destination and reply ports are the same! ! 988: * This is a little tedious to make atomic, because ! 989: * there are 25 combinations of dest_type/reply_type. ! 990: * However, most are easy. If either is move-sonce, ! 991: * then there must be an error. If either are ! 992: * make-send or make-sonce, then we must be looking ! 993: * at a receive right so the port can't die. ! 994: * The hard cases are the combinations of ! 995: * copy-send and make-send. ! 996: */ ! 997: ! 998: entry = ipc_entry_lookup(space, name); ! 999: if (entry == IE_NULL) ! 1000: goto invalid_dest; ! 1001: ! 1002: assert(reply_type != 0); /* because name not null */ ! 1003: ! 1004: if (!ipc_right_copyin_check(space, name, entry, reply_type)) ! 1005: goto invalid_reply; ! 1006: ! 1007: if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) || ! 1008: (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) { ! 1009: /* ! 1010: * Why must there be an error? To get a valid ! 1011: * destination, this entry must name a live ! 1012: * port (not a dead name or dead port). However ! 1013: * a successful move-sonce will destroy a ! 1014: * live entry. Therefore the other copyin, ! 1015: * whatever it is, would fail. We've already ! 1016: * checked for reply port errors above, ! 1017: * so report a destination error. ! 1018: */ ! 1019: ! 1020: goto invalid_dest; ! 1021: } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) || ! 1022: (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) || ! 1023: (reply_type == MACH_MSG_TYPE_MAKE_SEND) || ! 1024: (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) { ! 1025: kr = ipc_right_copyin(space, name, entry, ! 1026: dest_type, FALSE, ! 1027: &dest_port, &dest_soright); ! 1028: if (kr != KERN_SUCCESS) ! 1029: goto invalid_dest; ! 1030: ! 1031: /* ! 1032: * Either dest or reply needs a receive right. ! 1033: * We know the receive right is there, because ! 1034: * of the copyin_check and copyin calls. Hence ! 1035: * the port is not in danger of dying. If dest ! 1036: * used the receive right, then the right needed ! 1037: * by reply (and verified by copyin_check) will ! 1038: * still be there. ! 1039: */ ! 1040: ! 1041: assert(IO_VALID(dest_port)); ! 1042: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); ! 1043: assert(dest_soright == IP_NULL); ! 1044: ! 1045: kr = ipc_right_copyin(space, name, entry, ! 1046: reply_type, TRUE, ! 1047: &reply_port, &reply_soright); ! 1048: ! 1049: assert(kr == KERN_SUCCESS); ! 1050: assert(reply_port == dest_port); ! 1051: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); ! 1052: assert(reply_soright == IP_NULL); ! 1053: } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) && ! 1054: (reply_type == MACH_MSG_TYPE_COPY_SEND)) { ! 1055: /* ! 1056: * To make this atomic, just do one copy-send, ! 1057: * and dup the send right we get out. ! 1058: */ ! 1059: ! 1060: kr = ipc_right_copyin(space, name, entry, ! 1061: dest_type, FALSE, ! 1062: &dest_port, &dest_soright); ! 1063: if (kr != KERN_SUCCESS) ! 1064: goto invalid_dest; ! 1065: ! 1066: assert(entry->ie_bits & MACH_PORT_TYPE_SEND); ! 1067: assert(dest_soright == IP_NULL); ! 1068: ! 1069: /* ! 1070: * It's OK if the port we got is dead now, ! 1071: * so reply_port is IP_DEAD, because the msg ! 1072: * won't go anywhere anyway. ! 1073: */ ! 1074: ! 1075: reply_port = (ipc_object_t) ! 1076: ipc_port_copy_send((ipc_port_t) dest_port); ! 1077: reply_soright = IP_NULL; ! 1078: } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) && ! 1079: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) { ! 1080: /* ! 1081: * This is an easy case. Just use our ! 1082: * handy-dandy special-purpose copyin call ! 1083: * to get two send rights for the price of one. ! 1084: */ ! 1085: ! 1086: kr = ipc_right_copyin_two(space, name, entry, ! 1087: &dest_port, &dest_soright); ! 1088: if (kr != KERN_SUCCESS) ! 1089: goto invalid_dest; ! 1090: ! 1091: /* the entry might need to be deallocated */ ! 1092: ! 1093: if (IE_BITS_TYPE(entry->ie_bits) ! 1094: == MACH_PORT_TYPE_NONE) ! 1095: ipc_entry_dealloc(space, name, entry); ! 1096: ! 1097: reply_port = dest_port; ! 1098: reply_soright = IP_NULL; ! 1099: } else { ! 1100: ipc_port_t soright; ! 1101: ! 1102: assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) && ! 1103: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) || ! 1104: ((dest_type == MACH_MSG_TYPE_MOVE_SEND) && ! 1105: (reply_type == MACH_MSG_TYPE_COPY_SEND))); ! 1106: ! 1107: /* ! 1108: * To make this atomic, just do a move-send, ! 1109: * and dup the send right we get out. ! 1110: */ ! 1111: ! 1112: kr = ipc_right_copyin(space, name, entry, ! 1113: MACH_MSG_TYPE_MOVE_SEND, FALSE, ! 1114: &dest_port, &soright); ! 1115: if (kr != KERN_SUCCESS) ! 1116: goto invalid_dest; ! 1117: ! 1118: /* the entry might need to be deallocated */ ! 1119: ! 1120: if (IE_BITS_TYPE(entry->ie_bits) ! 1121: == MACH_PORT_TYPE_NONE) ! 1122: ipc_entry_dealloc(space, name, entry); ! 1123: ! 1124: /* ! 1125: * It's OK if the port we got is dead now, ! 1126: * so reply_port is IP_DEAD, because the msg ! 1127: * won't go anywhere anyway. ! 1128: */ ! 1129: ! 1130: reply_port = (ipc_object_t) ! 1131: ipc_port_copy_send((ipc_port_t) dest_port); ! 1132: ! 1133: if (dest_type == MACH_MSG_TYPE_MOVE_SEND) { ! 1134: dest_soright = soright; ! 1135: reply_soright = IP_NULL; ! 1136: } else { ! 1137: dest_soright = IP_NULL; ! 1138: reply_soright = soright; ! 1139: } ! 1140: } ! 1141: } else if (!MACH_PORT_VALID(reply_name)) { ! 1142: ipc_entry_t entry; ! 1143: ! 1144: /* ! 1145: * No reply port! This is an easy case ! 1146: * to make atomic. Just copyin the destination. ! 1147: */ ! 1148: ! 1149: entry = ipc_entry_lookup(space, dest_name); ! 1150: if (entry == IE_NULL) ! 1151: goto invalid_dest; ! 1152: ! 1153: kr = ipc_right_copyin(space, dest_name, entry, ! 1154: dest_type, FALSE, ! 1155: &dest_port, &dest_soright); ! 1156: if (kr != KERN_SUCCESS) ! 1157: goto invalid_dest; ! 1158: ! 1159: /* the entry might need to be deallocated */ ! 1160: ! 1161: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1162: ipc_entry_dealloc(space, dest_name, entry); ! 1163: ! 1164: reply_port = (ipc_object_t) reply_name; ! 1165: reply_soright = IP_NULL; ! 1166: } else { ! 1167: ipc_entry_t dest_entry, reply_entry; ! 1168: ipc_port_t saved_reply; ! 1169: ! 1170: /* ! 1171: * This is the tough case to make atomic. ! 1172: * The difficult problem is serializing with port death. ! 1173: * At the time we copyin dest_port, it must be alive. ! 1174: * If reply_port is alive when we copyin it, then ! 1175: * we are OK, because we serialize before the death ! 1176: * of both ports. Assume reply_port is dead at copyin. ! 1177: * Then if dest_port dies/died after reply_port died, ! 1178: * we are OK, because we serialize between the death ! 1179: * of the two ports. So the bad case is when dest_port ! 1180: * dies after its copyin, reply_port dies before its ! 1181: * copyin, and dest_port dies before reply_port. Then ! 1182: * the copyins operated as if dest_port was alive ! 1183: * and reply_port was dead, which shouldn't have happened ! 1184: * because they died in the other order. ! 1185: * ! 1186: * We handle the bad case by undoing the copyins ! 1187: * (which is only possible because the ports are dead) ! 1188: * and failing with MACH_SEND_INVALID_DEST, serializing ! 1189: * after the death of the ports. ! 1190: * ! 1191: * Note that it is easy for a user task to tell if ! 1192: * a copyin happened before or after a port died. ! 1193: * For example, suppose both dest and reply are ! 1194: * send-once rights (types are both move-sonce) and ! 1195: * both rights have dead-name requests registered. ! 1196: * If a port dies before copyin, a dead-name notification ! 1197: * is generated and the dead name's urefs are incremented, ! 1198: * and if the copyin happens first, a port-deleted ! 1199: * notification is generated. ! 1200: * ! 1201: * Note that although the entries are different, ! 1202: * dest_port and reply_port might still be the same. ! 1203: */ ! 1204: ! 1205: dest_entry = ipc_entry_lookup(space, dest_name); ! 1206: if (dest_entry == IE_NULL) ! 1207: goto invalid_dest; ! 1208: ! 1209: reply_entry = ipc_entry_lookup(space, reply_name); ! 1210: if (reply_entry == IE_NULL) ! 1211: goto invalid_reply; ! 1212: ! 1213: assert(dest_entry != reply_entry); /* names are not equal */ ! 1214: assert(reply_type != 0); /* because reply_name not null */ ! 1215: ! 1216: if (!ipc_right_copyin_check(space, reply_name, reply_entry, ! 1217: reply_type)) ! 1218: goto invalid_reply; ! 1219: ! 1220: kr = ipc_right_copyin(space, dest_name, dest_entry, ! 1221: dest_type, FALSE, ! 1222: &dest_port, &dest_soright); ! 1223: if (kr != KERN_SUCCESS) ! 1224: goto invalid_dest; ! 1225: ! 1226: assert(IO_VALID(dest_port)); ! 1227: ! 1228: saved_reply = (ipc_port_t) reply_entry->ie_object; ! 1229: /* might be IP_NULL, if this is a dead name */ ! 1230: if (saved_reply != IP_NULL) ! 1231: ipc_port_reference(saved_reply); ! 1232: ! 1233: kr = ipc_right_copyin(space, reply_name, reply_entry, ! 1234: reply_type, TRUE, ! 1235: &reply_port, &reply_soright); ! 1236: #if MACH_IPC_COMPAT ! 1237: if (kr != KERN_SUCCESS) { ! 1238: assert(kr == KERN_INVALID_NAME); ! 1239: ! 1240: /* ! 1241: * Oops. This must have been a compat entry ! 1242: * and the port died after the check above. ! 1243: * We should back out the copyin of dest_port, ! 1244: * and report MACH_SEND_INVALID_REPLY, but ! 1245: * if dest_port is alive we can't always do that. ! 1246: * Punt and pretend we got IO_DEAD, skipping ! 1247: * further hairy atomicity problems. ! 1248: */ ! 1249: ! 1250: reply_port = IO_DEAD; ! 1251: reply_soright = IP_NULL; ! 1252: goto skip_reply_checks; ! 1253: } ! 1254: #else /* MACH_IPC_COMPAT */ ! 1255: assert(kr == KERN_SUCCESS); ! 1256: #endif /* MACH_IPC_COMPAT */ ! 1257: ! 1258: if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) { ! 1259: ipc_port_t dest = (ipc_port_t) dest_port; ! 1260: ipc_port_timestamp_t timestamp; ! 1261: boolean_t must_undo; ! 1262: ! 1263: /* ! 1264: * The reply port died before copyin. ! 1265: * Check if dest port died before reply. ! 1266: */ ! 1267: ! 1268: ip_lock(saved_reply); ! 1269: assert(!ip_active(saved_reply)); ! 1270: timestamp = saved_reply->ip_timestamp; ! 1271: ip_unlock(saved_reply); ! 1272: ! 1273: ip_lock(dest); ! 1274: must_undo = (!ip_active(dest) && ! 1275: IP_TIMESTAMP_ORDER(dest->ip_timestamp, ! 1276: timestamp)); ! 1277: ip_unlock(dest); ! 1278: ! 1279: if (must_undo) { ! 1280: /* ! 1281: * Our worst nightmares are realized. ! 1282: * Both destination and reply ports ! 1283: * are dead, but in the wrong order, ! 1284: * so we must undo the copyins and ! 1285: * possibly generate a dead-name notif. ! 1286: */ ! 1287: ! 1288: ipc_right_copyin_undo( ! 1289: space, dest_name, dest_entry, ! 1290: dest_type, dest_port, ! 1291: dest_soright); ! 1292: /* dest_entry may be deallocated now */ ! 1293: ! 1294: ipc_right_copyin_undo( ! 1295: space, reply_name, reply_entry, ! 1296: reply_type, reply_port, ! 1297: reply_soright); ! 1298: /* reply_entry may be deallocated now */ ! 1299: ! 1300: is_write_unlock(space); ! 1301: ! 1302: if (dest_soright != IP_NULL) ! 1303: ipc_notify_dead_name(dest_soright, ! 1304: dest_name); ! 1305: assert(reply_soright == IP_NULL); ! 1306: ! 1307: ipc_port_release(saved_reply); ! 1308: return MACH_SEND_INVALID_DEST; ! 1309: } ! 1310: } ! 1311: ! 1312: /* the entries might need to be deallocated */ ! 1313: ! 1314: if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1315: ipc_entry_dealloc(space, reply_name, reply_entry); ! 1316: ! 1317: #if MACH_IPC_COMPAT ! 1318: skip_reply_checks: ! 1319: /* ! 1320: * We jump here if the reply entry was a compat entry ! 1321: * and the port died on us. In this case, the copyin ! 1322: * code already deallocated reply_entry. ! 1323: */ ! 1324: #endif /* MACH_IPC_COMPAT */ ! 1325: ! 1326: if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1327: ipc_entry_dealloc(space, dest_name, dest_entry); ! 1328: ! 1329: if (saved_reply != IP_NULL) ! 1330: ipc_port_release(saved_reply); ! 1331: } ! 1332: ! 1333: /* ! 1334: * At this point, dest_port, reply_port, ! 1335: * dest_soright, reply_soright are all initialized. ! 1336: * Any defunct entries have been deallocated. ! 1337: * The space is still write-locked, and we need to ! 1338: * make the MACH_SEND_CANCEL check. The notify_port pointer ! 1339: * is still usable, because the copyin code above won't ever ! 1340: * deallocate a receive right, so its entry still exists ! 1341: * and holds a ref. Note notify_port might even equal ! 1342: * dest_port or reply_port. ! 1343: */ ! 1344: ! 1345: if ((notify != MACH_PORT_NULL) && ! 1346: (dest_soright == notify_port)) { ! 1347: ipc_port_release_sonce(dest_soright); ! 1348: dest_soright = IP_NULL; ! 1349: } ! 1350: ! 1351: is_write_unlock(space); ! 1352: ! 1353: if (dest_soright != IP_NULL) ! 1354: ipc_notify_port_deleted(dest_soright, dest_name); ! 1355: ! 1356: if (reply_soright != IP_NULL) ! 1357: ipc_notify_port_deleted(reply_soright, reply_name); ! 1358: ! 1359: dest_type = ipc_object_copyin_type(dest_type); ! 1360: reply_type = ipc_object_copyin_type(reply_type); ! 1361: ! 1362: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1363: MACH_MSGH_BITS(dest_type, reply_type)); ! 1364: msg->msgh_remote_port = (mach_port_t) dest_port; ! 1365: msg->msgh_local_port = (mach_port_t) reply_port; ! 1366: } ! 1367: ! 1368: return MACH_MSG_SUCCESS; ! 1369: ! 1370: invalid_dest: ! 1371: is_write_unlock(space); ! 1372: return MACH_SEND_INVALID_DEST; ! 1373: ! 1374: invalid_reply: ! 1375: is_write_unlock(space); ! 1376: return MACH_SEND_INVALID_REPLY; ! 1377: } ! 1378: ! 1379: mach_msg_return_t ! 1380: ipc_kmsg_copyin_body(kmsg, space, map) ! 1381: ipc_kmsg_t kmsg; ! 1382: ipc_space_t space; ! 1383: vm_map_t map; ! 1384: { ! 1385: ipc_object_t dest; ! 1386: vm_offset_t saddr, eaddr; ! 1387: boolean_t complex; ! 1388: mach_msg_return_t mr; ! 1389: boolean_t use_page_lists, steal_pages; ! 1390: ! 1391: dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 1392: complex = FALSE; ! 1393: use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest)); ! 1394: steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest)); ! 1395: ! 1396: #if NORMA_IPC ! 1397: if (IP_NORMA_IS_PROXY((ipc_port_t) dest)) { ! 1398: use_page_lists = TRUE; ! 1399: steal_pages = TRUE; ! 1400: } ! 1401: #endif /* NORMA_IPC */ ! 1402: ! 1403: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 1404: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size; ! 1405: ! 1406: while (saddr < eaddr) { ! 1407: vm_offset_t taddr = saddr; ! 1408: mach_msg_type_long_t *type; ! 1409: mach_msg_type_name_t name; ! 1410: mach_msg_type_size_t size; ! 1411: mach_msg_type_number_t number; ! 1412: boolean_t is_inline, longform, dealloc, is_port; ! 1413: vm_offset_t data; ! 1414: vm_size_t length; ! 1415: kern_return_t kr; ! 1416: ! 1417: type = (mach_msg_type_long_t *) saddr; ! 1418: ! 1419: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) || ! 1420: ((longform = ((mach_msg_type_t*)type)->msgt_longform) && ! 1421: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) { ! 1422: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0); ! 1423: return MACH_SEND_MSG_TOO_SMALL; ! 1424: } ! 1425: ! 1426: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 1427: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate; ! 1428: if (longform) { ! 1429: /* This must be aligned */ ! 1430: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 1431: (is_misaligned(type))) { ! 1432: saddr = ptr_align(saddr); ! 1433: continue; ! 1434: } ! 1435: name = type->msgtl_name; ! 1436: size = type->msgtl_size; ! 1437: number = type->msgtl_number; ! 1438: saddr += sizeof(mach_msg_type_long_t); ! 1439: } else { ! 1440: name = ((mach_msg_type_t*)type)->msgt_name; ! 1441: size = ((mach_msg_type_t*)type)->msgt_size; ! 1442: number = ((mach_msg_type_t*)type)->msgt_number; ! 1443: saddr += sizeof(mach_msg_type_t); ! 1444: } ! 1445: ! 1446: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 1447: ! 1448: if ((is_port && (size != PORT_T_SIZE_IN_BITS)) || ! 1449: (longform && ((type->msgtl_header.msgt_name != 0) || ! 1450: (type->msgtl_header.msgt_size != 0) || ! 1451: (type->msgtl_header.msgt_number != 0))) || ! 1452: (((mach_msg_type_t*)type)->msgt_unused != 0) || ! 1453: (dealloc && is_inline)) { ! 1454: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0); ! 1455: return MACH_SEND_INVALID_TYPE; ! 1456: } ! 1457: ! 1458: /* padding (ptrs and ports) ? */ ! 1459: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 1460: ((size >> 3) == sizeof(natural_t))) ! 1461: saddr = ptr_align(saddr); ! 1462: ! 1463: /* calculate length of data in bytes, rounding up */ ! 1464: ! 1465: length = ((number * size) + 7) >> 3; ! 1466: ! 1467: if (is_inline) { ! 1468: vm_size_t amount; ! 1469: ! 1470: /* inline data sizes round up to int boundaries */ ! 1471: ! 1472: amount = (length + 3) &~ 3; ! 1473: if ((eaddr - saddr) < amount) { ! 1474: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0); ! 1475: return MACH_SEND_MSG_TOO_SMALL; ! 1476: } ! 1477: ! 1478: data = saddr; ! 1479: saddr += amount; ! 1480: } else { ! 1481: vm_offset_t addr; ! 1482: ! 1483: if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t)) ! 1484: saddr = ptr_align(saddr); ! 1485: ! 1486: if ((eaddr - saddr) < sizeof(vm_offset_t)) { ! 1487: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0); ! 1488: return MACH_SEND_MSG_TOO_SMALL; ! 1489: } ! 1490: ! 1491: /* grab the out-of-line data */ ! 1492: ! 1493: addr = * (vm_offset_t *) saddr; ! 1494: ! 1495: if (length == 0) ! 1496: data = 0; ! 1497: else if (is_port) { ! 1498: data = kalloc(length); ! 1499: if (data == 0) ! 1500: goto invalid_memory; ! 1501: ! 1502: if (copyinmap(map, (char *) addr, ! 1503: (char *) data, length) || ! 1504: (dealloc && ! 1505: (vm_deallocate(map, addr, length) != ! 1506: KERN_SUCCESS))) { ! 1507: kfree(data, length); ! 1508: goto invalid_memory; ! 1509: } ! 1510: } else { ! 1511: vm_map_copy_t copy; ! 1512: ! 1513: if (use_page_lists) { ! 1514: kr = vm_map_copyin_page_list(map, ! 1515: addr, length, dealloc, ! 1516: steal_pages, ©, FALSE); ! 1517: } else { ! 1518: kr = vm_map_copyin(map, addr, length, ! 1519: dealloc, ©); ! 1520: } ! 1521: if (kr != KERN_SUCCESS) { ! 1522: invalid_memory: ! 1523: ipc_kmsg_clean_partial(kmsg, taddr, ! 1524: FALSE, 0); ! 1525: return MACH_SEND_INVALID_MEMORY; ! 1526: } ! 1527: ! 1528: data = (vm_offset_t) copy; ! 1529: } ! 1530: ! 1531: * (vm_offset_t *) saddr = data; ! 1532: saddr += sizeof(vm_offset_t); ! 1533: complex = TRUE; ! 1534: } ! 1535: ! 1536: if (is_port) { ! 1537: mach_msg_type_name_t newname = ! 1538: ipc_object_copyin_type(name); ! 1539: ipc_object_t *objects = (ipc_object_t *) data; ! 1540: mach_msg_type_number_t i; ! 1541: ! 1542: if (longform) ! 1543: type->msgtl_name = newname; ! 1544: else ! 1545: ((mach_msg_type_t*)type)->msgt_name = newname; ! 1546: ! 1547: for (i = 0; i < number; i++) { ! 1548: mach_port_t port = (mach_port_t) objects[i]; ! 1549: ipc_object_t object; ! 1550: ! 1551: if (!MACH_PORT_VALID(port)) ! 1552: continue; ! 1553: ! 1554: kr = ipc_object_copyin(space, port, ! 1555: name, &object); ! 1556: if (kr != KERN_SUCCESS) { ! 1557: ipc_kmsg_clean_partial(kmsg, taddr, ! 1558: TRUE, i); ! 1559: return MACH_SEND_INVALID_RIGHT; ! 1560: } ! 1561: ! 1562: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) && ! 1563: ipc_port_check_circularity( ! 1564: (ipc_port_t) object, ! 1565: (ipc_port_t) dest)) ! 1566: kmsg->ikm_header.msgh_bits |= ! 1567: MACH_MSGH_BITS_CIRCULAR; ! 1568: ! 1569: objects[i] = object; ! 1570: } ! 1571: ! 1572: complex = TRUE; ! 1573: } ! 1574: } ! 1575: ! 1576: if (!complex) ! 1577: kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; ! 1578: ! 1579: return MACH_MSG_SUCCESS; ! 1580: } ! 1581: ! 1582: /* ! 1583: * Routine: ipc_kmsg_copyin ! 1584: * Purpose: ! 1585: * "Copy-in" port rights and out-of-line memory ! 1586: * in the message. ! 1587: * ! 1588: * In all failure cases, the message is left holding ! 1589: * no rights or memory. However, the message buffer ! 1590: * is not deallocated. If successful, the message ! 1591: * contains a valid destination port. ! 1592: * Conditions: ! 1593: * Nothing locked. ! 1594: * Returns: ! 1595: * MACH_MSG_SUCCESS Successful copyin. ! 1596: * MACH_SEND_INVALID_HEADER ! 1597: * Illegal value in the message header bits. ! 1598: * MACH_SEND_INVALID_NOTIFY Bad notify port. ! 1599: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 1600: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 1601: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory. ! 1602: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body. ! 1603: * MACH_SEND_INVALID_TYPE Bad type specification. ! 1604: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data. ! 1605: */ ! 1606: ! 1607: mach_msg_return_t ! 1608: ipc_kmsg_copyin(kmsg, space, map, notify) ! 1609: ipc_kmsg_t kmsg; ! 1610: ipc_space_t space; ! 1611: vm_map_t map; ! 1612: mach_port_t notify; ! 1613: { ! 1614: mach_msg_return_t mr; ! 1615: ! 1616: mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify); ! 1617: if (mr != MACH_MSG_SUCCESS) ! 1618: return mr; ! 1619: ! 1620: if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) ! 1621: return MACH_MSG_SUCCESS; ! 1622: ! 1623: return ipc_kmsg_copyin_body(kmsg, space, map); ! 1624: } ! 1625: ! 1626: /* ! 1627: * Routine: ipc_kmsg_copyin_from_kernel ! 1628: * Purpose: ! 1629: * "Copy-in" port rights and out-of-line memory ! 1630: * in a message sent from the kernel. ! 1631: * ! 1632: * Because the message comes from the kernel, ! 1633: * the implementation assumes there are no errors ! 1634: * or peculiarities in the message. ! 1635: * ! 1636: * Returns TRUE if queueing the message ! 1637: * would result in a circularity. ! 1638: * Conditions: ! 1639: * Nothing locked. ! 1640: */ ! 1641: ! 1642: void ! 1643: ipc_kmsg_copyin_from_kernel( ! 1644: ipc_kmsg_t kmsg) ! 1645: { ! 1646: mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits; ! 1647: mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits); ! 1648: mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits); ! 1649: ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 1650: ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 1651: vm_offset_t saddr, eaddr; ! 1652: ! 1653: /* translate the destination and reply ports */ ! 1654: ! 1655: ipc_object_copyin_from_kernel(remote, rname); ! 1656: if (IO_VALID(local)) ! 1657: ipc_object_copyin_from_kernel(local, lname); ! 1658: ! 1659: /* ! 1660: * The common case is a complex message with no reply port, ! 1661: * because that is what the memory_object interface uses. ! 1662: */ ! 1663: ! 1664: if (bits == (MACH_MSGH_BITS_COMPLEX | ! 1665: MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) { ! 1666: bits = (MACH_MSGH_BITS_COMPLEX | ! 1667: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0)); ! 1668: ! 1669: kmsg->ikm_header.msgh_bits = bits; ! 1670: } else { ! 1671: bits = (MACH_MSGH_BITS_OTHER(bits) | ! 1672: MACH_MSGH_BITS(ipc_object_copyin_type(rname), ! 1673: ipc_object_copyin_type(lname))); ! 1674: ! 1675: kmsg->ikm_header.msgh_bits = bits; ! 1676: if ((bits & MACH_MSGH_BITS_COMPLEX) == 0) ! 1677: return; ! 1678: } ! 1679: ! 1680: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 1681: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size; ! 1682: ! 1683: while (saddr < eaddr) { ! 1684: mach_msg_type_long_t *type; ! 1685: mach_msg_type_name_t name; ! 1686: mach_msg_type_size_t size; ! 1687: mach_msg_type_number_t number; ! 1688: boolean_t is_inline, longform, is_port; ! 1689: vm_offset_t data; ! 1690: vm_size_t length; ! 1691: ! 1692: type = (mach_msg_type_long_t *) saddr; ! 1693: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 1694: longform = ((mach_msg_type_t*)type)->msgt_longform; ! 1695: /* type->msgtl_header.msgt_deallocate not used */ ! 1696: if (longform) { ! 1697: /* This must be aligned */ ! 1698: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 1699: (is_misaligned(type))) { ! 1700: saddr = ptr_align(saddr); ! 1701: continue; ! 1702: } ! 1703: name = type->msgtl_name; ! 1704: size = type->msgtl_size; ! 1705: number = type->msgtl_number; ! 1706: saddr += sizeof(mach_msg_type_long_t); ! 1707: } else { ! 1708: name = ((mach_msg_type_t*)type)->msgt_name; ! 1709: size = ((mach_msg_type_t*)type)->msgt_size; ! 1710: number = ((mach_msg_type_t*)type)->msgt_number; ! 1711: saddr += sizeof(mach_msg_type_t); ! 1712: } ! 1713: ! 1714: /* padding (ptrs and ports) ? */ ! 1715: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 1716: ((size >> 3) == sizeof(natural_t))) ! 1717: saddr = ptr_align(saddr); ! 1718: ! 1719: /* calculate length of data in bytes, rounding up */ ! 1720: ! 1721: length = ((number * size) + 7) >> 3; ! 1722: ! 1723: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 1724: ! 1725: if (is_inline) { ! 1726: /* inline data sizes round up to int boundaries */ ! 1727: ! 1728: data = saddr; ! 1729: saddr += (length + 3) &~ 3; ! 1730: } else { ! 1731: /* ! 1732: * The sender should supply ready-made memory ! 1733: * for us, so we don't need to do anything. ! 1734: */ ! 1735: ! 1736: data = * (vm_offset_t *) saddr; ! 1737: saddr += sizeof(vm_offset_t); ! 1738: } ! 1739: ! 1740: if (is_port) { ! 1741: mach_msg_type_name_t newname = ! 1742: ipc_object_copyin_type(name); ! 1743: ipc_object_t *objects = (ipc_object_t *) data; ! 1744: mach_msg_type_number_t i; ! 1745: ! 1746: if (longform) ! 1747: type->msgtl_name = newname; ! 1748: else ! 1749: ((mach_msg_type_t*)type)->msgt_name = newname; ! 1750: for (i = 0; i < number; i++) { ! 1751: ipc_object_t object = objects[i]; ! 1752: ! 1753: if (!IO_VALID(object)) ! 1754: continue; ! 1755: ! 1756: ipc_object_copyin_from_kernel(object, name); ! 1757: ! 1758: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) && ! 1759: ipc_port_check_circularity( ! 1760: (ipc_port_t) object, ! 1761: (ipc_port_t) remote)) ! 1762: kmsg->ikm_header.msgh_bits |= ! 1763: MACH_MSGH_BITS_CIRCULAR; ! 1764: } ! 1765: } ! 1766: } ! 1767: } ! 1768: ! 1769: /* ! 1770: * Routine: ipc_kmsg_copyout_header ! 1771: * Purpose: ! 1772: * "Copy-out" port rights in the header of a message. ! 1773: * Operates atomically; if it doesn't succeed the ! 1774: * message header and the space are left untouched. ! 1775: * If it does succeed the remote/local port fields ! 1776: * contain port names instead of object pointers, ! 1777: * and the bits field is updated. ! 1778: * ! 1779: * The notify argument implements the MACH_RCV_NOTIFY option. ! 1780: * If it is not MACH_PORT_NULL, it should name a receive right. ! 1781: * If the process of receiving the reply port creates a ! 1782: * new right in the receiving task, then the new right is ! 1783: * automatically registered for a dead-name notification, ! 1784: * with the notify port supplying the send-once right. ! 1785: * Conditions: ! 1786: * Nothing locked. ! 1787: * Returns: ! 1788: * MACH_MSG_SUCCESS Copied out port rights. ! 1789: * MACH_RCV_INVALID_NOTIFY ! 1790: * Notify is non-null and doesn't name a receive right. ! 1791: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 1792: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE ! 1793: * The space is dead. ! 1794: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE ! 1795: * No room in space for another name. ! 1796: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL ! 1797: * Couldn't allocate memory for the reply port. ! 1798: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL ! 1799: * Couldn't allocate memory for the dead-name request. ! 1800: */ ! 1801: ! 1802: mach_msg_return_t ! 1803: ipc_kmsg_copyout_header(msg, space, notify) ! 1804: mach_msg_header_t *msg; ! 1805: ipc_space_t space; ! 1806: mach_port_t notify; ! 1807: { ! 1808: mach_msg_bits_t mbits = msg->msgh_bits; ! 1809: ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port; ! 1810: ! 1811: assert(IP_VALID(dest)); ! 1812: ! 1813: #ifndef MIGRATING_THREADS ! 1814: /* first check for common cases */ ! 1815: ! 1816: if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) { ! 1817: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): { ! 1818: mach_port_t dest_name; ! 1819: ipc_port_t nsrequest; ! 1820: ! 1821: /* receiving an asynchronous message */ ! 1822: ! 1823: ip_lock(dest); ! 1824: if (!ip_active(dest)) { ! 1825: ip_unlock(dest); ! 1826: break; ! 1827: } ! 1828: ! 1829: /* optimized ipc_object_copyout_dest */ ! 1830: ! 1831: assert(dest->ip_srights > 0); ! 1832: ip_release(dest); ! 1833: ! 1834: if (dest->ip_receiver == space) ! 1835: dest_name = dest->ip_receiver_name; ! 1836: else ! 1837: dest_name = MACH_PORT_NULL; ! 1838: ! 1839: if ((--dest->ip_srights == 0) && ! 1840: ((nsrequest = dest->ip_nsrequest) != IP_NULL)) { ! 1841: mach_port_mscount_t mscount; ! 1842: ! 1843: dest->ip_nsrequest = IP_NULL; ! 1844: mscount = dest->ip_mscount; ! 1845: ip_unlock(dest); ! 1846: ! 1847: ipc_notify_no_senders(nsrequest, mscount); ! 1848: } else ! 1849: ip_unlock(dest); ! 1850: ! 1851: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1852: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND)); ! 1853: msg->msgh_local_port = dest_name; ! 1854: msg->msgh_remote_port = MACH_PORT_NULL; ! 1855: return MACH_MSG_SUCCESS; ! 1856: } ! 1857: ! 1858: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, ! 1859: MACH_MSG_TYPE_PORT_SEND_ONCE): { ! 1860: ipc_entry_t table; ! 1861: mach_port_index_t index; ! 1862: ipc_entry_t entry; ! 1863: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port; ! 1864: mach_port_t dest_name, reply_name; ! 1865: ipc_port_t nsrequest; ! 1866: ! 1867: /* receiving a request message */ ! 1868: ! 1869: if (!IP_VALID(reply)) ! 1870: break; ! 1871: ! 1872: is_write_lock(space); ! 1873: if (!space->is_active || ! 1874: ((index = (table = space->is_table)->ie_next) == 0)) { ! 1875: is_write_unlock(space); ! 1876: break; ! 1877: } ! 1878: ! 1879: /* ! 1880: * To do an atomic copyout, need simultaneous ! 1881: * locks on both ports and the space. If ! 1882: * dest == reply, and simple locking is ! 1883: * enabled, then we will abort. Otherwise it's ! 1884: * OK to unlock twice. ! 1885: */ ! 1886: ! 1887: ip_lock(dest); ! 1888: if (!ip_active(dest) || !ip_lock_try(reply)) { ! 1889: ip_unlock(dest); ! 1890: is_write_unlock(space); ! 1891: break; ! 1892: } ! 1893: ! 1894: if (!ip_active(reply)) { ! 1895: ip_unlock(reply); ! 1896: ip_unlock(dest); ! 1897: is_write_unlock(space); ! 1898: break; ! 1899: } ! 1900: ! 1901: assert(reply->ip_sorights > 0); ! 1902: ip_unlock(reply); ! 1903: ! 1904: /* optimized ipc_entry_get */ ! 1905: ! 1906: entry = &table[index]; ! 1907: table->ie_next = entry->ie_next; ! 1908: entry->ie_request = 0; ! 1909: ! 1910: { ! 1911: mach_port_gen_t gen; ! 1912: ! 1913: assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); ! 1914: gen = entry->ie_bits + IE_BITS_GEN_ONE; ! 1915: ! 1916: reply_name = MACH_PORT_MAKE(index, gen); ! 1917: ! 1918: /* optimized ipc_right_copyout */ ! 1919: ! 1920: entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1); ! 1921: } ! 1922: ! 1923: assert(MACH_PORT_VALID(reply_name)); ! 1924: entry->ie_object = (ipc_object_t) reply; ! 1925: is_write_unlock(space); ! 1926: ! 1927: /* optimized ipc_object_copyout_dest */ ! 1928: ! 1929: assert(dest->ip_srights > 0); ! 1930: ip_release(dest); ! 1931: ! 1932: if (dest->ip_receiver == space) ! 1933: dest_name = dest->ip_receiver_name; ! 1934: else ! 1935: dest_name = MACH_PORT_NULL; ! 1936: ! 1937: if ((--dest->ip_srights == 0) && ! 1938: ((nsrequest = dest->ip_nsrequest) != IP_NULL)) { ! 1939: mach_port_mscount_t mscount; ! 1940: ! 1941: dest->ip_nsrequest = IP_NULL; ! 1942: mscount = dest->ip_mscount; ! 1943: ip_unlock(dest); ! 1944: ! 1945: ipc_notify_no_senders(nsrequest, mscount); ! 1946: } else ! 1947: ip_unlock(dest); ! 1948: ! 1949: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1950: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, ! 1951: MACH_MSG_TYPE_PORT_SEND)); ! 1952: msg->msgh_local_port = dest_name; ! 1953: msg->msgh_remote_port = reply_name; ! 1954: return MACH_MSG_SUCCESS; ! 1955: } ! 1956: ! 1957: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): { ! 1958: mach_port_t dest_name; ! 1959: ! 1960: /* receiving a reply message */ ! 1961: ! 1962: ip_lock(dest); ! 1963: if (!ip_active(dest)) { ! 1964: ip_unlock(dest); ! 1965: break; ! 1966: } ! 1967: ! 1968: /* optimized ipc_object_copyout_dest */ ! 1969: ! 1970: assert(dest->ip_sorights > 0); ! 1971: ! 1972: if (dest->ip_receiver == space) { ! 1973: ip_release(dest); ! 1974: dest->ip_sorights--; ! 1975: dest_name = dest->ip_receiver_name; ! 1976: ip_unlock(dest); ! 1977: } else { ! 1978: ip_unlock(dest); ! 1979: ! 1980: ipc_notify_send_once(dest); ! 1981: dest_name = MACH_PORT_NULL; ! 1982: } ! 1983: ! 1984: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1985: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE)); ! 1986: msg->msgh_local_port = dest_name; ! 1987: msg->msgh_remote_port = MACH_PORT_NULL; ! 1988: return MACH_MSG_SUCCESS; ! 1989: } ! 1990: ! 1991: default: ! 1992: /* don't bother optimizing */ ! 1993: break; ! 1994: } ! 1995: #endif /* MIGRATING_THREADS */ ! 1996: ! 1997: { ! 1998: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 1999: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 2000: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port; ! 2001: mach_port_t dest_name, reply_name; ! 2002: ! 2003: if (IP_VALID(reply)) { ! 2004: ipc_port_t notify_port; ! 2005: ipc_entry_t entry; ! 2006: kern_return_t kr; ! 2007: ! 2008: /* ! 2009: * Handling notify (for MACH_RCV_NOTIFY) is tricky. ! 2010: * The problem is atomically making a send-once right ! 2011: * from the notify port and installing it for a ! 2012: * dead-name request in the new entry, because this ! 2013: * requires two port locks (on the notify port and ! 2014: * the reply port). However, we can safely make ! 2015: * and consume send-once rights for the notify port ! 2016: * as long as we hold the space locked. This isn't ! 2017: * an atomicity problem, because the only way ! 2018: * to detect that a send-once right has been created ! 2019: * and then consumed if it wasn't needed is by getting ! 2020: * at the receive right to look at ip_sorights, and ! 2021: * because the space is write-locked status calls can't ! 2022: * lookup the notify port receive right. When we make ! 2023: * the send-once right, we lock the notify port, ! 2024: * so any status calls in progress will be done. ! 2025: */ ! 2026: ! 2027: is_write_lock(space); ! 2028: ! 2029: for (;;) { ! 2030: ipc_port_request_index_t request; ! 2031: ! 2032: if (!space->is_active) { ! 2033: is_write_unlock(space); ! 2034: return (MACH_RCV_HEADER_ERROR| ! 2035: MACH_MSG_IPC_SPACE); ! 2036: } ! 2037: ! 2038: if (notify != MACH_PORT_NULL) { ! 2039: notify_port = ipc_port_lookup_notify(space, ! 2040: notify); ! 2041: if (notify_port == IP_NULL) { ! 2042: is_write_unlock(space); ! 2043: return MACH_RCV_INVALID_NOTIFY; ! 2044: } ! 2045: } else ! 2046: notify_port = IP_NULL; ! 2047: ! 2048: if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) && ! 2049: ipc_right_reverse(space, (ipc_object_t) reply, ! 2050: &reply_name, &entry)) { ! 2051: /* reply port is locked and active */ ! 2052: ! 2053: /* ! 2054: * We don't need the notify_port ! 2055: * send-once right, but we can't release ! 2056: * it here because reply port is locked. ! 2057: * Wait until after the copyout to ! 2058: * release the notify port right. ! 2059: */ ! 2060: ! 2061: assert(entry->ie_bits & ! 2062: MACH_PORT_TYPE_SEND_RECEIVE); ! 2063: break; ! 2064: } ! 2065: ! 2066: ip_lock(reply); ! 2067: if (!ip_active(reply)) { ! 2068: ip_release(reply); ! 2069: ip_check_unlock(reply); ! 2070: ! 2071: if (notify_port != IP_NULL) ! 2072: ipc_port_release_sonce(notify_port); ! 2073: ! 2074: ip_lock(dest); ! 2075: is_write_unlock(space); ! 2076: ! 2077: reply = IP_DEAD; ! 2078: reply_name = MACH_PORT_DEAD; ! 2079: goto copyout_dest; ! 2080: } ! 2081: ! 2082: kr = ipc_entry_get(space, &reply_name, &entry); ! 2083: if (kr != KERN_SUCCESS) { ! 2084: ip_unlock(reply); ! 2085: ! 2086: if (notify_port != IP_NULL) ! 2087: ipc_port_release_sonce(notify_port); ! 2088: ! 2089: /* space is locked */ ! 2090: kr = ipc_entry_grow_table(space); ! 2091: if (kr != KERN_SUCCESS) { ! 2092: /* space is unlocked */ ! 2093: ! 2094: if (kr == KERN_RESOURCE_SHORTAGE) ! 2095: return (MACH_RCV_HEADER_ERROR| ! 2096: MACH_MSG_IPC_KERNEL); ! 2097: else ! 2098: return (MACH_RCV_HEADER_ERROR| ! 2099: MACH_MSG_IPC_SPACE); ! 2100: } ! 2101: /* space is locked again; start over */ ! 2102: ! 2103: continue; ! 2104: } ! 2105: ! 2106: assert(IE_BITS_TYPE(entry->ie_bits) ! 2107: == MACH_PORT_TYPE_NONE); ! 2108: assert(entry->ie_object == IO_NULL); ! 2109: ! 2110: if (notify_port == IP_NULL) { ! 2111: /* not making a dead-name request */ ! 2112: ! 2113: entry->ie_object = (ipc_object_t) reply; ! 2114: break; ! 2115: } ! 2116: ! 2117: kr = ipc_port_dnrequest(reply, reply_name, ! 2118: notify_port, &request); ! 2119: if (kr != KERN_SUCCESS) { ! 2120: ip_unlock(reply); ! 2121: ! 2122: ipc_port_release_sonce(notify_port); ! 2123: ! 2124: ipc_entry_dealloc(space, reply_name, entry); ! 2125: is_write_unlock(space); ! 2126: ! 2127: ip_lock(reply); ! 2128: if (!ip_active(reply)) { ! 2129: /* will fail next time around loop */ ! 2130: ! 2131: ip_unlock(reply); ! 2132: is_write_lock(space); ! 2133: continue; ! 2134: } ! 2135: ! 2136: kr = ipc_port_dngrow(reply); ! 2137: /* port is unlocked */ ! 2138: if (kr != KERN_SUCCESS) ! 2139: return (MACH_RCV_HEADER_ERROR| ! 2140: MACH_MSG_IPC_KERNEL); ! 2141: ! 2142: is_write_lock(space); ! 2143: continue; ! 2144: } ! 2145: ! 2146: notify_port = IP_NULL; /* don't release right below */ ! 2147: ! 2148: entry->ie_object = (ipc_object_t) reply; ! 2149: entry->ie_request = request; ! 2150: break; ! 2151: } ! 2152: ! 2153: /* space and reply port are locked and active */ ! 2154: ! 2155: ip_reference(reply); /* hold onto the reply port */ ! 2156: ! 2157: kr = ipc_right_copyout(space, reply_name, entry, ! 2158: reply_type, TRUE, (ipc_object_t) reply); ! 2159: /* reply port is unlocked */ ! 2160: assert(kr == KERN_SUCCESS); ! 2161: ! 2162: if (notify_port != IP_NULL) ! 2163: ipc_port_release_sonce(notify_port); ! 2164: ! 2165: ip_lock(dest); ! 2166: is_write_unlock(space); ! 2167: } else { ! 2168: /* ! 2169: * No reply port! This is an easy case. ! 2170: * We only need to have the space locked ! 2171: * when checking notify and when locking ! 2172: * the destination (to ensure atomicity). ! 2173: */ ! 2174: ! 2175: is_read_lock(space); ! 2176: if (!space->is_active) { ! 2177: is_read_unlock(space); ! 2178: return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE; ! 2179: } ! 2180: ! 2181: if (notify != MACH_PORT_NULL) { ! 2182: ipc_entry_t entry; ! 2183: ! 2184: /* must check notify even though it won't be used */ ! 2185: ! 2186: if (((entry = ipc_entry_lookup(space, notify)) ! 2187: == IE_NULL) || ! 2188: ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) { ! 2189: is_read_unlock(space); ! 2190: return MACH_RCV_INVALID_NOTIFY; ! 2191: } ! 2192: } ! 2193: ! 2194: ip_lock(dest); ! 2195: is_read_unlock(space); ! 2196: ! 2197: reply_name = (mach_port_t) reply; ! 2198: } ! 2199: ! 2200: /* ! 2201: * At this point, the space is unlocked and the destination ! 2202: * port is locked. (Lock taken while space was locked.) ! 2203: * reply_name is taken care of; we still need dest_name. ! 2204: * We still hold a ref for reply (if it is valid). ! 2205: * ! 2206: * If the space holds receive rights for the destination, ! 2207: * we return its name for the right. Otherwise the task ! 2208: * managed to destroy or give away the receive right between ! 2209: * receiving the message and this copyout. If the destination ! 2210: * is dead, return MACH_PORT_DEAD, and if the receive right ! 2211: * exists somewhere else (another space, in transit) ! 2212: * return MACH_PORT_NULL. ! 2213: * ! 2214: * Making this copyout operation atomic with the previous ! 2215: * copyout of the reply port is a bit tricky. If there was ! 2216: * no real reply port (it wasn't IP_VALID) then this isn't ! 2217: * an issue. If the reply port was dead at copyout time, ! 2218: * then we are OK, because if dest is dead we serialize ! 2219: * after the death of both ports and if dest is alive ! 2220: * we serialize after reply died but before dest's (later) death. ! 2221: * So assume reply was alive when we copied it out. If dest ! 2222: * is alive, then we are OK because we serialize before ! 2223: * the ports' deaths. So assume dest is dead when we look at it. ! 2224: * If reply dies/died after dest, then we are OK because ! 2225: * we serialize after dest died but before reply dies. ! 2226: * So the hard case is when reply is alive at copyout, ! 2227: * dest is dead at copyout, and reply died before dest died. ! 2228: * In this case pretend that dest is still alive, so ! 2229: * we serialize while both ports are alive. ! 2230: * ! 2231: * Because the space lock is held across the copyout of reply ! 2232: * and locking dest, the receive right for dest can't move ! 2233: * in or out of the space while the copyouts happen, so ! 2234: * that isn't an atomicity problem. In the last hard case ! 2235: * above, this implies that when dest is dead that the ! 2236: * space couldn't have had receive rights for dest at ! 2237: * the time reply was copied-out, so when we pretend ! 2238: * that dest is still alive, we can return MACH_PORT_NULL. ! 2239: * ! 2240: * If dest == reply, then we have to make it look like ! 2241: * either both copyouts happened before the port died, ! 2242: * or both happened after the port died. This special ! 2243: * case works naturally if the timestamp comparison ! 2244: * is done correctly. ! 2245: */ ! 2246: ! 2247: copyout_dest: ! 2248: ! 2249: if (ip_active(dest)) { ! 2250: ipc_object_copyout_dest(space, (ipc_object_t) dest, ! 2251: dest_type, &dest_name); ! 2252: /* dest is unlocked */ ! 2253: } else { ! 2254: ipc_port_timestamp_t timestamp; ! 2255: ! 2256: timestamp = dest->ip_timestamp; ! 2257: ip_release(dest); ! 2258: ip_check_unlock(dest); ! 2259: ! 2260: if (IP_VALID(reply)) { ! 2261: ip_lock(reply); ! 2262: if (ip_active(reply) || ! 2263: IP_TIMESTAMP_ORDER(timestamp, ! 2264: reply->ip_timestamp)) ! 2265: dest_name = MACH_PORT_DEAD; ! 2266: else ! 2267: dest_name = MACH_PORT_NULL; ! 2268: ip_unlock(reply); ! 2269: } else ! 2270: dest_name = MACH_PORT_DEAD; ! 2271: } ! 2272: ! 2273: if (IP_VALID(reply)) ! 2274: ipc_port_release(reply); ! 2275: ! 2276: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 2277: MACH_MSGH_BITS(reply_type, dest_type)); ! 2278: msg->msgh_local_port = dest_name; ! 2279: msg->msgh_remote_port = reply_name; ! 2280: } ! 2281: ! 2282: return MACH_MSG_SUCCESS; ! 2283: } ! 2284: ! 2285: /* ! 2286: * Routine: ipc_kmsg_copyout_object ! 2287: * Purpose: ! 2288: * Copy-out a port right. Always returns a name, ! 2289: * even for unsuccessful return codes. Always ! 2290: * consumes the supplied object. ! 2291: * Conditions: ! 2292: * Nothing locked. ! 2293: * Returns: ! 2294: * MACH_MSG_SUCCESS The space acquired the right ! 2295: * (name is valid) or the object is dead (MACH_PORT_DEAD). ! 2296: * MACH_MSG_IPC_SPACE No room in space for the right, ! 2297: * or the space is dead. (Name is MACH_PORT_NULL.) ! 2298: * MACH_MSG_IPC_KERNEL Kernel resource shortage. ! 2299: * (Name is MACH_PORT_NULL.) ! 2300: */ ! 2301: ! 2302: mach_msg_return_t ! 2303: ipc_kmsg_copyout_object(space, object, msgt_name, namep) ! 2304: ipc_space_t space; ! 2305: ipc_object_t object; ! 2306: mach_msg_type_name_t msgt_name; ! 2307: mach_port_t *namep; ! 2308: { ! 2309: if (!IO_VALID(object)) { ! 2310: *namep = (mach_port_t) object; ! 2311: return MACH_MSG_SUCCESS; ! 2312: } ! 2313: ! 2314: #ifndef MIGRATING_THREADS ! 2315: /* ! 2316: * Attempt quick copyout of send rights. We optimize for a ! 2317: * live port for which the receiver holds send (and not ! 2318: * receive) rights in his local table. ! 2319: */ ! 2320: ! 2321: if (msgt_name != MACH_MSG_TYPE_PORT_SEND) ! 2322: goto slow_copyout; ! 2323: ! 2324: { ! 2325: register ipc_port_t port = (ipc_port_t) object; ! 2326: ipc_entry_t entry; ! 2327: ! 2328: is_write_lock(space); ! 2329: if (!space->is_active) { ! 2330: is_write_unlock(space); ! 2331: goto slow_copyout; ! 2332: } ! 2333: ! 2334: ip_lock(port); ! 2335: if (!ip_active(port) || ! 2336: !ipc_hash_local_lookup(space, (ipc_object_t) port, ! 2337: namep, &entry)) { ! 2338: ip_unlock(port); ! 2339: is_write_unlock(space); ! 2340: goto slow_copyout; ! 2341: } ! 2342: ! 2343: /* ! 2344: * Copyout the send right, incrementing urefs ! 2345: * unless it would overflow, and consume the right. ! 2346: */ ! 2347: ! 2348: assert(port->ip_srights > 1); ! 2349: port->ip_srights--; ! 2350: ip_release(port); ! 2351: ip_unlock(port); ! 2352: ! 2353: assert(entry->ie_bits & MACH_PORT_TYPE_SEND); ! 2354: assert(IE_BITS_UREFS(entry->ie_bits) > 0); ! 2355: assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX); ! 2356: ! 2357: { ! 2358: register ipc_entry_bits_t bits = entry->ie_bits + 1; ! 2359: ! 2360: if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) ! 2361: entry->ie_bits = bits; ! 2362: } ! 2363: ! 2364: is_write_unlock(space); ! 2365: return MACH_MSG_SUCCESS; ! 2366: } ! 2367: ! 2368: slow_copyout: ! 2369: #endif /* MIGRATING_THREADS */ ! 2370: ! 2371: { ! 2372: kern_return_t kr; ! 2373: ! 2374: kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep); ! 2375: if (kr != KERN_SUCCESS) { ! 2376: ipc_object_destroy(object, msgt_name); ! 2377: ! 2378: if (kr == KERN_INVALID_CAPABILITY) ! 2379: *namep = MACH_PORT_DEAD; ! 2380: else { ! 2381: *namep = MACH_PORT_NULL; ! 2382: ! 2383: if (kr == KERN_RESOURCE_SHORTAGE) ! 2384: return MACH_MSG_IPC_KERNEL; ! 2385: else ! 2386: return MACH_MSG_IPC_SPACE; ! 2387: } ! 2388: } ! 2389: ! 2390: return MACH_MSG_SUCCESS; ! 2391: } ! 2392: } ! 2393: ! 2394: /* ! 2395: * Routine: ipc_kmsg_copyout_body ! 2396: * Purpose: ! 2397: * "Copy-out" port rights and out-of-line memory ! 2398: * in the body of a message. ! 2399: * ! 2400: * The error codes are a combination of special bits. ! 2401: * The copyout proceeds despite errors. ! 2402: * Conditions: ! 2403: * Nothing locked. ! 2404: * Returns: ! 2405: * MACH_MSG_SUCCESS Successful copyout. ! 2406: * MACH_MSG_IPC_SPACE No room for port right in name space. ! 2407: * MACH_MSG_VM_SPACE No room for memory in address space. ! 2408: * MACH_MSG_IPC_KERNEL Resource shortage handling port right. ! 2409: * MACH_MSG_VM_KERNEL Resource shortage handling memory. ! 2410: */ ! 2411: ! 2412: mach_msg_return_t ! 2413: ipc_kmsg_copyout_body(saddr, eaddr, space, map) ! 2414: vm_offset_t saddr, eaddr; ! 2415: ipc_space_t space; ! 2416: vm_map_t map; ! 2417: { ! 2418: mach_msg_return_t mr = MACH_MSG_SUCCESS; ! 2419: kern_return_t kr; ! 2420: ! 2421: while (saddr < eaddr) { ! 2422: vm_offset_t taddr = saddr; ! 2423: mach_msg_type_long_t *type; ! 2424: mach_msg_type_name_t name; ! 2425: mach_msg_type_size_t size; ! 2426: mach_msg_type_number_t number; ! 2427: boolean_t is_inline, longform, is_port; ! 2428: vm_size_t length; ! 2429: vm_offset_t addr; ! 2430: ! 2431: type = (mach_msg_type_long_t *) saddr; ! 2432: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 2433: longform = ((mach_msg_type_t*)type)->msgt_longform; ! 2434: if (longform) { ! 2435: /* This must be aligned */ ! 2436: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 2437: (is_misaligned(type))) { ! 2438: saddr = ptr_align(saddr); ! 2439: continue; ! 2440: } ! 2441: name = type->msgtl_name; ! 2442: size = type->msgtl_size; ! 2443: number = type->msgtl_number; ! 2444: saddr += sizeof(mach_msg_type_long_t); ! 2445: } else { ! 2446: name = ((mach_msg_type_t*)type)->msgt_name; ! 2447: size = ((mach_msg_type_t*)type)->msgt_size; ! 2448: number = ((mach_msg_type_t*)type)->msgt_number; ! 2449: saddr += sizeof(mach_msg_type_t); ! 2450: } ! 2451: ! 2452: /* padding (ptrs and ports) ? */ ! 2453: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 2454: ((size >> 3) == sizeof(natural_t))) ! 2455: saddr = ptr_align(saddr); ! 2456: ! 2457: /* calculate length of data in bytes, rounding up */ ! 2458: ! 2459: length = ((number * size) + 7) >> 3; ! 2460: ! 2461: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 2462: ! 2463: if (is_port) { ! 2464: mach_port_t *objects; ! 2465: mach_msg_type_number_t i; ! 2466: ! 2467: if (!is_inline && (length != 0)) { ! 2468: /* first allocate memory in the map */ ! 2469: ! 2470: kr = vm_allocate(map, &addr, length, TRUE); ! 2471: if (kr != KERN_SUCCESS) { ! 2472: ipc_kmsg_clean_body(taddr, saddr); ! 2473: goto vm_copyout_failure; ! 2474: } ! 2475: } ! 2476: ! 2477: objects = (mach_port_t *) ! 2478: (is_inline ? saddr : * (vm_offset_t *) saddr); ! 2479: ! 2480: /* copyout port rights carried in the message */ ! 2481: ! 2482: for (i = 0; i < number; i++) { ! 2483: ipc_object_t object = ! 2484: (ipc_object_t) objects[i]; ! 2485: ! 2486: mr |= ipc_kmsg_copyout_object(space, object, ! 2487: name, &objects[i]); ! 2488: } ! 2489: } ! 2490: ! 2491: if (is_inline) { ! 2492: /* inline data sizes round up to int boundaries */ ! 2493: ! 2494: ((mach_msg_type_t*)type)->msgt_deallocate = FALSE; ! 2495: saddr += (length + 3) &~ 3; ! 2496: } else { ! 2497: vm_offset_t data; ! 2498: ! 2499: if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t)) ! 2500: saddr = ptr_align(saddr); ! 2501: ! 2502: data = * (vm_offset_t *) saddr; ! 2503: ! 2504: /* copyout memory carried in the message */ ! 2505: ! 2506: if (length == 0) { ! 2507: assert(data == 0); ! 2508: addr = 0; ! 2509: } else if (is_port) { ! 2510: /* copyout to memory allocated above */ ! 2511: ! 2512: (void) copyoutmap(map, (char *) data, ! 2513: (char *) addr, length); ! 2514: kfree(data, length); ! 2515: } else { ! 2516: vm_map_copy_t copy = (vm_map_copy_t) data; ! 2517: ! 2518: kr = vm_map_copyout(map, &addr, copy); ! 2519: if (kr != KERN_SUCCESS) { ! 2520: vm_map_copy_discard(copy); ! 2521: ! 2522: vm_copyout_failure: ! 2523: ! 2524: addr = 0; ! 2525: if (longform) ! 2526: type->msgtl_size = 0; ! 2527: else ! 2528: ((mach_msg_type_t*)type)->msgt_size = 0; ! 2529: ! 2530: if (kr == KERN_RESOURCE_SHORTAGE) ! 2531: mr |= MACH_MSG_VM_KERNEL; ! 2532: else ! 2533: mr |= MACH_MSG_VM_SPACE; ! 2534: } ! 2535: } ! 2536: ! 2537: ((mach_msg_type_t*)type)->msgt_deallocate = TRUE; ! 2538: * (vm_offset_t *) saddr = addr; ! 2539: saddr += sizeof(vm_offset_t); ! 2540: } ! 2541: } ! 2542: ! 2543: return mr; ! 2544: } ! 2545: ! 2546: /* ! 2547: * Routine: ipc_kmsg_copyout ! 2548: * Purpose: ! 2549: * "Copy-out" port rights and out-of-line memory ! 2550: * in the message. ! 2551: * Conditions: ! 2552: * Nothing locked. ! 2553: * Returns: ! 2554: * MACH_MSG_SUCCESS Copied out all rights and memory. ! 2555: * MACH_RCV_INVALID_NOTIFY Bad notify port. ! 2556: * Rights and memory in the message are intact. ! 2557: * MACH_RCV_HEADER_ERROR + special bits ! 2558: * Rights and memory in the message are intact. ! 2559: * MACH_RCV_BODY_ERROR + special bits ! 2560: * The message header was successfully copied out. ! 2561: * As much of the body was handled as possible. ! 2562: */ ! 2563: ! 2564: mach_msg_return_t ! 2565: ipc_kmsg_copyout(kmsg, space, map, notify) ! 2566: ipc_kmsg_t kmsg; ! 2567: ipc_space_t space; ! 2568: vm_map_t map; ! 2569: mach_port_t notify; ! 2570: { ! 2571: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 2572: mach_msg_return_t mr; ! 2573: ! 2574: mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify); ! 2575: if (mr != MACH_MSG_SUCCESS) ! 2576: return mr; ! 2577: ! 2578: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 2579: vm_offset_t saddr, eaddr; ! 2580: ! 2581: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 2582: eaddr = (vm_offset_t) &kmsg->ikm_header + ! 2583: kmsg->ikm_header.msgh_size; ! 2584: ! 2585: mr = ipc_kmsg_copyout_body(saddr, eaddr, space, map); ! 2586: if (mr != MACH_MSG_SUCCESS) ! 2587: mr |= MACH_RCV_BODY_ERROR; ! 2588: } ! 2589: ! 2590: return mr; ! 2591: } ! 2592: ! 2593: /* ! 2594: * Routine: ipc_kmsg_copyout_pseudo ! 2595: * Purpose: ! 2596: * Does a pseudo-copyout of the message. ! 2597: * This is like a regular copyout, except ! 2598: * that the ports in the header are handled ! 2599: * as if they are in the body. They aren't reversed. ! 2600: * ! 2601: * The error codes are a combination of special bits. ! 2602: * The copyout proceeds despite errors. ! 2603: * Conditions: ! 2604: * Nothing locked. ! 2605: * Returns: ! 2606: * MACH_MSG_SUCCESS Successful copyout. ! 2607: * MACH_MSG_IPC_SPACE No room for port right in name space. ! 2608: * MACH_MSG_VM_SPACE No room for memory in address space. ! 2609: * MACH_MSG_IPC_KERNEL Resource shortage handling port right. ! 2610: * MACH_MSG_VM_KERNEL Resource shortage handling memory. ! 2611: */ ! 2612: ! 2613: mach_msg_return_t ! 2614: ipc_kmsg_copyout_pseudo( ! 2615: ipc_kmsg_t kmsg, ! 2616: ipc_space_t space, ! 2617: vm_map_t map) ! 2618: { ! 2619: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 2620: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 2621: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 2622: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 2623: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 2624: mach_port_t dest_name, reply_name; ! 2625: mach_msg_return_t mr; ! 2626: ! 2627: assert(IO_VALID(dest)); ! 2628: ! 2629: mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) | ! 2630: ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name)); ! 2631: ! 2632: kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR; ! 2633: kmsg->ikm_header.msgh_remote_port = dest_name; ! 2634: kmsg->ikm_header.msgh_local_port = reply_name; ! 2635: ! 2636: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 2637: vm_offset_t saddr, eaddr; ! 2638: ! 2639: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 2640: eaddr = (vm_offset_t) &kmsg->ikm_header + ! 2641: kmsg->ikm_header.msgh_size; ! 2642: ! 2643: mr |= ipc_kmsg_copyout_body(saddr, eaddr, space, map); ! 2644: } ! 2645: ! 2646: return mr; ! 2647: } ! 2648: ! 2649: /* ! 2650: * Routine: ipc_kmsg_copyout_dest ! 2651: * Purpose: ! 2652: * Copies out the destination port in the message. ! 2653: * Destroys all other rights and memory in the message. ! 2654: * Conditions: ! 2655: * Nothing locked. ! 2656: */ ! 2657: ! 2658: void ! 2659: ipc_kmsg_copyout_dest(kmsg, space) ! 2660: ipc_kmsg_t kmsg; ! 2661: ipc_space_t space; ! 2662: { ! 2663: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 2664: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 2665: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 2666: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 2667: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 2668: mach_port_t dest_name, reply_name; ! 2669: ! 2670: assert(IO_VALID(dest)); ! 2671: ! 2672: io_lock(dest); ! 2673: if (io_active(dest)) { ! 2674: ipc_object_copyout_dest(space, dest, dest_type, &dest_name); ! 2675: /* dest is unlocked */ ! 2676: } else { ! 2677: io_release(dest); ! 2678: io_check_unlock(dest); ! 2679: dest_name = MACH_PORT_DEAD; ! 2680: } ! 2681: ! 2682: if (IO_VALID(reply)) { ! 2683: ipc_object_destroy(reply, reply_type); ! 2684: reply_name = MACH_PORT_NULL; ! 2685: } else ! 2686: reply_name = (mach_port_t) reply; ! 2687: ! 2688: kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 2689: MACH_MSGH_BITS(reply_type, dest_type)); ! 2690: kmsg->ikm_header.msgh_local_port = dest_name; ! 2691: kmsg->ikm_header.msgh_remote_port = reply_name; ! 2692: ! 2693: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 2694: vm_offset_t saddr, eaddr; ! 2695: ! 2696: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 2697: eaddr = (vm_offset_t) &kmsg->ikm_header + ! 2698: kmsg->ikm_header.msgh_size; ! 2699: ! 2700: ipc_kmsg_clean_body(saddr, eaddr); ! 2701: } ! 2702: } ! 2703: ! 2704: #if NORMA_IPC || NORMA_VM ! 2705: /* ! 2706: * Routine: ipc_kmsg_copyout_to_kernel ! 2707: * Purpose: ! 2708: * Copies out the destination and reply ports in the message. ! 2709: * Leaves all other rights and memory in the message alone. ! 2710: * Conditions: ! 2711: * Nothing locked. ! 2712: * ! 2713: * Derived from ipc_kmsg_copyout_dest. ! 2714: * Use by mach_msg_rpc_from_kernel (which used to use copyout_dest). ! 2715: * We really do want to save rights and memory. ! 2716: */ ! 2717: ! 2718: void ! 2719: ipc_kmsg_copyout_to_kernel(kmsg, space) ! 2720: ipc_kmsg_t kmsg; ! 2721: ipc_space_t space; ! 2722: { ! 2723: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 2724: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 2725: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 2726: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 2727: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 2728: mach_port_t dest_name, reply_name; ! 2729: ! 2730: assert(IO_VALID(dest)); ! 2731: ! 2732: io_lock(dest); ! 2733: if (io_active(dest)) { ! 2734: ipc_object_copyout_dest(space, dest, dest_type, &dest_name); ! 2735: /* dest is unlocked */ ! 2736: } else { ! 2737: io_release(dest); ! 2738: io_check_unlock(dest); ! 2739: dest_name = MACH_PORT_DEAD; ! 2740: } ! 2741: ! 2742: reply_name = (mach_port_t) reply; ! 2743: ! 2744: kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 2745: MACH_MSGH_BITS(reply_type, dest_type)); ! 2746: kmsg->ikm_header.msgh_local_port = dest_name; ! 2747: kmsg->ikm_header.msgh_remote_port = reply_name; ! 2748: } ! 2749: #endif /* NORMA_IPC || NORMA_VM */ ! 2750: ! 2751: #if MACH_IPC_COMPAT ! 2752: ! 2753: /* ! 2754: * Routine: ipc_kmsg_copyin_compat ! 2755: * Purpose: ! 2756: * "Copy-in" port rights and out-of-line memory ! 2757: * in the message. ! 2758: * ! 2759: * In all failure cases, the message is left holding ! 2760: * no rights or memory. However, the message buffer ! 2761: * is not deallocated. If successful, the message ! 2762: * contains a valid destination port. ! 2763: * Conditions: ! 2764: * Nothing locked. ! 2765: * Returns: ! 2766: * MACH_MSG_SUCCESS Successful copyin. ! 2767: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 2768: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 2769: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory. ! 2770: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body. ! 2771: * MACH_SEND_INVALID_TYPE Bad type specification. ! 2772: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data. ! 2773: */ ! 2774: ! 2775: mach_msg_return_t ! 2776: ipc_kmsg_copyin_compat(kmsg, space, map) ! 2777: ipc_kmsg_t kmsg; ! 2778: ipc_space_t space; ! 2779: vm_map_t map; ! 2780: { ! 2781: msg_header_t msg; ! 2782: mach_port_t dest_name; ! 2783: mach_port_t reply_name; ! 2784: ipc_object_t dest, reply; ! 2785: mach_msg_type_name_t dest_type, reply_type; ! 2786: vm_offset_t saddr, eaddr; ! 2787: boolean_t complex; ! 2788: kern_return_t kr; ! 2789: boolean_t use_page_lists, steal_pages; ! 2790: ! 2791: msg = * (msg_header_t *) &kmsg->ikm_header; ! 2792: dest_name = (mach_port_t) msg.msg_remote_port; ! 2793: reply_name = (mach_port_t) msg.msg_local_port; ! 2794: ! 2795: /* translate the destination and reply ports */ ! 2796: ! 2797: kr = ipc_object_copyin_header(space, dest_name, &dest, &dest_type); ! 2798: if (kr != KERN_SUCCESS) ! 2799: return MACH_SEND_INVALID_DEST; ! 2800: ! 2801: if (reply_name == MACH_PORT_NULL) { ! 2802: reply = IO_NULL; ! 2803: reply_type = 0; ! 2804: } else { ! 2805: kr = ipc_object_copyin_header(space, reply_name, ! 2806: &reply, &reply_type); ! 2807: if (kr != KERN_SUCCESS) { ! 2808: ipc_object_destroy(dest, dest_type); ! 2809: return MACH_SEND_INVALID_REPLY; ! 2810: } ! 2811: } ! 2812: ! 2813: kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(dest_type, reply_type); ! 2814: kmsg->ikm_header.msgh_size = (mach_msg_size_t) msg.msg_size; ! 2815: kmsg->ikm_header.msgh_remote_port = (mach_port_t) dest; ! 2816: kmsg->ikm_header.msgh_local_port = (mach_port_t) reply; ! 2817: kmsg->ikm_header.msgh_seqno = (mach_msg_kind_t) msg.msg_type; ! 2818: kmsg->ikm_header.msgh_id = (mach_msg_id_t) msg.msg_id; ! 2819: ! 2820: if (msg.msg_simple) ! 2821: return MACH_MSG_SUCCESS; ! 2822: ! 2823: complex = FALSE; ! 2824: use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest)); ! 2825: steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest)); ! 2826: ! 2827: #if NORMA_IPC ! 2828: if (IP_NORMA_IS_PROXY((ipc_port_t) dest)) { ! 2829: use_page_lists = TRUE; ! 2830: steal_pages = TRUE; ! 2831: } ! 2832: #endif /* NORMA_IPC */ ! 2833: ! 2834: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 2835: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size; ! 2836: ! 2837: while (saddr < eaddr) { ! 2838: vm_offset_t taddr = saddr; ! 2839: mach_msg_type_long_t *type; ! 2840: mach_msg_type_name_t name; ! 2841: mach_msg_type_size_t size; ! 2842: mach_msg_type_number_t number; ! 2843: boolean_t is_inline, longform, dealloc, is_port; ! 2844: vm_offset_t data; ! 2845: vm_size_t length; ! 2846: ! 2847: type = (mach_msg_type_long_t *) saddr; ! 2848: ! 2849: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) || ! 2850: ((longform = ((mach_msg_type_t*)type)->msgt_longform) && ! 2851: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) { ! 2852: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0); ! 2853: return MACH_SEND_MSG_TOO_SMALL; ! 2854: } ! 2855: ! 2856: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 2857: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate; ! 2858: if (longform) { ! 2859: /* This must be aligned */ ! 2860: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 2861: (is_misaligned(type))) { ! 2862: saddr = ptr_align(saddr); ! 2863: continue; ! 2864: } ! 2865: name = type->msgtl_name; ! 2866: size = type->msgtl_size; ! 2867: number = type->msgtl_number; ! 2868: saddr += sizeof(mach_msg_type_long_t); ! 2869: } else { ! 2870: name = ((mach_msg_type_t*)type)->msgt_name; ! 2871: size = ((mach_msg_type_t*)type)->msgt_size; ! 2872: number = ((mach_msg_type_t*)type)->msgt_number; ! 2873: saddr += sizeof(mach_msg_type_t); ! 2874: } ! 2875: ! 2876: is_port = MSG_TYPE_PORT_ANY(name); ! 2877: ! 2878: if (is_port && (size != PORT_T_SIZE_IN_BITS)) { ! 2879: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0); ! 2880: return MACH_SEND_INVALID_TYPE; ! 2881: } ! 2882: ! 2883: /* ! 2884: * New IPC says these should be zero, but old IPC ! 2885: * tasks often leave them with random values. So ! 2886: * we have to clear them. ! 2887: */ ! 2888: ! 2889: ((mach_msg_type_t*)type)->msgt_unused = 0; ! 2890: if (longform) { ! 2891: type->msgtl_header.msgt_name = 0; ! 2892: type->msgtl_header.msgt_size = 0; ! 2893: type->msgtl_header.msgt_number = 0; ! 2894: } ! 2895: ! 2896: /* padding (ptrs and ports) ? */ ! 2897: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 2898: ((size >> 3) == sizeof(natural_t))) ! 2899: saddr = ptr_align(saddr); ! 2900: ! 2901: /* calculate length of data in bytes, rounding up */ ! 2902: ! 2903: length = ((number * size) + 7) >> 3; ! 2904: ! 2905: if (is_inline) { ! 2906: vm_size_t amount; ! 2907: ! 2908: /* inline data sizes round up to int boundaries */ ! 2909: ! 2910: amount = (length + 3) &~ 3; ! 2911: if ((eaddr - saddr) < amount) { ! 2912: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0); ! 2913: return MACH_SEND_MSG_TOO_SMALL; ! 2914: } ! 2915: ! 2916: data = saddr; ! 2917: saddr += amount; ! 2918: } else { ! 2919: vm_offset_t addr; ! 2920: ! 2921: if ((eaddr - saddr) < sizeof(vm_offset_t)) { ! 2922: ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0); ! 2923: return MACH_SEND_MSG_TOO_SMALL; ! 2924: } ! 2925: ! 2926: /* grab the out-of-line data */ ! 2927: ! 2928: addr = * (vm_offset_t *) saddr; ! 2929: ! 2930: if (length == 0) ! 2931: data = 0; ! 2932: else if (is_port) { ! 2933: data = kalloc(length); ! 2934: if (data == 0) ! 2935: goto invalid_memory; ! 2936: ! 2937: if (copyinmap(map, (char *) addr, ! 2938: (char *) data, length) || ! 2939: (dealloc && ! 2940: (vm_deallocate(map, addr, length) != ! 2941: KERN_SUCCESS))) { ! 2942: kfree(data, length); ! 2943: goto invalid_memory; ! 2944: } ! 2945: } else { ! 2946: vm_map_copy_t copy; ! 2947: ! 2948: if (use_page_lists) { ! 2949: kr = vm_map_copyin_page_list(map, ! 2950: addr, length, dealloc, ! 2951: steal_pages, ©, FALSE); ! 2952: } else { ! 2953: kr = vm_map_copyin(map, addr, length, ! 2954: dealloc, ! 2955: ©); ! 2956: } ! 2957: if (kr != KERN_SUCCESS) { ! 2958: invalid_memory: ! 2959: ipc_kmsg_clean_partial(kmsg, taddr, ! 2960: FALSE, 0); ! 2961: return MACH_SEND_INVALID_MEMORY; ! 2962: } ! 2963: ! 2964: data = (vm_offset_t) copy; ! 2965: } ! 2966: ! 2967: * (vm_offset_t *) saddr = data; ! 2968: saddr += sizeof(vm_offset_t); ! 2969: complex = TRUE; ! 2970: } ! 2971: ! 2972: if (is_port) { ! 2973: mach_msg_type_name_t newname = ! 2974: ipc_object_copyin_type(name); ! 2975: ipc_object_t *objects = (ipc_object_t *) data; ! 2976: mach_msg_type_number_t i; ! 2977: ! 2978: if (longform) ! 2979: type->msgtl_name = newname; ! 2980: else ! 2981: ((mach_msg_type_t*)type)->msgt_name = newname; ! 2982: ! 2983: for (i = 0; i < number; i++) { ! 2984: mach_port_t port = (mach_port_t) objects[i]; ! 2985: ipc_object_t object; ! 2986: ! 2987: if (!MACH_PORT_VALID(port)) ! 2988: continue; ! 2989: ! 2990: kr = ipc_object_copyin_compat(space, port, ! 2991: name, dealloc, &object); ! 2992: if (kr != KERN_SUCCESS) { ! 2993: ipc_kmsg_clean_partial(kmsg, taddr, ! 2994: TRUE, i); ! 2995: return MACH_SEND_INVALID_RIGHT; ! 2996: } ! 2997: ! 2998: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) && ! 2999: ipc_port_check_circularity( ! 3000: (ipc_port_t) object, ! 3001: (ipc_port_t) dest)) ! 3002: kmsg->ikm_header.msgh_bits |= ! 3003: MACH_MSGH_BITS_CIRCULAR; ! 3004: ! 3005: objects[i] = object; ! 3006: } ! 3007: ! 3008: complex = TRUE; ! 3009: } ! 3010: } ! 3011: ! 3012: if (complex) ! 3013: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX; ! 3014: ! 3015: return MACH_MSG_SUCCESS; ! 3016: } ! 3017: ! 3018: /* ! 3019: * Routine: ipc_kmsg_copyout_compat ! 3020: * Purpose: ! 3021: * "Copy-out" port rights and out-of-line memory ! 3022: * in the message, producing an old IPC message. ! 3023: * ! 3024: * Doesn't bother to handle the header atomically. ! 3025: * Skips over errors. Problem ports produce MACH_PORT_NULL ! 3026: * (MACH_PORT_DEAD is never produced), and problem memory ! 3027: * produces a zero address. ! 3028: * Conditions: ! 3029: * Nothing locked. ! 3030: * Returns: ! 3031: * MACH_MSG_SUCCESS Copied out rights and memory. ! 3032: */ ! 3033: ! 3034: mach_msg_return_t ! 3035: ipc_kmsg_copyout_compat(kmsg, space, map) ! 3036: ipc_kmsg_t kmsg; ! 3037: ipc_space_t space; ! 3038: vm_map_t map; ! 3039: { ! 3040: msg_header_t msg; ! 3041: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 3042: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 3043: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 3044: mach_port_t dest_name, reply_name; ! 3045: vm_offset_t saddr, eaddr; ! 3046: kern_return_t kr; ! 3047: ! 3048: assert(IO_VALID(dest)); ! 3049: ! 3050: io_lock(dest); ! 3051: if (io_active(dest)) { ! 3052: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 3053: ! 3054: ipc_object_copyout_dest(space, dest, dest_type, &dest_name); ! 3055: /* dest is unlocked */ ! 3056: } else { ! 3057: io_release(dest); ! 3058: io_check_unlock(dest); ! 3059: dest_name = MACH_PORT_NULL; ! 3060: } ! 3061: ! 3062: if (IO_VALID(reply)) { ! 3063: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 3064: ! 3065: kr = ipc_object_copyout_compat(space, reply, reply_type, ! 3066: &reply_name); ! 3067: if (kr != KERN_SUCCESS) { ! 3068: ipc_object_destroy(reply, reply_type); ! 3069: reply_name = MACH_PORT_NULL; ! 3070: } ! 3071: } else ! 3072: reply_name = MACH_PORT_NULL; ! 3073: ! 3074: msg.msg_unused = 0; ! 3075: msg.msg_simple = (mbits & MACH_MSGH_BITS_COMPLEX) ? FALSE : TRUE; ! 3076: msg.msg_size = (msg_size_t) kmsg->ikm_header.msgh_size; ! 3077: msg.msg_type = (integer_t) kmsg->ikm_header.msgh_seqno; ! 3078: msg.msg_local_port = (port_name_t) dest_name; ! 3079: msg.msg_remote_port = (port_name_t) reply_name; ! 3080: msg.msg_id = (integer_t) kmsg->ikm_header.msgh_id; ! 3081: * (msg_header_t *) &kmsg->ikm_header = msg; ! 3082: ! 3083: if (msg.msg_simple) ! 3084: return MACH_MSG_SUCCESS; ! 3085: ! 3086: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 3087: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size; ! 3088: ! 3089: while (saddr < eaddr) { ! 3090: vm_offset_t taddr = saddr; ! 3091: mach_msg_type_long_t *type; ! 3092: mach_msg_type_name_t name; ! 3093: mach_msg_type_size_t size; ! 3094: mach_msg_type_number_t number; ! 3095: boolean_t is_inline, longform, is_port; ! 3096: vm_size_t length; ! 3097: vm_offset_t addr; ! 3098: ! 3099: type = (mach_msg_type_long_t *) saddr; ! 3100: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 3101: longform = ((mach_msg_type_t*)type)->msgt_longform; ! 3102: if (longform) { ! 3103: /* This must be aligned */ ! 3104: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 3105: (is_misaligned(type))) { ! 3106: saddr = ptr_align(saddr); ! 3107: continue; ! 3108: } ! 3109: name = type->msgtl_name; ! 3110: size = type->msgtl_size; ! 3111: number = type->msgtl_number; ! 3112: saddr += sizeof(mach_msg_type_long_t); ! 3113: } else { ! 3114: name = ((mach_msg_type_t*)type)->msgt_name; ! 3115: size = ((mach_msg_type_t*)type)->msgt_size; ! 3116: number = ((mach_msg_type_t*)type)->msgt_number; ! 3117: saddr += sizeof(mach_msg_type_t); ! 3118: } ! 3119: ! 3120: /* padding (ptrs and ports) ? */ ! 3121: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 3122: ((size >> 3) == sizeof(natural_t))) ! 3123: saddr = ptr_align(saddr); ! 3124: ! 3125: /* calculate length of data in bytes, rounding up */ ! 3126: ! 3127: length = ((number * size) + 7) >> 3; ! 3128: ! 3129: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 3130: ! 3131: if (is_port) { ! 3132: mach_port_t *objects; ! 3133: mach_msg_type_number_t i; ! 3134: mach_msg_type_name_t newname; ! 3135: ! 3136: if (!is_inline && (length != 0)) { ! 3137: /* first allocate memory in the map */ ! 3138: ! 3139: kr = vm_allocate(map, &addr, length, TRUE); ! 3140: if (kr != KERN_SUCCESS) { ! 3141: ipc_kmsg_clean_body(taddr, saddr); ! 3142: goto vm_copyout_failure; ! 3143: } ! 3144: } ! 3145: ! 3146: newname = ipc_object_copyout_type_compat(name); ! 3147: if (longform) ! 3148: type->msgtl_name = newname; ! 3149: else ! 3150: ((mach_msg_type_t*)type)->msgt_name = newname; ! 3151: ! 3152: objects = (mach_port_t *) ! 3153: (is_inline ? saddr : * (vm_offset_t *) saddr); ! 3154: ! 3155: /* copyout port rights carried in the message */ ! 3156: ! 3157: for (i = 0; i < number; i++) { ! 3158: ipc_object_t object = ! 3159: (ipc_object_t) objects[i]; ! 3160: ! 3161: if (!IO_VALID(object)) { ! 3162: objects[i] = MACH_PORT_NULL; ! 3163: continue; ! 3164: } ! 3165: ! 3166: kr = ipc_object_copyout_compat(space, object, ! 3167: name, &objects[i]); ! 3168: if (kr != KERN_SUCCESS) { ! 3169: ipc_object_destroy(object, name); ! 3170: objects[i] = MACH_PORT_NULL; ! 3171: } ! 3172: } ! 3173: } ! 3174: ! 3175: if (is_inline) { ! 3176: /* inline data sizes round up to int boundaries */ ! 3177: ! 3178: saddr += (length + 3) &~ 3; ! 3179: } else { ! 3180: vm_offset_t data = * (vm_offset_t *) saddr; ! 3181: ! 3182: /* copyout memory carried in the message */ ! 3183: ! 3184: if (length == 0) { ! 3185: assert(data == 0); ! 3186: addr = 0; ! 3187: } else if (is_port) { ! 3188: /* copyout to memory allocated above */ ! 3189: ! 3190: (void) copyoutmap(map, (char *) data, ! 3191: (char *) addr, length); ! 3192: kfree(data, length); ! 3193: } else { ! 3194: vm_map_copy_t copy = (vm_map_copy_t) data; ! 3195: ! 3196: kr = vm_map_copyout(map, &addr, copy); ! 3197: if (kr != KERN_SUCCESS) { ! 3198: vm_map_copy_discard(copy); ! 3199: ! 3200: vm_copyout_failure: ! 3201: ! 3202: addr = 0; ! 3203: } ! 3204: } ! 3205: ! 3206: * (vm_offset_t *) saddr = addr; ! 3207: saddr += sizeof(vm_offset_t); ! 3208: } ! 3209: } ! 3210: ! 3211: return MACH_MSG_SUCCESS; ! 3212: } ! 3213: ! 3214: #endif /* MACH_IPC_COMPAT */ ! 3215: ! 3216: #include <mach_kdb.h> ! 3217: #if MACH_KDB ! 3218: ! 3219: char * ! 3220: ipc_type_name(type_name, received) ! 3221: int type_name; ! 3222: boolean_t received; ! 3223: { ! 3224: switch (type_name) { ! 3225: case MACH_MSG_TYPE_BOOLEAN: ! 3226: return "boolean"; ! 3227: ! 3228: case MACH_MSG_TYPE_INTEGER_16: ! 3229: return "short"; ! 3230: ! 3231: case MACH_MSG_TYPE_INTEGER_32: ! 3232: return "int32"; ! 3233: ! 3234: case MACH_MSG_TYPE_INTEGER_64: ! 3235: return "int64"; ! 3236: ! 3237: case MACH_MSG_TYPE_CHAR: ! 3238: return "char"; ! 3239: ! 3240: case MACH_MSG_TYPE_BYTE: ! 3241: return "byte"; ! 3242: ! 3243: case MACH_MSG_TYPE_REAL: ! 3244: return "real"; ! 3245: ! 3246: case MACH_MSG_TYPE_STRING: ! 3247: return "string"; ! 3248: ! 3249: case MACH_MSG_TYPE_PORT_NAME: ! 3250: return "port_name"; ! 3251: ! 3252: case MACH_MSG_TYPE_MOVE_RECEIVE: ! 3253: if (received) { ! 3254: return "port_receive"; ! 3255: } else { ! 3256: return "move_receive"; ! 3257: } ! 3258: ! 3259: case MACH_MSG_TYPE_MOVE_SEND: ! 3260: if (received) { ! 3261: return "port_send"; ! 3262: } else { ! 3263: return "move_send"; ! 3264: } ! 3265: ! 3266: case MACH_MSG_TYPE_MOVE_SEND_ONCE: ! 3267: if (received) { ! 3268: return "port_send_once"; ! 3269: } else { ! 3270: return "move_send_once"; ! 3271: } ! 3272: ! 3273: case MACH_MSG_TYPE_COPY_SEND: ! 3274: return "copy_send"; ! 3275: ! 3276: case MACH_MSG_TYPE_MAKE_SEND: ! 3277: return "make_send"; ! 3278: ! 3279: case MACH_MSG_TYPE_MAKE_SEND_ONCE: ! 3280: return "make_send_once"; ! 3281: ! 3282: default: ! 3283: return (char *) 0; ! 3284: } ! 3285: } ! 3286: ! 3287: void ! 3288: ipc_print_type_name( ! 3289: int type_name) ! 3290: { ! 3291: char *name = ipc_type_name(type_name, TRUE); ! 3292: if (name) { ! 3293: printf("%s", name); ! 3294: } else { ! 3295: printf("type%d", type_name); ! 3296: } ! 3297: } ! 3298: ! 3299: /* ! 3300: * ipc_kmsg_print [ debug ] ! 3301: */ ! 3302: void ! 3303: ipc_kmsg_print(kmsg) ! 3304: ipc_kmsg_t kmsg; ! 3305: { ! 3306: db_printf("kmsg=0x%x\n", kmsg); ! 3307: db_printf("ikm_next=0x%x,prev=0x%x,size=%d,marequest=0x%x", ! 3308: kmsg->ikm_next, ! 3309: kmsg->ikm_prev, ! 3310: kmsg->ikm_size, ! 3311: kmsg->ikm_marequest); ! 3312: #if NORMA_IPC ! 3313: db_printf(",page=0x%x,copy=0x%x\n", ! 3314: kmsg->ikm_page, ! 3315: kmsg->ikm_copy); ! 3316: #else /* NORMA_IPC */ ! 3317: db_printf("\n"); ! 3318: #endif /* NORMA_IPC */ ! 3319: ipc_msg_print(&kmsg->ikm_header); ! 3320: } ! 3321: ! 3322: /* ! 3323: * ipc_msg_print [ debug ] ! 3324: */ ! 3325: void ! 3326: ipc_msg_print(msgh) ! 3327: mach_msg_header_t *msgh; ! 3328: { ! 3329: vm_offset_t saddr, eaddr; ! 3330: ! 3331: db_printf("msgh_bits=0x%x: ", msgh->msgh_bits); ! 3332: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX) { ! 3333: db_printf("complex,"); ! 3334: } ! 3335: if (msgh->msgh_bits & MACH_MSGH_BITS_CIRCULAR) { ! 3336: db_printf("circular,"); ! 3337: } ! 3338: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_PORTS) { ! 3339: db_printf("complex_ports,"); ! 3340: } ! 3341: if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_DATA) { ! 3342: db_printf("complex_data,"); ! 3343: } ! 3344: if (msgh->msgh_bits & MACH_MSGH_BITS_MIGRATED) { ! 3345: db_printf("migrated,"); ! 3346: } ! 3347: if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) { ! 3348: db_printf("unused=0x%x,", ! 3349: msgh->msgh_bits & MACH_MSGH_BITS_UNUSED); ! 3350: } ! 3351: db_printf("l=0x%x,r=0x%x\n", ! 3352: MACH_MSGH_BITS_LOCAL(msgh->msgh_bits), ! 3353: MACH_MSGH_BITS_REMOTE(msgh->msgh_bits)); ! 3354: ! 3355: db_printf("msgh_id=%d,size=%d,seqno=%d,", ! 3356: msgh->msgh_id, ! 3357: msgh->msgh_size, ! 3358: msgh->msgh_seqno); ! 3359: ! 3360: if (msgh->msgh_remote_port) { ! 3361: db_printf("remote=0x%x(", msgh->msgh_remote_port); ! 3362: ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits)); ! 3363: db_printf("),"); ! 3364: } else { ! 3365: db_printf("remote=null,\n"); ! 3366: } ! 3367: ! 3368: if (msgh->msgh_local_port) { ! 3369: db_printf("local=0x%x(", msgh->msgh_local_port); ! 3370: ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits)); ! 3371: db_printf(")\n"); ! 3372: } else { ! 3373: db_printf("local=null\n"); ! 3374: } ! 3375: ! 3376: saddr = (vm_offset_t) (msgh + 1); ! 3377: eaddr = (vm_offset_t) msgh + msgh->msgh_size; ! 3378: ! 3379: while (saddr < eaddr) { ! 3380: mach_msg_type_long_t *type; ! 3381: mach_msg_type_name_t name; ! 3382: mach_msg_type_size_t size; ! 3383: mach_msg_type_number_t number; ! 3384: boolean_t is_inline, longform, dealloc, is_port; ! 3385: vm_size_t length; ! 3386: ! 3387: type = (mach_msg_type_long_t *) saddr; ! 3388: ! 3389: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) || ! 3390: ((longform = ((mach_msg_type_t*)type)->msgt_longform) && ! 3391: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) { ! 3392: db_printf("*** msg too small\n"); ! 3393: return; ! 3394: } ! 3395: ! 3396: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 3397: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate; ! 3398: if (longform) { ! 3399: /* This must be aligned */ ! 3400: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 3401: (is_misaligned(type))) { ! 3402: saddr = ptr_align(saddr); ! 3403: continue; ! 3404: } ! 3405: name = type->msgtl_name; ! 3406: size = type->msgtl_size; ! 3407: number = type->msgtl_number; ! 3408: saddr += sizeof(mach_msg_type_long_t); ! 3409: } else { ! 3410: name = ((mach_msg_type_t*)type)->msgt_name; ! 3411: size = ((mach_msg_type_t*)type)->msgt_size; ! 3412: number = ((mach_msg_type_t*)type)->msgt_number; ! 3413: saddr += sizeof(mach_msg_type_t); ! 3414: } ! 3415: ! 3416: db_printf("-- type="); ! 3417: ipc_print_type_name(name); ! 3418: if (! is_inline) { ! 3419: db_printf(",ool"); ! 3420: } ! 3421: if (dealloc) { ! 3422: db_printf(",dealloc"); ! 3423: } ! 3424: if (longform) { ! 3425: db_printf(",longform"); ! 3426: } ! 3427: db_printf(",size=%d,number=%d,addr=0x%x\n", ! 3428: size, ! 3429: number, ! 3430: saddr); ! 3431: ! 3432: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 3433: ! 3434: if ((is_port && (size != PORT_T_SIZE_IN_BITS)) || ! 3435: (longform && ((type->msgtl_header.msgt_name != 0) || ! 3436: (type->msgtl_header.msgt_size != 0) || ! 3437: (type->msgtl_header.msgt_number != 0))) || ! 3438: (((mach_msg_type_t*)type)->msgt_unused != 0) || ! 3439: (dealloc && is_inline)) { ! 3440: db_printf("*** invalid type\n"); ! 3441: return; ! 3442: } ! 3443: ! 3444: /* padding (ptrs and ports) ? */ ! 3445: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 3446: ((size >> 3) == sizeof(natural_t))) ! 3447: saddr = ptr_align(saddr); ! 3448: ! 3449: /* calculate length of data in bytes, rounding up */ ! 3450: ! 3451: length = ((number * size) + 7) >> 3; ! 3452: ! 3453: if (is_inline) { ! 3454: vm_size_t amount; ! 3455: int i, numwords; ! 3456: ! 3457: /* inline data sizes round up to int boundaries */ ! 3458: amount = (length + 3) &~ 3; ! 3459: if ((eaddr - saddr) < amount) { ! 3460: db_printf("*** too small\n"); ! 3461: return; ! 3462: } ! 3463: numwords = amount / sizeof(int); ! 3464: if (numwords > 8) { ! 3465: numwords = 8; ! 3466: } ! 3467: for (i = 0; i < numwords; i++) { ! 3468: db_printf("0x%x\n", ((int *) saddr)[i]); ! 3469: } ! 3470: if (numwords < amount / sizeof(int)) { ! 3471: db_printf("...\n"); ! 3472: } ! 3473: saddr += amount; ! 3474: } else { ! 3475: if ((eaddr - saddr) < sizeof(vm_offset_t)) { ! 3476: db_printf("*** too small\n"); ! 3477: return; ! 3478: } ! 3479: db_printf("0x%x\n", * (vm_offset_t *) saddr); ! 3480: saddr += sizeof(vm_offset_t); ! 3481: } ! 3482: } ! 3483: } ! 3484: #endif /* MACH_KDB */
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.