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