xref: /xnu-12377.81.4/osfmk/kern/ipc_mig.c (revision 043036a2b3718f7f0be807e2870f8f47d3fa0796)
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_kdescriptor_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(mach_msg_header_t * msg,mach_msg_size_t send_size)111 mach_msg_send_from_kernel(
112 	mach_msg_header_t      *msg,
113 	mach_msg_size_t         send_size)
114 {
115 	mach_msg_option64_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_option64_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_option64_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_option64_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_option64_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_option64_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_option64_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 	option &= ~MACH64_POLICY_KERNEL_EXTENSION;
192 	mr = ipc_kmsg_get_from_kernel(msg, send_size, option, &kmsg);
193 	if (mr != MACH_MSG_SUCCESS) {
194 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
195 		return mr;
196 	}
197 
198 	return kernel_mach_msg_send_common(kmsg, option, timeout_val, message_moved);
199 }
200 
201 extern typeof(mach_msg_send_from_kernel) mach_msg_send_from_kernel_proper;
202 mach_msg_return_t
mach_msg_send_from_kernel_proper(mach_msg_header_t * msg,mach_msg_size_t send_size)203 mach_msg_send_from_kernel_proper(
204 	mach_msg_header_t      *msg,
205 	mach_msg_size_t         send_size)
206 {
207 	mach_msg_option64_t option = MACH_SEND_KERNEL_DEFAULT;
208 	mach_msg_timeout_t  timeout_val = MACH_MSG_TIMEOUT_NONE;
209 	ipc_kmsg_t          kmsg;
210 	mach_msg_return_t   mr;
211 
212 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
213 
214 	option |= MACH64_POLICY_KERNEL_EXTENSION;
215 	mr = ipc_kmsg_get_from_kernel(msg, send_size, option, &kmsg);
216 	if (mr != MACH_MSG_SUCCESS) {
217 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
218 		return mr;
219 	}
220 
221 	return kernel_mach_msg_send_common(kmsg, option, timeout_val, NULL);
222 }
223 
224 mach_msg_return_t
kernel_mach_msg_send_kmsg(ipc_kmsg_t kmsg)225 kernel_mach_msg_send_kmsg(
226 	ipc_kmsg_t              kmsg)
227 {
228 	mach_msg_option_t   option = MACH_SEND_KERNEL_DEFAULT;
229 	mach_msg_timeout_t  timeout_val = MACH_MSG_TIMEOUT_NONE;
230 
231 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
232 
233 	return kernel_mach_msg_send_common(kmsg, option, timeout_val, NULL);
234 }
235 
236 mach_msg_return_t
237 kernel_mach_msg_send_with_builder_internal(
238 	mach_msg_size_t         desc_count,
239 	mach_msg_size_t         payload_size, /* Not total send size */
240 	mach_msg_option64_t     option,
241 	mach_msg_timeout_t      timeout_val,
242 	boolean_t              *message_moved,
243 	void                  (^builder)(mach_msg_header_t *, mach_msg_descriptor_t *, void *))
244 {
245 	ipc_kmsg_t kmsg;
246 	mach_msg_return_t mr;
247 	mach_msg_header_t *hdr;
248 	void *udata;
249 	bool complex;
250 	mach_msg_size_t send_size;
251 
252 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
253 
254 	/*
255 	 * If message has descriptors it must be complex and vice versa. We assume
256 	 * this for messages originated from kernel. The two are not equivalent for
257 	 * user messages for bin-compat reasons.
258 	 */
259 	complex = (desc_count > 0);
260 	send_size = sizeof(mach_msg_header_t) + payload_size;
261 
262 	if (complex) {
263 		send_size += sizeof(mach_msg_body_t) + desc_count * KERNEL_DESC_SIZE;
264 	}
265 	if (message_moved) {
266 		*message_moved = FALSE;
267 	}
268 
269 	kmsg = ipc_kmsg_alloc(send_size, 0, desc_count,
270 	    IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_ZERO);
271 	/* kmsg can be non-linear */
272 
273 	if (kmsg == IKM_NULL) {
274 		mr = MACH_SEND_NO_BUFFER;
275 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
276 		return mr;
277 	}
278 
279 	hdr   = ikm_header(kmsg);
280 	udata = (payload_size > 0) ? ikm_udata(kmsg, desc_count, complex) : NULL;
281 
282 	/* Allow the caller to build the message, and sanity check it */
283 	if (complex) {
284 		mach_msg_kbase_t *kbase = mach_msg_header_to_kbase(hdr);
285 
286 		builder(hdr, (mach_msg_descriptor_t *)kbase->msgb_dsc_array, udata);
287 
288 		assert(hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX);
289 		hdr->msgh_bits |= MACH_MSGH_BITS_COMPLEX;
290 
291 		/* Set the correct descriptor count */
292 		kbase->msgb_dsc_count = desc_count;
293 	} else {
294 		builder(hdr, NULL, udata);
295 
296 		assert(!(hdr->msgh_bits & MACH_MSGH_BITS_COMPLEX));
297 		hdr->msgh_bits &= ~MACH_MSGH_BITS_COMPLEX;
298 	}
299 	assert(hdr->msgh_size == send_size);
300 
301 	return kernel_mach_msg_send_common(kmsg, option, timeout_val, NULL);
302 }
303 
304 mach_msg_return_t
305 kernel_mach_msg_send_with_builder(
306 	mach_msg_size_t         desc_count,
307 	mach_msg_size_t         udata_size,
308 	void                    (^builder)(mach_msg_header_t *,
309 	mach_msg_descriptor_t *, void *))
310 {
311 	mach_msg_option64_t options;
312 
313 	options = MACH_SEND_KERNEL_DEFAULT | MACH64_POLICY_KERNEL_EXTENSION;
314 	return kernel_mach_msg_send_with_builder_internal(desc_count, udata_size,
315 	           options, MACH_MSG_TIMEOUT_NONE, NULL, builder);
316 }
317 
318 /*
319  *	Routine:	mach_msg_rpc_from_kernel
320  *	Purpose:
321  *		Send a message from the kernel and receive a reply.
322  *		Uses ith_rpc_reply for the reply port.
323  *
324  *		This is used by the client side of KernelUser interfaces
325  *		to implement Routines.
326  *	Conditions:
327  *		Nothing locked.
328  *	Returns:
329  *		MACH_MSG_SUCCESS	Sent the message.
330  *		MACH_RCV_PORT_DIED	The reply port was deallocated.
331  */
332 
333 static mach_msg_return_t
kernel_mach_msg_rpc_common(mach_msg_header_t * msg,mach_msg_size_t send_size,mach_msg_size_t rcv_size,boolean_t interruptible,mach_msg_option64_t options,boolean_t * message_moved)334 kernel_mach_msg_rpc_common(
335 	mach_msg_header_t       *msg,
336 	mach_msg_size_t         send_size,
337 	mach_msg_size_t         rcv_size,
338 	boolean_t               interruptible,
339 	mach_msg_option64_t     options,
340 	boolean_t              *message_moved)
341 {
342 	thread_t self = current_thread();
343 	ipc_port_t dest = IPC_PORT_NULL;
344 	/* Sync IPC from kernel should pass adopted voucher and importance */
345 	mach_msg_option64_t option = MACH_SEND_KERNEL_DEFAULT & ~MACH_SEND_NOIMPORTANCE;
346 	ipc_port_t reply;
347 	ipc_kmsg_t kmsg;
348 	mach_msg_header_t *hdr;
349 	mach_port_seqno_t seqno;
350 	mach_msg_return_t mr;
351 
352 	assert(msg->msgh_local_port == MACH_PORT_NULL);
353 
354 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
355 
356 	if (message_moved) {
357 		*message_moved = FALSE;
358 	}
359 
360 	if (!IP_VALID(msg->msgh_remote_port)) {
361 		return MACH_SEND_INVALID_DEST;
362 	}
363 
364 	mr = ipc_kmsg_get_from_kernel(msg, send_size, options, &kmsg);
365 	/* kmsg can be non-linear */
366 
367 	if (mr != MACH_MSG_SUCCESS) {
368 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
369 		return mr;
370 	}
371 	hdr = ikm_header(kmsg);
372 
373 	reply = self->ith_kernel_reply_port;
374 	if (reply == IP_NULL) {
375 		thread_get_kernel_special_reply_port();
376 		reply = self->ith_kernel_reply_port;
377 		if (reply == IP_NULL) {
378 			panic("mach_msg_rpc_from_kernel");
379 		}
380 	}
381 
382 	/* Get voucher port for the current thread's voucher */
383 	ipc_voucher_t voucher = IPC_VOUCHER_NULL;
384 	ipc_port_t voucher_port = IP_NULL;
385 
386 	/* Kernel server routines do not need voucher */
387 	bool has_voucher = !ip_is_kobject(hdr->msgh_remote_port);
388 
389 	if (has_voucher && thread_get_mach_voucher(self, 0, &voucher) == KERN_SUCCESS) {
390 		/* If thread does not have a voucher, get the default voucher of the process */
391 		if (voucher == IPC_VOUCHER_NULL) {
392 			voucher = ipc_voucher_get_default_voucher();
393 		}
394 		voucher_port = convert_voucher_to_port(voucher);
395 		ipc_kmsg_set_voucher_port(kmsg, voucher_port, MACH_MSG_TYPE_MOVE_SEND);
396 	}
397 
398 	/* insert send-once right for the reply port and send right for the adopted voucher */
399 	hdr->msgh_local_port = reply;
400 	hdr->msgh_bits |=
401 	    MACH_MSGH_BITS_SET_PORTS(
402 		0,
403 		MACH_MSG_TYPE_MAKE_SEND_ONCE,
404 		has_voucher ? MACH_MSG_TYPE_MOVE_SEND : 0);
405 
406 	mr = ipc_kmsg_copyin_from_kernel(kmsg);
407 	if (mr != MACH_MSG_SUCCESS) {
408 		/* Remove the voucher from the kmsg */
409 		if (has_voucher) {
410 			voucher_port = ipc_kmsg_get_voucher_port(kmsg);
411 			ipc_kmsg_clear_voucher_port(kmsg);
412 			ipc_port_release_send(voucher_port);
413 		}
414 
415 		ipc_kmsg_free(kmsg);
416 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
417 		return mr;
418 	}
419 
420 	if (message_moved) {
421 		*message_moved = TRUE;
422 	}
423 
424 	/*
425 	 * Destination port would be needed during receive for creating
426 	 * Sync IPC linkage with kernel special reply port, grab a reference
427 	 * of the destination port before it gets donated to mqueue in ipc_kmsg_send.
428 	 */
429 	dest = hdr->msgh_remote_port;
430 	ip_reference(dest);
431 
432 	mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE);
433 	if (mr != MACH_MSG_SUCCESS) {
434 		ip_release(dest);
435 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
436 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
437 		return mr;
438 	}
439 
440 	for (;;) {
441 		assert(!ip_in_pset(reply));
442 		require_ip_active(reply);
443 
444 		/* JMM - why this check? */
445 		if (interruptible && !self->active && !self->inspection) {
446 			ip_release(dest);
447 			thread_dealloc_kernel_special_reply_port(current_thread());
448 			return MACH_RCV_INTERRUPTED;
449 		}
450 
451 		/* Setup the sync IPC linkage for the special reply port */
452 		ipc_port_link_special_reply_port(reply,
453 		    dest, FALSE);
454 
455 		bzero(&self->ith_receive, sizeof(self->ith_receive));
456 		self->ith_recv_bufs = (mach_msg_recv_bufs_t){
457 			.recv_msg_size = MACH_MSG_SIZE_MAX,
458 		};
459 		self->ith_object = IPC_OBJECT_NULL;
460 		self->ith_option = MACH64_MSG_OPTION_NONE;
461 		self->ith_knote  = ITH_KNOTE_NULL; /* not part of ith_receive */
462 
463 		ipc_mqueue_receive(&reply->ip_waitq, MACH_MSG_TIMEOUT_NONE,
464 		    interruptible ? THREAD_INTERRUPTIBLE : THREAD_UNINT,
465 		    self, /* continuation ? */ false);
466 
467 		mr = self->ith_state;
468 		kmsg = self->ith_kmsg;
469 		seqno = self->ith_seqno;
470 
471 		mach_msg_receive_results_complete(ip_to_object(reply));
472 
473 		if (mr == MACH_MSG_SUCCESS) {
474 			break;
475 		}
476 
477 		assert(mr == MACH_RCV_INTERRUPTED);
478 		assert(interruptible);
479 		assert(reply == self->ith_kernel_reply_port);
480 
481 		if (thread_ast_peek(self, AST_APC)) {
482 			ip_release(dest);
483 			thread_dealloc_kernel_special_reply_port(current_thread());
484 			return mr;
485 		}
486 	}
487 
488 	/* release the destination port ref acquired above */
489 	ip_release(dest);
490 	dest = IPC_PORT_NULL;
491 
492 	/* reload hdr from reply kmsg got above */
493 	hdr = ikm_header(kmsg);
494 
495 	mach_msg_size_t kmsg_size = hdr->msgh_size;
496 	mach_msg_size_t kmsg_and_max_trailer_size;
497 
498 	/*
499 	 * The amount of trailer to receive is flexible (see below),
500 	 * but the kmsg header must have a size that allows for a maximum
501 	 * trailer to follow as that's how IPC works (otherwise it might be corrupt).
502 	 */
503 	if (os_add_overflow(kmsg_size, MAX_TRAILER_SIZE, &kmsg_and_max_trailer_size)) {
504 		panic("kernel_mach_msg_rpc");
505 	}
506 
507 	/* The message header and body itself must be receivable */
508 	if (rcv_size < kmsg_size) {
509 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
510 		return MACH_RCV_TOO_LARGE;
511 	}
512 
513 	/*
514 	 *	We want to preserve rights and memory in reply!
515 	 *	We don't have to put them anywhere; just leave them
516 	 *	as they are.
517 	 */
518 	ipc_kmsg_copyout_dest_to_kernel(kmsg, ipc_space_reply);
519 
520 	mach_msg_format_0_trailer_t *trailer =  (mach_msg_format_0_trailer_t *)
521 	    ipc_kmsg_get_trailer(kmsg);
522 
523 	/* Determine what trailer bits we can receive (as no option specified) */
524 	if (rcv_size < kmsg_size + MACH_MSG_TRAILER_MINIMUM_SIZE) {
525 		rcv_size = kmsg_size;
526 	} else {
527 		if (rcv_size >= kmsg_and_max_trailer_size) {
528 			/*
529 			 * Enough room for a maximum trailer.
530 			 * JMM - we really should set the expected receiver-set fields:
531 			 *       (seqno, context, filterid, etc...) but nothing currently
532 			 *       expects them anyway.
533 			 */
534 			trailer->msgh_trailer_size = MAX_TRAILER_SIZE;
535 			rcv_size = kmsg_and_max_trailer_size;
536 		} else {
537 			assert(trailer->msgh_trailer_size == MACH_MSG_TRAILER_MINIMUM_SIZE);
538 			rcv_size = kmsg_size + MACH_MSG_TRAILER_MINIMUM_SIZE;
539 		}
540 	}
541 	assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0);
542 	mr = MACH_MSG_SUCCESS;
543 
544 	ipc_kmsg_put_to_kernel(msg, options, kmsg, rcv_size);
545 	return mr;
546 }
547 
548 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)549 kernel_mach_msg_rpc(
550 	mach_msg_header_t       *msg,
551 	mach_msg_size_t         send_size,
552 	mach_msg_size_t         rcv_size,
553 	boolean_t               interruptible,
554 	boolean_t              *message_moved)
555 {
556 	mach_msg_option64_t options = MACH64_MSG_OPTION_NONE;
557 
558 	return kernel_mach_msg_rpc_common(msg, send_size, rcv_size,
559 	           interruptible, options, message_moved);
560 }
561 
562 mach_msg_return_t
mach_msg_rpc_from_kernel(mach_msg_header_t * msg,mach_msg_size_t send_size,mach_msg_size_t rcv_size)563 mach_msg_rpc_from_kernel(
564 	mach_msg_header_t       *msg,
565 	mach_msg_size_t         send_size,
566 	mach_msg_size_t         rcv_size)
567 {
568 	mach_msg_option64_t options = MACH64_MSG_OPTION_NONE;
569 
570 	return kernel_mach_msg_rpc_common(msg, send_size, rcv_size, TRUE,
571 	           options, NULL);
572 }
573 
574 /* same as mach_msg_rpc_from_kernel but for kexts */
575 extern typeof(mach_msg_rpc_from_kernel) mach_msg_rpc_from_kernel_proper;
576 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)577 mach_msg_rpc_from_kernel_proper(
578 	mach_msg_header_t       *msg,
579 	mach_msg_size_t         send_size,
580 	mach_msg_size_t         rcv_size)
581 {
582 	mach_msg_option64_t options = MACH64_POLICY_KERNEL_EXTENSION;
583 
584 	return kernel_mach_msg_rpc_common(msg, send_size, rcv_size, TRUE,
585 	           options, NULL);
586 }
587 
588 /*
589  *	Routine:	mach_msg_destroy_from_kernel
590  *	Purpose:
591  *		mach_msg_destroy_from_kernel is used to destroy
592  *		an unwanted/unexpected reply message from a MIG
593  *		kernel-specific user-side stub.	It is like ipc_kmsg_destroy(),
594  *		except we no longer have the kmsg - just the contents.
595  */
596 void
mach_msg_destroy_from_kernel(mach_msg_header_t * msg)597 mach_msg_destroy_from_kernel(mach_msg_header_t *msg)
598 {
599 	mach_msg_bits_t mbits = msg->msgh_bits;
600 	ipc_port_t      port = msg->msgh_remote_port;
601 
602 	if (IP_VALID(port)) {
603 		ipc_object_destroy(port, MACH_MSGH_BITS_REMOTE(mbits));
604 		msg->msgh_remote_port = IP_NULL;
605 	}
606 
607 	/*
608 	 * The destination (now in msg->msgh_local_port via
609 	 * ipc_kmsg_copyout_dest_to_kernel) has been consumed with
610 	 * ipc_object_copyout_dest.
611 	 */
612 
613 	/* MIG kernel users don't receive vouchers */
614 	assert(!MACH_MSGH_BITS_VOUCHER(mbits));
615 
616 	/* For simple messages, we're done */
617 	if (mbits & MACH_MSGH_BITS_COMPLEX) {
618 		mach_msg_kbase_t *kbase = mach_msg_header_to_kbase(msg);
619 
620 		ipc_kmsg_clean_descriptors(kbase->msgb_dsc_array,
621 		    kbase->msgb_dsc_count);
622 	}
623 }
624 
625 /* same as mach_msg_destroy_from_kernel but for kexts */
626 extern typeof(mach_msg_destroy_from_kernel) mach_msg_destroy_from_kernel_proper;
627 void
mach_msg_destroy_from_kernel_proper(mach_msg_header_t * msg)628 mach_msg_destroy_from_kernel_proper(mach_msg_header_t *msg)
629 {
630 	if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
631 		mach_msg_kbase_t *kbase = mach_msg_header_to_kbase(msg);
632 
633 		ipc_kmsg_sign_descriptors(kbase->msgb_dsc_array,
634 		    kbase->msgb_dsc_count);
635 	}
636 	mach_msg_destroy_from_kernel(msg);
637 }
638 
639 
640 /************** These Calls are set up for kernel-loaded tasks/threads **************/
641 
642 /*
643  *	Routine:	mig_get_reply_port
644  *	Purpose:
645  *		Called by client side interfaces living in the kernel
646  *		to get a reply port.
647  */
648 mach_port_t
mig_get_reply_port(void)649 mig_get_reply_port(void)
650 {
651 	return MACH_PORT_NULL;
652 }
653 
654 /*
655  *	Routine:	mig_dealloc_reply_port
656  *	Purpose:
657  *		Called by client side interfaces to get rid of a reply port.
658  */
659 
660 void
mig_dealloc_reply_port(__unused mach_port_t reply_port)661 mig_dealloc_reply_port(
662 	__unused mach_port_t reply_port)
663 {
664 }
665 
666 /*
667  *	Routine:	mig_put_reply_port
668  *	Purpose:
669  *		Called by client side interfaces after each RPC to
670  *		let the client recycle the reply port if it wishes.
671  */
672 void
mig_put_reply_port(__unused mach_port_t reply_port)673 mig_put_reply_port(
674 	__unused mach_port_t reply_port)
675 {
676 }
677 
678 /*
679  * mig_strncpy.c - by Joshua Block
680  *
681  * mig_strncp -- Bounded string copy.  Does what the library routine strncpy
682  * OUGHT to do:  Copies the (null terminated) string in src into dest, a
683  * buffer of length len.  Assures that the copy is still null terminated
684  * and doesn't overflow the buffer, truncating the copy if necessary.
685  *
686  * Parameters:
687  *
688  *     dest - Pointer to destination buffer.
689  *
690  *     src - Pointer to source string.
691  *
692  *     len - Length of destination buffer.
693  */
694 int
mig_strncpy(char * dest,const char * src,int len)695 mig_strncpy(
696 	char            *dest,
697 	const char      *src,
698 	int             len)
699 {
700 	int i = 0;
701 
702 	if (len > 0) {
703 		if (dest != NULL) {
704 			if (src != NULL) {
705 				for (i = 1; i < len; i++) {
706 					if (!(*dest++ = *src++)) {
707 						return i;
708 					}
709 				}
710 			}
711 			*dest = '\0';
712 		}
713 	}
714 	return i;
715 }
716 
717 /*
718  * mig_strncpy_zerofill -- Bounded string copy.  Does what the
719  * library routine strncpy OUGHT to do:  Copies the (null terminated)
720  * string in src into dest, a buffer of length len.  Assures that
721  * the copy is still null terminated and doesn't overflow the buffer,
722  * truncating the copy if necessary. If the string in src is smaller
723  * than given length len, it will zero fill the remaining bytes in dest.
724  *
725  * Parameters:
726  *
727  *     dest - Pointer to destination buffer.
728  *
729  *     src - Pointer to source string.
730  *
731  *     len - Length of destination buffer.
732  */
733 int
mig_strncpy_zerofill(char * dest,const char * src,int len)734 mig_strncpy_zerofill(
735 	char            *dest,
736 	const char      *src,
737 	int             len)
738 {
739 	int i = 0;
740 	boolean_t terminated = FALSE;
741 	int retval = 0;
742 
743 	if (len <= 0 || dest == NULL) {
744 		return 0;
745 	}
746 
747 	if (src == NULL) {
748 		terminated = TRUE;
749 	}
750 
751 	for (i = 1; i < len; i++) {
752 		if (!terminated) {
753 			if (!(*dest++ = *src++)) {
754 				retval = i;
755 				terminated = TRUE;
756 			}
757 		} else {
758 			*dest++ = '\0';
759 		}
760 	}
761 
762 	*dest = '\0';
763 	if (!terminated) {
764 		retval = i;
765 	}
766 
767 	return retval;
768 }
769 
770 void *
mig_user_allocate(vm_size_t size)771 mig_user_allocate(
772 	vm_size_t       size)
773 {
774 	return kalloc_type_var_impl(KT_IPC_KMSG_KDATA_OOL,
775 	           size, Z_WAITOK, NULL);
776 }
777 
778 void
mig_user_deallocate(char * data,vm_size_t size)779 mig_user_deallocate(
780 	char            *data,
781 	vm_size_t       size)
782 {
783 	kfree_type_var_impl(KT_IPC_KMSG_KDATA_OOL, data, size);
784 }
785