xref: /xnu-10063.121.3/osfmk/ipc/mach_msg.c (revision 2c2f96dc2b9a4408a43d3150ae9c105355ca3daa)
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 
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(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  */
414 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)415 mach_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  */
519 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)520 mach_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(msg_vecp, &data_vecs[MACH_MSGV_IDX_MSG], sizeof(mach_msg_vector_t));
549 
550 	if (cpin_count == MACH_MSGV_MAX_COUNT) {
551 		memcpy(aux_vecp, &data_vecs[MACH_MSGV_IDX_AUX], 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
559 static TUNABLE(bool, allow_legacy_mach_msg, "allow_legacy_mach_msg", false);
560 #endif /* DEVELOPMENT || DEBUG */
561 
562 extern char *proc_name_address(struct proc *p);
563 
564 CA_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 
572 static void
mach_msg_legacy_send_analytics(mach_msg_id_t msgh_id,uint32_t platform,uint32_t sdk)573 mach_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(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(msg_event->proc_name, proc_name, CA_PROCNAME_LEN);
591 	}
592 
593 	if (team_id) {
594 		strlcpy(msg_event->team_id, team_id, CA_TEAMID_MAX_LEN);
595 	}
596 
597 	if (signing_id) {
598 		strlcpy(msg_event->signing_id, signing_id, CA_SIGNINGID_MAX_LEN);
599 	}
600 
601 	CA_EVENT_SEND(ca_event);
602 }
603 
604 static bool
mach_msg_legacy_allowed(mach_msg_user_header_t * header)605 mach_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(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  */
692 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)693 mach_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(&user_base.header)) {
740 		mach_port_guard_exception(user_base.header.msgh_id, 0, 0, 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(header, &user_base, 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  */
771 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)772 mach_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, msg_send_size, (aux_send_size == 0) ?
836 	    0 : aux_addr, aux_send_size, user_header, desc_count, option64, &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 	    &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, 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, option64, msg_addr, msg_send_size,
863 		    (aux_send_size == 0) ? 0 : aux_addr, aux_send_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  */
880 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)881 mach_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, rcv_name, &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, 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_msg_rcv_size,
934 	    max_aux_rcv_size, 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  */
963 mach_msg_return_t
mach_msg_overwrite_trap(struct mach_msg_overwrite_trap_args * args)964 mach_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, send_size, &user_header, &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, 0, (mach_msg_option64_t)option32,
1004 		    msg_timeout, priority, filter_nonfatal,
1005 		    user_header, 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, 0, (mach_msg_option64_t)option32,
1031 		    msg_timeout, sync_send, rcv_size, 0, rcv_name);
1032 	}
1033 
1034 end:
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  */
1057 mach_msg_return_t
mach_msg_trap(struct mach_msg_overwrite_trap_args * args)1058 mach_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 
1066 static inline bool
mach_msg2_cfi_option_valid(mach_msg_option64_t option64)1067 mach_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  */
1085 mach_msg_return_t
mach_msg2_trap(struct mach_msg2_trap_args * args)1086 mach_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(0, 0, 0, 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((mach_msg_vector_t *)data_addr,
1137 		    MAX(send_data_cnt, rcv_data_cnt), option64, &msg_vec, &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, &aux_vec, 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(0, 0, 0, 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(0, 0, 0, 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, &aux_vec, 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 
1240 end:
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  */
1256 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)1257 mach_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(), dest_name_port, &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  */
1301 void
mach_msg_receive_results_complete(ipc_object_t object)1302 mach_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(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  */
1354 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)1355 msg_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((mach_msg_option_t)option64, self);
1387 	ipc_kmsg_add_trailer(kmsg, space, (mach_msg_option_t)option64, 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, &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, option64, msg_rcv_addr,
1402 	    max_msg_size, aux_rcv_addr, max_aux_size,
1403 	    trailer_size, sizep, aux_sizep) == MACH_RCV_INVALID_DATA) {
1404 		return MACH_RCV_INVALID_DATA;
1405 	} else {
1406 		return MACH_MSG_SUCCESS;
1407 	}
1408 }
1409 
1410 
1411 SECURITY_READ_ONLY_LATE(struct mach_msg_filter_callbacks) mach_msg_filter_callbacks;
1412 
1413 kern_return_t
mach_msg_filter_register_callback(const struct mach_msg_filter_callbacks * callbacks)1414 mach_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(&mach_msg_filter_callbacks, callbacks, size);
1452 	return KERN_SUCCESS;
1453 }
1454 
1455 /* This function should only be called if the task and port allow message filtering */
1456 boolean_t
mach_msg_fetch_filter_policy(void * port_label,mach_msg_id_t msgh_id,mach_msg_filter_id * fid)1457 mach_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