xref: /xnu-10063.121.3/osfmk/kern/ipc_mig.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
1 /*
2  * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_COPYRIGHT@
30  */
31 /*
32  * Mach Operating System
33  * Copyright (c) 1991,1990 Carnegie Mellon University
34  * All Rights Reserved.
35  *
36  * Permission to use, copy, modify and distribute this software and its
37  * documentation is hereby granted, provided that both the copyright
38  * notice and this permission notice appear in all copies of the
39  * software, derivative works or modified versions, and any portions
40  * thereof, and that both notices appear in supporting documentation.
41  *
42  * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS"
43  * CONDITION.  CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR
44  * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
45  *
46  * Carnegie Mellon requests users of this software to return to
47  *
48  *  Software Distribution Coordinator  or  [email protected]
49  *  School of Computer Science
50  *  Carnegie Mellon University
51  *  Pittsburgh PA 15213-3890
52  *
53  * any improvements or extensions that they make and grant Carnegie Mellon
54  * the rights to redistribute these changes.
55  */
56 /*
57  */
58 
59 #include <mach/boolean.h>
60 #include <mach/port.h>
61 #include <mach/mig.h>
62 #include <mach/mig_errors.h>
63 #include <mach/mach_types.h>
64 #include <mach/mach_traps.h>
65 
66 #include <kern/ipc_tt.h>
67 #include <kern/ipc_mig.h>
68 #include <kern/kalloc.h>
69 #include <kern/task.h>
70 #include <kern/thread.h>
71 #include <kern/ipc_kobject.h>
72 #include <kern/misc_protos.h>
73 
74 #include <ipc/port.h>
75 #include <ipc/ipc_kmsg.h>
76 #include <ipc/ipc_entry.h>
77 #include <ipc/ipc_object.h>
78 #include <ipc/ipc_mqueue.h>
79 #include <ipc/ipc_space.h>
80 #include <ipc/ipc_port.h>
81 #include <ipc/ipc_pset.h>
82 #include <ipc/ipc_notify.h>
83 #include <vm/vm_map.h>
84 #include <mach/thread_act.h>
85 
86 #include <libkern/OSAtomic.h>
87 
88 #define KERNEL_DESC_SIZE             sizeof(mach_msg_descriptor_t)
89 
90 void
91 mach_msg_receive_results_complete(ipc_object_t object);
92 
93 /*
94  *	Routine:	mach_msg_send_from_kernel
95  *	Purpose:
96  *		Send a message from the kernel.
97  *
98  *		This is used by the client side of KernelUser interfaces
99  *		to implement SimpleRoutines.  Currently, this includes
100  *		memory_object messages.
101  *	Conditions:
102  *		Nothing locked.
103  *	Returns:
104  *		MACH_MSG_SUCCESS	Sent the message.
105  *		MACH_SEND_INVALID_DEST	Bad destination port.
106  *		MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer
107  *		                        or destination is above kernel limit
108  */
109 
110 mach_msg_return_t
mach_msg_send_from_kernel_proper(mach_msg_header_t * msg,mach_msg_size_t send_size)111 mach_msg_send_from_kernel_proper(
112 	mach_msg_header_t       *msg,
113 	mach_msg_size_t         send_size)
114 {
115 	mach_msg_option_t   option = MACH_SEND_KERNEL_DEFAULT;
116 	mach_msg_timeout_t  timeout_val = MACH_MSG_TIMEOUT_NONE;
117 	return kernel_mach_msg_send(msg, send_size, option, timeout_val, NULL);
118 }
119 
120 mach_msg_return_t
mach_msg_send_from_kernel_with_options(mach_msg_header_t * msg,mach_msg_size_t send_size,mach_msg_option_t option,mach_msg_timeout_t timeout_val)121 mach_msg_send_from_kernel_with_options(
122 	mach_msg_header_t       *msg,
123 	mach_msg_size_t         send_size,
124 	mach_msg_option_t       option,
125 	mach_msg_timeout_t      timeout_val)
126 {
127 	return kernel_mach_msg_send(msg, send_size, option, timeout_val, NULL);
128 }
129 
130 static mach_msg_return_t
kernel_mach_msg_send_common(ipc_kmsg_t kmsg,mach_msg_option_t option,mach_msg_timeout_t timeout_val,boolean_t * message_moved)131 kernel_mach_msg_send_common(
132 	ipc_kmsg_t              kmsg,
133 	mach_msg_option_t       option,
134 	mach_msg_timeout_t      timeout_val,
135 	boolean_t               *message_moved)
136 {
137 	mach_msg_return_t mr;
138 
139 	mr = ipc_kmsg_copyin_from_kernel(kmsg);
140 	if (mr != MACH_MSG_SUCCESS) {
141 		ipc_kmsg_free(kmsg);
142 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
143 		return mr;
144 	}
145 
146 	if (message_moved) {
147 		*message_moved = TRUE;
148 	}
149 
150 	/*
151 	 * Until we are sure of its effects, we are disabling
152 	 * importance donation from the kernel-side of user
153 	 * threads in importance-donating tasks - unless the
154 	 * option to force importance donation is passed in,
155 	 * or the thread's SEND_IMPORTANCE option has been set.
156 	 * (11938665 & 23925818)
157 	 */
158 	if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) {
159 		option &= ~MACH_SEND_NOIMPORTANCE;
160 	} else if ((option & MACH_SEND_IMPORTANCE) == 0) {
161 		option |= MACH_SEND_NOIMPORTANCE;
162 	}
163 
164 	mr = ipc_kmsg_send(kmsg, option, timeout_val);
165 
166 	if (mr != MACH_MSG_SUCCESS) {
167 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
168 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
169 	}
170 
171 	return mr;
172 }
173 
174 mach_msg_return_t
kernel_mach_msg_send(mach_msg_header_t * msg,mach_msg_size_t send_size,mach_msg_option_t option,mach_msg_timeout_t timeout_val,boolean_t * message_moved)175 kernel_mach_msg_send(
176 	mach_msg_header_t       *msg,
177 	mach_msg_size_t         send_size,
178 	mach_msg_option_t       option,
179 	mach_msg_timeout_t      timeout_val,
180 	boolean_t               *message_moved)
181 {
182 	ipc_kmsg_t kmsg;
183 	mach_msg_return_t mr;
184 
185 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
186 
187 	if (message_moved) {
188 		*message_moved = FALSE;
189 	}
190 
191 	mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
192 	if (mr != MACH_MSG_SUCCESS) {
193 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
194 		return mr;
195 	}
196 
197 	return kernel_mach_msg_send_common(kmsg, option, timeout_val, message_moved);
198 }
199 
200 mach_msg_return_t
201 kernel_mach_msg_send_with_builder_internal(
202 	mach_msg_size_t         desc_count,
203 	mach_msg_size_t         payload_size, /* Not total send size */
204 	mach_msg_option_t       option,
205 	mach_msg_timeout_t      timeout_val,
206 	boolean_t               *message_moved,
207 	void                    (^builder)(mach_msg_header_t *,
208 	mach_msg_descriptor_t *, void *))
209 {
210 	ipc_kmsg_t kmsg;
211 	mach_msg_return_t mr;
212 	mach_msg_header_t *hdr;
213 	void *udata;
214 	bool complex;
215 	mach_msg_size_t send_size;
216 	mach_msg_descriptor_t *desc;
217 
218 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
219 
220 	/*
221 	 * If message has descriptors it must be complex and vice versa. We assume
222 	 * this for messages originated from kernel. The two are not equivalent for
223 	 * user messages for bin-compat reasons.
224 	 */
225 	complex = (desc_count > 0);
226 	send_size = sizeof(mach_msg_header_t) + payload_size;
227 
228 	if (complex) {
229 		send_size += sizeof(mach_msg_body_t) + desc_count * KERNEL_DESC_SIZE;
230 	}
231 	if (message_moved) {
232 		*message_moved = FALSE;
233 	}
234 
235 	kmsg = ipc_kmsg_alloc(send_size, 0, desc_count,
236 	    IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_ZERO);
237 	/* kmsg can be non-linear */
238 
239 	if (kmsg == IKM_NULL) {
240 		mr = MACH_SEND_NO_BUFFER;
241 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
242 		return mr;
243 	}
244 
245 	hdr = ikm_header(kmsg);
246 	udata = (payload_size > 0) ? ikm_udata(kmsg, desc_count, complex) : NULL;
247 	desc = (desc_count > 0) ? (mach_msg_descriptor_t *)((vm_address_t)hdr + sizeof(mach_msg_base_t)) : NULL;
248 
249 	/* Allow the caller to build the message, and sanity check it */
250 	builder(hdr, desc, udata);
251 	assert(hdr->msgh_size == send_size);
252 	if (complex) {
253 		assert(hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX);
254 		hdr->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
255 		/* Set the correct descriptor count */
256 		((mach_msg_base_t *)hdr)->body.msgh_descriptor_count = desc_count;
257 	} else {
258 		assert(!(hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX));
259 		hdr->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
260 	}
261 
262 	return kernel_mach_msg_send_common(kmsg, option, timeout_val, NULL);
263 }
264 
265 mach_msg_return_t
266 kernel_mach_msg_send_with_builder(
267 	mach_msg_size_t         desc_count,
268 	mach_msg_size_t         udata_size,
269 	void                    (^builder)(mach_msg_header_t *,
270 	mach_msg_descriptor_t *, void *))
271 {
272 	return kernel_mach_msg_send_with_builder_internal(desc_count, udata_size,
273 	           MACH_SEND_KERNEL_DEFAULT, MACH_MSG_TIMEOUT_NONE, NULL, builder);
274 }
275 
276 /*
277  *	Routine:	mach_msg_rpc_from_kernel
278  *	Purpose:
279  *		Send a message from the kernel and receive a reply.
280  *		Uses ith_rpc_reply for the reply port.
281  *
282  *		This is used by the client side of KernelUser interfaces
283  *		to implement Routines.
284  *	Conditions:
285  *		Nothing locked.
286  *	Returns:
287  *		MACH_MSG_SUCCESS	Sent the message.
288  *		MACH_RCV_PORT_DIED	The reply port was deallocated.
289  */
290 
291 mach_msg_return_t
mach_msg_rpc_from_kernel_proper(mach_msg_header_t * msg,mach_msg_size_t send_size,mach_msg_size_t rcv_size)292 mach_msg_rpc_from_kernel_proper(
293 	mach_msg_header_t       *msg,
294 	mach_msg_size_t         send_size,
295 	mach_msg_size_t         rcv_size)
296 {
297 	return kernel_mach_msg_rpc(msg, send_size, rcv_size, TRUE, NULL);
298 }
299 
300 mach_msg_return_t
kernel_mach_msg_rpc(mach_msg_header_t * msg,mach_msg_size_t send_size,mach_msg_size_t rcv_size,boolean_t interruptible,boolean_t * message_moved)301 kernel_mach_msg_rpc(
302 	mach_msg_header_t       *msg,
303 	mach_msg_size_t         send_size,
304 	mach_msg_size_t         rcv_size,
305 	boolean_t               interruptible,
306 	boolean_t               *message_moved)
307 {
308 	thread_t self = current_thread();
309 	ipc_port_t dest = IPC_PORT_NULL;
310 	/* Sync IPC from kernel should pass adopted voucher and importance */
311 	mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT & ~MACH_SEND_NOIMPORTANCE;
312 	ipc_port_t reply;
313 	ipc_kmsg_t kmsg;
314 	mach_msg_header_t *hdr;
315 	mach_port_seqno_t seqno;
316 	mach_msg_return_t mr;
317 
318 	assert(msg->msgh_local_port == MACH_PORT_NULL);
319 
320 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
321 
322 	if (message_moved) {
323 		*message_moved = FALSE;
324 	}
325 
326 	if (!IP_VALID(msg->msgh_remote_port)) {
327 		return MACH_SEND_INVALID_DEST;
328 	}
329 
330 	mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
331 	/* kmsg can be non-linear */
332 
333 	if (mr != MACH_MSG_SUCCESS) {
334 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
335 		return mr;
336 	}
337 	hdr = ikm_header(kmsg);
338 
339 	reply = self->ith_kernel_reply_port;
340 	if (reply == IP_NULL) {
341 		thread_get_kernel_special_reply_port();
342 		reply = self->ith_kernel_reply_port;
343 		if (reply == IP_NULL) {
344 			panic("mach_msg_rpc_from_kernel");
345 		}
346 	}
347 
348 	/* Get voucher port for the current thread's voucher */
349 	ipc_voucher_t voucher = IPC_VOUCHER_NULL;
350 	ipc_port_t voucher_port = IP_NULL;
351 
352 	/* Kernel server routines do not need voucher */
353 	bool has_voucher = !ip_is_kobject(hdr->msgh_remote_port);
354 
355 	if (has_voucher && thread_get_mach_voucher(self, 0, &voucher) == KERN_SUCCESS) {
356 		/* If thread does not have a voucher, get the default voucher of the process */
357 		if (voucher == IPC_VOUCHER_NULL) {
358 			voucher = ipc_voucher_get_default_voucher();
359 		}
360 		voucher_port = convert_voucher_to_port(voucher);
361 		ipc_kmsg_set_voucher_port(kmsg, voucher_port, MACH_MSG_TYPE_MOVE_SEND);
362 	}
363 
364 	/* insert send-once right for the reply port and send right for the adopted voucher */
365 	hdr->msgh_local_port = reply;
366 	hdr->msgh_bits |=
367 	    MACH_MSGH_BITS_SET_PORTS(
368 		0,
369 		MACH_MSG_TYPE_MAKE_SEND_ONCE,
370 		has_voucher ? MACH_MSG_TYPE_MOVE_SEND : 0);
371 
372 	mr = ipc_kmsg_copyin_from_kernel(kmsg);
373 	if (mr != MACH_MSG_SUCCESS) {
374 		/* Remove the voucher from the kmsg */
375 		if (has_voucher) {
376 			voucher_port = ipc_kmsg_get_voucher_port(kmsg);
377 			ipc_kmsg_clear_voucher_port(kmsg);
378 			ipc_port_release_send(voucher_port);
379 		}
380 
381 		ipc_kmsg_free(kmsg);
382 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
383 		return mr;
384 	}
385 
386 	if (message_moved) {
387 		*message_moved = TRUE;
388 	}
389 
390 	/*
391 	 * Destination port would be needed during receive for creating
392 	 * Sync IPC linkage with kernel special reply port, grab a reference
393 	 * of the destination port before it gets donated to mqueue in ipc_kmsg_send.
394 	 */
395 	dest = hdr->msgh_remote_port;
396 	ip_reference(dest);
397 
398 	mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE);
399 	if (mr != MACH_MSG_SUCCESS) {
400 		ip_release(dest);
401 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
402 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
403 		return mr;
404 	}
405 
406 	for (;;) {
407 		assert(!ip_in_pset(reply));
408 		require_ip_active(reply);
409 
410 		/* JMM - why this check? */
411 		if (interruptible && !self->active && !self->inspection) {
412 			ip_release(dest);
413 			thread_dealloc_kernel_special_reply_port(current_thread());
414 			return MACH_RCV_INTERRUPTED;
415 		}
416 
417 		/* Setup the sync IPC linkage for the special reply port */
418 		ipc_port_link_special_reply_port(reply,
419 		    dest, FALSE);
420 
421 		ipc_mqueue_receive(&reply->ip_waitq,
422 		    MACH64_MSG_OPTION_NONE,
423 		    MACH_MSG_SIZE_MAX,
424 		    0,
425 		    MACH_MSG_TIMEOUT_NONE,
426 		    interruptible ? THREAD_INTERRUPTIBLE : THREAD_UNINT,
427 		    /* continuation ? */ false);
428 
429 		mr = self->ith_state;
430 		kmsg = self->ith_kmsg;
431 		seqno = self->ith_seqno;
432 
433 		mach_msg_receive_results_complete(ip_to_object(reply));
434 
435 		if (mr == MACH_MSG_SUCCESS) {
436 			break;
437 		}
438 
439 		assert(mr == MACH_RCV_INTERRUPTED);
440 		assert(interruptible);
441 		assert(reply == self->ith_kernel_reply_port);
442 
443 		if (thread_ast_peek(self, AST_APC)) {
444 			ip_release(dest);
445 			thread_dealloc_kernel_special_reply_port(current_thread());
446 			return mr;
447 		}
448 	}
449 
450 	/* release the destination port ref acquired above */
451 	ip_release(dest);
452 	dest = IPC_PORT_NULL;
453 
454 	/* reload hdr from reply kmsg got above */
455 	hdr = ikm_header(kmsg);
456 
457 	mach_msg_size_t kmsg_size = hdr->msgh_size;
458 	mach_msg_size_t kmsg_and_max_trailer_size;
459 
460 	/*
461 	 * The amount of trailer to receive is flexible (see below),
462 	 * but the kmsg header must have a size that allows for a maximum
463 	 * trailer to follow as that's how IPC works (otherwise it might be corrupt).
464 	 */
465 	if (os_add_overflow(kmsg_size, MAX_TRAILER_SIZE, &kmsg_and_max_trailer_size)) {
466 		panic("kernel_mach_msg_rpc");
467 	}
468 
469 	/* The message header and body itself must be receivable */
470 	if (rcv_size < kmsg_size) {
471 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
472 		return MACH_RCV_TOO_LARGE;
473 	}
474 
475 	/*
476 	 *	We want to preserve rights and memory in reply!
477 	 *	We don't have to put them anywhere; just leave them
478 	 *	as they are.
479 	 */
480 	ipc_kmsg_copyout_dest_to_kernel(kmsg, ipc_space_reply);
481 
482 	mach_msg_format_0_trailer_t *trailer =  (mach_msg_format_0_trailer_t *)
483 	    ipc_kmsg_get_trailer(kmsg, false);
484 
485 	/* Determine what trailer bits we can receive (as no option specified) */
486 	if (rcv_size < kmsg_size + MACH_MSG_TRAILER_MINIMUM_SIZE) {
487 		rcv_size = kmsg_size;
488 	} else {
489 		if (rcv_size >= kmsg_and_max_trailer_size) {
490 			/*
491 			 * Enough room for a maximum trailer.
492 			 * JMM - we really should set the expected receiver-set fields:
493 			 *       (seqno, context, filterid, etc...) but nothing currently
494 			 *       expects them anyway.
495 			 */
496 			trailer->msgh_trailer_size = MAX_TRAILER_SIZE;
497 			rcv_size = kmsg_and_max_trailer_size;
498 		} else {
499 			assert(trailer->msgh_trailer_size == MACH_MSG_TRAILER_MINIMUM_SIZE);
500 			rcv_size = kmsg_size + MACH_MSG_TRAILER_MINIMUM_SIZE;
501 		}
502 	}
503 	assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0);
504 	mr = MACH_MSG_SUCCESS;
505 
506 	ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size);
507 	return mr;
508 }
509 
510 /*
511  *	Routine:	mach_msg_destroy_from_kernel_proper
512  *	Purpose:
513  *		mach_msg_destroy_from_kernel_proper is used to destroy
514  *		an unwanted/unexpected reply message from a MIG
515  *		kernel-specific user-side stub.	It is like ipc_kmsg_destroy(),
516  *		except we no longer have the kmsg - just the contents.
517  */
518 void
mach_msg_destroy_from_kernel_proper(mach_msg_header_t * msg)519 mach_msg_destroy_from_kernel_proper(mach_msg_header_t *msg)
520 {
521 	mach_msg_bits_t mbits = msg->msgh_bits;
522 	ipc_object_t object;
523 
524 	object = (ipc_object_t) msg->msgh_remote_port;
525 	if (IO_VALID(object)) {
526 		ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
527 	}
528 
529 	/*
530 	 * The destination (now in msg->msgh_local_port via
531 	 * ipc_kmsg_copyout_dest_to_kernel) has been consumed with
532 	 * ipc_object_copyout_dest.
533 	 */
534 
535 	/* MIG kernel users don't receive vouchers */
536 	assert(!MACH_MSGH_BITS_VOUCHER(mbits));
537 
538 	/* For simple messages, we're done */
539 	if ((mbits & MACH_MSGH_BITS_COMPLEX) == 0) {
540 		return;
541 	}
542 
543 	/* Discard descriptor contents */
544 	mach_msg_body_t *body = (mach_msg_body_t *)(msg + 1);
545 	mach_msg_descriptor_t *daddr = (mach_msg_descriptor_t *)(body + 1);
546 	mach_msg_size_t i;
547 
548 	for (i = 0; i < body->msgh_descriptor_count; i++, daddr++) {
549 		switch (daddr->type.type) {
550 		case MACH_MSG_PORT_DESCRIPTOR: {
551 			mach_msg_port_descriptor_t *dsc = &daddr->port;
552 			if (IO_VALID((ipc_object_t) dsc->name)) {
553 				ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
554 			}
555 			break;
556 		}
557 		case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
558 		case MACH_MSG_OOL_DESCRIPTOR: {
559 			mach_msg_ool_descriptor_t *dsc =
560 			    (mach_msg_ool_descriptor_t *)&daddr->out_of_line;
561 
562 			if (dsc->size > 0) {
563 				vm_map_copy_discard((vm_map_copy_t) dsc->address);
564 			} else {
565 				assert(dsc->address == (void *) 0);
566 			}
567 			break;
568 		}
569 		case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
570 			ipc_object_t                    *objects;
571 			mach_msg_type_number_t          j;
572 			mach_msg_ool_ports_descriptor_t *dsc;
573 
574 			dsc = (mach_msg_ool_ports_descriptor_t  *)&daddr->ool_ports;
575 			objects = (ipc_object_t *) dsc->address;
576 
577 			if (dsc->count == 0) {
578 				break;
579 			}
580 			assert(objects != 0);
581 			for (j = 0; j < dsc->count; j++) {
582 				object = objects[j];
583 				if (IO_VALID(object)) {
584 					ipc_object_destroy(object, dsc->disposition);
585 				}
586 			}
587 			kfree_type(mach_port_t, dsc->count, dsc->address);
588 			break;
589 		}
590 		case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
591 			mach_msg_guarded_port_descriptor_t *dsc = (mach_msg_guarded_port_descriptor_t *)&daddr->guarded_port;
592 			if (IO_VALID((ipc_object_t) dsc->name)) {
593 				ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
594 			}
595 			break;
596 		}
597 		default:
598 			break;
599 		}
600 	}
601 }
602 
603 /************** These Calls are set up for kernel-loaded tasks/threads **************/
604 
605 /*
606  *	Routine:	mig_get_reply_port
607  *	Purpose:
608  *		Called by client side interfaces living in the kernel
609  *		to get a reply port.
610  */
611 mach_port_t
mig_get_reply_port(void)612 mig_get_reply_port(void)
613 {
614 	return MACH_PORT_NULL;
615 }
616 
617 /*
618  *	Routine:	mig_dealloc_reply_port
619  *	Purpose:
620  *		Called by client side interfaces to get rid of a reply port.
621  */
622 
623 void
mig_dealloc_reply_port(__unused mach_port_t reply_port)624 mig_dealloc_reply_port(
625 	__unused mach_port_t reply_port)
626 {
627 }
628 
629 /*
630  *	Routine:	mig_put_reply_port
631  *	Purpose:
632  *		Called by client side interfaces after each RPC to
633  *		let the client recycle the reply port if it wishes.
634  */
635 void
mig_put_reply_port(__unused mach_port_t reply_port)636 mig_put_reply_port(
637 	__unused mach_port_t reply_port)
638 {
639 }
640 
641 /*
642  * mig_strncpy.c - by Joshua Block
643  *
644  * mig_strncp -- Bounded string copy.  Does what the library routine strncpy
645  * OUGHT to do:  Copies the (null terminated) string in src into dest, a
646  * buffer of length len.  Assures that the copy is still null terminated
647  * and doesn't overflow the buffer, truncating the copy if necessary.
648  *
649  * Parameters:
650  *
651  *     dest - Pointer to destination buffer.
652  *
653  *     src - Pointer to source string.
654  *
655  *     len - Length of destination buffer.
656  */
657 int
mig_strncpy(char * dest,const char * src,int len)658 mig_strncpy(
659 	char            *dest,
660 	const char      *src,
661 	int             len)
662 {
663 	int i = 0;
664 
665 	if (len > 0) {
666 		if (dest != NULL) {
667 			if (src != NULL) {
668 				for (i = 1; i < len; i++) {
669 					if (!(*dest++ = *src++)) {
670 						return i;
671 					}
672 				}
673 			}
674 			*dest = '\0';
675 		}
676 	}
677 	return i;
678 }
679 
680 /*
681  * mig_strncpy_zerofill -- Bounded string copy.  Does what the
682  * library routine strncpy OUGHT to do:  Copies the (null terminated)
683  * string in src into dest, a buffer of length len.  Assures that
684  * the copy is still null terminated and doesn't overflow the buffer,
685  * truncating the copy if necessary. If the string in src is smaller
686  * than given length len, it will zero fill the remaining bytes in dest.
687  *
688  * Parameters:
689  *
690  *     dest - Pointer to destination buffer.
691  *
692  *     src - Pointer to source string.
693  *
694  *     len - Length of destination buffer.
695  */
696 int
mig_strncpy_zerofill(char * dest,const char * src,int len)697 mig_strncpy_zerofill(
698 	char            *dest,
699 	const char      *src,
700 	int             len)
701 {
702 	int i = 0;
703 	boolean_t terminated = FALSE;
704 	int retval = 0;
705 
706 	if (len <= 0 || dest == NULL) {
707 		return 0;
708 	}
709 
710 	if (src == NULL) {
711 		terminated = TRUE;
712 	}
713 
714 	for (i = 1; i < len; i++) {
715 		if (!terminated) {
716 			if (!(*dest++ = *src++)) {
717 				retval = i;
718 				terminated = TRUE;
719 			}
720 		} else {
721 			*dest++ = '\0';
722 		}
723 	}
724 
725 	*dest = '\0';
726 	if (!terminated) {
727 		retval = i;
728 	}
729 
730 	return retval;
731 }
732 
733 void *
mig_user_allocate(vm_size_t size)734 mig_user_allocate(
735 	vm_size_t       size)
736 {
737 	return kalloc_type_var_impl(KT_IPC_KMSG_KDATA_OOL,
738 	           size, Z_WAITOK, NULL);
739 }
740 
741 void
mig_user_deallocate(char * data,vm_size_t size)742 mig_user_deallocate(
743 	char            *data,
744 	vm_size_t       size)
745 {
746 	kfree_type_var_impl(KT_IPC_KMSG_KDATA_OOL, data, size);
747 }
748