|
|
1.1 ! root 1: /* ! 2: * Copyright (c) 1999 Apple Computer, Inc. All rights reserved. ! 3: * ! 4: * @APPLE_LICENSE_HEADER_START@ ! 5: * ! 6: * Portions Copyright (c) 1999 Apple Computer, Inc. All Rights ! 7: * Reserved. This file contains Original Code and/or Modifications of ! 8: * Original Code as defined in and that are subject to the Apple Public ! 9: * Source License Version 1.1 (the "License"). You may not use this file ! 10: * except in compliance with the License. Please obtain a copy of the ! 11: * License at http://www.apple.com/publicsource and read it before using ! 12: * this file. ! 13: * ! 14: * The Original Code and all software distributed under the License are ! 15: * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER ! 16: * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES, ! 17: * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY, ! 18: * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the ! 19: * License for the specific language governing rights and limitations ! 20: * under the License. ! 21: * ! 22: * @APPLE_LICENSE_HEADER_END@ ! 23: */ ! 24: ! 25: /* ! 26: * Copyright (c) 1995, 1994, 1993, 1992, 1991, 1990 ! 27: * Open Software Foundation, Inc. ! 28: * ! 29: * Permission to use, copy, modify, and distribute this software and ! 30: * its documentation for any purpose and without fee is hereby granted, ! 31: * provided that the above copyright notice appears in all copies and ! 32: * that both the copyright notice and this permission notice appear in ! 33: * supporting documentation, and that the name of ("OSF") or Open Software ! 34: * Foundation not be used in advertising or publicity pertaining to ! 35: * distribution of the software without specific, written prior permission. ! 36: * ! 37: * OSF DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE ! 38: * INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS ! 39: * FOR A PARTICULAR PURPOSE. IN NO EVENT SHALL OSF BE LIABLE FOR ANY ! 40: * SPECIAL, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES ! 41: * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN ! 42: * ACTION OF CONTRACT, NEGLIGENCE, OR OTHER TORTIOUS ACTION, ARISING ! 43: * OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE ! 44: */ ! 45: /* ! 46: * OSF Research Institute MK6.1 (unencumbered) 1/31/1995 ! 47: */ ! 48: /* ! 49: * Mach Operating System ! 50: * Copyright (c) 1991,1990,1989 Carnegie Mellon University ! 51: * All Rights Reserved. ! 52: * ! 53: * Permission to use, copy, modify and distribute this software and its ! 54: * documentation is hereby granted, provided that both the copyright ! 55: * notice and this permission notice appear in all copies of the ! 56: * software, derivative works or modified versions, and any portions ! 57: * thereof, and that both notices appear in supporting documentation. ! 58: * ! 59: * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" ! 60: * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR ! 61: * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. ! 62: * ! 63: * Carnegie Mellon requests users of this software to return to ! 64: * ! 65: * Software Distribution Coordinator or [email protected] ! 66: * School of Computer Science ! 67: * Carnegie Mellon University ! 68: * Pittsburgh PA 15213-3890 ! 69: * ! 70: * any improvements or extensions that they make and grant Carnegie Mellon ! 71: * the rights to redistribute these changes. ! 72: */ ! 73: /* ! 74: * File: ipc/ipc_kmsg.c ! 75: * Author: Rich Draves ! 76: * Date: 1989 ! 77: * ! 78: * Operations on kernel messages. ! 79: */ ! 80: ! 81: #import <mach/features.h> ! 82: ! 83: #include <mach/boolean.h> ! 84: #include <mach/kern_return.h> ! 85: #include <mach/message.h> ! 86: #include <mach/port.h> ! 87: #include <kern/assert.h> ! 88: #include <kern/kalloc.h> ! 89: #include <vm/vm_map.h> ! 90: #include <vm/vm_object.h> ! 91: #include <vm/vm_kern.h> ! 92: #include <ipc/port.h> ! 93: #include <ipc/ipc_entry.h> ! 94: #include <ipc/ipc_kmsg.h> ! 95: #include <ipc/ipc_thread.h> ! 96: #include <ipc/ipc_marequest.h> ! 97: #include <ipc/ipc_notify.h> ! 98: #include <ipc/ipc_object.h> ! 99: #include <ipc/ipc_space.h> ! 100: #include <ipc/ipc_port.h> ! 101: #include <ipc/ipc_right.h> ! 102: ! 103: #include <ipc/ipc_machdep.h> ! 104: ! 105: #define MSG_OOL_SIZE_SMALL (PAGE_SIZE >> 2) ! 106: ! 107: extern int copyinmap(); ! 108: extern int copyoutmap(); ! 109: ! 110: #define is_misaligned(x) \ ! 111: ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) ) ! 112: #define ptr_align(x) \ ! 113: ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & \ ! 114: ~(sizeof(vm_offset_t)-1) ) ! 115: ! 116: ipc_kmsg_t ipc_kmsg_cache[NCPUS]; ! 117: ! 118: /* ! 119: * Forward declarations ! 120: */ ! 121: ! 122: void ipc_kmsg_clean( ! 123: ipc_kmsg_t kmsg); ! 124: ! 125: void ipc_kmsg_clean_body( ! 126: ipc_kmsg_t kmsg, ! 127: int number); ! 128: ! 129: void ipc_kmsg_clean_partial( ! 130: ipc_kmsg_t kmsg, ! 131: mach_msg_type_number_t number, ! 132: vm_offset_t paddr, ! 133: vm_size_t length); ! 134: ! 135: mach_msg_return_t ipc_kmsg_copyout_body( ! 136: ipc_kmsg_t kmsg, ! 137: ipc_space_t space, ! 138: vm_map_t map, ! 139: ipc_kmsg_t list); ! 140: ! 141: mach_msg_return_t ipc_kmsg_copyin_body( ! 142: ipc_kmsg_t kmsg, ! 143: ipc_space_t space, ! 144: vm_map_t map); ! 145: ! 146: /* ! 147: * Routine: ipc_kmsg_enqueue ! 148: * Purpose: ! 149: * Enqueue a kmsg. ! 150: */ ! 151: ! 152: void ! 153: ipc_kmsg_enqueue( ! 154: ipc_kmsg_queue_t queue, ! 155: ipc_kmsg_t kmsg) ! 156: { ! 157: ipc_kmsg_enqueue_macro(queue, kmsg); ! 158: } ! 159: ! 160: /* ! 161: * Routine: ipc_kmsg_dequeue ! 162: * Purpose: ! 163: * Dequeue and return a kmsg. ! 164: */ ! 165: ! 166: ipc_kmsg_t ! 167: ipc_kmsg_dequeue( ! 168: ipc_kmsg_queue_t queue) ! 169: { ! 170: ipc_kmsg_t first; ! 171: ! 172: first = ipc_kmsg_queue_first(queue); ! 173: ! 174: if (first != IKM_NULL) ! 175: ipc_kmsg_rmqueue_first_macro(queue, first); ! 176: ! 177: return first; ! 178: } ! 179: ! 180: /* ! 181: * Routine: ipc_kmsg_rmqueue ! 182: * Purpose: ! 183: * Pull a kmsg out of a queue. ! 184: */ ! 185: ! 186: void ! 187: ipc_kmsg_rmqueue( ! 188: ipc_kmsg_queue_t queue, ! 189: ipc_kmsg_t kmsg) ! 190: { ! 191: ipc_kmsg_t next, prev; ! 192: ! 193: assert(queue->ikmq_base != IKM_NULL); ! 194: ! 195: next = kmsg->ikm_next; ! 196: prev = kmsg->ikm_prev; ! 197: ! 198: if (next == kmsg) { ! 199: assert(prev == kmsg); ! 200: assert(queue->ikmq_base == kmsg); ! 201: ! 202: queue->ikmq_base = IKM_NULL; ! 203: } else { ! 204: if (queue->ikmq_base == kmsg) ! 205: queue->ikmq_base = next; ! 206: ! 207: next->ikm_prev = prev; ! 208: prev->ikm_next = next; ! 209: } ! 210: } ! 211: ! 212: /* ! 213: * Routine: ipc_kmsg_queue_next ! 214: * Purpose: ! 215: * Return the kmsg following the given kmsg. ! 216: * (Or IKM_NULL if it is the last one in the queue.) ! 217: */ ! 218: ! 219: ipc_kmsg_t ! 220: ipc_kmsg_queue_next( ! 221: ipc_kmsg_queue_t queue, ! 222: ipc_kmsg_t kmsg) ! 223: { ! 224: ipc_kmsg_t next; ! 225: ! 226: assert(queue->ikmq_base != IKM_NULL); ! 227: ! 228: next = kmsg->ikm_next; ! 229: if (queue->ikmq_base == next) ! 230: next = IKM_NULL; ! 231: ! 232: return next; ! 233: } ! 234: ! 235: /* ! 236: * Routine: ipc_kmsg_destroy ! 237: * Purpose: ! 238: * Destroys a kernel message. Releases all rights, ! 239: * references, and memory held by the message. ! 240: * Frees the message. ! 241: * Conditions: ! 242: * No locks held. ! 243: */ ! 244: ! 245: void ! 246: ipc_kmsg_destroy( ! 247: ipc_kmsg_t kmsg) ! 248: { ! 249: ipc_kmsg_queue_t queue; ! 250: boolean_t empty; ! 251: ! 252: /* ! 253: * ipc_kmsg_clean can cause more messages to be destroyed. ! 254: * Curtail recursion by queueing messages. If a message ! 255: * is already queued, then this is a recursive call. ! 256: */ ! 257: ! 258: queue = ¤t_thread()->ith_messages; ! 259: empty = ipc_kmsg_queue_empty(queue); ! 260: ipc_kmsg_enqueue(queue, kmsg); ! 261: ! 262: if (empty) { ! 263: /* must leave kmsg in queue while cleaning it */ ! 264: ! 265: while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) { ! 266: ipc_kmsg_clean(kmsg); ! 267: ipc_kmsg_rmqueue(queue, kmsg); ! 268: ikm_free(kmsg); ! 269: } ! 270: } ! 271: } ! 272: ! 273: /* ! 274: * Routine: ipc_kmsg_clean_body ! 275: * Purpose: ! 276: * Cleans the body of a kernel message. ! 277: * Releases all rights, references, and memory. ! 278: * ! 279: * Conditions: ! 280: * No locks held. ! 281: */ ! 282: ! 283: void ! 284: ipc_kmsg_clean_body( ! 285: ipc_kmsg_t kmsg, ! 286: int number) ! 287: { ! 288: mach_msg_descriptor_t *saddr, *eaddr; ! 289: ! 290: if ( number == 0 ) ! 291: return; ! 292: ! 293: saddr = (mach_msg_descriptor_t *) ! 294: ((mach_msg_base_t *) &kmsg->ikm_header + 1); ! 295: eaddr = saddr + number; ! 296: ! 297: for ( ; saddr < eaddr; saddr++ ) { ! 298: ! 299: switch (saddr->type.type) { ! 300: ! 301: case MACH_MSG_PORT_DESCRIPTOR: { ! 302: mach_msg_port_descriptor_t *dsc; ! 303: ! 304: dsc = &saddr->port; ! 305: ! 306: /* ! 307: * Destroy port rights carried in the message ! 308: */ ! 309: if (!IO_VALID((ipc_object_t) dsc->name)) ! 310: continue; ! 311: ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition); ! 312: break; ! 313: } ! 314: case MACH_MSG_OOL_DESCRIPTOR : { ! 315: mach_msg_ool_descriptor_t *dsc; ! 316: ! 317: dsc = &saddr->out_of_line; ! 318: ! 319: /* ! 320: * Destroy memory carried in the message ! 321: */ ! 322: if (dsc->size == 0) { ! 323: assert(dsc->address == (void *) 0); ! 324: } else { ! 325: #if MACH_OLD_VM_COPY ! 326: (void) vm_deallocate( ! 327: ipc_soft_map, ! 328: (vm_offset_t)dsc->address, ! 329: (vm_size_t)dsc->size); ! 330: #else ! 331: if (dsc->copy == MACH_MSG_PHYSICAL_COPY && ! 332: dsc->size <= MSG_OOL_SIZE_SMALL) { ! 333: kfree((vm_offset_t)dsc->address, ! 334: (vm_size_t)dsc->size); ! 335: } else { ! 336: vm_map_copy_discard((vm_map_copy_t) dsc->address); ! 337: } ! 338: #endif ! 339: } ! 340: break; ! 341: } ! 342: case MACH_MSG_OOL_PORTS_DESCRIPTOR : { ! 343: ipc_object_t *objects; ! 344: mach_msg_type_number_t j; ! 345: mach_msg_ool_ports_descriptor_t *dsc; ! 346: ! 347: dsc = &saddr->ool_ports; ! 348: objects = (ipc_object_t *) dsc->address; ! 349: ! 350: if (dsc->count == 0) { ! 351: break; ! 352: } ! 353: ! 354: assert(objects != (ipc_object_t *) 0); ! 355: ! 356: /* destroy port rights carried in the message */ ! 357: ! 358: for (j = 0; j < dsc->count; j++) { ! 359: ipc_object_t object = objects[j]; ! 360: ! 361: if (!IO_VALID(object)) ! 362: continue; ! 363: ! 364: ipc_object_destroy(object, dsc->disposition); ! 365: } ! 366: ! 367: /* destroy memory carried in the message */ ! 368: ! 369: assert(dsc->count != 0); ! 370: ! 371: kfree((vm_offset_t) dsc->address, ! 372: (vm_size_t) dsc->count * sizeof(mach_port_t)); ! 373: break; ! 374: } ! 375: default : { ! 376: panic("ipc_kmsg_clean_body: bad descriptor type %d", ! 377: saddr->type.type); ! 378: } ! 379: } ! 380: } ! 381: } ! 382: ! 383: void ! 384: ipc_kmsg_clean_body_compat( ! 385: vm_offset_t saddr, ! 386: vm_offset_t eaddr) ! 387: { ! 388: while (saddr < eaddr) { ! 389: mach_msg_type_long_t *type; ! 390: mach_msg_type_name_t name; ! 391: mach_msg_type_size_t size; ! 392: mach_msg_type_number_t number; ! 393: boolean_t is_inline, is_port; ! 394: vm_size_t length; ! 395: ! 396: type = (mach_msg_type_long_t *) saddr; ! 397: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 398: if (((mach_msg_type_t*)type)->msgt_longform) { ! 399: /* This must be aligned */ ! 400: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 401: (is_misaligned(type))) { ! 402: saddr = ptr_align(saddr); ! 403: continue; ! 404: } ! 405: name = type->msgtl_name; ! 406: size = type->msgtl_size; ! 407: number = type->msgtl_number; ! 408: saddr += sizeof(mach_msg_type_long_t); ! 409: } else { ! 410: name = ((mach_msg_type_t*)type)->msgt_name; ! 411: size = ((mach_msg_type_t*)type)->msgt_size; ! 412: number = ((mach_msg_type_t*)type)->msgt_number; ! 413: saddr += sizeof(mach_msg_type_t); ! 414: } ! 415: ! 416: /* padding (ptrs and ports) ? */ ! 417: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 418: ((size >> 3) == sizeof(natural_t))) ! 419: saddr = ptr_align(saddr); ! 420: ! 421: /* calculate length of data in bytes, rounding up */ ! 422: ! 423: length = ((number * size) + 7) >> 3; ! 424: ! 425: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 426: ! 427: if (is_port) { ! 428: ipc_object_t *objects; ! 429: mach_msg_type_number_t i; ! 430: ! 431: if (is_inline) { ! 432: objects = (ipc_object_t *) saddr; ! 433: /* sanity check */ ! 434: while (eaddr < (vm_offset_t)&objects[number]) number--; ! 435: } else { ! 436: objects = (ipc_object_t *) ! 437: * (vm_offset_t *) saddr; ! 438: } ! 439: ! 440: /* destroy port rights carried in the message */ ! 441: ! 442: for (i = 0; i < number; i++) { ! 443: ipc_object_t object = objects[i]; ! 444: ! 445: if (!IO_VALID(object)) ! 446: continue; ! 447: ! 448: ipc_object_destroy(object, name); ! 449: } ! 450: } ! 451: ! 452: if (is_inline) { ! 453: /* inline data sizes round up to int boundaries */ ! 454: ! 455: saddr += (length + 3) &~ 3; ! 456: } else { ! 457: vm_offset_t data = * (vm_offset_t *) saddr; ! 458: ! 459: /* destroy memory carried in the message */ ! 460: ! 461: if (length == 0) ! 462: assert(data == 0); ! 463: else if (is_port) ! 464: kfree(data, length); ! 465: else ! 466: #if MACH_OLD_VM_COPY ! 467: (void) vm_deallocate( ! 468: ipc_soft_map, data, length); ! 469: #else ! 470: vm_map_copy_discard((vm_map_copy_t) data); ! 471: #endif ! 472: ! 473: saddr += sizeof(vm_offset_t); ! 474: } ! 475: } ! 476: } ! 477: ! 478: /* ! 479: * Routine: ipc_kmsg_clean_partial ! 480: * Purpose: ! 481: * Cleans a partially-acquired kernel message. ! 482: * Conditions: ! 483: * Nothing locked. ! 484: */ ! 485: ! 486: void ! 487: ipc_kmsg_clean_partial( ! 488: ipc_kmsg_t kmsg, ! 489: mach_msg_type_number_t number, ! 490: vm_offset_t paddr, ! 491: vm_size_t length) ! 492: { ! 493: ipc_object_t object; ! 494: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 495: ! 496: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 497: assert(IO_VALID(object)); ! 498: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits)); ! 499: ! 500: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 501: if (IO_VALID(object)) ! 502: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits)); ! 503: ! 504: if (paddr) { ! 505: (void) vm_deallocate(ipc_kernel_copy_map, paddr, length); ! 506: } ! 507: ! 508: ipc_kmsg_clean_body(kmsg, number); ! 509: } ! 510: ! 511: void ! 512: ipc_kmsg_clean_partial_compat( ! 513: ipc_kmsg_t kmsg, ! 514: vm_offset_t eaddr, ! 515: boolean_t dolast, ! 516: mach_msg_type_number_t number) ! 517: { ! 518: ipc_object_t object; ! 519: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 520: vm_offset_t saddr; ! 521: ! 522: assert(kmsg->ikm_marequest == IMAR_NULL); ! 523: ! 524: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 525: assert(IO_VALID(object)); ! 526: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits)); ! 527: ! 528: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 529: if (IO_VALID(object)) ! 530: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits)); ! 531: ! 532: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 533: ipc_kmsg_clean_body_compat(saddr, eaddr); ! 534: ! 535: if (dolast) { ! 536: mach_msg_type_long_t *type; ! 537: mach_msg_type_name_t name; ! 538: mach_msg_type_size_t size; ! 539: mach_msg_type_number_t rnumber; ! 540: boolean_t is_inline, is_port; ! 541: vm_size_t length; ! 542: ! 543: xxx: type = (mach_msg_type_long_t *) eaddr; ! 544: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 545: if (((mach_msg_type_t*)type)->msgt_longform) { ! 546: /* This must be aligned */ ! 547: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 548: (is_misaligned(type))) { ! 549: eaddr = ptr_align(eaddr); ! 550: goto xxx; ! 551: } ! 552: name = type->msgtl_name; ! 553: size = type->msgtl_size; ! 554: rnumber = type->msgtl_number; ! 555: eaddr += sizeof(mach_msg_type_long_t); ! 556: } else { ! 557: name = ((mach_msg_type_t*)type)->msgt_name; ! 558: size = ((mach_msg_type_t*)type)->msgt_size; ! 559: rnumber = ((mach_msg_type_t*)type)->msgt_number; ! 560: eaddr += sizeof(mach_msg_type_t); ! 561: } ! 562: ! 563: /* padding (ptrs and ports) ? */ ! 564: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 565: ((size >> 3) == sizeof(natural_t))) ! 566: eaddr = ptr_align(eaddr); ! 567: ! 568: /* calculate length of data in bytes, rounding up */ ! 569: ! 570: length = ((rnumber * size) + 7) >> 3; ! 571: ! 572: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 573: ! 574: if (is_port) { ! 575: ipc_object_t *objects; ! 576: mach_msg_type_number_t i; ! 577: ! 578: objects = (ipc_object_t *) ! 579: (is_inline ? eaddr : * (vm_offset_t *) eaddr); ! 580: ! 581: /* destroy port rights carried in the message */ ! 582: ! 583: for (i = 0; i < number; i++) { ! 584: ipc_object_t obj = objects[i]; ! 585: ! 586: if (!IO_VALID(obj)) ! 587: continue; ! 588: ! 589: ipc_object_destroy(obj, name); ! 590: } ! 591: } ! 592: ! 593: if (!is_inline) { ! 594: vm_offset_t data = * (vm_offset_t *) eaddr; ! 595: ! 596: /* destroy memory carried in the message */ ! 597: ! 598: if (length == 0) ! 599: assert(data == 0); ! 600: else if (is_port) ! 601: kfree(data, length); ! 602: else ! 603: #if MACH_OLD_VM_COPY ! 604: (void) vm_deallocate( ! 605: ipc_soft_map, data, length); ! 606: #else ! 607: vm_map_copy_discard((vm_map_copy_t) data); ! 608: #endif ! 609: } ! 610: } ! 611: } ! 612: ! 613: /* ! 614: * Routine: ipc_kmsg_clean ! 615: * Purpose: ! 616: * Cleans a kernel message. Releases all rights, ! 617: * references, and memory held by the message. ! 618: * Conditions: ! 619: * No locks held. ! 620: */ ! 621: ! 622: void ! 623: ipc_kmsg_clean( ! 624: ipc_kmsg_t kmsg) ! 625: { ! 626: ipc_marequest_t marequest; ! 627: ipc_object_t object; ! 628: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 629: ! 630: marequest = kmsg->ikm_marequest; ! 631: if (marequest != IMAR_NULL) ! 632: ipc_marequest_destroy(marequest); ! 633: ! 634: object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 635: if (IO_VALID(object)) ! 636: ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits)); ! 637: ! 638: object = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 639: if (IO_VALID(object)) ! 640: ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits)); ! 641: ! 642: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 643: if (mbits & MACH_MSGH_BITS_OLD_FORMAT) { ! 644: vm_offset_t saddr, eaddr; ! 645: ! 646: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 647: eaddr = (vm_offset_t) &kmsg->ikm_header + ! 648: kmsg->ikm_header.msgh_size; ! 649: ! 650: ipc_kmsg_clean_body_compat(saddr, eaddr); ! 651: } ! 652: else { ! 653: mach_msg_body_t *body; ! 654: ! 655: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 656: ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count); ! 657: } ! 658: } ! 659: } ! 660: ! 661: /* ! 662: * Routine: ipc_kmsg_free ! 663: * Purpose: ! 664: * Free a kernel message buffer. ! 665: * Conditions: ! 666: * Nothing locked. ! 667: */ ! 668: ! 669: void ! 670: ipc_kmsg_free( ! 671: ipc_kmsg_t kmsg) ! 672: { ! 673: vm_size_t size = kmsg->ikm_size; ! 674: ! 675: switch (size) { ! 676: case IKM_SIZE_NETWORK: ! 677: /* return it to the network code */ ! 678: break; ! 679: ! 680: #if DRIVERKIT ! 681: case IKM_SIZE_DEVICE: ! 682: KernDeviceInterruptMsgRelease(kmsg); ! 683: break; ! 684: #endif ! 685: ! 686: #if MACH_NET ! 687: case IKM_SIZE_NETIPC: ! 688: netipc_msg_release(kmsg); ! 689: break; ! 690: #endif ! 691: ! 692: default: ! 693: kfree((vm_offset_t) kmsg, size); ! 694: break; ! 695: } ! 696: } ! 697: ! 698: /* ! 699: * Routine: ipc_kmsg_get ! 700: * Purpose: ! 701: * Allocates a kernel message buffer. ! 702: * Copies a user message to the message buffer. ! 703: * Conditions: ! 704: * Nothing locked. ! 705: * Returns: ! 706: * MACH_MSG_SUCCESS Acquired a message buffer. ! 707: * MACH_SEND_MSG_TOO_SMALL Message smaller than a header. ! 708: * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple. ! 709: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer. ! 710: * MACH_SEND_INVALID_DATA Couldn't copy message data. ! 711: */ ! 712: ! 713: mach_msg_return_t ! 714: ipc_kmsg_get( ! 715: mach_msg_header_t *msg, ! 716: mach_msg_option_t option, ! 717: mach_msg_size_t size, ! 718: integer_t delta, ! 719: ipc_kmsg_t *kmsgp) ! 720: { ! 721: ipc_kmsg_t kmsg; ! 722: mach_msg_size_t send_size, msg_size; ! 723: ! 724: if ((size < sizeof(mach_msg_header_t)) || (size & 3)) ! 725: return MACH_SEND_MSG_TOO_SMALL; ! 726: ! 727: /* ! 728: * Three different notions of message size: ! 729: * 1) 'size' is the value passed through the API, ! 730: * which is the actual size of the message to the ! 731: * sender. In the case of the old API, this value ! 732: * will have been rounded up to a 4 byte boundary, ! 733: * and delta will be set to a negative value such ! 734: * that (size + delta) is the original value passed ! 735: * through the API. ! 736: * 2) 'msg_size' is the minimum sized kmsg needed to ! 737: * hold the message. This is equal to the size of ! 738: * the message plus the *maximum* sized trailer which ! 739: * can be generated by this kernel. In the case of ! 740: * the old API, this will be equal to 'size'. ! 741: * 3) 'send_size' is the actual amount of data which ! 742: * will be copied from the sender. In the case of ! 743: * MACH_SEND_TRAILER, this will include a *minimum* ! 744: * sized trailer in order to acquire the size and ! 745: * type fields of the entire trailer. The actual ! 746: * trailer data will then be fetched using a separate ! 747: * copy operation. ! 748: */ ! 749: if (delta <= 0) { ! 750: msg_size = size; ! 751: send_size = size + delta; ! 752: } ! 753: else { ! 754: if ((delta & 3) || ! 755: delta < MACH_MSG_TRAILER_MINIMUM_SIZE || ! 756: delta > MAX_TRAILER_SIZE) ! 757: return MACH_SEND_INVALID_TRAILER; ! 758: ! 759: msg_size = size + delta; ! 760: send_size = size + ((option & MACH_SEND_TRAILER) ? ! 761: sizeof (mach_msg_trailer_t) : 0); ! 762: } ! 763: ! 764: if (msg_size <= IKM_SAVED_MSG_SIZE) { ! 765: kmsg = ikm_cache(); ! 766: if (kmsg != IKM_NULL) { ! 767: ikm_cache() = IKM_NULL; ! 768: ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE); ! 769: } else { ! 770: kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE); ! 771: if (kmsg == IKM_NULL) ! 772: return MACH_SEND_NO_BUFFER; ! 773: ikm_init(kmsg, IKM_SAVED_MSG_SIZE); ! 774: } ! 775: } else { ! 776: kmsg = ikm_alloc(msg_size); ! 777: if (kmsg == IKM_NULL) ! 778: return MACH_SEND_NO_BUFFER; ! 779: ikm_init(kmsg, msg_size); ! 780: } ! 781: ! 782: if (copyinmsg( ! 783: (char *) msg, (char *) &kmsg->ikm_header, send_size)) { ! 784: ikm_free(kmsg); ! 785: return MACH_SEND_INVALID_DATA; ! 786: } ! 787: ! 788: /* ! 789: * Process trailers, excepting old ! 790: * message format. ! 791: */ ! 792: if (delta > 0) { ! 793: if (option & MACH_SEND_TRAILER) { ! 794: /* ! 795: * The send operation includes the ! 796: * MACH_SEND_TRAILER option. ! 797: */ ! 798: mach_msg_trailer_t *trailer; ! 799: mach_msg_trailer_size_t trailer_size; ! 800: ! 801: trailer = (mach_msg_trailer_t *) ! 802: ((vm_offset_t)&kmsg->ikm_header + size); ! 803: ! 804: if (trailer->msgh_trailer_type != 0) { ! 805: ikm_free(kmsg); ! 806: return MACH_SEND_INVALID_TRAILER; ! 807: } ! 808: ! 809: trailer_size = trailer->msgh_trailer_size; ! 810: if (trailer_size > delta || (trailer_size & 3) || ! 811: trailer_size < MACH_MSG_TRAILER_MINIMUM_SIZE || ! 812: trailer_size > MACH_MSG_TRAILER_FORMAT_0_SIZE) { ! 813: ikm_free(kmsg); ! 814: return MACH_SEND_INVALID_TRAILER; ! 815: } ! 816: ! 817: if (trailer_size > sizeof (*trailer) && ! 818: copyinmsg( ! 819: (char *)((vm_offset_t)msg + size + ! 820: sizeof (*trailer)), ! 821: (char *)((vm_offset_t)trailer + ! 822: sizeof (*trailer)), ! 823: trailer_size - sizeof (*trailer))) { ! 824: ikm_free(kmsg); ! 825: return MACH_SEND_INVALID_TRAILER; ! 826: } ! 827: ! 828: delta = trailer_size; ! 829: } ! 830: else ! 831: delta = 0; ! 832: } ! 833: ! 834: kmsg->ikm_delta = delta; ! 835: kmsg->ikm_header.msgh_size = size; ! 836: ! 837: *kmsgp = kmsg; ! 838: return MACH_MSG_SUCCESS; ! 839: } ! 840: ! 841: /* ! 842: * Routine: ipc_kmsg_get_from_kernel ! 843: * Purpose: ! 844: * Allocates a kernel message buffer. ! 845: * Copies a kernel message to the message buffer. ! 846: * Only resource errors are allowed. ! 847: * Conditions: ! 848: * Nothing locked. ! 849: * Returns: ! 850: * MACH_MSG_SUCCESS Acquired a message buffer. ! 851: * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer. ! 852: */ ! 853: ! 854: extern mach_msg_return_t ! 855: ipc_kmsg_get_from_kernel( ! 856: mach_msg_header_t *msg, ! 857: mach_msg_option_t option, ! 858: mach_msg_size_t size, ! 859: integer_t delta, ! 860: ipc_kmsg_t *kmsgp) ! 861: { ! 862: ipc_kmsg_t kmsg; ! 863: mach_msg_size_t send_size, msg_size; ! 864: ! 865: assert(size >= sizeof(mach_msg_header_t)); ! 866: assert((size & 3) == 0 && (delta <= 0)); ! 867: ! 868: if (delta <= 0) { ! 869: msg_size = size; ! 870: send_size = size + delta; ! 871: } ! 872: else { ! 873: if ((delta & 3) || ! 874: delta < MACH_MSG_TRAILER_MINIMUM_SIZE || ! 875: delta > MAX_TRAILER_SIZE) ! 876: return MACH_SEND_INVALID_TRAILER; ! 877: ! 878: msg_size = size + delta; ! 879: send_size = size + ((option & MACH_SEND_TRAILER) ? ! 880: sizeof (mach_msg_trailer_t) : 0); ! 881: } ! 882: ! 883: kmsg = ikm_alloc(msg_size); ! 884: ! 885: if (kmsg == IKM_NULL) ! 886: return MACH_SEND_NO_BUFFER; ! 887: ikm_init(kmsg, msg_size); ! 888: kmsg->ikm_sender = KERNEL_SECURITY_ID_VALUE; ! 889: ! 890: bcopy((char *) msg, (char *) &kmsg->ikm_header, send_size); ! 891: ! 892: /* ! 893: * Process trailers, excepting old ! 894: * message format. ! 895: */ ! 896: if (delta > 0) { ! 897: if (option & MACH_SEND_TRAILER) { ! 898: /* ! 899: * The send operation includes the ! 900: * MACH_SEND_TRAILER option. ! 901: */ ! 902: mach_msg_trailer_t *trailer; ! 903: mach_msg_trailer_size_t trailer_size; ! 904: ! 905: trailer = (mach_msg_trailer_t *) ! 906: ((vm_offset_t)&kmsg->ikm_header + size); ! 907: ! 908: if (trailer->msgh_trailer_type != 0) { ! 909: ikm_free(kmsg); ! 910: return MACH_SEND_INVALID_TRAILER; ! 911: } ! 912: ! 913: trailer_size = trailer->msgh_trailer_size; ! 914: if (trailer_size > delta || (trailer_size & 3) || ! 915: trailer_size < MACH_MSG_TRAILER_MINIMUM_SIZE || ! 916: trailer_size > MACH_MSG_TRAILER_FORMAT_0_SIZE) { ! 917: ikm_free(kmsg); ! 918: return MACH_SEND_INVALID_TRAILER; ! 919: } ! 920: ! 921: if (trailer_size > sizeof (*trailer)) { ! 922: bcopy( ! 923: (char *)((vm_offset_t)msg + size + ! 924: sizeof (*trailer)), ! 925: (char *)((vm_offset_t)trailer + ! 926: sizeof (*trailer)), ! 927: trailer_size - sizeof (*trailer)); ! 928: } ! 929: ! 930: delta = trailer_size; ! 931: } ! 932: else ! 933: delta = 0; ! 934: } ! 935: ! 936: kmsg->ikm_delta = delta; ! 937: kmsg->ikm_header.msgh_size = size; ! 938: ! 939: *kmsgp = kmsg; ! 940: return MACH_MSG_SUCCESS; ! 941: } ! 942: ! 943: /* ! 944: * Routine: ipc_kmsg_put ! 945: * Purpose: ! 946: * Copies a message buffer to a user message. ! 947: * Copies only the specified number of bytes. ! 948: * Frees the message buffer. ! 949: * Conditions: ! 950: * Nothing locked. The message buffer must have clean ! 951: * header (ikm_marequest) fields. ! 952: * Returns: ! 953: * MACH_MSG_SUCCESS Copied data out of message buffer. ! 954: * MACH_RCV_INVALID_DATA Couldn't copy to user message. ! 955: */ ! 956: ! 957: mach_msg_return_t ! 958: ipc_kmsg_put( ! 959: mach_msg_header_t *msg, ! 960: ipc_kmsg_t kmsg, ! 961: mach_msg_size_t size) ! 962: { ! 963: mach_msg_return_t mr; ! 964: ! 965: ikm_check_initialized(kmsg, kmsg->ikm_size); ! 966: ! 967: if (copyoutmsg((const char *) &kmsg->ikm_header, (char *) msg, size)) ! 968: mr = MACH_RCV_INVALID_DATA; ! 969: else ! 970: mr = MACH_MSG_SUCCESS; ! 971: ! 972: if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) && ! 973: (ikm_cache() == IKM_NULL)) ! 974: ikm_cache() = kmsg; ! 975: else ! 976: ikm_free(kmsg); ! 977: ! 978: return mr; ! 979: } ! 980: ! 981: /* ! 982: * Routine: ipc_kmsg_put_to_kernel ! 983: * Purpose: ! 984: * Copies a message buffer to a kernel message. ! 985: * Frees the message buffer. ! 986: * No errors allowed. ! 987: * Conditions: ! 988: * Nothing locked. ! 989: */ ! 990: ! 991: void ! 992: ipc_kmsg_put_to_kernel( ! 993: mach_msg_header_t *msg, ! 994: ipc_kmsg_t kmsg, ! 995: mach_msg_size_t size) ! 996: { ! 997: bcopy((char *) &kmsg->ikm_header, (char *) msg, size); ! 998: ! 999: ikm_free(kmsg); ! 1000: } ! 1001: ! 1002: /* ! 1003: * Routine: ipc_kmsg_copyin_header ! 1004: * Purpose: ! 1005: * "Copy-in" port rights in the header of a message. ! 1006: * Operates atomically; if it doesn't succeed the ! 1007: * message header and the space are left untouched. ! 1008: * If it does succeed the remote/local port fields ! 1009: * contain object pointers instead of port names, ! 1010: * and the bits field is updated. The destination port ! 1011: * will be a valid port pointer. ! 1012: * ! 1013: * The notify argument implements the MACH_SEND_CANCEL option. ! 1014: * If it is not MACH_PORT_NULL, it should name a receive right. ! 1015: * If the processing of the destination port would generate ! 1016: * a port-deleted notification (because the right for the ! 1017: * destination port is destroyed and it had a request for ! 1018: * a dead-name notification registered), and the port-deleted ! 1019: * notification would be sent to the named receive right, ! 1020: * then it isn't sent and the send-once right for the notify ! 1021: * port is quietly destroyed. ! 1022: * ! 1023: * [MACH_IPC_COMPAT] There is an atomicity problem if the ! 1024: * reply port is a compat entry and dies at an inopportune ! 1025: * time. This doesn't have any serious consequences ! 1026: * (an observant user task might conceivably notice that ! 1027: * the destination and reply ports were handled inconsistently), ! 1028: * only happens in compat mode, and is extremely unlikely. ! 1029: * Conditions: ! 1030: * Nothing locked. ! 1031: * Returns: ! 1032: * MACH_MSG_SUCCESS Successful copyin. ! 1033: * MACH_SEND_INVALID_HEADER ! 1034: * Illegal value in the message header bits. ! 1035: * MACH_SEND_INVALID_DEST The space is dead. ! 1036: * MACH_SEND_INVALID_NOTIFY ! 1037: * Notify is non-null and doesn't name a receive right. ! 1038: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 1039: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 1040: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 1041: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 1042: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 1043: */ ! 1044: ! 1045: mach_msg_return_t ! 1046: ipc_kmsg_copyin_header( ! 1047: mach_msg_header_t *msg, ! 1048: ipc_space_t space, ! 1049: mach_port_t notify) ! 1050: { ! 1051: mach_msg_bits_t mbits = msg->msgh_bits &~ ! 1052: (MACH_MSGH_BITS_CIRCULAR | MACH_MSGH_BITS_OLD_FORMAT); ! 1053: mach_port_t dest_name = msg->msgh_remote_port; ! 1054: mach_port_t reply_name = msg->msgh_local_port; ! 1055: kern_return_t kr; ! 1056: ! 1057: /* first check for common cases */ ! 1058: ! 1059: if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) { ! 1060: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): { ! 1061: ipc_entry_t entry; ! 1062: ipc_entry_bits_t bits; ! 1063: ipc_port_t dest_port; ! 1064: ! 1065: /* sending an asynchronous message */ ! 1066: ! 1067: if (reply_name != MACH_PORT_NULL) ! 1068: break; ! 1069: ! 1070: is_read_lock(space); ! 1071: if (!space->is_active) ! 1072: goto abort_async; ! 1073: ! 1074: /* optimized ipc_entry_lookup */ ! 1075: ! 1076: { ! 1077: mach_port_index_t index = MACH_PORT_INDEX(dest_name); ! 1078: mach_port_gen_t gen = MACH_PORT_GEN(dest_name); ! 1079: ! 1080: if (index >= space->is_table_size) ! 1081: goto abort_async; ! 1082: ! 1083: entry = &space->is_table[index]; ! 1084: bits = entry->ie_bits; ! 1085: ! 1086: /* check generation number and type bit */ ! 1087: ! 1088: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != ! 1089: (gen | MACH_PORT_TYPE_SEND)) ! 1090: goto abort_async; ! 1091: } ! 1092: ! 1093: /* optimized ipc_right_copyin */ ! 1094: ! 1095: assert(IE_BITS_UREFS(bits) > 0); ! 1096: ! 1097: dest_port = (ipc_port_t) entry->ie_object; ! 1098: assert(dest_port != IP_NULL); ! 1099: ! 1100: ip_lock(dest_port); ! 1101: /* can unlock space now without compromising atomicity */ ! 1102: is_read_unlock(space); ! 1103: ! 1104: if (!ip_active(dest_port)) { ! 1105: ip_unlock(dest_port); ! 1106: break; ! 1107: } ! 1108: ! 1109: assert(dest_port->ip_srights > 0); ! 1110: dest_port->ip_srights++; ! 1111: ip_reference(dest_port); ! 1112: ip_unlock(dest_port); ! 1113: ! 1114: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1115: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0)); ! 1116: msg->msgh_remote_port = (mach_port_t) dest_port; ! 1117: return MACH_MSG_SUCCESS; ! 1118: ! 1119: abort_async: ! 1120: is_read_unlock(space); ! 1121: break; ! 1122: } ! 1123: ! 1124: case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, ! 1125: MACH_MSG_TYPE_MAKE_SEND_ONCE): { ! 1126: ipc_entry_num_t size; ! 1127: ipc_entry_t table; ! 1128: ipc_entry_t entry; ! 1129: ipc_entry_bits_t bits; ! 1130: ipc_port_t dest_port, reply_port; ! 1131: ! 1132: /* sending a request message */ ! 1133: ! 1134: is_read_lock(space); ! 1135: if (!space->is_active) ! 1136: goto abort_request; ! 1137: ! 1138: size = space->is_table_size; ! 1139: table = space->is_table; ! 1140: ! 1141: /* optimized ipc_entry_lookup of dest_name */ ! 1142: ! 1143: { ! 1144: mach_port_index_t index = MACH_PORT_INDEX(dest_name); ! 1145: mach_port_gen_t gen = MACH_PORT_GEN(dest_name); ! 1146: ! 1147: if (index >= size) ! 1148: goto abort_request; ! 1149: ! 1150: entry = &table[index]; ! 1151: bits = entry->ie_bits; ! 1152: ! 1153: /* check generation number and type bit */ ! 1154: ! 1155: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) != ! 1156: (gen | MACH_PORT_TYPE_SEND)) ! 1157: goto abort_request; ! 1158: } ! 1159: ! 1160: assert(IE_BITS_UREFS(bits) > 0); ! 1161: ! 1162: dest_port = (ipc_port_t) entry->ie_object; ! 1163: assert(dest_port != IP_NULL); ! 1164: ! 1165: /* optimized ipc_entry_lookup of reply_name */ ! 1166: ! 1167: { ! 1168: mach_port_index_t index = MACH_PORT_INDEX(reply_name); ! 1169: mach_port_gen_t gen = MACH_PORT_GEN(reply_name); ! 1170: ! 1171: if (index >= size) ! 1172: goto abort_request; ! 1173: ! 1174: entry = &table[index]; ! 1175: bits = entry->ie_bits; ! 1176: ! 1177: /* check generation number and type bit */ ! 1178: ! 1179: if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_RECEIVE)) != ! 1180: (gen | MACH_PORT_TYPE_RECEIVE)) ! 1181: goto abort_request; ! 1182: } ! 1183: ! 1184: reply_port = (ipc_port_t) entry->ie_object; ! 1185: assert(reply_port != IP_NULL); ! 1186: ! 1187: /* ! 1188: * To do an atomic copyin, need simultaneous ! 1189: * locks on both ports and the space. If ! 1190: * dest_port == reply_port, and simple locking is ! 1191: * enabled, then we will abort. Otherwise it's ! 1192: * OK to unlock twice. ! 1193: */ ! 1194: ! 1195: ip_lock(dest_port); ! 1196: if (!ip_active(dest_port) || !ip_lock_try(reply_port)) { ! 1197: ip_unlock(dest_port); ! 1198: goto abort_request; ! 1199: } ! 1200: /* can unlock space now without compromising atomicity */ ! 1201: is_read_unlock(space); ! 1202: ! 1203: assert(dest_port->ip_srights > 0); ! 1204: dest_port->ip_srights++; ! 1205: ip_reference(dest_port); ! 1206: ip_unlock(dest_port); ! 1207: ! 1208: assert(ip_active(reply_port)); ! 1209: assert(reply_port->ip_receiver_name == reply_name); ! 1210: assert(reply_port->ip_receiver == space); ! 1211: ! 1212: reply_port->ip_sorights++; ! 1213: ip_reference(reply_port); ! 1214: ip_unlock(reply_port); ! 1215: ! 1216: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1217: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, ! 1218: MACH_MSG_TYPE_PORT_SEND_ONCE)); ! 1219: msg->msgh_remote_port = (mach_port_t) dest_port; ! 1220: msg->msgh_local_port = (mach_port_t) reply_port; ! 1221: return MACH_MSG_SUCCESS; ! 1222: ! 1223: abort_request: ! 1224: is_read_unlock(space); ! 1225: break; ! 1226: } ! 1227: ! 1228: case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): { ! 1229: mach_port_index_t index; ! 1230: mach_port_gen_t gen; ! 1231: ipc_entry_t table; ! 1232: ipc_entry_t entry; ! 1233: ipc_entry_bits_t bits; ! 1234: ipc_port_t dest_port; ! 1235: ! 1236: /* sending a reply message */ ! 1237: ! 1238: if (reply_name != MACH_PORT_NULL) ! 1239: break; ! 1240: ! 1241: is_write_lock(space); ! 1242: if (!space->is_active) ! 1243: goto abort_reply; ! 1244: ! 1245: /* optimized ipc_entry_lookup */ ! 1246: ! 1247: table = space->is_table; ! 1248: ! 1249: index = MACH_PORT_INDEX(dest_name); ! 1250: gen = MACH_PORT_GEN(dest_name); ! 1251: ! 1252: if (index >= space->is_table_size) ! 1253: goto abort_reply; ! 1254: ! 1255: entry = &table[index]; ! 1256: bits = entry->ie_bits; ! 1257: ! 1258: /* check generation number, collision bit, and type bit */ ! 1259: ! 1260: if ((bits & (IE_BITS_GEN_MASK|IE_BITS_COLLISION| ! 1261: MACH_PORT_TYPE_SEND_ONCE)) != ! 1262: (gen | MACH_PORT_TYPE_SEND_ONCE)) ! 1263: goto abort_reply; ! 1264: ! 1265: /* optimized ipc_right_copyin */ ! 1266: ! 1267: assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE); ! 1268: assert(IE_BITS_UREFS(bits) == 1); ! 1269: assert((bits & IE_BITS_MAREQUEST) == 0); ! 1270: ! 1271: if (entry->ie_request != 0) ! 1272: goto abort_reply; ! 1273: ! 1274: dest_port = (ipc_port_t) entry->ie_object; ! 1275: assert(dest_port != IP_NULL); ! 1276: ! 1277: ip_lock(dest_port); ! 1278: if (!ip_active(dest_port)) { ! 1279: ip_unlock(dest_port); ! 1280: goto abort_reply; ! 1281: } ! 1282: ! 1283: assert(dest_port->ip_sorights > 0); ! 1284: ip_unlock(dest_port); ! 1285: ! 1286: /* optimized ipc_entry_dealloc */ ! 1287: ! 1288: entry->ie_next = table->ie_next; ! 1289: table->ie_next = index; ! 1290: entry->ie_bits = gen; ! 1291: entry->ie_object = IO_NULL; ! 1292: is_write_unlock(space); ! 1293: ! 1294: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1295: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, ! 1296: 0)); ! 1297: msg->msgh_remote_port = (mach_port_t) dest_port; ! 1298: return MACH_MSG_SUCCESS; ! 1299: ! 1300: abort_reply: ! 1301: is_write_unlock(space); ! 1302: break; ! 1303: } ! 1304: ! 1305: default: ! 1306: /* don't bother optimizing */ ! 1307: break; ! 1308: } ! 1309: ! 1310: { ! 1311: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 1312: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 1313: ipc_object_t dest_port, reply_port; ! 1314: ipc_port_t dest_soright, reply_soright; ! 1315: ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */ ! 1316: ! 1317: if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type)) ! 1318: return MACH_SEND_INVALID_HEADER; ! 1319: ! 1320: if ((reply_type == 0) ? ! 1321: (reply_name != MACH_PORT_NULL) : ! 1322: !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type)) ! 1323: return MACH_SEND_INVALID_HEADER; ! 1324: ! 1325: is_write_lock(space); ! 1326: if (!space->is_active) ! 1327: goto invalid_dest; ! 1328: ! 1329: if (notify != MACH_PORT_NULL) { ! 1330: ipc_entry_t entry; ! 1331: ! 1332: if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) || ! 1333: ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) { ! 1334: is_write_unlock(space); ! 1335: return MACH_SEND_INVALID_NOTIFY; ! 1336: } ! 1337: ! 1338: notify_port = (ipc_port_t) entry->ie_object; ! 1339: } ! 1340: ! 1341: if (dest_name == reply_name) { ! 1342: ipc_entry_t entry; ! 1343: mach_port_t name = dest_name; ! 1344: ! 1345: /* ! 1346: * Destination and reply ports are the same! ! 1347: * This is a little tedious to make atomic, because ! 1348: * there are 25 combinations of dest_type/reply_type. ! 1349: * However, most are easy. If either is move-sonce, ! 1350: * then there must be an error. If either are ! 1351: * make-send or make-sonce, then we must be looking ! 1352: * at a receive right so the port can't die. ! 1353: * The hard cases are the combinations of ! 1354: * copy-send and make-send. ! 1355: */ ! 1356: ! 1357: entry = ipc_entry_lookup(space, name); ! 1358: if (entry == IE_NULL) ! 1359: goto invalid_dest; ! 1360: ! 1361: assert(reply_type != 0); /* because name not null */ ! 1362: ! 1363: if (!ipc_right_copyin_check(space, name, entry, reply_type)) ! 1364: goto invalid_reply; ! 1365: ! 1366: if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) || ! 1367: (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) { ! 1368: /* ! 1369: * Why must there be an error? To get a valid ! 1370: * destination, this entry must name a live ! 1371: * port (not a dead name or dead port). However ! 1372: * a successful move-sonce will destroy a ! 1373: * live entry. Therefore the other copyin, ! 1374: * whatever it is, would fail. We've already ! 1375: * checked for reply port errors above, ! 1376: * so report a destination error. ! 1377: */ ! 1378: ! 1379: goto invalid_dest; ! 1380: } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) || ! 1381: (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) || ! 1382: (reply_type == MACH_MSG_TYPE_MAKE_SEND) || ! 1383: (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) { ! 1384: kr = ipc_right_copyin(space, name, entry, ! 1385: dest_type, FALSE, ! 1386: &dest_port, &dest_soright); ! 1387: if (kr != KERN_SUCCESS) ! 1388: goto invalid_dest; ! 1389: ! 1390: /* ! 1391: * Either dest or reply needs a receive right. ! 1392: * We know the receive right is there, because ! 1393: * of the copyin_check and copyin calls. Hence ! 1394: * the port is not in danger of dying. If dest ! 1395: * used the receive right, then the right needed ! 1396: * by reply (and verified by copyin_check) will ! 1397: * still be there. ! 1398: */ ! 1399: ! 1400: assert(IO_VALID(dest_port)); ! 1401: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); ! 1402: assert(dest_soright == IP_NULL); ! 1403: ! 1404: kr = ipc_right_copyin(space, name, entry, ! 1405: reply_type, TRUE, ! 1406: &reply_port, &reply_soright); ! 1407: ! 1408: assert(kr == KERN_SUCCESS); ! 1409: assert(reply_port == dest_port); ! 1410: assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE); ! 1411: assert(reply_soright == IP_NULL); ! 1412: } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) && ! 1413: (reply_type == MACH_MSG_TYPE_COPY_SEND)) { ! 1414: /* ! 1415: * To make this atomic, just do one copy-send, ! 1416: * and dup the send right we get out. ! 1417: */ ! 1418: ! 1419: kr = ipc_right_copyin(space, name, entry, ! 1420: dest_type, FALSE, ! 1421: &dest_port, &dest_soright); ! 1422: if (kr != KERN_SUCCESS) ! 1423: goto invalid_dest; ! 1424: ! 1425: assert(entry->ie_bits & MACH_PORT_TYPE_SEND); ! 1426: assert(dest_soright == IP_NULL); ! 1427: ! 1428: /* ! 1429: * It's OK if the port we got is dead now, ! 1430: * so reply_port is IP_DEAD, because the msg ! 1431: * won't go anywhere anyway. ! 1432: */ ! 1433: ! 1434: reply_port = (ipc_object_t) ! 1435: ipc_port_copy_send((ipc_port_t) dest_port); ! 1436: reply_soright = IP_NULL; ! 1437: } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) && ! 1438: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) { ! 1439: /* ! 1440: * This is an easy case. Just use our ! 1441: * handy-dandy special-purpose copyin call ! 1442: * to get two send rights for the price of one. ! 1443: */ ! 1444: ! 1445: kr = ipc_right_copyin_two(space, name, entry, ! 1446: &dest_port, &dest_soright); ! 1447: if (kr != KERN_SUCCESS) ! 1448: goto invalid_dest; ! 1449: ! 1450: /* the entry might need to be deallocated */ ! 1451: ! 1452: if (IE_BITS_TYPE(entry->ie_bits) ! 1453: == MACH_PORT_TYPE_NONE) ! 1454: ipc_entry_dealloc(space, name, entry); ! 1455: ! 1456: reply_port = dest_port; ! 1457: reply_soright = IP_NULL; ! 1458: } else { ! 1459: ipc_port_t soright; ! 1460: ! 1461: assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) && ! 1462: (reply_type == MACH_MSG_TYPE_MOVE_SEND)) || ! 1463: ((dest_type == MACH_MSG_TYPE_MOVE_SEND) && ! 1464: (reply_type == MACH_MSG_TYPE_COPY_SEND))); ! 1465: ! 1466: /* ! 1467: * To make this atomic, just do a move-send, ! 1468: * and dup the send right we get out. ! 1469: */ ! 1470: ! 1471: kr = ipc_right_copyin(space, name, entry, ! 1472: MACH_MSG_TYPE_MOVE_SEND, FALSE, ! 1473: &dest_port, &soright); ! 1474: if (kr != KERN_SUCCESS) ! 1475: goto invalid_dest; ! 1476: ! 1477: /* the entry might need to be deallocated */ ! 1478: ! 1479: if (IE_BITS_TYPE(entry->ie_bits) ! 1480: == MACH_PORT_TYPE_NONE) ! 1481: ipc_entry_dealloc(space, name, entry); ! 1482: ! 1483: /* ! 1484: * It's OK if the port we got is dead now, ! 1485: * so reply_port is IP_DEAD, because the msg ! 1486: * won't go anywhere anyway. ! 1487: */ ! 1488: ! 1489: reply_port = (ipc_object_t) ! 1490: ipc_port_copy_send((ipc_port_t) dest_port); ! 1491: ! 1492: if (dest_type == MACH_MSG_TYPE_MOVE_SEND) { ! 1493: dest_soright = soright; ! 1494: reply_soright = IP_NULL; ! 1495: } else { ! 1496: dest_soright = IP_NULL; ! 1497: reply_soright = soright; ! 1498: } ! 1499: } ! 1500: } else if (!MACH_PORT_VALID(reply_name)) { ! 1501: ipc_entry_t entry; ! 1502: ! 1503: /* ! 1504: * No reply port! This is an easy case ! 1505: * to make atomic. Just copyin the destination. ! 1506: */ ! 1507: ! 1508: entry = ipc_entry_lookup(space, dest_name); ! 1509: if (entry == IE_NULL) ! 1510: goto invalid_dest; ! 1511: ! 1512: kr = ipc_right_copyin(space, dest_name, entry, ! 1513: dest_type, FALSE, ! 1514: &dest_port, &dest_soright); ! 1515: if (kr != KERN_SUCCESS) ! 1516: goto invalid_dest; ! 1517: ! 1518: /* the entry might need to be deallocated */ ! 1519: ! 1520: if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1521: ipc_entry_dealloc(space, dest_name, entry); ! 1522: ! 1523: reply_port = (ipc_object_t) reply_name; ! 1524: reply_soright = IP_NULL; ! 1525: } else { ! 1526: ipc_entry_t dest_entry, reply_entry; ! 1527: ipc_port_t saved_reply; ! 1528: ! 1529: /* ! 1530: * This is the tough case to make atomic. ! 1531: * The difficult problem is serializing with port death. ! 1532: * At the time we copyin dest_port, it must be alive. ! 1533: * If reply_port is alive when we copyin it, then ! 1534: * we are OK, because we serialize before the death ! 1535: * of both ports. Assume reply_port is dead at copyin. ! 1536: * Then if dest_port dies/died after reply_port died, ! 1537: * we are OK, because we serialize between the death ! 1538: * of the two ports. So the bad case is when dest_port ! 1539: * dies after its copyin, reply_port dies before its ! 1540: * copyin, and dest_port dies before reply_port. Then ! 1541: * the copyins operated as if dest_port was alive ! 1542: * and reply_port was dead, which shouldn't have happened ! 1543: * because they died in the other order. ! 1544: * ! 1545: * We handle the bad case by undoing the copyins ! 1546: * (which is only possible because the ports are dead) ! 1547: * and failing with MACH_SEND_INVALID_DEST, serializing ! 1548: * after the death of the ports. ! 1549: * ! 1550: * Note that it is easy for a user task to tell if ! 1551: * a copyin happened before or after a port died. ! 1552: * For example, suppose both dest and reply are ! 1553: * send-once rights (types are both move-sonce) and ! 1554: * both rights have dead-name requests registered. ! 1555: * If a port dies before copyin, a dead-name notification ! 1556: * is generated and the dead name's urefs are incremented, ! 1557: * and if the copyin happens first, a port-deleted ! 1558: * notification is generated. ! 1559: * ! 1560: * Note that although the entries are different, ! 1561: * dest_port and reply_port might still be the same. ! 1562: */ ! 1563: ! 1564: dest_entry = ipc_entry_lookup(space, dest_name); ! 1565: if (dest_entry == IE_NULL) ! 1566: goto invalid_dest; ! 1567: ! 1568: reply_entry = ipc_entry_lookup(space, reply_name); ! 1569: if (reply_entry == IE_NULL) ! 1570: goto invalid_reply; ! 1571: ! 1572: assert(dest_entry != reply_entry); /* names are not equal */ ! 1573: assert(reply_type != 0); /* because reply_name not null */ ! 1574: ! 1575: if (!ipc_right_copyin_check(space, reply_name, reply_entry, ! 1576: reply_type)) ! 1577: goto invalid_reply; ! 1578: ! 1579: kr = ipc_right_copyin(space, dest_name, dest_entry, ! 1580: dest_type, FALSE, ! 1581: &dest_port, &dest_soright); ! 1582: if (kr != KERN_SUCCESS) ! 1583: goto invalid_dest; ! 1584: ! 1585: assert(IO_VALID(dest_port)); ! 1586: ! 1587: saved_reply = (ipc_port_t) reply_entry->ie_object; ! 1588: /* might be IP_NULL, if this is a dead name */ ! 1589: if (saved_reply != IP_NULL) ! 1590: ipc_port_reference(saved_reply); ! 1591: ! 1592: kr = ipc_right_copyin(space, reply_name, reply_entry, ! 1593: reply_type, TRUE, ! 1594: &reply_port, &reply_soright); ! 1595: #if MACH_IPC_COMPAT ! 1596: if (kr != KERN_SUCCESS) { ! 1597: assert(kr == KERN_INVALID_NAME); ! 1598: ! 1599: /* ! 1600: * Oops. This must have been a compat entry ! 1601: * and the port died after the check above. ! 1602: * We should back out the copyin of dest_port, ! 1603: * and report MACH_SEND_INVALID_REPLY, but ! 1604: * if dest_port is alive we can't always do that. ! 1605: * Punt and pretend we got IO_DEAD, skipping ! 1606: * further hairy atomicity problems. ! 1607: */ ! 1608: ! 1609: reply_port = IO_DEAD; ! 1610: reply_soright = IP_NULL; ! 1611: goto skip_reply_checks; ! 1612: } ! 1613: #else MACH_IPC_COMPAT ! 1614: assert(kr == KERN_SUCCESS); ! 1615: #endif MACH_IPC_COMPAT ! 1616: ! 1617: if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) { ! 1618: ipc_port_t dest = (ipc_port_t) dest_port; ! 1619: ipc_port_timestamp_t timestamp; ! 1620: boolean_t must_undo; ! 1621: ! 1622: /* ! 1623: * The reply port died before copyin. ! 1624: * Check if dest port died before reply. ! 1625: */ ! 1626: ! 1627: ip_lock(saved_reply); ! 1628: assert(!ip_active(saved_reply)); ! 1629: timestamp = saved_reply->ip_timestamp; ! 1630: ip_unlock(saved_reply); ! 1631: ! 1632: ip_lock(dest); ! 1633: must_undo = (!ip_active(dest) && ! 1634: IP_TIMESTAMP_ORDER(dest->ip_timestamp, ! 1635: timestamp)); ! 1636: ip_unlock(dest); ! 1637: ! 1638: if (must_undo) { ! 1639: /* ! 1640: * Our worst nightmares are realized. ! 1641: * Both destination and reply ports ! 1642: * are dead, but in the wrong order, ! 1643: * so we must undo the copyins and ! 1644: * possibly generate a dead-name notif. ! 1645: */ ! 1646: ! 1647: ipc_right_copyin_undo( ! 1648: space, dest_name, dest_entry, ! 1649: dest_type, dest_port, ! 1650: dest_soright); ! 1651: /* dest_entry may be deallocated now */ ! 1652: ! 1653: ipc_right_copyin_undo( ! 1654: space, reply_name, reply_entry, ! 1655: reply_type, reply_port, ! 1656: reply_soright); ! 1657: /* reply_entry may be deallocated now */ ! 1658: ! 1659: is_write_unlock(space); ! 1660: ! 1661: if (dest_soright != IP_NULL) ! 1662: ipc_notify_dead_name(dest_soright, ! 1663: dest_name); ! 1664: assert(reply_soright == IP_NULL); ! 1665: ! 1666: ipc_port_release(saved_reply); ! 1667: return MACH_SEND_INVALID_DEST; ! 1668: } ! 1669: } ! 1670: ! 1671: /* the entries might need to be deallocated */ ! 1672: ! 1673: if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1674: ipc_entry_dealloc(space, reply_name, reply_entry); ! 1675: ! 1676: #if MACH_IPC_COMPAT ! 1677: skip_reply_checks: ! 1678: /* ! 1679: * We jump here if the reply entry was a compat entry ! 1680: * and the port died on us. In this case, the copyin ! 1681: * code already deallocated reply_entry. ! 1682: */ ! 1683: #endif MACH_IPC_COMPAT ! 1684: ! 1685: if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE) ! 1686: ipc_entry_dealloc(space, dest_name, dest_entry); ! 1687: ! 1688: if (saved_reply != IP_NULL) ! 1689: ipc_port_release(saved_reply); ! 1690: } ! 1691: ! 1692: /* ! 1693: * At this point, dest_port, reply_port, ! 1694: * dest_soright, reply_soright are all initialized. ! 1695: * Any defunct entries have been deallocated. ! 1696: * The space is still write-locked, and we need to ! 1697: * make the MACH_SEND_CANCEL check. The notify_port pointer ! 1698: * is still usable, because the copyin code above won't ever ! 1699: * deallocate a receive right, so its entry still exists ! 1700: * and holds a ref. Note notify_port might even equal ! 1701: * dest_port or reply_port. ! 1702: */ ! 1703: ! 1704: if ((notify != MACH_PORT_NULL) && ! 1705: (dest_soright == notify_port)) { ! 1706: ipc_port_release_sonce(dest_soright); ! 1707: dest_soright = IP_NULL; ! 1708: } ! 1709: ! 1710: is_write_unlock(space); ! 1711: ! 1712: if (dest_soright != IP_NULL) ! 1713: ipc_notify_port_deleted(dest_soright, dest_name); ! 1714: ! 1715: if (reply_soright != IP_NULL) ! 1716: ipc_notify_port_deleted(reply_soright, reply_name); ! 1717: ! 1718: dest_type = ipc_object_copyin_type(dest_type); ! 1719: reply_type = ipc_object_copyin_type(reply_type); ! 1720: ! 1721: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 1722: MACH_MSGH_BITS(dest_type, reply_type)); ! 1723: msg->msgh_remote_port = (mach_port_t) dest_port; ! 1724: msg->msgh_local_port = (mach_port_t) reply_port; ! 1725: } ! 1726: ! 1727: return MACH_MSG_SUCCESS; ! 1728: ! 1729: invalid_dest: ! 1730: is_write_unlock(space); ! 1731: return MACH_SEND_INVALID_DEST; ! 1732: ! 1733: invalid_reply: ! 1734: is_write_unlock(space); ! 1735: return MACH_SEND_INVALID_REPLY; ! 1736: } ! 1737: ! 1738: /* ! 1739: * Routine: ipc_kmsg_copyin_body ! 1740: * Purpose: ! 1741: * "Copy-in" port rights and out-of-line memory ! 1742: * in the message body. ! 1743: * ! 1744: * In all failure cases, the message is left holding ! 1745: * no rights or memory. However, the message buffer ! 1746: * is not deallocated. If successful, the message ! 1747: * contains a valid destination port. ! 1748: * Conditions: ! 1749: * Nothing locked. ! 1750: * Returns: ! 1751: * MACH_MSG_SUCCESS Successful copyin. ! 1752: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory. ! 1753: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body. ! 1754: * MACH_SEND_INVALID_TYPE Bad type specification. ! 1755: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data. ! 1756: */ ! 1757: ! 1758: mach_msg_return_t ! 1759: ipc_kmsg_copyin_body( ! 1760: ipc_kmsg_t kmsg, ! 1761: ipc_space_t space, ! 1762: vm_map_t map) ! 1763: { ! 1764: ipc_object_t dest; ! 1765: mach_msg_body_t *body; ! 1766: mach_msg_descriptor_t *saddr, *eaddr; ! 1767: boolean_t complex; ! 1768: boolean_t use_page_lists, steal_pages; ! 1769: int i; ! 1770: kern_return_t kr; ! 1771: vm_size_t space_needed = 0; ! 1772: vm_offset_t paddr = 0; ! 1773: mach_msg_descriptor_t *sstart; ! 1774: vm_map_copy_t copy = VM_MAP_COPY_NULL; ! 1775: ! 1776: /* ! 1777: * Determine if the target is a kernel port. ! 1778: */ ! 1779: dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 1780: complex = FALSE; ! 1781: use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest)); ! 1782: steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest)); ! 1783: ! 1784: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 1785: saddr = (mach_msg_descriptor_t *) (body + 1); ! 1786: eaddr = saddr + body->msgh_descriptor_count; ! 1787: ! 1788: /* make sure the message does not ask for more msg descriptors ! 1789: * than the message can hold. ! 1790: */ ! 1791: ! 1792: if (eaddr <= saddr || ! 1793: eaddr > (mach_msg_descriptor_t *) (&kmsg->ikm_header + ! 1794: kmsg->ikm_header.msgh_size)) { ! 1795: ipc_kmsg_clean_partial(kmsg, 0, 0, 0); ! 1796: return MACH_SEND_MSG_TOO_SMALL; ! 1797: } ! 1798: ! 1799: /* ! 1800: * Make an initial pass to determine kernal VM space requirements for ! 1801: * physical copies. ! 1802: */ ! 1803: for (sstart = saddr; sstart < eaddr; sstart++) { ! 1804: ! 1805: if (sstart->type.type == MACH_MSG_OOL_DESCRIPTOR) { ! 1806: ! 1807: assert(!(sstart->out_of_line.copy == MACH_MSG_PHYSICAL_COPY && ! 1808: (use_page_lists || steal_pages))); ! 1809: ! 1810: if (sstart->out_of_line.copy != MACH_MSG_PHYSICAL_COPY && ! 1811: sstart->out_of_line.copy != MACH_MSG_VIRTUAL_COPY) { ! 1812: /* ! 1813: * Invalid copy option ! 1814: */ ! 1815: ipc_kmsg_clean_partial(kmsg, 0, 0, 0); ! 1816: return MACH_SEND_INVALID_TYPE; ! 1817: } ! 1818: ! 1819: if (sstart->out_of_line.copy == MACH_MSG_PHYSICAL_COPY && ! 1820: #if MACH_OLD_VM_COPY ! 1821: #else ! 1822: sstart->out_of_line.size > MSG_OOL_SIZE_SMALL && ! 1823: #endif ! 1824: !sstart->out_of_line.deallocate) { ! 1825: ! 1826: /* ! 1827: * Out-of-line memory descriptor, accumulate kernel ! 1828: * memory requirements ! 1829: */ ! 1830: space_needed += round_page(sstart->out_of_line.size); ! 1831: } ! 1832: } ! 1833: } ! 1834: ! 1835: /* ! 1836: * Allocate space in the pageable kernel ipc copy map for all the ! 1837: * ool data that is to be physically copied. Map is marked wait for ! 1838: * space. ! 1839: */ ! 1840: if (space_needed > 0) { ! 1841: if (vm_allocate(ipc_kernel_copy_map, &paddr, space_needed, ! 1842: TRUE) != KERN_SUCCESS) { ! 1843: ipc_kmsg_clean_partial(kmsg, 0, 0, 0); ! 1844: return MACH_MSG_VM_KERNEL; ! 1845: } ! 1846: } ! 1847: ! 1848: /* ! 1849: * handle the OOL regions and port descriptors. ! 1850: * the check for complex messages was done earlier. ! 1851: */ ! 1852: ! 1853: for (i = 0, sstart = saddr; sstart < eaddr; sstart++) { ! 1854: ! 1855: switch (sstart->type.type) { ! 1856: ! 1857: case MACH_MSG_PORT_DESCRIPTOR: { ! 1858: mach_msg_type_name_t name; ! 1859: ipc_object_t object; ! 1860: mach_msg_port_descriptor_t *dsc; ! 1861: ! 1862: dsc = &sstart->port; ! 1863: ! 1864: /* this is really the type SEND, SEND_ONCE, etc. */ ! 1865: name = dsc->disposition; ! 1866: if (!MACH_MSG_TYPE_PORT_ANY(name)) { ! 1867: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 1868: return MACH_SEND_INVALID_TYPE; ! 1869: } ! 1870: dsc->disposition = ipc_object_copyin_type(name); ! 1871: ! 1872: if (!MACH_PORT_VALID(dsc->name)) { ! 1873: complex = TRUE; ! 1874: break; ! 1875: } ! 1876: kr = ipc_object_copyin(space, dsc->name, name, &object); ! 1877: if (kr != KERN_SUCCESS) { ! 1878: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 1879: return MACH_SEND_INVALID_RIGHT; ! 1880: } ! 1881: if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) && ! 1882: ipc_port_check_circularity((ipc_port_t) object, ! 1883: (ipc_port_t) dest)) { ! 1884: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR; ! 1885: } ! 1886: dsc->name = (mach_port_t) object; ! 1887: complex = TRUE; ! 1888: break; ! 1889: } ! 1890: case MACH_MSG_OOL_DESCRIPTOR: { ! 1891: vm_size_t length; ! 1892: boolean_t dealloc; ! 1893: vm_offset_t addr; ! 1894: vm_offset_t kaddr; ! 1895: mach_msg_ool_descriptor_t *dsc; ! 1896: ! 1897: dsc = &sstart->out_of_line; ! 1898: dealloc = dsc->deallocate; ! 1899: addr = (vm_offset_t) dsc->address; ! 1900: ! 1901: length = dsc->size; ! 1902: ! 1903: if (length == 0) { ! 1904: dsc->address = 0; ! 1905: #if OLD_VM_CODE ! 1906: #else ! 1907: } else if (use_page_lists) { ! 1908: int options; ! 1909: ! 1910: /* ! 1911: * Use page list copy mechanism if specified. Since the ! 1912: * destination is a kernel port, no RT handling is ! 1913: * necessary. ! 1914: */ ! 1915: if (steal_pages == FALSE) { ! 1916: /* ! 1917: * XXX Temporary Hackaround. ! 1918: * XXX Because the same page ! 1919: * XXX might be in more than one ! 1920: * XXX out of line region, steal ! 1921: * XXX (busy) pages from previous ! 1922: * XXX region so that this copyin ! 1923: * XXX won't block (permanently). ! 1924: */ ! 1925: if (copy != VM_MAP_COPY_NULL) ! 1926: vm_map_copy_steal_pages(copy); ! 1927: } ! 1928: ! 1929: /* ! 1930: * Set up options for copying in page list. ! 1931: * If deallocating, steal pages to prevent ! 1932: * vm code from lazy evaluating deallocation. ! 1933: */ ! 1934: options = VM_PROT_READ; ! 1935: if (dealloc) { ! 1936: options |= VM_MAP_COPYIN_OPT_SRC_DESTROY | ! 1937: VM_MAP_COPYIN_OPT_STEAL_PAGES; ! 1938: } ! 1939: else if (steal_pages) { ! 1940: options |= VM_MAP_COPYIN_OPT_STEAL_PAGES; ! 1941: } ! 1942: ! 1943: if (vm_map_copyin_page_list(map, addr, length, options, ! 1944: ©, FALSE) ! 1945: != KERN_SUCCESS) { ! 1946: ! 1947: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1948: space_needed); ! 1949: return MACH_SEND_INVALID_MEMORY; ! 1950: } ! 1951: ! 1952: dsc->address = (void *) copy; ! 1953: dsc->copy = MACH_MSG_PAGE_LIST_COPY_T; ! 1954: #endif ! 1955: #if MACH_OLD_VM_COPY ! 1956: #else ! 1957: } else if (length <= MSG_OOL_SIZE_SMALL && ! 1958: dsc->copy == MACH_MSG_PHYSICAL_COPY) { ! 1959: ! 1960: /* ! 1961: * If the data is 'small' enough, always kalloc space for ! 1962: * it and copy it in. The data will be copied out ! 1963: * on the message receive. This is a performance ! 1964: * optimization that assumes the cost of VM operations ! 1965: * dominates the copyin/copyout overhead for 'small' ! 1966: * regions. ! 1967: * If the kernel is the message target, a consistent data ! 1968: * repesentation is needed for ool data since kernel ! 1969: * functions may deallocate the ool data. In this case ! 1970: * a vm_map_copy_t is allocated along with the space for ! 1971: * the data as an optimization. No RT handling is needed. ! 1972: */ ! 1973: if (is_ipc_kobject(ip_kotype((ipc_port_t)dest))) { ! 1974: vm_map_copy_t copy; ! 1975: ! 1976: copy = (vm_map_copy_t) kalloc( ! 1977: sizeof(struct vm_map_copy) + length); ! 1978: if (copy == VM_MAP_COPY_NULL) { ! 1979: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1980: space_needed); ! 1981: return MACH_MSG_VM_KERNEL; ! 1982: } ! 1983: copy->type = VM_MAP_COPY_KERNEL_BUFFER; ! 1984: if (copyin((const char *) addr, (char *) (copy + 1), ! 1985: length)) { ! 1986: kfree((vm_offset_t) copy, ! 1987: sizeof(struct vm_map_copy) + length); ! 1988: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 1989: space_needed); ! 1990: return MACH_SEND_INVALID_MEMORY; ! 1991: } ! 1992: dsc->address = (void *) copy; ! 1993: dsc->copy = MACH_MSG_KALLOC_COPY_T; ! 1994: copy->size = length; ! 1995: copy->offset = 0; ! 1996: copy->cpy_data = (vm_offset_t) (copy + 1); ! 1997: } else { ! 1998: if ((kaddr = kalloc(length)) == (vm_offset_t) 0) { ! 1999: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 2000: space_needed); ! 2001: return MACH_MSG_VM_KERNEL; ! 2002: } ! 2003: ! 2004: if (copyin((const char *) addr, (char *) kaddr, ! 2005: length)) { ! 2006: kfree(kaddr, length); ! 2007: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 2008: space_needed); ! 2009: return MACH_SEND_INVALID_MEMORY; ! 2010: } ! 2011: dsc->address = (void *) kaddr; ! 2012: } ! 2013: if (dealloc) { ! 2014: #if OLD_VM_CODE ! 2015: (void) vm_deallocate(map, addr, length); ! 2016: #else ! 2017: (void) vm_map_remove(map, trunc_page(addr), ! 2018: round_page(addr + length), ! 2019: VM_MAP_REMOVE_WAIT_FOR_KWIRE| ! 2020: VM_MAP_REMOVE_INTERRUPTIBLE); ! 2021: #endif ! 2022: } ! 2023: #endif ! 2024: } else { ! 2025: if ((dsc->copy == MACH_MSG_PHYSICAL_COPY) && !dealloc) { ! 2026: ! 2027: /* ! 2028: * If the request is a physical copy and the source ! 2029: * is not being deallocated, then allocate space ! 2030: * in the kernel's pageable ipc copy map and copy ! 2031: * the data in. The semantics guarantee that the ! 2032: * data will have been physically copied before ! 2033: * the send operation terminates. Thus if the data ! 2034: * is not being deallocated, we must be prepared ! 2035: * to page if the region is sufficiently large. ! 2036: */ ! 2037: if (copyin((const char *) addr, (char *) paddr, ! 2038: length)) { ! 2039: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 2040: space_needed); ! 2041: return MACH_SEND_INVALID_MEMORY; ! 2042: } ! 2043: ! 2044: /* ! 2045: * The kernel ipc copy map is marked no_zero_fill. ! 2046: * If the transfer is not a page multiple, we need ! 2047: * to zero fill the balance. ! 2048: */ ! 2049: if (!page_aligned(length)) { ! 2050: (void) bzero((void *) (paddr + length), ! 2051: round_page(length) - length); ! 2052: } ! 2053: #if MACH_OLD_VM_COPY ! 2054: if (vm_move( ! 2055: ipc_kernel_copy_map, paddr, ! 2056: ipc_soft_map, length, FALSE, ! 2057: (vm_offset_t *)©) != KERN_SUCCESS) { ! 2058: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 2059: space_needed); ! 2060: return MACH_MSG_VM_KERNEL; ! 2061: } ! 2062: (void) vm_deallocate( ! 2063: ipc_kernel_copy_map, paddr, length); ! 2064: #else ! 2065: if (vm_map_copyin(ipc_kernel_copy_map, paddr, length, ! 2066: TRUE, ©) != KERN_SUCCESS) { ! 2067: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 2068: space_needed); ! 2069: return MACH_MSG_VM_KERNEL; ! 2070: } ! 2071: #endif ! 2072: paddr += round_page(length); ! 2073: space_needed -= round_page(length); ! 2074: } else { ! 2075: ! 2076: /* ! 2077: * Make a virtual copy of the of the data if requested ! 2078: * or if a physical copy was requested but the source ! 2079: * is being deallocated. ! 2080: */ ! 2081: #if MACH_OLD_VM_COPY ! 2082: if (vm_move( ! 2083: map, addr, ! 2084: ipc_soft_map, length, FALSE, ! 2085: (vm_offset_t *)©) != KERN_SUCCESS) { ! 2086: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 2087: space_needed); ! 2088: return MACH_SEND_INVALID_MEMORY; ! 2089: } ! 2090: if (dealloc) ! 2091: (void) vm_deallocate( ! 2092: map, addr, length); ! 2093: #else ! 2094: if (vm_map_copyin(map, addr, length, ! 2095: dealloc, ©) != KERN_SUCCESS) { ! 2096: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 2097: space_needed); ! 2098: return MACH_SEND_INVALID_MEMORY; ! 2099: } ! 2100: #endif ! 2101: } ! 2102: dsc->address = (void *) copy; ! 2103: } ! 2104: complex = TRUE; ! 2105: break; ! 2106: } ! 2107: case MACH_MSG_OOL_PORTS_DESCRIPTOR: { ! 2108: vm_size_t length; ! 2109: vm_offset_t data; ! 2110: vm_offset_t addr; ! 2111: ipc_object_t *objects; ! 2112: int j; ! 2113: mach_msg_type_name_t name; ! 2114: mach_msg_ool_ports_descriptor_t *dsc; ! 2115: ! 2116: dsc = &sstart->ool_ports; ! 2117: addr = (vm_offset_t) dsc->address; ! 2118: ! 2119: /* calculate length of data in bytes, rounding up */ ! 2120: length = dsc->count * sizeof(mach_port_t); ! 2121: ! 2122: if (length == 0) { ! 2123: complex = TRUE; ! 2124: dsc->address = (void *) 0; ! 2125: break; ! 2126: } ! 2127: ! 2128: data = kalloc(length); ! 2129: ! 2130: if (data == 0) { ! 2131: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 2132: return MACH_SEND_NO_BUFFER; ! 2133: } ! 2134: ! 2135: if (copyinmap(map, addr, data, length)) { ! 2136: kfree(data, length); ! 2137: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 2138: return MACH_SEND_INVALID_MEMORY; ! 2139: } ! 2140: ! 2141: /* this is really the type SEND, SEND_ONCE, etc. */ ! 2142: name = dsc->disposition; ! 2143: if (!MACH_MSG_TYPE_PORT_ANY(name)) { ! 2144: kfree(data, length); ! 2145: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 2146: return MACH_SEND_INVALID_TYPE; ! 2147: } ! 2148: dsc->disposition = ipc_object_copyin_type(name); ! 2149: ! 2150: if (dsc->deallocate) { ! 2151: (void) vm_deallocate(map, addr, length); ! 2152: } ! 2153: ! 2154: dsc->address = (void *) data; ! 2155: objects = (ipc_object_t *) data; ! 2156: ! 2157: for ( j = 0; j < dsc->count; j++) { ! 2158: mach_port_t port = (mach_port_t) objects[j]; ! 2159: ipc_object_t object; ! 2160: ! 2161: if (!MACH_PORT_VALID(port)) ! 2162: continue; ! 2163: ! 2164: kr = ipc_object_copyin(space, port, name, &object); ! 2165: ! 2166: if (kr != KERN_SUCCESS) { ! 2167: int k; ! 2168: ! 2169: for(k = 0; k < j; k++) { ! 2170: object = objects[k]; ! 2171: if (!MACH_PORT_VALID(port)) ! 2172: continue; ! 2173: ipc_object_destroy(object, dsc->disposition); ! 2174: } ! 2175: kfree(data, length); ! 2176: ipc_kmsg_clean_partial(kmsg, i, paddr, ! 2177: space_needed); ! 2178: return MACH_SEND_INVALID_RIGHT; ! 2179: } ! 2180: ! 2181: if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) && ! 2182: ipc_port_check_circularity( ! 2183: (ipc_port_t) object, ! 2184: (ipc_port_t) dest)) ! 2185: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR; ! 2186: ! 2187: objects[j] = object; ! 2188: } ! 2189: ! 2190: complex = TRUE; ! 2191: break; ! 2192: } ! 2193: default: { ! 2194: /* ! 2195: * Invalid descriptor ! 2196: */ ! 2197: ipc_kmsg_clean_partial(kmsg, i, paddr, space_needed); ! 2198: return MACH_SEND_INVALID_TYPE; ! 2199: } ! 2200: } ! 2201: i++ ; ! 2202: } ! 2203: ! 2204: if (!complex) ! 2205: kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX; ! 2206: ! 2207: return MACH_MSG_SUCCESS; ! 2208: } ! 2209: ! 2210: ! 2211: /* ! 2212: * Routine: ipc_kmsg_copyin ! 2213: * Purpose: ! 2214: * "Copy-in" port rights and out-of-line memory ! 2215: * in the message. ! 2216: * ! 2217: * In all failure cases, the message is left holding ! 2218: * no rights or memory. However, the message buffer ! 2219: * is not deallocated. If successful, the message ! 2220: * contains a valid destination port. ! 2221: * Conditions: ! 2222: * Nothing locked. ! 2223: * Returns: ! 2224: * MACH_MSG_SUCCESS Successful copyin. ! 2225: * MACH_SEND_INVALID_HEADER ! 2226: * Illegal value in the message header bits. ! 2227: * MACH_SEND_INVALID_NOTIFY Bad notify port. ! 2228: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 2229: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 2230: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory. ! 2231: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body. ! 2232: * MACH_SEND_INVALID_TYPE Bad type specification. ! 2233: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data. ! 2234: */ ! 2235: ! 2236: mach_msg_return_t ! 2237: ipc_kmsg_copyin( ! 2238: ipc_kmsg_t kmsg, ! 2239: ipc_space_t space, ! 2240: vm_map_t map, ! 2241: mach_port_t notify) ! 2242: { ! 2243: mach_msg_return_t mr; ! 2244: ! 2245: mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify); ! 2246: if (mr != MACH_MSG_SUCCESS) ! 2247: return mr; ! 2248: ! 2249: if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) ! 2250: return MACH_MSG_SUCCESS; ! 2251: ! 2252: return( ipc_kmsg_copyin_body( kmsg, space, map ) ); ! 2253: } ! 2254: ! 2255: /* ! 2256: * Routine: ipc_kmsg_copyin_from_kernel ! 2257: * Purpose: ! 2258: * "Copy-in" port rights and out-of-line memory ! 2259: * in a message sent from the kernel. ! 2260: * ! 2261: * Because the message comes from the kernel, ! 2262: * the implementation assumes there are no errors ! 2263: * or peculiarities in the message. ! 2264: * ! 2265: * Returns TRUE if queueing the message ! 2266: * would result in a circularity. ! 2267: * Conditions: ! 2268: * Nothing locked. ! 2269: */ ! 2270: ! 2271: void ! 2272: ipc_kmsg_copyin_from_kernel( ! 2273: ipc_kmsg_t kmsg) ! 2274: { ! 2275: mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits &~ ! 2276: MACH_MSGH_BITS_OLD_FORMAT; ! 2277: mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits); ! 2278: mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits); ! 2279: ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 2280: ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 2281: ! 2282: /* translate the destination and reply ports */ ! 2283: ! 2284: ipc_object_copyin_from_kernel(remote, rname); ! 2285: if (IO_VALID(local)) ! 2286: ipc_object_copyin_from_kernel(local, lname); ! 2287: ! 2288: /* ! 2289: * The common case is a complex message with no reply port, ! 2290: * because that is what the memory_object interface uses. ! 2291: */ ! 2292: ! 2293: if (bits == (MACH_MSGH_BITS_COMPLEX | ! 2294: MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) { ! 2295: bits = (MACH_MSGH_BITS_COMPLEX | ! 2296: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0)); ! 2297: ! 2298: kmsg->ikm_header.msgh_bits = bits; ! 2299: } else { ! 2300: bits = (MACH_MSGH_BITS_OTHER(bits) | ! 2301: MACH_MSGH_BITS(ipc_object_copyin_type(rname), ! 2302: ipc_object_copyin_type(lname))); ! 2303: ! 2304: kmsg->ikm_header.msgh_bits = bits; ! 2305: if ((bits & MACH_MSGH_BITS_COMPLEX) == 0) ! 2306: return; ! 2307: } ! 2308: { ! 2309: mach_msg_descriptor_t *saddr, *eaddr; ! 2310: mach_msg_body_t *body; ! 2311: ! 2312: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 2313: saddr = (mach_msg_descriptor_t *) (body + 1); ! 2314: eaddr = (mach_msg_descriptor_t *) saddr + body->msgh_descriptor_count; ! 2315: ! 2316: for ( ; saddr < eaddr; saddr++) { ! 2317: ! 2318: switch (saddr->type.type) { ! 2319: ! 2320: case MACH_MSG_PORT_DESCRIPTOR: { ! 2321: mach_msg_type_name_t name; ! 2322: ipc_object_t object; ! 2323: mach_msg_port_descriptor_t *dsc; ! 2324: ! 2325: dsc = &saddr->port; ! 2326: ! 2327: /* this is really the type SEND, SEND_ONCE, etc. */ ! 2328: name = dsc->disposition; ! 2329: object = (ipc_object_t) dsc->name; ! 2330: dsc->disposition = ipc_object_copyin_type(name); ! 2331: ! 2332: if (!IO_VALID(object)) { ! 2333: break; ! 2334: } ! 2335: ! 2336: ipc_object_copyin_from_kernel(object, name); ! 2337: ! 2338: if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) && ! 2339: ipc_port_check_circularity((ipc_port_t) object, ! 2340: (ipc_port_t) remote)) { ! 2341: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR; ! 2342: } ! 2343: break; ! 2344: } ! 2345: case MACH_MSG_OOL_DESCRIPTOR: { ! 2346: /* ! 2347: * The sender should supply ready-made memory, i.e. ! 2348: * a vm_map_copy_t, so we don't need to do anything. ! 2349: */ ! 2350: break; ! 2351: } ! 2352: case MACH_MSG_OOL_PORTS_DESCRIPTOR: { ! 2353: ipc_object_t *objects; ! 2354: int j; ! 2355: mach_msg_type_name_t name; ! 2356: mach_msg_ool_ports_descriptor_t *dsc; ! 2357: ! 2358: dsc = &saddr->ool_ports; ! 2359: ! 2360: /* this is really the type SEND, SEND_ONCE, etc. */ ! 2361: name = dsc->disposition; ! 2362: dsc->disposition = ipc_object_copyin_type(name); ! 2363: ! 2364: objects = (ipc_object_t *) dsc->address; ! 2365: ! 2366: for ( j = 0; j < dsc->count; j++) { ! 2367: ipc_object_t object = objects[j]; ! 2368: ! 2369: if (!IO_VALID(object)) ! 2370: continue; ! 2371: ! 2372: ipc_object_copyin_from_kernel(object, name); ! 2373: ! 2374: if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) && ! 2375: ipc_port_check_circularity( ! 2376: (ipc_port_t) object, ! 2377: (ipc_port_t) remote)) ! 2378: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_CIRCULAR; ! 2379: } ! 2380: break; ! 2381: } ! 2382: default: { ! 2383: #if MACH_ASSERT ! 2384: panic("ipc_kmsg_copyin_from_kernel: bad descriptor type %d", ! 2385: saddr->type.type); ! 2386: #endif /* MACH_ASSERT */ ! 2387: } ! 2388: } ! 2389: } ! 2390: } ! 2391: } ! 2392: ! 2393: /* ! 2394: * Routine: ipc_kmsg_copyout_header ! 2395: * Purpose: ! 2396: * "Copy-out" port rights in the header of a message. ! 2397: * Operates atomically; if it doesn't succeed the ! 2398: * message header and the space are left untouched. ! 2399: * If it does succeed the remote/local port fields ! 2400: * contain port names instead of object pointers, ! 2401: * and the bits field is updated. ! 2402: * ! 2403: * The notify argument implements the MACH_RCV_NOTIFY option. ! 2404: * If it is not MACH_PORT_NULL, it should name a receive right. ! 2405: * If the process of receiving the reply port creates a ! 2406: * new right in the receiving task, then the new right is ! 2407: * automatically registered for a dead-name notification, ! 2408: * with the notify port supplying the send-once right. ! 2409: * Conditions: ! 2410: * Nothing locked. ! 2411: * Returns: ! 2412: * MACH_MSG_SUCCESS Copied out port rights. ! 2413: * MACH_RCV_INVALID_NOTIFY ! 2414: * Notify is non-null and doesn't name a receive right. ! 2415: * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.) ! 2416: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE ! 2417: * The space is dead. ! 2418: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE ! 2419: * No room in space for another name. ! 2420: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL ! 2421: * Couldn't allocate memory for the reply port. ! 2422: * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL ! 2423: * Couldn't allocate memory for the dead-name request. ! 2424: */ ! 2425: ! 2426: mach_msg_return_t ! 2427: ipc_kmsg_copyout_header( ! 2428: mach_msg_header_t *msg, ! 2429: ipc_space_t space, ! 2430: mach_port_t notify) ! 2431: { ! 2432: mach_msg_bits_t mbits = msg->msgh_bits; ! 2433: ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port; ! 2434: ! 2435: assert(IP_VALID(dest)); ! 2436: ! 2437: /* first check for common cases */ ! 2438: ! 2439: if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) { ! 2440: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): { ! 2441: mach_port_t dest_name; ! 2442: ipc_port_t nsrequest; ! 2443: ! 2444: /* receiving an asynchronous message */ ! 2445: ! 2446: ip_lock(dest); ! 2447: if (!ip_active(dest)) { ! 2448: ip_unlock(dest); ! 2449: break; ! 2450: } ! 2451: ! 2452: /* optimized ipc_object_copyout_dest */ ! 2453: ! 2454: assert(dest->ip_srights > 0); ! 2455: ip_release(dest); ! 2456: ! 2457: if (dest->ip_receiver == space) ! 2458: dest_name = dest->ip_receiver_name; ! 2459: else ! 2460: dest_name = MACH_PORT_NULL; ! 2461: ! 2462: if ((--dest->ip_srights == 0) && ! 2463: ((nsrequest = dest->ip_nsrequest) != IP_NULL)) { ! 2464: mach_port_mscount_t mscount; ! 2465: ! 2466: dest->ip_nsrequest = IP_NULL; ! 2467: mscount = dest->ip_mscount; ! 2468: ip_unlock(dest); ! 2469: ! 2470: ipc_notify_no_senders(nsrequest, mscount); ! 2471: } else ! 2472: ip_unlock(dest); ! 2473: ! 2474: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 2475: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND)); ! 2476: msg->msgh_local_port = dest_name; ! 2477: msg->msgh_remote_port = MACH_PORT_NULL; ! 2478: return MACH_MSG_SUCCESS; ! 2479: } ! 2480: ! 2481: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, ! 2482: MACH_MSG_TYPE_PORT_SEND_ONCE): { ! 2483: ipc_entry_t table; ! 2484: mach_port_index_t index; ! 2485: ipc_entry_t entry; ! 2486: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port; ! 2487: mach_port_t dest_name, reply_name; ! 2488: ipc_port_t nsrequest; ! 2489: ! 2490: /* receiving a request message */ ! 2491: ! 2492: if (!IP_VALID(reply)) ! 2493: break; ! 2494: ! 2495: is_write_lock(space); ! 2496: if (!space->is_active || ! 2497: ((index = (table = space->is_table)->ie_next) == 0)) { ! 2498: is_write_unlock(space); ! 2499: break; ! 2500: } ! 2501: ! 2502: /* ! 2503: * To do an atomic copyout, need simultaneous ! 2504: * locks on both ports and the space. If ! 2505: * dest == reply, and simple locking is ! 2506: * enabled, then we will abort. Otherwise it's ! 2507: * OK to unlock twice. ! 2508: */ ! 2509: ! 2510: ip_lock(dest); ! 2511: if (!ip_active(dest) || !ip_lock_try(reply)) { ! 2512: ip_unlock(dest); ! 2513: is_write_unlock(space); ! 2514: break; ! 2515: } ! 2516: ! 2517: if (!ip_active(reply)) { ! 2518: ip_unlock(reply); ! 2519: ip_unlock(dest); ! 2520: is_write_unlock(space); ! 2521: break; ! 2522: } ! 2523: ! 2524: assert(reply->ip_sorights > 0); ! 2525: ip_unlock(reply); ! 2526: ! 2527: /* optimized ipc_entry_get */ ! 2528: ! 2529: entry = &table[index]; ! 2530: table->ie_next = entry->ie_next; ! 2531: entry->ie_request = 0; ! 2532: ! 2533: { ! 2534: mach_port_gen_t gen; ! 2535: ! 2536: assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0); ! 2537: gen = entry->ie_bits + IE_BITS_GEN_ONE; ! 2538: ! 2539: reply_name = MACH_PORT_MAKE(index, gen); ! 2540: ! 2541: /* optimized ipc_right_copyout */ ! 2542: ! 2543: entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1); ! 2544: } ! 2545: ! 2546: assert(MACH_PORT_VALID(reply_name)); ! 2547: entry->ie_object = (ipc_object_t) reply; ! 2548: is_write_unlock(space); ! 2549: ! 2550: /* optimized ipc_object_copyout_dest */ ! 2551: ! 2552: assert(dest->ip_srights > 0); ! 2553: ip_release(dest); ! 2554: ! 2555: if (dest->ip_receiver == space) ! 2556: dest_name = dest->ip_receiver_name; ! 2557: else ! 2558: dest_name = MACH_PORT_NULL; ! 2559: ! 2560: if ((--dest->ip_srights == 0) && ! 2561: ((nsrequest = dest->ip_nsrequest) != IP_NULL)) { ! 2562: mach_port_mscount_t mscount; ! 2563: ! 2564: dest->ip_nsrequest = IP_NULL; ! 2565: mscount = dest->ip_mscount; ! 2566: ip_unlock(dest); ! 2567: ! 2568: ipc_notify_no_senders(nsrequest, mscount); ! 2569: } else ! 2570: ip_unlock(dest); ! 2571: ! 2572: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 2573: MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, ! 2574: MACH_MSG_TYPE_PORT_SEND)); ! 2575: msg->msgh_local_port = dest_name; ! 2576: msg->msgh_remote_port = reply_name; ! 2577: return MACH_MSG_SUCCESS; ! 2578: } ! 2579: ! 2580: case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): { ! 2581: mach_port_t dest_name; ! 2582: ! 2583: /* receiving a reply message */ ! 2584: ! 2585: ip_lock(dest); ! 2586: if (!ip_active(dest)) { ! 2587: ip_unlock(dest); ! 2588: break; ! 2589: } ! 2590: ! 2591: /* optimized ipc_object_copyout_dest */ ! 2592: ! 2593: assert(dest->ip_sorights > 0); ! 2594: ! 2595: if (dest->ip_receiver == space) { ! 2596: ip_release(dest); ! 2597: dest->ip_sorights--; ! 2598: dest_name = dest->ip_receiver_name; ! 2599: ip_unlock(dest); ! 2600: } else { ! 2601: ip_unlock(dest); ! 2602: ! 2603: ipc_notify_send_once(dest); ! 2604: dest_name = MACH_PORT_NULL; ! 2605: } ! 2606: ! 2607: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 2608: MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE)); ! 2609: msg->msgh_local_port = dest_name; ! 2610: msg->msgh_remote_port = MACH_PORT_NULL; ! 2611: return MACH_MSG_SUCCESS; ! 2612: } ! 2613: ! 2614: default: ! 2615: /* don't bother optimizing */ ! 2616: break; ! 2617: } ! 2618: ! 2619: { ! 2620: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 2621: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 2622: ipc_port_t reply = (ipc_port_t) msg->msgh_local_port; ! 2623: mach_port_t dest_name, reply_name; ! 2624: ! 2625: if (IP_VALID(reply)) { ! 2626: ipc_port_t notify_port; ! 2627: ipc_entry_t entry; ! 2628: kern_return_t kr; ! 2629: ! 2630: /* ! 2631: * Handling notify (for MACH_RCV_NOTIFY) is tricky. ! 2632: * The problem is atomically making a send-once right ! 2633: * from the notify port and installing it for a ! 2634: * dead-name request in the new entry, because this ! 2635: * requires two port locks (on the notify port and ! 2636: * the reply port). However, we can safely make ! 2637: * and consume send-once rights for the notify port ! 2638: * as long as we hold the space locked. This isn't ! 2639: * an atomicity problem, because the only way ! 2640: * to detect that a send-once right has been created ! 2641: * and then consumed if it wasn't needed is by getting ! 2642: * at the receive right to look at ip_sorights, and ! 2643: * because the space is write-locked status calls can't ! 2644: * lookup the notify port receive right. When we make ! 2645: * the send-once right, we lock the notify port, ! 2646: * so any status calls in progress will be done. ! 2647: */ ! 2648: ! 2649: is_write_lock(space); ! 2650: ! 2651: for (;;) { ! 2652: ipc_port_request_index_t request; ! 2653: ! 2654: if (!space->is_active) { ! 2655: is_write_unlock(space); ! 2656: return (MACH_RCV_HEADER_ERROR| ! 2657: MACH_MSG_IPC_SPACE); ! 2658: } ! 2659: ! 2660: if (notify != MACH_PORT_NULL) { ! 2661: notify_port = ipc_port_lookup_notify(space, ! 2662: notify); ! 2663: if (notify_port == IP_NULL) { ! 2664: is_write_unlock(space); ! 2665: return MACH_RCV_INVALID_NOTIFY; ! 2666: } ! 2667: } else ! 2668: notify_port = IP_NULL; ! 2669: ! 2670: if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) && ! 2671: ipc_right_reverse(space, (ipc_object_t) reply, ! 2672: &reply_name, &entry)) { ! 2673: /* reply port is locked and active */ ! 2674: ! 2675: /* ! 2676: * We don't need the notify_port ! 2677: * send-once right, but we can't release ! 2678: * it here because reply port is locked. ! 2679: * Wait until after the copyout to ! 2680: * release the notify port right. ! 2681: */ ! 2682: ! 2683: assert(entry->ie_bits & ! 2684: MACH_PORT_TYPE_SEND_RECEIVE); ! 2685: break; ! 2686: } ! 2687: ! 2688: ip_lock(reply); ! 2689: if (!ip_active(reply)) { ! 2690: ip_release(reply); ! 2691: ip_check_unlock(reply); ! 2692: ! 2693: if (notify_port != IP_NULL) ! 2694: ipc_port_release_sonce(notify_port); ! 2695: ! 2696: ip_lock(dest); ! 2697: is_write_unlock(space); ! 2698: ! 2699: reply = IP_DEAD; ! 2700: reply_name = MACH_PORT_DEAD; ! 2701: goto copyout_dest; ! 2702: } ! 2703: ! 2704: kr = ipc_entry_get(space, &reply_name, &entry); ! 2705: if (kr != KERN_SUCCESS) { ! 2706: ip_unlock(reply); ! 2707: ! 2708: if (notify_port != IP_NULL) ! 2709: ipc_port_release_sonce(notify_port); ! 2710: ! 2711: /* space is locked */ ! 2712: kr = ipc_entry_grow_table(space, ! 2713: ITS_SIZE_NONE); ! 2714: if (kr != KERN_SUCCESS) { ! 2715: /* space is unlocked */ ! 2716: ! 2717: if (kr == KERN_RESOURCE_SHORTAGE) ! 2718: return (MACH_RCV_HEADER_ERROR| ! 2719: MACH_MSG_IPC_KERNEL); ! 2720: else ! 2721: return (MACH_RCV_HEADER_ERROR| ! 2722: MACH_MSG_IPC_SPACE); ! 2723: } ! 2724: /* space is locked again; start over */ ! 2725: ! 2726: continue; ! 2727: } ! 2728: ! 2729: assert(IE_BITS_TYPE(entry->ie_bits) ! 2730: == MACH_PORT_TYPE_NONE); ! 2731: assert(entry->ie_object == IO_NULL); ! 2732: ! 2733: if (notify_port == IP_NULL) { ! 2734: /* not making a dead-name request */ ! 2735: ! 2736: entry->ie_object = (ipc_object_t) reply; ! 2737: break; ! 2738: } ! 2739: ! 2740: kr = ipc_port_dnrequest(reply, reply_name, ! 2741: notify_port, &request); ! 2742: if (kr != KERN_SUCCESS) { ! 2743: ip_unlock(reply); ! 2744: ! 2745: ipc_port_release_sonce(notify_port); ! 2746: ! 2747: ipc_entry_dealloc(space, reply_name, entry); ! 2748: is_write_unlock(space); ! 2749: ! 2750: ip_lock(reply); ! 2751: if (!ip_active(reply)) { ! 2752: /* will fail next time around loop */ ! 2753: ! 2754: ip_unlock(reply); ! 2755: is_write_lock(space); ! 2756: continue; ! 2757: } ! 2758: ! 2759: kr = ipc_port_dngrow(reply, ITS_SIZE_NONE); ! 2760: /* port is unlocked */ ! 2761: if (kr != KERN_SUCCESS) ! 2762: return (MACH_RCV_HEADER_ERROR| ! 2763: MACH_MSG_IPC_KERNEL); ! 2764: ! 2765: is_write_lock(space); ! 2766: continue; ! 2767: } ! 2768: ! 2769: notify_port = IP_NULL; /* don't release right below */ ! 2770: ! 2771: entry->ie_object = (ipc_object_t) reply; ! 2772: entry->ie_request = request; ! 2773: break; ! 2774: } ! 2775: ! 2776: /* space and reply port are locked and active */ ! 2777: ! 2778: ip_reference(reply); /* hold onto the reply port */ ! 2779: ! 2780: kr = ipc_right_copyout(space, reply_name, entry, ! 2781: reply_type, TRUE, (ipc_object_t) reply); ! 2782: /* reply port is unlocked */ ! 2783: assert(kr == KERN_SUCCESS); ! 2784: ! 2785: if (notify_port != IP_NULL) ! 2786: ipc_port_release_sonce(notify_port); ! 2787: ! 2788: ip_lock(dest); ! 2789: is_write_unlock(space); ! 2790: } else { ! 2791: /* ! 2792: * No reply port! This is an easy case. ! 2793: * We only need to have the space locked ! 2794: * when checking notify and when locking ! 2795: * the destination (to ensure atomicity). ! 2796: */ ! 2797: ! 2798: is_read_lock(space); ! 2799: if (!space->is_active) { ! 2800: is_read_unlock(space); ! 2801: return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE; ! 2802: } ! 2803: ! 2804: if (notify != MACH_PORT_NULL) { ! 2805: ipc_entry_t entry; ! 2806: ! 2807: /* must check notify even though it won't be used */ ! 2808: ! 2809: if (((entry = ipc_entry_lookup(space, notify)) ! 2810: == IE_NULL) || ! 2811: ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) { ! 2812: is_read_unlock(space); ! 2813: return MACH_RCV_INVALID_NOTIFY; ! 2814: } ! 2815: } ! 2816: ! 2817: ip_lock(dest); ! 2818: is_read_unlock(space); ! 2819: ! 2820: reply_name = (mach_port_t) reply; ! 2821: } ! 2822: ! 2823: /* ! 2824: * At this point, the space is unlocked and the destination ! 2825: * port is locked. (Lock taken while space was locked.) ! 2826: * reply_name is taken care of; we still need dest_name. ! 2827: * We still hold a ref for reply (if it is valid). ! 2828: * ! 2829: * If the space holds receive rights for the destination, ! 2830: * we return its name for the right. Otherwise the task ! 2831: * managed to destroy or give away the receive right between ! 2832: * receiving the message and this copyout. If the destination ! 2833: * is dead, return MACH_PORT_DEAD, and if the receive right ! 2834: * exists somewhere else (another space, in transit) ! 2835: * return MACH_PORT_NULL. ! 2836: * ! 2837: * Making this copyout operation atomic with the previous ! 2838: * copyout of the reply port is a bit tricky. If there was ! 2839: * no real reply port (it wasn't IP_VALID) then this isn't ! 2840: * an issue. If the reply port was dead at copyout time, ! 2841: * then we are OK, because if dest is dead we serialize ! 2842: * after the death of both ports and if dest is alive ! 2843: * we serialize after reply died but before dest's (later) death. ! 2844: * So assume reply was alive when we copied it out. If dest ! 2845: * is alive, then we are OK because we serialize before ! 2846: * the ports' deaths. So assume dest is dead when we look at it. ! 2847: * If reply dies/died after dest, then we are OK because ! 2848: * we serialize after dest died but before reply dies. ! 2849: * So the hard case is when reply is alive at copyout, ! 2850: * dest is dead at copyout, and reply died before dest died. ! 2851: * In this case pretend that dest is still alive, so ! 2852: * we serialize while both ports are alive. ! 2853: * ! 2854: * Because the space lock is held across the copyout of reply ! 2855: * and locking dest, the receive right for dest can't move ! 2856: * in or out of the space while the copyouts happen, so ! 2857: * that isn't an atomicity problem. In the last hard case ! 2858: * above, this implies that when dest is dead that the ! 2859: * space couldn't have had receive rights for dest at ! 2860: * the time reply was copied-out, so when we pretend ! 2861: * that dest is still alive, we can return MACH_PORT_NULL. ! 2862: * ! 2863: * If dest == reply, then we have to make it look like ! 2864: * either both copyouts happened before the port died, ! 2865: * or both happened after the port died. This special ! 2866: * case works naturally if the timestamp comparison ! 2867: * is done correctly. ! 2868: */ ! 2869: ! 2870: copyout_dest: ! 2871: ! 2872: if (ip_active(dest)) { ! 2873: ipc_object_copyout_dest(space, (ipc_object_t) dest, ! 2874: dest_type, &dest_name); ! 2875: /* dest is unlocked */ ! 2876: } else { ! 2877: ipc_port_timestamp_t timestamp; ! 2878: ! 2879: timestamp = dest->ip_timestamp; ! 2880: ip_release(dest); ! 2881: ip_check_unlock(dest); ! 2882: ! 2883: if (IP_VALID(reply)) { ! 2884: ip_lock(reply); ! 2885: if (ip_active(reply) || ! 2886: IP_TIMESTAMP_ORDER(timestamp, ! 2887: reply->ip_timestamp)) ! 2888: dest_name = MACH_PORT_DEAD; ! 2889: else ! 2890: dest_name = MACH_PORT_NULL; ! 2891: ip_unlock(reply); ! 2892: } else ! 2893: dest_name = MACH_PORT_DEAD; ! 2894: } ! 2895: ! 2896: if (IP_VALID(reply)) ! 2897: ipc_port_release(reply); ! 2898: ! 2899: msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 2900: MACH_MSGH_BITS(reply_type, dest_type)); ! 2901: msg->msgh_local_port = dest_name; ! 2902: msg->msgh_remote_port = reply_name; ! 2903: } ! 2904: ! 2905: return MACH_MSG_SUCCESS; ! 2906: } ! 2907: ! 2908: /* ! 2909: * Routine: ipc_kmsg_copyout_object ! 2910: * Purpose: ! 2911: * Copy-out a port right. Always returns a name, ! 2912: * even for unsuccessful return codes. Always ! 2913: * consumes the supplied object. ! 2914: * Conditions: ! 2915: * Nothing locked. ! 2916: * Returns: ! 2917: * MACH_MSG_SUCCESS The space acquired the right ! 2918: * (name is valid) or the object is dead (MACH_PORT_DEAD). ! 2919: * MACH_MSG_IPC_SPACE No room in space for the right, ! 2920: * or the space is dead. (Name is MACH_PORT_NULL.) ! 2921: * MACH_MSG_IPC_KERNEL Kernel resource shortage. ! 2922: * (Name is MACH_PORT_NULL.) ! 2923: */ ! 2924: ! 2925: mach_msg_return_t ! 2926: ipc_kmsg_copyout_object( ! 2927: ipc_space_t space, ! 2928: ipc_object_t object, ! 2929: mach_msg_type_name_t msgt_name, ! 2930: mach_port_t *namep) ! 2931: { ! 2932: if (!IO_VALID(object)) { ! 2933: *namep = (mach_port_t) object; ! 2934: return MACH_MSG_SUCCESS; ! 2935: } ! 2936: ! 2937: /* ! 2938: * Attempt quick copyout of send rights. We optimize for a ! 2939: * live port for which the receiver holds send (and not ! 2940: * receive) rights in his local table. ! 2941: */ ! 2942: ! 2943: if (msgt_name != MACH_MSG_TYPE_PORT_SEND) ! 2944: goto slow_copyout; ! 2945: ! 2946: { ! 2947: register ipc_port_t port = (ipc_port_t) object; ! 2948: ipc_entry_t entry; ! 2949: ! 2950: is_write_lock(space); ! 2951: if (!space->is_active) { ! 2952: is_write_unlock(space); ! 2953: goto slow_copyout; ! 2954: } ! 2955: ! 2956: ip_lock(port); ! 2957: if (!ip_active(port) || ! 2958: !ipc_hash_local_lookup(space, (ipc_object_t) port, ! 2959: namep, &entry)) { ! 2960: ip_unlock(port); ! 2961: is_write_unlock(space); ! 2962: goto slow_copyout; ! 2963: } ! 2964: ! 2965: /* ! 2966: * Copyout the send right, incrementing urefs ! 2967: * unless it would overflow, and consume the right. ! 2968: */ ! 2969: ! 2970: assert(port->ip_srights > 1); ! 2971: port->ip_srights--; ! 2972: ip_release(port); ! 2973: ip_unlock(port); ! 2974: ! 2975: assert(entry->ie_bits & MACH_PORT_TYPE_SEND); ! 2976: assert(IE_BITS_UREFS(entry->ie_bits) > 0); ! 2977: assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX); ! 2978: ! 2979: { ! 2980: register ipc_entry_bits_t bits = entry->ie_bits + 1; ! 2981: ! 2982: if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX) ! 2983: entry->ie_bits = bits; ! 2984: } ! 2985: ! 2986: is_write_unlock(space); ! 2987: return MACH_MSG_SUCCESS; ! 2988: } ! 2989: ! 2990: slow_copyout: { ! 2991: kern_return_t kr; ! 2992: ! 2993: kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep); ! 2994: if (kr != KERN_SUCCESS) { ! 2995: ipc_object_destroy(object, msgt_name); ! 2996: ! 2997: if (kr == KERN_INVALID_CAPABILITY) ! 2998: *namep = MACH_PORT_DEAD; ! 2999: else { ! 3000: *namep = MACH_PORT_NULL; ! 3001: ! 3002: if (kr == KERN_RESOURCE_SHORTAGE) ! 3003: return MACH_MSG_IPC_KERNEL; ! 3004: else ! 3005: return MACH_MSG_IPC_SPACE; ! 3006: } ! 3007: } ! 3008: ! 3009: return MACH_MSG_SUCCESS; ! 3010: } ! 3011: } ! 3012: ! 3013: #define SKIP_PORT_DESCRIPTORS(s, e) \ ! 3014: MACRO_BEGIN \ ! 3015: if ((s) != MACH_MSG_DESCRIPTOR_NULL) { \ ! 3016: while ((s) < (e)) { \ ! 3017: if ((s)->type.type != MACH_MSG_PORT_DESCRIPTOR) \ ! 3018: break; \ ! 3019: (s)++; \ ! 3020: } \ ! 3021: if ((s) >= (e)) \ ! 3022: (s) = MACH_MSG_DESCRIPTOR_NULL; \ ! 3023: } \ ! 3024: MACRO_END ! 3025: ! 3026: #define INCREMENT_SCATTER(s) \ ! 3027: MACRO_BEGIN \ ! 3028: if ((s) != MACH_MSG_DESCRIPTOR_NULL) { \ ! 3029: (s)++; \ ! 3030: } \ ! 3031: MACRO_END ! 3032: ! 3033: /* ! 3034: * Routine: ipc_kmsg_copyout_body ! 3035: * Purpose: ! 3036: * "Copy-out" port rights and out-of-line memory ! 3037: * in the body of a message. ! 3038: * ! 3039: * The error codes are a combination of special bits. ! 3040: * The copyout proceeds despite errors. ! 3041: * Conditions: ! 3042: * Nothing locked. ! 3043: * Returns: ! 3044: * MACH_MSG_SUCCESS Successfull copyout. ! 3045: * MACH_MSG_IPC_SPACE No room for port right in name space. ! 3046: * MACH_MSG_VM_SPACE No room for memory in address space. ! 3047: * MACH_MSG_IPC_KERNEL Resource shortage handling port right. ! 3048: * MACH_MSG_VM_KERNEL Resource shortage handling memory. ! 3049: */ ! 3050: ! 3051: mach_msg_return_t ! 3052: ipc_kmsg_copyout_body( ! 3053: ipc_kmsg_t kmsg, ! 3054: ipc_space_t space, ! 3055: vm_map_t map, ! 3056: ipc_kmsg_t list) ! 3057: { ! 3058: mach_msg_body_t *body; ! 3059: mach_msg_descriptor_t *saddr, *eaddr; ! 3060: mach_msg_return_t mr = MACH_MSG_SUCCESS; ! 3061: kern_return_t kr; ! 3062: vm_offset_t data; ! 3063: mach_msg_descriptor_t *sstart, *send; ! 3064: ! 3065: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 3066: saddr = (mach_msg_descriptor_t *) (body + 1); ! 3067: eaddr = saddr + body->msgh_descriptor_count; ! 3068: ! 3069: /* ! 3070: * Do scatter list setup ! 3071: */ ! 3072: if (list != IKM_NULL) { ! 3073: mach_msg_body_t *sbody = ! 3074: (mach_msg_body_t *)(&list->ikm_header + 1); ! 3075: ! 3076: sstart = (mach_msg_descriptor_t *) (sbody + 1); ! 3077: send = sstart + sbody->msgh_descriptor_count; ! 3078: } ! 3079: else ! 3080: sstart = MACH_MSG_DESCRIPTOR_NULL; ! 3081: ! 3082: for ( ; saddr < eaddr; saddr++ ) { ! 3083: ! 3084: switch (saddr->type.type) { ! 3085: ! 3086: case MACH_MSG_PORT_DESCRIPTOR: { ! 3087: mach_msg_port_descriptor_t *dsc; ! 3088: ! 3089: /* ! 3090: * Copyout port right carried in the message ! 3091: */ ! 3092: dsc = &saddr->port; ! 3093: mr |= ipc_kmsg_copyout_object(space, ! 3094: (ipc_object_t) dsc->name, ! 3095: dsc->disposition, ! 3096: (mach_port_t *) &dsc->name); ! 3097: ! 3098: break; ! 3099: } ! 3100: case MACH_MSG_OOL_DESCRIPTOR : { ! 3101: vm_offset_t rcv_addr; ! 3102: vm_offset_t snd_addr; ! 3103: mach_msg_ool_descriptor_t *dsc; ! 3104: mach_msg_copy_options_t copy_option; ! 3105: ! 3106: SKIP_PORT_DESCRIPTORS(sstart, send); ! 3107: ! 3108: dsc = &saddr->out_of_line; ! 3109: ! 3110: assert(dsc->copy != MACH_MSG_KALLOC_COPY_T); ! 3111: assert(dsc->copy != MACH_MSG_PAGE_LIST_COPY_T); ! 3112: ! 3113: copy_option = dsc->copy; ! 3114: ! 3115: if ((snd_addr = (vm_offset_t) dsc->address) != 0) { ! 3116: if (sstart != MACH_MSG_DESCRIPTOR_NULL && ! 3117: sstart->out_of_line.copy == MACH_MSG_OVERWRITE) { ! 3118: ! 3119: /* ! 3120: * There is an overwrite descriptor specified in the ! 3121: * scatter list for this ool data. The descriptor ! 3122: * has already been verified ! 3123: */ ! 3124: rcv_addr = (vm_offset_t) sstart->out_of_line.address; ! 3125: dsc->copy = MACH_MSG_OVERWRITE; ! 3126: } else { ! 3127: dsc->copy = MACH_MSG_ALLOCATE; ! 3128: } ! 3129: ! 3130: #if MACH_OLD_VM_COPY ! 3131: if (dsc->copy == MACH_MSG_OVERWRITE) { ! 3132: kr = vm_map_copy( ! 3133: map, ipc_soft_map, ! 3134: rcv_addr, dsc->size, snd_addr, ! 3135: FALSE, FALSE); ! 3136: } ! 3137: else { ! 3138: kr = vm_move( ! 3139: ipc_soft_map, snd_addr, ! 3140: map, dsc->size, FALSE, &rcv_addr); ! 3141: } ! 3142: (void) vm_deallocate(ipc_soft_map, snd_addr, dsc->size); ! 3143: if (kr != KERN_SUCCESS) { ! 3144: if (kr == KERN_RESOURCE_SHORTAGE) ! 3145: mr |= MACH_MSG_VM_KERNEL; ! 3146: else ! 3147: mr |= MACH_MSG_VM_SPACE; ! 3148: dsc->address = 0; ! 3149: INCREMENT_SCATTER(sstart); ! 3150: break; ! 3151: } ! 3152: #else ! 3153: if (copy_option == MACH_MSG_PHYSICAL_COPY && ! 3154: dsc->size <= MSG_OOL_SIZE_SMALL(rt)) { ! 3155: ! 3156: /* ! 3157: * Sufficiently 'small' data was copied into a kalloc'ed ! 3158: * buffer copy was requested. Just copy it out and ! 3159: * free the buffer. ! 3160: */ ! 3161: if (dsc->copy == MACH_MSG_ALLOCATE) { ! 3162: ! 3163: /* ! 3164: * If there is no overwrite region, allocate ! 3165: * space in receiver's address space for the ! 3166: * data ! 3167: */ ! 3168: if ((kr = vm_allocate(map, &rcv_addr, dsc->size, ! 3169: TRUE)) != KERN_SUCCESS) { ! 3170: if (kr == KERN_RESOURCE_SHORTAGE) ! 3171: mr |= MACH_MSG_VM_KERNEL; ! 3172: else ! 3173: mr |= MACH_MSG_VM_SPACE; ! 3174: kfree(snd_addr, dsc->size); ! 3175: dsc->address = (void *) 0; ! 3176: INCREMENT_SCATTER(sstart); ! 3177: break; ! 3178: } ! 3179: } ! 3180: (void) copyoutmap(map, snd_addr, rcv_addr, dsc->size); ! 3181: kfree(snd_addr, dsc->size); ! 3182: } else { ! 3183: ! 3184: /* ! 3185: * Whether the data was virtually or physically ! 3186: * copied we have a vm_map_copy_t for it. ! 3187: * If there's an overwrite region specified ! 3188: * overwrite it, otherwise do a virtual copy out. ! 3189: */ ! 3190: if (dsc->copy == MACH_MSG_OVERWRITE) { ! 3191: kr = vm_map_copy_overwrite(map, rcv_addr, ! 3192: (vm_map_copy_t) dsc->address, TRUE); ! 3193: } else { ! 3194: kr = vm_map_copyout(map, &rcv_addr, ! 3195: (vm_map_copy_t) dsc->address); ! 3196: } ! 3197: if (kr != KERN_SUCCESS) { ! 3198: if (kr == KERN_RESOURCE_SHORTAGE) ! 3199: mr |= MACH_MSG_VM_KERNEL; ! 3200: else ! 3201: mr |= MACH_MSG_VM_SPACE; ! 3202: vm_map_copy_discard((vm_map_copy_t) dsc->address); ! 3203: dsc->address = 0; ! 3204: INCREMENT_SCATTER(sstart); ! 3205: break; ! 3206: } ! 3207: } ! 3208: #endif ! 3209: dsc->address = (void *) rcv_addr; ! 3210: } ! 3211: INCREMENT_SCATTER(sstart); ! 3212: break; ! 3213: } ! 3214: case MACH_MSG_OOL_PORTS_DESCRIPTOR : { ! 3215: vm_offset_t addr; ! 3216: mach_port_t *objects; ! 3217: mach_msg_type_number_t j; ! 3218: vm_size_t length; ! 3219: mach_msg_ool_ports_descriptor_t *dsc; ! 3220: ! 3221: SKIP_PORT_DESCRIPTORS(sstart, send); ! 3222: ! 3223: dsc = &saddr->ool_ports; ! 3224: ! 3225: length = dsc->count * sizeof(mach_port_t); ! 3226: ! 3227: if (length != 0) { ! 3228: if (sstart != MACH_MSG_DESCRIPTOR_NULL && ! 3229: sstart->ool_ports.copy == MACH_MSG_OVERWRITE) { ! 3230: ! 3231: /* ! 3232: * There is an overwrite descriptor specified in the ! 3233: * scatter list for this ool data. The descriptor ! 3234: * has already been verified ! 3235: */ ! 3236: addr = (vm_offset_t) sstart->out_of_line.address; ! 3237: dsc->copy = MACH_MSG_OVERWRITE; ! 3238: } ! 3239: else { ! 3240: ! 3241: /* ! 3242: * Dynamically allocate the region ! 3243: */ ! 3244: dsc->copy = MACH_MSG_ALLOCATE; ! 3245: if ((kr = vm_allocate(map, &addr, length, TRUE)) != ! 3246: KERN_SUCCESS) { ! 3247: ipc_kmsg_clean_body(kmsg, ! 3248: body->msgh_descriptor_count); ! 3249: dsc->address = 0; ! 3250: ! 3251: if (kr == KERN_RESOURCE_SHORTAGE){ ! 3252: mr |= MACH_MSG_VM_KERNEL; ! 3253: } else { ! 3254: mr |= MACH_MSG_VM_SPACE; ! 3255: } ! 3256: INCREMENT_SCATTER(sstart); ! 3257: break; ! 3258: } ! 3259: } ! 3260: } else { ! 3261: assert(dsc->address == 0); ! 3262: INCREMENT_SCATTER(sstart); ! 3263: break; ! 3264: } ! 3265: ! 3266: ! 3267: objects = (mach_port_t *) dsc->address ; ! 3268: ! 3269: /* copyout port rights carried in the message */ ! 3270: ! 3271: for ( j = 0; j < dsc->count ; j++) { ! 3272: ipc_object_t object = ! 3273: (ipc_object_t) objects[j]; ! 3274: ! 3275: mr |= ipc_kmsg_copyout_object(space, object, ! 3276: dsc->disposition, &objects[j]); ! 3277: } ! 3278: ! 3279: /* copyout to memory allocated above */ ! 3280: ! 3281: data = (vm_offset_t) dsc->address; ! 3282: (void) copyoutmap(map, data, addr, length); ! 3283: kfree(data, length); ! 3284: ! 3285: dsc->address = (void *) addr; ! 3286: INCREMENT_SCATTER(sstart); ! 3287: break; ! 3288: } ! 3289: default : { ! 3290: panic("ipc_kmsg_copyout_body: bad descriptor type %d", ! 3291: saddr->type.type); ! 3292: } ! 3293: } ! 3294: } ! 3295: return mr; ! 3296: } ! 3297: ! 3298: /* ! 3299: * Routine: ipc_kmsg_copyout ! 3300: * Purpose: ! 3301: * "Copy-out" port rights and out-of-line memory ! 3302: * in the message. ! 3303: * Conditions: ! 3304: * Nothing locked. ! 3305: * Returns: ! 3306: * MACH_MSG_SUCCESS Copied out all rights and memory. ! 3307: * MACH_RCV_INVALID_NOTIFY Bad notify port. ! 3308: * Rights and memory in the message are intact. ! 3309: * MACH_RCV_HEADER_ERROR + special bits ! 3310: * Rights and memory in the message are intact. ! 3311: * MACH_RCV_BODY_ERROR + special bits ! 3312: * The message header was successfully copied out. ! 3313: * As much of the body was handled as possible. ! 3314: */ ! 3315: ! 3316: mach_msg_return_t ! 3317: ipc_kmsg_copyout( ! 3318: ipc_kmsg_t kmsg, ! 3319: ipc_space_t space, ! 3320: vm_map_t map, ! 3321: mach_port_t notify, ! 3322: ipc_kmsg_t list) ! 3323: { ! 3324: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 3325: mach_msg_return_t mr; ! 3326: ! 3327: mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify); ! 3328: if (mr != MACH_MSG_SUCCESS) ! 3329: return mr; ! 3330: ! 3331: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 3332: mr = ipc_kmsg_copyout_body(kmsg, space, map, list); ! 3333: ! 3334: if (mr != MACH_MSG_SUCCESS) ! 3335: mr |= MACH_RCV_BODY_ERROR; ! 3336: } ! 3337: ! 3338: return mr; ! 3339: } ! 3340: ! 3341: /* ! 3342: * Routine: ipc_kmsg_copyout_pseudo ! 3343: * Purpose: ! 3344: * Does a pseudo-copyout of the message. ! 3345: * This is like a regular copyout, except ! 3346: * that the ports in the header are handled ! 3347: * as if they are in the body. They aren't reversed. ! 3348: * ! 3349: * The error codes are a combination of special bits. ! 3350: * The copyout proceeds despite errors. ! 3351: * Conditions: ! 3352: * Nothing locked. ! 3353: * Returns: ! 3354: * MACH_MSG_SUCCESS Successful copyout. ! 3355: * MACH_MSG_IPC_SPACE No room for port right in name space. ! 3356: * MACH_MSG_VM_SPACE No room for memory in address space. ! 3357: * MACH_MSG_IPC_KERNEL Resource shortage handling port right. ! 3358: * MACH_MSG_VM_KERNEL Resource shortage handling memory. ! 3359: */ ! 3360: ! 3361: mach_msg_return_t ! 3362: ipc_kmsg_copyout_pseudo( ! 3363: ipc_kmsg_t kmsg, ! 3364: ipc_space_t space, ! 3365: vm_map_t map, ! 3366: ipc_kmsg_t list) ! 3367: { ! 3368: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 3369: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 3370: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 3371: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 3372: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 3373: mach_port_t dest_name, reply_name; ! 3374: mach_msg_return_t mr; ! 3375: ! 3376: assert(IO_VALID(dest)); ! 3377: ! 3378: mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) | ! 3379: ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name)); ! 3380: ! 3381: kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR; ! 3382: kmsg->ikm_header.msgh_remote_port = dest_name; ! 3383: kmsg->ikm_header.msgh_local_port = reply_name; ! 3384: ! 3385: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 3386: mr |= ipc_kmsg_copyout_body(kmsg, space, map, list); ! 3387: } ! 3388: ! 3389: return mr; ! 3390: } ! 3391: ! 3392: /* ! 3393: * Routine: ipc_kmsg_copyout_dest ! 3394: * Purpose: ! 3395: * Copies out the destination port in the message. ! 3396: * Destroys all other rights and memory in the message. ! 3397: * Conditions: ! 3398: * Nothing locked. ! 3399: */ ! 3400: ! 3401: void ! 3402: ipc_kmsg_copyout_dest( ! 3403: ipc_kmsg_t kmsg, ! 3404: ipc_space_t space) ! 3405: { ! 3406: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 3407: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 3408: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 3409: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 3410: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 3411: mach_port_t dest_name, reply_name; ! 3412: ! 3413: assert(IO_VALID(dest)); ! 3414: ! 3415: io_lock(dest); ! 3416: if (io_active(dest)) { ! 3417: ipc_object_copyout_dest(space, dest, dest_type, &dest_name); ! 3418: /* dest is unlocked */ ! 3419: } else { ! 3420: io_release(dest); ! 3421: io_check_unlock(dest); ! 3422: dest_name = MACH_PORT_DEAD; ! 3423: } ! 3424: ! 3425: if (IO_VALID(reply)) { ! 3426: ipc_object_destroy(reply, reply_type); ! 3427: reply_name = MACH_PORT_NULL; ! 3428: } else ! 3429: reply_name = (mach_port_t) reply; ! 3430: ! 3431: kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 3432: MACH_MSGH_BITS(reply_type, dest_type)); ! 3433: kmsg->ikm_header.msgh_local_port = dest_name; ! 3434: kmsg->ikm_header.msgh_remote_port = reply_name; ! 3435: ! 3436: if (mbits & MACH_MSGH_BITS_COMPLEX) { ! 3437: if (mbits & MACH_MSGH_BITS_OLD_FORMAT) { ! 3438: vm_offset_t saddr, eaddr; ! 3439: ! 3440: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 3441: eaddr = (vm_offset_t) &kmsg->ikm_header + ! 3442: kmsg->ikm_header.msgh_size; ! 3443: ! 3444: ipc_kmsg_clean_body_compat(saddr, eaddr); ! 3445: } ! 3446: else { ! 3447: mach_msg_body_t *body; ! 3448: ! 3449: body = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 3450: ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count); ! 3451: } ! 3452: } ! 3453: } ! 3454: ! 3455: /* ! 3456: * Routine: ipc_kmsg_check_scatter ! 3457: * Purpose: ! 3458: * Checks scatter and gather lists for consistency. ! 3459: * ! 3460: * Algorithm: ! 3461: * The gather is assumed valid since it has been copied in. ! 3462: * The scatter list has only been range checked. ! 3463: * Gather list descriptors are sequentially paired with scatter ! 3464: * list descriptors, with port descriptors in either list ignored. ! 3465: * Descriptors are consistent if the type fileds match and size ! 3466: * of the scatter descriptor is less than or equal to the ! 3467: * size of the gather descriptor. A MACH_MSG_ALLOCATE copy ! 3468: * strategy in a scatter descriptor matches any size in the ! 3469: * corresponding gather descriptor assuming they are the same type. ! 3470: * Either list may be larger than the other. During the ! 3471: * subsequent copy out, excess scatter descriptors are ignored ! 3472: * and excess gather descriptors default to dynamic allocation. ! 3473: * ! 3474: * In the case of a size error, a new scatter list is formed ! 3475: * from the gather list copying only the size and type fields. ! 3476: * ! 3477: * Conditions: ! 3478: * Nothing locked. ! 3479: * Returns: ! 3480: * MACH_MSG_SUCCESS Lists are consistent ! 3481: * MACH_RCV_INVALID_TYPE Scatter type does not match ! 3482: * gather type ! 3483: * MACH_RCV_SCATTER_SMALL Scatter size less than gather ! 3484: * size ! 3485: */ ! 3486: ! 3487: mach_msg_return_t ! 3488: ipc_kmsg_check_scatter( ! 3489: ipc_kmsg_t kmsg, ! 3490: mach_msg_option_t option, ! 3491: ipc_kmsg_t *list) ! 3492: { ! 3493: mach_msg_body_t *gbody, *sbody; ! 3494: mach_msg_descriptor_t *gstart, *gend; ! 3495: mach_msg_descriptor_t *sstart, *send; ! 3496: boolean_t size_error = FALSE; ! 3497: ! 3498: assert(*list != IKM_NULL); ! 3499: ! 3500: gbody = (mach_msg_body_t *) (&kmsg->ikm_header + 1); ! 3501: gstart = (mach_msg_descriptor_t *) (gbody + 1); ! 3502: gend = gstart + gbody->msgh_descriptor_count; ! 3503: ! 3504: sbody = (mach_msg_body_t *) (&(*list)->ikm_header + 1); ! 3505: sstart = (mach_msg_descriptor_t *) (sbody + 1); ! 3506: send = sstart + sbody->msgh_descriptor_count; ! 3507: ! 3508: while (gstart < gend) { ! 3509: ! 3510: /* ! 3511: * Skip port descriptors in gather list. ! 3512: */ ! 3513: if (gstart->type.type != MACH_MSG_PORT_DESCRIPTOR) { ! 3514: ! 3515: /* ! 3516: * A scatter list with a 0 descriptor count is treated as an ! 3517: * automatic size mismatch. ! 3518: */ ! 3519: if (sbody->msgh_descriptor_count == 0) { ! 3520: if ((option & MACH_RCV_LARGE) == 0) ! 3521: return MACH_RCV_SCATTER_SMALL; ! 3522: size_error = TRUE; ! 3523: break; ! 3524: } ! 3525: ! 3526: /* ! 3527: * Skip port descriptors in scatter list. ! 3528: */ ! 3529: while (sstart < send) { ! 3530: if (sstart->type.type != MACH_MSG_PORT_DESCRIPTOR) ! 3531: break; ! 3532: sstart++; ! 3533: } ! 3534: ! 3535: /* ! 3536: * No more scatter descriptors, we're done ! 3537: */ ! 3538: if (sstart >= send) ! 3539: break; ! 3540: ! 3541: /* ! 3542: * Check type, copy and size fields ! 3543: */ ! 3544: if (gstart->type.type == MACH_MSG_OOL_DESCRIPTOR) { ! 3545: if (sstart->type.type != MACH_MSG_OOL_DESCRIPTOR) ! 3546: return MACH_RCV_INVALID_TYPE; ! 3547: ! 3548: if (sstart->out_of_line.copy == MACH_MSG_OVERWRITE && ! 3549: gstart->out_of_line.size > sstart->out_of_line.size) { ! 3550: if ((option & MACH_RCV_LARGE) == 0) ! 3551: return MACH_RCV_SCATTER_SMALL; ! 3552: size_error = TRUE; ! 3553: } ! 3554: } ! 3555: else { ! 3556: if (sstart->type.type != MACH_MSG_OOL_PORTS_DESCRIPTOR) ! 3557: return MACH_RCV_INVALID_TYPE; ! 3558: ! 3559: if (sstart->ool_ports.copy == MACH_MSG_OVERWRITE && ! 3560: gstart->ool_ports.count > sstart->ool_ports.count) { ! 3561: if ((option & MACH_RCV_LARGE) == 0) ! 3562: return MACH_RCV_SCATTER_SMALL; ! 3563: size_error = TRUE; ! 3564: } ! 3565: } ! 3566: sstart++; ! 3567: } ! 3568: gstart++; ! 3569: } ! 3570: ! 3571: /* ! 3572: * If there is a size error, form a new scatter list from the ! 3573: * gather list. ! 3574: */ ! 3575: if (size_error) { ! 3576: ipc_kmsg_t new_list; ! 3577: mach_msg_size_t new_size = (unsigned)gend - (unsigned)gbody; ! 3578: ! 3579: new_list = ikm_alloc(new_size); ! 3580: if (new_list == IKM_NULL) ! 3581: return MACH_MSG_VM_KERNEL|MACH_RCV_BODY_ERROR; ! 3582: ! 3583: new_list->ikm_header = (*list)->ikm_header; ! 3584: new_list->ikm_header.msgh_size = new_size; ! 3585: ! 3586: ikm_free(*list); (*list) = new_list; ! 3587: ! 3588: /* ! 3589: * Now fill in the descriptor count and the type and size ! 3590: * fields for each descriptor ! 3591: */ ! 3592: sbody = (mach_msg_body_t *)(&new_list->ikm_header + 1); ! 3593: sbody->msgh_descriptor_count = gbody->msgh_descriptor_count; ! 3594: sstart = (mach_msg_descriptor_t *) (sbody + 1); ! 3595: ! 3596: gstart = (mach_msg_descriptor_t *) (gbody + 1); ! 3597: gend = gstart + gbody->msgh_descriptor_count; ! 3598: ! 3599: for (; gstart < gend; gstart++, sstart++) { ! 3600: sstart->type.type = gstart->type.type; ! 3601: switch (gstart->type.type) { ! 3602: case MACH_MSG_PORT_DESCRIPTOR: ! 3603: break; ! 3604: case MACH_MSG_OOL_DESCRIPTOR: ! 3605: sstart->out_of_line.size = gstart->out_of_line.size; ! 3606: break; ! 3607: case MACH_MSG_OOL_PORTS_DESCRIPTOR: ! 3608: sstart->ool_ports.count = gstart->ool_ports.count; ! 3609: break; ! 3610: } ! 3611: } ! 3612: ! 3613: return MACH_RCV_SCATTER_SMALL; ! 3614: } ! 3615: ! 3616: return MACH_MSG_SUCCESS; ! 3617: } ! 3618: ! 3619: /* ! 3620: * Routine: ipc_kmsg_copyout_to_kernel ! 3621: * Purpose: ! 3622: * Copies out the destination and reply ports in the message. ! 3623: * Leaves all other rights and memory in the message alone. ! 3624: * Conditions: ! 3625: * Nothing locked. ! 3626: * ! 3627: * Derived from ipc_kmsg_copyout_dest. ! 3628: * Use by mach_msg_rpc_from_kernel (which used to use copyout_dest). ! 3629: * We really do want to save rights and memory. ! 3630: */ ! 3631: ! 3632: void ! 3633: ipc_kmsg_copyout_to_kernel( ! 3634: ipc_kmsg_t kmsg, ! 3635: ipc_space_t space) ! 3636: { ! 3637: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 3638: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 3639: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 3640: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 3641: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 3642: mach_port_t dest_name, reply_name; ! 3643: ! 3644: assert(IO_VALID(dest)); ! 3645: ! 3646: io_lock(dest); ! 3647: if (io_active(dest)) { ! 3648: ipc_object_copyout_dest(space, dest, dest_type, &dest_name); ! 3649: /* dest is unlocked */ ! 3650: } else { ! 3651: io_release(dest); ! 3652: io_check_unlock(dest); ! 3653: dest_name = MACH_PORT_DEAD; ! 3654: } ! 3655: ! 3656: reply_name = (mach_port_t) reply; ! 3657: ! 3658: kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) | ! 3659: MACH_MSGH_BITS(reply_type, dest_type)); ! 3660: kmsg->ikm_header.msgh_local_port = dest_name; ! 3661: kmsg->ikm_header.msgh_remote_port = reply_name; ! 3662: } ! 3663: ! 3664: #if MACH_IPC_COMPAT ! 3665: ! 3666: /* ! 3667: * Routine: ipc_kmsg_copyin_compat ! 3668: * Purpose: ! 3669: * "Copy-in" port rights and out-of-line memory ! 3670: * in the message. ! 3671: * ! 3672: * In all failure cases, the message is left holding ! 3673: * no rights or memory. However, the message buffer ! 3674: * is not deallocated. If successful, the message ! 3675: * contains a valid destination port. ! 3676: * Conditions: ! 3677: * Nothing locked. ! 3678: * Returns: ! 3679: * MACH_MSG_SUCCESS Successful copyin. ! 3680: * MACH_SEND_INVALID_DEST Can't copyin destination port. ! 3681: * MACH_SEND_INVALID_REPLY Can't copyin reply port. ! 3682: * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory. ! 3683: * MACH_SEND_INVALID_RIGHT Can't copyin port right in body. ! 3684: * MACH_SEND_INVALID_TYPE Bad type specification. ! 3685: * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data. ! 3686: */ ! 3687: ! 3688: mach_msg_return_t ! 3689: ipc_kmsg_copyin_compat(kmsg, space, map) ! 3690: ipc_kmsg_t kmsg; ! 3691: ipc_space_t space; ! 3692: vm_map_t map; ! 3693: { ! 3694: msg_header_t msg; ! 3695: mach_port_t dest_name; ! 3696: mach_port_t reply_name; ! 3697: ipc_object_t dest, reply; ! 3698: mach_msg_type_name_t dest_type, reply_type; ! 3699: vm_offset_t saddr, eaddr; ! 3700: boolean_t complex; ! 3701: kern_return_t kr; ! 3702: boolean_t use_page_lists, steal_pages; ! 3703: ! 3704: msg = * (msg_header_t *) &kmsg->ikm_header; ! 3705: dest_name = (mach_port_t) msg.msg_remote_port; ! 3706: reply_name = (mach_port_t) msg.msg_local_port; ! 3707: ! 3708: /* translate the destination and reply ports */ ! 3709: ! 3710: kr = ipc_object_copyin_header(space, dest_name, &dest, &dest_type); ! 3711: if (kr != KERN_SUCCESS) ! 3712: return MACH_SEND_INVALID_DEST; ! 3713: ! 3714: if (reply_name == MACH_PORT_NULL) { ! 3715: reply = IO_NULL; ! 3716: reply_type = 0; ! 3717: } else { ! 3718: kr = ipc_object_copyin_header(space, reply_name, ! 3719: &reply, &reply_type); ! 3720: if (kr != KERN_SUCCESS) { ! 3721: ipc_object_destroy(dest, dest_type); ! 3722: return MACH_SEND_INVALID_REPLY; ! 3723: } ! 3724: } ! 3725: ! 3726: kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(dest_type, reply_type) | ! 3727: MACH_MSGH_BITS_OLD_FORMAT; ! 3728: kmsg->ikm_header.msgh_size = (mach_msg_size_t) msg.msg_size; ! 3729: kmsg->ikm_header.msgh_remote_port = (mach_port_t) dest; ! 3730: kmsg->ikm_header.msgh_local_port = (mach_port_t) reply; ! 3731: kmsg->ikm_header.msgh_reserved = (mach_port_seqno_t) msg.msg_type; ! 3732: kmsg->ikm_header.msgh_id = (mach_msg_id_t) msg.msg_id; ! 3733: ! 3734: if (msg.msg_simple) ! 3735: return MACH_MSG_SUCCESS; ! 3736: ! 3737: complex = FALSE; ! 3738: use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest)); ! 3739: steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest)); ! 3740: ! 3741: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 3742: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size; ! 3743: ! 3744: while (saddr < eaddr) { ! 3745: vm_offset_t taddr = saddr; ! 3746: mach_msg_type_long_t *type; ! 3747: mach_msg_type_name_t name; ! 3748: mach_msg_type_size_t size; ! 3749: mach_msg_type_number_t number; ! 3750: boolean_t is_inline, longform, dealloc, is_port; ! 3751: vm_offset_t data; ! 3752: vm_size_t length; ! 3753: ! 3754: type = (mach_msg_type_long_t *) saddr; ! 3755: ! 3756: if (((eaddr - saddr) < sizeof(mach_msg_type_t)) || ! 3757: ((longform = ((mach_msg_type_t*)type)->msgt_longform) && ! 3758: ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) { ! 3759: ipc_kmsg_clean_partial_compat(kmsg, taddr, FALSE, 0); ! 3760: return MACH_SEND_MSG_TOO_SMALL; ! 3761: } ! 3762: ! 3763: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 3764: dealloc = ((mach_msg_type_t*)type)->msgt_deallocate; ! 3765: if (longform) { ! 3766: /* This must be aligned */ ! 3767: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 3768: (is_misaligned(type))) { ! 3769: saddr = ptr_align(saddr); ! 3770: continue; ! 3771: } ! 3772: name = type->msgtl_name; ! 3773: size = type->msgtl_size; ! 3774: number = type->msgtl_number; ! 3775: saddr += sizeof(mach_msg_type_long_t); ! 3776: } else { ! 3777: name = ((mach_msg_type_t*)type)->msgt_name; ! 3778: size = ((mach_msg_type_t*)type)->msgt_size; ! 3779: number = ((mach_msg_type_t*)type)->msgt_number; ! 3780: saddr += sizeof(mach_msg_type_t); ! 3781: } ! 3782: ! 3783: is_port = MSG_TYPE_PORT_ANY(name); ! 3784: ! 3785: if (is_port && (size != PORT_T_SIZE_IN_BITS)) { ! 3786: ipc_kmsg_clean_partial_compat(kmsg, taddr, FALSE, 0); ! 3787: return MACH_SEND_INVALID_TYPE; ! 3788: } ! 3789: ! 3790: /* ! 3791: * New IPC says these should be zero, but old IPC ! 3792: * tasks often leave them with random values. So ! 3793: * we have to clear them. ! 3794: */ ! 3795: ! 3796: ((mach_msg_type_t*)type)->msgt_unused = 0; ! 3797: if (longform) { ! 3798: type->msgtl_header.msgt_name = 0; ! 3799: type->msgtl_header.msgt_size = 0; ! 3800: type->msgtl_header.msgt_number = 0; ! 3801: } ! 3802: ! 3803: /* padding (ptrs and ports) ? */ ! 3804: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 3805: ((size >> 3) == sizeof(natural_t))) ! 3806: saddr = ptr_align(saddr); ! 3807: ! 3808: /* calculate length of data in bytes, rounding up */ ! 3809: ! 3810: length = ((number * size) + 7) >> 3; ! 3811: ! 3812: if (is_inline) { ! 3813: vm_size_t amount; ! 3814: ! 3815: /* inline data sizes round up to int boundaries */ ! 3816: ! 3817: amount = (length + 3) &~ 3; ! 3818: if ((eaddr - saddr) < amount) { ! 3819: ipc_kmsg_clean_partial_compat( ! 3820: kmsg, taddr, FALSE, 0); ! 3821: return MACH_SEND_MSG_TOO_SMALL; ! 3822: } ! 3823: ! 3824: data = saddr; ! 3825: saddr += amount; ! 3826: } else { ! 3827: vm_offset_t addr; ! 3828: ! 3829: if ((eaddr - saddr) < sizeof(vm_offset_t)) { ! 3830: ipc_kmsg_clean_partial_compat( ! 3831: kmsg, taddr, FALSE, 0); ! 3832: return MACH_SEND_MSG_TOO_SMALL; ! 3833: } ! 3834: ! 3835: /* grab the out-of-line data */ ! 3836: ! 3837: addr = * (vm_offset_t *) saddr; ! 3838: ! 3839: if (length == 0) ! 3840: data = 0; ! 3841: else if (is_port) { ! 3842: data = kalloc(length); ! 3843: if (data == 0) ! 3844: goto invalid_memory; ! 3845: ! 3846: if (copyinmap(map, (char *) addr, ! 3847: (char *) data, length) || ! 3848: (dealloc && ! 3849: (vm_deallocate(map, addr, length) != ! 3850: KERN_SUCCESS))) { ! 3851: kfree(data, length); ! 3852: goto invalid_memory; ! 3853: } ! 3854: } else { ! 3855: #if MACH_OLD_VM_COPY ! 3856: vm_offset_t copy; ! 3857: ! 3858: kr = vm_move(map, addr, ! 3859: ipc_soft_map, length, ! 3860: dealloc, ©); ! 3861: #else ! 3862: vm_map_copy_t copy; ! 3863: ! 3864: if (use_page_lists) { ! 3865: kr = vm_map_copyin_page_list(map, ! 3866: addr, length, dealloc, ! 3867: steal_pages, ©, FALSE); ! 3868: } else { ! 3869: kr = vm_map_copyin(map, addr, length, ! 3870: dealloc, ! 3871: ©); ! 3872: } ! 3873: #endif ! 3874: if (kr != KERN_SUCCESS) { ! 3875: invalid_memory: ! 3876: ipc_kmsg_clean_partial_compat( ! 3877: kmsg, taddr, FALSE, 0); ! 3878: return MACH_SEND_INVALID_MEMORY; ! 3879: } ! 3880: ! 3881: data = (vm_offset_t) copy; ! 3882: } ! 3883: ! 3884: * (vm_offset_t *) saddr = data; ! 3885: saddr += sizeof(vm_offset_t); ! 3886: complex = TRUE; ! 3887: } ! 3888: ! 3889: if (is_port) { ! 3890: mach_msg_type_name_t newname = ! 3891: ipc_object_copyin_type(name); ! 3892: ipc_object_t *objects = (ipc_object_t *) data; ! 3893: mach_msg_type_number_t i; ! 3894: ! 3895: if (longform) ! 3896: type->msgtl_name = newname; ! 3897: else ! 3898: ((mach_msg_type_t*)type)->msgt_name = newname; ! 3899: ! 3900: for (i = 0; i < number; i++) { ! 3901: mach_port_t port = (mach_port_t) objects[i]; ! 3902: ipc_object_t object; ! 3903: ! 3904: if (!MACH_PORT_VALID(port)) ! 3905: continue; ! 3906: ! 3907: kr = ipc_object_copyin_compat(space, port, ! 3908: name, dealloc, &object); ! 3909: if (kr != KERN_SUCCESS) { ! 3910: ipc_kmsg_clean_partial_compat( ! 3911: kmsg, taddr, TRUE, i); ! 3912: return MACH_SEND_INVALID_RIGHT; ! 3913: } ! 3914: ! 3915: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) && ! 3916: ipc_port_check_circularity( ! 3917: (ipc_port_t) object, ! 3918: (ipc_port_t) dest)) ! 3919: kmsg->ikm_header.msgh_bits |= ! 3920: MACH_MSGH_BITS_CIRCULAR; ! 3921: ! 3922: objects[i] = object; ! 3923: } ! 3924: ! 3925: complex = TRUE; ! 3926: } ! 3927: } ! 3928: ! 3929: if (complex) ! 3930: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX; ! 3931: ! 3932: return MACH_MSG_SUCCESS; ! 3933: } ! 3934: ! 3935: void ! 3936: ipc_kmsg_copyin_compat_from_kernel(kmsg) ! 3937: ipc_kmsg_t kmsg; ! 3938: { ! 3939: msg_header_t msg; ! 3940: ipc_object_t remote, local; ! 3941: mach_msg_type_name_t rname, lname; ! 3942: vm_offset_t saddr, eaddr; ! 3943: boolean_t complex; ! 3944: ! 3945: msg = * (msg_header_t *) &kmsg->ikm_header; ! 3946: remote = (ipc_object_t) msg.msg_remote_port; ! 3947: rname = MACH_MSG_TYPE_COPY_SEND; ! 3948: local = (ipc_object_t) msg.msg_local_port; ! 3949: lname = MACH_MSG_TYPE_MAKE_SEND; ! 3950: ! 3951: /* translate the destination and reply ports */ ! 3952: ! 3953: ipc_object_copyin_from_kernel(remote, rname); ! 3954: if (IO_VALID(local)) ! 3955: ipc_object_copyin_from_kernel(local, lname); ! 3956: ! 3957: kmsg->ikm_header.msgh_bits = ! 3958: MACH_MSGH_BITS( ! 3959: ipc_object_copyin_type(rname), ! 3960: ipc_object_copyin_type(lname)) | ! 3961: MACH_MSGH_BITS_OLD_FORMAT; ! 3962: kmsg->ikm_header.msgh_size = (mach_msg_size_t) msg.msg_size; ! 3963: kmsg->ikm_header.msgh_remote_port = (mach_port_t) remote; ! 3964: kmsg->ikm_header.msgh_local_port = (mach_port_t) local; ! 3965: kmsg->ikm_header.msgh_reserved = (mach_port_seqno_t) msg.msg_type; ! 3966: kmsg->ikm_header.msgh_id = (mach_msg_id_t) msg.msg_id; ! 3967: ! 3968: if (msg.msg_simple) ! 3969: return; ! 3970: ! 3971: complex = FALSE; ! 3972: ! 3973: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 3974: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size; ! 3975: ! 3976: while (saddr < eaddr) { ! 3977: mach_msg_type_long_t *type; ! 3978: mach_msg_type_name_t name; ! 3979: mach_msg_type_size_t size; ! 3980: mach_msg_type_number_t number; ! 3981: boolean_t is_inline, longform, is_port; ! 3982: vm_offset_t data; ! 3983: vm_size_t length; ! 3984: ! 3985: type = (mach_msg_type_long_t *) saddr; ! 3986: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 3987: longform = ((mach_msg_type_t*)type)->msgt_longform; ! 3988: /* type->msgtl_header.msgt_deallocate not used */ ! 3989: if (longform) { ! 3990: /* This must be aligned */ ! 3991: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 3992: (is_misaligned(type))) { ! 3993: saddr = ptr_align(saddr); ! 3994: continue; ! 3995: } ! 3996: name = type->msgtl_name; ! 3997: size = type->msgtl_size; ! 3998: number = type->msgtl_number; ! 3999: saddr += sizeof(mach_msg_type_long_t); ! 4000: } else { ! 4001: name = ((mach_msg_type_t*)type)->msgt_name; ! 4002: size = ((mach_msg_type_t*)type)->msgt_size; ! 4003: number = ((mach_msg_type_t*)type)->msgt_number; ! 4004: saddr += sizeof(mach_msg_type_t); ! 4005: } ! 4006: ! 4007: is_port = MSG_TYPE_PORT_ANY(name); ! 4008: ! 4009: /* ! 4010: * New IPC says these should be zero, but old IPC ! 4011: * tasks often leave them with random values. So ! 4012: * we have to clear them. ! 4013: */ ! 4014: ! 4015: ((mach_msg_type_t*)type)->msgt_unused = 0; ! 4016: if (longform) { ! 4017: type->msgtl_header.msgt_name = 0; ! 4018: type->msgtl_header.msgt_size = 0; ! 4019: type->msgtl_header.msgt_number = 0; ! 4020: } ! 4021: ! 4022: /* padding (ptrs and ports) ? */ ! 4023: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 4024: ((size >> 3) == sizeof(natural_t))) ! 4025: saddr = ptr_align(saddr); ! 4026: ! 4027: /* calculate length of data in bytes, rounding up */ ! 4028: ! 4029: length = ((number * size) + 7) >> 3; ! 4030: ! 4031: if (is_inline) { ! 4032: /* inline data sizes round up to int boundaries */ ! 4033: ! 4034: data = saddr; ! 4035: saddr += (length + 3) &~ 3; ! 4036: } else { ! 4037: /* ! 4038: * The sender should supply ready-made memory ! 4039: * for us, so we don't need to do anything. ! 4040: */ ! 4041: ! 4042: data = * (vm_offset_t *) saddr; ! 4043: saddr += sizeof(vm_offset_t); ! 4044: complex = TRUE; ! 4045: } ! 4046: ! 4047: if (is_port) { ! 4048: mach_msg_type_name_t newname = ! 4049: ipc_object_copyin_type(name); ! 4050: ipc_object_t *objects = (ipc_object_t *) data; ! 4051: mach_msg_type_number_t i; ! 4052: ! 4053: if (longform) ! 4054: type->msgtl_name = newname; ! 4055: else ! 4056: ((mach_msg_type_t*)type)->msgt_name = newname; ! 4057: ! 4058: for (i = 0; i < number; i++) { ! 4059: ipc_object_t object = objects[i]; ! 4060: ! 4061: if (!IO_VALID(object)) ! 4062: continue; ! 4063: ! 4064: ipc_object_copyin_from_kernel(object, name); ! 4065: ! 4066: if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) && ! 4067: ipc_port_check_circularity( ! 4068: (ipc_port_t) object, ! 4069: (ipc_port_t) remote)) ! 4070: kmsg->ikm_header.msgh_bits |= ! 4071: MACH_MSGH_BITS_CIRCULAR; ! 4072: } ! 4073: ! 4074: complex = TRUE; ! 4075: } ! 4076: } ! 4077: ! 4078: if (complex) ! 4079: kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX; ! 4080: } ! 4081: ! 4082: /* ! 4083: * Routine: ipc_kmsg_copyout_compat ! 4084: * Purpose: ! 4085: * "Copy-out" port rights and out-of-line memory ! 4086: * in the message, producing an old IPC message. ! 4087: * ! 4088: * Doesn't bother to handle the header atomically. ! 4089: * Skips over errors. Problem ports produce MACH_PORT_NULL ! 4090: * (MACH_PORT_DEAD is never produced), and problem memory ! 4091: * produces a zero address. ! 4092: * Conditions: ! 4093: * Nothing locked. ! 4094: * Returns: ! 4095: * MACH_MSG_SUCCESS Copied out rights and memory. ! 4096: */ ! 4097: ! 4098: mach_msg_return_t ! 4099: ipc_kmsg_copyout_compat(kmsg, space, map) ! 4100: ipc_kmsg_t kmsg; ! 4101: ipc_space_t space; ! 4102: vm_map_t map; ! 4103: { ! 4104: msg_header_t msg; ! 4105: mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits; ! 4106: ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port; ! 4107: ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port; ! 4108: mach_port_t dest_name, reply_name; ! 4109: vm_offset_t saddr, eaddr; ! 4110: kern_return_t kr; ! 4111: ! 4112: assert(IO_VALID(dest)); ! 4113: ! 4114: io_lock(dest); ! 4115: if (io_active(dest)) { ! 4116: mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits); ! 4117: ! 4118: ipc_object_copyout_dest(space, dest, dest_type, &dest_name); ! 4119: /* dest is unlocked */ ! 4120: } else { ! 4121: io_release(dest); ! 4122: io_check_unlock(dest); ! 4123: dest_name = MACH_PORT_NULL; ! 4124: } ! 4125: ! 4126: if (IO_VALID(reply)) { ! 4127: mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits); ! 4128: ! 4129: kr = ipc_object_copyout_compat(space, reply, reply_type, ! 4130: &reply_name); ! 4131: if (kr != KERN_SUCCESS) { ! 4132: ipc_object_destroy(reply, reply_type); ! 4133: reply_name = MACH_PORT_NULL; ! 4134: } ! 4135: } else ! 4136: reply_name = MACH_PORT_NULL; ! 4137: ! 4138: msg.msg_unused = 0; ! 4139: msg.msg_simple = (mbits & MACH_MSGH_BITS_COMPLEX) ? FALSE : TRUE; ! 4140: msg.msg_size = (msg_size_t) kmsg->ikm_header.msgh_size; ! 4141: msg.msg_type = (integer_t) kmsg->ikm_header.msgh_reserved; ! 4142: msg.msg_local_port = (port_name_t) dest_name; ! 4143: msg.msg_remote_port = (port_name_t) reply_name; ! 4144: msg.msg_id = (integer_t) kmsg->ikm_header.msgh_id; ! 4145: * (msg_header_t *) &kmsg->ikm_header = msg; ! 4146: ! 4147: if (msg.msg_simple) ! 4148: return MACH_MSG_SUCCESS; ! 4149: ! 4150: saddr = (vm_offset_t) (&kmsg->ikm_header + 1); ! 4151: eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size; ! 4152: ! 4153: while (saddr < eaddr) { ! 4154: vm_offset_t taddr = saddr; ! 4155: mach_msg_type_long_t *type; ! 4156: mach_msg_type_name_t name; ! 4157: mach_msg_type_size_t size; ! 4158: mach_msg_type_number_t number; ! 4159: boolean_t is_inline, longform, is_port; ! 4160: vm_size_t length; ! 4161: vm_offset_t addr; ! 4162: ! 4163: type = (mach_msg_type_long_t *) saddr; ! 4164: is_inline = ((mach_msg_type_t*)type)->msgt_inline; ! 4165: longform = ((mach_msg_type_t*)type)->msgt_longform; ! 4166: if (longform) { ! 4167: /* This must be aligned */ ! 4168: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 4169: (is_misaligned(type))) { ! 4170: saddr = ptr_align(saddr); ! 4171: continue; ! 4172: } ! 4173: name = type->msgtl_name; ! 4174: size = type->msgtl_size; ! 4175: number = type->msgtl_number; ! 4176: saddr += sizeof(mach_msg_type_long_t); ! 4177: } else { ! 4178: name = ((mach_msg_type_t*)type)->msgt_name; ! 4179: size = ((mach_msg_type_t*)type)->msgt_size; ! 4180: number = ((mach_msg_type_t*)type)->msgt_number; ! 4181: saddr += sizeof(mach_msg_type_t); ! 4182: } ! 4183: ! 4184: /* padding (ptrs and ports) ? */ ! 4185: if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) && ! 4186: ((size >> 3) == sizeof(natural_t))) ! 4187: saddr = ptr_align(saddr); ! 4188: ! 4189: /* calculate length of data in bytes, rounding up */ ! 4190: ! 4191: length = ((number * size) + 7) >> 3; ! 4192: ! 4193: is_port = MACH_MSG_TYPE_PORT_ANY(name); ! 4194: ! 4195: if (is_port) { ! 4196: mach_port_t *objects; ! 4197: mach_msg_type_number_t i; ! 4198: mach_msg_type_name_t newname; ! 4199: ! 4200: if (!is_inline && (length != 0)) { ! 4201: /* first allocate memory in the map */ ! 4202: ! 4203: kr = vm_allocate(map, &addr, length, TRUE); ! 4204: if (kr != KERN_SUCCESS) { ! 4205: ipc_kmsg_clean_body_compat( ! 4206: taddr, saddr); ! 4207: goto vm_copyout_failure; ! 4208: } ! 4209: } ! 4210: ! 4211: newname = ipc_object_copyout_type_compat(name); ! 4212: if (longform) ! 4213: type->msgtl_name = newname; ! 4214: else ! 4215: ((mach_msg_type_t*)type)->msgt_name = newname; ! 4216: ! 4217: objects = (mach_port_t *) ! 4218: (is_inline ? saddr : * (vm_offset_t *) saddr); ! 4219: ! 4220: /* copyout port rights carried in the message */ ! 4221: ! 4222: for (i = 0; i < number; i++) { ! 4223: ipc_object_t object = ! 4224: (ipc_object_t) objects[i]; ! 4225: ! 4226: if (!IO_VALID(object)) { ! 4227: objects[i] = MACH_PORT_NULL; ! 4228: continue; ! 4229: } ! 4230: ! 4231: kr = ipc_object_copyout_compat(space, object, ! 4232: name, &objects[i]); ! 4233: if (kr != KERN_SUCCESS) { ! 4234: ipc_object_destroy(object, name); ! 4235: objects[i] = MACH_PORT_NULL; ! 4236: } ! 4237: } ! 4238: } ! 4239: ! 4240: if (is_inline) { ! 4241: /* inline data sizes round up to int boundaries */ ! 4242: ! 4243: saddr += (length + 3) &~ 3; ! 4244: } else { ! 4245: vm_offset_t data = * (vm_offset_t *) saddr; ! 4246: ! 4247: /* copyout memory carried in the message */ ! 4248: ! 4249: if (length == 0) { ! 4250: assert(data == 0); ! 4251: addr = 0; ! 4252: } else if (is_port) { ! 4253: /* copyout to memory allocated above */ ! 4254: ! 4255: (void) copyoutmap(map, (char *) data, ! 4256: (char *) addr, length); ! 4257: kfree(data, length); ! 4258: } else { ! 4259: #if MACH_OLD_VM_COPY ! 4260: kr = vm_move( ! 4261: ipc_soft_map, data, ! 4262: map, length, ! 4263: FALSE, &addr); ! 4264: (void) vm_deallocate( ! 4265: ipc_soft_map, data, length); ! 4266: if (kr != KERN_SUCCESS) { ! 4267: #else ! 4268: vm_map_copy_t copy = (vm_map_copy_t) data; ! 4269: ! 4270: kr = vm_map_copyout(map, &addr, copy); ! 4271: if (kr != KERN_SUCCESS) { ! 4272: vm_map_copy_discard(copy); ! 4273: #endif ! 4274: ! 4275: vm_copyout_failure: ! 4276: ! 4277: addr = 0; ! 4278: } ! 4279: } ! 4280: ! 4281: * (vm_offset_t *) saddr = addr; ! 4282: saddr += sizeof(vm_offset_t); ! 4283: } ! 4284: } ! 4285: ! 4286: return MACH_MSG_SUCCESS; ! 4287: } ! 4288: ! 4289: #endif MACH_IPC_COMPAT
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.