1 /*
2 * Copyright (c) 2000-2007 Apple 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,1989 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 * NOTICE: This file was modified by McAfee Research in 2004 to introduce
58 * support for mandatory and extensible security protections. This notice
59 * is included in support of clause 2.2 (b) of the Apple Public License,
60 * Version 2.0.
61 * Copyright (c) 2005 SPARTA, Inc.
62 */
63 /*
64 */
65 /*
66 * File: ipc/mach_msg.c
67 * Author: Rich Draves
68 * Date: 1989
69 *
70 * Exported message traps. See mach/message.h.
71 */
72
73 #include <mach/mach_types.h>
74 #include <mach/kern_return.h>
75 #include <mach/port.h>
76 #include <mach/message.h>
77 #include <mach/mig_errors.h>
78 #include <mach/mach_traps.h>
79
80 #include <kern/kern_types.h>
81 #include <kern/assert.h>
82 #include <kern/cpu_number.h>
83 #include <kern/ipc_kobject.h>
84 #include <kern/ipc_mig.h>
85 #include <kern/task.h>
86 #include <kern/thread.h>
87 #include <kern/sched_prim.h>
88 #include <kern/exception.h>
89 #include <kern/misc_protos.h>
90 #include <kern/processor.h>
91 #include <kern/syscall_subr.h>
92 #include <kern/policy_internal.h>
93 #include <kern/mach_filter.h>
94
95 #include <vm/vm_map.h>
96
97 #include <ipc/port.h>
98 #include <ipc/ipc_types.h>
99 #include <ipc/ipc_kmsg.h>
100 #include <ipc/ipc_mqueue.h>
101 #include <ipc/ipc_object.h>
102 #include <ipc/ipc_notify.h>
103 #include <ipc/ipc_port.h>
104 #include <ipc/ipc_pset.h>
105 #include <ipc/ipc_space.h>
106 #include <ipc/ipc_entry.h>
107 #include <ipc/ipc_importance.h>
108 #include <ipc/ipc_voucher.h>
109
110 #include <machine/machine_routines.h>
111 #include <security/mac_mach_internal.h>
112
113 #include <sys/kdebug.h>
114 #include <sys/proc_ro.h>
115
116 #ifndef offsetof
117 #define offsetof(type, member) ((size_t)(&((type *)0)->member))
118 #endif /* offsetof */
119
120 /*
121 * Forward declarations - kernel internal routines
122 */
123
124 static mach_msg_return_t msg_receive_error(
125 ipc_kmsg_t kmsg,
126 mach_msg_option64_t option64,
127 mach_vm_address_t rcv_addr,
128 mach_msg_size_t rcv_size,
129 mach_vm_address_t aux_addr,
130 mach_msg_size_t aux_size,
131 mach_port_seqno_t seqno,
132 ipc_space_t space,
133 mach_msg_size_t *sizep,
134 mach_msg_size_t *aux_sizep);
135
136 static mach_msg_return_t
137 mach_msg_rcv_link_special_reply_port(
138 ipc_port_t special_reply_port,
139 mach_port_name_t dest_name_port);
140
141 void
142 mach_msg_receive_results_complete(ipc_object_t object);
143
144 const security_token_t KERNEL_SECURITY_TOKEN = KERNEL_SECURITY_TOKEN_VALUE;
145 const audit_token_t KERNEL_AUDIT_TOKEN = KERNEL_AUDIT_TOKEN_VALUE;
146
147 /*
148 * values to limit inline message body handling
149 * avoid copyin/out limits - even after accounting for maximum descriptor expansion.
150 */
151 #define IPC_KMSG_MAX_SPACE (64 * 1024 * 1024) /* keep in sync with COPYSIZELIMIT_PANIC */
152 static const vm_size_t ipc_kmsg_max_body_space = ((IPC_KMSG_MAX_SPACE * 3) / 4 - MAX_TRAILER_SIZE);
153
154 static const vm_size_t ipc_kmsg_max_aux_data_space = 1024;
155
156 #define MACH_MSG_DESC_MIN_SIZE sizeof(mach_msg_type_descriptor_t)
157
158 /*
159 * Routine: mach_msg_receive_results
160 * Purpose:
161 * Receive a message.
162 * Conditions:
163 * Nothing locked.
164 *
165 * Arguments passed on thread struct:
166 * If MACH64_RCV_LINEAR_VECTOR is not set:
167 * - ith_msg_addr: buffer address for message proper
168 * - ith_aux_addr: buffer address for auxiliary data (if any),
169 * only used if MACH64_MSG_VECTOR
170 * - ith_max_msize: size of message proper buffer
171 * - ith_max_asize: size of aux data buffer (if any)
172 * Otherwise:
173 * - ith_msg_addr: buffer address for combined message and aux
174 * - ith_aux_addr: Unused
175 * - ith_max_msize: size of combined
176 * - ith_max_asize: Unused
177 * Returns:
178 * sizep (out): copied out size of message proper
179 * aux_sizep (out): copied out size of aux data
180 * MACH_MSG_SUCCESS Received a message.
181 * MACH_RCV_INVALID_NAME The name doesn't denote a right,
182 * or the denoted right is not receive or port set.
183 * MACH_RCV_IN_SET Receive right is a member of a set.
184 * MACH_RCV_TOO_LARGE Message wouldn't fit into buffer.
185 * MACH_RCV_TIMED_OUT Timeout expired without a message.
186 * MACH_RCV_INTERRUPTED Reception interrupted.
187 * MACH_RCV_PORT_DIED Port/set died while receiving.
188 * MACH_RCV_PORT_CHANGED Port moved into set while receiving.
189 * MACH_RCV_INVALID_DATA Couldn't copy to user buffer.
190 * MACH_RCV_INVALID_NOTIFY Bad notify port.
191 * MACH_RCV_HEADER_ERROR
192 */
193 mach_msg_return_t
mach_msg_receive_results_kevent(mach_msg_size_t * sizep,mach_msg_size_t * aux_sizep,uint32_t * ppri,mach_msg_qos_t * oqos)194 mach_msg_receive_results_kevent(
195 mach_msg_size_t *sizep, /* copied out msg size */
196 mach_msg_size_t *aux_sizep, /* copied out aux size */
197 uint32_t *ppri, /* received message pthread_priority_t */
198 mach_msg_qos_t *oqos) /* override qos for message */
199 {
200 mach_msg_trailer_size_t trailer_size;
201 mach_vm_address_t context;
202
203 thread_t self = current_thread();
204 ipc_space_t space = current_space();
205 vm_map_t map = current_map();
206
207 /*
208 * /!\IMPORTANT/!\: Pull out values we stashed on thread struct now.
209 * Values may be stomped over if copyio operations in this function
210 * trigger kernel IPC calls.
211 */
212 ipc_object_t object = self->ith_object;
213 mach_msg_return_t mr = self->ith_state;
214 mach_vm_address_t msg_rcv_addr = self->ith_msg_addr;
215 mach_msg_size_t msg_rcv_size = self->ith_max_msize;
216 mach_port_name_t receiver_name = self->ith_receiver_name;
217
218 mach_vm_address_t aux_rcv_addr = self->ith_aux_addr;
219 mach_msg_size_t aux_rcv_size = self->ith_max_asize;
220 mach_msg_size_t msg_size = self->ith_msize;
221 mach_msg_size_t aux_size = self->ith_asize;
222
223 mach_msg_option64_t option64 = self->ith_option;
224 ipc_kmsg_t kmsg = self->ith_kmsg;
225 mach_port_seqno_t seqno = self->ith_seqno;
226
227 mach_msg_size_t cpout_msg_size = 0, cpout_aux_size = 0;
228
229 /*
230 * unlink the special_reply_port before releasing reference to object.
231 * get the thread's turnstile, if the thread donated it's turnstile to the port
232 */
233 mach_msg_receive_results_complete(object);
234 io_release(object);
235
236 if (option64 & MACH64_RCV_LINEAR_VECTOR) {
237 assert(aux_rcv_addr == 0);
238 assert(aux_rcv_size == 0);
239 }
240
241 if (mr != MACH_MSG_SUCCESS) {
242 if (mr == MACH_RCV_TOO_LARGE) {
243 /*
244 * If the receive operation occurs with MACH_RCV_LARGE set
245 * then no message was extracted from the queue, and the size
246 * and (optionally) receiver names were the only thing captured.
247 * Just copyout the size (and optional port name) in a fake
248 * header.
249 */
250 if (option64 & MACH64_RCV_LARGE) {
251 if (!(option64 & MACH64_RCV_STACK) &&
252 msg_rcv_size >= offsetof(mach_msg_user_header_t, msgh_reserved)) {
253 /*
254 * We need to inform the user-level code that it needs more
255 * space. The value for how much space was returned in the
256 * msize save area instead of the message (which was left on
257 * the queue).
258 */
259 if (option64 & MACH64_RCV_LARGE_IDENTITY) {
260 if (copyout((char *) &receiver_name,
261 msg_rcv_addr + offsetof(mach_msg_user_header_t, msgh_local_port),
262 sizeof(mach_port_name_t))) {
263 mr = MACH_RCV_INVALID_DATA;
264 }
265 }
266 if (copyout((char *) &msg_size,
267 msg_rcv_addr + offsetof(mach_msg_user_header_t, msgh_size),
268 sizeof(mach_msg_size_t))) {
269 mr = MACH_RCV_INVALID_DATA;
270 }
271 }
272
273 /* Report the incoming aux size if caller has aux buffer */
274 if (!(option64 & MACH64_RCV_STACK) &&
275 !(option64 & MACH64_RCV_LINEAR_VECTOR) &&
276 aux_rcv_addr != 0) {
277 if (copyout((char *) &aux_size,
278 aux_rcv_addr + offsetof(mach_msg_aux_header_t, msgdh_size),
279 sizeof(mach_msg_size_t))) {
280 assert(aux_rcv_size >= sizeof(mach_msg_aux_header_t));
281 mr = MACH_RCV_INVALID_DATA;
282 }
283 }
284 } else {
285 /* discard importance in message */
286 ipc_importance_clean(kmsg);
287
288 if (msg_receive_error(kmsg, option64, msg_rcv_addr, msg_rcv_size,
289 aux_rcv_addr, aux_rcv_size, seqno, space, &cpout_msg_size,
290 &cpout_aux_size) == MACH_RCV_INVALID_DATA) {
291 /* MACH_RCV_INVALID_DATA takes precedence */
292 mr = MACH_RCV_INVALID_DATA;
293 }
294 }
295 }
296
297 if (sizep) {
298 *sizep = cpout_msg_size;
299 }
300 if (aux_sizep) {
301 *aux_sizep = cpout_aux_size;
302 }
303 return mr;
304 }
305
306 /* MACH_MSG_SUCCESS */
307 assert(mr == MACH_MSG_SUCCESS);
308
309 #if IMPORTANCE_INHERITANCE
310
311 /* adopt/transform any importance attributes carried in the message */
312 ipc_importance_receive(kmsg, (mach_msg_option_t)option64);
313
314 #endif /* IMPORTANCE_INHERITANCE */
315
316 /* auto redeem the voucher in the message */
317 ipc_voucher_receive_postprocessing(kmsg, (mach_msg_option_t)option64);
318
319 /* Save destination port context for the trailer before copyout */
320 context = ikm_header(kmsg)->msgh_remote_port->ip_context;
321
322 mr = ipc_kmsg_copyout(kmsg, space, map, (mach_msg_option_t)option64);
323
324 trailer_size = ipc_kmsg_trailer_size((mach_msg_option_t)option64, self);
325
326 if (mr != MACH_MSG_SUCCESS) {
327 /* already received importance, so have to undo that here */
328 ipc_importance_unreceive(kmsg, (mach_msg_option_t)option64);
329
330 /* if we had a body error copyout what we have, otherwise a simple header/trailer */
331 if ((mr & ~MACH_MSG_MASK) == MACH_RCV_BODY_ERROR) {
332 ipc_kmsg_add_trailer(kmsg, space, (mach_msg_option_t)option64,
333 self, seqno, FALSE, context);
334 if (ipc_kmsg_put_to_user(kmsg, option64, msg_rcv_addr,
335 msg_rcv_size, aux_rcv_addr, aux_rcv_size, trailer_size,
336 &cpout_msg_size, &cpout_aux_size) == MACH_RCV_INVALID_DATA) {
337 mr = MACH_RCV_INVALID_DATA;
338 }
339 } else {
340 if (msg_receive_error(kmsg, option64, msg_rcv_addr, msg_rcv_size,
341 aux_rcv_addr, aux_rcv_size, seqno, space,
342 &cpout_msg_size, &cpout_aux_size) == MACH_RCV_INVALID_DATA) {
343 mr = MACH_RCV_INVALID_DATA;
344 }
345 }
346 } else {
347 if (ppri) {
348 *ppri = kmsg->ikm_ppriority;
349 }
350 if (oqos) {
351 *oqos = kmsg->ikm_qos_override;
352 }
353 ipc_kmsg_add_trailer(kmsg, space, option64, self, seqno, FALSE, context);
354
355 mr = ipc_kmsg_put_to_user(kmsg, option64, msg_rcv_addr, msg_rcv_size,
356 aux_rcv_addr, aux_rcv_size, trailer_size, &cpout_msg_size, &cpout_aux_size);
357 /* kmsg freed */
358 }
359
360 if (sizep) {
361 *sizep = cpout_msg_size;
362 }
363
364 if (aux_sizep) {
365 *aux_sizep = cpout_aux_size;
366 }
367
368 /*
369 * Restore the values that are used by filt_machportprocess() after this
370 * call, as they may be overwritten by upcalls duing copyout().
371 *
372 * We should make this code more legible in 95817694.
373 */
374 self->ith_asize = aux_size;
375 self->ith_msize = msg_size;
376 self->ith_receiver_name = receiver_name;
377
378 return mr;
379 }
380
381 mach_msg_return_t
mach_msg_receive_results(void)382 mach_msg_receive_results(void)
383 {
384 return mach_msg_receive_results_kevent(NULL, NULL, NULL, NULL);
385 }
386
387 void
mach_msg_receive_continue(void)388 mach_msg_receive_continue(void)
389 {
390 mach_msg_return_t mr;
391 thread_t self = current_thread();
392
393 ipc_port_thread_group_unblocked();
394 if (self->ith_state == MACH_PEEK_READY) {
395 mr = MACH_PEEK_READY;
396 } else {
397 mr = mach_msg_receive_results();
398 }
399 thread_syscall_return(mr);
400 }
401
402 /*
403 * Routine: mach_msg_validate_data_vectors
404 * Purpose:
405 * Perform validations on message and auxiliary data vectors
406 * we have copied in.
407 */
408 static mach_msg_return_t
mach_msg_validate_data_vectors(mach_msg_vector_t * msg_vec,mach_msg_vector_t * aux_vec,mach_msg_size_t vec_count,__unused mach_msg_option64_t option64,bool sending)409 mach_msg_validate_data_vectors(
410 mach_msg_vector_t *msg_vec,
411 mach_msg_vector_t *aux_vec,
412 mach_msg_size_t vec_count,
413 __unused mach_msg_option64_t option64,
414 bool sending)
415 {
416 mach_msg_size_t msg_size = 0, aux_size = 0; /* user size */
417
418 assert(vec_count <= MACH_MSGV_MAX_COUNT);
419 assert(option64 & MACH64_MSG_VECTOR);
420
421 assert(msg_vec != NULL);
422 assert(aux_vec != NULL);
423
424 if (vec_count == 0) {
425 /*
426 * can't use MACH_RCV_TOO_LARGE or MACH_RCV_INVALID_DATA here because
427 * they imply a message has been dropped. use a new error code that
428 * suggests an early error and that message is still queued.
429 */
430 return sending ? MACH_SEND_MSG_TOO_SMALL : MACH_RCV_INVALID_ARGUMENTS;
431 }
432
433 /*
434 * Validate first (message proper) data vector.
435 *
436 * Since we are using mach_msg2_trap() to shim existing mach_msg() calls,
437 * we unfortunately cannot validate message rcv address or message rcv size
438 * at this point for compatibility reasons.
439 *
440 * (1) If rcv address is invalid, we will destroy the incoming message during
441 * ipc_kmsg_put_to_user(), instead of returning an error before receive
442 * is attempted.
443 * (2) If rcv size is smaller than the minimal message header and trailer
444 * that msg_receive_error() builds, we will truncate the message and copy
445 * out a partial message.
446 *
447 * See: ipc_kmsg_put_vector_to_user().
448 */
449 if (sending) {
450 if (msg_vec->msgv_data == 0) {
451 return MACH_SEND_INVALID_DATA;
452 }
453 msg_size = msg_vec->msgv_send_size;
454 if ((msg_size < sizeof(mach_msg_user_header_t)) || (msg_size & 3)) {
455 return MACH_SEND_MSG_TOO_SMALL;
456 }
457 if (msg_size > ipc_kmsg_max_body_space) {
458 return MACH_SEND_TOO_LARGE;
459 }
460 }
461
462 /* Validate second (optional auxiliary) data vector */
463 if (vec_count == MACH_MSGV_MAX_COUNT) {
464 if (sending) {
465 aux_size = aux_vec->msgv_send_size;
466 if (aux_size != 0 && aux_vec->msgv_data == 0) {
467 return MACH_SEND_INVALID_DATA;
468 }
469 if (aux_size != 0 && aux_size < sizeof(mach_msg_aux_header_t)) {
470 return MACH_SEND_AUX_TOO_SMALL;
471 }
472 if (aux_size > ipc_kmsg_max_aux_data_space) {
473 return MACH_SEND_AUX_TOO_LARGE;
474 }
475 } else {
476 mach_vm_address_t rcv_addr = aux_vec->msgv_rcv_addr ?
477 aux_vec->msgv_rcv_addr : aux_vec->msgv_data;
478
479 if (rcv_addr == 0) {
480 return MACH_RCV_INVALID_ARGUMENTS;
481 }
482 /*
483 * We are using this aux vector to receive, kernel will at
484 * least copy out an empty aux data header.
485 *
486 * See: ipc_kmsg_put_vector_to_user()
487 */
488 aux_size = aux_vec->msgv_rcv_size;
489 if (aux_size < sizeof(mach_msg_aux_header_t)) {
490 return MACH_RCV_INVALID_ARGUMENTS;
491 }
492 }
493 } else {
494 if (sending) {
495 /*
496 * Not sending aux data vector, but we still might have copied it
497 * in if doing a combined send/receive. Nil out the send size.
498 */
499 aux_vec->msgv_send_size = 0;
500 } else {
501 /* Do the same for receive */
502 aux_vec->msgv_rcv_size = 0;
503 }
504 }
505
506 return MACH_MSG_SUCCESS;
507 }
508 /*
509 * Routine: mach_msg_copyin_data_vectors
510 * Purpose:
511 * Copy in and message user data vectors.
512 */
513 static mach_msg_return_t
mach_msg_copyin_data_vectors(mach_msg_vector_t * data_addr,mach_msg_size_t cpin_count,mach_msg_option64_t option64,mach_msg_vector_t * msg_vecp,mach_msg_vector_t * aux_vecp)514 mach_msg_copyin_data_vectors(
515 mach_msg_vector_t *data_addr,/* user address */
516 mach_msg_size_t cpin_count,
517 mach_msg_option64_t option64,
518 mach_msg_vector_t *msg_vecp,/* out */
519 mach_msg_vector_t *aux_vecp)/* out */
520 {
521 mach_msg_vector_t data_vecs[MACH_MSGV_MAX_COUNT] = {};
522
523 static_assert(MACH_MSGV_MAX_COUNT == 2);
524 assert(option64 & MACH64_MSG_VECTOR);
525
526 if (cpin_count > MACH_MSGV_MAX_COUNT) {
527 return (option64 & MACH64_SEND_MSG) ?
528 MACH_SEND_INVALID_DATA : MACH_RCV_INVALID_ARGUMENTS;
529 }
530
531 if (cpin_count == 0) {
532 return (option64 & MACH64_SEND_MSG) ?
533 MACH_SEND_MSG_TOO_SMALL : MACH_RCV_INVALID_ARGUMENTS;
534 }
535
536 if (copyin((user_addr_t)data_addr, (caddr_t)data_vecs,
537 cpin_count * sizeof(mach_msg_vector_t))) {
538 return (option64 & MACH64_SEND_MSG) ?
539 MACH_SEND_INVALID_DATA : MACH_RCV_INVALID_ARGUMENTS;
540 }
541
542 memcpy(msg_vecp, &data_vecs[MACH_MSGV_IDX_MSG], sizeof(mach_msg_vector_t));
543
544 if (cpin_count == MACH_MSGV_MAX_COUNT) {
545 memcpy(aux_vecp, &data_vecs[MACH_MSGV_IDX_AUX], sizeof(mach_msg_vector_t));
546 }
547
548 return MACH_MSG_SUCCESS;
549 }
550
551 #if XNU_TARGET_OS_OSX || XNU_TARGET_OS_IOS
552 #if DEVELOPMENT || DEBUG
553 static TUNABLE(bool, allow_legacy_mach_msg, "allow_legacy_mach_msg", false);
554 #endif /* DEVELOPMENT || DEBUG */
555
556 static bool
mach_msg_legacy_allowed(mach_msg_user_header_t * header)557 mach_msg_legacy_allowed(mach_msg_user_header_t *header)
558 {
559 struct proc_ro *pro = current_thread_ro()->tro_proc_ro;
560 uint32_t platform = pro->p_platform_data.p_platform;
561 uint32_t sdk = pro->p_platform_data.p_sdk;
562 uint32_t sdk_major = sdk >> 16;
563 #if __x86_64__ || CONFIG_ROSETTA
564 task_t task = current_task();
565 #endif
566
567 #if __x86_64__
568 if (!task_has_64Bit_addr(task)) {
569 /*
570 * Legacy mach_msg_trap() is the only
571 * available thing for 32-bit tasks
572 */
573 return true;
574 }
575 #endif /* __x86_64__ */
576 #if CONFIG_ROSETTA
577 if (task_is_translated(task)) {
578 /*
579 * Similarly, on Rosetta, allow mach_msg_trap()
580 * as those apps likely can't be fixed anymore
581 */
582 return true;
583 }
584 #endif
585 if (pro->t_flags_ro & TFRO_PLATFORM) {
586 /* Platform binaries must use mach_msg2_trap() */
587 return false;
588 }
589
590 #if DEVELOPMENT || DEBUG
591 if (allow_legacy_mach_msg) {
592 /* Honor boot-arg */
593 return true;
594 }
595 #endif /* DEVELOPMENT || DEBUG */
596
597 /*
598 * Special rules, due to unfortunate bincompat reasons,
599 * allow for a hardcoded list of MIG calls to XNU to go through:
600 * - for iOS, Catalyst and iOS Simulator apps linked against
601 * an SDK older than 15.x,
602 * - for macOS apps linked against an SDK older than 12.x.
603 */
604 switch (platform) {
605 case PLATFORM_IOS:
606 case PLATFORM_IOSSIMULATOR:
607 case PLATFORM_MACCATALYST:
608 if (sdk == 0 || sdk_major > 15) {
609 return false;
610 }
611 break;
612 case PLATFORM_MACOS:
613 if (sdk == 0 || sdk_major > 12) {
614 return false;
615 }
616 break;
617 default:
618 return false;
619 }
620
621 switch (header->msgh_id) {
622 case 0xd4a: /* task_threads */
623 case 0xd4d: /* task_info */
624 case 0xe13: /* thread_get_state */
625 case 0x12c4: /* mach_vm_read */
626 case 0x12c8: /* mach_vm_read_overwrite */
627 return true;
628 default:
629 return false;
630 }
631 }
632
633 /*
634 * Routine: mach_msg_copyin_user_header
635 * Purpose:
636 * Copy in the message header, or up until message body if message is
637 * large enough. Returns the header of the message and number of descriptors.
638 * Used for mach_msg_overwrite_trap() only. Not available on embedded.
639 * Returns:
640 * MACH_MSG_SUCCESS - Copyin succeeded, msg_addr and msg_size are validated.
641 * MACH_SEND_MSG_TOO_SMALL
642 * MACH_SEND_TOO_LARGE
643 * MACH_SEND_INVALID_DATA
644 */
645 static mach_msg_return_t
mach_msg_copyin_user_header(mach_vm_address_t msg_addr,mach_msg_size_t msg_size,mach_msg_user_header_t * header,mach_msg_size_t * desc_count)646 mach_msg_copyin_user_header(
647 mach_vm_address_t msg_addr,
648 mach_msg_size_t msg_size,
649 mach_msg_user_header_t *header,
650 mach_msg_size_t *desc_count)
651 {
652 mach_msg_size_t len_copied;
653 mach_msg_size_t descriptors;
654 mach_msg_user_base_t user_base;
655
656 if ((msg_size < sizeof(mach_msg_user_header_t)) || (msg_size & 3)) {
657 return MACH_SEND_MSG_TOO_SMALL;
658 }
659
660 if (msg_size > ipc_kmsg_max_body_space) {
661 return MACH_SEND_TOO_LARGE;
662 }
663
664 if (msg_size == sizeof(mach_msg_user_header_t)) {
665 len_copied = sizeof(mach_msg_user_header_t);
666 } else {
667 len_copied = sizeof(mach_msg_user_base_t);
668 }
669
670 user_base.body.msgh_descriptor_count = descriptors = 0;
671 /*
672 * If message is larger than mach_msg_user_header_t, first copy in
673 * header + next 4 bytes, which is treated as descriptor count
674 * if message is complex.
675 */
676 if (copyinmsg(msg_addr, (char *)&user_base, len_copied)) {
677 return MACH_SEND_INVALID_DATA;
678 }
679
680 /*
681 * If the message claims to be complex, it must at least
682 * have the length of a "base" message (header + dsc_count).
683 */
684 if (user_base.header.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
685 if (len_copied < sizeof(mach_msg_user_base_t)) {
686 return MACH_SEND_MSG_TOO_SMALL;
687 }
688 descriptors = user_base.body.msgh_descriptor_count;
689 /* desc count bound check in mach_msg_trap_send() */
690 }
691
692 if (!mach_msg_legacy_allowed(&user_base.header)) {
693 mach_port_guard_exception(user_base.header.msgh_id, 0, 0, kGUARD_EXC_INVALID_OPTIONS);
694 /*
695 * this should be MACH_SEND_INVALID_OPTIONS,
696 * but this is a new mach_msg2 error only.
697 */
698 return KERN_NOT_SUPPORTED;
699 }
700
701 memcpy(header, &user_base, sizeof(mach_msg_user_header_t));
702
703 /*
704 * return message "body" as desriptor count,
705 * zero if message is not complex.
706 */
707 *desc_count = descriptors;
708
709 return MACH_MSG_SUCCESS;
710 }
711 #endif /* XNU_TARGET_OS_OSX || XNU_TARGET_OS_IOS */
712
713 /*
714 * Routine: mach_msg_trap_send [internal]
715 * Purpose:
716 * Send a message.
717 * Conditions:
718 * MACH_SEND_MSG is set. aux_send_size is bound checked.
719 * aux_{addr, send_size} are 0 if not vector send.
720 * msg_send_size needs additional bound checks.
721 * Returns:
722 * All of mach_msg_send error codes.
723 */
724 static mach_msg_return_t
mach_msg_trap_send(mach_vm_address_t msg_addr,mach_vm_address_t aux_addr,mach_msg_option64_t option64,mach_msg_timeout_t msg_timeout,mach_msg_priority_t priority,bool filter_nonfatal,mach_msg_user_header_t user_header,mach_msg_size_t msg_send_size,mach_msg_size_t aux_send_size,mach_msg_size_t desc_count)725 mach_msg_trap_send(
726 /* shared args between send and receive */
727 mach_vm_address_t msg_addr,
728 mach_vm_address_t aux_addr,
729 mach_msg_option64_t option64,
730 mach_msg_timeout_t msg_timeout,
731 mach_msg_priority_t priority,
732 /* msg send args */
733 bool filter_nonfatal,
734 mach_msg_user_header_t user_header,
735 mach_msg_size_t msg_send_size,
736 mach_msg_size_t aux_send_size, /* bound checked */
737 mach_msg_size_t desc_count)
738 {
739 ipc_kmsg_t kmsg;
740
741 mach_msg_return_t mr = MACH_MSG_SUCCESS;
742 vm_map_t map = current_map();
743 ipc_space_t space = current_space();
744
745 assert(option64 & MACH64_SEND_MSG);
746
747 /*
748 * Bound checks on msg_send_size to cover mach_msg2() scalar send case.
749 *
750 * For mach_msg2() vector send:
751 * - We have checked during mach_msg_validate_data_vectors().
752 * For mach_msg() send:
753 * - We have checked during mach_msg_copyin_user_header().
754 *
755 * But checking again here can't hurt.
756 */
757 if ((msg_send_size < sizeof(mach_msg_user_header_t)) || (msg_send_size & 3)) {
758 return MACH_SEND_MSG_TOO_SMALL;
759 }
760 if (msg_send_size > ipc_kmsg_max_body_space) {
761 return MACH_SEND_TOO_LARGE;
762 }
763 /*
764 * Complex message must have a body, also do a bound check on descriptor count
765 * (more in ikm_check_descriptors()).
766 */
767 if (user_header.msgh_bits & MACH_MSGH_BITS_COMPLEX) {
768 if (msg_send_size < sizeof(mach_msg_user_base_t)) {
769 return MACH_SEND_MSG_TOO_SMALL;
770 }
771 if (desc_count > (msg_send_size - sizeof(mach_msg_user_base_t)) / MACH_MSG_DESC_MIN_SIZE) {
772 return MACH_SEND_MSG_TOO_SMALL;
773 }
774 } else if (desc_count != 0) {
775 /*
776 * Simple message cannot contain descriptors. This invalid config can only
777 * happen from mach_msg2_trap() since desc_count is passed as its own trap
778 * argument.
779 */
780 assert(option64 & MACH64_MACH_MSG2);
781 return MACH_SEND_TOO_LARGE;
782 }
783
784 /*
785 * Now that we have validated msg_send_size, aux_send_size and desc_count,
786 * copy in the message.
787 */
788 mr = ipc_kmsg_get_from_user(msg_addr, msg_send_size, (aux_send_size == 0) ?
789 0 : aux_addr, aux_send_size, user_header, desc_count, option64, &kmsg);
790
791 if (mr != MACH_MSG_SUCCESS) {
792 return mr;
793 }
794
795 KERNEL_DEBUG_CONSTANT(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_LINK) | DBG_FUNC_NONE,
796 (uintptr_t)msg_addr,
797 VM_KERNEL_ADDRPERM((uintptr_t)kmsg),
798 0, 0, 0);
799
800 /* holding kmsg ref */
801 mr = ipc_kmsg_copyin_from_user(kmsg, space, map, priority,
802 &option64, /* may add MACH64_SEND_ALWAYS option */
803 filter_nonfatal);
804
805 if (mr != MACH_MSG_SUCCESS) {
806 ipc_kmsg_free(kmsg);
807 return mr;
808 }
809
810 mr = ipc_kmsg_send(kmsg, option64, msg_timeout);
811
812 if (mr != MACH_MSG_SUCCESS) {
813 /* we still have the kmsg */
814 mr |= ipc_kmsg_copyout_pseudo(kmsg, space, map);
815 (void)ipc_kmsg_put_to_user(kmsg, option64, msg_addr, msg_send_size,
816 (aux_send_size == 0) ? 0 : aux_addr, aux_send_size, 0, NULL, NULL);
817 /* kmsg is freed */
818 }
819
820 return mr;
821 }
822
823 /*
824 * Routine: mach_msg_trap_receive [internal]
825 * Purpose:
826 * Receive a message.
827 * Conditions:
828 * MACH_RCV_MSG is set.
829 * max_{msg, aux}_rcv_size are already validated.
830 * Returns:
831 * All of mach_msg_receive error codes.
832 */
833 static mach_msg_return_t
mach_msg_trap_receive(mach_vm_address_t msg_addr,mach_vm_address_t aux_addr,mach_msg_option64_t option64,mach_msg_timeout_t msg_timeout,mach_port_name_t sync_send,mach_msg_size_t max_msg_rcv_size,mach_msg_size_t max_aux_rcv_size,mach_port_name_t rcv_name)834 mach_msg_trap_receive(
835 /* shared args between send and receive */
836 mach_vm_address_t msg_addr,
837 mach_vm_address_t aux_addr, /* 0 if not vector send/rcv */
838 mach_msg_option64_t option64,
839 mach_msg_timeout_t msg_timeout,
840 mach_port_name_t sync_send,
841 /* msg receive args */
842 mach_msg_size_t max_msg_rcv_size,
843 mach_msg_size_t max_aux_rcv_size, /* 0 if not vector send/rcv */
844 mach_port_name_t rcv_name)
845 {
846 ipc_object_t object;
847
848 thread_t self = current_thread();
849 ipc_space_t space = current_space();
850 mach_msg_return_t mr = MACH_MSG_SUCCESS;
851
852 assert(option64 & MACH64_RCV_MSG);
853
854 mr = ipc_mqueue_copyin(space, rcv_name, &object);
855 if (mr != MACH_MSG_SUCCESS) {
856 return mr;
857 }
858 /* hold ref for object */
859
860 if (sync_send != MACH_PORT_NULL) {
861 ipc_port_t special_reply_port = ip_object_to_port(object);
862 /* link the special reply port to the destination */
863 mr = mach_msg_rcv_link_special_reply_port(special_reply_port, sync_send);
864 if (mr != MACH_MSG_SUCCESS) {
865 io_release(object);
866 return mr;
867 }
868 }
869
870 /* Set up message proper receive params on thread */
871 self->ith_msg_addr = msg_addr;
872 self->ith_max_msize = max_msg_rcv_size;
873 self->ith_msize = 0;
874
875 /* Set up aux data receive params on thread */
876 self->ith_aux_addr = (max_aux_rcv_size == 0) ? 0 : aux_addr;
877 self->ith_max_asize = max_aux_rcv_size;
878 self->ith_asize = 0;
879
880 self->ith_object = object;
881 self->ith_option = option64;
882 self->ith_receiver_name = MACH_PORT_NULL;
883 self->ith_knote = ITH_KNOTE_NULL;
884
885 ipc_mqueue_receive(io_waitq(object),
886 option64, max_msg_rcv_size,
887 max_aux_rcv_size, msg_timeout,
888 THREAD_ABORTSAFE, /* continuation ? */ true);
889 /* NOTREACHED if thread started waiting */
890
891 if ((option64 & MACH_RCV_TIMEOUT) && msg_timeout == 0) {
892 thread_poll_yield(self);
893 }
894
895 mr = mach_msg_receive_results();
896 /* release ref on ith_object */
897
898 return mr;
899 }
900
901 /*
902 * Routine: mach_msg_overwrite_trap [mach trap]
903 * Purpose:
904 * Possibly send a message; possibly receive a message.
905 *
906 * /!\ Deprecated /!\
907 * No longer supported on embedded and will be removed from macOS.
908 * Use mach_msg2_trap() instead.
909 * Conditions:
910 * Nothing locked.
911 * The 'priority' is only a QoS if MACH_SEND_OVERRIDE is passed -
912 * otherwise, it is a port name.
913 * Returns:
914 * All of mach_msg_send and mach_msg_receive error codes.
915 */
916 mach_msg_return_t
mach_msg_overwrite_trap(struct mach_msg_overwrite_trap_args * args)917 mach_msg_overwrite_trap(
918 struct mach_msg_overwrite_trap_args *args)
919 {
920 #if XNU_TARGET_OS_OSX || XNU_TARGET_OS_IOS
921 mach_msg_return_t mr;
922 bool filter_nonfatal;
923
924 mach_vm_address_t msg_addr = args->msg;
925 mach_msg_option_t option32 = args->option;
926 mach_msg_size_t send_size = args->send_size;
927 mach_msg_size_t rcv_size = args->rcv_size;
928 mach_port_name_t rcv_name = args->rcv_name;
929 mach_msg_timeout_t msg_timeout = args->timeout;
930 mach_msg_priority_t priority = args->priority;
931 mach_vm_address_t rcv_msg_addr = args->rcv_msg;
932
933 mach_msg_user_header_t user_header = {};
934 mach_msg_size_t desc_count = 0;
935 mach_port_name_t sync_send = MACH_PORT_NULL;
936
937 option32 &= MACH_MSG_OPTION_USER;
938 /*
939 * MACH_SEND_FILTER_NONFATAL is aliased to MACH_SEND_ALWAYS kernel
940 * flag. Unset it as early as possible.
941 */
942 filter_nonfatal = (option32 & MACH_SEND_FILTER_NONFATAL);
943 option32 &= ~MACH_SEND_FILTER_NONFATAL;
944
945 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
946
947 if (option32 & MACH_SEND_MSG) {
948 mr = mach_msg_copyin_user_header(msg_addr, send_size, &user_header, &desc_count);
949 if (mr != MACH_MSG_SUCCESS) {
950 return mr;
951 }
952 }
953
954 if (option32 & MACH_SEND_MSG) {
955 /* send_size is bound checked */
956 mr = mach_msg_trap_send(msg_addr, 0, (mach_msg_option64_t)option32,
957 msg_timeout, priority, filter_nonfatal,
958 user_header, send_size, 0, desc_count);
959 }
960
961 /* If send failed, skip receive */
962 if (mr != MACH_MSG_SUCCESS) {
963 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
964 goto end;
965 }
966
967 if (option32 & MACH_RCV_MSG) {
968 /*
969 * Although just the presence of MACH_RCV_SYNC_WAIT and absence of
970 * MACH_SEND_OVERRIDE should imply that 'priority' is a valid port name
971 * to link, in practice older userspace is dependent on
972 * MACH_SEND_SYNC_OVERRIDE also excluding this path.
973 */
974 if ((option32 & MACH_RCV_SYNC_WAIT) &&
975 !(option32 & (MACH_SEND_OVERRIDE | MACH_SEND_MSG)) &&
976 !(option32 & MACH_SEND_SYNC_OVERRIDE)) {
977 sync_send = (mach_port_name_t)priority;
978 }
979
980 if (rcv_msg_addr != 0) {
981 msg_addr = rcv_msg_addr;
982 }
983 mr = mach_msg_trap_receive(msg_addr, 0, (mach_msg_option64_t)option32,
984 msg_timeout, sync_send, rcv_size, 0, rcv_name);
985 }
986
987 end:
988 /* unblock call is idempotent */
989 ipc_port_thread_group_unblocked();
990 return mr;
991 #else
992 (void)args;
993 return KERN_NOT_SUPPORTED;
994 #endif /* XNU_TARGET_OS_OSX || XNU_TARGET_OS_IOS */
995 }
996
997 /*
998 * Routine: mach_msg_trap [mach trap]
999 * Purpose:
1000 * Possibly send a message; possibly receive a message.
1001 *
1002 * /!\ Deprecated /!\
1003 * No longer supported on embedded and will be removed from macOS.
1004 * Use mach_msg2_trap() instead.
1005 * Conditions:
1006 * Nothing locked.
1007 * Returns:
1008 * All of mach_msg_send and mach_msg_receive error codes.
1009 */
1010 mach_msg_return_t
mach_msg_trap(struct mach_msg_overwrite_trap_args * args)1011 mach_msg_trap(
1012 struct mach_msg_overwrite_trap_args *args)
1013 {
1014 args->rcv_msg = (mach_vm_address_t)0;
1015
1016 return mach_msg_overwrite_trap(args);
1017 }
1018
1019 static inline bool
mach_msg2_cfi_option_valid(mach_msg_option64_t option64)1020 mach_msg2_cfi_option_valid(
1021 mach_msg_option64_t option64)
1022 {
1023 option64 &= MACH64_MSG_OPTION_CFI_MASK;
1024
1025 /* mach_msg2() calls must have _exactly_ one of three options set */
1026 return (option64 != 0) && ((option64 & (option64 - 1)) == 0);
1027 }
1028
1029 /*
1030 * Routine: mach_msg2_trap [mach trap]
1031 * Purpose:
1032 * Modern mach_msg_trap() with vector message and CFI support.
1033 * Conditions:
1034 * Nothing locked.
1035 * Returns:
1036 * All of mach_msg_send and mach_msg_receive error codes.
1037 */
1038 mach_msg_return_t
mach_msg2_trap(struct mach_msg2_trap_args * args)1039 mach_msg2_trap(
1040 struct mach_msg2_trap_args *args)
1041 {
1042 mach_port_name_t rcv_name, sync_send;
1043 mach_vm_address_t msg_addr, aux_addr;
1044 mach_msg_size_t msg_send_size, max_msg_rcv_size,
1045 aux_send_size, max_aux_rcv_size,
1046 send_data_cnt, rcv_data_cnt;
1047 mach_msg_size_t desc_count;
1048 mach_msg_priority_t priority;
1049 bool filter_nonfatal, vector_msg;
1050
1051 mach_vm_address_t data_addr = args->data;
1052 mach_msg_option64_t option64 = args->options;
1053 /* packed arguments, LO_BITS_and_HI_BITS */
1054 uint64_t mb_ss = args->msgh_bits_and_send_size;
1055 uint64_t mr_lp = args->msgh_remote_and_local_port;
1056 uint64_t mv_id = args->msgh_voucher_and_id;
1057 uint64_t dc_rn = args->desc_count_and_rcv_name;
1058 uint64_t rs_pr = args->rcv_size_and_priority;
1059
1060 mach_msg_timeout_t msg_timeout = (mach_msg_timeout_t)args->timeout;
1061 mach_msg_return_t mr = MACH_MSG_SUCCESS;
1062
1063 mach_msg_user_header_t user_header = {};
1064 mach_msg_vector_t msg_vec = {}, aux_vec = {}; /* zeroed */
1065
1066 option64 &= MACH64_MSG_OPTION_USER;
1067 option64 |= MACH64_MACH_MSG2;
1068
1069 /*
1070 * MACH_SEND_FILTER_NONFATAL is aliased to MACH_SEND_ALWAYS kernel
1071 * flag. Unset it as early as possible.
1072 */
1073 filter_nonfatal = (option64 & MACH64_SEND_FILTER_NONFATAL);
1074 option64 &= ~MACH64_SEND_FILTER_NONFATAL;
1075 vector_msg = (option64 & MACH64_MSG_VECTOR);
1076
1077 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_START);
1078
1079 /* kobject calls must be scalar calls (hence no aux data) */
1080 if (__improbable((option64 & MACH64_SEND_KOBJECT_CALL) && vector_msg)) {
1081 mach_port_guard_exception(0, 0, 0, kGUARD_EXC_INVALID_OPTIONS);
1082 return MACH_SEND_INVALID_OPTIONS;
1083 }
1084
1085 if (vector_msg) {
1086 send_data_cnt = (mb_ss >> 32);
1087 rcv_data_cnt = (mach_msg_size_t)rs_pr;
1088
1089 mr = mach_msg_copyin_data_vectors((mach_msg_vector_t *)data_addr,
1090 MAX(send_data_cnt, rcv_data_cnt), option64, &msg_vec, &aux_vec);
1091
1092 if (mr != MACH_MSG_SUCCESS) {
1093 return mr;
1094 }
1095 }
1096
1097 if (option64 & MACH64_SEND_MSG) {
1098 if (vector_msg) {
1099 /*
1100 * only validate msg send related arguments. bad receive args
1101 * do not stop us from sending during combined send/rcv.
1102 */
1103 mr = mach_msg_validate_data_vectors(&msg_vec, &aux_vec, send_data_cnt,
1104 option64, /* sending? */ TRUE);
1105 if (mr != MACH_MSG_SUCCESS) {
1106 return mr;
1107 }
1108 /* msg_vec.msgv_send_size is bound checked */
1109 }
1110
1111 /* desc_count is bound checked in mach_msg_trap_send() */
1112 desc_count = (mach_msg_size_t)dc_rn;
1113 priority = (mach_msg_priority_t)(rs_pr >> 32);
1114
1115 msg_addr = vector_msg ? msg_vec.msgv_data : data_addr;
1116 /* mb_ss is bound checked in mach_msg_trap_send() */
1117 msg_send_size = vector_msg ? msg_vec.msgv_send_size : (mb_ss >> 32);
1118
1119 /* Nullable for vector send without aux */
1120 aux_send_size = vector_msg ? aux_vec.msgv_send_size : 0;
1121 aux_addr = (vector_msg && aux_send_size) ? aux_vec.msgv_data : 0;
1122
1123 user_header = (mach_msg_user_header_t){
1124 .msgh_bits = (mach_msg_bits_t) (mb_ss),
1125 .msgh_size = (mach_msg_size_t) (msg_send_size),
1126 .msgh_remote_port = (mach_port_name_t) (mr_lp),
1127 .msgh_local_port = (mach_port_name_t) (mr_lp >> 32),
1128 .msgh_voucher_port = (mach_port_name_t) (mv_id),
1129 .msgh_id = (mach_msg_id_t) (mv_id >> 32),
1130 };
1131
1132 /*
1133 * if it's not to a message queue and user attempts to send aux data,
1134 * something fishy is going on.
1135 */
1136 if (__improbable(!(option64 & MACH64_SEND_MQ_CALL) && (aux_send_size != 0))) {
1137 mach_port_guard_exception(0, 0, 0, kGUARD_EXC_INVALID_OPTIONS);
1138 return MACH_SEND_INVALID_OPTIONS;
1139 }
1140 /* must have _exactly_ one of three cfi options set */
1141 if (__improbable(!mach_msg2_cfi_option_valid(option64))) {
1142 mach_port_guard_exception(0, 0, 0, kGUARD_EXC_INVALID_OPTIONS);
1143 return MACH_SEND_INVALID_OPTIONS;
1144 }
1145
1146 /* for scalar send: msg_send_size (from mb_ss) has not been bound checked */
1147 mr = mach_msg_trap_send(msg_addr, aux_addr, option64,
1148 msg_timeout, priority, filter_nonfatal,
1149 user_header, msg_send_size,
1150 aux_send_size, desc_count);
1151 }
1152
1153 /* if send failed, skip receive */
1154 if (mr != MACH_MSG_SUCCESS) {
1155 KDBG(MACHDBG_CODE(DBG_MACH_IPC, MACH_IPC_KMSG_INFO) | DBG_FUNC_END, mr);
1156 goto end;
1157 }
1158
1159 if (option64 & MACH64_RCV_MSG) {
1160 if (vector_msg) {
1161 /* only validate msg receive related arguments */
1162 mr = mach_msg_validate_data_vectors(&msg_vec, &aux_vec, rcv_data_cnt,
1163 option64, /* sending? */ FALSE);
1164 if (mr != MACH_MSG_SUCCESS) {
1165 goto end;
1166 }
1167 }
1168 rcv_name = (mach_port_name_t)(dc_rn >> 32);
1169
1170 msg_addr = vector_msg ?
1171 (msg_vec.msgv_rcv_addr ? msg_vec.msgv_rcv_addr : msg_vec.msgv_data) :
1172 data_addr;
1173 max_msg_rcv_size = vector_msg ? msg_vec.msgv_rcv_size : (mach_msg_size_t)rs_pr;
1174
1175 /* Nullable for vector receive without aux */
1176 max_aux_rcv_size = vector_msg ? aux_vec.msgv_rcv_size : 0;
1177 aux_addr = (vector_msg && max_aux_rcv_size) ?
1178 (aux_vec.msgv_rcv_addr ? aux_vec.msgv_rcv_addr : aux_vec.msgv_data) :
1179 0;
1180
1181 if (option64 & MACH64_RCV_SYNC_WAIT) {
1182 /* use msgh_remote_port as sync send boosting port */
1183 sync_send = (mach_port_name_t)mr_lp;
1184 } else {
1185 sync_send = MACH_PORT_NULL;
1186 }
1187
1188 mr = mach_msg_trap_receive(msg_addr, aux_addr, option64,
1189 msg_timeout, sync_send, max_msg_rcv_size,
1190 max_aux_rcv_size, rcv_name);
1191 }
1192
1193 end:
1194 /* unblock call is idempotent */
1195 ipc_port_thread_group_unblocked();
1196 return mr;
1197 }
1198
1199 /*
1200 * Routine: mach_msg_rcv_link_special_reply_port
1201 * Purpose:
1202 * Link the special reply port(rcv right) to the
1203 * other end of the sync ipc channel.
1204 * Conditions:
1205 * Nothing locked.
1206 * Returns:
1207 * None.
1208 */
1209 static mach_msg_return_t
mach_msg_rcv_link_special_reply_port(ipc_port_t special_reply_port,mach_port_name_t dest_name_port)1210 mach_msg_rcv_link_special_reply_port(
1211 ipc_port_t special_reply_port,
1212 mach_port_name_t dest_name_port)
1213 {
1214 ipc_port_t dest_port = IP_NULL;
1215 kern_return_t kr;
1216
1217 if (current_thread()->ith_special_reply_port != special_reply_port) {
1218 return MACH_RCV_INVALID_NOTIFY;
1219 }
1220
1221 /* Copyin the destination port */
1222 if (!MACH_PORT_VALID(dest_name_port)) {
1223 return MACH_RCV_INVALID_NOTIFY;
1224 }
1225
1226 kr = ipc_port_translate_send(current_space(), dest_name_port, &dest_port);
1227 if (kr == KERN_SUCCESS) {
1228 ip_reference(dest_port);
1229 ip_mq_unlock(dest_port);
1230
1231 /*
1232 * The receive right of dest port might have gone away,
1233 * do not fail the receive in that case.
1234 */
1235 ipc_port_link_special_reply_port(special_reply_port,
1236 dest_port, FALSE);
1237
1238 ip_release(dest_port);
1239 }
1240 return MACH_MSG_SUCCESS;
1241 }
1242
1243 /*
1244 * Routine: mach_msg_receive_results_complete
1245 * Purpose:
1246 * Get thread's turnstile back from the object and
1247 * if object is a special reply port then reset its
1248 * linkage.
1249 * Condition:
1250 * Nothing locked.
1251 * Returns:
1252 * None.
1253 */
1254 void
mach_msg_receive_results_complete(ipc_object_t object)1255 mach_msg_receive_results_complete(ipc_object_t object)
1256 {
1257 thread_t self = current_thread();
1258 ipc_port_t port = IPC_PORT_NULL;
1259 boolean_t get_turnstile = (self->turnstile == TURNSTILE_NULL);
1260
1261 if (io_otype(object) == IOT_PORT) {
1262 port = ip_object_to_port(object);
1263 } else {
1264 assert(self->turnstile != TURNSTILE_NULL);
1265 return;
1266 }
1267
1268 uint8_t flags = IPC_PORT_ADJUST_SR_ALLOW_SYNC_LINKAGE;
1269
1270 /*
1271 * Don't clear the ip_srp_msg_sent bit if...
1272 */
1273 if (!((self->ith_state == MACH_RCV_TOO_LARGE && self->ith_option & MACH_RCV_LARGE) || //msg was too large and the next receive will get it
1274 self->ith_state == MACH_RCV_INTERRUPTED ||
1275 self->ith_state == MACH_RCV_TIMED_OUT ||
1276 self->ith_state == MACH_RCV_PORT_CHANGED ||
1277 self->ith_state == MACH_PEEK_READY)) {
1278 flags |= IPC_PORT_ADJUST_SR_RECEIVED_MSG;
1279 }
1280
1281 if (port->ip_specialreply || get_turnstile) {
1282 ip_mq_lock(port);
1283 ipc_port_adjust_special_reply_port_locked(port, NULL,
1284 flags, get_turnstile);
1285 /* port unlocked */
1286 }
1287 assert(self->turnstile != TURNSTILE_NULL);
1288 /* thread now has a turnstile */
1289 }
1290
1291 /*
1292 * Routine: msg_receive_error [internal]
1293 * Purpose:
1294 * Builds a minimal header/trailer and copies it to
1295 * the user message buffer. Invoked when in the case of a
1296 * MACH_RCV_TOO_LARGE or MACH_RCV_BODY_ERROR error.
1297 * Conditions:
1298 * ipc_kmsg_copyout_body() has not been called. ipc_kmsg_add_trailer()
1299 * relies on this condition to calculate trailer address.
1300 * Nothing locked. kmsg is freed upon return.
1301 * Returns:
1302 * MACH_MSG_SUCCESS minimal header/trailer copied
1303 * MACH_RCV_INVALID_DATA copyout to user buffer failed
1304 */
1305 static mach_msg_return_t
msg_receive_error(ipc_kmsg_t kmsg,mach_msg_option64_t option64,mach_vm_address_t msg_rcv_addr,mach_msg_size_t max_msg_size,mach_vm_address_t aux_rcv_addr,mach_msg_size_t max_aux_size,mach_port_seqno_t seqno,ipc_space_t space,mach_msg_size_t * sizep,mach_msg_size_t * aux_sizep)1306 msg_receive_error(
1307 ipc_kmsg_t kmsg,
1308 mach_msg_option64_t option64,
1309 mach_vm_address_t msg_rcv_addr,
1310 mach_msg_size_t max_msg_size,
1311 mach_vm_address_t aux_rcv_addr, /* Nullable */
1312 mach_msg_size_t max_aux_size, /* Nullable */
1313 mach_port_seqno_t seqno,
1314 ipc_space_t space,
1315 mach_msg_size_t *sizep,
1316 mach_msg_size_t *aux_sizep)
1317 {
1318 mach_vm_address_t context;
1319 mach_msg_trailer_size_t trailer_size;
1320 thread_t self = current_thread();
1321 mach_msg_header_t *hdr = ikm_header(kmsg);
1322
1323 context = hdr->msgh_remote_port->ip_context;
1324
1325 /*
1326 * Copy out the destination port in the message.
1327 * Destroy all other rights and memory in the message.
1328 */
1329 ipc_kmsg_copyout_dest_to_user(kmsg, space);
1330
1331 /*
1332 * Build a minimal message with the requested trailer.
1333 */
1334 hdr->msgh_size = sizeof(mach_msg_header_t);
1335 ipc_kmsg_init_trailer(kmsg, TASK_NULL);
1336
1337 trailer_size = ipc_kmsg_trailer_size((mach_msg_option_t)option64, self);
1338 ipc_kmsg_add_trailer(kmsg, space, (mach_msg_option_t)option64, self,
1339 seqno, TRUE, context);
1340
1341 /* Build a minimal aux data header for vector kmsg with aux */
1342 mach_msg_aux_header_t aux_header = {
1343 .msgdh_size = sizeof(mach_msg_aux_header_t)
1344 };
1345 ipc_kmsg_set_aux_data_header(kmsg, &aux_header);
1346
1347 /*
1348 * Copy the message to user space and return the size
1349 * (note that ipc_kmsg_put_to_user may also adjust the actual
1350 * msg and aux size copied out to user-space).
1351 */
1352 if (ipc_kmsg_put_to_user(kmsg, option64, msg_rcv_addr,
1353 max_msg_size, aux_rcv_addr, max_aux_size,
1354 trailer_size, sizep, aux_sizep) == MACH_RCV_INVALID_DATA) {
1355 return MACH_RCV_INVALID_DATA;
1356 } else {
1357 return MACH_MSG_SUCCESS;
1358 }
1359 }
1360
1361
1362 SECURITY_READ_ONLY_LATE(struct mach_msg_filter_callbacks) mach_msg_filter_callbacks;
1363
1364 kern_return_t
mach_msg_filter_register_callback(const struct mach_msg_filter_callbacks * callbacks)1365 mach_msg_filter_register_callback(
1366 const struct mach_msg_filter_callbacks *callbacks)
1367 {
1368 size_t size = 0;
1369
1370 if (callbacks == NULL) {
1371 return KERN_INVALID_ARGUMENT;
1372 }
1373 if (mach_msg_filter_callbacks.fetch_filter_policy != NULL) {
1374 /* double init */
1375 return KERN_FAILURE;
1376 }
1377
1378 if (callbacks->version >= MACH_MSG_FILTER_CALLBACKS_VERSION_0) {
1379 /* check for missing v0 callbacks */
1380 if (callbacks->fetch_filter_policy == NULL) {
1381 return KERN_INVALID_ARGUMENT;
1382 }
1383 size = offsetof(struct mach_msg_filter_callbacks, alloc_service_port_sblabel);
1384 }
1385
1386 if (callbacks->version >= MACH_MSG_FILTER_CALLBACKS_VERSION_1) {
1387 if (callbacks->alloc_service_port_sblabel == NULL ||
1388 callbacks->dealloc_service_port_sblabel == NULL ||
1389 callbacks->derive_sblabel_from_service_port == NULL ||
1390 callbacks->get_connection_port_filter_policy == NULL ||
1391 callbacks->retain_sblabel == NULL) {
1392 return KERN_INVALID_ARGUMENT;
1393 }
1394 size = sizeof(struct mach_msg_filter_callbacks);
1395 }
1396
1397 if (callbacks->version > MACH_MSG_FILTER_CALLBACKS_VERSION_1) {
1398 /* invalid version */
1399 return KERN_INVALID_ARGUMENT;
1400 }
1401
1402 memcpy(&mach_msg_filter_callbacks, callbacks, size);
1403 return KERN_SUCCESS;
1404 }
1405
1406 /* This function should only be called if the task and port allow message filtering */
1407 boolean_t
mach_msg_fetch_filter_policy(void * port_label,mach_msg_id_t msgh_id,mach_msg_filter_id * fid)1408 mach_msg_fetch_filter_policy(
1409 void *port_label,
1410 mach_msg_id_t msgh_id,
1411 mach_msg_filter_id *fid)
1412 {
1413 boolean_t ret = TRUE;
1414
1415 if (mach_msg_fetch_filter_policy_callback == NULL) {
1416 *fid = MACH_MSG_FILTER_POLICY_ALLOW;
1417 return true;
1418 }
1419 ret = mach_msg_fetch_filter_policy_callback(current_task(), port_label, msgh_id, fid);
1420
1421 return ret;
1422 }
1423