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