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