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