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