FreeBSD/Linux Kernel Cross Reference
sys/ipc/ipc_kmsg.c
1 /*
2 * Mach Operating System
3 * Copyright (c) 1993-1989 Carnegie Mellon University
4 * All Rights Reserved.
5 *
6 * Permission to use, copy, modify and distribute this software and its
7 * documentation is hereby granted, provided that both the copyright
8 * notice and this permission notice appear in all copies of the
9 * software, derivative works or modified versions, and any portions
10 * thereof, and that both notices appear in supporting documentation.
11 *
12 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
13 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
14 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
15 *
16 * Carnegie Mellon requests users of this software to return to
17 *
18 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
19 * School of Computer Science
20 * Carnegie Mellon University
21 * Pittsburgh PA 15213-3890
22 *
23 * any improvements or extensions that they make and grant Carnegie Mellon
24 * the rights to redistribute these changes.
25 */
26 /*
27 * HISTORY
28 * $Log: ipc_kmsg.c,v $
29 * Revision 2.33 93/11/17 16:57:14 dbg
30 * Added kmsg type for kernel reply messages. Added ANSI
31 * function prototypes.
32 * [93/03/29 dbg]
33 *
34 * Revision 2.32 93/08/31 15:16:33 mrt
35 * Defend against the case of a long type that is mis-aligned.
36 * This can be used (horrible fix, sorry) to solve the
37 * issue of what to put in the filler spot of a troublesome
38 * message. This happens, for instance, with varsize inline
39 * arrays followed by OOL data described by a long type.
40 * One can use a bogus short-type that has the longform bit on...
41 * [93/08/16 af]
42 *
43 * Revision 2.31 93/08/10 15:15:52 mrt
44 * Religious-fix for GCC on alpha. This compiler insists that
45 * if a structure contains a long then it must be aligned and
46 * also all fields in it must be. So our trick with short and
47 * long type descriptors would not play quite right, some 64bit
48 * loads were generated for 32bit quantities.
49 * Put casts all over the place for this.
50 * [93/08/04 af]
51 *
52 * Revision 2.30 93/01/14 17:32:42 danner
53 * 64bit cleanup
54 * [92/11/30 af]
55 *
56 * Revision 2.29 92/08/03 17:34:23 jfriedl
57 * removed silly prototypes
58 * [92/08/02 jfriedl]
59 *
60 * Revision 2.28 92/05/21 17:10:21 jfriedl
61 * Added void to fcns that needed it. Renamed one of the two local
62 * variables 'object' to 'obj' in ipc_kmsg_clean_partial to keep clean.
63 * Added return after error in ipc_msg_print().
64 * [92/05/16 jfriedl]
65 *
66 * Revision 2.27 92/03/10 16:25:43 jsb
67 * Merged in norma branch changes as of NORMA_MK7:
68 * Moved ipc_kmsg_copyout_to_network to norma/ipc_output.c.
69 * Moved ipc_kmsg_uncopyout_to_network to norma/ipc_clean.c.
70 * [92/02/21 10:34:46 jsb]
71 * We no longer convert to network format directly from user format;
72 * this greatly reduces the number of NORMA_IPC conditionals here.
73 * Added code to detect and recover from vm_map_convert_to_page_list
74 * failure. Streamlined and fixed ipc_kmsg_copyout_to_network.
75 * [92/02/21 09:01:52 jsb]
76 *
77 * Revision 2.26 92/03/05 18:53:54 rpd
78 * Undid norma changes that were inadvertently picked up in 2.24.
79 * [92/03/05 rpd]
80 *
81 * Revision 2.25 92/03/01 15:14:54 rpd
82 * Picked up page-list/norma code for ipc_kmsg_copyin_compat, from jsb.
83 * [92/03/01 rpd]
84 *
85 * Revision 2.24 92/02/23 19:52:31 elf
86 * Eliminate keep_wired argument from vm_map_copyin().
87 *
88 * Revision 2.23 92/01/14 16:44:23 rpd
89 * Fixed ipc_kmsg_copyin, ipc_kmsg_copyout, etc
90 * to use copyinmap and copyoutmap for out-of-line ports.
91 * [91/12/16 rpd]
92 *
93 * Revision 2.22 91/12/15 10:37:53 jsb
94 * Improved ddb 'show kmsg' support.
95 *
96 * Revision 2.21 91/12/14 14:26:03 jsb
97 * Removed ipc_fields.h hack.
98 * Made ipc_kmsg_clean_{body,partial} aware of remote ports.
99 * They don't yet clean up remote ports, but at least they
100 * no longer pass port uids to ipc_object_destroy.
101 *
102 * Revision 2.20 91/12/13 13:51:58 jsb
103 * Use norma_ipc_copyin_page_list when sending to remote port.
104 *
105 * Revision 2.19 91/12/10 13:25:46 jsb
106 * Added ipc_kmsg_copyout_to_network, as required by ipc_kserver.c.
107 * Picked up vm_map_convert_to_page_list call changes from dlb.
108 * Changed NORMA_VM conditional for ipc_kmsg_copyout_to_kernel
109 * to NORMA_IPC.
110 * [91/12/10 11:20:36 jsb]
111 *
112 * Revision 2.18 91/11/14 16:55:57 rpd
113 * Picked up mysterious norma changes.
114 * [91/11/14 rpd]
115 *
116 * Revision 2.17 91/10/09 16:09:08 af
117 * Changed msgh_kind to msgh_seqno in ipc_msg_print.
118 * [91/10/05 rpd]
119 *
120 * Removed unused variables. Added <ipc/ipc_notify.h>.
121 * [91/09/02 rpd]
122 *
123 * Revision 2.16 91/08/28 11:13:20 jsb
124 * Changed msgh_kind to msgh_seqno.
125 * [91/08/09 rpd]
126 * Changed for new vm_map_copyout failure behavior.
127 * [91/08/03 rpd]
128 * Update page list discriminant logic to allow use of page list for
129 * kernel objects that do not require page stealing (devices).
130 * [91/07/31 15:00:55 dlb]
131 *
132 * Add arg to vm_map_copyin_page_list.
133 * [91/07/30 14:10:38 dlb]
134 *
135 * Turn page lists on by default.
136 * [91/07/03 14:01:00 dlb]
137 * Renamed clport fields in struct ipc_port to ip_norma fields.
138 * Added checks for sending receive rights remotely.
139 * [91/08/15 08:22:20 jsb]
140 *
141 * Revision 2.15 91/08/03 18:18:16 jsb
142 * Added support for ddb commands ``show msg'' and ``show kmsg''.
143 * Made changes for elimination of intermediate clport structure.
144 * [91/07/27 22:25:06 jsb]
145 *
146 * Moved MACH_MSGH_BITS_COMPLEX_{PORTS,DATA} to mach/message.h.
147 * Removed complex_data_hint_xxx[] garbage.
148 * Adopted new vm_map_copy_t page_list technology.
149 * [91/07/04 13:09:45 jsb]
150 *
151 * Revision 2.14 91/07/01 08:24:34 jsb
152 * From David Black at OSF: generalized page list support.
153 * [91/06/29 16:29:29 jsb]
154 *
155 * Revision 2.13 91/06/17 15:46:04 jsb
156 * Renamed NORMA conditionals.
157 * [91/06/17 10:45:05 jsb]
158 *
159 * Revision 2.12 91/06/06 17:05:52 jsb
160 * More NORMA_IPC stuff. Cleanup will follow.
161 * [91/06/06 16:00:08 jsb]
162 *
163 * Revision 2.11 91/05/14 16:33:01 mrt
164 * Correcting copyright
165 *
166 * Revision 2.10 91/03/16 14:47:57 rpd
167 * Replaced ith_saved with ipc_kmsg_cache.
168 * [91/02/16 rpd]
169 *
170 * Revision 2.9 91/02/05 17:21:52 mrt
171 * Changed to new Mach copyright
172 * [91/02/01 15:45:30 mrt]
173 *
174 * Revision 2.8 91/01/08 15:13:49 rpd
175 * Added ipc_kmsg_free.
176 * [91/01/05 rpd]
177 * Optimized ipc_kmsg_copyout_object for send rights.
178 * [90/12/21 rpd]
179 * Changed to use new copyinmsg/copyoutmsg operations.
180 * Changed ipc_kmsg_get to check that the size is multiple of four.
181 * [90/12/05 rpd]
182 * Removed MACH_IPC_GENNOS.
183 * [90/11/08 rpd]
184 *
185 * Revision 2.7 90/11/05 14:28:36 rpd
186 * Changed ip_reference to ipc_port_reference.
187 * Changed ip_release to ipc_port_release.
188 * Use new io_reference and io_release.
189 * Use new ip_reference and ip_release.
190 * [90/10/29 rpd]
191 *
192 * Revision 2.6 90/09/09 14:31:50 rpd
193 * Fixed ipc_kmsg_copyin_compat to clear unused bits instead
194 * of returning an error when they are non-zero.
195 * [90/09/08 rpd]
196 *
197 * Revision 2.5 90/08/06 17:05:53 rpd
198 * Fixed ipc_kmsg_copyout_body to turn off msgt_deallocate
199 * for in-line data. It might be on if the compatibility mode
200 * generated the message.
201 *
202 * Fixed ipc_kmsg_copyin, ipc_kmsg_copyin_compat to check
203 * that msgt_name, msgt_size, msgt_number are zero
204 * in long-form type descriptors.
205 * [90/08/04 rpd]
206 *
207 * Fixed atomicity bug in ipc_kmsg_copyout_header,
208 * when the destination and reply ports are the same.
209 * [90/08/02 rpd]
210 *
211 * Revision 2.4 90/08/06 15:07:31 rwd
212 * Fixed ipc_kmsg_clean_partial to deallocate correctly
213 * the OOL memory in the last type spec.
214 * Removed debugging panic in ipc_kmsg_put.
215 * [90/06/21 rpd]
216 *
217 * Revision 2.3 90/06/19 22:58:03 rpd
218 * For debugging: added panic to ipc_kmsg_put.
219 * [90/06/04 rpd]
220 *
221 * Revision 2.2 90/06/02 14:50:05 rpd
222 * Changed ocurrences of inline; it is a gcc keyword.
223 * [90/06/02 rpd]
224 *
225 * For out-of-line memory, if length is zero allow any address.
226 * This is more compatible with old IPC.
227 * [90/04/23 rpd]
228 * Created for new IPC.
229 * [90/03/26 20:55:45 rpd]
230 *
231 */
232 /*
233 * File: ipc/ipc_kmsg.c
234 * Author: Rich Draves
235 * Date: 1989
236 *
237 * Operations on kernel messages.
238 */
239
240 #include <cpus.h>
241 #include <mach_ipc_compat.h>
242 #include <norma_ipc.h>
243 #include <norma_vm.h>
244
245 #include <mach/boolean.h>
246 #include <mach/kern_return.h>
247 #include <mach/message.h>
248 #include <mach/port.h>
249 #include <kern/assert.h>
250 #include <kern/kalloc.h>
251 #include <kern/kern_kmsg.h>
252 #include <kern/memory.h>
253 #include <vm/vm_map.h>
254 #include <vm/vm_object.h>
255 #include <vm/vm_kern.h>
256 #include <vm/vm_user.h>
257 #include <ipc/port.h>
258 #include <ipc/ipc_entry.h>
259 #include <ipc/ipc_kmsg.h>
260 #include <ipc/ipc_hash.h>
261 #include <ipc/ipc_thread.h>
262 #include <ipc/ipc_marequest.h>
263 #include <ipc/ipc_notify.h>
264 #include <ipc/ipc_object.h>
265 #include <ipc/ipc_space.h>
266 #include <ipc/ipc_port.h>
267 #include <ipc/ipc_right.h>
268
269 #include <device/net_io.h> /* net_kmsg_put */
270
271 #include <ipc/ipc_machdep.h>
272
273 extern int copyinmap();
274 extern int copyoutmap();
275 void ipc_msg_print(); /* forward */
276
277 #define is_misaligned(x) ( ((vm_offset_t)(x)) & (sizeof(vm_offset_t)-1) )
278 #define ptr_align(x) \
279 ( ( ((vm_offset_t)(x)) + (sizeof(vm_offset_t)-1) ) & ~(sizeof(vm_offset_t)-1) )
280
281 ipc_kmsg_t ipc_kmsg_cache[NCPUS];
282
283 /*
284 * Routine: ipc_kmsg_enqueue
285 * Purpose:
286 * Enqueue a kmsg.
287 */
288
289 void
290 ipc_kmsg_enqueue(
291 ipc_kmsg_queue_t queue,
292 ipc_kmsg_t kmsg)
293 {
294 ipc_kmsg_enqueue_macro(queue, kmsg);
295 }
296
297 /*
298 * Routine: ipc_kmsg_dequeue
299 * Purpose:
300 * Dequeue and return a kmsg.
301 */
302
303 ipc_kmsg_t
304 ipc_kmsg_dequeue(
305 ipc_kmsg_queue_t queue)
306 {
307 ipc_kmsg_t first;
308
309 first = ipc_kmsg_queue_first(queue);
310
311 if (first != IKM_NULL)
312 ipc_kmsg_rmqueue_first_macro(queue, first);
313
314 return first;
315 }
316
317 /*
318 * Routine: ipc_kmsg_rmqueue
319 * Purpose:
320 * Pull a kmsg out of a queue.
321 */
322
323 void
324 ipc_kmsg_rmqueue(
325 ipc_kmsg_queue_t queue,
326 ipc_kmsg_t kmsg)
327 {
328 ipc_kmsg_t next, prev;
329
330 assert(queue->ikmq_base != IKM_NULL);
331
332 next = kmsg->ikm_next;
333 prev = kmsg->ikm_prev;
334
335 if (next == kmsg) {
336 assert(prev == kmsg);
337 assert(queue->ikmq_base == kmsg);
338
339 queue->ikmq_base = IKM_NULL;
340 } else {
341 if (queue->ikmq_base == kmsg)
342 queue->ikmq_base = next;
343
344 next->ikm_prev = prev;
345 prev->ikm_next = next;
346 }
347 }
348
349 /*
350 * Routine: ipc_kmsg_queue_next
351 * Purpose:
352 * Return the kmsg following the given kmsg.
353 * (Or IKM_NULL if it is the last one in the queue.)
354 */
355
356 ipc_kmsg_t
357 ipc_kmsg_queue_next(
358 ipc_kmsg_queue_t queue,
359 ipc_kmsg_t kmsg)
360 {
361 ipc_kmsg_t next;
362
363 assert(queue->ikmq_base != IKM_NULL);
364
365 next = kmsg->ikm_next;
366 if (queue->ikmq_base == next)
367 next = IKM_NULL;
368
369 return next;
370 }
371
372 /*
373 * Routine: ipc_kmsg_destroy
374 * Purpose:
375 * Destroys a kernel message. Releases all rights,
376 * references, and memory held by the message.
377 * Frees the message.
378 * Conditions:
379 * No locks held.
380 */
381
382 void
383 ipc_kmsg_destroy(
384 ipc_kmsg_t kmsg)
385 {
386 ipc_kmsg_queue_t queue;
387 boolean_t empty;
388
389 /*
390 * ipc_kmsg_clean can cause more messages to be destroyed.
391 * Curtail recursion by queueing messages. If a message
392 * is already queued, then this is a recursive call.
393 */
394
395 queue = ¤t_thread()->ith_messages;
396 empty = ipc_kmsg_queue_empty(queue);
397 ipc_kmsg_enqueue(queue, kmsg);
398
399 if (empty) {
400 /* must leave kmsg in queue while cleaning it */
401
402 while ((kmsg = ipc_kmsg_queue_first(queue)) != IKM_NULL) {
403 ipc_kmsg_clean(kmsg);
404 ipc_kmsg_rmqueue(queue, kmsg);
405 ikm_free(kmsg);
406 }
407 }
408 }
409
410 /*
411 * Routine: ipc_kmsg_clean_body
412 * Purpose:
413 * Cleans the body of a kernel message.
414 * Releases all rights, references, and memory.
415 *
416 * The last type/data pair might stretch past eaddr.
417 * (See the usage in ipc_kmsg_copyout.)
418 * Conditions:
419 * No locks held.
420 */
421
422 void
423 ipc_kmsg_clean_body(
424 vm_offset_t saddr,
425 vm_offset_t eaddr)
426 {
427 while (saddr < eaddr) {
428 mach_msg_type_long_t *type;
429 mach_msg_type_name_t name;
430 mach_msg_type_size_t size;
431 mach_msg_type_number_t number;
432 boolean_t is_inline, is_port;
433 vm_size_t length;
434
435 type = (mach_msg_type_long_t *) saddr;
436 is_inline = ((mach_msg_type_t*)type)->msgt_inline;
437 if (((mach_msg_type_t*)type)->msgt_longform) {
438 /* This must be aligned */
439 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
440 (is_misaligned(type))) {
441 saddr = ptr_align(saddr);
442 continue;
443 }
444 name = type->msgtl_name;
445 size = type->msgtl_size;
446 number = type->msgtl_number;
447 saddr += sizeof(mach_msg_type_long_t);
448 } else {
449 name = ((mach_msg_type_t*)type)->msgt_name;
450 size = ((mach_msg_type_t*)type)->msgt_size;
451 number = ((mach_msg_type_t*)type)->msgt_number;
452 saddr += sizeof(mach_msg_type_t);
453 }
454
455 /* padding (ptrs and ports) ? */
456 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
457 ((size >> 3) == sizeof(natural_t)))
458 saddr = ptr_align(saddr);
459
460 /* calculate length of data in bytes, rounding up */
461
462 length = ((number * size) + 7) >> 3;
463
464 is_port = MACH_MSG_TYPE_PORT_ANY(name);
465
466 if (is_port) {
467 ipc_object_t *objects;
468 mach_msg_type_number_t i;
469
470 if (is_inline) {
471 objects = (ipc_object_t *) saddr;
472 /* sanity check */
473 while (eaddr < (vm_offset_t)&objects[number])
474 number--;
475 } else {
476 objects = (ipc_object_t *)
477 * (vm_offset_t *) saddr;
478 }
479
480 /* destroy port rights carried in the message */
481
482 for (i = 0; i < number; i++) {
483 ipc_object_t object = objects[i];
484
485 if (!IO_VALID(object))
486 continue;
487
488 ipc_object_destroy(object, name);
489 }
490 }
491
492 if (is_inline) {
493 /* inline data sizes round up to int boundaries */
494
495 saddr += (length + 3) &~ 3;
496 } else {
497 vm_offset_t data = * (vm_offset_t *) saddr;
498
499 /* destroy memory carried in the message */
500
501 if (length == 0)
502 assert(data == 0);
503 else if (is_port)
504 kfree(data, length);
505 else
506 vm_map_copy_discard((vm_map_copy_t) data);
507
508 saddr += sizeof(vm_offset_t);
509 }
510 }
511 }
512
513 /*
514 * Routine: ipc_kmsg_clean
515 * Purpose:
516 * Cleans a kernel message. Releases all rights,
517 * references, and memory held by the message.
518 * Conditions:
519 * No locks held.
520 */
521
522 void
523 ipc_kmsg_clean(
524 ipc_kmsg_t kmsg)
525 {
526 ipc_marequest_t marequest;
527 ipc_object_t object;
528 mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
529
530 marequest = kmsg->ikm_marequest;
531 if (marequest != IMAR_NULL)
532 ipc_marequest_destroy(marequest);
533
534 object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
535 if (IO_VALID(object))
536 ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
537
538 object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
539 if (IO_VALID(object))
540 ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
541
542 if (mbits & MACH_MSGH_BITS_COMPLEX) {
543 vm_offset_t saddr, eaddr;
544
545 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
546 eaddr = (vm_offset_t) &kmsg->ikm_header +
547 kmsg->ikm_header.msgh_size;
548
549 ipc_kmsg_clean_body(saddr, eaddr);
550 }
551 }
552
553 /*
554 * Routine: ipc_kmsg_clean_partial
555 * Purpose:
556 * Cleans a partially-acquired kernel message.
557 * eaddr is the address of the type specification
558 * in the body of the message that contained the error.
559 * If dolast, the memory and port rights in this last
560 * type spec are also cleaned. In that case, number
561 * specifies the number of port rights to clean.
562 * Conditions:
563 * Nothing locked.
564 */
565
566 void
567 ipc_kmsg_clean_partial(
568 ipc_kmsg_t kmsg,
569 vm_offset_t eaddr,
570 boolean_t dolast,
571 mach_msg_type_number_t number)
572 {
573 ipc_object_t object;
574 mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
575 vm_offset_t saddr;
576
577 assert(kmsg->ikm_marequest == IMAR_NULL);
578
579 object = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
580 assert(IO_VALID(object));
581 ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
582
583 object = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
584 if (IO_VALID(object))
585 ipc_object_destroy(object, MACH_MSGH_BITS_LOCAL(mbits));
586
587 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
588 ipc_kmsg_clean_body(saddr, eaddr);
589
590 if (dolast) {
591 mach_msg_type_long_t *type;
592 mach_msg_type_name_t name;
593 mach_msg_type_size_t size;
594 mach_msg_type_number_t rnumber;
595 boolean_t is_inline, is_port;
596 vm_size_t length;
597
598 xxx: type = (mach_msg_type_long_t *) eaddr;
599 is_inline = ((mach_msg_type_t*)type)->msgt_inline;
600 if (((mach_msg_type_t*)type)->msgt_longform) {
601 /* This must be aligned */
602 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
603 (is_misaligned(type))) {
604 eaddr = ptr_align(eaddr);
605 goto xxx;
606 }
607 name = type->msgtl_name;
608 size = type->msgtl_size;
609 rnumber = type->msgtl_number;
610 eaddr += sizeof(mach_msg_type_long_t);
611 } else {
612 name = ((mach_msg_type_t*)type)->msgt_name;
613 size = ((mach_msg_type_t*)type)->msgt_size;
614 rnumber = ((mach_msg_type_t*)type)->msgt_number;
615 eaddr += sizeof(mach_msg_type_t);
616 }
617
618 /* padding (ptrs and ports) ? */
619 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
620 ((size >> 3) == sizeof(natural_t)))
621 eaddr = ptr_align(eaddr);
622
623 /* calculate length of data in bytes, rounding up */
624
625 length = ((rnumber * size) + 7) >> 3;
626
627 is_port = MACH_MSG_TYPE_PORT_ANY(name);
628
629 if (is_port) {
630 ipc_object_t *objects;
631 mach_msg_type_number_t i;
632
633 objects = (ipc_object_t *)
634 (is_inline ? eaddr : * (vm_offset_t *) eaddr);
635
636 /* destroy port rights carried in the message */
637
638 for (i = 0; i < number; i++) {
639 ipc_object_t obj = objects[i];
640
641 if (!IO_VALID(obj))
642 continue;
643
644 ipc_object_destroy(obj, name);
645 }
646 }
647
648 if (!is_inline) {
649 vm_offset_t data = * (vm_offset_t *) eaddr;
650
651 /* destroy memory carried in the message */
652
653 if (length == 0)
654 assert(data == 0);
655 else if (is_port)
656 kfree(data, length);
657 else
658 vm_map_copy_discard((vm_map_copy_t) data);
659 }
660 }
661 }
662
663 /*
664 * Routine: ipc_kmsg_free
665 * Purpose:
666 * Free a kernel message buffer.
667 * Conditions:
668 * Nothing locked.
669 */
670
671 void
672 ipc_kmsg_free(
673 ipc_kmsg_t kmsg)
674 {
675 vm_size_t size = kmsg->ikm_size;
676
677 switch (size) {
678 #if NORMA_IPC
679 case IKM_SIZE_NORMA:
680 /* return it to the norma ipc code */
681 norma_kmsg_put(kmsg);
682 break;
683 #endif /* NORMA_IPC */
684
685 case IKM_SIZE_NETWORK:
686 /* return it to the network code */
687 net_kmsg_put(kmsg);
688 break;
689
690 case IKM_SIZE_KERN_REPLY:
691 /* return it to the kernel object system */
692 kernel_reply_kmsg_put(kmsg);
693 break;
694
695 default:
696 kfree((vm_offset_t) kmsg, size);
697 break;
698 }
699 }
700
701 /*
702 * Routine: ipc_kmsg_get
703 * Purpose:
704 * Allocates a kernel message buffer.
705 * Copies a user message to the message buffer.
706 * Conditions:
707 * Nothing locked.
708 * Returns:
709 * MACH_MSG_SUCCESS Acquired a message buffer.
710 * MACH_SEND_MSG_TOO_SMALL Message smaller than a header.
711 * MACH_SEND_MSG_TOO_SMALL Message size not long-word multiple.
712 * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
713 * MACH_SEND_INVALID_DATA Couldn't copy message data.
714 */
715
716 mach_msg_return_t
717 ipc_kmsg_get(
718 mach_msg_header_t *msg,
719 mach_msg_size_t size,
720 ipc_kmsg_t *kmsgp)
721 {
722 ipc_kmsg_t kmsg;
723
724 if ((size < sizeof(mach_msg_header_t)) || (size & 3))
725 return MACH_SEND_MSG_TOO_SMALL;
726
727 if (size <= IKM_SAVED_MSG_SIZE) {
728 kmsg = ikm_cache();
729 if (kmsg != IKM_NULL) {
730 ikm_cache() = IKM_NULL;
731 ikm_check_initialized(kmsg, IKM_SAVED_KMSG_SIZE);
732 } else {
733 kmsg = ikm_alloc(IKM_SAVED_MSG_SIZE);
734 if (kmsg == IKM_NULL)
735 return MACH_SEND_NO_BUFFER;
736 ikm_init(kmsg, IKM_SAVED_MSG_SIZE);
737 }
738 } else {
739 kmsg = ikm_alloc(size);
740 if (kmsg == IKM_NULL)
741 return MACH_SEND_NO_BUFFER;
742 ikm_init(kmsg, size);
743 }
744
745 if (copyinmsg((char *) msg, (char *) &kmsg->ikm_header, size)) {
746 ikm_free(kmsg);
747 return MACH_SEND_INVALID_DATA;
748 }
749
750 kmsg->ikm_header.msgh_size = size;
751 *kmsgp = kmsg;
752 return MACH_MSG_SUCCESS;
753 }
754
755 /*
756 * Routine: ipc_kmsg_get_from_kernel
757 * Purpose:
758 * Allocates a kernel message buffer.
759 * Copies a kernel message to the message buffer.
760 * Only resource errors are allowed.
761 * Conditions:
762 * Nothing locked.
763 * Returns:
764 * MACH_MSG_SUCCESS Acquired a message buffer.
765 * MACH_SEND_NO_BUFFER Couldn't allocate a message buffer.
766 */
767
768 extern mach_msg_return_t
769 ipc_kmsg_get_from_kernel(
770 mach_msg_header_t *msg,
771 mach_msg_size_t size,
772 ipc_kmsg_t *kmsgp)
773 {
774 ipc_kmsg_t kmsg;
775
776 assert(size >= sizeof(mach_msg_header_t));
777 assert((size & 3) == 0);
778
779 kmsg = ikm_alloc(size);
780 if (kmsg == IKM_NULL)
781 return MACH_SEND_NO_BUFFER;
782 ikm_init(kmsg, size);
783
784 bcopy((char *) msg, (char *) &kmsg->ikm_header, size);
785
786 kmsg->ikm_header.msgh_size = size;
787 *kmsgp = kmsg;
788 return MACH_MSG_SUCCESS;
789 }
790
791 /*
792 * Routine: ipc_kmsg_put
793 * Purpose:
794 * Copies a message buffer to a user message.
795 * Copies only the specified number of bytes.
796 * Frees the message buffer.
797 * Conditions:
798 * Nothing locked. The message buffer must have clean
799 * header (ikm_marequest) fields.
800 * Returns:
801 * MACH_MSG_SUCCESS Copied data out of message buffer.
802 * MACH_RCV_INVALID_DATA Couldn't copy to user message.
803 */
804
805 mach_msg_return_t
806 ipc_kmsg_put(
807 mach_msg_header_t *msg,
808 ipc_kmsg_t kmsg,
809 mach_msg_size_t size)
810 {
811 mach_msg_return_t mr;
812
813 ikm_check_initialized(kmsg, kmsg->ikm_size);
814
815 if (copyoutmsg((char *) &kmsg->ikm_header, (char *) msg, size))
816 mr = MACH_RCV_INVALID_DATA;
817 else
818 mr = MACH_MSG_SUCCESS;
819
820 if ((kmsg->ikm_size == IKM_SAVED_KMSG_SIZE) &&
821 (ikm_cache() == IKM_NULL))
822 ikm_cache() = kmsg;
823 else
824 ikm_free(kmsg);
825
826 return mr;
827 }
828
829 /*
830 * Routine: ipc_kmsg_put_to_kernel
831 * Purpose:
832 * Copies a message buffer to a kernel message.
833 * Frees the message buffer.
834 * No errors allowed.
835 * Conditions:
836 * Nothing locked.
837 */
838
839 void
840 ipc_kmsg_put_to_kernel(
841 mach_msg_header_t *msg,
842 ipc_kmsg_t kmsg,
843 mach_msg_size_t size)
844 {
845 bcopy((char *) &kmsg->ikm_header, (char *) msg, size);
846
847 ikm_free(kmsg);
848 }
849
850 /*
851 * Routine: ipc_kmsg_copyin_header
852 * Purpose:
853 * "Copy-in" port rights in the header of a message.
854 * Operates atomically; if it doesn't succeed the
855 * message header and the space are left untouched.
856 * If it does succeed the remote/local port fields
857 * contain object pointers instead of port names,
858 * and the bits field is updated. The destination port
859 * will be a valid port pointer.
860 *
861 * The notify argument implements the MACH_SEND_CANCEL option.
862 * If it is not MACH_PORT_NULL, it should name a receive right.
863 * If the processing of the destination port would generate
864 * a port-deleted notification (because the right for the
865 * destination port is destroyed and it had a request for
866 * a dead-name notification registered), and the port-deleted
867 * notification would be sent to the named receive right,
868 * then it isn't sent and the send-once right for the notify
869 * port is quietly destroyed.
870 *
871 * [MACH_IPC_COMPAT] There is an atomicity problem if the
872 * reply port is a compat entry and dies at an inopportune
873 * time. This doesn't have any serious consequences
874 * (an observant user task might conceivably notice that
875 * the destination and reply ports were handled inconsistently),
876 * only happens in compat mode, and is extremely unlikely.
877 * Conditions:
878 * Nothing locked.
879 * Returns:
880 * MACH_MSG_SUCCESS Successful copyin.
881 * MACH_SEND_INVALID_HEADER
882 * Illegal value in the message header bits.
883 * MACH_SEND_INVALID_DEST The space is dead.
884 * MACH_SEND_INVALID_NOTIFY
885 * Notify is non-null and doesn't name a receive right.
886 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
887 * MACH_SEND_INVALID_DEST Can't copyin destination port.
888 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
889 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
890 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
891 */
892
893 mach_msg_return_t
894 ipc_kmsg_copyin_header(
895 mach_msg_header_t *msg,
896 ipc_space_t space,
897 mach_port_t notify)
898 {
899 mach_msg_bits_t mbits = msg->msgh_bits &~ MACH_MSGH_BITS_CIRCULAR;
900 mach_port_t dest_name = msg->msgh_remote_port;
901 mach_port_t reply_name = msg->msgh_local_port;
902 kern_return_t kr;
903
904 /* first check for common cases */
905
906 if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
907 case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0): {
908 ipc_entry_t entry;
909 ipc_entry_bits_t bits;
910 ipc_port_t dest_port;
911
912 /* sending an asynchronous message */
913
914 if (reply_name != MACH_PORT_NULL)
915 break;
916
917 is_read_lock(space);
918 if (!space->is_active)
919 goto abort_async;
920
921 /* optimized ipc_entry_lookup */
922
923 {
924 mach_port_index_t index = MACH_PORT_INDEX(dest_name);
925 mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
926
927 if (index >= space->is_table_size)
928 goto abort_async;
929
930 entry = &space->is_table[index];
931 bits = entry->ie_bits;
932
933 /* check generation number and type bit */
934
935 if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
936 (gen | MACH_PORT_TYPE_SEND))
937 goto abort_async;
938 }
939
940 /* optimized ipc_right_copyin */
941
942 assert(IE_BITS_UREFS(bits) > 0);
943
944 dest_port = (ipc_port_t) entry->ie_object;
945 assert(dest_port != IP_NULL);
946
947 ip_lock(dest_port);
948 /* can unlock space now without compromising atomicity */
949 is_read_unlock(space);
950
951 if (!ip_active(dest_port)) {
952 ip_unlock(dest_port);
953 break;
954 }
955
956 assert(dest_port->ip_srights > 0);
957 dest_port->ip_srights++;
958 ip_reference(dest_port);
959 ip_unlock(dest_port);
960
961 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
962 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
963 msg->msgh_remote_port = (mach_port_t) dest_port;
964 return MACH_MSG_SUCCESS;
965
966 abort_async:
967 is_read_unlock(space);
968 break;
969 }
970
971 case MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND,
972 MACH_MSG_TYPE_MAKE_SEND_ONCE): {
973 ipc_entry_num_t size;
974 ipc_entry_t table;
975 ipc_entry_t entry;
976 ipc_entry_bits_t bits;
977 ipc_port_t dest_port, reply_port;
978
979 /* sending a request message */
980
981 is_read_lock(space);
982 if (!space->is_active)
983 goto abort_request;
984
985 size = space->is_table_size;
986 table = space->is_table;
987
988 /* optimized ipc_entry_lookup of dest_name */
989
990 {
991 mach_port_index_t index = MACH_PORT_INDEX(dest_name);
992 mach_port_gen_t gen = MACH_PORT_GEN(dest_name);
993
994 if (index >= size)
995 goto abort_request;
996
997 entry = &table[index];
998 bits = entry->ie_bits;
999
1000 /* check generation number and type bit */
1001
1002 if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_SEND)) !=
1003 (gen | MACH_PORT_TYPE_SEND))
1004 goto abort_request;
1005 }
1006
1007 assert(IE_BITS_UREFS(bits) > 0);
1008
1009 dest_port = (ipc_port_t) entry->ie_object;
1010 assert(dest_port != IP_NULL);
1011
1012 /* optimized ipc_entry_lookup of reply_name */
1013
1014 {
1015 mach_port_index_t index = MACH_PORT_INDEX(reply_name);
1016 mach_port_gen_t gen = MACH_PORT_GEN(reply_name);
1017
1018 if (index >= size)
1019 goto abort_request;
1020
1021 entry = &table[index];
1022 bits = entry->ie_bits;
1023
1024 /* check generation number and type bit */
1025
1026 if ((bits & (IE_BITS_GEN_MASK|MACH_PORT_TYPE_RECEIVE)) !=
1027 (gen | MACH_PORT_TYPE_RECEIVE))
1028 goto abort_request;
1029 }
1030
1031 reply_port = (ipc_port_t) entry->ie_object;
1032 assert(reply_port != IP_NULL);
1033
1034 /*
1035 * To do an atomic copyin, need simultaneous
1036 * locks on both ports and the space. If
1037 * dest_port == reply_port, and simple locking is
1038 * enabled, then we will abort. Otherwise it's
1039 * OK to unlock twice.
1040 */
1041
1042 ip_lock(dest_port);
1043 if (!ip_active(dest_port) || !ip_lock_try(reply_port)) {
1044 ip_unlock(dest_port);
1045 goto abort_request;
1046 }
1047 /* can unlock space now without compromising atomicity */
1048 is_read_unlock(space);
1049
1050 assert(dest_port->ip_srights > 0);
1051 dest_port->ip_srights++;
1052 ip_reference(dest_port);
1053 ip_unlock(dest_port);
1054
1055 assert(ip_active(reply_port));
1056 assert(reply_port->ip_receiver_name == reply_name);
1057 assert(reply_port->ip_receiver == space);
1058
1059 reply_port->ip_sorights++;
1060 ip_reference(reply_port);
1061 ip_unlock(reply_port);
1062
1063 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1064 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
1065 MACH_MSG_TYPE_PORT_SEND_ONCE));
1066 msg->msgh_remote_port = (mach_port_t) dest_port;
1067 msg->msgh_local_port = (mach_port_t) reply_port;
1068 return MACH_MSG_SUCCESS;
1069
1070 abort_request:
1071 is_read_unlock(space);
1072 break;
1073 }
1074
1075 case MACH_MSGH_BITS(MACH_MSG_TYPE_MOVE_SEND_ONCE, 0): {
1076 mach_port_index_t index;
1077 mach_port_gen_t gen;
1078 ipc_entry_t table;
1079 ipc_entry_t entry;
1080 ipc_entry_bits_t bits;
1081 ipc_port_t dest_port;
1082
1083 /* sending a reply message */
1084
1085 if (reply_name != MACH_PORT_NULL)
1086 break;
1087
1088 is_write_lock(space);
1089 if (!space->is_active)
1090 goto abort_reply;
1091
1092 /* optimized ipc_entry_lookup */
1093
1094 table = space->is_table;
1095
1096 index = MACH_PORT_INDEX(dest_name);
1097 gen = MACH_PORT_GEN(dest_name);
1098
1099 if (index >= space->is_table_size)
1100 goto abort_reply;
1101
1102 entry = &table[index];
1103 bits = entry->ie_bits;
1104
1105 /* check generation number, collision bit, and type bit */
1106
1107 if ((bits & (IE_BITS_GEN_MASK|IE_BITS_COLLISION|
1108 MACH_PORT_TYPE_SEND_ONCE)) !=
1109 (gen | MACH_PORT_TYPE_SEND_ONCE))
1110 goto abort_reply;
1111
1112 /* optimized ipc_right_copyin */
1113
1114 assert(IE_BITS_TYPE(bits) == MACH_PORT_TYPE_SEND_ONCE);
1115 assert(IE_BITS_UREFS(bits) == 1);
1116 assert((bits & IE_BITS_MAREQUEST) == 0);
1117
1118 if (entry->ie_request != 0)
1119 goto abort_reply;
1120
1121 dest_port = (ipc_port_t) entry->ie_object;
1122 assert(dest_port != IP_NULL);
1123
1124 ip_lock(dest_port);
1125 if (!ip_active(dest_port)) {
1126 ip_unlock(dest_port);
1127 goto abort_reply;
1128 }
1129
1130 assert(dest_port->ip_sorights > 0);
1131 ip_unlock(dest_port);
1132
1133 /* optimized ipc_entry_dealloc */
1134
1135 entry->ie_next = table->ie_next;
1136 table->ie_next = index;
1137 entry->ie_bits = gen;
1138 entry->ie_object = IO_NULL;
1139 is_write_unlock(space);
1140
1141 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1142 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
1143 0));
1144 msg->msgh_remote_port = (mach_port_t) dest_port;
1145 return MACH_MSG_SUCCESS;
1146
1147 abort_reply:
1148 is_write_unlock(space);
1149 break;
1150 }
1151
1152 default:
1153 /* don't bother optimizing */
1154 break;
1155 }
1156
1157 {
1158 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
1159 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
1160 ipc_object_t dest_port, reply_port;
1161 ipc_port_t dest_soright, reply_soright;
1162 ipc_port_t notify_port = 0; /* '=0' to quiet gcc warnings */
1163
1164 if (!MACH_MSG_TYPE_PORT_ANY_SEND(dest_type))
1165 return MACH_SEND_INVALID_HEADER;
1166
1167 if ((reply_type == 0) ?
1168 (reply_name != MACH_PORT_NULL) :
1169 !MACH_MSG_TYPE_PORT_ANY_SEND(reply_type))
1170 return MACH_SEND_INVALID_HEADER;
1171
1172 is_write_lock(space);
1173 if (!space->is_active)
1174 goto invalid_dest;
1175
1176 if (notify != MACH_PORT_NULL) {
1177 ipc_entry_t entry;
1178
1179 if (((entry = ipc_entry_lookup(space, notify)) == IE_NULL) ||
1180 ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
1181 is_write_unlock(space);
1182 return MACH_SEND_INVALID_NOTIFY;
1183 }
1184
1185 notify_port = (ipc_port_t) entry->ie_object;
1186 }
1187
1188 if (dest_name == reply_name) {
1189 ipc_entry_t entry;
1190 mach_port_t name = dest_name;
1191
1192 /*
1193 * Destination and reply ports are the same!
1194 * This is a little tedious to make atomic, because
1195 * there are 25 combinations of dest_type/reply_type.
1196 * However, most are easy. If either is move-sonce,
1197 * then there must be an error. If either are
1198 * make-send or make-sonce, then we must be looking
1199 * at a receive right so the port can't die.
1200 * The hard cases are the combinations of
1201 * copy-send and make-send.
1202 */
1203
1204 entry = ipc_entry_lookup(space, name);
1205 if (entry == IE_NULL)
1206 goto invalid_dest;
1207
1208 assert(reply_type != 0); /* because name not null */
1209
1210 if (!ipc_right_copyin_check(space, name, entry, reply_type))
1211 goto invalid_reply;
1212
1213 if ((dest_type == MACH_MSG_TYPE_MOVE_SEND_ONCE) ||
1214 (reply_type == MACH_MSG_TYPE_MOVE_SEND_ONCE)) {
1215 /*
1216 * Why must there be an error? To get a valid
1217 * destination, this entry must name a live
1218 * port (not a dead name or dead port). However
1219 * a successful move-sonce will destroy a
1220 * live entry. Therefore the other copyin,
1221 * whatever it is, would fail. We've already
1222 * checked for reply port errors above,
1223 * so report a destination error.
1224 */
1225
1226 goto invalid_dest;
1227 } else if ((dest_type == MACH_MSG_TYPE_MAKE_SEND) ||
1228 (dest_type == MACH_MSG_TYPE_MAKE_SEND_ONCE) ||
1229 (reply_type == MACH_MSG_TYPE_MAKE_SEND) ||
1230 (reply_type == MACH_MSG_TYPE_MAKE_SEND_ONCE)) {
1231 kr = ipc_right_copyin(space, name, entry,
1232 dest_type, FALSE,
1233 &dest_port, &dest_soright);
1234 if (kr != KERN_SUCCESS)
1235 goto invalid_dest;
1236
1237 /*
1238 * Either dest or reply needs a receive right.
1239 * We know the receive right is there, because
1240 * of the copyin_check and copyin calls. Hence
1241 * the port is not in danger of dying. If dest
1242 * used the receive right, then the right needed
1243 * by reply (and verified by copyin_check) will
1244 * still be there.
1245 */
1246
1247 assert(IO_VALID(dest_port));
1248 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
1249 assert(dest_soright == IP_NULL);
1250
1251 kr = ipc_right_copyin(space, name, entry,
1252 reply_type, TRUE,
1253 &reply_port, &reply_soright);
1254
1255 assert(kr == KERN_SUCCESS);
1256 assert(reply_port == dest_port);
1257 assert(entry->ie_bits & MACH_PORT_TYPE_RECEIVE);
1258 assert(reply_soright == IP_NULL);
1259 } else if ((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
1260 (reply_type == MACH_MSG_TYPE_COPY_SEND)) {
1261 /*
1262 * To make this atomic, just do one copy-send,
1263 * and dup the send right we get out.
1264 */
1265
1266 kr = ipc_right_copyin(space, name, entry,
1267 dest_type, FALSE,
1268 &dest_port, &dest_soright);
1269 if (kr != KERN_SUCCESS)
1270 goto invalid_dest;
1271
1272 assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
1273 assert(dest_soright == IP_NULL);
1274
1275 /*
1276 * It's OK if the port we got is dead now,
1277 * so reply_port is IP_DEAD, because the msg
1278 * won't go anywhere anyway.
1279 */
1280
1281 reply_port = (ipc_object_t)
1282 ipc_port_copy_send((ipc_port_t) dest_port);
1283 reply_soright = IP_NULL;
1284 } else if ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
1285 (reply_type == MACH_MSG_TYPE_MOVE_SEND)) {
1286 /*
1287 * This is an easy case. Just use our
1288 * handy-dandy special-purpose copyin call
1289 * to get two send rights for the price of one.
1290 */
1291
1292 kr = ipc_right_copyin_two(space, name, entry,
1293 &dest_port, &dest_soright);
1294 if (kr != KERN_SUCCESS)
1295 goto invalid_dest;
1296
1297 /* the entry might need to be deallocated */
1298
1299 if (IE_BITS_TYPE(entry->ie_bits)
1300 == MACH_PORT_TYPE_NONE)
1301 ipc_entry_dealloc(space, name, entry);
1302
1303 reply_port = dest_port;
1304 reply_soright = IP_NULL;
1305 } else {
1306 ipc_port_t soright;
1307
1308 assert(((dest_type == MACH_MSG_TYPE_COPY_SEND) &&
1309 (reply_type == MACH_MSG_TYPE_MOVE_SEND)) ||
1310 ((dest_type == MACH_MSG_TYPE_MOVE_SEND) &&
1311 (reply_type == MACH_MSG_TYPE_COPY_SEND)));
1312
1313 /*
1314 * To make this atomic, just do a move-send,
1315 * and dup the send right we get out.
1316 */
1317
1318 kr = ipc_right_copyin(space, name, entry,
1319 MACH_MSG_TYPE_MOVE_SEND, FALSE,
1320 &dest_port, &soright);
1321 if (kr != KERN_SUCCESS)
1322 goto invalid_dest;
1323
1324 /* the entry might need to be deallocated */
1325
1326 if (IE_BITS_TYPE(entry->ie_bits)
1327 == MACH_PORT_TYPE_NONE)
1328 ipc_entry_dealloc(space, name, entry);
1329
1330 /*
1331 * It's OK if the port we got is dead now,
1332 * so reply_port is IP_DEAD, because the msg
1333 * won't go anywhere anyway.
1334 */
1335
1336 reply_port = (ipc_object_t)
1337 ipc_port_copy_send((ipc_port_t) dest_port);
1338
1339 if (dest_type == MACH_MSG_TYPE_MOVE_SEND) {
1340 dest_soright = soright;
1341 reply_soright = IP_NULL;
1342 } else {
1343 dest_soright = IP_NULL;
1344 reply_soright = soright;
1345 }
1346 }
1347 } else if (!MACH_PORT_VALID(reply_name)) {
1348 ipc_entry_t entry;
1349
1350 /*
1351 * No reply port! This is an easy case
1352 * to make atomic. Just copyin the destination.
1353 */
1354
1355 entry = ipc_entry_lookup(space, dest_name);
1356 if (entry == IE_NULL)
1357 goto invalid_dest;
1358
1359 kr = ipc_right_copyin(space, dest_name, entry,
1360 dest_type, FALSE,
1361 &dest_port, &dest_soright);
1362 if (kr != KERN_SUCCESS)
1363 goto invalid_dest;
1364
1365 /* the entry might need to be deallocated */
1366
1367 if (IE_BITS_TYPE(entry->ie_bits) == MACH_PORT_TYPE_NONE)
1368 ipc_entry_dealloc(space, dest_name, entry);
1369
1370 reply_port = (ipc_object_t) reply_name;
1371 reply_soright = IP_NULL;
1372 } else {
1373 ipc_entry_t dest_entry, reply_entry;
1374 ipc_port_t saved_reply;
1375
1376 /*
1377 * This is the tough case to make atomic.
1378 * The difficult problem is serializing with port death.
1379 * At the time we copyin dest_port, it must be alive.
1380 * If reply_port is alive when we copyin it, then
1381 * we are OK, because we serialize before the death
1382 * of both ports. Assume reply_port is dead at copyin.
1383 * Then if dest_port dies/died after reply_port died,
1384 * we are OK, because we serialize between the death
1385 * of the two ports. So the bad case is when dest_port
1386 * dies after its copyin, reply_port dies before its
1387 * copyin, and dest_port dies before reply_port. Then
1388 * the copyins operated as if dest_port was alive
1389 * and reply_port was dead, which shouldn't have happened
1390 * because they died in the other order.
1391 *
1392 * We handle the bad case by undoing the copyins
1393 * (which is only possible because the ports are dead)
1394 * and failing with MACH_SEND_INVALID_DEST, serializing
1395 * after the death of the ports.
1396 *
1397 * Note that it is easy for a user task to tell if
1398 * a copyin happened before or after a port died.
1399 * For example, suppose both dest and reply are
1400 * send-once rights (types are both move-sonce) and
1401 * both rights have dead-name requests registered.
1402 * If a port dies before copyin, a dead-name notification
1403 * is generated and the dead name's urefs are incremented,
1404 * and if the copyin happens first, a port-deleted
1405 * notification is generated.
1406 *
1407 * Note that although the entries are different,
1408 * dest_port and reply_port might still be the same.
1409 */
1410
1411 dest_entry = ipc_entry_lookup(space, dest_name);
1412 if (dest_entry == IE_NULL)
1413 goto invalid_dest;
1414
1415 reply_entry = ipc_entry_lookup(space, reply_name);
1416 if (reply_entry == IE_NULL)
1417 goto invalid_reply;
1418
1419 assert(dest_entry != reply_entry); /* names are not equal */
1420 assert(reply_type != 0); /* because reply_name not null */
1421
1422 if (!ipc_right_copyin_check(space, reply_name, reply_entry,
1423 reply_type))
1424 goto invalid_reply;
1425
1426 kr = ipc_right_copyin(space, dest_name, dest_entry,
1427 dest_type, FALSE,
1428 &dest_port, &dest_soright);
1429 if (kr != KERN_SUCCESS)
1430 goto invalid_dest;
1431
1432 assert(IO_VALID(dest_port));
1433
1434 saved_reply = (ipc_port_t) reply_entry->ie_object;
1435 /* might be IP_NULL, if this is a dead name */
1436 if (saved_reply != IP_NULL)
1437 ipc_port_reference(saved_reply);
1438
1439 kr = ipc_right_copyin(space, reply_name, reply_entry,
1440 reply_type, TRUE,
1441 &reply_port, &reply_soright);
1442 #if MACH_IPC_COMPAT
1443 if (kr != KERN_SUCCESS) {
1444 assert(kr == KERN_INVALID_NAME);
1445
1446 /*
1447 * Oops. This must have been a compat entry
1448 * and the port died after the check above.
1449 * We should back out the copyin of dest_port,
1450 * and report MACH_SEND_INVALID_REPLY, but
1451 * if dest_port is alive we can't always do that.
1452 * Punt and pretend we got IO_DEAD, skipping
1453 * further hairy atomicity problems.
1454 */
1455
1456 reply_port = IO_DEAD;
1457 reply_soright = IP_NULL;
1458 goto skip_reply_checks;
1459 }
1460 #else /* MACH_IPC_COMPAT */
1461 assert(kr == KERN_SUCCESS);
1462 #endif /* MACH_IPC_COMPAT */
1463
1464 if ((saved_reply != IP_NULL) && (reply_port == IO_DEAD)) {
1465 ipc_port_t dest = (ipc_port_t) dest_port;
1466 ipc_port_timestamp_t timestamp;
1467 boolean_t must_undo;
1468
1469 /*
1470 * The reply port died before copyin.
1471 * Check if dest port died before reply.
1472 */
1473
1474 ip_lock(saved_reply);
1475 assert(!ip_active(saved_reply));
1476 timestamp = saved_reply->ip_timestamp;
1477 ip_unlock(saved_reply);
1478
1479 ip_lock(dest);
1480 must_undo = (!ip_active(dest) &&
1481 IP_TIMESTAMP_ORDER(dest->ip_timestamp,
1482 timestamp));
1483 ip_unlock(dest);
1484
1485 if (must_undo) {
1486 /*
1487 * Our worst nightmares are realized.
1488 * Both destination and reply ports
1489 * are dead, but in the wrong order,
1490 * so we must undo the copyins and
1491 * possibly generate a dead-name notif.
1492 */
1493
1494 ipc_right_copyin_undo(
1495 space, dest_name, dest_entry,
1496 dest_type, dest_port,
1497 dest_soright);
1498 /* dest_entry may be deallocated now */
1499
1500 ipc_right_copyin_undo(
1501 space, reply_name, reply_entry,
1502 reply_type, reply_port,
1503 reply_soright);
1504 /* reply_entry may be deallocated now */
1505
1506 is_write_unlock(space);
1507
1508 if (dest_soright != IP_NULL)
1509 ipc_notify_dead_name(dest_soright,
1510 dest_name);
1511 assert(reply_soright == IP_NULL);
1512
1513 ipc_port_release(saved_reply);
1514 return MACH_SEND_INVALID_DEST;
1515 }
1516 }
1517
1518 /* the entries might need to be deallocated */
1519
1520 if (IE_BITS_TYPE(reply_entry->ie_bits) == MACH_PORT_TYPE_NONE)
1521 ipc_entry_dealloc(space, reply_name, reply_entry);
1522
1523 #if MACH_IPC_COMPAT
1524 skip_reply_checks:
1525 /*
1526 * We jump here if the reply entry was a compat entry
1527 * and the port died on us. In this case, the copyin
1528 * code already deallocated reply_entry.
1529 */
1530 #endif /* MACH_IPC_COMPAT */
1531
1532 if (IE_BITS_TYPE(dest_entry->ie_bits) == MACH_PORT_TYPE_NONE)
1533 ipc_entry_dealloc(space, dest_name, dest_entry);
1534
1535 if (saved_reply != IP_NULL)
1536 ipc_port_release(saved_reply);
1537 }
1538
1539 /*
1540 * At this point, dest_port, reply_port,
1541 * dest_soright, reply_soright are all initialized.
1542 * Any defunct entries have been deallocated.
1543 * The space is still write-locked, and we need to
1544 * make the MACH_SEND_CANCEL check. The notify_port pointer
1545 * is still usable, because the copyin code above won't ever
1546 * deallocate a receive right, so its entry still exists
1547 * and holds a ref. Note notify_port might even equal
1548 * dest_port or reply_port.
1549 */
1550
1551 if ((notify != MACH_PORT_NULL) &&
1552 (dest_soright == notify_port)) {
1553 ipc_port_release_sonce(dest_soright);
1554 dest_soright = IP_NULL;
1555 }
1556
1557 is_write_unlock(space);
1558
1559 if (dest_soright != IP_NULL)
1560 ipc_notify_port_deleted(dest_soright, dest_name);
1561
1562 if (reply_soright != IP_NULL)
1563 ipc_notify_port_deleted(reply_soright, reply_name);
1564
1565 dest_type = ipc_object_copyin_type(dest_type);
1566 reply_type = ipc_object_copyin_type(reply_type);
1567
1568 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
1569 MACH_MSGH_BITS(dest_type, reply_type));
1570 msg->msgh_remote_port = (mach_port_t) dest_port;
1571 msg->msgh_local_port = (mach_port_t) reply_port;
1572 }
1573
1574 return MACH_MSG_SUCCESS;
1575
1576 invalid_dest:
1577 is_write_unlock(space);
1578 return MACH_SEND_INVALID_DEST;
1579
1580 invalid_reply:
1581 is_write_unlock(space);
1582 return MACH_SEND_INVALID_REPLY;
1583 }
1584
1585 /*
1586 * Routine: ipc_kmsg_copyin
1587 * Purpose:
1588 * "Copy-in" port rights and out-of-line memory
1589 * in the message.
1590 *
1591 * In all failure cases, the message is left holding
1592 * no rights or memory. However, the message buffer
1593 * is not deallocated. If successful, the message
1594 * contains a valid destination port.
1595 * Conditions:
1596 * Nothing locked.
1597 * Returns:
1598 * MACH_MSG_SUCCESS Successful copyin.
1599 * MACH_SEND_INVALID_HEADER
1600 * Illegal value in the message header bits.
1601 * MACH_SEND_INVALID_NOTIFY Bad notify port.
1602 * MACH_SEND_INVALID_DEST Can't copyin destination port.
1603 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
1604 * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
1605 * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
1606 * MACH_SEND_INVALID_TYPE Bad type specification.
1607 * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
1608 */
1609
1610 mach_msg_return_t
1611 ipc_kmsg_copyin(
1612 ipc_kmsg_t kmsg,
1613 ipc_space_t space,
1614 vm_map_t map,
1615 mach_port_t notify)
1616 {
1617 ipc_object_t dest;
1618 vm_offset_t saddr, eaddr;
1619 boolean_t complex;
1620 mach_msg_return_t mr;
1621 boolean_t use_page_lists, steal_pages;
1622
1623 mr = ipc_kmsg_copyin_header(&kmsg->ikm_header, space, notify);
1624 if (mr != MACH_MSG_SUCCESS)
1625 return mr;
1626
1627 if ((kmsg->ikm_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) == 0)
1628 return MACH_MSG_SUCCESS;
1629
1630 dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
1631 complex = FALSE;
1632 use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
1633 steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
1634
1635 #if NORMA_IPC
1636 if (IP_NORMA_IS_PROXY((ipc_port_t) dest)) {
1637 use_page_lists = TRUE;
1638 steal_pages = TRUE;
1639 }
1640 #endif /* NORMA_IPC */
1641
1642 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
1643 eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
1644
1645 while (saddr < eaddr) {
1646 vm_offset_t taddr = saddr;
1647 mach_msg_type_long_t *type;
1648 mach_msg_type_name_t name;
1649 mach_msg_type_size_t size;
1650 mach_msg_type_number_t number;
1651 boolean_t is_inline, longform, dealloc, is_port;
1652 vm_offset_t data;
1653 vm_size_t length;
1654 kern_return_t kr;
1655
1656 type = (mach_msg_type_long_t *) saddr;
1657
1658 if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
1659 ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
1660 ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
1661 ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1662 return MACH_SEND_MSG_TOO_SMALL;
1663 }
1664
1665 is_inline = ((mach_msg_type_t*)type)->msgt_inline;
1666 dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
1667 if (longform) {
1668 /* This must be aligned */
1669 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1670 (is_misaligned(type))) {
1671 saddr = ptr_align(saddr);
1672 continue;
1673 }
1674 name = type->msgtl_name;
1675 size = type->msgtl_size;
1676 number = type->msgtl_number;
1677 saddr += sizeof(mach_msg_type_long_t);
1678 } else {
1679 name = ((mach_msg_type_t*)type)->msgt_name;
1680 size = ((mach_msg_type_t*)type)->msgt_size;
1681 number = ((mach_msg_type_t*)type)->msgt_number;
1682 saddr += sizeof(mach_msg_type_t);
1683 }
1684
1685 is_port = MACH_MSG_TYPE_PORT_ANY(name);
1686
1687 if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
1688 (longform && ((type->msgtl_header.msgt_name != 0) ||
1689 (type->msgtl_header.msgt_size != 0) ||
1690 (type->msgtl_header.msgt_number != 0))) ||
1691 (((mach_msg_type_t*)type)->msgt_unused != 0) ||
1692 (dealloc && is_inline)) {
1693 ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1694 return MACH_SEND_INVALID_TYPE;
1695 }
1696
1697 /* padding (ptrs and ports) ? */
1698 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1699 ((size >> 3) == sizeof(natural_t)))
1700 saddr = ptr_align(saddr);
1701
1702 /* calculate length of data in bytes, rounding up */
1703
1704 length = ((number * size) + 7) >> 3;
1705
1706 if (is_inline) {
1707 vm_size_t amount;
1708
1709 /* inline data sizes round up to int boundaries */
1710
1711 amount = (length + 3) &~ 3;
1712 if ((eaddr - saddr) < amount) {
1713 ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1714 return MACH_SEND_MSG_TOO_SMALL;
1715 }
1716
1717 data = saddr;
1718 saddr += amount;
1719 } else {
1720 vm_offset_t addr;
1721
1722 if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
1723 saddr = ptr_align(saddr);
1724
1725 if ((eaddr - saddr) < sizeof(vm_offset_t)) {
1726 ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
1727 return MACH_SEND_MSG_TOO_SMALL;
1728 }
1729
1730 /* grab the out-of-line data */
1731
1732 addr = * (vm_offset_t *) saddr;
1733
1734 if (length == 0)
1735 data = 0;
1736 else if (is_port) {
1737 data = kalloc(length);
1738 if (data == 0)
1739 goto invalid_memory;
1740
1741 if (copyinmap(map, (char *) addr,
1742 (char *) data, length) ||
1743 (dealloc &&
1744 (vm_deallocate(map, addr, length) !=
1745 KERN_SUCCESS))) {
1746 kfree(data, length);
1747 goto invalid_memory;
1748 }
1749 } else {
1750 vm_map_copy_t copy;
1751
1752 if (use_page_lists) {
1753 kr = vm_map_copyin_page_list(map,
1754 addr, length, dealloc,
1755 steal_pages, ©, FALSE);
1756 } else {
1757 kr = vm_map_copyin(map, addr, length,
1758 dealloc, ©);
1759 }
1760 if (kr != KERN_SUCCESS) {
1761 invalid_memory:
1762 ipc_kmsg_clean_partial(kmsg, taddr,
1763 FALSE, 0);
1764 return MACH_SEND_INVALID_MEMORY;
1765 }
1766
1767 data = (vm_offset_t) copy;
1768 }
1769
1770 * (vm_offset_t *) saddr = data;
1771 saddr += sizeof(vm_offset_t);
1772 complex = TRUE;
1773 }
1774
1775 if (is_port) {
1776 mach_msg_type_name_t newname =
1777 ipc_object_copyin_type(name);
1778 ipc_object_t *objects = (ipc_object_t *) data;
1779 mach_msg_type_number_t i;
1780
1781 if (longform)
1782 type->msgtl_name = newname;
1783 else
1784 ((mach_msg_type_t*)type)->msgt_name = newname;
1785
1786 for (i = 0; i < number; i++) {
1787 mach_port_t port = (mach_port_t) objects[i];
1788 ipc_object_t object;
1789
1790 if (!MACH_PORT_VALID(port))
1791 continue;
1792
1793 kr = ipc_object_copyin(space, port,
1794 name, &object);
1795 if (kr != KERN_SUCCESS) {
1796 ipc_kmsg_clean_partial(kmsg, taddr,
1797 TRUE, i);
1798 return MACH_SEND_INVALID_RIGHT;
1799 }
1800
1801 if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
1802 ipc_port_check_circularity(
1803 (ipc_port_t) object,
1804 (ipc_port_t) dest))
1805 kmsg->ikm_header.msgh_bits |=
1806 MACH_MSGH_BITS_CIRCULAR;
1807
1808 objects[i] = object;
1809 }
1810
1811 complex = TRUE;
1812 }
1813 }
1814
1815 if (!complex)
1816 kmsg->ikm_header.msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
1817
1818 return MACH_MSG_SUCCESS;
1819 }
1820
1821 /*
1822 * Routine: ipc_kmsg_copyin_from_kernel
1823 * Purpose:
1824 * "Copy-in" port rights and out-of-line memory
1825 * in a message sent from the kernel.
1826 *
1827 * Because the message comes from the kernel,
1828 * the implementation assumes there are no errors
1829 * or peculiarities in the message.
1830 *
1831 * Returns TRUE if queueing the message
1832 * would result in a circularity.
1833 * Conditions:
1834 * Nothing locked.
1835 */
1836
1837 void
1838 ipc_kmsg_copyin_from_kernel(
1839 ipc_kmsg_t kmsg)
1840 {
1841 mach_msg_bits_t bits = kmsg->ikm_header.msgh_bits;
1842 mach_msg_type_name_t rname = MACH_MSGH_BITS_REMOTE(bits);
1843 mach_msg_type_name_t lname = MACH_MSGH_BITS_LOCAL(bits);
1844 ipc_object_t remote = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
1845 ipc_object_t local = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
1846 vm_offset_t saddr, eaddr;
1847
1848 /* translate the destination and reply ports */
1849
1850 ipc_object_copyin_from_kernel(remote, rname);
1851 if (IO_VALID(local))
1852 ipc_object_copyin_from_kernel(local, lname);
1853
1854 /*
1855 * The common case is a complex message with no reply port,
1856 * because that is what the memory_object interface uses.
1857 */
1858
1859 if (bits == (MACH_MSGH_BITS_COMPLEX |
1860 MACH_MSGH_BITS(MACH_MSG_TYPE_COPY_SEND, 0))) {
1861 bits = (MACH_MSGH_BITS_COMPLEX |
1862 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0));
1863
1864 kmsg->ikm_header.msgh_bits = bits;
1865 } else {
1866 bits = (MACH_MSGH_BITS_OTHER(bits) |
1867 MACH_MSGH_BITS(ipc_object_copyin_type(rname),
1868 ipc_object_copyin_type(lname)));
1869
1870 kmsg->ikm_header.msgh_bits = bits;
1871 if ((bits & MACH_MSGH_BITS_COMPLEX) == 0)
1872 return;
1873 }
1874
1875 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
1876 eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
1877
1878 while (saddr < eaddr) {
1879 mach_msg_type_long_t *type;
1880 mach_msg_type_name_t name;
1881 mach_msg_type_size_t size;
1882 mach_msg_type_number_t number;
1883 boolean_t is_inline, longform, is_port;
1884 vm_offset_t data;
1885 vm_size_t length;
1886
1887 type = (mach_msg_type_long_t *) saddr;
1888 is_inline = ((mach_msg_type_t*)type)->msgt_inline;
1889 longform = ((mach_msg_type_t*)type)->msgt_longform;
1890 /* type->msgtl_header.msgt_deallocate not used */
1891 if (longform) {
1892 /* This must be aligned */
1893 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1894 (is_misaligned(type))) {
1895 saddr = ptr_align(saddr);
1896 continue;
1897 }
1898 name = type->msgtl_name;
1899 size = type->msgtl_size;
1900 number = type->msgtl_number;
1901 saddr += sizeof(mach_msg_type_long_t);
1902 } else {
1903 name = ((mach_msg_type_t*)type)->msgt_name;
1904 size = ((mach_msg_type_t*)type)->msgt_size;
1905 number = ((mach_msg_type_t*)type)->msgt_number;
1906 saddr += sizeof(mach_msg_type_t);
1907 }
1908
1909 /* padding (ptrs and ports) ? */
1910 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
1911 ((size >> 3) == sizeof(natural_t)))
1912 saddr = ptr_align(saddr);
1913
1914 /* calculate length of data in bytes, rounding up */
1915
1916 length = ((number * size) + 7) >> 3;
1917
1918 is_port = MACH_MSG_TYPE_PORT_ANY(name);
1919
1920 if (is_inline) {
1921 /* inline data sizes round up to int boundaries */
1922
1923 data = saddr;
1924 saddr += (length + 3) &~ 3;
1925 } else {
1926 /*
1927 * The sender should supply ready-made memory
1928 * for us, so we don't need to do anything.
1929 */
1930
1931 data = * (vm_offset_t *) saddr;
1932 saddr += sizeof(vm_offset_t);
1933 }
1934
1935 if (is_port) {
1936 mach_msg_type_name_t newname =
1937 ipc_object_copyin_type(name);
1938 ipc_object_t *objects = (ipc_object_t *) data;
1939 mach_msg_type_number_t i;
1940
1941 if (longform)
1942 type->msgtl_name = newname;
1943 else
1944 ((mach_msg_type_t*)type)->msgt_name = newname;
1945 for (i = 0; i < number; i++) {
1946 ipc_object_t object = objects[i];
1947
1948 if (!IO_VALID(object))
1949 continue;
1950
1951 ipc_object_copyin_from_kernel(object, name);
1952
1953 if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
1954 ipc_port_check_circularity(
1955 (ipc_port_t) object,
1956 (ipc_port_t) remote))
1957 kmsg->ikm_header.msgh_bits |=
1958 MACH_MSGH_BITS_CIRCULAR;
1959 }
1960 }
1961 }
1962 }
1963
1964 /*
1965 * Routine: ipc_kmsg_copyout_header
1966 * Purpose:
1967 * "Copy-out" port rights in the header of a message.
1968 * Operates atomically; if it doesn't succeed the
1969 * message header and the space are left untouched.
1970 * If it does succeed the remote/local port fields
1971 * contain port names instead of object pointers,
1972 * and the bits field is updated.
1973 *
1974 * The notify argument implements the MACH_RCV_NOTIFY option.
1975 * If it is not MACH_PORT_NULL, it should name a receive right.
1976 * If the process of receiving the reply port creates a
1977 * new right in the receiving task, then the new right is
1978 * automatically registered for a dead-name notification,
1979 * with the notify port supplying the send-once right.
1980 * Conditions:
1981 * Nothing locked.
1982 * Returns:
1983 * MACH_MSG_SUCCESS Copied out port rights.
1984 * MACH_RCV_INVALID_NOTIFY
1985 * Notify is non-null and doesn't name a receive right.
1986 * (Either KERN_INVALID_NAME or KERN_INVALID_RIGHT.)
1987 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
1988 * The space is dead.
1989 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE
1990 * No room in space for another name.
1991 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
1992 * Couldn't allocate memory for the reply port.
1993 * MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_KERNEL
1994 * Couldn't allocate memory for the dead-name request.
1995 */
1996
1997 mach_msg_return_t
1998 ipc_kmsg_copyout_header(
1999 mach_msg_header_t *msg,
2000 ipc_space_t space,
2001 mach_port_t notify)
2002 {
2003 mach_msg_bits_t mbits = msg->msgh_bits;
2004 ipc_port_t dest = (ipc_port_t) msg->msgh_remote_port;
2005
2006 assert(IP_VALID(dest));
2007
2008 /* first check for common cases */
2009
2010 if (notify == MACH_PORT_NULL) switch (MACH_MSGH_BITS_PORTS(mbits)) {
2011 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND, 0): {
2012 mach_port_t dest_name;
2013 ipc_port_t nsrequest;
2014
2015 /* receiving an asynchronous message */
2016
2017 ip_lock(dest);
2018 if (!ip_active(dest)) {
2019 ip_unlock(dest);
2020 break;
2021 }
2022
2023 /* optimized ipc_object_copyout_dest */
2024
2025 assert(dest->ip_srights > 0);
2026 ip_release(dest);
2027
2028 if (dest->ip_receiver == space)
2029 dest_name = dest->ip_receiver_name;
2030 else
2031 dest_name = MACH_PORT_NULL;
2032
2033 if ((--dest->ip_srights == 0) &&
2034 ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
2035 mach_port_mscount_t mscount;
2036
2037 dest->ip_nsrequest = IP_NULL;
2038 mscount = dest->ip_mscount;
2039 ip_unlock(dest);
2040
2041 ipc_notify_no_senders(nsrequest, mscount);
2042 } else
2043 ip_unlock(dest);
2044
2045 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2046 MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND));
2047 msg->msgh_local_port = dest_name;
2048 msg->msgh_remote_port = MACH_PORT_NULL;
2049 return MACH_MSG_SUCCESS;
2050 }
2051
2052 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND,
2053 MACH_MSG_TYPE_PORT_SEND_ONCE): {
2054 ipc_entry_t table;
2055 mach_port_index_t index;
2056 ipc_entry_t entry;
2057 ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
2058 mach_port_t dest_name, reply_name;
2059 ipc_port_t nsrequest;
2060
2061 /* receiving a request message */
2062
2063 if (!IP_VALID(reply))
2064 break;
2065
2066 is_write_lock(space);
2067 if (!space->is_active ||
2068 ((index = (table = space->is_table)->ie_next) == 0)) {
2069 is_write_unlock(space);
2070 break;
2071 }
2072
2073 /*
2074 * To do an atomic copyout, need simultaneous
2075 * locks on both ports and the space. If
2076 * dest == reply, and simple locking is
2077 * enabled, then we will abort. Otherwise it's
2078 * OK to unlock twice.
2079 */
2080
2081 ip_lock(dest);
2082 if (!ip_active(dest) || !ip_lock_try(reply)) {
2083 ip_unlock(dest);
2084 is_write_unlock(space);
2085 break;
2086 }
2087
2088 if (!ip_active(reply)) {
2089 ip_unlock(reply);
2090 ip_unlock(dest);
2091 is_write_unlock(space);
2092 break;
2093 }
2094
2095 assert(reply->ip_sorights > 0);
2096 ip_unlock(reply);
2097
2098 /* optimized ipc_entry_get */
2099
2100 entry = &table[index];
2101 table->ie_next = entry->ie_next;
2102 entry->ie_request = 0;
2103
2104 {
2105 mach_port_gen_t gen;
2106
2107 assert((entry->ie_bits &~ IE_BITS_GEN_MASK) == 0);
2108 gen = entry->ie_bits + IE_BITS_GEN_ONE;
2109
2110 reply_name = MACH_PORT_MAKE(index, gen);
2111
2112 /* optimized ipc_right_copyout */
2113
2114 entry->ie_bits = gen | (MACH_PORT_TYPE_SEND_ONCE | 1);
2115 }
2116
2117 assert(MACH_PORT_VALID(reply_name));
2118 entry->ie_object = (ipc_object_t) reply;
2119 is_write_unlock(space);
2120
2121 /* optimized ipc_object_copyout_dest */
2122
2123 assert(dest->ip_srights > 0);
2124 ip_release(dest);
2125
2126 if (dest->ip_receiver == space)
2127 dest_name = dest->ip_receiver_name;
2128 else
2129 dest_name = MACH_PORT_NULL;
2130
2131 if ((--dest->ip_srights == 0) &&
2132 ((nsrequest = dest->ip_nsrequest) != IP_NULL)) {
2133 mach_port_mscount_t mscount;
2134
2135 dest->ip_nsrequest = IP_NULL;
2136 mscount = dest->ip_mscount;
2137 ip_unlock(dest);
2138
2139 ipc_notify_no_senders(nsrequest, mscount);
2140 } else
2141 ip_unlock(dest);
2142
2143 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2144 MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE,
2145 MACH_MSG_TYPE_PORT_SEND));
2146 msg->msgh_local_port = dest_name;
2147 msg->msgh_remote_port = reply_name;
2148 return MACH_MSG_SUCCESS;
2149 }
2150
2151 case MACH_MSGH_BITS(MACH_MSG_TYPE_PORT_SEND_ONCE, 0): {
2152 mach_port_t dest_name;
2153
2154 /* receiving a reply message */
2155
2156 ip_lock(dest);
2157 if (!ip_active(dest)) {
2158 ip_unlock(dest);
2159 break;
2160 }
2161
2162 /* optimized ipc_object_copyout_dest */
2163
2164 assert(dest->ip_sorights > 0);
2165
2166 if (dest->ip_receiver == space) {
2167 ip_release(dest);
2168 dest->ip_sorights--;
2169 dest_name = dest->ip_receiver_name;
2170 ip_unlock(dest);
2171 } else {
2172 ip_unlock(dest);
2173
2174 ipc_notify_send_once(dest);
2175 dest_name = MACH_PORT_NULL;
2176 }
2177
2178 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2179 MACH_MSGH_BITS(0, MACH_MSG_TYPE_PORT_SEND_ONCE));
2180 msg->msgh_local_port = dest_name;
2181 msg->msgh_remote_port = MACH_PORT_NULL;
2182 return MACH_MSG_SUCCESS;
2183 }
2184
2185 default:
2186 /* don't bother optimizing */
2187 break;
2188 }
2189
2190 {
2191 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2192 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2193 ipc_port_t reply = (ipc_port_t) msg->msgh_local_port;
2194 mach_port_t dest_name, reply_name;
2195
2196 if (IP_VALID(reply)) {
2197 ipc_port_t notify_port;
2198 ipc_entry_t entry;
2199 kern_return_t kr;
2200
2201 /*
2202 * Handling notify (for MACH_RCV_NOTIFY) is tricky.
2203 * The problem is atomically making a send-once right
2204 * from the notify port and installing it for a
2205 * dead-name request in the new entry, because this
2206 * requires two port locks (on the notify port and
2207 * the reply port). However, we can safely make
2208 * and consume send-once rights for the notify port
2209 * as long as we hold the space locked. This isn't
2210 * an atomicity problem, because the only way
2211 * to detect that a send-once right has been created
2212 * and then consumed if it wasn't needed is by getting
2213 * at the receive right to look at ip_sorights, and
2214 * because the space is write-locked status calls can't
2215 * lookup the notify port receive right. When we make
2216 * the send-once right, we lock the notify port,
2217 * so any status calls in progress will be done.
2218 */
2219
2220 is_write_lock(space);
2221
2222 for (;;) {
2223 ipc_port_request_index_t request;
2224
2225 if (!space->is_active) {
2226 is_write_unlock(space);
2227 return (MACH_RCV_HEADER_ERROR|
2228 MACH_MSG_IPC_SPACE);
2229 }
2230
2231 if (notify != MACH_PORT_NULL) {
2232 notify_port = ipc_port_lookup_notify(space,
2233 notify);
2234 if (notify_port == IP_NULL) {
2235 is_write_unlock(space);
2236 return MACH_RCV_INVALID_NOTIFY;
2237 }
2238 } else
2239 notify_port = IP_NULL;
2240
2241 if ((reply_type != MACH_MSG_TYPE_PORT_SEND_ONCE) &&
2242 ipc_right_reverse(space, (ipc_object_t) reply,
2243 &reply_name, &entry)) {
2244 /* reply port is locked and active */
2245
2246 /*
2247 * We don't need the notify_port
2248 * send-once right, but we can't release
2249 * it here because reply port is locked.
2250 * Wait until after the copyout to
2251 * release the notify port right.
2252 */
2253
2254 assert(entry->ie_bits &
2255 MACH_PORT_TYPE_SEND_RECEIVE);
2256 break;
2257 }
2258
2259 ip_lock(reply);
2260 if (!ip_active(reply)) {
2261 ip_release(reply);
2262 ip_check_unlock(reply);
2263
2264 if (notify_port != IP_NULL)
2265 ipc_port_release_sonce(notify_port);
2266
2267 ip_lock(dest);
2268 is_write_unlock(space);
2269
2270 reply = IP_DEAD;
2271 reply_name = MACH_PORT_DEAD;
2272 goto copyout_dest;
2273 }
2274
2275 kr = ipc_entry_get(space, &reply_name, &entry);
2276 if (kr != KERN_SUCCESS) {
2277 ip_unlock(reply);
2278
2279 if (notify_port != IP_NULL)
2280 ipc_port_release_sonce(notify_port);
2281
2282 /* space is locked */
2283 kr = ipc_entry_grow_table(space);
2284 if (kr != KERN_SUCCESS) {
2285 /* space is unlocked */
2286
2287 if (kr == KERN_RESOURCE_SHORTAGE)
2288 return (MACH_RCV_HEADER_ERROR|
2289 MACH_MSG_IPC_KERNEL);
2290 else
2291 return (MACH_RCV_HEADER_ERROR|
2292 MACH_MSG_IPC_SPACE);
2293 }
2294 /* space is locked again; start over */
2295
2296 continue;
2297 }
2298
2299 assert(IE_BITS_TYPE(entry->ie_bits)
2300 == MACH_PORT_TYPE_NONE);
2301 assert(entry->ie_object == IO_NULL);
2302
2303 if (notify_port == IP_NULL) {
2304 /* not making a dead-name request */
2305
2306 entry->ie_object = (ipc_object_t) reply;
2307 break;
2308 }
2309
2310 kr = ipc_port_dnrequest(reply, reply_name,
2311 notify_port, &request);
2312 if (kr != KERN_SUCCESS) {
2313 ip_unlock(reply);
2314
2315 ipc_port_release_sonce(notify_port);
2316
2317 ipc_entry_dealloc(space, reply_name, entry);
2318 is_write_unlock(space);
2319
2320 ip_lock(reply);
2321 if (!ip_active(reply)) {
2322 /* will fail next time around loop */
2323
2324 ip_unlock(reply);
2325 is_write_lock(space);
2326 continue;
2327 }
2328
2329 kr = ipc_port_dngrow(reply);
2330 /* port is unlocked */
2331 if (kr != KERN_SUCCESS)
2332 return (MACH_RCV_HEADER_ERROR|
2333 MACH_MSG_IPC_KERNEL);
2334
2335 is_write_lock(space);
2336 continue;
2337 }
2338
2339 notify_port = IP_NULL; /* don't release right below */
2340
2341 entry->ie_object = (ipc_object_t) reply;
2342 entry->ie_request = request;
2343 break;
2344 }
2345
2346 /* space and reply port are locked and active */
2347
2348 ip_reference(reply); /* hold onto the reply port */
2349
2350 kr = ipc_right_copyout(space, reply_name, entry,
2351 reply_type, TRUE, (ipc_object_t) reply);
2352 /* reply port is unlocked */
2353 assert(kr == KERN_SUCCESS);
2354
2355 if (notify_port != IP_NULL)
2356 ipc_port_release_sonce(notify_port);
2357
2358 ip_lock(dest);
2359 is_write_unlock(space);
2360 } else {
2361 /*
2362 * No reply port! This is an easy case.
2363 * We only need to have the space locked
2364 * when checking notify and when locking
2365 * the destination (to ensure atomicity).
2366 */
2367
2368 is_read_lock(space);
2369 if (!space->is_active) {
2370 is_read_unlock(space);
2371 return MACH_RCV_HEADER_ERROR|MACH_MSG_IPC_SPACE;
2372 }
2373
2374 if (notify != MACH_PORT_NULL) {
2375 ipc_entry_t entry;
2376
2377 /* must check notify even though it won't be used */
2378
2379 if (((entry = ipc_entry_lookup(space, notify))
2380 == IE_NULL) ||
2381 ((entry->ie_bits & MACH_PORT_TYPE_RECEIVE) == 0)) {
2382 is_read_unlock(space);
2383 return MACH_RCV_INVALID_NOTIFY;
2384 }
2385 }
2386
2387 ip_lock(dest);
2388 is_read_unlock(space);
2389
2390 reply_name = (mach_port_t) reply;
2391 }
2392
2393 /*
2394 * At this point, the space is unlocked and the destination
2395 * port is locked. (Lock taken while space was locked.)
2396 * reply_name is taken care of; we still need dest_name.
2397 * We still hold a ref for reply (if it is valid).
2398 *
2399 * If the space holds receive rights for the destination,
2400 * we return its name for the right. Otherwise the task
2401 * managed to destroy or give away the receive right between
2402 * receiving the message and this copyout. If the destination
2403 * is dead, return MACH_PORT_DEAD, and if the receive right
2404 * exists somewhere else (another space, in transit)
2405 * return MACH_PORT_NULL.
2406 *
2407 * Making this copyout operation atomic with the previous
2408 * copyout of the reply port is a bit tricky. If there was
2409 * no real reply port (it wasn't IP_VALID) then this isn't
2410 * an issue. If the reply port was dead at copyout time,
2411 * then we are OK, because if dest is dead we serialize
2412 * after the death of both ports and if dest is alive
2413 * we serialize after reply died but before dest's (later) death.
2414 * So assume reply was alive when we copied it out. If dest
2415 * is alive, then we are OK because we serialize before
2416 * the ports' deaths. So assume dest is dead when we look at it.
2417 * If reply dies/died after dest, then we are OK because
2418 * we serialize after dest died but before reply dies.
2419 * So the hard case is when reply is alive at copyout,
2420 * dest is dead at copyout, and reply died before dest died.
2421 * In this case pretend that dest is still alive, so
2422 * we serialize while both ports are alive.
2423 *
2424 * Because the space lock is held across the copyout of reply
2425 * and locking dest, the receive right for dest can't move
2426 * in or out of the space while the copyouts happen, so
2427 * that isn't an atomicity problem. In the last hard case
2428 * above, this implies that when dest is dead that the
2429 * space couldn't have had receive rights for dest at
2430 * the time reply was copied-out, so when we pretend
2431 * that dest is still alive, we can return MACH_PORT_NULL.
2432 *
2433 * If dest == reply, then we have to make it look like
2434 * either both copyouts happened before the port died,
2435 * or both happened after the port died. This special
2436 * case works naturally if the timestamp comparison
2437 * is done correctly.
2438 */
2439
2440 copyout_dest:
2441
2442 if (ip_active(dest)) {
2443 ipc_object_copyout_dest(space, (ipc_object_t) dest,
2444 dest_type, &dest_name);
2445 /* dest is unlocked */
2446 } else {
2447 ipc_port_timestamp_t timestamp;
2448
2449 timestamp = dest->ip_timestamp;
2450 ip_release(dest);
2451 ip_check_unlock(dest);
2452
2453 if (IP_VALID(reply)) {
2454 ip_lock(reply);
2455 if (ip_active(reply) ||
2456 IP_TIMESTAMP_ORDER(timestamp,
2457 reply->ip_timestamp))
2458 dest_name = MACH_PORT_DEAD;
2459 else
2460 dest_name = MACH_PORT_NULL;
2461 ip_unlock(reply);
2462 } else
2463 dest_name = MACH_PORT_DEAD;
2464 }
2465
2466 if (IP_VALID(reply))
2467 ipc_port_release(reply);
2468
2469 msg->msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2470 MACH_MSGH_BITS(reply_type, dest_type));
2471 msg->msgh_local_port = dest_name;
2472 msg->msgh_remote_port = reply_name;
2473 }
2474
2475 return MACH_MSG_SUCCESS;
2476 }
2477
2478 /*
2479 * Routine: ipc_kmsg_copyout_object
2480 * Purpose:
2481 * Copy-out a port right. Always returns a name,
2482 * even for unsuccessful return codes. Always
2483 * consumes the supplied object.
2484 * Conditions:
2485 * Nothing locked.
2486 * Returns:
2487 * MACH_MSG_SUCCESS The space acquired the right
2488 * (name is valid) or the object is dead (MACH_PORT_DEAD).
2489 * MACH_MSG_IPC_SPACE No room in space for the right,
2490 * or the space is dead. (Name is MACH_PORT_NULL.)
2491 * MACH_MSG_IPC_KERNEL Kernel resource shortage.
2492 * (Name is MACH_PORT_NULL.)
2493 */
2494
2495 mach_msg_return_t
2496 ipc_kmsg_copyout_object(
2497 ipc_space_t space,
2498 ipc_object_t object,
2499 mach_msg_type_name_t msgt_name,
2500 mach_port_t *namep)
2501 {
2502 if (!IO_VALID(object)) {
2503 *namep = (mach_port_t) object;
2504 return MACH_MSG_SUCCESS;
2505 }
2506
2507 /*
2508 * Attempt quick copyout of send rights. We optimize for a
2509 * live port for which the receiver holds send (and not
2510 * receive) rights in his local table.
2511 */
2512
2513 if (msgt_name != MACH_MSG_TYPE_PORT_SEND)
2514 goto slow_copyout;
2515
2516 {
2517 register ipc_port_t port = (ipc_port_t) object;
2518 ipc_entry_t entry;
2519
2520 is_write_lock(space);
2521 if (!space->is_active) {
2522 is_write_unlock(space);
2523 goto slow_copyout;
2524 }
2525
2526 ip_lock(port);
2527 if (!ip_active(port) ||
2528 !ipc_hash_local_lookup(space, (ipc_object_t) port,
2529 namep, &entry)) {
2530 ip_unlock(port);
2531 is_write_unlock(space);
2532 goto slow_copyout;
2533 }
2534
2535 /*
2536 * Copyout the send right, incrementing urefs
2537 * unless it would overflow, and consume the right.
2538 */
2539
2540 assert(port->ip_srights > 1);
2541 port->ip_srights--;
2542 ip_release(port);
2543 ip_unlock(port);
2544
2545 assert(entry->ie_bits & MACH_PORT_TYPE_SEND);
2546 assert(IE_BITS_UREFS(entry->ie_bits) > 0);
2547 assert(IE_BITS_UREFS(entry->ie_bits) < MACH_PORT_UREFS_MAX);
2548
2549 {
2550 register ipc_entry_bits_t bits = entry->ie_bits + 1;
2551
2552 if (IE_BITS_UREFS(bits) < MACH_PORT_UREFS_MAX)
2553 entry->ie_bits = bits;
2554 }
2555
2556 is_write_unlock(space);
2557 return MACH_MSG_SUCCESS;
2558 }
2559
2560 slow_copyout: {
2561 kern_return_t kr;
2562
2563 kr = ipc_object_copyout(space, object, msgt_name, TRUE, namep);
2564 if (kr != KERN_SUCCESS) {
2565 ipc_object_destroy(object, msgt_name);
2566
2567 if (kr == KERN_INVALID_CAPABILITY)
2568 *namep = MACH_PORT_DEAD;
2569 else {
2570 *namep = MACH_PORT_NULL;
2571
2572 if (kr == KERN_RESOURCE_SHORTAGE)
2573 return MACH_MSG_IPC_KERNEL;
2574 else
2575 return MACH_MSG_IPC_SPACE;
2576 }
2577 }
2578
2579 return MACH_MSG_SUCCESS;
2580 }
2581 }
2582
2583 /*
2584 * Routine: ipc_kmsg_copyout_body
2585 * Purpose:
2586 * "Copy-out" port rights and out-of-line memory
2587 * in the body of a message.
2588 *
2589 * The error codes are a combination of special bits.
2590 * The copyout proceeds despite errors.
2591 * Conditions:
2592 * Nothing locked.
2593 * Returns:
2594 * MACH_MSG_SUCCESS Successfull copyout.
2595 * MACH_MSG_IPC_SPACE No room for port right in name space.
2596 * MACH_MSG_VM_SPACE No room for memory in address space.
2597 * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
2598 * MACH_MSG_VM_KERNEL Resource shortage handling memory.
2599 */
2600
2601 mach_msg_return_t
2602 ipc_kmsg_copyout_body(
2603 vm_offset_t saddr,
2604 vm_offset_t eaddr,
2605 ipc_space_t space,
2606 vm_map_t map)
2607 {
2608 mach_msg_return_t mr = MACH_MSG_SUCCESS;
2609 kern_return_t kr;
2610
2611 while (saddr < eaddr) {
2612 vm_offset_t taddr = saddr;
2613 mach_msg_type_long_t *type;
2614 mach_msg_type_name_t name;
2615 mach_msg_type_size_t size;
2616 mach_msg_type_number_t number;
2617 boolean_t is_inline, longform, is_port;
2618 vm_size_t length;
2619 vm_offset_t addr;
2620
2621 type = (mach_msg_type_long_t *) saddr;
2622 is_inline = ((mach_msg_type_t*)type)->msgt_inline;
2623 longform = ((mach_msg_type_t*)type)->msgt_longform;
2624 if (longform) {
2625 /* This must be aligned */
2626 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2627 (is_misaligned(type))) {
2628 saddr = ptr_align(saddr);
2629 continue;
2630 }
2631 name = type->msgtl_name;
2632 size = type->msgtl_size;
2633 number = type->msgtl_number;
2634 saddr += sizeof(mach_msg_type_long_t);
2635 } else {
2636 name = ((mach_msg_type_t*)type)->msgt_name;
2637 size = ((mach_msg_type_t*)type)->msgt_size;
2638 number = ((mach_msg_type_t*)type)->msgt_number;
2639 saddr += sizeof(mach_msg_type_t);
2640 }
2641
2642 /* padding (ptrs and ports) ? */
2643 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
2644 ((size >> 3) == sizeof(natural_t)))
2645 saddr = ptr_align(saddr);
2646
2647 /* calculate length of data in bytes, rounding up */
2648
2649 length = ((number * size) + 7) >> 3;
2650
2651 is_port = MACH_MSG_TYPE_PORT_ANY(name);
2652
2653 if (is_port) {
2654 mach_port_t *objects;
2655 mach_msg_type_number_t i;
2656
2657 if (!is_inline && (length != 0)) {
2658 /* first allocate memory in the map */
2659
2660 kr = vm_allocate(map, &addr, length, TRUE);
2661 if (kr != KERN_SUCCESS) {
2662 ipc_kmsg_clean_body(taddr, saddr);
2663 goto vm_copyout_failure;
2664 }
2665 }
2666
2667 objects = (mach_port_t *)
2668 (is_inline ? saddr : * (vm_offset_t *) saddr);
2669
2670 /* copyout port rights carried in the message */
2671
2672 for (i = 0; i < number; i++) {
2673 ipc_object_t object =
2674 (ipc_object_t) objects[i];
2675
2676 mr |= ipc_kmsg_copyout_object(space, object,
2677 name, &objects[i]);
2678 }
2679 }
2680
2681 if (is_inline) {
2682 /* inline data sizes round up to int boundaries */
2683
2684 ((mach_msg_type_t*)type)->msgt_deallocate = FALSE;
2685 saddr += (length + 3) &~ 3;
2686 } else {
2687 vm_offset_t data;
2688
2689 if (sizeof(vm_offset_t) > sizeof(mach_msg_type_t))
2690 saddr = ptr_align(saddr);
2691
2692 data = * (vm_offset_t *) saddr;
2693
2694 /* copyout memory carried in the message */
2695
2696 if (length == 0) {
2697 assert(data == 0);
2698 addr = 0;
2699 } else if (is_port) {
2700 /* copyout to memory allocated above */
2701
2702 (void) copyoutmap(map, (char *) data,
2703 (char *) addr, length);
2704 kfree(data, length);
2705 } else {
2706 vm_map_copy_t copy = (vm_map_copy_t) data;
2707
2708 kr = vm_map_copyout(map, &addr, copy);
2709 if (kr != KERN_SUCCESS) {
2710 vm_map_copy_discard(copy);
2711
2712 vm_copyout_failure:
2713
2714 addr = 0;
2715 if (longform)
2716 type->msgtl_size = 0;
2717 else
2718 ((mach_msg_type_t*)type)->msgt_size = 0;
2719
2720 if (kr == KERN_RESOURCE_SHORTAGE)
2721 mr |= MACH_MSG_VM_KERNEL;
2722 else
2723 mr |= MACH_MSG_VM_SPACE;
2724 }
2725 }
2726
2727 ((mach_msg_type_t*)type)->msgt_deallocate = TRUE;
2728 * (vm_offset_t *) saddr = addr;
2729 saddr += sizeof(vm_offset_t);
2730 }
2731 }
2732
2733 return mr;
2734 }
2735
2736 /*
2737 * Routine: ipc_kmsg_copyout
2738 * Purpose:
2739 * "Copy-out" port rights and out-of-line memory
2740 * in the message.
2741 * Conditions:
2742 * Nothing locked.
2743 * Returns:
2744 * MACH_MSG_SUCCESS Copied out all rights and memory.
2745 * MACH_RCV_INVALID_NOTIFY Bad notify port.
2746 * Rights and memory in the message are intact.
2747 * MACH_RCV_HEADER_ERROR + special bits
2748 * Rights and memory in the message are intact.
2749 * MACH_RCV_BODY_ERROR + special bits
2750 * The message header was successfully copied out.
2751 * As much of the body was handled as possible.
2752 */
2753
2754 mach_msg_return_t
2755 ipc_kmsg_copyout(
2756 ipc_kmsg_t kmsg,
2757 ipc_space_t space,
2758 vm_map_t map,
2759 mach_port_t notify)
2760 {
2761 mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2762 mach_msg_return_t mr;
2763
2764 mr = ipc_kmsg_copyout_header(&kmsg->ikm_header, space, notify);
2765 if (mr != MACH_MSG_SUCCESS)
2766 return mr;
2767
2768 if (mbits & MACH_MSGH_BITS_COMPLEX) {
2769 vm_offset_t saddr, eaddr;
2770
2771 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2772 eaddr = (vm_offset_t) &kmsg->ikm_header +
2773 kmsg->ikm_header.msgh_size;
2774
2775 mr = ipc_kmsg_copyout_body(saddr, eaddr, space, map);
2776 if (mr != MACH_MSG_SUCCESS)
2777 mr |= MACH_RCV_BODY_ERROR;
2778 }
2779
2780 return mr;
2781 }
2782
2783 /*
2784 * Routine: ipc_kmsg_copyout_pseudo
2785 * Purpose:
2786 * Does a pseudo-copyout of the message.
2787 * This is like a regular copyout, except
2788 * that the ports in the header are handled
2789 * as if they are in the body. They aren't reversed.
2790 *
2791 * The error codes are a combination of special bits.
2792 * The copyout proceeds despite errors.
2793 * Conditions:
2794 * Nothing locked.
2795 * Returns:
2796 * MACH_MSG_SUCCESS Successful copyout.
2797 * MACH_MSG_IPC_SPACE No room for port right in name space.
2798 * MACH_MSG_VM_SPACE No room for memory in address space.
2799 * MACH_MSG_IPC_KERNEL Resource shortage handling port right.
2800 * MACH_MSG_VM_KERNEL Resource shortage handling memory.
2801 */
2802
2803 mach_msg_return_t
2804 ipc_kmsg_copyout_pseudo(
2805 ipc_kmsg_t kmsg,
2806 ipc_space_t space,
2807 vm_map_t map)
2808 {
2809 mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2810 ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
2811 ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
2812 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2813 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2814 mach_port_t dest_name, reply_name;
2815 mach_msg_return_t mr;
2816
2817 assert(IO_VALID(dest));
2818
2819 mr = (ipc_kmsg_copyout_object(space, dest, dest_type, &dest_name) |
2820 ipc_kmsg_copyout_object(space, reply, reply_type, &reply_name));
2821
2822 kmsg->ikm_header.msgh_bits = mbits &~ MACH_MSGH_BITS_CIRCULAR;
2823 kmsg->ikm_header.msgh_remote_port = dest_name;
2824 kmsg->ikm_header.msgh_local_port = reply_name;
2825
2826 if (mbits & MACH_MSGH_BITS_COMPLEX) {
2827 vm_offset_t saddr, eaddr;
2828
2829 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2830 eaddr = (vm_offset_t) &kmsg->ikm_header +
2831 kmsg->ikm_header.msgh_size;
2832
2833 mr |= ipc_kmsg_copyout_body(saddr, eaddr, space, map);
2834 }
2835
2836 return mr;
2837 }
2838
2839 /*
2840 * Routine: ipc_kmsg_copyout_dest
2841 * Purpose:
2842 * Copies out the destination port in the message.
2843 * Destroys all other rights and memory in the message.
2844 * Conditions:
2845 * Nothing locked.
2846 */
2847
2848 void
2849 ipc_kmsg_copyout_dest(
2850 ipc_kmsg_t kmsg,
2851 ipc_space_t space)
2852 {
2853 mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2854 ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
2855 ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
2856 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2857 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2858 mach_port_t dest_name, reply_name;
2859
2860 assert(IO_VALID(dest));
2861
2862 io_lock(dest);
2863 if (io_active(dest)) {
2864 ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
2865 /* dest is unlocked */
2866 } else {
2867 io_release(dest);
2868 io_check_unlock(dest);
2869 dest_name = MACH_PORT_DEAD;
2870 }
2871
2872 if (IO_VALID(reply)) {
2873 ipc_object_destroy(reply, reply_type);
2874 reply_name = MACH_PORT_NULL;
2875 } else
2876 reply_name = (mach_port_t) reply;
2877
2878 kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2879 MACH_MSGH_BITS(reply_type, dest_type));
2880 kmsg->ikm_header.msgh_local_port = dest_name;
2881 kmsg->ikm_header.msgh_remote_port = reply_name;
2882
2883 if (mbits & MACH_MSGH_BITS_COMPLEX) {
2884 vm_offset_t saddr, eaddr;
2885
2886 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
2887 eaddr = (vm_offset_t) &kmsg->ikm_header +
2888 kmsg->ikm_header.msgh_size;
2889
2890 ipc_kmsg_clean_body(saddr, eaddr);
2891 }
2892 }
2893
2894 #if NORMA_IPC || NORMA_VM
2895 /*
2896 * Routine: ipc_kmsg_copyout_to_kernel
2897 * Purpose:
2898 * Copies out the destination and reply ports in the message.
2899 * Leaves all other rights and memory in the message alone.
2900 * Conditions:
2901 * Nothing locked.
2902 *
2903 * Derived from ipc_kmsg_copyout_dest.
2904 * Use by mach_msg_rpc_from_kernel (which used to use copyout_dest).
2905 * We really do want to save rights and memory.
2906 */
2907
2908 void
2909 ipc_kmsg_copyout_to_kernel(
2910 ipc_kmsg_t kmsg,
2911 ipc_space_t space)
2912 {
2913 mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
2914 ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
2915 ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
2916 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
2917 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
2918 mach_port_t dest_name, reply_name;
2919
2920 assert(IO_VALID(dest));
2921
2922 io_lock(dest);
2923 if (io_active(dest)) {
2924 ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
2925 /* dest is unlocked */
2926 } else {
2927 io_release(dest);
2928 io_check_unlock(dest);
2929 dest_name = MACH_PORT_DEAD;
2930 }
2931
2932 reply_name = (mach_port_t) reply;
2933
2934 kmsg->ikm_header.msgh_bits = (MACH_MSGH_BITS_OTHER(mbits) |
2935 MACH_MSGH_BITS(reply_type, dest_type));
2936 kmsg->ikm_header.msgh_local_port = dest_name;
2937 kmsg->ikm_header.msgh_remote_port = reply_name;
2938 }
2939 #endif /* NORMA_IPC || NORMA_VM */
2940
2941 #if MACH_IPC_COMPAT
2942
2943 /*
2944 * Routine: ipc_kmsg_copyin_compat
2945 * Purpose:
2946 * "Copy-in" port rights and out-of-line memory
2947 * in the message.
2948 *
2949 * In all failure cases, the message is left holding
2950 * no rights or memory. However, the message buffer
2951 * is not deallocated. If successful, the message
2952 * contains a valid destination port.
2953 * Conditions:
2954 * Nothing locked.
2955 * Returns:
2956 * MACH_MSG_SUCCESS Successful copyin.
2957 * MACH_SEND_INVALID_DEST Can't copyin destination port.
2958 * MACH_SEND_INVALID_REPLY Can't copyin reply port.
2959 * MACH_SEND_INVALID_MEMORY Can't grab out-of-line memory.
2960 * MACH_SEND_INVALID_RIGHT Can't copyin port right in body.
2961 * MACH_SEND_INVALID_TYPE Bad type specification.
2962 * MACH_SEND_MSG_TOO_SMALL Body is too small for types/data.
2963 */
2964
2965 mach_msg_return_t
2966 ipc_kmsg_copyin_compat(
2967 ipc_kmsg_t kmsg,
2968 ipc_space_t space,
2969 vm_map_t map)
2970 {
2971 msg_header_t msg;
2972 mach_port_t dest_name;
2973 mach_port_t reply_name;
2974 ipc_object_t dest, reply;
2975 mach_msg_type_name_t dest_type, reply_type;
2976 vm_offset_t saddr, eaddr;
2977 boolean_t complex;
2978 kern_return_t kr;
2979 boolean_t use_page_lists, steal_pages;
2980
2981 msg = * (msg_header_t *) &kmsg->ikm_header;
2982 dest_name = (mach_port_t) msg.msg_remote_port;
2983 reply_name = (mach_port_t) msg.msg_local_port;
2984
2985 /* translate the destination and reply ports */
2986
2987 kr = ipc_object_copyin_header(space, dest_name, &dest, &dest_type);
2988 if (kr != KERN_SUCCESS)
2989 return MACH_SEND_INVALID_DEST;
2990
2991 if (reply_name == MACH_PORT_NULL) {
2992 reply = IO_NULL;
2993 reply_type = 0;
2994 } else {
2995 kr = ipc_object_copyin_header(space, reply_name,
2996 &reply, &reply_type);
2997 if (kr != KERN_SUCCESS) {
2998 ipc_object_destroy(dest, dest_type);
2999 return MACH_SEND_INVALID_REPLY;
3000 }
3001 }
3002
3003 kmsg->ikm_header.msgh_bits = MACH_MSGH_BITS(dest_type, reply_type);
3004 kmsg->ikm_header.msgh_size = (mach_msg_size_t) msg.msg_size;
3005 kmsg->ikm_header.msgh_remote_port = (mach_port_t) dest;
3006 kmsg->ikm_header.msgh_local_port = (mach_port_t) reply;
3007 kmsg->ikm_header.msgh_seqno = (mach_msg_kind_t) msg.msg_type;
3008 kmsg->ikm_header.msgh_id = (mach_msg_id_t) msg.msg_id;
3009
3010 if (msg.msg_simple)
3011 return MACH_MSG_SUCCESS;
3012
3013 complex = FALSE;
3014 use_page_lists = ipc_kobject_vm_page_list(ip_kotype((ipc_port_t)dest));
3015 steal_pages = ipc_kobject_vm_page_steal(ip_kotype((ipc_port_t)dest));
3016
3017 #if NORMA_IPC
3018 if (IP_NORMA_IS_PROXY((ipc_port_t) dest)) {
3019 use_page_lists = TRUE;
3020 steal_pages = TRUE;
3021 }
3022 #endif /* NORMA_IPC */
3023
3024 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
3025 eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
3026
3027 while (saddr < eaddr) {
3028 vm_offset_t taddr = saddr;
3029 mach_msg_type_long_t *type;
3030 mach_msg_type_name_t name;
3031 mach_msg_type_size_t size;
3032 mach_msg_type_number_t number;
3033 boolean_t is_inline, longform, dealloc, is_port;
3034 vm_offset_t data;
3035 vm_size_t length;
3036
3037 type = (mach_msg_type_long_t *) saddr;
3038
3039 if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
3040 ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
3041 ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
3042 ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
3043 return MACH_SEND_MSG_TOO_SMALL;
3044 }
3045
3046 is_inline = ((mach_msg_type_t*)type)->msgt_inline;
3047 dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
3048 if (longform) {
3049 /* This must be aligned */
3050 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3051 (is_misaligned(type))) {
3052 saddr = ptr_align(saddr);
3053 continue;
3054 }
3055 name = type->msgtl_name;
3056 size = type->msgtl_size;
3057 number = type->msgtl_number;
3058 saddr += sizeof(mach_msg_type_long_t);
3059 } else {
3060 name = ((mach_msg_type_t*)type)->msgt_name;
3061 size = ((mach_msg_type_t*)type)->msgt_size;
3062 number = ((mach_msg_type_t*)type)->msgt_number;
3063 saddr += sizeof(mach_msg_type_t);
3064 }
3065
3066 is_port = MSG_TYPE_PORT_ANY(name);
3067
3068 if (is_port && (size != PORT_T_SIZE_IN_BITS)) {
3069 ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
3070 return MACH_SEND_INVALID_TYPE;
3071 }
3072
3073 /*
3074 * New IPC says these should be zero, but old IPC
3075 * tasks often leave them with random values. So
3076 * we have to clear them.
3077 */
3078
3079 ((mach_msg_type_t*)type)->msgt_unused = 0;
3080 if (longform) {
3081 type->msgtl_header.msgt_name = 0;
3082 type->msgtl_header.msgt_size = 0;
3083 type->msgtl_header.msgt_number = 0;
3084 }
3085
3086 /* padding (ptrs and ports) ? */
3087 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3088 ((size >> 3) == sizeof(natural_t)))
3089 saddr = ptr_align(saddr);
3090
3091 /* calculate length of data in bytes, rounding up */
3092
3093 length = ((number * size) + 7) >> 3;
3094
3095 if (is_inline) {
3096 vm_size_t amount;
3097
3098 /* inline data sizes round up to int boundaries */
3099
3100 amount = (length + 3) &~ 3;
3101 if ((eaddr - saddr) < amount) {
3102 ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
3103 return MACH_SEND_MSG_TOO_SMALL;
3104 }
3105
3106 data = saddr;
3107 saddr += amount;
3108 } else {
3109 vm_offset_t addr;
3110
3111 if ((eaddr - saddr) < sizeof(vm_offset_t)) {
3112 ipc_kmsg_clean_partial(kmsg, taddr, FALSE, 0);
3113 return MACH_SEND_MSG_TOO_SMALL;
3114 }
3115
3116 /* grab the out-of-line data */
3117
3118 addr = * (vm_offset_t *) saddr;
3119
3120 if (length == 0)
3121 data = 0;
3122 else if (is_port) {
3123 data = kalloc(length);
3124 if (data == 0)
3125 goto invalid_memory;
3126
3127 if (copyinmap(map, (char *) addr,
3128 (char *) data, length) ||
3129 (dealloc &&
3130 (vm_deallocate(map, addr, length) !=
3131 KERN_SUCCESS))) {
3132 kfree(data, length);
3133 goto invalid_memory;
3134 }
3135 } else {
3136 vm_map_copy_t copy;
3137
3138 if (use_page_lists) {
3139 kr = vm_map_copyin_page_list(map,
3140 addr, length, dealloc,
3141 steal_pages, ©, FALSE);
3142 } else {
3143 kr = vm_map_copyin(map, addr, length,
3144 dealloc,
3145 ©);
3146 }
3147 if (kr != KERN_SUCCESS) {
3148 invalid_memory:
3149 ipc_kmsg_clean_partial(kmsg, taddr,
3150 FALSE, 0);
3151 return MACH_SEND_INVALID_MEMORY;
3152 }
3153
3154 data = (vm_offset_t) copy;
3155 }
3156
3157 * (vm_offset_t *) saddr = data;
3158 saddr += sizeof(vm_offset_t);
3159 complex = TRUE;
3160 }
3161
3162 if (is_port) {
3163 mach_msg_type_name_t newname =
3164 ipc_object_copyin_type(name);
3165 ipc_object_t *objects = (ipc_object_t *) data;
3166 mach_msg_type_number_t i;
3167
3168 if (longform)
3169 type->msgtl_name = newname;
3170 else
3171 ((mach_msg_type_t*)type)->msgt_name = newname;
3172
3173 for (i = 0; i < number; i++) {
3174 mach_port_t port = (mach_port_t) objects[i];
3175 ipc_object_t object;
3176
3177 if (!MACH_PORT_VALID(port))
3178 continue;
3179
3180 kr = ipc_object_copyin_compat(space, port,
3181 name, dealloc, &object);
3182 if (kr != KERN_SUCCESS) {
3183 ipc_kmsg_clean_partial(kmsg, taddr,
3184 TRUE, i);
3185 return MACH_SEND_INVALID_RIGHT;
3186 }
3187
3188 if ((newname == MACH_MSG_TYPE_PORT_RECEIVE) &&
3189 ipc_port_check_circularity(
3190 (ipc_port_t) object,
3191 (ipc_port_t) dest))
3192 kmsg->ikm_header.msgh_bits |=
3193 MACH_MSGH_BITS_CIRCULAR;
3194
3195 objects[i] = object;
3196 }
3197
3198 complex = TRUE;
3199 }
3200 }
3201
3202 if (complex)
3203 kmsg->ikm_header.msgh_bits |= MACH_MSGH_BITS_COMPLEX;
3204
3205 return MACH_MSG_SUCCESS;
3206 }
3207
3208 /*
3209 * Routine: ipc_kmsg_copyout_compat
3210 * Purpose:
3211 * "Copy-out" port rights and out-of-line memory
3212 * in the message, producing an old IPC message.
3213 *
3214 * Doesn't bother to handle the header atomically.
3215 * Skips over errors. Problem ports produce MACH_PORT_NULL
3216 * (MACH_PORT_DEAD is never produced), and problem memory
3217 * produces a zero address.
3218 * Conditions:
3219 * Nothing locked.
3220 * Returns:
3221 * MACH_MSG_SUCCESS Copied out rights and memory.
3222 */
3223
3224 mach_msg_return_t
3225 ipc_kmsg_copyout_compat(
3226 ipc_kmsg_t kmsg,
3227 ipc_space_t space,
3228 vm_map_t map)
3229 {
3230 msg_header_t msg;
3231 mach_msg_bits_t mbits = kmsg->ikm_header.msgh_bits;
3232 ipc_object_t dest = (ipc_object_t) kmsg->ikm_header.msgh_remote_port;
3233 ipc_object_t reply = (ipc_object_t) kmsg->ikm_header.msgh_local_port;
3234 mach_port_t dest_name, reply_name;
3235 vm_offset_t saddr, eaddr;
3236 kern_return_t kr;
3237
3238 assert(IO_VALID(dest));
3239
3240 io_lock(dest);
3241 if (io_active(dest)) {
3242 mach_msg_type_name_t dest_type = MACH_MSGH_BITS_REMOTE(mbits);
3243
3244 ipc_object_copyout_dest(space, dest, dest_type, &dest_name);
3245 /* dest is unlocked */
3246 } else {
3247 io_release(dest);
3248 io_check_unlock(dest);
3249 dest_name = MACH_PORT_NULL;
3250 }
3251
3252 if (IO_VALID(reply)) {
3253 mach_msg_type_name_t reply_type = MACH_MSGH_BITS_LOCAL(mbits);
3254
3255 kr = ipc_object_copyout_compat(space, reply, reply_type,
3256 &reply_name);
3257 if (kr != KERN_SUCCESS) {
3258 ipc_object_destroy(reply, reply_type);
3259 reply_name = MACH_PORT_NULL;
3260 }
3261 } else
3262 reply_name = MACH_PORT_NULL;
3263
3264 msg.msg_unused = 0;
3265 msg.msg_simple = (mbits & MACH_MSGH_BITS_COMPLEX) ? FALSE : TRUE;
3266 msg.msg_size = (msg_size_t) kmsg->ikm_header.msgh_size;
3267 msg.msg_type = (integer_t) kmsg->ikm_header.msgh_seqno;
3268 msg.msg_local_port = (port_name_t) dest_name;
3269 msg.msg_remote_port = (port_name_t) reply_name;
3270 msg.msg_id = (integer_t) kmsg->ikm_header.msgh_id;
3271 * (msg_header_t *) &kmsg->ikm_header = msg;
3272
3273 if (msg.msg_simple)
3274 return MACH_MSG_SUCCESS;
3275
3276 saddr = (vm_offset_t) (&kmsg->ikm_header + 1);
3277 eaddr = (vm_offset_t) &kmsg->ikm_header + kmsg->ikm_header.msgh_size;
3278
3279 while (saddr < eaddr) {
3280 vm_offset_t taddr = saddr;
3281 mach_msg_type_long_t *type;
3282 mach_msg_type_name_t name;
3283 mach_msg_type_size_t size;
3284 mach_msg_type_number_t number;
3285 boolean_t is_inline, longform, is_port;
3286 vm_size_t length;
3287 vm_offset_t addr;
3288
3289 type = (mach_msg_type_long_t *) saddr;
3290 is_inline = ((mach_msg_type_t*)type)->msgt_inline;
3291 longform = ((mach_msg_type_t*)type)->msgt_longform;
3292 if (longform) {
3293 /* This must be aligned */
3294 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3295 (is_misaligned(type))) {
3296 saddr = ptr_align(saddr);
3297 continue;
3298 }
3299 name = type->msgtl_name;
3300 size = type->msgtl_size;
3301 number = type->msgtl_number;
3302 saddr += sizeof(mach_msg_type_long_t);
3303 } else {
3304 name = ((mach_msg_type_t*)type)->msgt_name;
3305 size = ((mach_msg_type_t*)type)->msgt_size;
3306 number = ((mach_msg_type_t*)type)->msgt_number;
3307 saddr += sizeof(mach_msg_type_t);
3308 }
3309
3310 /* padding (ptrs and ports) ? */
3311 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3312 ((size >> 3) == sizeof(natural_t)))
3313 saddr = ptr_align(saddr);
3314
3315 /* calculate length of data in bytes, rounding up */
3316
3317 length = ((number * size) + 7) >> 3;
3318
3319 is_port = MACH_MSG_TYPE_PORT_ANY(name);
3320
3321 if (is_port) {
3322 mach_port_t *objects;
3323 mach_msg_type_number_t i;
3324 mach_msg_type_name_t newname;
3325
3326 if (!is_inline && (length != 0)) {
3327 /* first allocate memory in the map */
3328
3329 kr = vm_allocate(map, &addr, length, TRUE);
3330 if (kr != KERN_SUCCESS) {
3331 ipc_kmsg_clean_body(taddr, saddr);
3332 goto vm_copyout_failure;
3333 }
3334 }
3335
3336 newname = ipc_object_copyout_type_compat(name);
3337 if (longform)
3338 type->msgtl_name = newname;
3339 else
3340 ((mach_msg_type_t*)type)->msgt_name = newname;
3341
3342 objects = (mach_port_t *)
3343 (is_inline ? saddr : * (vm_offset_t *) saddr);
3344
3345 /* copyout port rights carried in the message */
3346
3347 for (i = 0; i < number; i++) {
3348 ipc_object_t object =
3349 (ipc_object_t) objects[i];
3350
3351 if (!IO_VALID(object)) {
3352 objects[i] = MACH_PORT_NULL;
3353 continue;
3354 }
3355
3356 kr = ipc_object_copyout_compat(space, object,
3357 name, &objects[i]);
3358 if (kr != KERN_SUCCESS) {
3359 ipc_object_destroy(object, name);
3360 objects[i] = MACH_PORT_NULL;
3361 }
3362 }
3363 }
3364
3365 if (is_inline) {
3366 /* inline data sizes round up to int boundaries */
3367
3368 saddr += (length + 3) &~ 3;
3369 } else {
3370 vm_offset_t data = * (vm_offset_t *) saddr;
3371
3372 /* copyout memory carried in the message */
3373
3374 if (length == 0) {
3375 assert(data == 0);
3376 addr = 0;
3377 } else if (is_port) {
3378 /* copyout to memory allocated above */
3379
3380 (void) copyoutmap(map, (char *) data,
3381 (char *) addr, length);
3382 kfree(data, length);
3383 } else {
3384 vm_map_copy_t copy = (vm_map_copy_t) data;
3385
3386 kr = vm_map_copyout(map, &addr, copy);
3387 if (kr != KERN_SUCCESS) {
3388 vm_map_copy_discard(copy);
3389
3390 vm_copyout_failure:
3391
3392 addr = 0;
3393 }
3394 }
3395
3396 * (vm_offset_t *) saddr = addr;
3397 saddr += sizeof(vm_offset_t);
3398 }
3399 }
3400
3401 return MACH_MSG_SUCCESS;
3402 }
3403
3404 #endif /* MACH_IPC_COMPAT */
3405
3406 #include <mach_kdb.h>
3407 #if MACH_KDB
3408 #include <ddb/db_output.h> /* db_printf */
3409
3410 char *
3411 ipc_type_name(
3412 int type_name,
3413 boolean_t received)
3414 {
3415 switch (type_name) {
3416 case MACH_MSG_TYPE_BOOLEAN:
3417 return "boolean";
3418
3419 case MACH_MSG_TYPE_INTEGER_16:
3420 return "short";
3421
3422 case MACH_MSG_TYPE_INTEGER_32:
3423 return "int32";
3424
3425 case MACH_MSG_TYPE_INTEGER_64:
3426 return "int64";
3427
3428 case MACH_MSG_TYPE_CHAR:
3429 return "char";
3430
3431 case MACH_MSG_TYPE_BYTE:
3432 return "byte";
3433
3434 case MACH_MSG_TYPE_REAL:
3435 return "real";
3436
3437 case MACH_MSG_TYPE_STRING:
3438 return "string";
3439
3440 case MACH_MSG_TYPE_PORT_NAME:
3441 return "port_name";
3442
3443 case MACH_MSG_TYPE_MOVE_RECEIVE:
3444 if (received) {
3445 return "port_receive";
3446 } else {
3447 return "move_receive";
3448 }
3449
3450 case MACH_MSG_TYPE_MOVE_SEND:
3451 if (received) {
3452 return "port_send";
3453 } else {
3454 return "move_send";
3455 }
3456
3457 case MACH_MSG_TYPE_MOVE_SEND_ONCE:
3458 if (received) {
3459 return "port_send_once";
3460 } else {
3461 return "move_send_once";
3462 }
3463
3464 case MACH_MSG_TYPE_COPY_SEND:
3465 return "copy_send";
3466
3467 case MACH_MSG_TYPE_MAKE_SEND:
3468 return "make_send";
3469
3470 case MACH_MSG_TYPE_MAKE_SEND_ONCE:
3471 return "make_send_once";
3472
3473 default:
3474 return (char *) 0;
3475 }
3476 }
3477
3478 void
3479 ipc_print_type_name(
3480 int type_name)
3481 {
3482 char *name = ipc_type_name(type_name, TRUE);
3483 if (name) {
3484 db_printf("%s", name);
3485 } else {
3486 db_printf("type%d", type_name);
3487 }
3488 }
3489
3490 /*
3491 * ipc_kmsg_print [ debug ]
3492 */
3493 void
3494 ipc_kmsg_print(
3495 ipc_kmsg_t kmsg)
3496 {
3497 db_printf("kmsg=0x%x\n", kmsg);
3498 db_printf("ikm_next=0x%x,prev=0x%x,size=%d,marequest=0x%x",
3499 kmsg->ikm_next,
3500 kmsg->ikm_prev,
3501 kmsg->ikm_size,
3502 kmsg->ikm_marequest);
3503 #if NORMA_IPC
3504 db_printf(",page=0x%x,copy=0x%x\n",
3505 kmsg->ikm_page,
3506 kmsg->ikm_copy);
3507 #else /* NORMA_IPC */
3508 db_printf("\n");
3509 #endif /* NORMA_IPC */
3510 ipc_msg_print(&kmsg->ikm_header);
3511 }
3512
3513 /*
3514 * ipc_msg_print [ debug ]
3515 */
3516 void
3517 ipc_msg_print(
3518 mach_msg_header_t *msgh)
3519 {
3520 vm_offset_t saddr, eaddr;
3521
3522 db_printf("msgh_bits=0x%x: ", msgh->msgh_bits);
3523 if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
3524 db_printf("complex,");
3525 }
3526 if (msgh->msgh_bits & MACH_MSGH_BITS_CIRCULAR) {
3527 db_printf("circular,");
3528 }
3529 if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_PORTS) {
3530 db_printf("complex_ports,");
3531 }
3532 if (msgh->msgh_bits & MACH_MSGH_BITS_COMPLEX_DATA) {
3533 db_printf("complex_data,");
3534 }
3535 if (msgh->msgh_bits & MACH_MSGH_BITS_MIGRATED) {
3536 db_printf("migrated,");
3537 }
3538 if (msgh->msgh_bits & MACH_MSGH_BITS_UNUSED) {
3539 db_printf("unused=0x%x,",
3540 msgh->msgh_bits & MACH_MSGH_BITS_UNUSED);
3541 }
3542 db_printf("l=0x%x,r=0x%x\n",
3543 MACH_MSGH_BITS_LOCAL(msgh->msgh_bits),
3544 MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
3545
3546 db_printf("msgh_id=%d,size=%d,seqno=%d,",
3547 msgh->msgh_id,
3548 msgh->msgh_size,
3549 msgh->msgh_seqno);
3550
3551 if (msgh->msgh_remote_port) {
3552 db_printf("remote=0x%x(", msgh->msgh_remote_port);
3553 ipc_print_type_name(MACH_MSGH_BITS_REMOTE(msgh->msgh_bits));
3554 db_printf("),");
3555 } else {
3556 db_printf("remote=null,\n");
3557 }
3558
3559 if (msgh->msgh_local_port) {
3560 db_printf("local=0x%x(", msgh->msgh_local_port);
3561 ipc_print_type_name(MACH_MSGH_BITS_LOCAL(msgh->msgh_bits));
3562 db_printf(")\n");
3563 } else {
3564 db_printf("local=null\n");
3565 }
3566
3567 saddr = (vm_offset_t) (msgh + 1);
3568 eaddr = (vm_offset_t) msgh + msgh->msgh_size;
3569
3570 while (saddr < eaddr) {
3571 mach_msg_type_long_t *type;
3572 mach_msg_type_name_t name;
3573 mach_msg_type_size_t size;
3574 mach_msg_type_number_t number;
3575 boolean_t is_inline, longform, dealloc, is_port;
3576 vm_size_t length;
3577
3578 type = (mach_msg_type_long_t *) saddr;
3579
3580 if (((eaddr - saddr) < sizeof(mach_msg_type_t)) ||
3581 ((longform = ((mach_msg_type_t*)type)->msgt_longform) &&
3582 ((eaddr - saddr) < sizeof(mach_msg_type_long_t)))) {
3583 db_printf("*** msg too small\n");
3584 return;
3585 }
3586
3587 is_inline = ((mach_msg_type_t*)type)->msgt_inline;
3588 dealloc = ((mach_msg_type_t*)type)->msgt_deallocate;
3589 if (longform) {
3590 /* This must be aligned */
3591 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3592 (is_misaligned(type))) {
3593 saddr = ptr_align(saddr);
3594 continue;
3595 }
3596 name = type->msgtl_name;
3597 size = type->msgtl_size;
3598 number = type->msgtl_number;
3599 saddr += sizeof(mach_msg_type_long_t);
3600 } else {
3601 name = ((mach_msg_type_t*)type)->msgt_name;
3602 size = ((mach_msg_type_t*)type)->msgt_size;
3603 number = ((mach_msg_type_t*)type)->msgt_number;
3604 saddr += sizeof(mach_msg_type_t);
3605 }
3606
3607 db_printf("-- type=");
3608 ipc_print_type_name(name);
3609 if (! is_inline) {
3610 db_printf(",ool");
3611 }
3612 if (dealloc) {
3613 db_printf(",dealloc");
3614 }
3615 if (longform) {
3616 db_printf(",longform");
3617 }
3618 db_printf(",size=%d,number=%d,addr=0x%x\n",
3619 size,
3620 number,
3621 saddr);
3622
3623 is_port = MACH_MSG_TYPE_PORT_ANY(name);
3624
3625 if ((is_port && (size != PORT_T_SIZE_IN_BITS)) ||
3626 (longform && ((type->msgtl_header.msgt_name != 0) ||
3627 (type->msgtl_header.msgt_size != 0) ||
3628 (type->msgtl_header.msgt_number != 0))) ||
3629 (((mach_msg_type_t*)type)->msgt_unused != 0) ||
3630 (dealloc && is_inline)) {
3631 db_printf("*** invalid type\n");
3632 return;
3633 }
3634
3635 /* padding (ptrs and ports) ? */
3636 if ((sizeof(natural_t) > sizeof(mach_msg_type_t)) &&
3637 ((size >> 3) == sizeof(natural_t)))
3638 saddr = ptr_align(saddr);
3639
3640 /* calculate length of data in bytes, rounding up */
3641
3642 length = ((number * size) + 7) >> 3;
3643
3644 if (is_inline) {
3645 vm_size_t amount;
3646 int i, numwords;
3647
3648 /* inline data sizes round up to int boundaries */
3649 amount = (length + 3) &~ 3;
3650 if ((eaddr - saddr) < amount) {
3651 db_printf("*** too small\n");
3652 return;
3653 }
3654 numwords = amount / sizeof(int);
3655 if (numwords > 8) {
3656 numwords = 8;
3657 }
3658 for (i = 0; i < numwords; i++) {
3659 db_printf("0x%x\n", ((int *) saddr)[i]);
3660 }
3661 if (numwords < amount / sizeof(int)) {
3662 db_printf("...\n");
3663 }
3664 saddr += amount;
3665 } else {
3666 if ((eaddr - saddr) < sizeof(vm_offset_t)) {
3667 db_printf("*** too small\n");
3668 return;
3669 }
3670 db_printf("0x%x\n", * (vm_offset_t *) saddr);
3671 saddr += sizeof(vm_offset_t);
3672 }
3673 }
3674 }
3675 #endif /* MACH_KDB */
Cache object: 40b9017f034dda541b545d0b58715b72
|