xref: /xnu-8792.41.9/osfmk/kern/ipc_mig.c (revision 5c2921b07a2480ab43ec66f5b9e41cb872bc554f)
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 void
89 mach_msg_receive_results_complete(ipc_object_t object);
90 
91 /*
92  *	Routine:	mach_msg_send_from_kernel
93  *	Purpose:
94  *		Send a message from the kernel.
95  *
96  *		This is used by the client side of KernelUser interfaces
97  *		to implement SimpleRoutines.  Currently, this includes
98  *		memory_object messages.
99  *	Conditions:
100  *		Nothing locked.
101  *	Returns:
102  *		MACH_MSG_SUCCESS	Sent the message.
103  *		MACH_SEND_INVALID_DEST	Bad destination port.
104  *		MACH_MSG_SEND_NO_BUFFER Destination port had inuse fixed bufer
105  *		                        or destination is above kernel limit
106  */
107 
108 mach_msg_return_t
mach_msg_send_from_kernel_proper(mach_msg_header_t * msg,mach_msg_size_t send_size)109 mach_msg_send_from_kernel_proper(
110 	mach_msg_header_t       *msg,
111 	mach_msg_size_t         send_size)
112 {
113 	mach_msg_option_t   option = MACH_SEND_KERNEL_DEFAULT;
114 	mach_msg_timeout_t  timeout_val = MACH_MSG_TIMEOUT_NONE;
115 	return kernel_mach_msg_send(msg, send_size, option, timeout_val, NULL);
116 }
117 
118 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)119 mach_msg_send_from_kernel_with_options(
120 	mach_msg_header_t       *msg,
121 	mach_msg_size_t         send_size,
122 	mach_msg_option_t       option,
123 	mach_msg_timeout_t      timeout_val)
124 {
125 	return kernel_mach_msg_send(msg, send_size, option, timeout_val, NULL);
126 }
127 
128 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)129 kernel_mach_msg_send_common(
130 	ipc_kmsg_t              kmsg,
131 	mach_msg_option_t       option,
132 	mach_msg_timeout_t      timeout_val,
133 	boolean_t               *message_moved)
134 {
135 	mach_msg_return_t mr;
136 
137 	mr = ipc_kmsg_copyin_from_kernel(kmsg);
138 	if (mr != MACH_MSG_SUCCESS) {
139 		ipc_kmsg_free(kmsg);
140 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
141 		return mr;
142 	}
143 
144 	if (message_moved) {
145 		*message_moved = TRUE;
146 	}
147 
148 	/*
149 	 * Until we are sure of its effects, we are disabling
150 	 * importance donation from the kernel-side of user
151 	 * threads in importance-donating tasks - unless the
152 	 * option to force importance donation is passed in,
153 	 * or the thread's SEND_IMPORTANCE option has been set.
154 	 * (11938665 & 23925818)
155 	 */
156 	if (current_thread()->options & TH_OPT_SEND_IMPORTANCE) {
157 		option &= ~MACH_SEND_NOIMPORTANCE;
158 	} else if ((option & MACH_SEND_IMPORTANCE) == 0) {
159 		option |= MACH_SEND_NOIMPORTANCE;
160 	}
161 
162 	mr = ipc_kmsg_send(kmsg, option, timeout_val);
163 
164 	if (mr != MACH_MSG_SUCCESS) {
165 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
166 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
167 	}
168 
169 	return mr;
170 }
171 
172 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)173 kernel_mach_msg_send(
174 	mach_msg_header_t       *msg,
175 	mach_msg_size_t         send_size,
176 	mach_msg_option_t       option,
177 	mach_msg_timeout_t      timeout_val,
178 	boolean_t               *message_moved)
179 {
180 	ipc_kmsg_t kmsg;
181 	mach_msg_return_t mr;
182 
183 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
184 
185 	if (message_moved) {
186 		*message_moved = FALSE;
187 	}
188 
189 	mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
190 	if (mr != MACH_MSG_SUCCESS) {
191 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
192 		return mr;
193 	}
194 
195 	return kernel_mach_msg_send_common(kmsg, option, timeout_val, message_moved);
196 }
197 
198 mach_msg_return_t
199 kernel_mach_msg_send_with_builder(
200 	mach_msg_size_t         send_size,
201 	mach_msg_option_t       option,
202 	mach_msg_timeout_t      timeout_val,
203 	boolean_t               *message_moved,
204 	void                    (^builder)(mach_msg_header_t *, mach_msg_size_t))
205 {
206 	ipc_kmsg_t kmsg;
207 	mach_msg_return_t mr;
208 	mach_msg_header_t *hdr;
209 
210 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
211 
212 	if (message_moved) {
213 		*message_moved = FALSE;
214 	}
215 
216 	kmsg = ipc_kmsg_alloc(send_size, 0, 0,
217 	    IPC_KMSG_ALLOC_KERNEL | IPC_KMSG_ALLOC_ZERO);
218 	if (kmsg == IKM_NULL) {
219 		mr = MACH_SEND_NO_BUFFER;
220 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
221 		return mr;
222 	}
223 	hdr = ikm_header(kmsg);
224 
225 	builder(hdr, send_size);
226 	hdr->msgh_size = send_size;
227 
228 	return kernel_mach_msg_send_common(kmsg, option, timeout_val, message_moved);
229 }
230 
231 /*
232  *	Routine:	mach_msg_rpc_from_kernel
233  *	Purpose:
234  *		Send a message from the kernel and receive a reply.
235  *		Uses ith_rpc_reply for the reply port.
236  *
237  *		This is used by the client side of KernelUser interfaces
238  *		to implement Routines.
239  *	Conditions:
240  *		Nothing locked.
241  *	Returns:
242  *		MACH_MSG_SUCCESS	Sent the message.
243  *		MACH_RCV_PORT_DIED	The reply port was deallocated.
244  */
245 
246 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)247 mach_msg_rpc_from_kernel_proper(
248 	mach_msg_header_t       *msg,
249 	mach_msg_size_t         send_size,
250 	mach_msg_size_t         rcv_size)
251 {
252 	return kernel_mach_msg_rpc(msg, send_size, rcv_size, TRUE, NULL);
253 }
254 
255 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)256 kernel_mach_msg_rpc(
257 	mach_msg_header_t       *msg,
258 	mach_msg_size_t         send_size,
259 	mach_msg_size_t         rcv_size,
260 	boolean_t               interruptible,
261 	boolean_t               *message_moved)
262 {
263 	thread_t self = current_thread();
264 	ipc_port_t dest = IPC_PORT_NULL;
265 	ipc_port_t reply;
266 	ipc_kmsg_t kmsg;
267 	mach_msg_header_t *hdr;
268 	mach_port_seqno_t seqno;
269 	mach_msg_return_t mr;
270 
271 	assert(msg->msgh_local_port == MACH_PORT_NULL);
272 
273 	KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
274 
275 	if (message_moved) {
276 		*message_moved = FALSE;
277 	}
278 
279 	mr = ipc_kmsg_get_from_kernel(msg, send_size, &kmsg);
280 	if (mr != MACH_MSG_SUCCESS) {
281 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
282 		return mr;
283 	}
284 	hdr = ikm_header(kmsg);
285 
286 	reply = self->ith_kernel_reply_port;
287 	if (reply == IP_NULL) {
288 		thread_get_kernel_special_reply_port();
289 		reply = self->ith_kernel_reply_port;
290 		if (reply == IP_NULL) {
291 			panic("mach_msg_rpc_from_kernel");
292 		}
293 	}
294 
295 	/* Get voucher port for the current thread's voucher */
296 	ipc_voucher_t voucher = IPC_VOUCHER_NULL;
297 	ipc_port_t voucher_port = IP_NULL;
298 	if (thread_get_mach_voucher(self, 0, &voucher) == KERN_SUCCESS) {
299 		/* If thread does not have a voucher, get the default voucher of the process */
300 		if (voucher == IPC_VOUCHER_NULL) {
301 			voucher = ipc_voucher_get_default_voucher();
302 		}
303 		voucher_port = convert_voucher_to_port(voucher);
304 	}
305 
306 	/* insert send-once right for the reply port and send right for the adopted voucher */
307 	ikm_header(kmsg)->msgh_local_port = reply;
308 	ipc_kmsg_set_voucher_port(kmsg, voucher_port, MACH_MSG_TYPE_MOVE_SEND);
309 	ikm_header(kmsg)->msgh_bits |=
310 	    MACH_MSGH_BITS_SET_PORTS(0, MACH_MSG_TYPE_MAKE_SEND_ONCE, MACH_MSG_TYPE_MOVE_SEND);
311 
312 	mr = ipc_kmsg_copyin_from_kernel(kmsg);
313 	if (mr != MACH_MSG_SUCCESS) {
314 		/* Remove the voucher from the kmsg */
315 		voucher_port = ipc_kmsg_get_voucher_port(kmsg);
316 		ipc_kmsg_clear_voucher_port(kmsg);
317 		ipc_port_release_send(voucher_port);
318 
319 		ipc_kmsg_free(kmsg);
320 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
321 		return mr;
322 	}
323 
324 	if (message_moved) {
325 		*message_moved = TRUE;
326 	}
327 
328 	/*
329 	 * Sync IPC from kernel should pass adopted voucher and importance.
330 	 */
331 	mach_msg_option_t option = MACH_SEND_KERNEL_DEFAULT;
332 	option &= ~MACH_SEND_NOIMPORTANCE;
333 
334 	/*
335 	 * Destination port would be needed during receive for creating
336 	 * Sync IPC linkage with kernel special reply port, grab a reference
337 	 * of the destination port before it gets donated to mqueue in ipc_kmsg_send.
338 	 */
339 	dest = ikm_header(kmsg)->msgh_remote_port;
340 	ip_reference(dest);
341 
342 	mr = ipc_kmsg_send(kmsg, option, MACH_MSG_TIMEOUT_NONE);
343 	if (mr != MACH_MSG_SUCCESS) {
344 		ip_release(dest);
345 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
346 		KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
347 		return mr;
348 	}
349 
350 	for (;;) {
351 		assert(!ip_in_pset(reply));
352 		require_ip_active(reply);
353 
354 		/* JMM - why this check? */
355 		if (interruptible && !self->active && !self->inspection) {
356 			ip_release(dest);
357 			thread_dealloc_kernel_special_reply_port(current_thread());
358 			return MACH_RCV_INTERRUPTED;
359 		}
360 
361 		/* Setup the sync IPC linkage for the special reply port */
362 		ipc_port_link_special_reply_port(reply,
363 		    dest, FALSE);
364 
365 		ipc_mqueue_receive(&reply->ip_waitq,
366 		    MACH64_MSG_OPTION_NONE,
367 		    MACH_MSG_SIZE_MAX,
368 		    0,
369 		    MACH_MSG_TIMEOUT_NONE,
370 		    interruptible ? THREAD_INTERRUPTIBLE : THREAD_UNINT,
371 		    /* continuation ? */ false);
372 
373 		mr = self->ith_state;
374 		kmsg = self->ith_kmsg;
375 		seqno = self->ith_seqno;
376 
377 		mach_msg_receive_results_complete(ip_to_object(reply));
378 
379 		if (mr == MACH_MSG_SUCCESS) {
380 			break;
381 		}
382 
383 		assert(mr == MACH_RCV_INTERRUPTED);
384 		assert(interruptible);
385 		assert(reply == self->ith_kernel_reply_port);
386 
387 		if (thread_ast_peek(self, AST_APC)) {
388 			ip_release(dest);
389 			thread_dealloc_kernel_special_reply_port(current_thread());
390 			return mr;
391 		}
392 	}
393 
394 	/* release the destination port ref acquired above */
395 	ip_release(dest);
396 	dest = IPC_PORT_NULL;
397 
398 	mach_msg_size_t kmsg_size = ikm_header(kmsg)->msgh_size;
399 	mach_msg_size_t kmsg_and_max_trailer_size;
400 
401 	/*
402 	 * The amount of trailer to receive is flexible (see below),
403 	 * but the kmsg header must have a size that allows for a maximum
404 	 * trailer to follow as that's how IPC works (otherwise it might be corrupt).
405 	 */
406 	if (os_add_overflow(kmsg_size, MAX_TRAILER_SIZE, &kmsg_and_max_trailer_size)) {
407 		panic("kernel_mach_msg_rpc");
408 	}
409 
410 	/* The message header and body itself must be receivable */
411 	if (rcv_size < kmsg_size) {
412 		ipc_kmsg_destroy(kmsg, IPC_KMSG_DESTROY_ALL);
413 		return MACH_RCV_TOO_LARGE;
414 	}
415 
416 	/*
417 	 *	We want to preserve rights and memory in reply!
418 	 *	We don't have to put them anywhere; just leave them
419 	 *	as they are.
420 	 */
421 	ipc_kmsg_copyout_dest_to_kernel(kmsg, ipc_space_reply);
422 
423 	mach_msg_format_0_trailer_t *trailer =  (mach_msg_format_0_trailer_t *)
424 	    ipc_kmsg_get_trailer(kmsg, false);
425 
426 	/* Determine what trailer bits we can receive (as no option specified) */
427 	if (rcv_size < kmsg_size + MACH_MSG_TRAILER_MINIMUM_SIZE) {
428 		rcv_size = kmsg_size;
429 	} else {
430 		if (rcv_size >= kmsg_and_max_trailer_size) {
431 			/*
432 			 * Enough room for a maximum trailer.
433 			 * JMM - we really should set the expected receiver-set fields:
434 			 *       (seqno, context, filterid, etc...) but nothing currently
435 			 *       expects them anyway.
436 			 */
437 			trailer->msgh_trailer_size = MAX_TRAILER_SIZE;
438 			rcv_size = kmsg_and_max_trailer_size;
439 		} else {
440 			assert(trailer->msgh_trailer_size == MACH_MSG_TRAILER_MINIMUM_SIZE);
441 			rcv_size = kmsg_size + MACH_MSG_TRAILER_MINIMUM_SIZE;
442 		}
443 	}
444 	assert(trailer->msgh_trailer_type == MACH_MSG_TRAILER_FORMAT_0);
445 	mr = MACH_MSG_SUCCESS;
446 
447 	ipc_kmsg_put_to_kernel(msg, kmsg, rcv_size);
448 	return mr;
449 }
450 
451 /*
452  *	Routine:	mach_msg_destroy_from_kernel_proper
453  *	Purpose:
454  *		mach_msg_destroy_from_kernel_proper is used to destroy
455  *		an unwanted/unexpected reply message from a MIG
456  *		kernel-specific user-side stub.	It is like ipc_kmsg_destroy(),
457  *		except we no longer have the kmsg - just the contents.
458  */
459 void
mach_msg_destroy_from_kernel_proper(mach_msg_header_t * msg)460 mach_msg_destroy_from_kernel_proper(mach_msg_header_t *msg)
461 {
462 	mach_msg_bits_t mbits = msg->msgh_bits;
463 	ipc_object_t object;
464 
465 	object = (ipc_object_t) msg->msgh_remote_port;
466 	if (IO_VALID(object)) {
467 		ipc_object_destroy(object, MACH_MSGH_BITS_REMOTE(mbits));
468 	}
469 
470 	/*
471 	 * The destination (now in msg->msgh_local_port via
472 	 * ipc_kmsg_copyout_dest_to_kernel) has been consumed with
473 	 * ipc_object_copyout_dest.
474 	 */
475 
476 	/* MIG kernel users don't receive vouchers */
477 	assert(!MACH_MSGH_BITS_VOUCHER(mbits));
478 
479 	/* For simple messages, we're done */
480 	if ((mbits & MACH_MSGH_BITS_COMPLEX) == 0) {
481 		return;
482 	}
483 
484 	/* Discard descriptor contents */
485 	mach_msg_body_t *body = (mach_msg_body_t *)(msg + 1);
486 	mach_msg_descriptor_t *daddr = (mach_msg_descriptor_t *)(body + 1);
487 	mach_msg_size_t i;
488 
489 	for (i = 0; i < body->msgh_descriptor_count; i++, daddr++) {
490 		switch (daddr->type.type) {
491 		case MACH_MSG_PORT_DESCRIPTOR: {
492 			mach_msg_port_descriptor_t *dsc = &daddr->port;
493 			if (IO_VALID((ipc_object_t) dsc->name)) {
494 				ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
495 			}
496 			break;
497 		}
498 		case MACH_MSG_OOL_VOLATILE_DESCRIPTOR:
499 		case MACH_MSG_OOL_DESCRIPTOR: {
500 			mach_msg_ool_descriptor_t *dsc =
501 			    (mach_msg_ool_descriptor_t *)&daddr->out_of_line;
502 
503 			if (dsc->size > 0) {
504 				vm_map_copy_discard((vm_map_copy_t) dsc->address);
505 			} else {
506 				assert(dsc->address == (void *) 0);
507 			}
508 			break;
509 		}
510 		case MACH_MSG_OOL_PORTS_DESCRIPTOR: {
511 			ipc_object_t                    *objects;
512 			mach_msg_type_number_t          j;
513 			mach_msg_ool_ports_descriptor_t *dsc;
514 
515 			dsc = (mach_msg_ool_ports_descriptor_t  *)&daddr->ool_ports;
516 			objects = (ipc_object_t *) dsc->address;
517 
518 			if (dsc->count == 0) {
519 				break;
520 			}
521 			assert(objects != 0);
522 			for (j = 0; j < dsc->count; j++) {
523 				object = objects[j];
524 				if (IO_VALID(object)) {
525 					ipc_object_destroy(object, dsc->disposition);
526 				}
527 			}
528 			kfree_type(mach_port_t, dsc->count, dsc->address);
529 			break;
530 		}
531 		case MACH_MSG_GUARDED_PORT_DESCRIPTOR: {
532 			mach_msg_guarded_port_descriptor_t *dsc = (mach_msg_guarded_port_descriptor_t *)&daddr->guarded_port;
533 			if (IO_VALID((ipc_object_t) dsc->name)) {
534 				ipc_object_destroy((ipc_object_t) dsc->name, dsc->disposition);
535 			}
536 			break;
537 		}
538 		default:
539 			break;
540 		}
541 	}
542 }
543 
544 /************** These Calls are set up for kernel-loaded tasks/threads **************/
545 
546 /*
547  *	Routine:	mig_get_reply_port
548  *	Purpose:
549  *		Called by client side interfaces living in the kernel
550  *		to get a reply port.
551  */
552 mach_port_t
mig_get_reply_port(void)553 mig_get_reply_port(void)
554 {
555 	return MACH_PORT_NULL;
556 }
557 
558 /*
559  *	Routine:	mig_dealloc_reply_port
560  *	Purpose:
561  *		Called by client side interfaces to get rid of a reply port.
562  */
563 
564 void
mig_dealloc_reply_port(__unused mach_port_t reply_port)565 mig_dealloc_reply_port(
566 	__unused mach_port_t reply_port)
567 {
568 }
569 
570 /*
571  *	Routine:	mig_put_reply_port
572  *	Purpose:
573  *		Called by client side interfaces after each RPC to
574  *		let the client recycle the reply port if it wishes.
575  */
576 void
mig_put_reply_port(__unused mach_port_t reply_port)577 mig_put_reply_port(
578 	__unused mach_port_t reply_port)
579 {
580 }
581 
582 /*
583  * mig_strncpy.c - by Joshua Block
584  *
585  * mig_strncp -- Bounded string copy.  Does what the library routine strncpy
586  * OUGHT to do:  Copies the (null terminated) string in src into dest, a
587  * buffer of length len.  Assures that the copy is still null terminated
588  * and doesn't overflow the buffer, truncating the copy if necessary.
589  *
590  * Parameters:
591  *
592  *     dest - Pointer to destination buffer.
593  *
594  *     src - Pointer to source string.
595  *
596  *     len - Length of destination buffer.
597  */
598 int
mig_strncpy(char * dest,const char * src,int len)599 mig_strncpy(
600 	char            *dest,
601 	const char      *src,
602 	int             len)
603 {
604 	int i = 0;
605 
606 	if (len > 0) {
607 		if (dest != NULL) {
608 			if (src != NULL) {
609 				for (i = 1; i < len; i++) {
610 					if (!(*dest++ = *src++)) {
611 						return i;
612 					}
613 				}
614 			}
615 			*dest = '\0';
616 		}
617 	}
618 	return i;
619 }
620 
621 /*
622  * mig_strncpy_zerofill -- Bounded string copy.  Does what the
623  * library routine strncpy OUGHT to do:  Copies the (null terminated)
624  * string in src into dest, a buffer of length len.  Assures that
625  * the copy is still null terminated and doesn't overflow the buffer,
626  * truncating the copy if necessary. If the string in src is smaller
627  * than given length len, it will zero fill the remaining bytes in dest.
628  *
629  * Parameters:
630  *
631  *     dest - Pointer to destination buffer.
632  *
633  *     src - Pointer to source string.
634  *
635  *     len - Length of destination buffer.
636  */
637 int
mig_strncpy_zerofill(char * dest,const char * src,int len)638 mig_strncpy_zerofill(
639 	char            *dest,
640 	const char      *src,
641 	int             len)
642 {
643 	int i = 0;
644 	boolean_t terminated = FALSE;
645 	int retval = 0;
646 
647 	if (len <= 0 || dest == NULL) {
648 		return 0;
649 	}
650 
651 	if (src == NULL) {
652 		terminated = TRUE;
653 	}
654 
655 	for (i = 1; i < len; i++) {
656 		if (!terminated) {
657 			if (!(*dest++ = *src++)) {
658 				retval = i;
659 				terminated = TRUE;
660 			}
661 		} else {
662 			*dest++ = '\0';
663 		}
664 	}
665 
666 	*dest = '\0';
667 	if (!terminated) {
668 		retval = i;
669 	}
670 
671 	return retval;
672 }
673 
674 void *
mig_user_allocate(vm_size_t size)675 mig_user_allocate(
676 	vm_size_t       size)
677 {
678 	return kalloc_data(size, Z_WAITOK);
679 }
680 
681 void
mig_user_deallocate(char * data,vm_size_t size)682 mig_user_deallocate(
683 	char            *data,
684 	vm_size_t       size)
685 {
686 	kfree_data(data, size);
687 }
688