]> git.saurik.com Git - apple/xnu.git/blame - osfmk/ipc/ipc_kmsg.c
xnu-6153.61.1.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@
0a7de745 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.
0a7de745 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.
0a7de745 17 *
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
0a7de745 31/*
1c79356b
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989 Carnegie Mellon University
34 * All Rights Reserved.
0a7de745 35 *
1c79356b
A
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.
0a7de745 41 *
1c79356b
A
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.
0a7de745 45 *
1c79356b 46 * Carnegie Mellon requests users of this software to return to
0a7de745 47 *
1c79356b
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
0a7de745 52 *
1c79356b
A
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>
1c79356b
A
92#include <kern/misc_protos.h>
93#include <kern/counters.h>
91447636 94#include <kern/cpu_data.h>
39037602 95#include <kern/policy_internal.h>
91447636 96
d9a64523
A
97#include <pthread/priority_private.h>
98
cb323159 99#include <machine/limits.h>
b0d623f7 100
1c79356b
A
101#include <vm/vm_map.h>
102#include <vm/vm_object.h>
103#include <vm/vm_kern.h>
91447636 104
1c79356b 105#include <ipc/port.h>
91447636 106#include <ipc/ipc_types.h>
1c79356b
A
107#include <ipc/ipc_entry.h>
108#include <ipc/ipc_kmsg.h>
109#include <ipc/ipc_notify.h>
110#include <ipc/ipc_object.h>
111#include <ipc/ipc_space.h>
112#include <ipc/ipc_port.h>
113#include <ipc/ipc_right.h>
114#include <ipc/ipc_hash.h>
115#include <ipc/ipc_table.h>
fe8ab488 116#include <ipc/ipc_importance.h>
39037602
A
117#if MACH_FLIPC
118#include <kern/mach_node.h>
119#include <ipc/flipc.h>
120#endif
1c79356b 121
d190cdc3
A
122#include <os/overflow.h>
123
2d21ac55
A
124#include <security/mac_mach_internal.h>
125
39037602
A
126#include <device/device_server.h>
127
1c79356b
A
128#include <string.h>
129
55e303ae
A
130#ifdef ppc
131#include <ppc/Firmware.h>
132#include <ppc/low_trace.h>
133#endif
134
b0d623f7
A
135#if DEBUG
136#define DEBUG_MSGS_K64 1
137#endif
138
39236c6e
A
139#include <sys/kdebug.h>
140#include <libkern/OSAtomic.h>
141
b0d623f7
A
142#pragma pack(4)
143
0a7de745
A
144typedef struct{
145 mach_msg_bits_t msgh_bits;
146 mach_msg_size_t msgh_size;
147 mach_port_name_t msgh_remote_port;
148 mach_port_name_t msgh_local_port;
149 mach_port_name_t msgh_voucher_port;
150 mach_msg_id_t msgh_id;
b0d623f7
A
151} mach_msg_legacy_header_t;
152
0a7de745
A
153typedef struct{
154 mach_msg_legacy_header_t header;
155 mach_msg_body_t body;
b0d623f7
A
156} mach_msg_legacy_base_t;
157
0a7de745
A
158typedef struct{
159 mach_port_name_t name;
160 mach_msg_size_t pad1;
161 uint32_t pad2 : 16;
162 mach_msg_type_name_t disposition : 8;
163 mach_msg_descriptor_type_t type : 8;
b0d623f7
A
164} mach_msg_legacy_port_descriptor_t;
165
166
0a7de745
A
167typedef union{
168 mach_msg_legacy_port_descriptor_t port;
169 mach_msg_ool_descriptor32_t out_of_line32;
170 mach_msg_ool_ports_descriptor32_t ool_ports32;
cb323159 171 mach_msg_guarded_port_descriptor32_t guarded_port32;
0a7de745 172 mach_msg_type_descriptor_t type;
b0d623f7
A
173} mach_msg_legacy_descriptor_t;
174
175#pragma pack()
176
177#define LEGACY_HEADER_SIZE_DELTA ((mach_msg_size_t)(sizeof(mach_msg_header_t) - sizeof(mach_msg_legacy_header_t)))
fe8ab488 178
b0d623f7
A
179// END LP64 fixes
180
181
182#if DEBUG_MSGS_K64
183extern void ipc_pset_print64(
0a7de745 184 ipc_pset_t pset);
b0d623f7 185
0a7de745
A
186extern void ipc_kmsg_print64(
187 ipc_kmsg_t kmsg,
188 const char *str);
b0d623f7 189
0a7de745
A
190extern void ipc_msg_print64(
191 mach_msg_header_t *msgh);
b0d623f7
A
192
193extern ipc_port_t ipc_name_to_data64(
0a7de745
A
194 task_t task,
195 mach_port_name_t name);
b0d623f7
A
196
197/*
198 * Forward declarations
199 */
200void ipc_msg_print_untyped64(
0a7de745 201 mach_msg_body_t *body);
b0d623f7
A
202
203const char * ipc_type_name64(
0a7de745
A
204 int type_name,
205 boolean_t received);
b0d623f7
A
206
207void ipc_print_type_name64(
0a7de745 208 int type_name);
b0d623f7
A
209
210const char *
211msgh_bit_decode64(
0a7de745 212 mach_msg_bits_t bit);
b0d623f7
A
213
214const char *
215mm_copy_options_string64(
0a7de745 216 mach_msg_copy_options_t option);
b0d623f7
A
217
218void db_print_msg_uid64(mach_msg_header_t *);
219
220static void
221ipc_msg_body_print64(void *body, int size)
222{
0a7de745
A
223 uint32_t *word = (uint32_t *) body;
224 uint32_t *end = (uint32_t *)(((uintptr_t) body) + size
225 - sizeof(mach_msg_header_t));
226 int i;
b0d623f7
A
227
228 kprintf(" body(%p-%p):\n %p: ", body, end, word);
229 for (;;) {
230 for (i = 0; i < 8; i++, word++) {
231 if (word >= end) {
232 kprintf("\n");
233 return;
234 }
0a7de745 235 kprintf("%08x ", *word);
b0d623f7
A
236 }
237 kprintf("\n %p: ", word);
238 }
239}
240
241
242const char *
243ipc_type_name64(
0a7de745
A
244 int type_name,
245 boolean_t received)
b0d623f7
A
246{
247 switch (type_name) {
0a7de745 248 case MACH_MSG_TYPE_PORT_NAME:
b0d623f7 249 return "port_name";
0a7de745
A
250
251 case MACH_MSG_TYPE_MOVE_RECEIVE:
b0d623f7
A
252 if (received) {
253 return "port_receive";
254 } else {
255 return "move_receive";
256 }
0a7de745
A
257
258 case MACH_MSG_TYPE_MOVE_SEND:
b0d623f7
A
259 if (received) {
260 return "port_send";
261 } else {
262 return "move_send";
263 }
0a7de745
A
264
265 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
b0d623f7
A
266 if (received) {
267 return "port_send_once";
268 } else {
269 return "move_send_once";
270 }
0a7de745
A
271
272 case MACH_MSG_TYPE_COPY_SEND:
b0d623f7 273 return "copy_send";
0a7de745
A
274
275 case MACH_MSG_TYPE_MAKE_SEND:
b0d623f7 276 return "make_send";
0a7de745
A
277
278 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
b0d623f7 279 return "make_send_once";
0a7de745
A
280
281 default:
b0d623f7
A
282 return (char *) 0;
283 }
284}
0a7de745 285
b0d623f7
A
286void
287ipc_print_type_name64(
0a7de745 288 int type_name)
b0d623f7
A
289{
290 const char *name = ipc_type_name64(type_name, TRUE);
291 if (name) {
292 kprintf("%s", name);
293 } else {
294 kprintf("type%d", type_name);
295 }
296}
297
298/*
299 * ipc_kmsg_print64 [ debug ]
300 */
301void
302ipc_kmsg_print64(
0a7de745
A
303 ipc_kmsg_t kmsg,
304 const char *str)
b0d623f7
A
305{
306 kprintf("%s kmsg=%p:\n", str, kmsg);
307 kprintf(" next=%p, prev=%p, size=%d",
0a7de745
A
308 kmsg->ikm_next,
309 kmsg->ikm_prev,
310 kmsg->ikm_size);
b0d623f7
A
311 kprintf("\n");
312 ipc_msg_print64(kmsg->ikm_header);
313}
314
315const char *
316msgh_bit_decode64(
0a7de745 317 mach_msg_bits_t bit)
b0d623f7
A
318{
319 switch (bit) {
0a7de745
A
320 case MACH_MSGH_BITS_COMPLEX: return "complex";
321 case MACH_MSGH_BITS_CIRCULAR: return "circular";
322 default: return (char *) 0;
b0d623f7
A
323 }
324}
325
326/*
327 * ipc_msg_print64 [ debug ]
328 */
329void
330ipc_msg_print64(
0a7de745 331 mach_msg_header_t *msgh)
b0d623f7 332{
0a7de745
A
333 mach_msg_bits_t mbits;
334 unsigned int bit, i;
335 const char *bit_name;
336 int needs_comma;
b0d623f7
A
337
338 mbits = msgh->msgh_bits;
339 kprintf(" msgh_bits=0x%x: l=0x%x,r=0x%x\n",
0a7de745
A
340 mbits,
341 MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
342 MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
b0d623f7
A
343
344 mbits = MACH_MSGH_BITS_OTHER(mbits) & MACH_MSGH_BITS_USED;
345 kprintf(" decoded bits: ");
346 needs_comma = 0;
347 for (i = 0, bit = 1; i < sizeof(mbits) * 8; ++i, bit <<= 1) {
0a7de745 348 if ((mbits & bit) == 0) {
b0d623f7 349 continue;
0a7de745 350 }
b0d623f7 351 bit_name = msgh_bit_decode64((mach_msg_bits_t)bit);
0a7de745 352 if (bit_name) {
b0d623f7 353 kprintf("%s%s", needs_comma ? "," : "", bit_name);
0a7de745 354 } else {
b0d623f7 355 kprintf("%sunknown(0x%x),", needs_comma ? "," : "", bit);
0a7de745 356 }
b0d623f7
A
357 ++needs_comma;
358 }
359 if (msgh->msgh_bits & ~MACH_MSGH_BITS_USED) {
360 kprintf("%sunused=0x%x,", needs_comma ? "," : "",
0a7de745 361 msgh->msgh_bits & ~MACH_MSGH_BITS_USED);
b0d623f7
A
362 }
363 kprintf("\n");
364
365 needs_comma = 1;
366 if (msgh->msgh_remote_port) {
367 kprintf(" remote=%p(", msgh->msgh_remote_port);
368 ipc_print_type_name64(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
369 kprintf(")");
370 } else {
371 kprintf(" remote=null");
372 }
373
374 if (msgh->msgh_local_port) {
375 kprintf("%slocal=%p(", needs_comma ? "," : "",
0a7de745 376 msgh->msgh_local_port);
b0d623f7
A
377 ipc_print_type_name64(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
378 kprintf(")\n");
379 } else {
380 kprintf("local=null\n");
381 }
382
383 kprintf(" msgh_id=%d, size=%d\n",
0a7de745
A
384 msgh->msgh_id,
385 msgh->msgh_size);
b0d623f7 386
0a7de745 387 if (mbits & MACH_MSGH_BITS_COMPLEX) {
b0d623f7
A
388 ipc_msg_print_untyped64((mach_msg_body_t *) (msgh + 1));
389 }
390
391 ipc_msg_body_print64((void *)(msgh + 1), msgh->msgh_size);
392}
393
394
395const char *
396mm_copy_options_string64(
0a7de745 397 mach_msg_copy_options_t option)
b0d623f7 398{
0a7de745 399 const char *name;
b0d623f7
A
400
401 switch (option) {
0a7de745 402 case MACH_MSG_PHYSICAL_COPY:
b0d623f7
A
403 name = "PHYSICAL";
404 break;
0a7de745 405 case MACH_MSG_VIRTUAL_COPY:
b0d623f7
A
406 name = "VIRTUAL";
407 break;
0a7de745 408 case MACH_MSG_OVERWRITE:
3e170ce0 409 name = "OVERWRITE(DEPRECATED)";
b0d623f7 410 break;
0a7de745 411 case MACH_MSG_ALLOCATE:
b0d623f7
A
412 name = "ALLOCATE";
413 break;
0a7de745 414 case MACH_MSG_KALLOC_COPY_T:
b0d623f7
A
415 name = "KALLOC_COPY_T";
416 break;
0a7de745 417 default:
b0d623f7
A
418 name = "unknown";
419 break;
420 }
421 return name;
422}
423
424void
425ipc_msg_print_untyped64(
0a7de745 426 mach_msg_body_t *body)
b0d623f7 427{
0a7de745
A
428 mach_msg_descriptor_t *saddr, *send;
429 mach_msg_descriptor_type_t type;
b0d623f7 430
0a7de745 431 kprintf(" %d descriptors: \n", body->msgh_descriptor_count);
b0d623f7 432
0a7de745
A
433 saddr = (mach_msg_descriptor_t *) (body + 1);
434 send = saddr + body->msgh_descriptor_count;
b0d623f7 435
0a7de745
A
436 for (; saddr < send; saddr++) {
437 type = saddr->type.type;
b0d623f7 438
0a7de745
A
439 switch (type) {
440 case MACH_MSG_PORT_DESCRIPTOR: {
441 mach_msg_port_descriptor_t *dsc;
b0d623f7 442
0a7de745
A
443 dsc = &saddr->port;
444 kprintf(" PORT name = %p disp = ", dsc->name);
445 ipc_print_type_name64(dsc->disposition);
446 kprintf("\n");
447 break;
448 }
449 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
450 case MACH_MSG_OOL_DESCRIPTOR: {
451 mach_msg_ool_descriptor_t *dsc;
452
453 dsc = (mach_msg_ool_descriptor_t *) &saddr->out_of_line;
454 kprintf(" OOL%s addr = %p size = 0x%x copy = %s %s\n",
455 type == MACH_MSG_OOL_DESCRIPTOR ? "" : " VOLATILE",
456 dsc->address, dsc->size,
457 mm_copy_options_string64(dsc->copy),
458 dsc->deallocate ? "DEALLOC" : "");
459 break;
460 }
461 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
462 mach_msg_ool_ports_descriptor_t *dsc;
463
464 dsc = (mach_msg_ool_ports_descriptor_t *) &saddr->ool_ports;
465
466 kprintf(" OOL_PORTS addr = %p count = 0x%x ",
467 dsc->address, dsc->count);
468 kprintf("disp = ");
469 ipc_print_type_name64(dsc->disposition);
470 kprintf(" copy = %s %s\n",
471 mm_copy_options_string64(dsc->copy),
472 dsc->deallocate ? "DEALLOC" : "");
473 break;
474 }
cb323159
A
475 case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
476 mach_msg_guarded_port_descriptor_t *dsc;
b0d623f7 477
cb323159
A
478 dsc = (mach_msg_guarded_port_descriptor_t *)&saddr->guarded_port;
479 kprintf(" GUARDED_PORT name = %p flags = 0x%x disp = ", dsc->name, dsc->flags);
480 ipc_print_type_name64(dsc->disposition);
481 kprintf("\n");
482 break;
483 }
0a7de745
A
484 default: {
485 kprintf(" UNKNOWN DESCRIPTOR 0x%x\n", type);
486 break;
487 }
488 }
b0d623f7 489 }
b0d623f7
A
490}
491
0a7de745
A
492#define DEBUG_IPC_KMSG_PRINT(kmsg, string) \
493 __unreachable_ok_push \
494 if (DEBUG_KPRINT_SYSCALL_PREDICATE(DEBUG_KPRINT_SYSCALL_IPC_MASK)) { \
495 ipc_kmsg_print64(kmsg, string); \
496 } \
fe8ab488
A
497 __unreachable_ok_pop
498
0a7de745
A
499#define DEBUG_IPC_MSG_BODY_PRINT(body, size) \
500 __unreachable_ok_push \
501 if (DEBUG_KPRINT_SYSCALL_PREDICATE(DEBUG_KPRINT_SYSCALL_IPC_MASK)) { \
502 ipc_msg_body_print64(body,size);\
503 } \
fe8ab488 504 __unreachable_ok_pop
b0d623f7 505#else /* !DEBUG_MSGS_K64 */
0a7de745
A
506#define DEBUG_IPC_KMSG_PRINT(kmsg, string)
507#define DEBUG_IPC_MSG_BODY_PRINT(body, size)
b0d623f7 508#endif /* !DEBUG_MSGS_K64 */
55e303ae 509
0a7de745
A
510extern vm_map_t ipc_kernel_copy_map;
511extern vm_size_t ipc_kmsg_max_space;
512extern vm_size_t ipc_kmsg_max_vm_space;
513extern vm_size_t ipc_kmsg_max_body_space;
514extern vm_size_t msg_ool_size_small;
1c79356b 515
0a7de745 516#define MSG_OOL_SIZE_SMALL msg_ool_size_small
1c79356b 517
91447636 518#if defined(__LP64__)
0a7de745
A
519#define MAP_SIZE_DIFFERS(map) (map->max_offset < MACH_VM_MAX_ADDRESS)
520#define OTHER_OOL_DESCRIPTOR mach_msg_ool_descriptor32_t
521#define OTHER_OOL_PORTS_DESCRIPTOR mach_msg_ool_ports_descriptor32_t
91447636 522#else
0a7de745
A
523#define MAP_SIZE_DIFFERS(map) (map->max_offset > VM_MAX_ADDRESS)
524#define OTHER_OOL_DESCRIPTOR mach_msg_ool_descriptor64_t
525#define OTHER_OOL_PORTS_DESCRIPTOR mach_msg_ool_ports_descriptor64_t
91447636
A
526#endif
527
0a7de745
A
528#define DESC_SIZE_ADJUSTMENT ((mach_msg_size_t)(sizeof(mach_msg_ool_descriptor64_t) - \
529 sizeof(mach_msg_ool_descriptor32_t)))
91447636
A
530
531/* scatter list macros */
532
0a7de745
A
533#define SKIP_PORT_DESCRIPTORS(s, c) \
534MACRO_BEGIN \
535 if ((s) != MACH_MSG_DESCRIPTOR_NULL) { \
536 while ((c) > 0) { \
537 if ((s)->type.type != MACH_MSG_PORT_DESCRIPTOR) \
538 break; \
539 (s)++; (c)--; \
540 } \
541 if (c == 0) \
542 (s) = MACH_MSG_DESCRIPTOR_NULL; \
543 } \
91447636
A
544MACRO_END
545
0a7de745
A
546#define INCREMENT_SCATTER(s, c, d) \
547MACRO_BEGIN \
548 if ((s) != MACH_MSG_DESCRIPTOR_NULL) { \
549 s = (d) ? (mach_msg_descriptor_t *) \
550 ((OTHER_OOL_DESCRIPTOR *)(s) + 1) : \
551 (s + 1); \
552 (c)--; \
553 } \
91447636
A
554MACRO_END
555
39037602
A
556#define KMSG_TRACE_FLAG_TRACED 0x000001
557#define KMSG_TRACE_FLAG_COMPLEX 0x000002
558#define KMSG_TRACE_FLAG_OOLMEM 0x000004
559#define KMSG_TRACE_FLAG_VCPY 0x000008
560#define KMSG_TRACE_FLAG_PCPY 0x000010
561#define KMSG_TRACE_FLAG_SND64 0x000020
562#define KMSG_TRACE_FLAG_RAISEIMP 0x000040
563#define KMSG_TRACE_FLAG_APP_SRC 0x000080
564#define KMSG_TRACE_FLAG_APP_DST 0x000100
565#define KMSG_TRACE_FLAG_DAEMON_SRC 0x000200
566#define KMSG_TRACE_FLAG_DAEMON_DST 0x000400
567#define KMSG_TRACE_FLAG_DST_NDFLTQ 0x000800
568#define KMSG_TRACE_FLAG_SRC_NDFLTQ 0x001000
569#define KMSG_TRACE_FLAG_DST_SONCE 0x002000
570#define KMSG_TRACE_FLAG_SRC_SONCE 0x004000
571#define KMSG_TRACE_FLAG_CHECKIN 0x008000
572#define KMSG_TRACE_FLAG_ONEWAY 0x010000
573#define KMSG_TRACE_FLAG_IOKIT 0x020000
574#define KMSG_TRACE_FLAG_SNDRCV 0x040000
575#define KMSG_TRACE_FLAG_DSTQFULL 0x080000
576#define KMSG_TRACE_FLAG_VOUCHER 0x100000
577#define KMSG_TRACE_FLAG_TIMER 0x200000
578#define KMSG_TRACE_FLAG_SEMA 0x400000
579#define KMSG_TRACE_FLAG_DTMPOWNER 0x800000
cb323159 580#define KMSG_TRACE_FLAG_GUARDED_DESC 0x1000000
39037602 581
cb323159 582#define KMSG_TRACE_FLAGS_MASK 0x1ffffff
39037602
A
583#define KMSG_TRACE_FLAGS_SHIFT 8
584
585#define KMSG_TRACE_PORTS_MASK 0xff
586#define KMSG_TRACE_PORTS_SHIFT 0
587
588#if (KDEBUG_LEVEL >= KDEBUG_LEVEL_STANDARD)
5ba3f43e 589#include <stdint.h>
39037602 590
0a7de745
A
591void
592ipc_kmsg_trace_send(ipc_kmsg_t kmsg,
593 mach_msg_option_t option)
39037602
A
594{
595 task_t send_task = TASK_NULL;
596 ipc_port_t dst_port, src_port;
597 boolean_t is_task_64bit;
598 mach_msg_header_t *msg;
599 mach_msg_trailer_t *trailer;
600
601 int kotype = 0;
602 uint32_t msg_size = 0;
cb323159 603 uint64_t msg_flags = KMSG_TRACE_FLAG_TRACED;
39037602
A
604 uint32_t num_ports = 0;
605 uint32_t send_pid, dst_pid;
606
607 /*
608 * check to see not only if ktracing is enabled, but if we will
609 * _actually_ emit the KMSG_INFO tracepoint. This saves us a
610 * significant amount of processing (and a port lock hold) in
611 * the non-tracing case.
612 */
0a7de745 613 if (__probable((kdebug_enable & KDEBUG_TRACE) == 0)) {
39037602 614 return;
0a7de745
A
615 }
616 if (!kdebug_debugid_enabled(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO))) {
39037602 617 return;
0a7de745 618 }
39037602
A
619
620 msg = kmsg->ikm_header;
621
cb323159 622 dst_port = msg->msgh_remote_port;
0a7de745 623 if (!IPC_PORT_VALID(dst_port)) {
39037602 624 return;
0a7de745 625 }
39037602
A
626
627 /*
628 * Message properties / options
629 */
0a7de745 630 if ((option & (MACH_SEND_MSG | MACH_RCV_MSG)) == (MACH_SEND_MSG | MACH_RCV_MSG)) {
39037602 631 msg_flags |= KMSG_TRACE_FLAG_SNDRCV;
0a7de745 632 }
39037602
A
633
634 if (msg->msgh_id >= is_iokit_subsystem.start &&
0a7de745 635 msg->msgh_id < is_iokit_subsystem.end + 100) {
39037602 636 msg_flags |= KMSG_TRACE_FLAG_IOKIT;
0a7de745 637 }
39037602 638 /* magic XPC checkin message id (XPC_MESSAGE_ID_CHECKIN) from libxpc */
0a7de745 639 else if (msg->msgh_id == 0x77303074u /* w00t */) {
39037602 640 msg_flags |= KMSG_TRACE_FLAG_CHECKIN;
0a7de745 641 }
39037602 642
0a7de745 643 if (msg->msgh_bits & MACH_MSGH_BITS_RAISEIMP) {
39037602 644 msg_flags |= KMSG_TRACE_FLAG_RAISEIMP;
0a7de745 645 }
39037602 646
0a7de745 647 if (unsafe_convert_port_to_voucher(kmsg->ikm_voucher)) {
39037602 648 msg_flags |= KMSG_TRACE_FLAG_VOUCHER;
0a7de745 649 }
39037602
A
650
651 /*
652 * Sending task / port
653 */
654 send_task = current_task();
655 send_pid = task_pid(send_task);
656
657 if (send_pid != 0) {
0a7de745 658 if (task_is_daemon(send_task)) {
39037602 659 msg_flags |= KMSG_TRACE_FLAG_DAEMON_SRC;
0a7de745 660 } else if (task_is_app(send_task)) {
39037602 661 msg_flags |= KMSG_TRACE_FLAG_APP_SRC;
0a7de745 662 }
39037602
A
663 }
664
665 is_task_64bit = (send_task->map->max_offset > VM_MAX_ADDRESS);
0a7de745 666 if (is_task_64bit) {
39037602 667 msg_flags |= KMSG_TRACE_FLAG_SND64;
0a7de745 668 }
39037602 669
cb323159 670 src_port = msg->msgh_local_port;
39037602 671 if (src_port) {
0a7de745 672 if (src_port->ip_messages.imq_qlimit != MACH_PORT_QLIMIT_DEFAULT) {
39037602 673 msg_flags |= KMSG_TRACE_FLAG_SRC_NDFLTQ;
0a7de745 674 }
39037602
A
675 switch (MACH_MSGH_BITS_LOCAL(msg->msgh_bits)) {
676 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
677 msg_flags |= KMSG_TRACE_FLAG_SRC_SONCE;
678 break;
679 default:
680 break;
681 }
682 } else {
683 msg_flags |= KMSG_TRACE_FLAG_ONEWAY;
684 }
685
686
687 /*
688 * Destination task / port
689 */
690 ip_lock(dst_port);
691 if (!ip_active(dst_port)) {
692 /* dst port is being torn down */
693 dst_pid = (uint32_t)0xfffffff0;
694 } else if (dst_port->ip_tempowner) {
695 msg_flags |= KMSG_TRACE_FLAG_DTMPOWNER;
0a7de745 696 if (IIT_NULL != dst_port->ip_imp_task) {
39037602 697 dst_pid = task_pid(dst_port->ip_imp_task->iit_task);
0a7de745 698 } else {
39037602 699 dst_pid = (uint32_t)0xfffffff1;
0a7de745 700 }
39037602
A
701 } else if (dst_port->ip_receiver_name == MACH_PORT_NULL) {
702 /* dst_port is otherwise in-transit */
703 dst_pid = (uint32_t)0xfffffff2;
704 } else {
705 if (dst_port->ip_receiver == ipc_space_kernel) {
706 dst_pid = 0;
707 } else {
708 ipc_space_t dst_space;
709 dst_space = dst_port->ip_receiver;
710 if (dst_space && is_active(dst_space)) {
711 dst_pid = task_pid(dst_space->is_task);
0a7de745 712 if (task_is_daemon(dst_space->is_task)) {
39037602 713 msg_flags |= KMSG_TRACE_FLAG_DAEMON_DST;
0a7de745 714 } else if (task_is_app(dst_space->is_task)) {
39037602 715 msg_flags |= KMSG_TRACE_FLAG_APP_DST;
0a7de745 716 }
39037602
A
717 } else {
718 /* receiving task is being torn down */
719 dst_pid = (uint32_t)0xfffffff3;
720 }
721 }
722 }
723
0a7de745 724 if (dst_port->ip_messages.imq_qlimit != MACH_PORT_QLIMIT_DEFAULT) {
39037602 725 msg_flags |= KMSG_TRACE_FLAG_DST_NDFLTQ;
0a7de745
A
726 }
727 if (imq_full(&dst_port->ip_messages)) {
39037602 728 msg_flags |= KMSG_TRACE_FLAG_DSTQFULL;
0a7de745 729 }
39037602
A
730
731 kotype = ip_kotype(dst_port);
732
733 ip_unlock(dst_port);
734
735 switch (kotype) {
736 case IKOT_SEMAPHORE:
737 msg_flags |= KMSG_TRACE_FLAG_SEMA;
738 break;
739 case IKOT_TIMER:
740 case IKOT_CLOCK:
741 msg_flags |= KMSG_TRACE_FLAG_TIMER;
742 break;
743 case IKOT_MASTER_DEVICE:
744 case IKOT_IOKIT_CONNECT:
745 case IKOT_IOKIT_OBJECT:
a39ff7e2 746 case IKOT_IOKIT_IDENT:
cb323159 747 case IKOT_UEXT_OBJECT:
39037602
A
748 msg_flags |= KMSG_TRACE_FLAG_IOKIT;
749 break;
750 default:
751 break;
752 }
753
0a7de745 754 switch (MACH_MSGH_BITS_REMOTE(msg->msgh_bits)) {
39037602
A
755 case MACH_MSG_TYPE_PORT_SEND_ONCE:
756 msg_flags |= KMSG_TRACE_FLAG_DST_SONCE;
757 break;
758 default:
759 break;
760 }
761
762
763 /*
764 * Message size / content
765 */
766 msg_size = msg->msgh_size - sizeof(mach_msg_header_t);
767
768 if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
769 mach_msg_body_t *msg_body;
770 mach_msg_descriptor_t *kern_dsc;
771 int dsc_count;
772
773 msg_flags |= KMSG_TRACE_FLAG_COMPLEX;
774
775 msg_body = (mach_msg_body_t *)(kmsg->ikm_header + 1);
776 dsc_count = (int)msg_body->msgh_descriptor_count;
777 kern_dsc = (mach_msg_descriptor_t *)(msg_body + 1);
778
779 /* this is gross: see ipc_kmsg_copyin_body()... */
0a7de745 780 if (!is_task_64bit) {
39037602 781 msg_size -= (dsc_count * 12);
0a7de745 782 }
39037602
A
783
784 for (int i = 0; i < dsc_count; i++) {
785 switch (kern_dsc[i].type.type) {
786 case MACH_MSG_PORT_DESCRIPTOR:
787 num_ports++;
0a7de745 788 if (is_task_64bit) {
39037602 789 msg_size -= 12;
0a7de745 790 }
39037602
A
791 break;
792 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
793 case MACH_MSG_OOL_DESCRIPTOR: {
794 mach_msg_ool_descriptor_t *dsc;
795 dsc = (mach_msg_ool_descriptor_t *)&kern_dsc[i];
796 msg_flags |= KMSG_TRACE_FLAG_OOLMEM;
797 msg_size += dsc->size;
798 if ((dsc->size >= MSG_OOL_SIZE_SMALL) &&
799 (dsc->copy == MACH_MSG_PHYSICAL_COPY) &&
0a7de745 800 !dsc->deallocate) {
39037602 801 msg_flags |= KMSG_TRACE_FLAG_PCPY;
0a7de745 802 } else if (dsc->size <= MSG_OOL_SIZE_SMALL) {
39037602 803 msg_flags |= KMSG_TRACE_FLAG_PCPY;
0a7de745 804 } else {
39037602 805 msg_flags |= KMSG_TRACE_FLAG_VCPY;
0a7de745
A
806 }
807 if (is_task_64bit) {
39037602 808 msg_size -= 16;
0a7de745
A
809 }
810 } break;
39037602 811 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
0a7de745 812 mach_msg_ool_ports_descriptor_t *dsc;
39037602
A
813 dsc = (mach_msg_ool_ports_descriptor_t *)&kern_dsc[i];
814 num_ports += dsc->count;
0a7de745 815 if (is_task_64bit) {
39037602 816 msg_size -= 16;
0a7de745
A
817 }
818 } break;
cb323159
A
819 case MACH_MSG_GUARDED_PORT_DESCRIPTOR:
820 num_ports++;
821 msg_flags |= KMSG_TRACE_FLAG_GUARDED_DESC;
822 if (is_task_64bit) {
823 msg_size -= 16;
824 }
39037602
A
825 default:
826 break;
827 }
828 }
829 }
830
831 /*
832 * Trailer contents
833 */
834 trailer = (mach_msg_trailer_t *)((vm_offset_t)msg +
0a7de745 835 round_msg((vm_offset_t)msg->msgh_size));
39037602 836 if (trailer->msgh_trailer_size <= sizeof(mach_msg_security_trailer_t)) {
cb323159 837 extern const security_token_t KERNEL_SECURITY_TOKEN;
39037602
A
838 mach_msg_security_trailer_t *strailer;
839 strailer = (mach_msg_security_trailer_t *)trailer;
840 /*
841 * verify the sender PID: replies from the kernel often look
842 * like self-talk because the sending port is not reset.
843 */
844 if (memcmp(&strailer->msgh_sender,
0a7de745
A
845 &KERNEL_SECURITY_TOKEN,
846 sizeof(KERNEL_SECURITY_TOKEN)) == 0) {
39037602
A
847 send_pid = 0;
848 msg_flags &= ~(KMSG_TRACE_FLAG_APP_SRC | KMSG_TRACE_FLAG_DAEMON_SRC);
849 }
850 }
851
0a7de745
A
852 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END,
853 (uintptr_t)send_pid,
854 (uintptr_t)dst_pid,
855 (uintptr_t)msg_size,
856 (uintptr_t)(
857 ((msg_flags & KMSG_TRACE_FLAGS_MASK) << KMSG_TRACE_FLAGS_SHIFT) |
858 ((num_ports & KMSG_TRACE_PORTS_MASK) << KMSG_TRACE_PORTS_SHIFT)
859 )
860 );
39037602
A
861}
862#endif
863
91447636 864/* zone for cached ipc_kmsg_t structures */
0a7de745 865zone_t ipc_kmsg_zone;
1c79356b
A
866
867/*
868 * Forward declarations
869 */
870
871void ipc_kmsg_clean(
0a7de745 872 ipc_kmsg_t kmsg);
1c79356b
A
873
874void ipc_kmsg_clean_body(
0a7de745
A
875 ipc_kmsg_t kmsg,
876 mach_msg_type_number_t number,
877 mach_msg_descriptor_t *desc);
1c79356b
A
878
879void ipc_kmsg_clean_partial(
0a7de745
A
880 ipc_kmsg_t kmsg,
881 mach_msg_type_number_t number,
882 mach_msg_descriptor_t *desc,
883 vm_offset_t paddr,
884 vm_size_t length);
1c79356b 885
1c79356b 886mach_msg_return_t ipc_kmsg_copyin_body(
d9a64523
A
887 ipc_kmsg_t kmsg,
888 ipc_space_t space,
889 vm_map_t map,
890 mach_msg_option_t *optionp);
5ba3f43e 891
cb323159
A
892
893extern int enforce_strict_reply;
894
895static void
896ipc_kmsg_link_reply_context_locked(
897 ipc_port_t reply_port,
898 ipc_port_t voucher_port);
899
900static kern_return_t
901ipc_kmsg_validate_reply_port_locked(
902 ipc_port_t reply_port,
903 mach_msg_option_t options);
904
905static mach_msg_return_t
906ipc_kmsg_validate_reply_context_locked(
907 mach_msg_option_t option,
908 ipc_port_t dest_port,
909 ipc_voucher_t voucher,
910 mach_port_name_t voucher_name);
911
912/* we can't include the BSD <sys/persona.h> header here... */
913#ifndef PERSONA_ID_NONE
914#define PERSONA_ID_NONE ((uint32_t)-1)
915#endif
916
1c79356b
A
917/*
918 * We keep a per-processor cache of kernel message buffers.
919 * The cache saves the overhead/locking of using kalloc/kfree.
920 * The per-processor cache seems to miss less than a per-thread cache,
921 * and it also uses less memory. Access to the cache doesn't
922 * require locking.
923 */
1c79356b
A
924
925/*
926 * Routine: ipc_kmsg_alloc
927 * Purpose:
928 * Allocate a kernel message structure. If we can get one from
929 * the cache, that is best. Otherwise, allocate a new one.
930 * Conditions:
931 * Nothing locked.
932 */
933ipc_kmsg_t
934ipc_kmsg_alloc(
935 mach_msg_size_t msg_and_trailer_size)
936{
91447636 937 mach_msg_size_t max_expanded_size;
1c79356b
A
938 ipc_kmsg_t kmsg;
939
91447636
A
940 /*
941 * LP64support -
942 * Pad the allocation in case we need to expand the
cb323159 943 * message descriptors for user spaces with pointers larger than
b0d623f7 944 * the kernel's own, or vice versa. We don't know how many descriptors
91447636
A
945 * there are yet, so just assume the whole body could be
946 * descriptors (if there could be any at all).
947 *
948 * The expansion space is left in front of the header,
949 * because it is easier to pull the header and descriptors
950 * forward as we process them than it is to push all the
951 * data backwards.
952 */
8ad349bb 953 mach_msg_size_t size = msg_and_trailer_size - MAX_TRAILER_SIZE;
316670eb
A
954
955 /* compare against implementation upper limit for the body */
0a7de745 956 if (size > ipc_kmsg_max_body_space) {
316670eb 957 return IKM_NULL;
0a7de745 958 }
316670eb 959
8ad349bb 960 if (size > sizeof(mach_msg_base_t)) {
b0d623f7 961 mach_msg_size_t max_desc = (mach_msg_size_t)(((size - sizeof(mach_msg_base_t)) /
0a7de745
A
962 sizeof(mach_msg_ool_descriptor32_t)) *
963 DESC_SIZE_ADJUSTMENT);
316670eb
A
964
965 /* make sure expansion won't cause wrap */
0a7de745 966 if (msg_and_trailer_size > MACH_MSG_SIZE_MAX - max_desc) {
8ad349bb 967 return IKM_NULL;
0a7de745 968 }
b0d623f7 969
8ad349bb 970 max_expanded_size = msg_and_trailer_size + max_desc;
0a7de745
A
971 } else {
972 max_expanded_size = msg_and_trailer_size;
973 }
91447636 974
0a7de745
A
975 if (max_expanded_size < IKM_SAVED_MSG_SIZE) {
976 max_expanded_size = IKM_SAVED_MSG_SIZE; /* round up for ikm_cache */
977 }
91447636 978 if (max_expanded_size == IKM_SAVED_MSG_SIZE) {
91447636
A
979 kmsg = (ipc_kmsg_t)zalloc(ipc_kmsg_zone);
980 } else {
981 kmsg = (ipc_kmsg_t)kalloc(ikm_plus_overhead(max_expanded_size));
1c79356b
A
982 }
983
1c79356b 984 if (kmsg != IKM_NULL) {
91447636 985 ikm_init(kmsg, max_expanded_size);
b7266188 986 ikm_set_header(kmsg, msg_and_trailer_size);
1c79356b 987 }
2d21ac55 988
0a7de745 989 return kmsg;
1c79356b
A
990}
991
992/*
993 * Routine: ipc_kmsg_free
994 * Purpose:
995 * Free a kernel message buffer. If the kms is preallocated
996 * to a port, just "put it back (marked unused)." We have to
997 * do this with the port locked. The port may have its hold
998 * on our message released. In that case, we have to just
999 * revert the message to a traditional one and free it normally.
1000 * Conditions:
1001 * Nothing locked.
1002 */
1003
1004void
1005ipc_kmsg_free(
0a7de745 1006 ipc_kmsg_t kmsg)
1c79356b
A
1007{
1008 mach_msg_size_t size = kmsg->ikm_size;
1009 ipc_port_t port;
1010
fe8ab488
A
1011 assert(!IP_VALID(kmsg->ikm_voucher));
1012
0a7de745
A
1013 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_FREE) | DBG_FUNC_NONE,
1014 VM_KERNEL_ADDRPERM((uintptr_t)kmsg),
1015 0, 0, 0, 0);
2d21ac55 1016
1c79356b
A
1017 /*
1018 * Check to see if the message is bound to the port. If so,
1019 * mark it not in use. If the port isn't already dead, then
91447636 1020 * leave the message associated with it. Otherwise, free it.
1c79356b
A
1021 */
1022 port = ikm_prealloc_inuse_port(kmsg);
1023 if (port != IP_NULL) {
1024 ip_lock(port);
1025 ikm_prealloc_clear_inuse(kmsg, port);
1026 if (ip_active(port) && (port->ip_premsg == kmsg)) {
1027 assert(IP_PREALLOC(port));
1028 ip_unlock(port);
316670eb 1029 ip_release(port);
1c79356b
A
1030 return;
1031 }
0a7de745 1032 ip_unlock(port);
316670eb 1033 ip_release(port); /* May be last reference */
1c79356b
A
1034 }
1035
91447636 1036 if (kmsg->ikm_size == IKM_SAVED_MSG_SIZE) {
91447636
A
1037 zfree(ipc_kmsg_zone, kmsg);
1038 return;
1c79356b 1039 }
91447636 1040 kfree(kmsg, ikm_plus_overhead(size));
1c79356b
A
1041}
1042
1043
1044/*
1045 * Routine: ipc_kmsg_enqueue
1046 * Purpose:
1047 * Enqueue a kmsg.
1048 */
1049
1050void
1051ipc_kmsg_enqueue(
0a7de745
A
1052 ipc_kmsg_queue_t queue,
1053 ipc_kmsg_t kmsg)
1c79356b 1054{
39037602
A
1055 ipc_kmsg_t first = queue->ikmq_base;
1056 ipc_kmsg_t last;
1057
1058 if (first == IKM_NULL) {
1059 queue->ikmq_base = kmsg;
1060 kmsg->ikm_next = kmsg;
1061 kmsg->ikm_prev = kmsg;
1062 } else {
1063 last = first->ikm_prev;
1064 kmsg->ikm_next = first;
1065 kmsg->ikm_prev = last;
1066 first->ikm_prev = kmsg;
1067 last->ikm_next = kmsg;
1068 }
1069}
1070
1071/*
1072 * Routine: ipc_kmsg_enqueue_qos
1073 * Purpose:
1074 * Enqueue a kmsg, propagating qos
1075 * overrides towards the head of the queue.
1076 *
1077 * Returns:
1078 * whether the head of the queue had
1079 * it's override-qos adjusted because
1080 * of this insertion.
1081 */
1082
1083boolean_t
1084ipc_kmsg_enqueue_qos(
0a7de745
A
1085 ipc_kmsg_queue_t queue,
1086 ipc_kmsg_t kmsg)
39037602
A
1087{
1088 ipc_kmsg_t first = queue->ikmq_base;
1089 ipc_kmsg_t prev;
1090 mach_msg_priority_t override;
1091
1092 if (first == IKM_NULL) {
1093 /* insert a first message */
1094 queue->ikmq_base = kmsg;
1095 kmsg->ikm_next = kmsg;
1096 kmsg->ikm_prev = kmsg;
1097 return TRUE;
1098 }
1099
1100 /* insert at the tail */
1101 prev = first->ikm_prev;
1102 kmsg->ikm_next = first;
1103 kmsg->ikm_prev = prev;
1104 first->ikm_prev = kmsg;
1105 prev->ikm_next = kmsg;
1106
1107 /* apply QoS overrides towards the head */
1108 override = kmsg->ikm_qos_override;
1109 while (prev != kmsg &&
0a7de745 1110 override > prev->ikm_qos_override) {
39037602
A
1111 prev->ikm_qos_override = override;
1112 prev = prev->ikm_prev;
1113 }
1114
1115 /* did we adjust everything? */
0a7de745 1116 return prev == kmsg;
39037602
A
1117}
1118
1119/*
1120 * Routine: ipc_kmsg_override_qos
1121 * Purpose:
1122 * Update the override for a given kmsg already
1123 * enqueued, propagating qos override adjustments
1124 * towards the head of the queue.
1125 *
1126 * Returns:
1127 * whether the head of the queue had
1128 * it's override-qos adjusted because
1129 * of this insertion.
1130 */
1131
1132boolean_t
1133ipc_kmsg_override_qos(
0a7de745 1134 ipc_kmsg_queue_t queue,
39037602
A
1135 ipc_kmsg_t kmsg,
1136 mach_msg_priority_t override)
1137{
1138 ipc_kmsg_t first = queue->ikmq_base;
1139 ipc_kmsg_t cur = kmsg;
1140
1141 /* apply QoS overrides towards the head */
1142 while (override > cur->ikm_qos_override) {
1143 cur->ikm_qos_override = override;
0a7de745 1144 if (cur == first) {
39037602 1145 return TRUE;
0a7de745
A
1146 }
1147 cur = cur->ikm_prev;
39037602
A
1148 }
1149 return FALSE;
1c79356b
A
1150}
1151
1152/*
1153 * Routine: ipc_kmsg_dequeue
1154 * Purpose:
1155 * Dequeue and return a kmsg.
1156 */
1157
1158ipc_kmsg_t
1159ipc_kmsg_dequeue(
0a7de745 1160 ipc_kmsg_queue_t queue)
1c79356b
A
1161{
1162 ipc_kmsg_t first;
1163
1164 first = ipc_kmsg_queue_first(queue);
1165
0a7de745 1166 if (first != IKM_NULL) {
39037602 1167 ipc_kmsg_rmqueue(queue, first);
0a7de745 1168 }
1c79356b
A
1169
1170 return first;
1171}
1172
1173/*
1174 * Routine: ipc_kmsg_rmqueue
1175 * Purpose:
1176 * Pull a kmsg out of a queue.
1177 */
1178
1179void
1180ipc_kmsg_rmqueue(
0a7de745
A
1181 ipc_kmsg_queue_t queue,
1182 ipc_kmsg_t kmsg)
1c79356b
A
1183{
1184 ipc_kmsg_t next, prev;
1185
1186 assert(queue->ikmq_base != IKM_NULL);
1187
1188 next = kmsg->ikm_next;
1189 prev = kmsg->ikm_prev;
1190
1191 if (next == kmsg) {
1192 assert(prev == kmsg);
1193 assert(queue->ikmq_base == kmsg);
1194
1195 queue->ikmq_base = IKM_NULL;
1196 } else {
5c9f4661
A
1197 if (__improbable(next->ikm_prev != kmsg || prev->ikm_next != kmsg)) {
1198 panic("ipc_kmsg_rmqueue: inconsistent prev/next pointers. "
0a7de745
A
1199 "(prev->next: %p, next->prev: %p, kmsg: %p)",
1200 prev->ikm_next, next->ikm_prev, kmsg);
5c9f4661
A
1201 }
1202
0a7de745 1203 if (queue->ikmq_base == kmsg) {
1c79356b 1204 queue->ikmq_base = next;
0a7de745 1205 }
1c79356b
A
1206
1207 next->ikm_prev = prev;
1208 prev->ikm_next = next;
1209 }
1210 /* XXX Temporary debug logic */
2d21ac55
A
1211 assert((kmsg->ikm_next = IKM_BOGUS) == IKM_BOGUS);
1212 assert((kmsg->ikm_prev = IKM_BOGUS) == IKM_BOGUS);
1c79356b
A
1213}
1214
1215/*
1216 * Routine: ipc_kmsg_queue_next
1217 * Purpose:
1218 * Return the kmsg following the given kmsg.
1219 * (Or IKM_NULL if it is the last one in the queue.)
1220 */
1221
1222ipc_kmsg_t
1223ipc_kmsg_queue_next(
0a7de745
A
1224 ipc_kmsg_queue_t queue,
1225 ipc_kmsg_t kmsg)
1c79356b
A
1226{
1227 ipc_kmsg_t next;
1228
1229 assert(queue->ikmq_base != IKM_NULL);
1230
1231 next = kmsg->ikm_next;
0a7de745 1232 if (queue->ikmq_base == next) {
1c79356b 1233 next = IKM_NULL;
0a7de745 1234 }
1c79356b
A
1235
1236 return next;
1237}
1238
1239/*
1240 * Routine: ipc_kmsg_destroy
1241 * Purpose:
1242 * Destroys a kernel message. Releases all rights,
1243 * references, and memory held by the message.
1244 * Frees the message.
1245 * Conditions:
1246 * No locks held.
1247 */
1248
1249void
1250ipc_kmsg_destroy(
0a7de745 1251 ipc_kmsg_t kmsg)
1c79356b 1252{
1c79356b 1253 /*
6d2010ae
A
1254 * Destroying a message can cause more messages to be destroyed.
1255 * Curtail recursion by putting messages on the deferred
1256 * destruction queue. If this was the first message on the
1257 * queue, this instance must process the full queue.
1c79356b 1258 */
0a7de745 1259 if (ipc_kmsg_delayed_destroy(kmsg)) {
6d2010ae 1260 ipc_kmsg_reap_delayed();
0a7de745 1261 }
6d2010ae 1262}
1c79356b 1263
6d2010ae
A
1264/*
1265 * Routine: ipc_kmsg_delayed_destroy
1266 * Purpose:
1267 * Enqueues a kernel message for deferred destruction.
1268 * Returns:
1269 * Boolean indicator that the caller is responsible to reap
1270 * deferred messages.
1271 */
1c79356b 1272
0a7de745
A
1273boolean_t
1274ipc_kmsg_delayed_destroy(
6d2010ae
A
1275 ipc_kmsg_t kmsg)
1276{
1277 ipc_kmsg_queue_t queue = &(current_thread()->ith_messages);
1278 boolean_t first = ipc_kmsg_queue_empty(queue);
1c79356b 1279
6d2010ae
A
1280 ipc_kmsg_enqueue(queue, kmsg);
1281 return first;
1c79356b
A
1282}
1283
1284/*
6d2010ae 1285 * Routine: ipc_kmsg_destroy_queue
1c79356b 1286 * Purpose:
6d2010ae
A
1287 * Destroys messages from the per-thread
1288 * deferred reaping queue.
1c79356b
A
1289 * Conditions:
1290 * No locks held.
1291 */
6d2010ae 1292
91447636 1293void
6d2010ae 1294ipc_kmsg_reap_delayed(void)
1c79356b 1295{
6d2010ae
A
1296 ipc_kmsg_queue_t queue = &(current_thread()->ith_messages);
1297 ipc_kmsg_t kmsg;
1c79356b 1298
6d2010ae
A
1299 /*
1300 * must leave kmsg in queue while cleaning it to assure
1301 * no nested calls recurse into here.
1302 */
1303 while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
1304 ipc_kmsg_clean(kmsg);
1305 ipc_kmsg_rmqueue(queue, kmsg);
1306 ipc_kmsg_free(kmsg);
1307 }
1c79356b
A
1308}
1309
1310/*
1311 * Routine: ipc_kmsg_clean_body
1312 * Purpose:
1313 * Cleans the body of a kernel message.
1314 * Releases all rights, references, and memory.
1315 *
1316 * Conditions:
1317 * No locks held.
1318 */
6d2010ae 1319static unsigned int _ipc_kmsg_clean_invalid_desc = 0;
1c79356b
A
1320void
1321ipc_kmsg_clean_body(
0a7de745
A
1322 __unused ipc_kmsg_t kmsg,
1323 mach_msg_type_number_t number,
1324 mach_msg_descriptor_t *saddr)
1c79356b 1325{
0a7de745 1326 mach_msg_type_number_t i;
1c79356b 1327
0a7de745
A
1328 if (number == 0) {
1329 return;
1330 }
1c79356b 1331
0a7de745
A
1332 for (i = 0; i < number; i++, saddr++) {
1333 switch (saddr->type.type) {
1334 case MACH_MSG_PORT_DESCRIPTOR: {
1335 mach_msg_port_descriptor_t *dsc;
1c79356b 1336
0a7de745 1337 dsc = &saddr->port;
1c79356b 1338
0a7de745
A
1339 /*
1340 * Destroy port rights carried in the message
1341 */
cb323159 1342 if (!IP_VALID(dsc->name)) {
0a7de745
A
1343 continue;
1344 }
cb323159 1345 ipc_object_destroy(ip_to_object(dsc->name), dsc->disposition);
0a7de745 1346 break;
1c79356b 1347 }
0a7de745
A
1348 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
1349 case MACH_MSG_OOL_DESCRIPTOR: {
1350 mach_msg_ool_descriptor_t *dsc;
1c79356b 1351
0a7de745 1352 dsc = (mach_msg_ool_descriptor_t *)&saddr->out_of_line;
1c79356b 1353
0a7de745
A
1354 /*
1355 * Destroy memory carried in the message
1356 */
1357 if (dsc->size == 0) {
1358 assert(dsc->address == (void *) 0);
1359 } else {
1360 vm_map_copy_discard((vm_map_copy_t) dsc->address);
1361 }
1c79356b
A
1362 break;
1363 }
0a7de745
A
1364 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
1365 ipc_object_t *objects;
1366 mach_msg_type_number_t j;
1367 mach_msg_ool_ports_descriptor_t *dsc;
1c79356b 1368
0a7de745
A
1369 dsc = (mach_msg_ool_ports_descriptor_t *)&saddr->ool_ports;
1370 objects = (ipc_object_t *) dsc->address;
1c79356b 1371
0a7de745
A
1372 if (dsc->count == 0) {
1373 break;
1374 }
1c79356b 1375
0a7de745 1376 assert(objects != (ipc_object_t *) 0);
1c79356b 1377
0a7de745
A
1378 /* destroy port rights carried in the message */
1379
1380 for (j = 0; j < dsc->count; j++) {
1381 ipc_object_t object = objects[j];
1382
1383 if (!IO_VALID(object)) {
1384 continue;
1385 }
1386
1387 ipc_object_destroy(object, dsc->disposition);
1388 }
1389
1390 /* destroy memory carried in the message */
1391
1392 assert(dsc->count != 0);
1393
1394 kfree(dsc->address,
1395 (vm_size_t) dsc->count * sizeof(mach_port_t));
1396 break;
1397 }
cb323159
A
1398 case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
1399 mach_msg_guarded_port_descriptor_t *dsc = (typeof(dsc)) & saddr->guarded_port;
1400
1401 /*
1402 * Destroy port rights carried in the message
1403 */
1404 if (!IP_VALID(dsc->name)) {
1405 continue;
1406 }
1407 ipc_object_destroy(ip_to_object(dsc->name), dsc->disposition);
1408 break;
1409 }
0a7de745 1410 default: {
cb323159 1411 _ipc_kmsg_clean_invalid_desc++; /* don't understand this type of descriptor */
0a7de745
A
1412 }
1413 }
1c79356b 1414 }
1c79356b
A
1415}
1416
1417/*
1418 * Routine: ipc_kmsg_clean_partial
1419 * Purpose:
1420 * Cleans a partially-acquired kernel message.
1421 * number is the index of the type descriptor
1422 * in the body of the message that contained the error.
1423 * If dolast, the memory and port rights in this last
1424 * type spec are also cleaned. In that case, number
1425 * specifies the number of port rights to clean.
1426 * Conditions:
1427 * Nothing locked.
1428 */
1429
1430void
1431ipc_kmsg_clean_partial(
0a7de745
A
1432 ipc_kmsg_t kmsg,
1433 mach_msg_type_number_t number,
1434 mach_msg_descriptor_t *desc,
1435 vm_offset_t paddr,
1436 vm_size_t length)
1c79356b
A
1437{
1438 ipc_object_t object;
91447636 1439 mach_msg_bits_t mbits = kmsg->ikm_header->msgh_bits;
1c79356b 1440
fe8ab488
A
1441 /* deal with importance chain while we still have dest and voucher references */
1442 ipc_importance_clean(kmsg);
1443
cb323159 1444 object = ip_to_object(kmsg->ikm_header->msgh_remote_port);
1c79356b 1445 assert(IO_VALID(object));
6d2010ae 1446 ipc_object_destroy_dest(object, MACH_MSGH_BITS_REMOTE(mbits));
1c79356b 1447
cb323159 1448 object = ip_to_object(kmsg->ikm_header->msgh_local_port);
0a7de745 1449 if (IO_VALID(object)) {
1c79356b 1450 ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
0a7de745 1451 }
1c79356b 1452
cb323159 1453 object = ip_to_object(kmsg->ikm_voucher);
fe8ab488
A
1454 if (IO_VALID(object)) {
1455 assert(MACH_MSGH_BITS_VOUCHER(mbits) == MACH_MSG_TYPE_MOVE_SEND);
1456 ipc_object_destroy(object, MACH_MSG_TYPE_PORT_SEND);
1457 kmsg->ikm_voucher = IP_NULL;
1458 }
1459
1c79356b
A
1460 if (paddr) {
1461 (void) vm_deallocate(ipc_kernel_copy_map, paddr, length);
1462 }
1463
91447636 1464 ipc_kmsg_clean_body(kmsg, number, desc);
1c79356b
A
1465}
1466
1467/*
1468 * Routine: ipc_kmsg_clean
1469 * Purpose:
1470 * Cleans a kernel message. Releases all rights,
1471 * references, and memory held by the message.
1472 * Conditions:
1473 * No locks held.
1474 */
1475
1476void
1477ipc_kmsg_clean(
0a7de745 1478 ipc_kmsg_t kmsg)
1c79356b
A
1479{
1480 ipc_object_t object;
1481 mach_msg_bits_t mbits;
1482
fe8ab488
A
1483 /* deal with importance chain while we still have dest and voucher references */
1484 ipc_importance_clean(kmsg);
1485
91447636 1486 mbits = kmsg->ikm_header->msgh_bits;
cb323159 1487 object = ip_to_object(kmsg->ikm_header->msgh_remote_port);
0a7de745 1488 if (IO_VALID(object)) {
6d2010ae 1489 ipc_object_destroy_dest(object, MACH_MSGH_BITS_REMOTE(mbits));
0a7de745 1490 }
1c79356b 1491
cb323159 1492 object = ip_to_object(kmsg->ikm_header->msgh_local_port);
0a7de745 1493 if (IO_VALID(object)) {
1c79356b 1494 ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
0a7de745 1495 }
1c79356b 1496
cb323159 1497 object = ip_to_object(kmsg->ikm_voucher);
fe8ab488
A
1498 if (IO_VALID(object)) {
1499 assert(MACH_MSGH_BITS_VOUCHER(mbits) == MACH_MSG_TYPE_MOVE_SEND);
1500 ipc_object_destroy(object, MACH_MSG_TYPE_PORT_SEND);
1501 kmsg->ikm_voucher = IP_NULL;
1502 }
1503
1c79356b
A
1504 if (mbits & MACH_MSGH_BITS_COMPLEX) {
1505 mach_msg_body_t *body;
1506
91447636
A
1507 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
1508 ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count,
0a7de745 1509 (mach_msg_descriptor_t *)(body + 1));
1c79356b
A
1510 }
1511}
1512
1513/*
1514 * Routine: ipc_kmsg_set_prealloc
1515 * Purpose:
1516 * Assign a kmsg as a preallocated message buffer to a port.
1517 * Conditions:
1518 * port locked.
1519 */
1520
1521void
1522ipc_kmsg_set_prealloc(
0a7de745
A
1523 ipc_kmsg_t kmsg,
1524 ipc_port_t port)
1c79356b
A
1525{
1526 assert(kmsg->ikm_prealloc == IP_NULL);
0a7de745 1527
1c79356b 1528 kmsg->ikm_prealloc = IP_NULL;
5ba3f43e 1529
d9a64523
A
1530 assert(port_send_turnstile(port) == TURNSTILE_NULL);
1531 kmsg->ikm_turnstile = TURNSTILE_NULL;
1c79356b
A
1532 IP_SET_PREALLOC(port, kmsg);
1533}
1534
1535/*
1536 * Routine: ipc_kmsg_clear_prealloc
1537 * Purpose:
1538 * Release the Assignment of a preallocated message buffer from a port.
1539 * Conditions:
1540 * port locked.
1541 */
1542void
1543ipc_kmsg_clear_prealloc(
0a7de745
A
1544 ipc_kmsg_t kmsg,
1545 ipc_port_t port)
1c79356b 1546{
d9a64523 1547 /* take the mqueue lock since the turnstile is protected under it */
5ba3f43e
A
1548 imq_lock(&port->ip_messages);
1549
1c79356b 1550 IP_CLEAR_PREALLOC(port, kmsg);
d9a64523 1551 set_port_send_turnstile(port, kmsg->ikm_turnstile);
5ba3f43e 1552 imq_unlock(&port->ip_messages);
1c79356b
A
1553}
1554
b7266188
A
1555/*
1556 * Routine: ipc_kmsg_prealloc
1557 * Purpose:
1558 * Wraper to ipc_kmsg_alloc() to account for
1559 * header expansion requirements.
1560 */
1561ipc_kmsg_t
1562ipc_kmsg_prealloc(mach_msg_size_t size)
1563{
1564#if defined(__LP64__)
0a7de745 1565 if (size > MACH_MSG_SIZE_MAX - LEGACY_HEADER_SIZE_DELTA) {
b7266188 1566 return IKM_NULL;
0a7de745 1567 }
b7266188
A
1568
1569 size += LEGACY_HEADER_SIZE_DELTA;
1570#endif
1571 return ipc_kmsg_alloc(size);
1572}
91447636
A
1573
1574
1c79356b
A
1575/*
1576 * Routine: ipc_kmsg_get
1577 * Purpose:
1578 * Allocates a kernel message buffer.
1579 * Copies a user message to the message buffer.
1580 * Conditions:
1581 * Nothing locked.
1582 * Returns:
1583 * MACH_MSG_SUCCESS Acquired a message buffer.
1584 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
1585 * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
316670eb 1586 * MACH_SEND_TOO_LARGE Message too large to ever be sent.
1c79356b
A
1587 * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
1588 * MACH_SEND_INVALID_DATA Couldn't copy message data.
1589 */
1590
1591mach_msg_return_t
1592ipc_kmsg_get(
0a7de745
A
1593 mach_vm_address_t msg_addr,
1594 mach_msg_size_t size,
1595 ipc_kmsg_t *kmsgp)
1c79356b 1596{
0a7de745
A
1597 mach_msg_size_t msg_and_trailer_size;
1598 ipc_kmsg_t kmsg;
1599 mach_msg_max_trailer_t *trailer;
1600 mach_msg_legacy_base_t legacy_base;
b0d623f7
A
1601 mach_msg_size_t len_copied;
1602 legacy_base.body.msgh_descriptor_count = 0;
1c79356b 1603
0a7de745 1604 if ((size < sizeof(mach_msg_legacy_header_t)) || (size & 3)) {
1c79356b 1605 return MACH_SEND_MSG_TOO_SMALL;
0a7de745 1606 }
1c79356b 1607
0a7de745 1608 if (size > ipc_kmsg_max_body_space) {
8ad349bb 1609 return MACH_SEND_TOO_LARGE;
0a7de745 1610 }
8ad349bb 1611
0a7de745 1612 if (size == sizeof(mach_msg_legacy_header_t)) {
b0d623f7 1613 len_copied = sizeof(mach_msg_legacy_header_t);
0a7de745 1614 } else {
b0d623f7 1615 len_copied = sizeof(mach_msg_legacy_base_t);
0a7de745 1616 }
1c79356b 1617
0a7de745 1618 if (copyinmsg(msg_addr, (char *)&legacy_base, len_copied)) {
b0d623f7 1619 return MACH_SEND_INVALID_DATA;
0a7de745 1620 }
b0d623f7 1621
5ba3f43e
A
1622 /*
1623 * If the message claims to be complex, it must at least
1624 * have the length of a "base" message (header + dsc_count).
1625 */
1626 if (len_copied < sizeof(mach_msg_legacy_base_t) &&
0a7de745 1627 (legacy_base.header.msgh_bits & MACH_MSGH_BITS_COMPLEX)) {
5ba3f43e 1628 return MACH_SEND_MSG_TOO_SMALL;
0a7de745 1629 }
5ba3f43e 1630
b0d623f7
A
1631 msg_addr += sizeof(legacy_base.header);
1632#if defined(__LP64__)
1633 size += LEGACY_HEADER_SIZE_DELTA;
1634#endif
fe8ab488
A
1635 /* unreachable if !DEBUG */
1636 __unreachable_ok_push
b0d623f7
A
1637 if (DEBUG_KPRINT_SYSCALL_PREDICATE(DEBUG_KPRINT_SYSCALL_IPC_MASK)) {
1638 unsigned int j;
0a7de745 1639 for (j = 0; j < sizeof(legacy_base.header); j++) {
b0d623f7
A
1640 kprintf("%02x\n", ((unsigned char*)&legacy_base.header)[j]);
1641 }
1642 }
fe8ab488 1643 __unreachable_ok_pop
1c79356b 1644
0a7de745 1645 msg_and_trailer_size = size + MAX_TRAILER_SIZE;
b0d623f7 1646 kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
0a7de745 1647 if (kmsg == IKM_NULL) {
1c79356b 1648 return MACH_SEND_NO_BUFFER;
0a7de745 1649 }
1c79356b 1650
0a7de745
A
1651 kmsg->ikm_header->msgh_size = size;
1652 kmsg->ikm_header->msgh_bits = legacy_base.header.msgh_bits;
1653 kmsg->ikm_header->msgh_remote_port = CAST_MACH_NAME_TO_PORT(legacy_base.header.msgh_remote_port);
1654 kmsg->ikm_header->msgh_local_port = CAST_MACH_NAME_TO_PORT(legacy_base.header.msgh_local_port);
1655 kmsg->ikm_header->msgh_voucher_port = legacy_base.header.msgh_voucher_port;
1656 kmsg->ikm_header->msgh_id = legacy_base.header.msgh_id;
b0d623f7
A
1657
1658 DEBUG_KPRINT_SYSCALL_IPC("ipc_kmsg_get header:\n"
0a7de745
A
1659 " size: 0x%.8x\n"
1660 " bits: 0x%.8x\n"
1661 " remote_port: %p\n"
1662 " local_port: %p\n"
1663 " voucher_port: 0x%.8x\n"
1664 " id: %.8d\n",
1665 kmsg->ikm_header->msgh_size,
1666 kmsg->ikm_header->msgh_bits,
1667 kmsg->ikm_header->msgh_remote_port,
1668 kmsg->ikm_header->msgh_local_port,
1669 kmsg->ikm_header->msgh_voucher_port,
1670 kmsg->ikm_header->msgh_id);
b0d623f7
A
1671
1672 if (copyinmsg(msg_addr, (char *)(kmsg->ikm_header + 1), size - (mach_msg_size_t)sizeof(mach_msg_header_t))) {
1c79356b
A
1673 ipc_kmsg_free(kmsg);
1674 return MACH_SEND_INVALID_DATA;
1675 }
1676
fe8ab488
A
1677 /* unreachable if !DEBUG */
1678 __unreachable_ok_push
0a7de745 1679 if (DEBUG_KPRINT_SYSCALL_PREDICATE(DEBUG_KPRINT_SYSCALL_IPC_MASK)) {
b0d623f7
A
1680 kprintf("body: size: %lu\n", (size - sizeof(mach_msg_header_t)));
1681 uint32_t i;
0a7de745
A
1682 for (i = 0; i * 4 < (size - sizeof(mach_msg_header_t)); i++) {
1683 kprintf("%.4x\n", ((uint32_t *)(kmsg->ikm_header + 1))[i]);
b0d623f7
A
1684 }
1685 }
fe8ab488 1686 __unreachable_ok_pop
b0d623f7 1687 DEBUG_IPC_KMSG_PRINT(kmsg, "ipc_kmsg_get()");
1c79356b 1688
0a7de745 1689 /*
1c79356b
A
1690 * I reserve for the trailer the largest space (MAX_TRAILER_SIZE)
1691 * However, the internal size field of the trailer (msgh_trailer_size)
1692 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to optimize
1693 * the cases where no implicit data is requested.
1694 */
91447636
A
1695 trailer = (mach_msg_max_trailer_t *) ((vm_offset_t)kmsg->ikm_header + size);
1696 trailer->msgh_sender = current_thread()->task->sec_token;
1697 trailer->msgh_audit = current_thread()->task->audit_token;
1c79356b
A
1698 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
1699 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
b0d623f7 1700
55e303ae 1701#ifdef ppc
0a7de745
A
1702 if (trcWork.traceMask) {
1703 dbgTrace(0x1100, (unsigned int)kmsg->ikm_header->msgh_id,
1704 (unsigned int)kmsg->ikm_header->msgh_remote_port,
1705 (unsigned int)kmsg->ikm_header->msgh_local_port, 0);
1706 }
55e303ae 1707#endif
2d21ac55 1708
b0d623f7 1709 trailer->msgh_labels.sender = 0;
1c79356b
A
1710 *kmsgp = kmsg;
1711 return MACH_MSG_SUCCESS;
1712}
1713
1714/*
1715 * Routine: ipc_kmsg_get_from_kernel
1716 * Purpose:
91447636
A
1717 * First checks for a preallocated message
1718 * reserved for kernel clients. If not found -
1719 * allocates a new kernel message buffer.
1c79356b
A
1720 * Copies a kernel message to the message buffer.
1721 * Only resource errors are allowed.
1722 * Conditions:
1723 * Nothing locked.
1724 * Ports in header are ipc_port_t.
1725 * Returns:
1726 * MACH_MSG_SUCCESS Acquired a message buffer.
1727 * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
1728 */
1729
1730mach_msg_return_t
1731ipc_kmsg_get_from_kernel(
0a7de745
A
1732 mach_msg_header_t *msg,
1733 mach_msg_size_t size,
1734 ipc_kmsg_t *kmsgp)
1c79356b 1735{
0a7de745
A
1736 ipc_kmsg_t kmsg;
1737 mach_msg_size_t msg_and_trailer_size;
55e303ae 1738 mach_msg_max_trailer_t *trailer;
0a7de745 1739 ipc_port_t dest_port;
1c79356b
A
1740
1741 assert(size >= sizeof(mach_msg_header_t));
316670eb 1742 assert((size & 3) == 0);
1c79356b 1743
cb323159 1744 dest_port = msg->msgh_remote_port;
1c79356b
A
1745
1746 msg_and_trailer_size = size + MAX_TRAILER_SIZE;
1747
1748 /*
1749 * See if the port has a pre-allocated kmsg for kernel
1750 * clients. These are set up for those kernel clients
1751 * which cannot afford to wait.
1752 */
6d2010ae 1753 if (IP_VALID(dest_port) && IP_PREALLOC(dest_port)) {
b7266188
A
1754 mach_msg_size_t max_desc = 0;
1755
1c79356b
A
1756 ip_lock(dest_port);
1757 if (!ip_active(dest_port)) {
1758 ip_unlock(dest_port);
1759 return MACH_SEND_NO_BUFFER;
1760 }
1761 assert(IP_PREALLOC(dest_port));
1762 kmsg = dest_port->ip_premsg;
1c79356b
A
1763 if (ikm_prealloc_inuse(kmsg)) {
1764 ip_unlock(dest_port);
1765 return MACH_SEND_NO_BUFFER;
1766 }
b7266188
A
1767#if !defined(__LP64__)
1768 if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
1769 assert(size > sizeof(mach_msg_base_t));
1770 max_desc = ((mach_msg_base_t *)msg)->body.msgh_descriptor_count *
0a7de745 1771 DESC_SIZE_ADJUSTMENT;
b7266188
A
1772 }
1773#endif
1774 if (msg_and_trailer_size > kmsg->ikm_size - max_desc) {
1775 ip_unlock(dest_port);
1776 return MACH_SEND_TOO_LARGE;
1777 }
1c79356b 1778 ikm_prealloc_set_inuse(kmsg, dest_port);
b7266188 1779 ikm_set_header(kmsg, msg_and_trailer_size);
1c79356b 1780 ip_unlock(dest_port);
0a7de745 1781 } else {
1c79356b 1782 kmsg = ipc_kmsg_alloc(msg_and_trailer_size);
0a7de745 1783 if (kmsg == IKM_NULL) {
1c79356b 1784 return MACH_SEND_NO_BUFFER;
0a7de745 1785 }
1c79356b
A
1786 }
1787
91447636 1788 (void) memcpy((void *) kmsg->ikm_header, (const void *) msg, size);
1c79356b 1789
5ba3f43e
A
1790 ikm_qos_init(kmsg);
1791
91447636 1792 kmsg->ikm_header->msgh_size = size;
1c79356b 1793
0a7de745 1794 /*
1c79356b
A
1795 * I reserve for the trailer the largest space (MAX_TRAILER_SIZE)
1796 * However, the internal size field of the trailer (msgh_trailer_size)
1797 * is initialized to the minimum (sizeof(mach_msg_trailer_t)), to
1798 * optimize the cases where no implicit data is requested.
1799 */
0a7de745
A
1800 trailer = (mach_msg_max_trailer_t *)
1801 ((vm_offset_t)kmsg->ikm_header + size);
1c79356b 1802 trailer->msgh_sender = KERNEL_SECURITY_TOKEN;
55e303ae 1803 trailer->msgh_audit = KERNEL_AUDIT_TOKEN;
1c79356b
A
1804 trailer->msgh_trailer_type = MACH_MSG_TRAILER_FORMAT_0;
1805 trailer->msgh_trailer_size = MACH_MSG_TRAILER_MINIMUM_SIZE;
1806
2d21ac55
A
1807 trailer->msgh_labels.sender = 0;
1808
1c79356b
A
1809 *kmsgp = kmsg;
1810 return MACH_MSG_SUCCESS;
1811}
1812
1813/*
1814 * Routine: ipc_kmsg_send
1815 * Purpose:
1816 * Send a message. The message holds a reference
1817 * for the destination port in the msgh_remote_port field.
1818 *
1819 * If unsuccessful, the caller still has possession of
1820 * the message and must do something with it. If successful,
1821 * the message is queued, given to a receiver, destroyed,
1822 * or handled directly by the kernel via mach_msg.
1823 * Conditions:
1824 * Nothing locked.
1825 * Returns:
1826 * MACH_MSG_SUCCESS The message was accepted.
1827 * MACH_SEND_TIMED_OUT Caller still has message.
1828 * MACH_SEND_INTERRUPTED Caller still has message.
6d2010ae 1829 * MACH_SEND_INVALID_DEST Caller still has message.
1c79356b
A
1830 */
1831mach_msg_return_t
1832ipc_kmsg_send(
0a7de745
A
1833 ipc_kmsg_t kmsg,
1834 mach_msg_option_t option,
1835 mach_msg_timeout_t send_timeout)
1c79356b 1836{
1c79356b 1837 ipc_port_t port;
3e170ce0 1838 thread_t th = current_thread();
b0d623f7 1839 mach_msg_return_t error = MACH_MSG_SUCCESS;
4bd07ac2 1840 boolean_t kernel_reply = FALSE;
91447636 1841
3e170ce0
A
1842 /* Check if honor qlimit flag is set on thread. */
1843 if ((th->options & TH_OPT_HONOR_QLIMIT) == TH_OPT_HONOR_QLIMIT) {
1844 /* Remove the MACH_SEND_ALWAYS flag to honor queue limit. */
1845 option &= (~MACH_SEND_ALWAYS);
1846 /* Add the timeout flag since the message queue might be full. */
1847 option |= MACH_SEND_TIMEOUT;
1848 th->options &= (~TH_OPT_HONOR_QLIMIT);
1849 }
1850
39236c6e 1851#if IMPORTANCE_INHERITANCE
d9a64523 1852 bool did_importance = false;
5ba3f43e 1853#if IMPORTANCE_TRACE
39236c6e
A
1854 mach_msg_id_t imp_msgh_id = -1;
1855 int sender_pid = -1;
5ba3f43e 1856#endif /* IMPORTANCE_TRACE */
39236c6e
A
1857#endif /* IMPORTANCE_INHERITANCE */
1858
1859 /* don't allow the creation of a circular loop */
1860 if (kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
1861 ipc_kmsg_destroy(kmsg);
0a7de745 1862 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, MACH_MSGH_BITS_CIRCULAR);
39236c6e
A
1863 return MACH_MSG_SUCCESS;
1864 }
1865
490019cf
A
1866 ipc_voucher_send_preprocessing(kmsg);
1867
cb323159 1868 port = kmsg->ikm_header->msgh_remote_port;
1c79356b 1869 assert(IP_VALID(port));
1c79356b
A
1870 ip_lock(port);
1871
cb323159
A
1872 /*
1873 * If the destination has been guarded with a reply context, and the
1874 * sender is consuming a send-once right, then assume this is a reply
1875 * to an RPC and we need to validate that this sender is currently in
1876 * the correct context.
1877 */
1878 if (enforce_strict_reply && port->ip_reply_context != 0 &&
1879 ((option & MACH_SEND_KERNEL) == 0) &&
1880 MACH_MSGH_BITS_REMOTE(kmsg->ikm_header->msgh_bits) == MACH_MSG_TYPE_PORT_SEND_ONCE) {
1881 error = ipc_kmsg_validate_reply_context_locked(option, port, th->ith_voucher, th->ith_voucher_name);
1882 if (error != MACH_MSG_SUCCESS) {
1883 ip_unlock(port);
1884 return error;
1885 }
1886 }
1887
fe8ab488
A
1888#if IMPORTANCE_INHERITANCE
1889retry:
1890#endif /* IMPORTANCE_INHERITANCE */
1891 /*
1892 * Can't deliver to a dead port.
1893 * However, we can pretend it got sent
1894 * and was then immediately destroyed.
1895 */
1896 if (!ip_active(port)) {
1897 ip_unlock(port);
39037602 1898#if MACH_FLIPC
0a7de745
A
1899 if (MACH_NODE_VALID(kmsg->ikm_node) && FPORT_VALID(port->ip_messages.imq_fport)) {
1900 flipc_msg_ack(kmsg->ikm_node, &port->ip_messages, FALSE);
1901 }
39037602 1902#endif
d9a64523
A
1903 if (did_importance) {
1904 /*
1905 * We're going to pretend we delivered this message
1906 * successfully, and just eat the kmsg. However, the
1907 * kmsg is actually visible via the importance_task!
1908 * We need to cleanup this linkage before we destroy
1909 * the message, and more importantly before we set the
1910 * msgh_remote_port to NULL. See: 34302571
1911 */
1912 ipc_importance_clean(kmsg);
1913 }
fe8ab488
A
1914 ip_release(port); /* JMM - Future: release right, not just ref */
1915 kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL;
1916 ipc_kmsg_destroy(kmsg);
0a7de745 1917 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, MACH_SEND_INVALID_DEST);
fe8ab488
A
1918 return MACH_MSG_SUCCESS;
1919 }
1920
1c79356b 1921 if (port->ip_receiver == ipc_space_kernel) {
1c79356b
A
1922 /*
1923 * We can check ip_receiver == ipc_space_kernel
1924 * before checking that the port is active because
1925 * ipc_port_dealloc_kernel clears ip_receiver
1926 * before destroying a kernel port.
1927 */
cb323159 1928 require_ip_active(port);
1c79356b
A
1929 port->ip_messages.imq_seqno++;
1930 ip_unlock(port);
1931
1932 current_task()->messages_sent++;
1933
1934 /*
1935 * Call the server routine, and get the reply message to send.
1936 */
39037602 1937 kmsg = ipc_kobject_server(kmsg, option);
0a7de745 1938 if (kmsg == IKM_NULL) {
1c79356b 1939 return MACH_MSG_SUCCESS;
0a7de745 1940 }
1c79356b 1941
39037602 1942 /* restart the KMSG_INFO tracing for the reply message */
0a7de745 1943 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
cb323159 1944 port = kmsg->ikm_header->msgh_remote_port;
1c79356b
A
1945 assert(IP_VALID(port));
1946 ip_lock(port);
1947 /* fall thru with reply - same options */
4bd07ac2 1948 kernel_reply = TRUE;
0a7de745 1949 if (!ip_active(port)) {
39037602 1950 error = MACH_SEND_INVALID_DEST;
0a7de745 1951 }
1c79356b
A
1952 }
1953
39236c6e
A
1954#if IMPORTANCE_INHERITANCE
1955 /*
1956 * Need to see if this message needs importance donation and/or
fe8ab488
A
1957 * propagation. That routine can drop the port lock temporarily.
1958 * If it does we'll have to revalidate the destination.
39236c6e 1959 */
d9a64523
A
1960 if (!did_importance) {
1961 did_importance = true;
0a7de745
A
1962 if (ipc_importance_send(kmsg, option)) {
1963 goto retry;
1964 }
1c79356b 1965 }
39236c6e 1966#endif /* IMPORTANCE_INHERITANCE */
1c79356b 1967
39037602
A
1968 if (error != MACH_MSG_SUCCESS) {
1969 ip_unlock(port);
1970 } else {
1971 /*
1972 * We have a valid message and a valid reference on the port.
1973 * we can unlock the port and call mqueue_send() on its message
1974 * queue. Lock message queue while port is locked.
1975 */
1976 imq_lock(&port->ip_messages);
d9a64523 1977
cb323159 1978 ipc_special_reply_port_msg_sent(port);
d9a64523 1979
39037602 1980 ip_unlock(port);
39236c6e 1981
39037602 1982 error = ipc_mqueue_send(&port->ip_messages, kmsg, option,
0a7de745 1983 send_timeout);
39037602 1984 }
b0d623f7 1985
39236c6e 1986#if IMPORTANCE_INHERITANCE
d9a64523 1987 if (did_importance) {
39236c6e
A
1988 __unused int importance_cleared = 0;
1989 switch (error) {
0a7de745
A
1990 case MACH_SEND_TIMED_OUT:
1991 case MACH_SEND_NO_BUFFER:
1992 case MACH_SEND_INTERRUPTED:
1993 case MACH_SEND_INVALID_DEST:
1994 /*
1995 * We still have the kmsg and its
1996 * reference on the port. But we
1997 * have to back out the importance
1998 * boost.
1999 *
2000 * The port could have changed hands,
2001 * be inflight to another destination,
2002 * etc... But in those cases our
2003 * back-out will find the new owner
2004 * (and all the operations that
2005 * transferred the right should have
2006 * applied their own boost adjustments
2007 * to the old owner(s)).
2008 */
2009 importance_cleared = 1;
2010 ipc_importance_clean(kmsg);
2011 break;
39236c6e 2012
0a7de745
A
2013 case MACH_MSG_SUCCESS:
2014 default:
2015 break;
39236c6e 2016 }
5ba3f43e 2017#if IMPORTANCE_TRACE
39236c6e 2018 KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_MSG, IMP_MSG_SEND)) | DBG_FUNC_END,
0a7de745 2019 task_pid(current_task()), sender_pid, imp_msgh_id, importance_cleared, 0);
5ba3f43e 2020#endif /* IMPORTANCE_TRACE */
39236c6e
A
2021 }
2022#endif /* IMPORTANCE_INHERITANCE */
2023
b0d623f7
A
2024 /*
2025 * If the port has been destroyed while we wait, treat the message
2026 * as a successful delivery (like we do for an inactive port).
2027 */
2028 if (error == MACH_SEND_INVALID_DEST) {
39037602 2029#if MACH_FLIPC
0a7de745
A
2030 if (MACH_NODE_VALID(kmsg->ikm_node) && FPORT_VALID(port->ip_messages.imq_fport)) {
2031 flipc_msg_ack(kmsg->ikm_node, &port->ip_messages, FALSE);
2032 }
39037602 2033#endif
fe8ab488 2034 ip_release(port); /* JMM - Future: release right, not just ref */
b0d623f7
A
2035 kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL;
2036 ipc_kmsg_destroy(kmsg);
0a7de745 2037 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, MACH_SEND_INVALID_DEST);
b0d623f7
A
2038 return MACH_MSG_SUCCESS;
2039 }
4bd07ac2
A
2040
2041 if (error != MACH_MSG_SUCCESS && kernel_reply) {
2042 /*
2043 * Kernel reply messages that fail can't be allowed to
2044 * pseudo-receive on error conditions. We need to just treat
2045 * the message as a successful delivery.
2046 */
39037602 2047#if MACH_FLIPC
0a7de745
A
2048 if (MACH_NODE_VALID(kmsg->ikm_node) && FPORT_VALID(port->ip_messages.imq_fport)) {
2049 flipc_msg_ack(kmsg->ikm_node, &port->ip_messages, FALSE);
2050 }
39037602 2051#endif
4bd07ac2
A
2052 ip_release(port); /* JMM - Future: release right, not just ref */
2053 kmsg->ikm_header->msgh_remote_port = MACH_PORT_NULL;
2054 ipc_kmsg_destroy(kmsg);
0a7de745 2055 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, error);
4bd07ac2
A
2056 return MACH_MSG_SUCCESS;
2057 }
b0d623f7 2058 return error;
1c79356b
A
2059}
2060
2061/*
2062 * Routine: ipc_kmsg_put
2063 * Purpose:
2064 * Copies a message buffer to a user message.
2065 * Copies only the specified number of bytes.
2066 * Frees the message buffer.
2067 * Conditions:
2068 * Nothing locked. The message buffer must have clean
2069 * header fields.
2070 * Returns:
2071 * MACH_MSG_SUCCESS Copied data out of message buffer.
2072 * MACH_RCV_INVALID_DATA Couldn't copy to user message.
2073 */
2074
2075mach_msg_return_t
2076ipc_kmsg_put(
0a7de745
A
2077 ipc_kmsg_t kmsg,
2078 mach_msg_option_t option,
2079 mach_vm_address_t rcv_addr,
2080 mach_msg_size_t rcv_size,
2081 mach_msg_size_t trailer_size,
2082 mach_msg_size_t *sizep)
1c79356b 2083{
39037602 2084 mach_msg_size_t size = kmsg->ikm_header->msgh_size + trailer_size;
1c79356b
A
2085 mach_msg_return_t mr;
2086
b0d623f7
A
2087 DEBUG_IPC_KMSG_PRINT(kmsg, "ipc_kmsg_put()");
2088
2089
2090 DEBUG_KPRINT_SYSCALL_IPC("ipc_kmsg_put header:\n"
0a7de745
A
2091 " size: 0x%.8x\n"
2092 " bits: 0x%.8x\n"
2093 " remote_port: %p\n"
2094 " local_port: %p\n"
2095 " voucher_port: 0x%.8x\n"
2096 " id: %.8d\n",
2097 kmsg->ikm_header->msgh_size,
2098 kmsg->ikm_header->msgh_bits,
2099 kmsg->ikm_header->msgh_remote_port,
2100 kmsg->ikm_header->msgh_local_port,
2101 kmsg->ikm_header->msgh_voucher_port,
2102 kmsg->ikm_header->msgh_id);
b0d623f7
A
2103
2104#if defined(__LP64__)
d9a64523 2105 if (current_task() != kernel_task) { /* don't if receiver expects fully-cooked in-kernel msg; */
0a7de745
A
2106 mach_msg_legacy_header_t *legacy_header =
2107 (mach_msg_legacy_header_t *)((vm_offset_t)(kmsg->ikm_header) + LEGACY_HEADER_SIZE_DELTA);
b0d623f7 2108
0a7de745
A
2109 mach_msg_bits_t bits = kmsg->ikm_header->msgh_bits;
2110 mach_msg_size_t msg_size = kmsg->ikm_header->msgh_size;
2111 mach_port_name_t remote_port = CAST_MACH_PORT_TO_NAME(kmsg->ikm_header->msgh_remote_port);
2112 mach_port_name_t local_port = CAST_MACH_PORT_TO_NAME(kmsg->ikm_header->msgh_local_port);
2113 mach_port_name_t voucher_port = kmsg->ikm_header->msgh_voucher_port;
2114 mach_msg_id_t id = kmsg->ikm_header->msgh_id;
b0d623f7 2115
0a7de745 2116 legacy_header->msgh_id = id;
fe8ab488
A
2117 legacy_header->msgh_local_port = local_port;
2118 legacy_header->msgh_remote_port = remote_port;
2119 legacy_header->msgh_voucher_port = voucher_port;
0a7de745
A
2120 legacy_header->msgh_size = msg_size - LEGACY_HEADER_SIZE_DELTA;
2121 legacy_header->msgh_bits = bits;
b0d623f7
A
2122
2123 size -= LEGACY_HEADER_SIZE_DELTA;
2124 kmsg->ikm_header = (mach_msg_header_t *)legacy_header;
2125 }
2126#endif
2127
fe8ab488
A
2128 /* unreachable if !DEBUG */
2129 __unreachable_ok_push
b0d623f7
A
2130 if (DEBUG_KPRINT_SYSCALL_PREDICATE(DEBUG_KPRINT_SYSCALL_IPC_MASK)) {
2131 kprintf("ipc_kmsg_put header+body: %d\n", (size));
2132 uint32_t i;
0a7de745
A
2133 for (i = 0; i * 4 < size; i++) {
2134 kprintf("%.4x\n", ((uint32_t *)kmsg->ikm_header)[i]);
b0d623f7 2135 }
0a7de745 2136 kprintf("type: %d\n", ((mach_msg_type_descriptor_t *)(((mach_msg_base_t *)kmsg->ikm_header) + 1))->type);
b0d623f7 2137 }
fe8ab488 2138 __unreachable_ok_pop
39037602 2139
0a7de745 2140 /* Re-Compute target address if using stack-style delivery */
39037602
A
2141 if (option & MACH_RCV_STACK) {
2142 rcv_addr += rcv_size - size;
2143 }
2144
2145 if (copyoutmsg((const char *) kmsg->ikm_header, rcv_addr, size)) {
1c79356b 2146 mr = MACH_RCV_INVALID_DATA;
39037602 2147 size = 0;
0a7de745 2148 } else {
1c79356b 2149 mr = MACH_MSG_SUCCESS;
0a7de745 2150 }
1c79356b 2151
0a7de745
A
2152 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_LINK) | DBG_FUNC_NONE,
2153 (rcv_addr >= VM_MIN_KERNEL_AND_KEXT_ADDRESS ||
2154 rcv_addr + size >= VM_MIN_KERNEL_AND_KEXT_ADDRESS) ? (uintptr_t)0 : (uintptr_t)rcv_addr,
2155 VM_KERNEL_ADDRPERM((uintptr_t)kmsg),
2156 1 /* this is on the receive/copyout path */,
2157 0,
2158 0);
1c79356b 2159 ipc_kmsg_free(kmsg);
39037602 2160
0a7de745 2161 if (sizep) {
39037602 2162 *sizep = size;
0a7de745 2163 }
1c79356b
A
2164 return mr;
2165}
2166
2167/*
2168 * Routine: ipc_kmsg_put_to_kernel
2169 * Purpose:
2170 * Copies a message buffer to a kernel message.
2171 * Frees the message buffer.
2172 * No errors allowed.
2173 * Conditions:
2174 * Nothing locked.
2175 */
2176
2177void
2178ipc_kmsg_put_to_kernel(
0a7de745
A
2179 mach_msg_header_t *msg,
2180 ipc_kmsg_t kmsg,
2181 mach_msg_size_t size)
1c79356b 2182{
91447636 2183 (void) memcpy((void *) msg, (const void *) kmsg->ikm_header, size);
1c79356b
A
2184
2185 ipc_kmsg_free(kmsg);
2186}
2187
d9a64523
A
2188static mach_msg_priority_t
2189ipc_get_current_thread_priority(void)
2190{
2191 thread_t thread = current_thread();
2192 thread_qos_t qos;
2193 int relpri;
2194
2195 qos = thread_get_requested_qos(thread, &relpri);
2196 if (!qos) {
2197 qos = thread_user_promotion_qos_for_pri(thread->base_pri);
2198 relpri = 0;
2199 }
2200 return (mach_msg_priority_t)_pthread_priority_make_from_thread_qos(qos, relpri, 0);
2201}
39037602 2202
5ba3f43e 2203static kern_return_t
39037602
A
2204ipc_kmsg_set_qos(
2205 ipc_kmsg_t kmsg,
2206 mach_msg_option_t options,
2207 mach_msg_priority_t override)
2208{
2209 kern_return_t kr;
5ba3f43e
A
2210 ipc_port_t special_reply_port = kmsg->ikm_header->msgh_local_port;
2211 ipc_port_t dest_port = kmsg->ikm_header->msgh_remote_port;
39037602
A
2212
2213 kr = ipc_get_pthpriority_from_kmsg_voucher(kmsg, &kmsg->ikm_qos);
2214 if (kr != KERN_SUCCESS) {
d9a64523
A
2215 if (options & MACH_SEND_PROPAGATE_QOS) {
2216 kmsg->ikm_qos = ipc_get_current_thread_priority();
2217 } else {
2218 kmsg->ikm_qos = MACH_MSG_PRIORITY_UNSPECIFIED;
2219 }
39037602
A
2220 }
2221 kmsg->ikm_qos_override = kmsg->ikm_qos;
2222
2223 if (options & MACH_SEND_OVERRIDE) {
d9a64523 2224 pthread_priority_t pp = _pthread_priority_normalize_for_ipc(override);
0a7de745 2225 if (pp > kmsg->ikm_qos) {
d9a64523 2226 kmsg->ikm_qos_override = (mach_msg_priority_t)pp;
0a7de745 2227 }
39037602 2228 }
5ba3f43e
A
2229
2230 kr = KERN_SUCCESS;
cb323159
A
2231
2232 if (IP_VALID(special_reply_port) &&
2233 MACH_MSGH_BITS_LOCAL(kmsg->ikm_header->msgh_bits) == MACH_MSG_TYPE_PORT_SEND_ONCE) {
2234 if ((options & MACH_SEND_SYNC_OVERRIDE)) {
2235 boolean_t sync_bootstrap_checkin = !!(options & MACH_SEND_SYNC_BOOTSTRAP_CHECKIN);
5ba3f43e 2236 /*
d9a64523
A
2237 * Link the destination port to special reply port and make sure that
2238 * dest port has a send turnstile, else allocate one.
5ba3f43e 2239 */
cb323159 2240 ipc_port_link_special_reply_port(special_reply_port, dest_port, sync_bootstrap_checkin);
5ba3f43e
A
2241 }
2242 }
2243 return kr;
39037602
A
2244}
2245
cb323159
A
2246static inline void
2247ipc_kmsg_allow_immovable_send(
2248 ipc_kmsg_t kmsg,
2249 ipc_entry_t dest_entry)
2250{
2251 ipc_object_t object = dest_entry->ie_object;
2252 /*
2253 * If the dest port is a kobject, allow copyin of immovable send
2254 * rights in the message body to succeed
2255 */
2256 if (IO_VALID(object) && io_is_kobject(object)) {
2257 kmsg->ikm_flags |= IPC_KMSG_FLAGS_ALLOW_IMMOVABLE_SEND;
2258 }
2259}
2260
2261/*
2262 * Routine: ipc_kmsg_link_reply_context_locked
2263 * Purpose:
2264 * Link any required context from the sending voucher
2265 * to the reply port. The ipc_kmsg_copyin function will
2266 * enforce that the sender calls mach_msg in this context.
2267 * Conditions:
2268 * reply port is locked
2269 */
2270static void
2271ipc_kmsg_link_reply_context_locked(
2272 ipc_port_t reply_port,
2273 ipc_port_t voucher_port)
2274{
2275 kern_return_t __assert_only kr;
2276 uint32_t persona_id = 0;
2277 ipc_voucher_t voucher;
2278
2279 ip_lock_held(reply_port);
2280
2281 if (!ip_active(reply_port)) {
2282 return;
2283 }
2284
2285 voucher = convert_port_to_voucher(voucher_port);
2286
2287 kr = bank_get_bank_ledger_thread_group_and_persona(voucher, NULL, NULL, &persona_id);
2288 assert(kr == KERN_SUCCESS);
2289 ipc_voucher_release(voucher);
2290
2291 if (persona_id == 0 || persona_id == PERSONA_ID_NONE) {
2292 /* there was no persona context to record */
2293 return;
2294 }
2295
2296 /*
2297 * Set the persona_id as the context on the reply port.
2298 * This will force the thread that replies to have adopted a voucher
2299 * with a matching persona.
2300 */
2301 reply_port->ip_reply_context = persona_id;
2302
2303 return;
2304}
2305
2306static kern_return_t
2307ipc_kmsg_validate_reply_port_locked(ipc_port_t reply_port, mach_msg_option_t options)
2308{
2309 ip_lock_held(reply_port);
2310
2311 if (!ip_active(reply_port)) {
2312 /*
2313 * Ideally, we would enforce that the reply receive right is
2314 * active, but asynchronous XPC cancellation destroys the
2315 * receive right, so we just have to return success here.
2316 */
2317 return KERN_SUCCESS;
2318 }
2319
2320 if (options & MACH_SEND_MSG) {
2321 /*
2322 * If the rely port is active, then it should not be
2323 * in-transit, and the receive right should be in the caller's
2324 * IPC space.
2325 */
2326 if (!reply_port->ip_receiver_name || reply_port->ip_receiver != current_task()->itk_space) {
2327 return KERN_INVALID_CAPABILITY;
2328 }
2329
2330 /*
2331 * A port used as a reply port in an RPC should have exactly 1
2332 * extant send-once right which we either just made or are
2333 * moving as part of the IPC.
2334 */
2335 if (reply_port->ip_sorights != 1) {
2336 return KERN_INVALID_CAPABILITY;
2337 }
2338 /*
2339 * XPC uses an extra send-right to keep the name of the reply
2340 * right around through cancellation. That makes it harder to
2341 * enforce a particular semantic kere, so for now, we say that
2342 * you can have a maximum of 1 send right (in addition to your
2343 * send once right). In the future, it would be great to lock
2344 * this down even further.
2345 */
2346 if (reply_port->ip_srights > 1) {
2347 return KERN_INVALID_CAPABILITY;
2348 }
2349
2350 /*
2351 * The sender can also specify that the receive right should
2352 * be immovable. Note that this check only applies to
2353 * send-only operations. Combined send/receive or rcv-only
2354 * operations can specify an immovable receive right by
2355 * opt-ing into guarded descriptors (MACH_RCV_GUARDED_DESC)
2356 * and using the MACH_MSG_STRICT_REPLY options flag.
2357 */
2358 if (MACH_SEND_REPLY_IS_IMMOVABLE(options)) {
2359 if (!reply_port->ip_immovable_receive) {
2360 return KERN_INVALID_CAPABILITY;
2361 }
2362 }
2363 }
2364
2365 /*
2366 * don't enforce this yet: need a better way of indicating the
2367 * receiver wants this...
2368 */
2369#if 0
2370 if (MACH_RCV_WITH_IMMOVABLE_REPLY(options)) {
2371 if (!reply_port->ip_immovable_receive) {
2372 return KERN_INVALID_CAPABILITY;
2373 }
2374 }
2375#endif /* 0 */
2376
2377 return KERN_SUCCESS;
2378}
2379
2380/*
2381 * Routine: ipc_kmsg_validate_reply_context_locked
2382 * Purpose:
2383 * Validate that the current thread is running in the context
2384 * required by the destination port.
2385 * Conditions:
2386 * dest_port is locked
2387 * Returns:
2388 * MACH_MSG_SUCCESS on success.
2389 * On error, an EXC_GUARD exception is also raised.
2390 * This function *always* resets the port reply context.
2391 */
2392static mach_msg_return_t
2393ipc_kmsg_validate_reply_context_locked(
2394 mach_msg_option_t option,
2395 ipc_port_t dest_port,
2396 ipc_voucher_t voucher,
2397 mach_port_name_t voucher_name)
2398{
2399 uint32_t dest_ctx = dest_port->ip_reply_context;
2400 dest_port->ip_reply_context = 0;
2401
2402 if (!ip_active(dest_port)) {
2403 return MACH_MSG_SUCCESS;
2404 }
2405
2406 if (voucher == IPC_VOUCHER_NULL || !MACH_PORT_VALID(voucher_name)) {
2407 if ((option & MACH_SEND_KERNEL) == 0) {
2408 mach_port_guard_exception(voucher_name, 0,
2409 (MPG_FLAGS_STRICT_REPLY_INVALID_VOUCHER | dest_ctx),
2410 kGUARD_EXC_STRICT_REPLY);
2411 }
2412 return MACH_SEND_INVALID_CONTEXT;
2413 }
2414
2415 kern_return_t __assert_only kr;
2416 uint32_t persona_id = 0;
2417 kr = bank_get_bank_ledger_thread_group_and_persona(voucher, NULL, NULL, &persona_id);
2418 assert(kr == KERN_SUCCESS);
2419
2420 if (dest_ctx != persona_id) {
2421 if ((option & MACH_SEND_KERNEL) == 0) {
2422 mach_port_guard_exception(voucher_name, 0,
2423 (MPG_FLAGS_STRICT_REPLY_MISMATCHED_PERSONA | ((((uint64_t)persona_id << 32) & MPG_FLAGS_STRICT_REPLY_MASK) | dest_ctx)),
2424 kGUARD_EXC_STRICT_REPLY);
2425 }
2426 return MACH_SEND_INVALID_CONTEXT;
2427 }
2428
2429 return MACH_MSG_SUCCESS;
2430}
2431
1c79356b
A
2432/*
2433 * Routine: ipc_kmsg_copyin_header
2434 * Purpose:
2435 * "Copy-in" port rights in the header of a message.
2436 * Operates atomically; if it doesn't succeed the
2437 * message header and the space are left untouched.
2438 * If it does succeed the remote/local port fields
2439 * contain object pointers instead of port names,
2440 * and the bits field is updated. The destination port
2441 * will be a valid port pointer.
2442 *
1c79356b
A
2443 * Conditions:
2444 * Nothing locked.
2445 * Returns:
2446 * MACH_MSG_SUCCESS Successful copyin.
2447 * MACH_SEND_INVALID_HEADER
2448 * Illegal value in the message header bits.
2449 * MACH_SEND_INVALID_DEST The space is dead.
1c79356b
A
2450 * MACH_SEND_INVALID_DEST Can't copyin destination port.
2451 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
2452 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
2453 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
2454 */
2455
2456mach_msg_return_t
2457ipc_kmsg_copyin_header(
fe8ab488 2458 ipc_kmsg_t kmsg,
0a7de745 2459 ipc_space_t space,
39037602 2460 mach_msg_priority_t override,
0a7de745 2461 mach_msg_option_t *optionp)
1c79356b 2462{
fe8ab488 2463 mach_msg_header_t *msg = kmsg->ikm_header;
1c79356b 2464 mach_msg_bits_t mbits = msg->msgh_bits & MACH_MSGH_BITS_USER;
b0d623f7
A
2465 mach_port_name_t dest_name = CAST_MACH_PORT_TO_NAME(msg->msgh_remote_port);
2466 mach_port_name_t reply_name = CAST_MACH_PORT_TO_NAME(msg->msgh_local_port);
fe8ab488 2467 mach_port_name_t voucher_name = MACH_PORT_NULL;
1c79356b
A
2468 kern_return_t kr;
2469
2470 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2471 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
fe8ab488
A
2472 mach_msg_type_name_t voucher_type = MACH_MSGH_BITS_VOUCHER(mbits);
2473 ipc_object_t dest_port = IO_NULL;
2474 ipc_object_t reply_port = IO_NULL;
2475 ipc_port_t dest_soright = IP_NULL;
2476 ipc_port_t reply_soright = IP_NULL;
2477 ipc_port_t voucher_soright = IP_NULL;
316670eb 2478 ipc_port_t release_port = IP_NULL;
fe8ab488
A
2479 ipc_port_t voucher_port = IP_NULL;
2480 ipc_port_t voucher_release_port = IP_NULL;
2481 ipc_entry_t dest_entry = IE_NULL;
2482 ipc_entry_t reply_entry = IE_NULL;
2483 ipc_entry_t voucher_entry = IE_NULL;
316670eb 2484
39236c6e 2485 int assertcnt = 0;
3e170ce0 2486#if IMPORTANCE_INHERITANCE
39236c6e
A
2487 boolean_t needboost = FALSE;
2488#endif /* IMPORTANCE_INHERITANCE */
2489
1c79356b
A
2490 if ((mbits != msg->msgh_bits) ||
2491 (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type)) ||
2492 ((reply_type == 0) ?
0a7de745
A
2493 (reply_name != MACH_PORT_NULL) :
2494 !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))) {
1c79356b 2495 return MACH_SEND_INVALID_HEADER;
0a7de745 2496 }
1c79356b 2497
0a7de745 2498 if (!MACH_PORT_VALID(dest_name)) {
fe8ab488 2499 return MACH_SEND_INVALID_DEST;
0a7de745 2500 }
1c79356b
A
2501
2502 is_write_lock(space);
fe8ab488
A
2503 if (!is_active(space)) {
2504 is_write_unlock(space);
2505 return MACH_SEND_INVALID_DEST;
2506 }
2507 /* space locked and active */
1c79356b 2508
2d21ac55 2509 /*
fe8ab488
A
2510 * If there is a voucher specified, make sure the disposition is
2511 * valid and the entry actually refers to a voucher port. Don't
2512 * actually copy in until we validate destination and reply.
2d21ac55 2513 */
fe8ab488 2514 if (voucher_type != MACH_MSGH_BITS_ZERO) {
fe8ab488
A
2515 voucher_name = msg->msgh_voucher_port;
2516
2517 if (voucher_name == MACH_PORT_DEAD ||
2518 (voucher_type != MACH_MSG_TYPE_MOVE_SEND &&
0a7de745 2519 voucher_type != MACH_MSG_TYPE_COPY_SEND)) {
fe8ab488 2520 is_write_unlock(space);
d9a64523
A
2521 if ((*optionp & MACH_SEND_KERNEL) == 0) {
2522 mach_port_guard_exception(voucher_name, 0, 0, kGUARD_EXC_SEND_INVALID_VOUCHER);
2523 }
fe8ab488
A
2524 return MACH_SEND_INVALID_VOUCHER;
2525 }
2526
2527 if (voucher_name != MACH_PORT_NULL) {
2528 voucher_entry = ipc_entry_lookup(space, voucher_name);
0a7de745 2529 if (voucher_entry == IE_NULL ||
fe8ab488
A
2530 (voucher_entry->ie_bits & MACH_PORT_TYPE_SEND) == 0 ||
2531 io_kotype(voucher_entry->ie_object) != IKOT_VOUCHER) {
2532 is_write_unlock(space);
d9a64523
A
2533 if ((*optionp & MACH_SEND_KERNEL) == 0) {
2534 mach_port_guard_exception(voucher_name, 0, 0, kGUARD_EXC_SEND_INVALID_VOUCHER);
2535 }
fe8ab488
A
2536 return MACH_SEND_INVALID_VOUCHER;
2537 }
2538 } else {
2539 voucher_type = MACH_MSG_TYPE_MOVE_SEND;
2d21ac55 2540 }
2d21ac55 2541 }
1c79356b 2542
cb323159
A
2543 if (enforce_strict_reply && MACH_SEND_WITH_STRICT_REPLY(*optionp) &&
2544 (!MACH_PORT_VALID(reply_name) ||
2545 ((reply_type != MACH_MSG_TYPE_MAKE_SEND_ONCE) && (reply_type != MACH_MSG_TYPE_MOVE_SEND_ONCE))
2546 )) {
2547 /*
2548 * The caller cannot enforce a reply context with an invalid
2549 * reply port name, or a non-send_once reply disposition.
2550 */
2551 is_write_unlock(space);
2552 if ((*optionp & MACH_SEND_KERNEL) == 0) {
2553 mach_port_guard_exception(reply_name, 0,
2554 (MPG_FLAGS_STRICT_REPLY_INVALID_REPLY_DISP | reply_type),
2555 kGUARD_EXC_STRICT_REPLY);
2556 }
2557 return MACH_SEND_INVALID_REPLY;
2558 }
2559
fe8ab488
A
2560 /*
2561 * Handle combinations of validating destination and reply; along
2562 * with copying in destination, reply, and voucher in an atomic way.
2563 */
2564
2565 if (dest_name == voucher_name) {
1c79356b 2566 /*
fe8ab488
A
2567 * If the destination name is the same as the voucher name,
2568 * the voucher_entry must already be known. Either that or
2569 * the destination name is MACH_PORT_NULL (i.e. invalid).
1c79356b 2570 */
fe8ab488
A
2571 dest_entry = voucher_entry;
2572 if (dest_entry == IE_NULL) {
1c79356b 2573 goto invalid_dest;
fe8ab488 2574 }
cb323159
A
2575 /* Check if dest port allows immovable send rights to be sent in the kmsg body */
2576 ipc_kmsg_allow_immovable_send(kmsg, dest_entry);
1c79356b 2577
fe8ab488
A
2578 /*
2579 * Make sure a future copyin of the reply port will succeed.
2580 * Once we start copying in the dest/voucher pair, we can't
2581 * back out.
2582 */
2583 if (MACH_PORT_VALID(reply_name)) {
2584 assert(reply_type != 0); /* because reply_name not null */
1c79356b 2585
fe8ab488
A
2586 /* It is just WRONG if dest, voucher, and reply are all the same. */
2587 if (voucher_name == reply_name) {
2588 goto invalid_reply;
2589 }
2590 reply_entry = ipc_entry_lookup(space, reply_name);
2591 if (reply_entry == IE_NULL) {
2592 goto invalid_reply;
2593 }
2594 assert(dest_entry != reply_entry); /* names are not equal */
cb323159 2595 if (!ipc_right_copyin_check_reply(space, reply_name, reply_entry, reply_type)) {
fe8ab488
A
2596 goto invalid_reply;
2597 }
2598 }
1c79356b 2599
0a7de745
A
2600 /*
2601 * Do the joint copyin of the dest disposition and
fe8ab488
A
2602 * voucher disposition from the one entry/port. We
2603 * already validated that the voucher copyin would
2604 * succeed (above). So, any failure in combining
2605 * the copyins can be blamed on the destination.
2606 */
2607 kr = ipc_right_copyin_two(space, dest_name, dest_entry,
cb323159 2608 dest_type, voucher_type, &dest_port, &dest_soright,
0a7de745 2609 &release_port);
fe8ab488
A
2610 if (kr != KERN_SUCCESS) {
2611 assert(kr != KERN_INVALID_CAPABILITY);
1c79356b 2612 goto invalid_dest;
fe8ab488 2613 }
cb323159 2614 voucher_port = ip_object_to_port(dest_port);
1c79356b 2615
0a7de745
A
2616 /*
2617 * could not have been one of these dispositions,
fe8ab488
A
2618 * validated the port was a true kernel voucher port above,
2619 * AND was successfully able to copyin both dest and voucher.
2620 */
2621 assert(dest_type != MACH_MSG_TYPE_MAKE_SEND);
2622 assert(dest_type != MACH_MSG_TYPE_MAKE_SEND_ONCE);
2623 assert(dest_type != MACH_MSG_TYPE_MOVE_SEND_ONCE);
0a7de745 2624
fe8ab488
A
2625 /*
2626 * Perform the delayed reply right copyin (guaranteed success).
2627 */
2628 if (reply_entry != IE_NULL) {
fe8ab488 2629 kr = ipc_right_copyin(space, reply_name, reply_entry,
0a7de745
A
2630 reply_type, IPC_RIGHT_COPYIN_FLAGS_DEADOK,
2631 &reply_port, &reply_soright,
cb323159 2632 &release_port, &assertcnt, 0, NULL);
39236c6e 2633 assert(assertcnt == 0);
1c79356b 2634 assert(kr == KERN_SUCCESS);
fe8ab488 2635 }
fe8ab488
A
2636 } else {
2637 if (dest_name == reply_name) {
1c79356b 2638 /*
fe8ab488
A
2639 * Destination and reply ports are the same!
2640 * This is very similar to the case where the
2641 * destination and voucher ports were the same
2642 * (except the reply port disposition is not
2643 * previously validated).
1c79356b 2644 */
fe8ab488
A
2645 dest_entry = ipc_entry_lookup(space, dest_name);
2646 if (dest_entry == IE_NULL) {
2647 goto invalid_dest;
2648 }
cb323159
A
2649 ipc_kmsg_allow_immovable_send(kmsg, dest_entry);
2650
fe8ab488
A
2651 reply_entry = dest_entry;
2652 assert(reply_type != 0); /* because name not null */
1c79356b 2653
cb323159
A
2654 /*
2655 * Pre-validate that the reply right can be copied in by itself
2656 */
2657 if (!ipc_right_copyin_check_reply(space, reply_name, reply_entry, reply_type)) {
2658 goto invalid_reply;
2659 }
2660
0a7de745
A
2661 /*
2662 * Do the joint copyin of the dest disposition and
fe8ab488 2663 * reply disposition from the one entry/port.
1c79356b 2664 */
fe8ab488 2665 kr = ipc_right_copyin_two(space, dest_name, dest_entry,
cb323159 2666 dest_type, reply_type, &dest_port, &dest_soright,
0a7de745 2667 &release_port);
fe8ab488
A
2668 if (kr == KERN_INVALID_CAPABILITY) {
2669 goto invalid_reply;
2670 } else if (kr != KERN_SUCCESS) {
1c79356b 2671 goto invalid_dest;
6d2010ae 2672 }
1c79356b 2673 reply_port = dest_port;
1c79356b 2674 } else {
fe8ab488
A
2675 /*
2676 * Handle destination and reply independently, as
2677 * they are independent entries (even if the entries
2678 * refer to the same port).
2679 *
2680 * This can be the tough case to make atomic.
2681 *
2682 * The difficult problem is serializing with port death.
2683 * The bad case is when dest_port dies after its copyin,
2684 * reply_port dies before its copyin, and dest_port dies before
2685 * reply_port. Then the copyins operated as if dest_port was
2686 * alive and reply_port was dead, which shouldn't have happened
2687 * because they died in the other order.
2688 *
2689 * Note that it is easy for a user task to tell if
2690 * a copyin happened before or after a port died.
2691 * If a port dies before copyin, a dead-name notification
2692 * is generated and the dead name's urefs are incremented,
2693 * and if the copyin happens first, a port-deleted
2694 * notification is generated.
2695 *
2696 * Even so, avoiding that potentially detectable race is too
2697 * expensive - and no known code cares about it. So, we just
2698 * do the expedient thing and copy them in one after the other.
2699 */
1c79356b 2700
fe8ab488
A
2701 dest_entry = ipc_entry_lookup(space, dest_name);
2702 if (dest_entry == IE_NULL) {
2703 goto invalid_dest;
2704 }
2705 assert(dest_entry != voucher_entry);
cb323159 2706 ipc_kmsg_allow_immovable_send(kmsg, dest_entry);
1c79356b
A
2707
2708 /*
fe8ab488 2709 * Make sure reply port entry is valid before dest copyin.
1c79356b 2710 */
fe8ab488
A
2711 if (MACH_PORT_VALID(reply_name)) {
2712 if (reply_name == voucher_name) {
2713 goto invalid_reply;
2714 }
2715 reply_entry = ipc_entry_lookup(space, reply_name);
2716 if (reply_entry == IE_NULL) {
2717 goto invalid_reply;
2718 }
2719 assert(dest_entry != reply_entry); /* names are not equal */
2720 assert(reply_type != 0); /* because reply_name not null */
2721
cb323159 2722 if (!ipc_right_copyin_check_reply(space, reply_name, reply_entry, reply_type)) {
fe8ab488
A
2723 goto invalid_reply;
2724 }
2725 }
1c79356b 2726
fe8ab488
A
2727 /*
2728 * copyin the destination.
2729 */
fe8ab488 2730 kr = ipc_right_copyin(space, dest_name, dest_entry,
cb323159
A
2731 dest_type, (IPC_RIGHT_COPYIN_FLAGS_ALLOW_IMMOVABLE_SEND |
2732 IPC_RIGHT_COPYIN_FLAGS_ALLOW_DEAD_SEND_ONCE),
0a7de745 2733 &dest_port, &dest_soright,
cb323159 2734 &release_port, &assertcnt, 0, NULL);
39236c6e 2735 assert(assertcnt == 0);
fe8ab488 2736 if (kr != KERN_SUCCESS) {
1c79356b 2737 goto invalid_dest;
6d2010ae 2738 }
fe8ab488
A
2739 assert(IO_VALID(dest_port));
2740 assert(!IP_VALID(release_port));
1c79356b
A
2741
2742 /*
fe8ab488
A
2743 * Copyin the pre-validated reply right.
2744 * It's OK if the reply right has gone dead in the meantime.
1c79356b 2745 */
fe8ab488 2746 if (MACH_PORT_VALID(reply_name)) {
fe8ab488 2747 kr = ipc_right_copyin(space, reply_name, reply_entry,
0a7de745
A
2748 reply_type, IPC_RIGHT_COPYIN_FLAGS_DEADOK,
2749 &reply_port, &reply_soright,
cb323159 2750 &release_port, &assertcnt, 0, NULL);
fe8ab488 2751 assert(assertcnt == 0);
fe8ab488
A
2752 assert(kr == KERN_SUCCESS);
2753 } else {
2754 /* convert invalid name to equivalent ipc_object type */
cb323159 2755 reply_port = ip_to_object(CAST_MACH_NAME_TO_PORT(reply_name));
fe8ab488 2756 }
6d2010ae 2757 }
1c79356b 2758
1c79356b 2759 /*
fe8ab488
A
2760 * Finally can copyin the voucher right now that dest and reply
2761 * are fully copied in (guaranteed success).
1c79356b 2762 */
fe8ab488 2763 if (IE_NULL != voucher_entry) {
fe8ab488 2764 kr = ipc_right_copyin(space, voucher_name, voucher_entry,
0a7de745
A
2765 voucher_type, IPC_RIGHT_COPYIN_FLAGS_NONE,
2766 (ipc_object_t *)&voucher_port,
2767 &voucher_soright,
2768 &voucher_release_port,
cb323159 2769 &assertcnt, 0, NULL);
fe8ab488 2770 assert(assertcnt == 0);
fe8ab488
A
2771 assert(KERN_SUCCESS == kr);
2772 assert(IP_VALID(voucher_port));
cb323159 2773 require_ip_active(voucher_port);
6d2010ae 2774 }
fe8ab488 2775 }
1c79356b 2776
d190cdc3
A
2777 /*
2778 * The entries might need to be deallocated.
2779 *
2780 * Each entry should be deallocated only once,
2781 * even if it was specified in more than one slot in the header.
2782 * Note that dest can be the same entry as reply or voucher,
2783 * but reply and voucher must be distinct entries.
2784 */
fe8ab488 2785 assert(IE_NULL != dest_entry);
0a7de745 2786 if (IE_NULL != reply_entry) {
d190cdc3 2787 assert(reply_entry != voucher_entry);
0a7de745 2788 }
d190cdc3 2789
fe8ab488
A
2790 if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE) {
2791 ipc_entry_dealloc(space, dest_name, dest_entry);
d190cdc3
A
2792
2793 if (dest_entry == reply_entry) {
2794 reply_entry = IE_NULL;
2795 }
2796
2797 if (dest_entry == voucher_entry) {
2798 voucher_entry = IE_NULL;
2799 }
2800
fe8ab488
A
2801 dest_entry = IE_NULL;
2802 }
d190cdc3 2803 if (IE_NULL != reply_entry &&
fe8ab488
A
2804 IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE) {
2805 ipc_entry_dealloc(space, reply_name, reply_entry);
2806 reply_entry = IE_NULL;
2807 }
d190cdc3 2808 if (IE_NULL != voucher_entry &&
fe8ab488
A
2809 IE_BITS_TYPE(voucher_entry->ie_bits) == MACH_PORT_TYPE_NONE) {
2810 ipc_entry_dealloc(space, voucher_name, voucher_entry);
2811 voucher_entry = IE_NULL;
2812 }
2813
6d2010ae
A
2814 dest_type = ipc_object_copyin_type(dest_type);
2815 reply_type = ipc_object_copyin_type(reply_type);
2816
1c79356b 2817 /*
6d2010ae
A
2818 * JMM - Without rdar://problem/6275821, this is the last place we can
2819 * re-arm the send-possible notifications. It may trigger unexpectedly
39236c6e
A
2820 * early (send may NOT have failed), but better than missing. We assure
2821 * we won't miss by forcing MACH_SEND_ALWAYS if we got past arming.
1c79356b 2822 */
0a7de745 2823 if (((*optionp & MACH_SEND_NOTIFY) != 0) &&
39236c6e 2824 dest_type != MACH_MSG_TYPE_PORT_SEND_ONCE &&
6d2010ae 2825 dest_entry != IE_NULL && dest_entry->ie_request != IE_REQ_NONE) {
cb323159 2826 ipc_port_t dport = ip_object_to_port(dest_port);
6d2010ae
A
2827
2828 assert(dport != IP_NULL);
2829 ip_lock(dport);
39236c6e
A
2830 if (ip_active(dport) && dport->ip_receiver != ipc_space_kernel) {
2831 if (ip_full(dport)) {
2832#if IMPORTANCE_INHERITANCE
0a7de745
A
2833 needboost = ipc_port_request_sparm(dport, dest_name,
2834 dest_entry->ie_request,
2835 *optionp,
2836 override);
2837 if (needboost == FALSE) {
39236c6e 2838 ip_unlock(dport);
0a7de745 2839 }
39236c6e 2840#else
39037602 2841 ipc_port_request_sparm(dport, dest_name,
0a7de745
A
2842 dest_entry->ie_request,
2843 *optionp,
2844 override);
39236c6e
A
2845 ip_unlock(dport);
2846#endif /* IMPORTANCE_INHERITANCE */
2847 } else {
2848 *optionp |= MACH_SEND_ALWAYS;
2849 ip_unlock(dport);
2850 }
2851 } else {
2852 ip_unlock(dport);
6d2010ae 2853 }
1c79356b
A
2854 }
2855
2856 is_write_unlock(space);
2857
39236c6e 2858#if IMPORTANCE_INHERITANCE
0a7de745 2859 /*
39236c6e
A
2860 * If our request is the first boosting send-possible
2861 * notification this cycle, push the boost down the
2862 * destination port.
2863 */
2864 if (needboost == TRUE) {
cb323159 2865 ipc_port_t dport = ip_object_to_port(dest_port);
39236c6e
A
2866
2867 /* dport still locked from above */
4bd07ac2 2868 if (ipc_port_importance_delta(dport, IPID_OPTION_SENDPOSSIBLE, 1) == FALSE) {
39236c6e 2869 ip_unlock(dport);
fe8ab488 2870 }
39236c6e
A
2871 }
2872#endif /* IMPORTANCE_INHERITANCE */
2873
fe8ab488 2874 if (dest_soright != IP_NULL) {
1c79356b 2875 ipc_notify_port_deleted(dest_soright, dest_name);
fe8ab488
A
2876 }
2877 if (reply_soright != IP_NULL) {
1c79356b 2878 ipc_notify_port_deleted(reply_soright, reply_name);
fe8ab488
A
2879 }
2880 if (voucher_soright != IP_NULL) {
2881 ipc_notify_port_deleted(voucher_soright, voucher_name);
2882 }
39037602
A
2883
2884 /*
2885 * No room to store voucher port in in-kernel msg header,
2886 * so we store it back in the kmsg itself. Extract the
2887 * qos, and apply any override before we enqueue the kmsg.
2888 */
2889 if (IP_VALID(voucher_port)) {
39037602
A
2890 kmsg->ikm_voucher = voucher_port;
2891 voucher_type = MACH_MSG_TYPE_MOVE_SEND;
2892 }
2893
fe8ab488 2894 msg->msgh_bits = MACH_MSGH_BITS_SET(dest_type, reply_type, voucher_type, mbits);
cb323159
A
2895 msg->msgh_remote_port = ip_object_to_port(dest_port);
2896 msg->msgh_local_port = ip_object_to_port(reply_port);
1c79356b 2897
5ba3f43e
A
2898 /* capture the qos value(s) for the kmsg */
2899 ipc_kmsg_set_qos(kmsg, *optionp, override);
2900
0a7de745 2901 if (release_port != IP_NULL) {
316670eb 2902 ip_release(release_port);
0a7de745 2903 }
316670eb 2904
0a7de745 2905 if (voucher_release_port != IP_NULL) {
fe8ab488 2906 ip_release(voucher_release_port);
0a7de745 2907 }
39236c6e 2908
cb323159
A
2909 if (enforce_strict_reply && MACH_SEND_WITH_STRICT_REPLY(*optionp) && IP_VALID(msg->msgh_local_port)) {
2910 /*
2911 * We've already validated that the reply disposition is a
2912 * [make/move] send-once. Ideally, we should enforce that the
2913 * reply port is also not dead, but XPC asynchronous
2914 * cancellation can make the reply port dead before we
2915 * actually make it to the mach_msg send.
2916 *
2917 * Here, we ensure that if we have a non-dead reply port, then
2918 * the reply port's receive right should not be in-transit,
2919 * and should live in the caller's IPC space.
2920 */
2921 ipc_port_t rport = msg->msgh_local_port;
2922 ip_lock(rport);
2923 kr = ipc_kmsg_validate_reply_port_locked(rport, *optionp);
2924 ip_unlock(rport);
2925 if (kr != KERN_SUCCESS) {
2926 /*
2927 * no descriptors have been copied in yet, but the
2928 * full header has been copied in: clean it up
2929 */
2930 ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
2931 if ((*optionp & MACH_SEND_KERNEL) == 0) {
2932 mach_port_guard_exception(reply_name, 0,
2933 (MPG_FLAGS_STRICT_REPLY_INVALID_REPLY_PORT | kr),
2934 kGUARD_EXC_STRICT_REPLY);
2935 }
2936 return MACH_SEND_INVALID_REPLY;
2937 }
2938 }
2939
1c79356b
A
2940 return MACH_MSG_SUCCESS;
2941
2942invalid_reply:
2943 is_write_unlock(space);
316670eb 2944
0a7de745 2945 if (release_port != IP_NULL) {
316670eb 2946 ip_release(release_port);
0a7de745 2947 }
316670eb 2948
fe8ab488
A
2949 assert(voucher_port == IP_NULL);
2950 assert(voucher_soright == IP_NULL);
2951
d9a64523
A
2952 if ((*optionp & MACH_SEND_KERNEL) == 0) {
2953 mach_port_guard_exception(reply_name, 0, 0, kGUARD_EXC_SEND_INVALID_REPLY);
2954 }
1c79356b
A
2955 return MACH_SEND_INVALID_REPLY;
2956
2957invalid_dest:
2958 is_write_unlock(space);
316670eb 2959
0a7de745 2960 if (release_port != IP_NULL) {
316670eb 2961 ip_release(release_port);
0a7de745 2962 }
316670eb 2963
0a7de745 2964 if (reply_soright != IP_NULL) {
1c79356b 2965 ipc_notify_port_deleted(reply_soright, reply_name);
0a7de745 2966 }
316670eb 2967
fe8ab488
A
2968 assert(voucher_port == IP_NULL);
2969 assert(voucher_soright == IP_NULL);
2970
1c79356b
A
2971 return MACH_SEND_INVALID_DEST;
2972}
2973
cb323159 2974static mach_msg_descriptor_t *
b0d623f7 2975ipc_kmsg_copyin_port_descriptor(
d9a64523
A
2976 volatile mach_msg_port_descriptor_t *dsc,
2977 mach_msg_legacy_port_descriptor_t *user_dsc_in,
2978 ipc_space_t space,
2979 ipc_object_t dest,
2980 ipc_kmsg_t kmsg,
2981 mach_msg_option_t *optionp,
2982 mach_msg_return_t *mr)
b0d623f7 2983{
0a7de745
A
2984 volatile mach_msg_legacy_port_descriptor_t *user_dsc = user_dsc_in;
2985 mach_msg_type_name_t user_disp;
2986 mach_msg_type_name_t result_disp;
2987 mach_port_name_t name;
2988 ipc_object_t object;
2989
2990 user_disp = user_dsc->disposition;
2991 result_disp = ipc_object_copyin_type(user_disp);
2992
2993 name = (mach_port_name_t)user_dsc->name;
2994 if (MACH_PORT_VALID(name)) {
cb323159 2995 kern_return_t kr = ipc_object_copyin(space, name, user_disp, &object, 0, NULL, kmsg->ikm_flags);
0a7de745 2996 if (kr != KERN_SUCCESS) {
cb323159 2997 if (((*optionp & MACH_SEND_KERNEL) == 0) && (kr == KERN_INVALID_RIGHT)) {
d9a64523
A
2998 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_SEND_INVALID_RIGHT);
2999 }
0a7de745
A
3000 *mr = MACH_SEND_INVALID_RIGHT;
3001 return NULL;
3002 }
3003
3004 if ((result_disp == MACH_MSG_TYPE_PORT_RECEIVE) &&
cb323159
A
3005 ipc_port_check_circularity(ip_object_to_port(object),
3006 ip_object_to_port(dest))) {
0a7de745
A
3007 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
3008 }
cb323159 3009 dsc->name = ip_object_to_port(object);
0a7de745
A
3010 } else {
3011 dsc->name = CAST_MACH_NAME_TO_PORT(name);
3012 }
3013 dsc->disposition = result_disp;
3014 dsc->type = MACH_MSG_PORT_DESCRIPTOR;
3015
cb323159 3016 dsc->pad_end = 0; // debug, unnecessary
0a7de745
A
3017
3018 return (mach_msg_descriptor_t *)(user_dsc_in + 1);
b0d623f7
A
3019}
3020
cb323159 3021static mach_msg_descriptor_t *
b0d623f7 3022ipc_kmsg_copyin_ool_descriptor(
d9a64523
A
3023 mach_msg_ool_descriptor_t *dsc,
3024 mach_msg_descriptor_t *user_dsc,
3025 int is_64bit,
3026 vm_offset_t *paddr,
3027 vm_map_copy_t *copy,
3028 vm_size_t *space_needed,
3029 vm_map_t map,
3030 __unused mach_msg_option_t *optionp,
3031 mach_msg_return_t *mr)
b0d623f7 3032{
0a7de745
A
3033 vm_size_t length;
3034 boolean_t dealloc;
3035 mach_msg_copy_options_t copy_options;
3036 mach_vm_offset_t addr;
3037 mach_msg_descriptor_type_t dsc_type;
3038
3039 if (is_64bit) {
3040 mach_msg_ool_descriptor64_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
3041
3042 addr = (mach_vm_offset_t) user_ool_dsc->address;
3043 length = user_ool_dsc->size;
3044 dealloc = user_ool_dsc->deallocate;
3045 copy_options = user_ool_dsc->copy;
3046 dsc_type = user_ool_dsc->type;
3047
3048 user_dsc = (typeof(user_dsc))(user_ool_dsc + 1);
3049 } else {
3050 mach_msg_ool_descriptor32_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
3051
3052 addr = CAST_USER_ADDR_T(user_ool_dsc->address);
3053 dealloc = user_ool_dsc->deallocate;
3054 copy_options = user_ool_dsc->copy;
3055 dsc_type = user_ool_dsc->type;
3056 length = user_ool_dsc->size;
3057
3058 user_dsc = (typeof(user_dsc))(user_ool_dsc + 1);
3059 }
3060
3061 dsc->size = (mach_msg_size_t)length;
3062 dsc->deallocate = dealloc;
3063 dsc->copy = copy_options;
3064 dsc->type = dsc_type;
3065
3066 if (length == 0) {
3067 dsc->address = NULL;
3068 } else if ((length >= MSG_OOL_SIZE_SMALL) &&
3069 (copy_options == MACH_MSG_PHYSICAL_COPY) && !dealloc) {
3070 /*
3071 * If the request is a physical copy and the source
3072 * is not being deallocated, then allocate space
3073 * in the kernel's pageable ipc copy map and copy
3074 * the data in. The semantics guarantee that the
3075 * data will have been physically copied before
3076 * the send operation terminates. Thus if the data
3077 * is not being deallocated, we must be prepared
3078 * to page if the region is sufficiently large.
3079 */
3080 if (copyin(addr, (char *)*paddr, length)) {
3081 *mr = MACH_SEND_INVALID_MEMORY;
3082 return NULL;
3083 }
3084
3085 /*
3086 * The kernel ipc copy map is marked no_zero_fill.
3087 * If the transfer is not a page multiple, we need
3088 * to zero fill the balance.
3089 */
3090 if (!page_aligned(length)) {
3091 (void) memset((void *) (*paddr + length), 0,
3092 round_page(length) - length);
3093 }
3094 if (vm_map_copyin(ipc_kernel_copy_map, (vm_map_address_t)*paddr,
3095 (vm_map_size_t)length, TRUE, copy) != KERN_SUCCESS) {
3096 *mr = MACH_MSG_VM_KERNEL;
3097 return NULL;
3098 }
3099 dsc->address = (void *)*copy;
3100 *paddr += round_page(length);
3101 *space_needed -= round_page(length);
3102 } else {
3103 /*
3104 * Make a vm_map_copy_t of the of the data. If the
3105 * data is small, this will do an optimized physical
3106 * copy. Otherwise, it will do a virtual copy.
3107 *
3108 * NOTE: A virtual copy is OK if the original is being
3109 * deallocted, even if a physical copy was requested.
3110 */
3111 kern_return_t kr = vm_map_copyin(map, addr,
3112 (vm_map_size_t)length, dealloc, copy);
3113 if (kr != KERN_SUCCESS) {
3114 *mr = (kr == KERN_RESOURCE_SHORTAGE) ?
3115 MACH_MSG_VM_KERNEL :
3116 MACH_SEND_INVALID_MEMORY;
3117 return NULL;
3118 }
3119 dsc->address = (void *)*copy;
3120 }
3121 return user_dsc;
b0d623f7
A
3122}
3123
cb323159 3124static mach_msg_descriptor_t *
b0d623f7 3125ipc_kmsg_copyin_ool_ports_descriptor(
d9a64523
A
3126 mach_msg_ool_ports_descriptor_t *dsc,
3127 mach_msg_descriptor_t *user_dsc,
3128 int is_64bit,
3129 vm_map_t map,
3130 ipc_space_t space,
3131 ipc_object_t dest,
3132 ipc_kmsg_t kmsg,
3133 mach_msg_option_t *optionp,
3134 mach_msg_return_t *mr)
b0d623f7 3135{
0a7de745
A
3136 void *data;
3137 ipc_object_t *objects;
3138 unsigned int i;
3139 mach_vm_offset_t addr;
3140 mach_msg_type_name_t user_disp;
3141 mach_msg_type_name_t result_disp;
3142 mach_msg_type_number_t count;
3143 mach_msg_copy_options_t copy_option;
3144 boolean_t deallocate;
3145 mach_msg_descriptor_type_t type;
3146 vm_size_t ports_length, names_length;
3147
3148 if (is_64bit) {
3149 mach_msg_ool_ports_descriptor64_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
3150
3151 addr = (mach_vm_offset_t)user_ool_dsc->address;
3152 count = user_ool_dsc->count;
3153 deallocate = user_ool_dsc->deallocate;
3154 copy_option = user_ool_dsc->copy;
3155 user_disp = user_ool_dsc->disposition;
3156 type = user_ool_dsc->type;
3157
3158 user_dsc = (typeof(user_dsc))(user_ool_dsc + 1);
3159 } else {
3160 mach_msg_ool_ports_descriptor32_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
3161
3162 addr = CAST_USER_ADDR_T(user_ool_dsc->address);
3163 count = user_ool_dsc->count;
3164 deallocate = user_ool_dsc->deallocate;
3165 copy_option = user_ool_dsc->copy;
3166 user_disp = user_ool_dsc->disposition;
3167 type = user_ool_dsc->type;
3168
3169 user_dsc = (typeof(user_dsc))(user_ool_dsc + 1);
3170 }
3171
3172 dsc->deallocate = deallocate;
3173 dsc->copy = copy_option;
3174 dsc->type = type;
3175 dsc->count = count;
3176 dsc->address = NULL; /* for now */
3177
3178 result_disp = ipc_object_copyin_type(user_disp);
3179 dsc->disposition = result_disp;
3180
3181 /* We always do a 'physical copy', but you have to specify something valid */
3182 if (copy_option != MACH_MSG_PHYSICAL_COPY &&
3183 copy_option != MACH_MSG_VIRTUAL_COPY) {
3184 *mr = MACH_SEND_INVALID_TYPE;
3185 return NULL;
3186 }
3187
3188 /* calculate length of data in bytes, rounding up */
3189
3190 if (os_mul_overflow(count, sizeof(mach_port_t), &ports_length)) {
3191 *mr = MACH_SEND_TOO_LARGE;
3192 return NULL;
3193 }
3194
3195 if (os_mul_overflow(count, sizeof(mach_port_name_t), &names_length)) {
3196 *mr = MACH_SEND_TOO_LARGE;
3197 return NULL;
3198 }
3199
3200 if (ports_length == 0) {
3201 return user_dsc;
3202 }
3203
3204 data = kalloc(ports_length);
3205
3206 if (data == NULL) {
3207 *mr = MACH_SEND_NO_BUFFER;
3208 return NULL;
3209 }
3210
b0d623f7 3211#ifdef __LP64__
0a7de745 3212 mach_port_name_t *names = &((mach_port_name_t *)data)[count];
b0d623f7 3213#else
0a7de745 3214 mach_port_name_t *names = ((mach_port_name_t *)data);
b0d623f7
A
3215#endif
3216
0a7de745
A
3217 if (copyinmap(map, addr, names, names_length) != KERN_SUCCESS) {
3218 kfree(data, ports_length);
3219 *mr = MACH_SEND_INVALID_MEMORY;
3220 return NULL;
3221 }
b0d623f7 3222
0a7de745
A
3223 if (deallocate) {
3224 (void) mach_vm_deallocate(map, addr, (mach_vm_size_t)ports_length);
3225 }
b0d623f7 3226
0a7de745
A
3227 objects = (ipc_object_t *) data;
3228 dsc->address = data;
b0d623f7 3229
0a7de745
A
3230 for (i = 0; i < count; i++) {
3231 mach_port_name_t name = names[i];
3232 ipc_object_t object;
b0d623f7 3233
0a7de745 3234 if (!MACH_PORT_VALID(name)) {
cb323159 3235 objects[i] = ip_to_object(CAST_MACH_NAME_TO_PORT(name));
0a7de745
A
3236 continue;
3237 }
b0d623f7 3238
cb323159 3239 kern_return_t kr = ipc_object_copyin(space, name, user_disp, &object, 0, NULL, kmsg->ikm_flags);
b0d623f7 3240
0a7de745
A
3241 if (kr != KERN_SUCCESS) {
3242 unsigned int j;
b0d623f7 3243
0a7de745
A
3244 for (j = 0; j < i; j++) {
3245 object = objects[j];
3246 if (IPC_OBJECT_VALID(object)) {
3247 ipc_object_destroy(object, result_disp);
3248 }
3249 }
3250 kfree(data, ports_length);
3251 dsc->address = NULL;
cb323159 3252 if (((*optionp & MACH_SEND_KERNEL) == 0) && (kr == KERN_INVALID_RIGHT)) {
d9a64523
A
3253 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_SEND_INVALID_RIGHT);
3254 }
0a7de745
A
3255 *mr = MACH_SEND_INVALID_RIGHT;
3256 return NULL;
3257 }
b0d623f7 3258
0a7de745 3259 if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
cb323159
A
3260 ipc_port_check_circularity(ip_object_to_port(object),
3261 ip_object_to_port(dest))) {
0a7de745
A
3262 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
3263 }
b0d623f7 3264
0a7de745
A
3265 objects[i] = object;
3266 }
b0d623f7 3267
0a7de745 3268 return user_dsc;
b0d623f7
A
3269}
3270
cb323159
A
3271static mach_msg_descriptor_t *
3272ipc_kmsg_copyin_guarded_port_descriptor(
3273 mach_msg_guarded_port_descriptor_t *dsc,
3274 mach_msg_descriptor_t *user_addr,
3275 int is_64bit,
3276 ipc_space_t space,
3277 ipc_object_t dest,
3278 ipc_kmsg_t kmsg,
3279 mach_msg_option_t *optionp,
3280 mach_msg_return_t *mr)
3281{
3282 mach_msg_descriptor_t *user_dsc;
3283 mach_msg_type_name_t disp;
3284 mach_msg_type_name_t result_disp;
3285 mach_port_name_t name;
3286 mach_msg_guard_flags_t guard_flags;
3287 ipc_object_t object;
3288 mach_port_context_t context;
3289
3290 if (!is_64bit) {
3291 mach_msg_guarded_port_descriptor32_t *user_gp_dsc = (typeof(user_gp_dsc))user_addr;
3292 name = user_gp_dsc->name;
3293 guard_flags = user_gp_dsc->flags;
3294 disp = user_gp_dsc->disposition;
3295 context = user_gp_dsc->context;
3296 user_dsc = (mach_msg_descriptor_t *)(user_gp_dsc + 1);
3297 } else {
3298 mach_msg_guarded_port_descriptor64_t *user_gp_dsc = (typeof(user_gp_dsc))user_addr;
3299 name = user_gp_dsc->name;
3300 guard_flags = user_gp_dsc->flags;
3301 disp = user_gp_dsc->disposition;
3302 context = user_gp_dsc->context;
3303 user_dsc = (mach_msg_descriptor_t *)(user_gp_dsc + 1);
3304 }
3305
3306 guard_flags &= MACH_MSG_GUARD_FLAGS_MASK;
3307 result_disp = ipc_object_copyin_type(disp);
3308
3309 if (MACH_PORT_VALID(name)) {
3310 kern_return_t kr = ipc_object_copyin(space, name, disp, &object, context, &guard_flags, kmsg->ikm_flags);
3311 if (kr != KERN_SUCCESS) {
3312 if (((*optionp & MACH_SEND_KERNEL) == 0) && (kr == KERN_INVALID_RIGHT)) {
3313 mach_port_guard_exception(name, 0, 0, kGUARD_EXC_SEND_INVALID_RIGHT);
3314 }
3315 *mr = MACH_SEND_INVALID_RIGHT;
3316 return NULL;
3317 }
3318
3319 if ((result_disp == MACH_MSG_TYPE_PORT_RECEIVE) &&
3320 ipc_port_check_circularity(ip_object_to_port(object),
3321 ip_object_to_port(dest))) {
3322 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
3323 }
3324 dsc->name = ip_object_to_port(object);
3325 } else {
3326 dsc->name = CAST_MACH_NAME_TO_PORT(name);
3327 }
3328 dsc->flags = guard_flags;
3329 dsc->disposition = result_disp;
3330 dsc->type = MACH_MSG_GUARDED_PORT_DESCRIPTOR;
3331
3332#if __LP64__
3333 dsc->pad_end = 0; // debug, unnecessary
3334#endif
3335 return user_dsc;
3336}
3337
3338
1c79356b
A
3339/*
3340 * Routine: ipc_kmsg_copyin_body
3341 * Purpose:
3342 * "Copy-in" port rights and out-of-line memory
3343 * in the message body.
3344 *
3345 * In all failure cases, the message is left holding
3346 * no rights or memory. However, the message buffer
3347 * is not deallocated. If successful, the message
3348 * contains a valid destination port.
3349 * Conditions:
3350 * Nothing locked.
3351 * Returns:
3352 * MACH_MSG_SUCCESS Successful copyin.
3353 * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
3354 * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
3355 * MACH_SEND_INVALID_TYPE Bad type specification.
3356 * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
3357 * MACH_SEND_INVALID_RT_OOL_SIZE OOL Buffer too large for RT
3358 * MACH_MSG_INVALID_RT_DESCRIPTOR Dealloc and RT are incompatible
cb323159 3359 * MACH_SEND_NO_GRANT_DEST Dest port doesn't accept ports in body
1c79356b
A
3360 */
3361
3362mach_msg_return_t
3363ipc_kmsg_copyin_body(
0a7de745
A
3364 ipc_kmsg_t kmsg,
3365 ipc_space_t space,
d9a64523
A
3366 vm_map_t map,
3367 mach_msg_option_t *optionp)
1c79356b 3368{
0a7de745
A
3369 ipc_object_t dest;
3370 mach_msg_body_t *body;
cb323159 3371 mach_msg_descriptor_t *daddr, *naddr, *end;
0a7de745
A
3372 mach_msg_descriptor_t *user_addr, *kern_addr;
3373 mach_msg_type_number_t dsc_count;
3374 boolean_t is_task_64bit = (map->max_offset > VM_MAX_ADDRESS);
3375 boolean_t complex = FALSE;
cb323159 3376 boolean_t contains_port_desc = FALSE;
0a7de745
A
3377 vm_size_t space_needed = 0;
3378 vm_offset_t paddr = 0;
3379 vm_map_copy_t copy = VM_MAP_COPY_NULL;
3380 mach_msg_type_number_t i;
3381 mach_msg_return_t mr = MACH_MSG_SUCCESS;
cb323159 3382 ipc_port_t remote_port = kmsg->ikm_header->msgh_remote_port;
0a7de745
A
3383
3384 vm_size_t descriptor_size = 0;
3385
3386 mach_msg_type_number_t total_ool_port_count = 0;
cb323159
A
3387 mach_msg_guard_flags_t guard_flags = 0;
3388 mach_port_context_t context;
3389 mach_msg_type_name_t disp;
91447636 3390
0a7de745
A
3391 /*
3392 * Determine if the target is a kernel port.
3393 */
cb323159 3394 dest = ip_to_object(remote_port);
0a7de745
A
3395 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
3396 naddr = (mach_msg_descriptor_t *) (body + 1);
cb323159 3397 end = (mach_msg_descriptor_t *) ((vm_offset_t)kmsg->ikm_header + kmsg->ikm_header->msgh_size);
fe8ab488 3398
0a7de745
A
3399 dsc_count = body->msgh_descriptor_count;
3400 if (dsc_count == 0) {
3401 return MACH_MSG_SUCCESS;
91447636 3402 }
1c79356b 3403
0a7de745
A
3404 /*
3405 * Make an initial pass to determine kernal VM space requirements for
3406 * physical copies and possible contraction of the descriptors from
3407 * processes with pointers larger than the kernel's.
3408 */
3409 daddr = NULL;
3410 for (i = 0; i < dsc_count; i++) {
3411 mach_msg_size_t size;
3412 mach_msg_type_number_t ool_port_count = 0;
d190cdc3 3413
0a7de745 3414 daddr = naddr;
91447636 3415
0a7de745
A
3416 /* make sure the descriptor fits in the message */
3417 if (is_task_64bit) {
cb323159
A
3418 if ((mach_msg_descriptor_t*)((vm_offset_t)daddr + 12) > end) {
3419 mr = MACH_SEND_MSG_TOO_SMALL;
3420 goto clean_message;
3421 }
3422
0a7de745
A
3423 switch (daddr->type.type) {
3424 case MACH_MSG_OOL_DESCRIPTOR:
3425 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
3426 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
cb323159 3427 case MACH_MSG_GUARDED_PORT_DESCRIPTOR:
0a7de745
A
3428 descriptor_size += 16;
3429 naddr = (typeof(naddr))((vm_offset_t)daddr + 16);
3430 break;
3431 default:
3432 descriptor_size += 12;
3433 naddr = (typeof(naddr))((vm_offset_t)daddr + 12);
3434 break;
3435 }
3436 } else {
3437 descriptor_size += 12;
3438 naddr = (typeof(naddr))((vm_offset_t)daddr + 12);
d190cdc3
A
3439 }
3440
cb323159 3441 if (naddr > end) {
0a7de745 3442 mr = MACH_SEND_MSG_TOO_SMALL;
d190cdc3
A
3443 goto clean_message;
3444 }
3445
0a7de745
A
3446 switch (daddr->type.type) {
3447 case MACH_MSG_OOL_DESCRIPTOR:
3448 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
3449 size = (is_task_64bit) ?
3450 ((mach_msg_ool_descriptor64_t *)daddr)->size :
3451 daddr->out_of_line.size;
3452
3453 if (daddr->out_of_line.copy != MACH_MSG_PHYSICAL_COPY &&
3454 daddr->out_of_line.copy != MACH_MSG_VIRTUAL_COPY) {
3455 /*
3456 * Invalid copy option
3457 */
3458 mr = MACH_SEND_INVALID_TYPE;
3459 goto clean_message;
3460 }
3461
3462 if ((size >= MSG_OOL_SIZE_SMALL) &&
3463 (daddr->out_of_line.copy == MACH_MSG_PHYSICAL_COPY) &&
3464 !(daddr->out_of_line.deallocate)) {
3465 /*
3466 * Out-of-line memory descriptor, accumulate kernel
3467 * memory requirements
3468 */
3469 if (space_needed + round_page(size) <= space_needed) {
3470 /* Overflow dectected */
3471 mr = MACH_MSG_VM_KERNEL;
3472 goto clean_message;
3473 }
3474
3475 space_needed += round_page(size);
3476 if (space_needed > ipc_kmsg_max_vm_space) {
3477 /* Per message kernel memory limit exceeded */
3478 mr = MACH_MSG_VM_KERNEL;
3479 goto clean_message;
3480 }
3481 }
3482 break;
3483 case MACH_MSG_PORT_DESCRIPTOR:
3484 if (os_add_overflow(total_ool_port_count, 1, &total_ool_port_count)) {
3485 /* Overflow detected */
3486 mr = MACH_SEND_TOO_LARGE;
3487 goto clean_message;
3488 }
cb323159 3489 contains_port_desc = TRUE;
0a7de745
A
3490 break;
3491 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
3492 ool_port_count = (is_task_64bit) ?
3493 ((mach_msg_ool_ports_descriptor64_t *)daddr)->count :
3494 daddr->ool_ports.count;
3495
3496 if (os_add_overflow(total_ool_port_count, ool_port_count, &total_ool_port_count)) {
3497 /* Overflow detected */
3498 mr = MACH_SEND_TOO_LARGE;
3499 goto clean_message;
3500 }
3501
3502 if (ool_port_count > (ipc_kmsg_max_vm_space / sizeof(mach_port_t))) {
3503 /* Per message kernel memory limit exceeded */
3504 mr = MACH_SEND_TOO_LARGE;
3505 goto clean_message;
3506 }
cb323159
A
3507 contains_port_desc = TRUE;
3508 break;
3509 case MACH_MSG_GUARDED_PORT_DESCRIPTOR:
3510 guard_flags = (is_task_64bit) ?
3511 ((mach_msg_guarded_port_descriptor64_t *)daddr)->flags :
3512 ((mach_msg_guarded_port_descriptor32_t *)daddr)->flags;
3513 context = (is_task_64bit) ?
3514 ((mach_msg_guarded_port_descriptor64_t *)daddr)->context :
3515 ((mach_msg_guarded_port_descriptor32_t *)daddr)->context;
3516 disp = (is_task_64bit) ?
3517 ((mach_msg_guarded_port_descriptor64_t *)daddr)->disposition :
3518 ((mach_msg_guarded_port_descriptor32_t *)daddr)->disposition;
3519
3520 /* Only MACH_MSG_TYPE_MOVE_RECEIVE is supported for now */
3521 if (!guard_flags || ((guard_flags & ~MACH_MSG_GUARD_FLAGS_MASK) != 0) ||
3522 ((guard_flags & MACH_MSG_GUARD_FLAGS_UNGUARDED_ON_SEND) && (context != 0)) ||
3523 (disp != MACH_MSG_TYPE_MOVE_RECEIVE)) {
3524 /*
3525 * Invalid guard flags, context or disposition
3526 */
3527 mr = MACH_SEND_INVALID_TYPE;
3528 goto clean_message;
3529 }
3530 if (os_add_overflow(total_ool_port_count, 1, &total_ool_port_count)) {
3531 /* Overflow detected */
3532 mr = MACH_SEND_TOO_LARGE;
3533 goto clean_message;
3534 }
3535 contains_port_desc = TRUE;
0a7de745 3536 break;
d190cdc3 3537 }
1c79356b 3538 }
1c79356b 3539
d190cdc3
A
3540 /* Sending more than 16383 rights in one message seems crazy */
3541 if (total_ool_port_count >= (MACH_PORT_UREFS_MAX / 4)) {
3542 mr = MACH_SEND_TOO_LARGE;
3543 goto clean_message;
3544 }
3545
cb323159
A
3546 /*
3547 * Check if dest is a no-grant port; Since this bit is set only on
3548 * port construction and cannot be unset later, we can peek at the
3549 * bit without paying the cost of locking the port.
3550 */
3551 if (contains_port_desc && remote_port->ip_no_grant) {
3552 mr = MACH_SEND_NO_GRANT_DEST;
3553 goto clean_message;
3554 }
3555
0a7de745
A
3556 /*
3557 * Allocate space in the pageable kernel ipc copy map for all the
3558 * ool data that is to be physically copied. Map is marked wait for
3559 * space.
3560 */
3561 if (space_needed) {
3562 if (vm_allocate_kernel(ipc_kernel_copy_map, &paddr, space_needed,
3563 VM_FLAGS_ANYWHERE, VM_KERN_MEMORY_IPC) != KERN_SUCCESS) {
3564 mr = MACH_MSG_VM_KERNEL;
3565 goto clean_message;
3566 }
3567 }
3568
3569 /* user_addr = just after base as it was copied in */
3570 user_addr = (mach_msg_descriptor_t *)((vm_offset_t)kmsg->ikm_header + sizeof(mach_msg_base_t));
3571
cb323159
A
3572 /* Shift the mach_msg_base_t down to make room for dsc_count*16bytes of descriptors on 64 bit kernels
3573 */
0a7de745
A
3574 if (descriptor_size != 16 * dsc_count) {
3575 vm_offset_t dsc_adjust = 16 * dsc_count - descriptor_size;
3576
3577 memmove((char *)(((vm_offset_t)kmsg->ikm_header) - dsc_adjust), kmsg->ikm_header, sizeof(mach_msg_base_t));
3578 kmsg->ikm_header = (mach_msg_header_t *)((vm_offset_t)kmsg->ikm_header - dsc_adjust);
3579
3580 /* Update the message size for the larger in-kernel representation */
3581 kmsg->ikm_header->msgh_size += (mach_msg_size_t)dsc_adjust;
3582 }
3583
3584
3585 /* kern_addr = just after base after it has been (conditionally) moved */
3586 kern_addr = (mach_msg_descriptor_t *)((vm_offset_t)kmsg->ikm_header + sizeof(mach_msg_base_t));
3587
3588 /* handle the OOL regions and port descriptors. */
3589 for (i = 0; i < dsc_count; i++) {
3590 switch (user_addr->type.type) {
3591 case MACH_MSG_PORT_DESCRIPTOR:
3592 user_addr = ipc_kmsg_copyin_port_descriptor((mach_msg_port_descriptor_t *)kern_addr,
3593 (mach_msg_legacy_port_descriptor_t *)user_addr, space, dest, kmsg, optionp, &mr);
3594 kern_addr++;
3595 complex = TRUE;
3596 break;
3597 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
3598 case MACH_MSG_OOL_DESCRIPTOR:
3599 user_addr = ipc_kmsg_copyin_ool_descriptor((mach_msg_ool_descriptor_t *)kern_addr,
3600 user_addr, is_task_64bit, &paddr, &copy, &space_needed, map, optionp, &mr);
3601 kern_addr++;
3602 complex = TRUE;
3603 break;
3604 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
3605 user_addr = ipc_kmsg_copyin_ool_ports_descriptor((mach_msg_ool_ports_descriptor_t *)kern_addr,
3606 user_addr, is_task_64bit, map, space, dest, kmsg, optionp, &mr);
3607 kern_addr++;
3608 complex = TRUE;
3609 break;
cb323159
A
3610 case MACH_MSG_GUARDED_PORT_DESCRIPTOR:
3611 user_addr = ipc_kmsg_copyin_guarded_port_descriptor((mach_msg_guarded_port_descriptor_t *)kern_addr,
3612 user_addr, is_task_64bit, space, dest, kmsg, optionp, &mr);
3613 kern_addr++;
3614 complex = TRUE;
3615 break;
0a7de745
A
3616 default:
3617 /* Invalid descriptor */
3618 mr = MACH_SEND_INVALID_TYPE;
3619 break;
3620 }
3621
3622 if (MACH_MSG_SUCCESS != mr) {
3623 /* clean from start of message descriptors to i */
3624 ipc_kmsg_clean_partial(kmsg, i,
3625 (mach_msg_descriptor_t *)((mach_msg_base_t *)kmsg->ikm_header + 1),
3626 paddr, space_needed);
3627 goto out;
3628 }
cb323159 3629 } /* End of loop */
0a7de745
A
3630
3631 if (!complex) {
3632 kmsg->ikm_header->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
3633 }
3634out:
3635 return mr;
d190cdc3
A
3636
3637clean_message:
3638 /* no descriptors have been copied in yet */
3639 ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
3640 return mr;
1c79356b
A
3641}
3642
3643
3644/*
3645 * Routine: ipc_kmsg_copyin
3646 * Purpose:
3647 * "Copy-in" port rights and out-of-line memory
3648 * in the message.
3649 *
3650 * In all failure cases, the message is left holding
3651 * no rights or memory. However, the message buffer
3652 * is not deallocated. If successful, the message
3653 * contains a valid destination port.
3654 * Conditions:
3655 * Nothing locked.
3656 * Returns:
3657 * MACH_MSG_SUCCESS Successful copyin.
3658 * MACH_SEND_INVALID_HEADER
3659 * Illegal value in the message header bits.
1c79356b
A
3660 * MACH_SEND_INVALID_DEST Can't copyin destination port.
3661 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
3662 * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
3663 * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
3664 * MACH_SEND_INVALID_TYPE Bad type specification.
3665 * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
3666 */
3667
3668mach_msg_return_t
3669ipc_kmsg_copyin(
0a7de745
A
3670 ipc_kmsg_t kmsg,
3671 ipc_space_t space,
3672 vm_map_t map,
39037602 3673 mach_msg_priority_t override,
0a7de745 3674 mach_msg_option_t *optionp)
1c79356b 3675{
0a7de745 3676 mach_msg_return_t mr;
39236c6e 3677
0a7de745 3678 kmsg->ikm_header->msgh_bits &= MACH_MSGH_BITS_USER;
39236c6e 3679
0a7de745 3680 mr = ipc_kmsg_copyin_header(kmsg, space, override, optionp);
39236c6e 3681
0a7de745
A
3682 if (mr != MACH_MSG_SUCCESS) {
3683 return mr;
3684 }
3685
3686 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_MSG_SEND) | DBG_FUNC_NONE,
3687 VM_KERNEL_ADDRPERM((uintptr_t)kmsg),
3688 (uintptr_t)kmsg->ikm_header->msgh_bits,
3689 (uintptr_t)kmsg->ikm_header->msgh_id,
3690 VM_KERNEL_ADDRPERM((uintptr_t)unsafe_convert_port_to_voucher(kmsg->ikm_voucher)),
3691 0);
3692
3693 DEBUG_KPRINT_SYSCALL_IPC("ipc_kmsg_copyin header:\n%.8x\n%.8x\n%p\n%p\n%p\n%.8x\n",
3694 kmsg->ikm_header->msgh_size,
3695 kmsg->ikm_header->msgh_bits,
3696 kmsg->ikm_header->msgh_remote_port,
3697 kmsg->ikm_header->msgh_local_port,
3698 kmsg->ikm_voucher,
3699 kmsg->ikm_header->msgh_id);
3700
3701 if ((kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0) {
3702 return MACH_MSG_SUCCESS;
3703 }
fe8ab488 3704
d9a64523 3705 mr = ipc_kmsg_copyin_body( kmsg, space, map, optionp);
fe8ab488
A
3706 /* unreachable if !DEBUG */
3707 __unreachable_ok_push
0a7de745 3708 if (DEBUG_KPRINT_SYSCALL_PREDICATE(DEBUG_KPRINT_SYSCALL_IPC_MASK)) {
b0d623f7
A
3709 kprintf("body:\n");
3710 uint32_t i;
0a7de745
A
3711 for (i = 0; i * 4 < (kmsg->ikm_header->msgh_size - sizeof(mach_msg_header_t)); i++) {
3712 kprintf("%.4x\n", ((uint32_t *)(kmsg->ikm_header + 1))[i]);
b0d623f7
A
3713 }
3714 }
fe8ab488 3715 __unreachable_ok_pop
39236c6e 3716
b0d623f7 3717 return mr;
1c79356b
A
3718}
3719
3720/*
3721 * Routine: ipc_kmsg_copyin_from_kernel
3722 * Purpose:
3723 * "Copy-in" port rights and out-of-line memory
3724 * in a message sent from the kernel.
3725 *
3726 * Because the message comes from the kernel,
3727 * the implementation assumes there are no errors
3728 * or peculiarities in the message.
1c79356b
A
3729 * Conditions:
3730 * Nothing locked.
3731 */
3732
6d2010ae 3733mach_msg_return_t
1c79356b 3734ipc_kmsg_copyin_from_kernel(
0a7de745 3735 ipc_kmsg_t kmsg)
1c79356b 3736{
91447636 3737 mach_msg_bits_t bits = kmsg->ikm_header->msgh_bits;
1c79356b
A
3738 mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
3739 mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
cb323159
A
3740 ipc_object_t remote = ip_to_object(kmsg->ikm_header->msgh_remote_port);
3741 ipc_object_t local = ip_to_object(kmsg->ikm_header->msgh_local_port);
3742 ipc_port_t dest = kmsg->ikm_header->msgh_remote_port;
1c79356b
A
3743
3744 /* translate the destination and reply ports */
0a7de745 3745 if (!IO_VALID(remote)) {
6d2010ae 3746 return MACH_SEND_INVALID_DEST;
0a7de745 3747 }
1c79356b
A
3748
3749 ipc_object_copyin_from_kernel(remote, rname);
0a7de745 3750 if (IO_VALID(local)) {
1c79356b 3751 ipc_object_copyin_from_kernel(local, lname);
0a7de745 3752 }
1c79356b
A
3753
3754 /*
3755 * The common case is a complex message with no reply port,
3756 * because that is what the memory_object interface uses.
3757 */
3758
3759 if (bits == (MACH_MSGH_BITS_COMPLEX |
0a7de745 3760 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
1c79356b 3761 bits = (MACH_MSGH_BITS_COMPLEX |
0a7de745 3762 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
1c79356b 3763
91447636 3764 kmsg->ikm_header->msgh_bits = bits;
1c79356b
A
3765 } else {
3766 bits = (MACH_MSGH_BITS_OTHER(bits) |
0a7de745
A
3767 MACH_MSGH_BITS(ipc_object_copyin_type(rname),
3768 ipc_object_copyin_type(lname)));
1c79356b 3769
91447636 3770 kmsg->ikm_header->msgh_bits = bits;
0a7de745 3771 if ((bits & MACH_MSGH_BITS_COMPLEX) == 0) {
6d2010ae 3772 return MACH_MSG_SUCCESS;
0a7de745 3773 }
1c79356b 3774 }
cb323159
A
3775
3776 /*
3777 * Check if the remote port accepts ports in the body.
3778 */
3779 if (dest->ip_no_grant) {
3780 mach_msg_descriptor_t *saddr;
3781 mach_msg_body_t *body;
3782 mach_msg_type_number_t i, count;
3783
3784 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
3785 saddr = (mach_msg_descriptor_t *) (body + 1);
3786 count = body->msgh_descriptor_count;
3787
3788 for (i = 0; i < count; i++, saddr++) {
3789 switch (saddr->type.type) {
3790 case MACH_MSG_PORT_DESCRIPTOR:
3791 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
3792 case MACH_MSG_GUARDED_PORT_DESCRIPTOR:
3793 /* no descriptors have been copied in yet */
3794 ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
3795 return MACH_SEND_NO_GRANT_DEST;
3796 }
3797 }
3798 }
0a7de745
A
3799 {
3800 mach_msg_descriptor_t *saddr;
3801 mach_msg_body_t *body;
3802 mach_msg_type_number_t i, count;
3803
3804 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
3805 saddr = (mach_msg_descriptor_t *) (body + 1);
3806 count = body->msgh_descriptor_count;
3807
3808 for (i = 0; i < count; i++, saddr++) {
3809 switch (saddr->type.type) {
3810 case MACH_MSG_PORT_DESCRIPTOR: {
3811 mach_msg_type_name_t name;
3812 ipc_object_t object;
3813 mach_msg_port_descriptor_t *dsc;
3814
3815 dsc = &saddr->port;
3816
3817 /* this is really the type SEND, SEND_ONCE, etc. */
3818 name = dsc->disposition;
cb323159 3819 object = ip_to_object(dsc->name);
0a7de745
A
3820 dsc->disposition = ipc_object_copyin_type(name);
3821
3822 if (!IO_VALID(object)) {
3823 break;
3824 }
3825
3826 ipc_object_copyin_from_kernel(object, name);
3827
3828 /* CDY avoid circularity when the destination is also */
3829 /* the kernel. This check should be changed into an */
3830 /* assert when the new kobject model is in place since*/
3831 /* ports will not be used in kernel to kernel chats */
3832
cb323159 3833 if (ip_object_to_port(remote)->ip_receiver != ipc_space_kernel) {
0a7de745 3834 if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
cb323159
A
3835 ipc_port_check_circularity(ip_object_to_port(object),
3836 ip_object_to_port(remote))) {
0a7de745
A
3837 kmsg->ikm_header->msgh_bits |=
3838 MACH_MSGH_BITS_CIRCULAR;
3839 }
3840 }
3841 break;
3842 }
3843 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
3844 case MACH_MSG_OOL_DESCRIPTOR: {
3845 /*
3846 * The sender should supply ready-made memory, i.e.
3847 * a vm_map_copy_t, so we don't need to do anything.
3848 */
3849 break;
3850 }
3851 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
3852 ipc_object_t *objects;
3853 unsigned int j;
3854 mach_msg_type_name_t name;
3855 mach_msg_ool_ports_descriptor_t *dsc;
3856
3857 dsc = (mach_msg_ool_ports_descriptor_t *)&saddr->ool_ports;
3858
3859 /* this is really the type SEND, SEND_ONCE, etc. */
3860 name = dsc->disposition;
3861 dsc->disposition = ipc_object_copyin_type(name);
3862
3863 objects = (ipc_object_t *) dsc->address;
3864
3865 for (j = 0; j < dsc->count; j++) {
3866 ipc_object_t object = objects[j];
3867
3868 if (!IO_VALID(object)) {
3869 continue;
3870 }
3871
3872 ipc_object_copyin_from_kernel(object, name);
3873
3874 if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
cb323159
A
3875 ipc_port_check_circularity(ip_object_to_port(object),
3876 ip_object_to_port(remote))) {
3877 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
3878 }
3879 }
3880 break;
3881 }
3882 case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
3883 mach_msg_guarded_port_descriptor_t *dsc = (typeof(dsc)) & saddr->guarded_port;
3884 mach_msg_type_name_t disp = dsc->disposition;
3885 ipc_object_t object = ip_to_object(dsc->name);
3886 dsc->disposition = ipc_object_copyin_type(disp);
3887 assert(dsc->flags == 0);
3888
3889 if (!IO_VALID(object)) {
3890 break;
3891 }
3892
3893 ipc_object_copyin_from_kernel(object, disp);
3894 /*
3895 * avoid circularity when the destination is also
3896 * the kernel. This check should be changed into an
3897 * assert when the new kobject model is in place since
3898 * ports will not be used in kernel to kernel chats
3899 */
3900
3901 if (ip_object_to_port(remote)->ip_receiver != ipc_space_kernel) {
3902 if ((dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
3903 ipc_port_check_circularity(ip_object_to_port(object),
3904 ip_object_to_port(remote))) {
0a7de745
A
3905 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
3906 }
3907 }
3908 break;
3909 }
3910 default: {
3911#if MACH_ASSERT
3912 panic("ipc_kmsg_copyin_from_kernel: bad descriptor");
3913#endif /* MACH_ASSERT */
3914 }
3915 }
1c79356b 3916 }
1c79356b 3917 }
0a7de745 3918 return MACH_MSG_SUCCESS;
1c79356b
A
3919}
3920
b0d623f7 3921#if IKM_SUPPORT_LEGACY
6d2010ae 3922mach_msg_return_t
b0d623f7 3923ipc_kmsg_copyin_from_kernel_legacy(
0a7de745 3924 ipc_kmsg_t kmsg)
b0d623f7
A
3925{
3926 mach_msg_bits_t bits = kmsg->ikm_header->msgh_bits;
3927 mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
3928 mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
cb323159
A
3929 ipc_object_t remote = ip_to_object(kmsg->ikm_header->msgh_remote_port);
3930 ipc_object_t local = ip_to_object(kmsg->ikm_header->msgh_local_port);
3931 ipc_port_t dest = kmsg->ikm_header->msgh_remote_port;
b0d623f7
A
3932
3933 /* translate the destination and reply ports */
0a7de745 3934 if (!IO_VALID(remote)) {
6d2010ae 3935 return MACH_SEND_INVALID_DEST;
0a7de745 3936 }
b0d623f7
A
3937
3938 ipc_object_copyin_from_kernel(remote, rname);
0a7de745 3939 if (IO_VALID(local)) {
b0d623f7 3940 ipc_object_copyin_from_kernel(local, lname);
0a7de745 3941 }
b0d623f7
A
3942
3943 /*
3944 * The common case is a complex message with no reply port,
3945 * because that is what the memory_object interface uses.
3946 */
3947
3948 if (bits == (MACH_MSGH_BITS_COMPLEX |
0a7de745 3949 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
b0d623f7 3950 bits = (MACH_MSGH_BITS_COMPLEX |
0a7de745 3951 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
b0d623f7
A
3952
3953 kmsg->ikm_header->msgh_bits = bits;
3954 } else {
3955 bits = (MACH_MSGH_BITS_OTHER(bits) |
0a7de745
A
3956 MACH_MSGH_BITS(ipc_object_copyin_type(rname),
3957 ipc_object_copyin_type(lname)));
b0d623f7
A
3958
3959 kmsg->ikm_header->msgh_bits = bits;
0a7de745 3960 if ((bits & MACH_MSGH_BITS_COMPLEX) == 0) {
6d2010ae 3961 return MACH_MSG_SUCCESS;
0a7de745 3962 }
b0d623f7 3963 }
cb323159
A
3964
3965 if (dest->ip_no_grant) {
3966 mach_msg_descriptor_t *saddr;
3967 mach_msg_body_t *body;
3968 mach_msg_type_number_t i, count;
3969
3970 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
3971 saddr = (mach_msg_descriptor_t *) (body + 1);
3972 count = body->msgh_descriptor_count;
3973
3974 for (i = 0; i < count; i++, saddr++) {
3975 switch (saddr->type.type) {
3976 case MACH_MSG_PORT_DESCRIPTOR:
3977 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
3978 case MACH_MSG_GUARDED_PORT_DESCRIPTOR:
3979 /* no descriptors have been copied in yet */
3980 ipc_kmsg_clean_partial(kmsg, 0, NULL, 0, 0);
3981 return MACH_SEND_NO_GRANT_DEST;
3982 }
3983 }
3984 }
3985
0a7de745
A
3986 {
3987 mach_msg_legacy_descriptor_t *saddr;
3988 mach_msg_descriptor_t *daddr;
3989 mach_msg_body_t *body;
3990 mach_msg_type_number_t i, count;
3991
3992 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
3993 saddr = (typeof(saddr))(body + 1);
3994 count = body->msgh_descriptor_count;
3995
3996 if (count) {
3997 vm_offset_t dsc_adjust = 4 * count;
3998 memmove((char *)(((vm_offset_t)kmsg->ikm_header) - dsc_adjust), kmsg->ikm_header, sizeof(mach_msg_base_t));
3999 kmsg->ikm_header = (mach_msg_header_t *)((vm_offset_t)kmsg->ikm_header - dsc_adjust);
4000 /* Update the message size for the larger in-kernel representation */
4001 kmsg->ikm_header->msgh_size += dsc_adjust;
4002 }
4003 daddr = (mach_msg_descriptor_t *)((vm_offset_t)kmsg->ikm_header + sizeof(mach_msg_base_t));
4004
4005 for (i = 0; i < count; i++, saddr++, daddr++) {
4006 switch (saddr->type.type) {
4007 case MACH_MSG_PORT_DESCRIPTOR: {
4008 mach_msg_type_name_t name;
4009 ipc_object_t object;
4010 mach_msg_legacy_port_descriptor_t *dsc;
4011 mach_msg_port_descriptor_t *dest_dsc;
4012
4013 dsc = (typeof(dsc)) & saddr->port;
4014 dest_dsc = &daddr->port;
4015
4016 /* this is really the type SEND, SEND_ONCE, etc. */
4017 name = dsc->disposition;
cb323159 4018 object = ip_to_object(CAST_MACH_NAME_TO_PORT(dsc->name));
0a7de745 4019 dest_dsc->disposition = ipc_object_copyin_type(name);
cb323159 4020 dest_dsc->name = ip_object_to_port(object);
0a7de745
A
4021 dest_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
4022
4023 if (!IO_VALID(object)) {
4024 break;
4025 }
4026
4027 ipc_object_copyin_from_kernel(object, name);
4028
4029 /* CDY avoid circularity when the destination is also */
4030 /* the kernel. This check should be changed into an */
4031 /* assert when the new kobject model is in place since*/
4032 /* ports will not be used in kernel to kernel chats */
4033
cb323159 4034 if (ip_object_to_port(remote)->ip_receiver != ipc_space_kernel) {
0a7de745 4035 if ((dest_dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
cb323159
A
4036 ipc_port_check_circularity(ip_object_to_port(object),
4037 ip_object_to_port(remote))) {
0a7de745
A
4038 kmsg->ikm_header->msgh_bits |=
4039 MACH_MSGH_BITS_CIRCULAR;
4040 }
4041 }
4042 break;
4043 }
4044 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
4045 case MACH_MSG_OOL_DESCRIPTOR: {
4046 /* The sender should supply ready-made memory, i.e. a vm_map_copy_t
4047 * so we don't need to do anything special. */
4048
4049 mach_msg_ool_descriptor32_t *source_dsc = &saddr->out_of_line32;
4050 mach_msg_ool_descriptor_t *dest_dsc = (typeof(dest_dsc)) & daddr->out_of_line;
4051
4052 vm_offset_t address = source_dsc->address;
4053 vm_size_t size = source_dsc->size;
4054 boolean_t deallocate = source_dsc->deallocate;
4055 mach_msg_copy_options_t copy = source_dsc->copy;
4056 mach_msg_descriptor_type_t type = source_dsc->type;
4057
4058 dest_dsc->address = (void *)address;
4059 dest_dsc->size = size;
4060 dest_dsc->deallocate = deallocate;
4061 dest_dsc->copy = copy;
4062 dest_dsc->type = type;
4063 break;
4064 }
4065 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
4066 ipc_object_t *objects;
4067 unsigned int j;
4068 mach_msg_type_name_t name;
4069 mach_msg_ool_ports_descriptor_t *dest_dsc;
4070
4071 mach_msg_ool_ports_descriptor32_t *source_dsc = &saddr->ool_ports32;
4072 dest_dsc = (typeof(dest_dsc)) & daddr->ool_ports;
4073
4074 boolean_t deallocate = source_dsc->deallocate;
4075 mach_msg_copy_options_t copy = source_dsc->copy;
4076 mach_msg_size_t port_count = source_dsc->count;
4077 mach_msg_type_name_t disposition = source_dsc->disposition;
4078
4079 /* this is really the type SEND, SEND_ONCE, etc. */
4080 name = disposition;
4081 disposition = ipc_object_copyin_type(name);
4082
4083 objects = (ipc_object_t *) (uintptr_t)source_dsc->address;
4084
4085 for (j = 0; j < port_count; j++) {
4086 ipc_object_t object = objects[j];
4087
4088 if (!IO_VALID(object)) {
4089 continue;
4090 }
4091
4092 ipc_object_copyin_from_kernel(object, name);
4093
4094 if ((disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
cb323159
A
4095 ipc_port_check_circularity(ip_object_to_port(object),
4096 ip_object_to_port(remote))) {
0a7de745
A
4097 kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_CIRCULAR;
4098 }
4099 }
4100
4101 dest_dsc->address = objects;
4102 dest_dsc->deallocate = deallocate;
4103 dest_dsc->copy = copy;
4104 dest_dsc->disposition = disposition;
4105 dest_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
4106 dest_dsc->count = port_count;
4107 break;
4108 }
cb323159
A
4109 case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
4110 mach_msg_type_name_t disp;
4111 ipc_object_t object;
4112 mach_msg_guarded_port_descriptor32_t *dsc;
4113 mach_msg_guarded_port_descriptor_t *dest_dsc;
4114
4115 dsc = (typeof(dsc)) & saddr->guarded_port32;
4116 dest_dsc = &daddr->guarded_port;
4117
4118 disp = dsc->disposition;
4119 object = ip_to_object(CAST_MACH_NAME_TO_PORT(dsc->name));
4120 assert(dsc->flags == 0);
4121 assert(dsc->context == 0);
4122
4123 dest_dsc->disposition = ipc_object_copyin_type(disp);
4124 dest_dsc->name = ip_object_to_port(object);
4125 dest_dsc->type = MACH_MSG_GUARDED_PORT_DESCRIPTOR;
4126 dest_dsc->flags = 0;
4127
4128 if (!IO_VALID(object)) {
4129 break;
4130 }
4131
4132 ipc_object_copyin_from_kernel(object, disp);
4133
4134 /* CDY avoid circularity when the destination is also */
4135 /* the kernel. This check should be changed into an */
4136 /* assert when the new kobject model is in place since*/
4137 /* ports will not be used in kernel to kernel chats */
4138
4139 if (ip_object_to_port(remote)->ip_receiver != ipc_space_kernel) {
4140 if ((dest_dsc->disposition == MACH_MSG_TYPE_PORT_RECEIVE) &&
4141 ipc_port_check_circularity(ip_object_to_port(object),
4142 ip_object_to_port(remote))) {
4143 kmsg->ikm_header->msgh_bits |=
4144 MACH_MSGH_BITS_CIRCULAR;
4145 }
4146 }
4147 break;
4148 }
0a7de745
A
4149 default: {
4150#if MACH_ASSERT
4151 panic("ipc_kmsg_copyin_from_kernel: bad descriptor");
4152#endif /* MACH_ASSERT */
4153 }
4154 }
b0d623f7 4155 }
b0d623f7 4156 }
0a7de745 4157 return MACH_MSG_SUCCESS;
b0d623f7
A
4158}
4159#endif /* IKM_SUPPORT_LEGACY */
4160
1c79356b
A
4161/*
4162 * Routine: ipc_kmsg_copyout_header
4163 * Purpose:
4164 * "Copy-out" port rights in the header of a message.
4165 * Operates atomically; if it doesn't succeed the
4166 * message header and the space are left untouched.
4167 * If it does succeed the remote/local port fields
4168 * contain port names instead of object pointers,
4169 * and the bits field is updated.
1c79356b
A
4170 * Conditions:
4171 * Nothing locked.
4172 * Returns:
4173 * MACH_MSG_SUCCESS Copied out port rights.
0a7de745 4174 * MACH_RCV_INVALID_NOTIFY
1c79356b
A
4175 * Notify is non-null and doesn't name a receive right.
4176 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
4177 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
4178 * The space is dead.
4179 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
4180 * No room in space for another name.
4181 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
4182 * Couldn't allocate memory for the reply port.
4183 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
4184 * Couldn't allocate memory for the dead-name request.
4185 */
4186
4187mach_msg_return_t
4188ipc_kmsg_copyout_header(
fe8ab488 4189 ipc_kmsg_t kmsg,
0a7de745
A
4190 ipc_space_t space,
4191 mach_msg_option_t option)
1c79356b 4192{
fe8ab488 4193 mach_msg_header_t *msg = kmsg->ikm_header;
1c79356b 4194 mach_msg_bits_t mbits = msg->msgh_bits;
cb323159 4195 ipc_port_t dest = msg->msgh_remote_port;
1c79356b
A
4196
4197 assert(IP_VALID(dest));
4198
6d2010ae
A
4199 /*
4200 * While we still hold a reference on the received-from port,
4201 * process all send-possible notfications we received along with
4202 * the message.
4203 */
4204 ipc_port_spnotify(dest);
4205
0a7de745
A
4206 {
4207 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
4208 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
4209 mach_msg_type_name_t voucher_type = MACH_MSGH_BITS_VOUCHER(mbits);
4210 ipc_port_t reply = msg->msgh_local_port;
4211 ipc_port_t release_reply_port = IP_NULL;
4212 mach_port_name_t dest_name, reply_name;
1c79356b 4213
0a7de745
A
4214 ipc_port_t voucher = kmsg->ikm_voucher;
4215 ipc_port_t release_voucher_port = IP_NULL;
4216 mach_port_name_t voucher_name;
fe8ab488 4217
0a7de745
A
4218 uint32_t entries_held = 0;
4219 boolean_t need_write_lock = FALSE;
4220 kern_return_t kr;
1c79356b 4221
0a7de745
A
4222 /*
4223 * Reserve any potentially needed entries in the target space.
4224 * We'll free any unused before unlocking the space.
4225 */
4226 if (IP_VALID(reply)) {
4227 entries_held++;
4228 need_write_lock = TRUE;
4229 }
4230 if (IP_VALID(voucher)) {
4231 assert(voucher_type == MACH_MSG_TYPE_MOVE_SEND);
1c79356b 4232
0a7de745
A
4233 if ((option & MACH_RCV_VOUCHER) != 0) {
4234 entries_held++;
1c79356b 4235 }
0a7de745 4236 need_write_lock = TRUE;
fe8ab488 4237 }
1c79356b 4238
0a7de745
A
4239 if (need_write_lock) {
4240 is_write_lock(space);
1c79356b 4241
0a7de745
A
4242 while (entries_held) {
4243 if (!is_active(space)) {
4244 is_write_unlock(space);
4245 return MACH_RCV_HEADER_ERROR |
4246 MACH_MSG_IPC_SPACE;
1c79356b 4247 }
fe8ab488 4248
0a7de745
A
4249 kr = ipc_entries_hold(space, entries_held);
4250 if (KERN_SUCCESS == kr) {
4251 break;
4252 }
1c79356b 4253
0a7de745
A
4254 kr = ipc_entry_grow_table(space, ITS_SIZE_NONE);
4255 if (KERN_SUCCESS != kr) {
4256 return MACH_RCV_HEADER_ERROR |
4257 MACH_MSG_IPC_SPACE;
fe8ab488 4258 }
0a7de745 4259 /* space was unlocked and relocked - retry */
fe8ab488 4260 }
fe8ab488 4261
0a7de745
A
4262 /* Handle reply port. */
4263 if (IP_VALID(reply)) {
fe8ab488
A
4264 ipc_entry_t entry;
4265
0a7de745
A
4266 /* Is there already an entry we can use? */
4267 if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
cb323159 4268 ipc_right_reverse(space, ip_to_object(reply), &reply_name, &entry)) {
0a7de745
A
4269 /* reply port is locked and active */
4270 assert(entry->ie_bits & MACH_PORT_TYPE_SEND_RECEIVE);
fe8ab488 4271 } else {
0a7de745
A
4272 ip_lock(reply);
4273 if (!ip_active(reply)) {
cb323159
A
4274 /* clear the context value */
4275 reply->ip_reply_context = 0;
0a7de745
A
4276 ip_unlock(reply);
4277
4278 release_reply_port = reply;
4279 reply = IP_DEAD;
4280 reply_name = MACH_PORT_DEAD;
4281 goto done_with_reply;
4282 }
4283
4284 /* claim a held entry for the reply port */
fe8ab488
A
4285 assert(entries_held > 0);
4286 entries_held--;
0a7de745 4287 ipc_entry_claim(space, &reply_name, &entry);
fe8ab488 4288 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
0a7de745 4289 assert(entry->ie_object == IO_NULL);
cb323159 4290 entry->ie_object = ip_to_object(reply);
fe8ab488 4291 }
0a7de745
A
4292
4293 /* space and reply port are locked and active */
cb323159
A
4294 ip_reference(reply); /* hold onto the reply port */
4295
4296 /*
4297 * If the receiver would like to enforce strict reply
4298 * semantics, and the message looks like it expects a reply,
4299 * and contains a voucher, then link the context in the
4300 * voucher with the reply port so that the next message sent
4301 * to the reply port must come from a thread that has a
4302 * matching context (voucher).
4303 */
4304 if (enforce_strict_reply && MACH_RCV_WITH_STRICT_REPLY(option) && IP_VALID(voucher)) {
4305 if (ipc_kmsg_validate_reply_port_locked(reply, option) != KERN_SUCCESS) {
4306 /* if the receiver isn't happy with the reply port: fail the receive. */
4307 ip_unlock(reply);
4308 ipc_entry_dealloc(space, reply_name, entry);
4309 is_write_unlock(space);
4310 ip_release(reply);
4311 return MACH_RCV_INVALID_REPLY;
4312 }
4313 ipc_kmsg_link_reply_context_locked(reply, voucher);
4314 } else {
4315 /*
4316 * if the receive did not choose to participate
4317 * in the strict reply/RPC, then don't enforce
4318 * anything (as this could lead to booby-trapped
4319 * messages that kill the server).
4320 */
4321 reply->ip_reply_context = 0;
4322 }
0a7de745
A
4323
4324 kr = ipc_right_copyout(space, reply_name, entry,
cb323159 4325 reply_type, NULL, NULL, ip_to_object(reply));
0a7de745
A
4326 assert(kr == KERN_SUCCESS);
4327 /* reply port is unlocked */
fe8ab488 4328 } else {
0a7de745 4329 reply_name = CAST_MACH_PORT_TO_NAME(reply);
fe8ab488 4330 }
39236c6e 4331
0a7de745 4332done_with_reply:
1c79356b 4333
0a7de745
A
4334 /* Handle voucher port. */
4335 if (voucher_type != MACH_MSGH_BITS_ZERO) {
4336 assert(voucher_type == MACH_MSG_TYPE_MOVE_SEND);
39236c6e 4337
0a7de745
A
4338 if (!IP_VALID(voucher)) {
4339 if ((option & MACH_RCV_VOUCHER) == 0) {
4340 voucher_type = MACH_MSGH_BITS_ZERO;
4341 }
4342 voucher_name = MACH_PORT_NULL;
4343 goto done_with_voucher;
4344 }
1c79356b 4345
0a7de745
A
4346 /* clear voucher from its hiding place back in the kmsg */
4347 kmsg->ikm_voucher = IP_NULL;
4348
4349 if ((option & MACH_RCV_VOUCHER) != 0) {
4350 ipc_entry_t entry;
4351
cb323159 4352 if (ipc_right_reverse(space, ip_to_object(voucher),
0a7de745
A
4353 &voucher_name, &entry)) {
4354 /* voucher port locked */
4355 assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
4356 } else {
4357 assert(entries_held > 0);
4358 entries_held--;
4359 ipc_entry_claim(space, &voucher_name, &entry);
4360 assert(IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE);
4361 assert(entry->ie_object == IO_NULL);
cb323159 4362 entry->ie_object = ip_to_object(voucher);
0a7de745
A
4363 ip_lock(voucher);
4364 }
4365 /* space is locked and active */
cb323159 4366 require_ip_active(voucher);
0a7de745
A
4367 assert(ip_kotype(voucher) == IKOT_VOUCHER);
4368 kr = ipc_right_copyout(space, voucher_name, entry,
cb323159
A
4369 MACH_MSG_TYPE_MOVE_SEND, NULL, NULL,
4370 ip_to_object(voucher));
0a7de745
A
4371 /* voucher port is unlocked */
4372 } else {
4373 voucher_type = MACH_MSGH_BITS_ZERO;
4374 release_voucher_port = voucher;
4375 voucher_name = MACH_PORT_NULL;
4376 }
4377 } else {
4378 voucher_name = msg->msgh_voucher_port;
4379 }
1c79356b 4380
0a7de745 4381done_with_voucher:
1c79356b 4382
0a7de745
A
4383 ip_lock(dest);
4384 is_write_unlock(space);
4385 } else {
4386 /*
4387 * No reply or voucher port! This is an easy case.
4388 * We only need to have the space locked
4389 * when locking the destination.
4390 */
fe8ab488 4391
0a7de745
A
4392 is_read_lock(space);
4393 if (!is_active(space)) {
4394 is_read_unlock(space);
4395 return MACH_RCV_HEADER_ERROR | MACH_MSG_IPC_SPACE;
4396 }
4397
4398 ip_lock(dest);
4399 is_read_unlock(space);
4400
4401 reply_name = CAST_MACH_PORT_TO_NAME(reply);
4402
4403 if (voucher_type != MACH_MSGH_BITS_ZERO) {
4404 assert(voucher_type == MACH_MSG_TYPE_MOVE_SEND);
4405 if ((option & MACH_RCV_VOUCHER) == 0) {
4406 voucher_type = MACH_MSGH_BITS_ZERO;
4407 }
4408 voucher_name = MACH_PORT_NULL;
4409 } else {
4410 voucher_name = msg->msgh_voucher_port;
fe8ab488 4411 }
fe8ab488 4412 }
1c79356b 4413
0a7de745
A
4414 /*
4415 * At this point, the space is unlocked and the destination
4416 * port is locked. (Lock taken while space was locked.)
4417 * reply_name is taken care of; we still need dest_name.
4418 * We still hold a ref for reply (if it is valid).
4419 *
4420 * If the space holds receive rights for the destination,
4421 * we return its name for the right. Otherwise the task
4422 * managed to destroy or give away the receive right between
4423 * receiving the message and this copyout. If the destination
4424 * is dead, return MACH_PORT_DEAD, and if the receive right
4425 * exists somewhere else (another space, in transit)
4426 * return MACH_PORT_NULL.
4427 *
4428 * Making this copyout operation atomic with the previous
4429 * copyout of the reply port is a bit tricky. If there was
4430 * no real reply port (it wasn't IP_VALID) then this isn't
4431 * an issue. If the reply port was dead at copyout time,
4432 * then we are OK, because if dest is dead we serialize
4433 * after the death of both ports and if dest is alive
4434 * we serialize after reply died but before dest's (later) death.
4435 * So assume reply was alive when we copied it out. If dest
4436 * is alive, then we are OK because we serialize before
4437 * the ports' deaths. So assume dest is dead when we look at it.
4438 * If reply dies/died after dest, then we are OK because
4439 * we serialize after dest died but before reply dies.
4440 * So the hard case is when reply is alive at copyout,
4441 * dest is dead at copyout, and reply died before dest died.
4442 * In this case pretend that dest is still alive, so
4443 * we serialize while both ports are alive.
4444 *
4445 * Because the space lock is held across the copyout of reply
4446 * and locking dest, the receive right for dest can't move
4447 * in or out of the space while the copyouts happen, so
4448 * that isn't an atomicity problem. In the last hard case
4449 * above, this implies that when dest is dead that the
4450 * space couldn't have had receive rights for dest at
4451 * the time reply was copied-out, so when we pretend
4452 * that dest is still alive, we can return MACH_PORT_NULL.
4453 *
4454 * If dest == reply, then we have to make it look like
4455 * either both copyouts happened before the port died,
4456 * or both happened after the port died. This special
4457 * case works naturally if the timestamp comparison
4458 * is done correctly.
4459 */
1c79356b 4460
0a7de745 4461 if (ip_active(dest)) {
cb323159 4462 ipc_object_copyout_dest(space, ip_to_object(dest),
0a7de745
A
4463 dest_type, &dest_name);
4464 /* dest is unlocked */
4465 } else {
4466 ipc_port_timestamp_t timestamp;
39236c6e 4467
0a7de745
A
4468 timestamp = dest->ip_timestamp;
4469 ip_unlock(dest);
4470 ip_release(dest);
1c79356b 4471
0a7de745
A
4472 if (IP_VALID(reply)) {
4473 ip_lock(reply);
4474 if (ip_active(reply) ||
4475 IP_TIMESTAMP_ORDER(timestamp,
4476 reply->ip_timestamp)) {
4477 dest_name = MACH_PORT_DEAD;
4478 } else {
4479 dest_name = MACH_PORT_NULL;
4480 }
4481 ip_unlock(reply);
4482 } else {
4483 dest_name = MACH_PORT_DEAD;
4484 }
4485 }
1c79356b
A
4486
4487 if (IP_VALID(reply)) {
0a7de745
A
4488 ip_release(reply);
4489 }
1c79356b 4490
0a7de745
A
4491 if (IP_VALID(release_reply_port)) {
4492 if (reply_type == MACH_MSG_TYPE_PORT_SEND_ONCE) {
4493 ipc_port_release_sonce(release_reply_port);
4494 } else {
4495 ipc_port_release_send(release_reply_port);
4496 }
4497 }
316670eb 4498
0a7de745
A
4499 if ((option & MACH_RCV_VOUCHER) != 0) {
4500 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_MSG_RECV) | DBG_FUNC_NONE,
4501 VM_KERNEL_ADDRPERM((uintptr_t)kmsg),
4502 (uintptr_t)kmsg->ikm_header->msgh_bits,
4503 (uintptr_t)kmsg->ikm_header->msgh_id,
4504 VM_KERNEL_ADDRPERM((uintptr_t)unsafe_convert_port_to_voucher(voucher)),
4505 0);
4506 } else {
4507 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_MSG_RECV_VOUCHER_REFUSED) | DBG_FUNC_NONE,
4508 VM_KERNEL_ADDRPERM((uintptr_t)kmsg),
4509 (uintptr_t)kmsg->ikm_header->msgh_bits,
4510 (uintptr_t)kmsg->ikm_header->msgh_id,
4511 VM_KERNEL_ADDRPERM((uintptr_t)unsafe_convert_port_to_voucher(voucher)),
4512 0);
4513 }
1c79356b 4514
cb323159
A
4515 if (IP_VALID(release_voucher_port)) {
4516 ipc_port_release_send(release_voucher_port);
4517 }
4518
0a7de745
A
4519 msg->msgh_bits = MACH_MSGH_BITS_SET(reply_type, dest_type,
4520 voucher_type, mbits);
4521 msg->msgh_local_port = CAST_MACH_NAME_TO_PORT(dest_name);
4522 msg->msgh_remote_port = CAST_MACH_NAME_TO_PORT(reply_name);
4523 msg->msgh_voucher_port = voucher_name;
4524 }
4525
4526 return MACH_MSG_SUCCESS;
1c79356b
A
4527}
4528
4529/*
4530 * Routine: ipc_kmsg_copyout_object
4531 * Purpose:
4532 * Copy-out a port right. Always returns a name,
4533 * even for unsuccessful return codes. Always
4534 * consumes the supplied object.
4535 * Conditions:
4536 * Nothing locked.
4537 * Returns:
4538 * MACH_MSG_SUCCESS The space acquired the right
4539 * (name is valid) or the object is dead (MACH_PORT_DEAD).
4540 * MACH_MSG_IPC_SPACE No room in space for the right,
4541 * or the space is dead. (Name is MACH_PORT_NULL.)
4542 * MACH_MSG_IPC_KERNEL Kernel resource shortage.
4543 * (Name is MACH_PORT_NULL.)
4544 */
4545
4546mach_msg_return_t
4547ipc_kmsg_copyout_object(
0a7de745
A
4548 ipc_space_t space,
4549 ipc_object_t object,
4550 mach_msg_type_name_t msgt_name,
cb323159
A
4551 mach_port_context_t *context,
4552 mach_msg_guard_flags_t *guard_flags,
0a7de745 4553 mach_port_name_t *namep)
1c79356b
A
4554{
4555 kern_return_t kr;
4556
4557 if (!IO_VALID(object)) {
b0d623f7 4558 *namep = CAST_MACH_PORT_TO_NAME(object);
1c79356b
A
4559 return MACH_MSG_SUCCESS;
4560 }
4561
cb323159 4562 kr = ipc_object_copyout(space, object, msgt_name, context, guard_flags, namep);
1c79356b
A
4563 if (kr != KERN_SUCCESS) {
4564 ipc_object_destroy(object, msgt_name);
4565
0a7de745 4566 if (kr == KERN_INVALID_CAPABILITY) {
1c79356b 4567 *namep = MACH_PORT_DEAD;
0a7de745 4568 } else {
1c79356b
A
4569 *namep = MACH_PORT_NULL;
4570
0a7de745 4571 if (kr == KERN_RESOURCE_SHORTAGE) {
1c79356b 4572 return MACH_MSG_IPC_KERNEL;
0a7de745 4573 } else {
1c79356b 4574 return MACH_MSG_IPC_SPACE;
0a7de745 4575 }
1c79356b
A
4576 }
4577 }
4578
4579 return MACH_MSG_SUCCESS;
4580}
4581
cb323159 4582static mach_msg_descriptor_t *
b0d623f7 4583ipc_kmsg_copyout_port_descriptor(mach_msg_descriptor_t *dsc,
0a7de745
A
4584 mach_msg_descriptor_t *dest_dsc,
4585 ipc_space_t space,
4586 kern_return_t *mr)
b0d623f7 4587{
0a7de745
A
4588 mach_port_t port;
4589 mach_port_name_t name;
4590 mach_msg_type_name_t disp;
4591
0a7de745
A
4592 /* Copyout port right carried in the message */
4593 port = dsc->port.name;
4594 disp = dsc->port.disposition;
4595 *mr |= ipc_kmsg_copyout_object(space,
cb323159 4596 ip_to_object(port), disp, NULL, NULL, &name);
0a7de745
A
4597
4598 if (current_task() == kernel_task) {
4599 mach_msg_port_descriptor_t *user_dsc = (typeof(user_dsc))dest_dsc;
cb323159 4600 user_dsc--; // point to the start of this port descriptor
0a7de745
A
4601 bzero((void *)user_dsc, sizeof(*user_dsc));
4602 user_dsc->name = CAST_MACH_NAME_TO_PORT(name);
4603 user_dsc->disposition = disp;
4604 user_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
4605 dest_dsc = (typeof(dest_dsc))user_dsc;
4606 } else {
4607 mach_msg_legacy_port_descriptor_t *user_dsc = (typeof(user_dsc))dest_dsc;
cb323159 4608 user_dsc--; // point to the start of this port descriptor
0a7de745
A
4609 bzero((void *)user_dsc, sizeof(*user_dsc));
4610 user_dsc->name = CAST_MACH_PORT_TO_NAME(name);
4611 user_dsc->disposition = disp;
4612 user_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
4613 dest_dsc = (typeof(dest_dsc))user_dsc;
4614 }
4615
4616 return (mach_msg_descriptor_t *)dest_dsc;
b0d623f7
A
4617}
4618
4619mach_msg_descriptor_t *
4620ipc_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);
4621mach_msg_descriptor_t *
4622ipc_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)
4623{
0a7de745
A
4624 vm_map_copy_t copy;
4625 vm_map_address_t rcv_addr;
4626 mach_msg_copy_options_t copy_options;
4627 vm_map_size_t size;
4628 mach_msg_descriptor_type_t dsc_type;
4629
4630 //SKIP_PORT_DESCRIPTORS(saddr, sdsc_count);
4631
4632 copy = (vm_map_copy_t)dsc->address;
4633 size = (vm_map_size_t)dsc->size;
4634 copy_options = dsc->copy;
4635 assert(copy_options != MACH_MSG_KALLOC_COPY_T);
4636 dsc_type = dsc->type;
4637
4638 if (copy != VM_MAP_COPY_NULL) {
4639 kern_return_t kr;
4640
4641 rcv_addr = 0;
4642 if (vm_map_copy_validate_size(map, copy, &size) == FALSE) {
4643 panic("Inconsistent OOL/copyout size on %p: expected %d, got %lld @%p",
4644 dsc, dsc->size, (unsigned long long)copy->size, copy);
4645 }
4646 kr = vm_map_copyout_size(map, &rcv_addr, copy, size);
4647 if (kr != KERN_SUCCESS) {
4648 if (kr == KERN_RESOURCE_SHORTAGE) {
4649 *mr |= MACH_MSG_VM_KERNEL;
4650 } else {
4651 *mr |= MACH_MSG_VM_SPACE;
4652 }
4653 vm_map_copy_discard(copy);
4654 rcv_addr = 0;
4655 size = 0;
4656 }
4657 } else {
4658 rcv_addr = 0;
4659 size = 0;
4660 }
b0d623f7 4661
0a7de745
A
4662 /*
4663 * Now update the descriptor as the user would see it.
4664 * This may require expanding the descriptor to the user
4665 * visible size. There is already space allocated for
4666 * this in what naddr points to.
4667 */
4668 if (current_task() == kernel_task) {
4669 mach_msg_ool_descriptor_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
4670 user_ool_dsc--;
4671 bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
4672
4673 user_ool_dsc->address = (void *)(uintptr_t)rcv_addr;
4674 user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
4675 TRUE : FALSE;
4676 user_ool_dsc->copy = copy_options;
4677 user_ool_dsc->type = dsc_type;
4678 user_ool_dsc->size = (mach_msg_size_t)size;
4679
4680 user_dsc = (typeof(user_dsc))user_ool_dsc;
4681 } else if (is_64bit) {
4682 mach_msg_ool_descriptor64_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
4683 user_ool_dsc--;
4684 bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
4685
4686 user_ool_dsc->address = rcv_addr;
4687 user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
4688 TRUE : FALSE;
4689 user_ool_dsc->copy = copy_options;
4690 user_ool_dsc->type = dsc_type;
4691 user_ool_dsc->size = (mach_msg_size_t)size;
4692
4693 user_dsc = (typeof(user_dsc))user_ool_dsc;
4694 } else {
4695 mach_msg_ool_descriptor32_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
4696 user_ool_dsc--;
4697 bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
4698
4699 user_ool_dsc->address = CAST_DOWN_EXPLICIT(uint32_t, rcv_addr);
4700 user_ool_dsc->size = (mach_msg_size_t)size;
4701 user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
4702 TRUE : FALSE;
4703 user_ool_dsc->copy = copy_options;
4704 user_ool_dsc->type = dsc_type;
4705
4706 user_dsc = (typeof(user_dsc))user_ool_dsc;
4707 }
4708 return user_dsc;
b0d623f7
A
4709}
4710
4711mach_msg_descriptor_t *
4712ipc_kmsg_copyout_ool_ports_descriptor(mach_msg_ool_ports_descriptor_t *dsc,
0a7de745
A
4713 mach_msg_descriptor_t *user_dsc,
4714 int is_64bit,
4715 vm_map_t map,
4716 ipc_space_t space,
4717 ipc_kmsg_t kmsg,
4718 mach_msg_return_t *mr);
b0d623f7
A
4719mach_msg_descriptor_t *
4720ipc_kmsg_copyout_ool_ports_descriptor(mach_msg_ool_ports_descriptor_t *dsc,
0a7de745
A
4721 mach_msg_descriptor_t *user_dsc,
4722 int is_64bit,
4723 vm_map_t map,
4724 ipc_space_t space,
4725 ipc_kmsg_t kmsg,
4726 mach_msg_return_t *mr)
b0d623f7 4727{
0a7de745
A
4728 mach_vm_offset_t rcv_addr = 0;
4729 mach_msg_type_name_t disp;
4730 mach_msg_type_number_t count, i;
4731 vm_size_t ports_length, names_length;
b0d623f7 4732
0a7de745 4733 mach_msg_copy_options_t copy_options = MACH_MSG_VIRTUAL_COPY;
b0d623f7 4734
0a7de745 4735 //SKIP_PORT_DESCRIPTORS(saddr, sdsc_count);
b0d623f7 4736
0a7de745
A
4737 count = dsc->count;
4738 disp = dsc->disposition;
4739 ports_length = count * sizeof(mach_port_t);
4740 names_length = count * sizeof(mach_port_name_t);
b0d623f7 4741
0a7de745
A
4742 if (ports_length != 0 && dsc->address != 0) {
4743 /*
4744 * Check to see if there is an overwrite descriptor
4745 * specified in the scatter list for this ool data.
4746 * The descriptor has already been verified.
4747 */
b0d623f7 4748#if 0
0a7de745
A
4749 if (saddr != MACH_MSG_DESCRIPTOR_NULL) {
4750 if (differs) {
4751 OTHER_OOL_DESCRIPTOR *scatter_dsc;
4752
4753 scatter_dsc = (OTHER_OOL_DESCRIPTOR *)saddr;
4754 rcv_addr = (mach_vm_offset_t) scatter_dsc->address;
4755 copy_options = scatter_dsc->copy;
4756 } else {
4757 mach_msg_ool_descriptor_t *scatter_dsc;
4758
4759 scatter_dsc = &saddr->out_of_line;
4760 rcv_addr = CAST_USER_ADDR_T(scatter_dsc->address);
4761 copy_options = scatter_dsc->copy;
4762 }
4763 INCREMENT_SCATTER(saddr, sdsc_count, differs);
4764 }
b0d623f7
A
4765#endif
4766
0a7de745
A
4767 if (copy_options == MACH_MSG_VIRTUAL_COPY) {
4768 /*
4769 * Dynamically allocate the region
4770 */
4771 vm_tag_t tag;
4772 if (vm_kernel_map_is_kernel(map)) {
4773 tag = VM_KERN_MEMORY_IPC;
4774 } else {
4775 tag = VM_MEMORY_MACH_MSG;
4776 }
4777
4778 kern_return_t kr;
4779 if ((kr = mach_vm_allocate_kernel(map, &rcv_addr,
4780 (mach_vm_size_t)names_length,
4781 VM_FLAGS_ANYWHERE, tag)) != KERN_SUCCESS) {
4782 ipc_kmsg_clean_body(kmsg, 1, (mach_msg_descriptor_t *)dsc);
4783 rcv_addr = 0;
4784
4785 if (kr == KERN_RESOURCE_SHORTAGE) {
4786 *mr |= MACH_MSG_VM_KERNEL;
4787 } else {
4788 *mr |= MACH_MSG_VM_SPACE;
4789 }
4790 }
4791 }
4792
4793 /*
4794 * Handle the port rights and copy out the names
4795 * for those rights out to user-space.
4796 */
4797 if (rcv_addr != 0) {
cb323159 4798 ipc_object_t *objects = (ipc_object_t *) dsc->address;
0a7de745
A
4799 mach_port_name_t *names = (mach_port_name_t *) dsc->address;
4800
4801 /* copyout port rights carried in the message */
4802
4803 for (i = 0; i < count; i++) {
cb323159 4804 ipc_object_t object = objects[i];
0a7de745
A
4805
4806 *mr |= ipc_kmsg_copyout_object(space, object,
cb323159 4807 disp, NULL, NULL, &names[i]);
0a7de745
A
4808 }
4809
4810 /* copyout to memory allocated above */
4811 void *data = dsc->address;
4812 if (copyoutmap(map, data, rcv_addr, names_length) != KERN_SUCCESS) {
4813 *mr |= MACH_MSG_VM_SPACE;
4814 }
4815 kfree(data, ports_length);
4816 }
4817 } else {
4818 rcv_addr = 0;
4819 }
4820
4821 /*
4822 * Now update the descriptor based on the information
4823 * calculated above.
4824 */
4825 if (current_task() == kernel_task) {
4826 mach_msg_ool_ports_descriptor_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
4827 user_ool_dsc--;
4828 bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
4829
4830 user_ool_dsc->address = (void *)(uintptr_t)rcv_addr;
4831 user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
4832 TRUE : FALSE;
4833 user_ool_dsc->copy = copy_options;
4834 user_ool_dsc->disposition = disp;
4835 user_ool_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
4836 user_ool_dsc->count = count;
4837
4838 user_dsc = (typeof(user_dsc))user_ool_dsc;
4839 } else if (is_64bit) {
4840 mach_msg_ool_ports_descriptor64_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
4841 user_ool_dsc--;
4842 bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
4843
4844 user_ool_dsc->address = rcv_addr;
4845 user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
4846 TRUE : FALSE;
4847 user_ool_dsc->copy = copy_options;
4848 user_ool_dsc->disposition = disp;
4849 user_ool_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
4850 user_ool_dsc->count = count;
4851
4852 user_dsc = (typeof(user_dsc))user_ool_dsc;
4853 } else {
4854 mach_msg_ool_ports_descriptor32_t *user_ool_dsc = (typeof(user_ool_dsc))user_dsc;
4855 user_ool_dsc--;
4856 bzero((void *)user_ool_dsc, sizeof(*user_ool_dsc));
4857
4858 user_ool_dsc->address = CAST_DOWN_EXPLICIT(uint32_t, rcv_addr);
4859 user_ool_dsc->count = count;
4860 user_ool_dsc->deallocate = (copy_options == MACH_MSG_VIRTUAL_COPY) ?
4861 TRUE : FALSE;
4862 user_ool_dsc->copy = copy_options;
4863 user_ool_dsc->disposition = disp;
4864 user_ool_dsc->type = MACH_MSG_OOL_PORTS_DESCRIPTOR;
4865
4866 user_dsc = (typeof(user_dsc))user_ool_dsc;
4867 }
4868 return user_dsc;
b0d623f7
A
4869}
4870
cb323159
A
4871static mach_msg_descriptor_t *
4872ipc_kmsg_copyout_guarded_port_descriptor(
4873 mach_msg_guarded_port_descriptor_t *dsc,
4874 mach_msg_descriptor_t *dest_dsc,
4875 int is_64bit,
4876 __unused ipc_kmsg_t kmsg,
4877 ipc_space_t space,
4878 mach_msg_option_t option,
4879 kern_return_t *mr)
4880{
4881 mach_port_t port;
4882 mach_port_name_t name = MACH_PORT_NULL;
4883 mach_msg_type_name_t disp;
4884 mach_msg_guard_flags_t guard_flags;
4885 mach_port_context_t context;
4886
4887 /* Copyout port right carried in the message */
4888 port = dsc->name;
4889 disp = dsc->disposition;
4890 guard_flags = dsc->flags;
4891 context = 0;
4892
4893 /* Currently kernel_task doesnt support receiving guarded port descriptors */
4894 struct knote *kn = current_thread()->ith_knote;
4895 if ((kn != ITH_KNOTE_PSEUDO) && (((option & MACH_RCV_GUARDED_DESC) == 0) ||
4896 (current_task() == kernel_task))) {
4897#if DEVELOPMENT || DEBUG
4898 if (current_task() != kernel_task) {
4899 /*
4900 * Simulated crash needed for debugging, notifies the receiver to opt into receiving
4901 * guarded descriptors.
4902 */
4903 mach_port_guard_exception(current_thread()->ith_receiver_name, 0, 0, kGUARD_EXC_RCV_GUARDED_DESC);
4904 }
4905#endif
4906 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_DESTROY_GUARDED_DESC), current_thread()->ith_receiver_name,
4907 VM_KERNEL_ADDRPERM(port), disp, guard_flags);
4908 ipc_object_destroy(ip_to_object(port), disp);
4909 mach_msg_legacy_port_descriptor_t *user_dsc = (typeof(user_dsc))dest_dsc;
4910 user_dsc--; // point to the start of this port descriptor
4911 bzero((void *)user_dsc, sizeof(*user_dsc));
4912 user_dsc->name = name;
4913 user_dsc->disposition = disp;
4914 user_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
4915 dest_dsc = (typeof(dest_dsc))user_dsc;
4916 } else {
4917 *mr |= ipc_kmsg_copyout_object(space,
4918 ip_to_object(port), disp, &context, &guard_flags, &name);
4919
4920 if (!is_64bit) {
4921 mach_msg_guarded_port_descriptor32_t *user_dsc = (typeof(user_dsc))dest_dsc;
4922 user_dsc--; // point to the start of this port descriptor
4923 bzero((void *)user_dsc, sizeof(*user_dsc));
4924 user_dsc->name = name;
4925 user_dsc->flags = guard_flags;
4926 user_dsc->disposition = disp;
4927 user_dsc->type = MACH_MSG_GUARDED_PORT_DESCRIPTOR;
4928 user_dsc->context = CAST_DOWN_EXPLICIT(uint32_t, context);
4929 dest_dsc = (typeof(dest_dsc))user_dsc;
4930 } else {
4931 mach_msg_guarded_port_descriptor64_t *user_dsc = (typeof(user_dsc))dest_dsc;
4932 user_dsc--; // point to the start of this port descriptor
4933 bzero((void *)user_dsc, sizeof(*user_dsc));
4934 user_dsc->name = name;
4935 user_dsc->flags = guard_flags;
4936 user_dsc->disposition = disp;
4937 user_dsc->type = MACH_MSG_GUARDED_PORT_DESCRIPTOR;
4938 user_dsc->context = context;
4939 dest_dsc = (typeof(dest_dsc))user_dsc;
4940 }
4941 }
4942
4943 return (mach_msg_descriptor_t *)dest_dsc;
4944}
4945
1c79356b
A
4946/*
4947 * Routine: ipc_kmsg_copyout_body
4948 * Purpose:
4949 * "Copy-out" port rights and out-of-line memory
4950 * in the body of a message.
4951 *
4952 * The error codes are a combination of special bits.
4953 * The copyout proceeds despite errors.
4954 * Conditions:
4955 * Nothing locked.
4956 * Returns:
4957 * MACH_MSG_SUCCESS Successful copyout.
4958 * MACH_MSG_IPC_SPACE No room for port right in name space.
4959 * MACH_MSG_VM_SPACE No room for memory in address space.
4960 * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
4961 * MACH_MSG_VM_KERNEL Resource shortage handling memory.
4962 * MACH_MSG_INVALID_RT_DESCRIPTOR Descriptor incompatible with RT
4963 */
4964
4965mach_msg_return_t
4966ipc_kmsg_copyout_body(
0a7de745
A
4967 ipc_kmsg_t kmsg,
4968 ipc_space_t space,
4969 vm_map_t map,
cb323159 4970 mach_msg_option_t option,
0a7de745 4971 mach_msg_body_t *slist)
1c79356b 4972{
0a7de745
A
4973 mach_msg_body_t *body;
4974 mach_msg_descriptor_t *kern_dsc, *user_dsc;
4975 mach_msg_descriptor_t *saddr;
4976 mach_msg_type_number_t dsc_count, sdsc_count;
4977 int i;
4978 mach_msg_return_t mr = MACH_MSG_SUCCESS;
4979 boolean_t is_task_64bit = (map->max_offset > VM_MAX_ADDRESS);
4980
4981 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
4982 dsc_count = body->msgh_descriptor_count;
4983 kern_dsc = (mach_msg_descriptor_t *) (body + 1);
4984 /* Point user_dsc just after the end of all the descriptors */
4985 user_dsc = &kern_dsc[dsc_count];
4986
4987 /* Do scatter list setup */
4988 if (slist != MACH_MSG_BODY_NULL) {
4989 panic("Scatter lists disabled");
4990 saddr = (mach_msg_descriptor_t *) (slist + 1);
4991 sdsc_count = slist->msgh_descriptor_count;
4992 } else {
4993 saddr = MACH_MSG_DESCRIPTOR_NULL;
4994 sdsc_count = 0;
4995 }
4996
4997 /* Now process the descriptors */
4998 for (i = dsc_count - 1; i >= 0; i--) {
4999 switch (kern_dsc[i].type.type) {
5000 case MACH_MSG_PORT_DESCRIPTOR:
5001 user_dsc = ipc_kmsg_copyout_port_descriptor(&kern_dsc[i], user_dsc, space, &mr);
5002 break;
5003 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
5004 case MACH_MSG_OOL_DESCRIPTOR:
5005 user_dsc = ipc_kmsg_copyout_ool_descriptor(
5006 (mach_msg_ool_descriptor_t *)&kern_dsc[i], user_dsc, is_task_64bit, map, &mr);
5007 break;
5008 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
5009 user_dsc = ipc_kmsg_copyout_ool_ports_descriptor(
5010 (mach_msg_ool_ports_descriptor_t *)&kern_dsc[i], user_dsc, is_task_64bit, map, space, kmsg, &mr);
5011 break;
cb323159
A
5012 case MACH_MSG_GUARDED_PORT_DESCRIPTOR:
5013 user_dsc = ipc_kmsg_copyout_guarded_port_descriptor(
5014 (mach_msg_guarded_port_descriptor_t *)&kern_dsc[i], user_dsc, is_task_64bit, kmsg, space, option, &mr);
5015 break;
0a7de745
A
5016 default: {
5017 panic("untyped IPC copyout body: invalid message descriptor");
5018 }
5019 }
5020 }
5021
5022 if (user_dsc != kern_dsc) {
5023 vm_offset_t dsc_adjust = (vm_offset_t)user_dsc - (vm_offset_t)kern_dsc;
5024 memmove((char *)((vm_offset_t)kmsg->ikm_header + dsc_adjust), kmsg->ikm_header, sizeof(mach_msg_base_t));
5025 kmsg->ikm_header = (mach_msg_header_t *)((vm_offset_t)kmsg->ikm_header + dsc_adjust);
5026 /* Update the message size for the smaller user representation */
5027 kmsg->ikm_header->msgh_size -= (mach_msg_size_t)dsc_adjust;
5028 }
5029
5030 return mr;
1c79356b
A
5031}
5032
91447636
A
5033/*
5034 * Routine: ipc_kmsg_copyout_size
5035 * Purpose:
5036 * Compute the size of the message as copied out to the given
5037 * map. If the destination map's pointers are a different size
5038 * than the kernel's, we have to allow for expansion/
5039 * contraction of the descriptors as appropriate.
5040 * Conditions:
5041 * Nothing locked.
5042 * Returns:
5043 * size of the message as it would be received.
5044 */
5045
5046mach_msg_size_t
5047ipc_kmsg_copyout_size(
0a7de745
A
5048 ipc_kmsg_t kmsg,
5049 vm_map_t map)
91447636 5050{
0a7de745 5051 mach_msg_size_t send_size;
91447636 5052
0a7de745 5053 send_size = kmsg->ikm_header->msgh_size;
91447636 5054
0a7de745 5055 boolean_t is_task_64bit = (map->max_offset > VM_MAX_ADDRESS);
91447636 5056
b0d623f7
A
5057#if defined(__LP64__)
5058 send_size -= LEGACY_HEADER_SIZE_DELTA;
5059#endif
91447636 5060
0a7de745
A
5061 if (kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
5062 mach_msg_body_t *body;
5063 mach_msg_descriptor_t *saddr, *eaddr;
5064
5065 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
5066 saddr = (mach_msg_descriptor_t *) (body + 1);
5067 eaddr = saddr + body->msgh_descriptor_count;
5068
5069 for (; saddr < eaddr; saddr++) {
5070 switch (saddr->type.type) {
5071 case MACH_MSG_OOL_DESCRIPTOR:
5072 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
5073 case MACH_MSG_OOL_PORTS_DESCRIPTOR:
cb323159 5074 case MACH_MSG_GUARDED_PORT_DESCRIPTOR:
0a7de745
A
5075 if (!is_task_64bit) {
5076 send_size -= DESC_SIZE_ADJUSTMENT;
5077 }
5078 break;
5079 case MACH_MSG_PORT_DESCRIPTOR:
5080 send_size -= DESC_SIZE_ADJUSTMENT;
5081 break;
5082 default:
5083 break;
5084 }
5085 }
5086 }
5087 return send_size;
91447636
A
5088}
5089
1c79356b
A
5090/*
5091 * Routine: ipc_kmsg_copyout
5092 * Purpose:
5093 * "Copy-out" port rights and out-of-line memory
5094 * in the message.
5095 * Conditions:
5096 * Nothing locked.
5097 * Returns:
5098 * MACH_MSG_SUCCESS Copied out all rights and memory.
1c79356b
A
5099 * MACH_RCV_HEADER_ERROR + special bits
5100 * Rights and memory in the message are intact.
5101 * MACH_RCV_BODY_ERROR + special bits
5102 * The message header was successfully copied out.
5103 * As much of the body was handled as possible.
5104 */
5105
5106mach_msg_return_t
5107ipc_kmsg_copyout(
0a7de745
A
5108 ipc_kmsg_t kmsg,
5109 ipc_space_t space,
5110 vm_map_t map,
5111 mach_msg_body_t *slist,
5112 mach_msg_option_t option)
1c79356b
A
5113{
5114 mach_msg_return_t mr;
5115
fe8ab488 5116 mr = ipc_kmsg_copyout_header(kmsg, space, option);
2d21ac55 5117 if (mr != MACH_MSG_SUCCESS) {
1c79356b 5118 return mr;
2d21ac55 5119 }
1c79356b 5120
91447636 5121 if (kmsg->ikm_header->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
cb323159 5122 mr = ipc_kmsg_copyout_body(kmsg, space, map, option, slist);
1c79356b 5123
0a7de745 5124 if (mr != MACH_MSG_SUCCESS) {
1c79356b 5125 mr |= MACH_RCV_BODY_ERROR;
0a7de745 5126 }
1c79356b
A
5127 }
5128
5129 return mr;
5130}
5131
5132/*
5133 * Routine: ipc_kmsg_copyout_pseudo
5134 * Purpose:
5135 * Does a pseudo-copyout of the message.
5136 * This is like a regular copyout, except
5137 * that the ports in the header are handled
5138 * as if they are in the body. They aren't reversed.
5139 *
5140 * The error codes are a combination of special bits.
5141 * The copyout proceeds despite errors.
5142 * Conditions:
5143 * Nothing locked.
5144 * Returns:
5145 * MACH_MSG_SUCCESS Successful copyout.
5146 * MACH_MSG_IPC_SPACE No room for port right in name space.
5147 * MACH_MSG_VM_SPACE No room for memory in address space.
5148 * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
5149 * MACH_MSG_VM_KERNEL Resource shortage handling memory.
5150 */
5151
5152mach_msg_return_t
5153ipc_kmsg_copyout_pseudo(
0a7de745
A
5154 ipc_kmsg_t kmsg,
5155 ipc_space_t space,
5156 vm_map_t map,
5157 mach_msg_body_t *slist)
1c79356b 5158{
91447636 5159 mach_msg_bits_t mbits = kmsg->ikm_header->msgh_bits;
cb323159
A
5160 ipc_object_t dest = ip_to_object(kmsg->ikm_header->msgh_remote_port);
5161 ipc_object_t reply = ip_to_object(kmsg->ikm_header->msgh_local_port);
5162 ipc_object_t voucher = ip_to_object(kmsg->ikm_voucher);
1c79356b
A
5163 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
5164 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
fe8ab488
A
5165 mach_msg_type_name_t voucher_type = MACH_MSGH_BITS_VOUCHER(mbits);
5166 mach_port_name_t voucher_name = kmsg->ikm_header->msgh_voucher_port;
1c79356b
A
5167 mach_port_name_t dest_name, reply_name;
5168 mach_msg_return_t mr;
5169
5ba3f43e
A
5170 /* Set ith_knote to ITH_KNOTE_PSEUDO */
5171 current_thread()->ith_knote = ITH_KNOTE_PSEUDO;
5172
1c79356b
A
5173 assert(IO_VALID(dest));
5174
fe8ab488
A
5175#if 0
5176 /*
5177 * If we did this here, it looks like we wouldn't need the undo logic
5178 * at the end of ipc_kmsg_send() in the error cases. Not sure which
5179 * would be more elegant to keep.
5180 */
5181 ipc_importance_clean(kmsg);
5182#else
5183 /* just assert it is already clean */
5184 ipc_importance_assert_clean(kmsg);
5185#endif
5186
cb323159
A
5187 mr = (ipc_kmsg_copyout_object(space, dest, dest_type, NULL, NULL, &dest_name) |
5188 ipc_kmsg_copyout_object(space, reply, reply_type, NULL, NULL, &reply_name));
1c79356b 5189
39236c6e 5190 kmsg->ikm_header->msgh_bits = mbits & MACH_MSGH_BITS_USER;
b0d623f7
A
5191 kmsg->ikm_header->msgh_remote_port = CAST_MACH_NAME_TO_PORT(dest_name);
5192 kmsg->ikm_header->msgh_local_port = CAST_MACH_NAME_TO_PORT(reply_name);
1c79356b 5193
fe8ab488
A
5194 if (IO_VALID(voucher)) {
5195 assert(voucher_type == MACH_MSG_TYPE_MOVE_SEND);
5196
5197 kmsg->ikm_voucher = IP_NULL;
cb323159 5198 mr |= ipc_kmsg_copyout_object(space, voucher, voucher_type, NULL, NULL, &voucher_name);
fe8ab488
A
5199 kmsg->ikm_header->msgh_voucher_port = voucher_name;
5200 }
0a7de745 5201
1c79356b 5202 if (mbits & MACH_MSGH_BITS_COMPLEX) {
cb323159 5203 mr |= ipc_kmsg_copyout_body(kmsg, space, map, 0, slist);
1c79356b
A
5204 }
5205
5206 return mr;
5207}
5208
5209/*
5210 * Routine: ipc_kmsg_copyout_dest
5211 * Purpose:
5212 * Copies out the destination port in the message.
5213 * Destroys all other rights and memory in the message.
5214 * Conditions:
5215 * Nothing locked.
5216 */
5217
5218void
5219ipc_kmsg_copyout_dest(
0a7de745
A
5220 ipc_kmsg_t kmsg,
5221 ipc_space_t space)
1c79356b
A
5222{
5223 mach_msg_bits_t mbits;
5224 ipc_object_t dest;
5225 ipc_object_t reply;
fe8ab488 5226 ipc_object_t voucher;
1c79356b
A
5227 mach_msg_type_name_t dest_type;
5228 mach_msg_type_name_t reply_type;
fe8ab488
A
5229 mach_msg_type_name_t voucher_type;
5230 mach_port_name_t dest_name, reply_name, voucher_name;
1c79356b 5231
91447636 5232 mbits = kmsg->ikm_header->msgh_bits;
cb323159
A
5233 dest = ip_to_object(kmsg->ikm_header->msgh_remote_port);
5234 reply = ip_to_object(kmsg->ikm_header->msgh_local_port);
5235 voucher = ip_to_object(kmsg->ikm_voucher);
fe8ab488 5236 voucher_name = kmsg->ikm_header->msgh_voucher_port;
1c79356b
A
5237 dest_type = MACH_MSGH_BITS_REMOTE(mbits);
5238 reply_type = MACH_MSGH_BITS_LOCAL(mbits);
fe8ab488 5239 voucher_type = MACH_MSGH_BITS_VOUCHER(mbits);
1c79356b
A
5240
5241 assert(IO_VALID(dest));
5242
fe8ab488
A
5243 ipc_importance_assert_clean(kmsg);
5244
1c79356b
A
5245 io_lock(dest);
5246 if (io_active(dest)) {
5247 ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
5248 /* dest is unlocked */
5249 } else {
316670eb 5250 io_unlock(dest);
1c79356b 5251 io_release(dest);
1c79356b
A
5252 dest_name = MACH_PORT_DEAD;
5253 }
5254
5255 if (IO_VALID(reply)) {
5256 ipc_object_destroy(reply, reply_type);
5257 reply_name = MACH_PORT_NULL;
0a7de745 5258 } else {
b0d623f7 5259 reply_name = CAST_MACH_PORT_TO_NAME(reply);
0a7de745 5260 }
1c79356b 5261
fe8ab488
A
5262 if (IO_VALID(voucher)) {
5263 assert(voucher_type == MACH_MSG_TYPE_MOVE_SEND);
5264
5265 kmsg->ikm_voucher = IP_NULL;
cb323159 5266 ipc_object_destroy(voucher, voucher_type);
fe8ab488
A
5267 voucher_name = MACH_PORT_NULL;
5268 }
5269
5270 kmsg->ikm_header->msgh_bits = MACH_MSGH_BITS_SET(reply_type, dest_type,
0a7de745 5271 voucher_type, mbits);
b0d623f7
A
5272 kmsg->ikm_header->msgh_local_port = CAST_MACH_NAME_TO_PORT(dest_name);
5273 kmsg->ikm_header->msgh_remote_port = CAST_MACH_NAME_TO_PORT(reply_name);
fe8ab488 5274 kmsg->ikm_header->msgh_voucher_port = voucher_name;
1c79356b
A
5275
5276 if (mbits & MACH_MSGH_BITS_COMPLEX) {
5277 mach_msg_body_t *body;
5278
91447636 5279 body = (mach_msg_body_t *) (kmsg->ikm_header + 1);
0a7de745
A
5280 ipc_kmsg_clean_body(kmsg, body->msgh_descriptor_count,
5281 (mach_msg_descriptor_t *)(body + 1));
1c79356b
A
5282 }
5283}
91447636 5284
1c79356b
A
5285/*
5286 * Routine: ipc_kmsg_copyout_to_kernel
5287 * Purpose:
5288 * Copies out the destination and reply ports in the message.
5289 * Leaves all other rights and memory in the message alone.
5290 * Conditions:
5291 * Nothing locked.
5292 *
5293 * Derived from ipc_kmsg_copyout_dest.
5294 * Use by mach_msg_rpc_from_kernel (which used to use copyout_dest).
5295 * We really do want to save rights and memory.
5296 */
5297
5298void
5299ipc_kmsg_copyout_to_kernel(
0a7de745
A
5300 ipc_kmsg_t kmsg,
5301 ipc_space_t space)
1c79356b
A
5302{
5303 ipc_object_t dest;
e8c3f781 5304 mach_port_t reply;
1c79356b
A
5305 mach_msg_type_name_t dest_type;
5306 mach_msg_type_name_t reply_type;
e8c3f781 5307 mach_port_name_t dest_name;
1c79356b 5308
cb323159 5309 dest = ip_to_object(kmsg->ikm_header->msgh_remote_port);
e8c3f781 5310 reply = kmsg->ikm_header->msgh_local_port;
91447636
A
5311 dest_type = MACH_MSGH_BITS_REMOTE(kmsg->ikm_header->msgh_bits);
5312 reply_type = MACH_MSGH_BITS_LOCAL(kmsg->ikm_header->msgh_bits);
1c79356b
A
5313
5314 assert(IO_VALID(dest));
5315
5316 io_lock(dest);
5317 if (io_active(dest)) {
5318 ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
5319 /* dest is unlocked */
5320 } else {
316670eb 5321 io_unlock(dest);
1c79356b 5322 io_release(dest);
1c79356b
A
5323 dest_name = MACH_PORT_DEAD;
5324 }
5325
0a7de745
A
5326 /*
5327 * While MIG kernel users don't receive vouchers, the
5328 * msgh_voucher_port field is intended to be round-tripped through the
5329 * kernel if there is no voucher disposition set. Here we check for a
5330 * non-zero voucher disposition, and consume the voucher send right as
5331 * there is no possible way to specify MACH_RCV_VOUCHER semantics.
5332 */
5333 mach_msg_type_name_t voucher_type;
5334 voucher_type = MACH_MSGH_BITS_VOUCHER(kmsg->ikm_header->msgh_bits);
5335 if (voucher_type != MACH_MSGH_BITS_ZERO) {
5336 assert(voucher_type == MACH_MSG_TYPE_MOVE_SEND);
5337 /*
5338 * someone managed to send this kernel routine a message with
5339 * a voucher in it. Cleanup the reference in
5340 * kmsg->ikm_voucher.
5341 */
5342 if (IP_VALID(kmsg->ikm_voucher)) {
5343 ipc_port_release_send(kmsg->ikm_voucher);
5344 }
5345 kmsg->ikm_voucher = IP_NULL;
5346 kmsg->ikm_header->msgh_voucher_port = 0;
5347 }
5348
91447636 5349 kmsg->ikm_header->msgh_bits =
0a7de745
A
5350 (MACH_MSGH_BITS_OTHER(kmsg->ikm_header->msgh_bits) |
5351 MACH_MSGH_BITS(reply_type, dest_type));
b0d623f7 5352 kmsg->ikm_header->msgh_local_port = CAST_MACH_NAME_TO_PORT(dest_name);
e8c3f781 5353 kmsg->ikm_header->msgh_remote_port = reply;
1c79356b
A
5354}
5355
b0d623f7
A
5356#if IKM_SUPPORT_LEGACY
5357void
5358ipc_kmsg_copyout_to_kernel_legacy(
0a7de745
A
5359 ipc_kmsg_t kmsg,
5360 ipc_space_t space)
b0d623f7
A
5361{
5362 ipc_object_t dest;
0a7de745 5363 mach_port_t reply;
b0d623f7
A
5364 mach_msg_type_name_t dest_type;
5365 mach_msg_type_name_t reply_type;
0a7de745 5366 mach_port_name_t dest_name;
b0d623f7 5367
cb323159 5368 dest = ip_to_object(kmsg->ikm_header->msgh_remote_port);
0a7de745 5369 reply = kmsg->ikm_header->msgh_local_port;
b0d623f7
A
5370 dest_type = MACH_MSGH_BITS_REMOTE(kmsg->ikm_header->msgh_bits);
5371 reply_type = MACH_MSGH_BITS_LOCAL(kmsg->ikm_header->msgh_bits);
5372
5373 assert(IO_VALID(dest));
5374
5375 io_lock(dest);
5376 if (io_active(dest)) {
5377 ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
5378 /* dest is unlocked */
5379 } else {
316670eb 5380 io_unlock(dest);
b0d623f7 5381 io_release(dest);
b0d623f7
A
5382 dest_name = MACH_PORT_DEAD;
5383 }
5384
0a7de745
A
5385 mach_msg_type_name_t voucher_type;
5386 voucher_type = MACH_MSGH_BITS_VOUCHER(kmsg->ikm_header->msgh_bits);
5387 if (voucher_type != MACH_MSGH_BITS_ZERO) {
5388 assert(voucher_type == MACH_MSG_TYPE_MOVE_SEND);
5389 assert(IP_VALID(kmsg->ikm_voucher));
5390 /*
5391 * someone managed to send this kernel routine a message with
5392 * a voucher in it. Cleanup the reference in
5393 * kmsg->ikm_voucher.
5394 */
5395 ipc_port_release_send(kmsg->ikm_voucher);
5396 kmsg->ikm_voucher = IP_NULL;
5397 kmsg->ikm_header->msgh_voucher_port = 0;
5398 }
b0d623f7
A
5399
5400 kmsg->ikm_header->msgh_bits =
0a7de745
A
5401 (MACH_MSGH_BITS_OTHER(kmsg->ikm_header->msgh_bits) |
5402 MACH_MSGH_BITS(reply_type, dest_type));
b0d623f7 5403 kmsg->ikm_header->msgh_local_port = CAST_MACH_NAME_TO_PORT(dest_name);
0a7de745
A
5404 kmsg->ikm_header->msgh_remote_port = reply;
5405
5406 mach_msg_descriptor_t *saddr;
5407 mach_msg_legacy_descriptor_t *daddr;
5408 mach_msg_type_number_t i, count = ((mach_msg_base_t *)kmsg->ikm_header)->body.msgh_descriptor_count;
5409 saddr = (mach_msg_descriptor_t *) (((mach_msg_base_t *)kmsg->ikm_header) + 1);
5410 saddr = &saddr[count - 1];
5411 daddr = (mach_msg_legacy_descriptor_t *)&saddr[count];
5412 daddr--;
5413
5414 vm_offset_t dsc_adjust = 0;
5415
5416 for (i = 0; i < count; i++, saddr--, daddr--) {
5417 switch (saddr->type.type) {
5418 case MACH_MSG_PORT_DESCRIPTOR: {
5419 mach_msg_port_descriptor_t *dsc = &saddr->port;
5420 mach_msg_legacy_port_descriptor_t *dest_dsc = &daddr->port;
5421
5422 mach_port_t name = dsc->name;
5423 mach_msg_type_name_t disposition = dsc->disposition;
5424
5425 dest_dsc->name = CAST_MACH_PORT_TO_NAME(name);
5426 dest_dsc->disposition = disposition;
5427 dest_dsc->type = MACH_MSG_PORT_DESCRIPTOR;
5428 break;
5429 }
5430 case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
5431 case MACH_MSG_OOL_DESCRIPTOR: {
5432 /* The sender should supply ready-made memory, i.e. a vm_map_copy_t
5433 * so we don't need to do anything special. */
5434
5435 mach_msg_ool_descriptor_t *source_dsc = (typeof(source_dsc)) & saddr->out_of_line;
b0d623f7 5436
0a7de745
A
5437 mach_msg_ool_descriptor32_t *dest_dsc = &daddr->out_of_line32;
5438
5439 vm_offset_t address = (vm_offset_t)source_dsc->address;
5440 vm_size_t size = source_dsc->size;
5441 boolean_t deallocate = source_dsc->deallocate;
5442 mach_msg_copy_options_t copy = source_dsc->copy;
5443 mach_msg_descriptor_type_t type = source_dsc->type;
5444
5445 dest_dsc->address = address;
5446 dest_dsc->size = size;
5447 dest_dsc->deallocate = deallocate;
5448 dest_dsc->copy = copy;
5449 dest_dsc->type = type;
5450 break;
5451 }
5452 case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
5453 mach_msg_ool_ports_descriptor_t *source_dsc = (typeof(source_dsc)) & saddr->ool_ports;
5454
5455 mach_msg_ool_ports_descriptor32_t *dest_dsc = &daddr->ool_ports32;
5456
5457 vm_offset_t address = (vm_offset_t)source_dsc->address;
5458 vm_size_t port_count = source_dsc->count;
5459 boolean_t deallocate = source_dsc->deallocate;
5460 mach_msg_copy_options_t copy = source_dsc->copy;
5461 mach_msg_descriptor_type_t type = source_dsc->type;
5462
5463 dest_dsc->address = address;
5464 dest_dsc->count = port_count;
5465 dest_dsc->deallocate = deallocate;
5466 dest_dsc->copy = copy;
5467 dest_dsc->type = type;
5468 break;
5469 }
cb323159
A
5470 case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
5471 mach_msg_guarded_port_descriptor_t *source_dsc = (typeof(source_dsc)) & saddr->guarded_port;
5472 mach_msg_guarded_port_descriptor32_t *dest_dsc = &daddr->guarded_port32;
5473
5474 dest_dsc->name = CAST_MACH_PORT_TO_NAME(source_dsc->name);
5475 dest_dsc->disposition = source_dsc->disposition;
5476 dest_dsc->flags = 0;
5477 dest_dsc->type = MACH_MSG_GUARDED_PORT_DESCRIPTOR;
5478 dest_dsc->context = 0;
5479 break;
5480 }
0a7de745
A
5481 default: {
5482#if MACH_ASSERT
cb323159 5483 panic("ipc_kmsg_copyout_to_kernel_legacy: bad descriptor");
0a7de745
A
5484#endif /* MACH_ASSERT */
5485 }
5486 }
5487 }
5488
5489 if (count) {
5490 dsc_adjust = 4 * count;
5491 memmove((char *)((vm_offset_t)kmsg->ikm_header + dsc_adjust), kmsg->ikm_header, sizeof(mach_msg_base_t));
5492 kmsg->ikm_header = (mach_msg_header_t *)((vm_offset_t)kmsg->ikm_header + dsc_adjust);
5493 /* Update the message size for the smaller user representation */
5494 kmsg->ikm_header->msgh_size -= dsc_adjust;
5495 }
b0d623f7
A
5496}
5497#endif /* IKM_SUPPORT_LEGACY */
5498
5ba3f43e
A
5499#ifdef __arm64__
5500/*
5501 * Just sets those parts of the trailer that aren't set up at allocation time.
5502 */
5503static void
0a7de745 5504ipc_kmsg_munge_trailer(mach_msg_max_trailer_t *in, void *_out, boolean_t is64bit)
5ba3f43e
A
5505{
5506 if (is64bit) {
5507 mach_msg_max_trailer64_t *out = (mach_msg_max_trailer64_t*)_out;
5508 out->msgh_seqno = in->msgh_seqno;
5509 out->msgh_context = in->msgh_context;
5510 out->msgh_trailer_size = in->msgh_trailer_size;
5511 out->msgh_ad = in->msgh_ad;
5512 } else {
5513 mach_msg_max_trailer32_t *out = (mach_msg_max_trailer32_t*)_out;
5514 out->msgh_seqno = in->msgh_seqno;
5515 out->msgh_context = (mach_port_context32_t)in->msgh_context;
5516 out->msgh_trailer_size = in->msgh_trailer_size;
5517 out->msgh_ad = in->msgh_ad;
5518 }
5519}
5520#endif /* __arm64__ */
fe8ab488 5521
316670eb 5522mach_msg_trailer_size_t
0a7de745
A
5523ipc_kmsg_add_trailer(ipc_kmsg_t kmsg, ipc_space_t space __unused,
5524 mach_msg_option_t option, thread_t thread,
5525 mach_port_seqno_t seqno, boolean_t minimal_trailer,
5526 mach_vm_offset_t context)
1c79356b 5527{
316670eb 5528 mach_msg_max_trailer_t *trailer;
1c79356b 5529
5ba3f43e
A
5530#ifdef __arm64__
5531 mach_msg_max_trailer_t tmp_trailer; /* This accommodates U64, and we'll munge */
5532 void *real_trailer_out = (void*)(mach_msg_max_trailer_t *)
0a7de745
A
5533 ((vm_offset_t)kmsg->ikm_header +
5534 round_msg(kmsg->ikm_header->msgh_size));
5ba3f43e 5535
0a7de745 5536 /*
5ba3f43e 5537 * Populate scratch with initial values set up at message allocation time.
0a7de745 5538 * After, we reinterpret the space in the message as the right type
5ba3f43e
A
5539 * of trailer for the address space in question.
5540 */
5541 bcopy(real_trailer_out, &tmp_trailer, MAX_TRAILER_SIZE);
5542 trailer = &tmp_trailer;
5543#else /* __arm64__ */
316670eb
A
5544 (void)thread;
5545 trailer = (mach_msg_max_trailer_t *)
0a7de745
A
5546 ((vm_offset_t)kmsg->ikm_header +
5547 round_msg(kmsg->ikm_header->msgh_size));
5ba3f43e 5548#endif /* __arm64__ */
1c79356b 5549
316670eb
A
5550 if (!(option & MACH_RCV_TRAILER_MASK)) {
5551 return trailer->msgh_trailer_size;
1c79356b 5552 }
1c79356b 5553
316670eb
A
5554 trailer->msgh_seqno = seqno;
5555 trailer->msgh_context = context;
d9a64523 5556 trailer->msgh_trailer_size = REQUESTED_TRAILER_SIZE(thread_is_64bit_addr(thread), option);
1c79356b 5557
0a7de745 5558 if (minimal_trailer) {
316670eb 5559 goto done;
1c79356b
A
5560 }
5561
b226f5e5 5562 if (GET_RCV_ELEMENTS(option) >= MACH_RCV_TRAILER_AV) {
fe8ab488 5563 trailer->msgh_ad = 0;
1c79356b 5564 }
1c79356b 5565
316670eb
A
5566 /*
5567 * The ipc_kmsg_t holds a reference to the label of a label
5568 * handle, not the port. We must get a reference to the port
5569 * and a send right to copyout to the receiver.
5570 */
1c79356b 5571
0a7de745 5572 if (option & MACH_RCV_TRAILER_ELEMENTS(MACH_RCV_TRAILER_LABELS)) {
316670eb 5573 trailer->msgh_labels.sender = 0;
1c79356b 5574 }
1c79356b 5575
316670eb 5576done:
5ba3f43e 5577#ifdef __arm64__
d9a64523 5578 ipc_kmsg_munge_trailer(trailer, real_trailer_out, thread_is_64bit_addr(thread));
5ba3f43e 5579#endif /* __arm64__ */
39236c6e 5580
316670eb 5581 return trailer->msgh_trailer_size;
1c79356b 5582}
cb323159
A
5583
5584mach_msg_header_t *
5585ipc_kmsg_msg_header(ipc_kmsg_t kmsg)
5586{
5587 if (NULL == kmsg) {
5588 return NULL;
5589 }
5590 return kmsg->ikm_header;
5591}