|
|
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.