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 = IO_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(ip_to_object(port),
604 MACH_MSGH_BITS_REMOTE(mbits));
605 msg->msgh_remote_port = IP_NULL;
606 }
607
608 /*
609 * The destination (now in msg->msgh_local_port via
610 * ipc_kmsg_copyout_dest_to_kernel) has been consumed with
611 * ipc_object_copyout_dest.
612 */
613
614 /* MIG kernel users don't receive vouchers */
615 assert(!MACH_MSGH_BITS_VOUCHER(mbits));
616
617 /* For simple messages, we're done */
618 if (mbits & MACH_MSGH_BITS_COMPLEX) {
619 mach_msg_kbase_t *kbase = mach_msg_header_to_kbase(msg);
620
621 ipc_kmsg_clean_descriptors(kbase->msgb_dsc_array,
622 kbase->msgb_dsc_count);
623 }
624 }
625
626 /* same as mach_msg_destroy_from_kernel but for kexts */
627 extern typeof(mach_msg_destroy_from_kernel) mach_msg_destroy_from_kernel_proper;
628 void
mach_msg_destroy_from_kernel_proper(mach_msg_header_t * msg)629 mach_msg_destroy_from_kernel_proper(mach_msg_header_t *msg)
630 {
631 if (msg->msgh_bits & MACH_MSGH_BITS_COMPLEX) {
632 mach_msg_kbase_t *kbase = mach_msg_header_to_kbase(msg);
633
634 ipc_kmsg_sign_descriptors(kbase->msgb_dsc_array,
635 kbase->msgb_dsc_count);
636 }
637 mach_msg_destroy_from_kernel(msg);
638 }
639
640
641 /************** These Calls are set up for kernel-loaded tasks/threads **************/
642
643 /*
644 * Routine: mig_get_reply_port
645 * Purpose:
646 * Called by client side interfaces living in the kernel
647 * to get a reply port.
648 */
649 mach_port_t
mig_get_reply_port(void)650 mig_get_reply_port(void)
651 {
652 return MACH_PORT_NULL;
653 }
654
655 /*
656 * Routine: mig_dealloc_reply_port
657 * Purpose:
658 * Called by client side interfaces to get rid of a reply port.
659 */
660
661 void
mig_dealloc_reply_port(__unused mach_port_t reply_port)662 mig_dealloc_reply_port(
663 __unused mach_port_t reply_port)
664 {
665 }
666
667 /*
668 * Routine: mig_put_reply_port
669 * Purpose:
670 * Called by client side interfaces after each RPC to
671 * let the client recycle the reply port if it wishes.
672 */
673 void
mig_put_reply_port(__unused mach_port_t reply_port)674 mig_put_reply_port(
675 __unused mach_port_t reply_port)
676 {
677 }
678
679 /*
680 * mig_strncpy.c - by Joshua Block
681 *
682 * mig_strncp -- Bounded string copy. Does what the library routine strncpy
683 * OUGHT to do: Copies the (null terminated) string in src into dest, a
684 * buffer of length len. Assures that the copy is still null terminated
685 * and doesn't overflow the buffer, truncating the copy if necessary.
686 *
687 * Parameters:
688 *
689 * dest - Pointer to destination buffer.
690 *
691 * src - Pointer to source string.
692 *
693 * len - Length of destination buffer.
694 */
695 int
mig_strncpy(char * dest,const char * src,int len)696 mig_strncpy(
697 char *dest,
698 const char *src,
699 int len)
700 {
701 int i = 0;
702
703 if (len > 0) {
704 if (dest != NULL) {
705 if (src != NULL) {
706 for (i = 1; i < len; i++) {
707 if (!(*dest++ = *src++)) {
708 return i;
709 }
710 }
711 }
712 *dest = '\0';
713 }
714 }
715 return i;
716 }
717
718 /*
719 * mig_strncpy_zerofill -- Bounded string copy. Does what the
720 * library routine strncpy OUGHT to do: Copies the (null terminated)
721 * string in src into dest, a buffer of length len. Assures that
722 * the copy is still null terminated and doesn't overflow the buffer,
723 * truncating the copy if necessary. If the string in src is smaller
724 * than given length len, it will zero fill the remaining bytes in dest.
725 *
726 * Parameters:
727 *
728 * dest - Pointer to destination buffer.
729 *
730 * src - Pointer to source string.
731 *
732 * len - Length of destination buffer.
733 */
734 int
mig_strncpy_zerofill(char * dest,const char * src,int len)735 mig_strncpy_zerofill(
736 char *dest,
737 const char *src,
738 int len)
739 {
740 int i = 0;
741 boolean_t terminated = FALSE;
742 int retval = 0;
743
744 if (len <= 0 || dest == NULL) {
745 return 0;
746 }
747
748 if (src == NULL) {
749 terminated = TRUE;
750 }
751
752 for (i = 1; i < len; i++) {
753 if (!terminated) {
754 if (!(*dest++ = *src++)) {
755 retval = i;
756 terminated = TRUE;
757 }
758 } else {
759 *dest++ = '\0';
760 }
761 }
762
763 *dest = '\0';
764 if (!terminated) {
765 retval = i;
766 }
767
768 return retval;
769 }
770
771 void *
mig_user_allocate(vm_size_t size)772 mig_user_allocate(
773 vm_size_t size)
774 {
775 return kalloc_type_var_impl(KT_IPC_KMSG_KDATA_OOL,
776 size, Z_WAITOK, NULL);
777 }
778
779 void
mig_user_deallocate(char * data,vm_size_t size)780 mig_user_deallocate(
781 char *data,
782 vm_size_t size)
783 {
784 kfree_type_var_impl(KT_IPC_KMSG_KDATA_OOL, data, size);
785 }
786