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