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