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