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