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