xref: /xnu-8019.80.24/osfmk/ipc/ipc_port.c (revision a325d9c4a84054e40bbe985afedcb50ab80993ea)
1 /*
2  * Copyright (c) 2000-2019 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_FREE_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  */
62 /*
63  */
64 /*
65  *	File:	ipc/ipc_port.c
66  *	Author:	Rich Draves
67  *	Date:	1989
68  *
69  *	Functions to manipulate IPC ports.
70  */
71 
72 #include <mach_assert.h>
73 
74 #include <mach/port.h>
75 #include <mach/kern_return.h>
76 #include <kern/backtrace.h>
77 #include <kern/debug.h>
78 #include <kern/ipc_kobject.h>
79 #include <kern/kcdata.h>
80 #include <kern/misc_protos.h>
81 #include <kern/policy_internal.h>
82 #include <kern/thread.h>
83 #include <kern/waitq.h>
84 #include <ipc/ipc_entry.h>
85 #include <ipc/ipc_space.h>
86 #include <ipc/ipc_object.h>
87 #include <ipc/ipc_right.h>
88 #include <ipc/ipc_port.h>
89 #include <ipc/ipc_pset.h>
90 #include <ipc/ipc_kmsg.h>
91 #include <ipc/ipc_mqueue.h>
92 #include <ipc/ipc_notify.h>
93 #include <ipc/ipc_table.h>
94 #include <ipc/ipc_importance.h>
95 #include <machine/limits.h>
96 #include <kern/turnstile.h>
97 #include <kern/machine.h>
98 
99 #include <security/mac_mach_internal.h>
100 #include <ipc/ipc_service_port.h>
101 
102 #include <string.h>
103 
104 static TUNABLE(bool, prioritize_launch, "prioritize_launch", true);
105 TUNABLE_WRITEABLE(int, ipc_portbt, "ipc_portbt", false);
106 
107 extern zone_t ipc_kobject_label_zone;
108 
109 LCK_SPIN_DECLARE_ATTR(ipc_port_multiple_lock_data, &ipc_lck_grp, &ipc_lck_attr);
110 ipc_port_timestamp_t ipc_port_timestamp_data;
111 
112 #if     MACH_ASSERT
113 static void ipc_port_init_debug(ipc_port_t, void *fp);
114 #endif  /* MACH_ASSERT */
115 
116 void __abortlike
__ipc_port_inactive_panic(ipc_port_t port)117 __ipc_port_inactive_panic(ipc_port_t port)
118 {
119 	panic("Using inactive port %p", port);
120 }
121 
122 static __abortlike void
__ipc_port_translate_receive_panic(ipc_space_t space,ipc_port_t port)123 __ipc_port_translate_receive_panic(ipc_space_t space, ipc_port_t port)
124 {
125 	panic("found receive right in space %p for port %p owned by space %p",
126 	    space, port, ip_get_receiver(port));
127 }
128 
129 static void
130 ipc_port_send_turnstile_recompute_push_locked(
131 	ipc_port_t port);
132 
133 static thread_t
134 ipc_port_get_watchport_inheritor(
135 	ipc_port_t port);
136 
137 void
ipc_port_release(ipc_port_t port)138 ipc_port_release(ipc_port_t port)
139 {
140 	ip_release(port);
141 }
142 
143 void
ipc_port_reference(ipc_port_t port)144 ipc_port_reference(ipc_port_t port)
145 {
146 	ip_reference(port);
147 }
148 
149 /*
150  *	Routine:	ipc_port_timestamp
151  *	Purpose:
152  *		Retrieve a timestamp value.
153  */
154 
155 ipc_port_timestamp_t
ipc_port_timestamp(void)156 ipc_port_timestamp(void)
157 {
158 	return OSIncrementAtomic(&ipc_port_timestamp_data);
159 }
160 
161 
162 /*
163  *	Routine:	ipc_port_translate_send
164  *	Purpose:
165  *		Look up a send right in a space.
166  *	Conditions:
167  *		Nothing locked before.  If successful, the object
168  *		is returned active and locked.  The caller doesn't get a ref.
169  *	Returns:
170  *		KERN_SUCCESS		Object returned locked.
171  *		KERN_INVALID_TASK	The space is dead.
172  *		KERN_INVALID_NAME	The name doesn't denote a right
173  *		KERN_INVALID_RIGHT	Name doesn't denote the correct right
174  */
175 kern_return_t
ipc_port_translate_send(ipc_space_t space,mach_port_name_t name,ipc_port_t * portp)176 ipc_port_translate_send(
177 	ipc_space_t                     space,
178 	mach_port_name_t                name,
179 	ipc_port_t                     *portp)
180 {
181 	ipc_port_t port = IP_NULL;
182 	ipc_object_t object;
183 	kern_return_t kr;
184 
185 	kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_SEND, &object);
186 	if (kr == KERN_SUCCESS) {
187 		port = ip_object_to_port(object);
188 	}
189 	*portp = port;
190 	return kr;
191 }
192 
193 
194 /*
195  *	Routine:	ipc_port_translate_receive
196  *	Purpose:
197  *		Look up a receive right in a space.
198  *		Performs some minimal security checks against tampering.
199  *	Conditions:
200  *		Nothing locked before.  If successful, the object
201  *		is returned active and locked.  The caller doesn't get a ref.
202  *	Returns:
203  *		KERN_SUCCESS		Object returned locked.
204  *		KERN_INVALID_TASK	The space is dead.
205  *		KERN_INVALID_NAME	The name doesn't denote a right
206  *		KERN_INVALID_RIGHT	Name doesn't denote the correct right
207  */
208 kern_return_t
ipc_port_translate_receive(ipc_space_t space,mach_port_name_t name,ipc_port_t * portp)209 ipc_port_translate_receive(
210 	ipc_space_t                     space,
211 	mach_port_name_t                name,
212 	ipc_port_t                     *portp)
213 {
214 	ipc_port_t port = IP_NULL;
215 	ipc_object_t object;
216 	kern_return_t kr;
217 
218 	kr = ipc_object_translate(space, name, MACH_PORT_RIGHT_RECEIVE, &object);
219 	if (kr == KERN_SUCCESS) {
220 		/* object is locked */
221 		port = ip_object_to_port(object);
222 		if (!ip_in_space(port, space)) {
223 			__ipc_port_translate_receive_panic(space, port);
224 		}
225 	}
226 	*portp = port;
227 	return kr;
228 }
229 
230 
231 /*
232  *	Routine:	ipc_port_request_alloc
233  *	Purpose:
234  *		Try to allocate a request slot.
235  *		If successful, returns the request index.
236  *		Otherwise returns zero.
237  *	Conditions:
238  *		The port is locked and active.
239  *	Returns:
240  *		KERN_SUCCESS		A request index was found.
241  *		KERN_NO_SPACE		No index allocated.
242  */
243 
244 #if IMPORTANCE_INHERITANCE
245 kern_return_t
ipc_port_request_alloc(ipc_port_t port,mach_port_name_t name,ipc_port_t soright,boolean_t send_possible,boolean_t immediate,ipc_port_request_index_t * indexp,boolean_t * importantp)246 ipc_port_request_alloc(
247 	ipc_port_t                      port,
248 	mach_port_name_t                name,
249 	ipc_port_t                      soright,
250 	boolean_t                       send_possible,
251 	boolean_t                       immediate,
252 	ipc_port_request_index_t        *indexp,
253 	boolean_t                       *importantp)
254 #else
255 kern_return_t
256 ipc_port_request_alloc(
257 	ipc_port_t                      port,
258 	mach_port_name_t                name,
259 	ipc_port_t                      soright,
260 	boolean_t                       send_possible,
261 	boolean_t                       immediate,
262 	ipc_port_request_index_t        *indexp)
263 #endif /* IMPORTANCE_INHERITANCE */
264 {
265 	ipc_port_request_t ipr, table;
266 	ipc_port_request_index_t index;
267 	uintptr_t mask = 0;
268 
269 #if IMPORTANCE_INHERITANCE
270 	*importantp = FALSE;
271 #endif /* IMPORTANCE_INHERITANCE */
272 
273 	require_ip_active(port);
274 	assert(name != MACH_PORT_NULL);
275 	assert(soright != IP_NULL);
276 
277 	table = port->ip_requests;
278 
279 	if (table == IPR_NULL) {
280 		return KERN_NO_SPACE;
281 	}
282 
283 	index = table->ipr_next;
284 	if (index == 0) {
285 		return KERN_NO_SPACE;
286 	}
287 
288 	ipr = &table[index];
289 	assert(ipr->ipr_name == MACH_PORT_NULL);
290 
291 	table->ipr_next = ipr->ipr_next;
292 	ipr->ipr_name = name;
293 
294 	if (send_possible) {
295 		mask |= IPR_SOR_SPREQ_MASK;
296 		if (immediate) {
297 			mask |= IPR_SOR_SPARM_MASK;
298 			if (port->ip_sprequests == 0) {
299 				port->ip_sprequests = 1;
300 #if IMPORTANCE_INHERITANCE
301 				/* TODO: Live importance support in send-possible */
302 				if (port->ip_impdonation != 0 &&
303 				    port->ip_spimportant == 0 &&
304 				    (task_is_importance_donor(current_task()))) {
305 					*importantp = TRUE;
306 				}
307 #endif /* IMPORTANCE_INHERTANCE */
308 			}
309 		}
310 	}
311 	ipr->ipr_soright = IPR_SOR_MAKE(soright, mask);
312 
313 	*indexp = index;
314 
315 	return KERN_SUCCESS;
316 }
317 
318 /*
319  *	Routine:	ipc_port_request_grow
320  *	Purpose:
321  *		Grow a port's table of requests.
322  *	Conditions:
323  *		The port must be locked and active.
324  *		Nothing else locked; will allocate memory.
325  *		Upon return the port is unlocked.
326  *	Returns:
327  *		KERN_SUCCESS		Grew the table.
328  *		KERN_SUCCESS		Somebody else grew the table.
329  *		KERN_SUCCESS		The port died.
330  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate new table.
331  *		KERN_NO_SPACE		Couldn't grow to desired size
332  */
333 
334 kern_return_t
ipc_port_request_grow(ipc_port_t port,ipc_table_elems_t target_size)335 ipc_port_request_grow(
336 	ipc_port_t              port,
337 	ipc_table_elems_t       target_size)
338 {
339 	ipc_table_size_t its;
340 	ipc_port_request_t otable, ntable;
341 	require_ip_active(port);
342 
343 	otable = port->ip_requests;
344 	if (otable == IPR_NULL) {
345 		its = &ipc_table_requests[0];
346 	} else {
347 		its = otable->ipr_size + 1;
348 	}
349 
350 	if (target_size != ITS_SIZE_NONE) {
351 		if ((otable != IPR_NULL) &&
352 		    (target_size <= otable->ipr_size->its_size)) {
353 			ip_mq_unlock(port);
354 			return KERN_SUCCESS;
355 		}
356 		while ((its->its_size) && (its->its_size < target_size)) {
357 			its++;
358 		}
359 		if (its->its_size == 0) {
360 			ip_mq_unlock(port);
361 			return KERN_NO_SPACE;
362 		}
363 	}
364 
365 	ip_reference(port);
366 	ip_mq_unlock(port);
367 
368 	if ((its->its_size == 0) ||
369 	    ((ntable = it_requests_alloc(its)) == IPR_NULL)) {
370 		ip_release(port);
371 		return KERN_RESOURCE_SHORTAGE;
372 	}
373 
374 	ip_mq_lock(port);
375 
376 	/*
377 	 *	Check that port is still active and that nobody else
378 	 *	has slipped in and grown the table on us.  Note that
379 	 *	just checking if the current table pointer == otable
380 	 *	isn't sufficient; must check ipr_size.
381 	 */
382 
383 	if (ip_active(port) && (port->ip_requests == otable) &&
384 	    ((otable == IPR_NULL) || (otable->ipr_size + 1 == its))) {
385 		ipc_table_size_t oits;
386 		ipc_table_elems_t osize, nsize;
387 		ipc_port_request_index_t free, i;
388 
389 		/* copy old table to new table */
390 
391 		if (otable != IPR_NULL) {
392 			oits = otable->ipr_size;
393 			osize = oits->its_size;
394 			free = otable->ipr_next;
395 
396 			(void) memcpy((void *)(ntable + 1),
397 			    (const void *)(otable + 1),
398 			    (osize - 1) * sizeof(struct ipc_port_request));
399 		} else {
400 			osize = 1;
401 			oits = 0;
402 			free = 0;
403 		}
404 
405 		nsize = its->its_size;
406 		assert(nsize > osize);
407 
408 		/* add new elements to the new table's free list */
409 
410 		for (i = osize; i < nsize; i++) {
411 			ipc_port_request_t ipr = &ntable[i];
412 
413 			ipr->ipr_name = MACH_PORT_NULL;
414 			ipr->ipr_next = free;
415 			free = i;
416 		}
417 
418 		ntable->ipr_next = free;
419 		ntable->ipr_size = its;
420 		port->ip_requests = ntable;
421 		ip_mq_unlock(port);
422 		ip_release(port);
423 
424 		if (otable != IPR_NULL) {
425 			it_requests_free(oits, otable);
426 		}
427 	} else {
428 		ip_mq_unlock(port);
429 		ip_release(port);
430 		it_requests_free(its, ntable);
431 	}
432 
433 	return KERN_SUCCESS;
434 }
435 
436 /*
437  *	Routine:	ipc_port_request_sparm
438  *	Purpose:
439  *		Arm delayed send-possible request.
440  *	Conditions:
441  *		The port must be locked and active.
442  *
443  *		Returns TRUE if the request was armed
444  *		(or armed with importance in that version).
445  */
446 
447 boolean_t
ipc_port_request_sparm(ipc_port_t port,__assert_only mach_port_name_t name,ipc_port_request_index_t index,mach_msg_option_t option,mach_msg_priority_t priority)448 ipc_port_request_sparm(
449 	ipc_port_t                      port,
450 	__assert_only mach_port_name_t  name,
451 	ipc_port_request_index_t        index,
452 	mach_msg_option_t               option,
453 	mach_msg_priority_t             priority)
454 {
455 	if (index != IE_REQ_NONE) {
456 		ipc_port_request_t ipr, table;
457 
458 		require_ip_active(port);
459 
460 		table = port->ip_requests;
461 		assert(table != IPR_NULL);
462 
463 		ipr = &table[index];
464 		assert(ipr->ipr_name == name);
465 
466 		/* Is there a valid destination? */
467 		if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
468 			ipr->ipr_soright = IPR_SOR_MAKE(ipr->ipr_soright, IPR_SOR_SPARM_MASK);
469 			port->ip_sprequests = 1;
470 
471 			if (option & MACH_SEND_OVERRIDE) {
472 				/* apply override to message queue */
473 				mach_msg_qos_t qos_ovr;
474 				if (mach_msg_priority_is_pthread_priority(priority)) {
475 					qos_ovr = _pthread_priority_thread_qos(priority);
476 				} else {
477 					qos_ovr = mach_msg_priority_overide_qos(priority);
478 				}
479 				if (qos_ovr) {
480 					ipc_mqueue_override_send_locked(&port->ip_messages, qos_ovr);
481 				}
482 			}
483 
484 #if IMPORTANCE_INHERITANCE
485 			if (((option & MACH_SEND_NOIMPORTANCE) == 0) &&
486 			    (port->ip_impdonation != 0) &&
487 			    (port->ip_spimportant == 0) &&
488 			    (((option & MACH_SEND_IMPORTANCE) != 0) ||
489 			    (task_is_importance_donor(current_task())))) {
490 				return TRUE;
491 			}
492 #else
493 			return TRUE;
494 #endif /* IMPORTANCE_INHERITANCE */
495 		}
496 	}
497 	return FALSE;
498 }
499 
500 /*
501  *	Routine:	ipc_port_request_type
502  *	Purpose:
503  *		Determine the type(s) of port requests enabled for a name.
504  *	Conditions:
505  *		The port must be locked or inactive (to avoid table growth).
506  *		The index must not be IE_REQ_NONE and for the name in question.
507  */
508 mach_port_type_t
ipc_port_request_type(ipc_port_t port,__assert_only mach_port_name_t name,ipc_port_request_index_t index)509 ipc_port_request_type(
510 	ipc_port_t                      port,
511 	__assert_only mach_port_name_t  name,
512 	ipc_port_request_index_t        index)
513 {
514 	ipc_port_request_t ipr, table;
515 	mach_port_type_t type = 0;
516 
517 	table = port->ip_requests;
518 	assert(table != IPR_NULL);
519 
520 	assert(index != IE_REQ_NONE);
521 	ipr = &table[index];
522 	assert(ipr->ipr_name == name);
523 
524 	if (IP_VALID(IPR_SOR_PORT(ipr->ipr_soright))) {
525 		type |= MACH_PORT_TYPE_DNREQUEST;
526 
527 		if (IPR_SOR_SPREQ(ipr->ipr_soright)) {
528 			type |= MACH_PORT_TYPE_SPREQUEST;
529 
530 			if (!IPR_SOR_SPARMED(ipr->ipr_soright)) {
531 				type |= MACH_PORT_TYPE_SPREQUEST_DELAYED;
532 			}
533 		}
534 	}
535 	return type;
536 }
537 
538 /*
539  *	Routine:	ipc_port_request_cancel
540  *	Purpose:
541  *		Cancel a dead-name/send-possible request and return the send-once right.
542  *	Conditions:
543  *		The port must be locked and active.
544  *		The index must not be IPR_REQ_NONE and must correspond with name.
545  */
546 
547 ipc_port_t
ipc_port_request_cancel(ipc_port_t port,__assert_only mach_port_name_t name,ipc_port_request_index_t index)548 ipc_port_request_cancel(
549 	ipc_port_t                      port,
550 	__assert_only mach_port_name_t  name,
551 	ipc_port_request_index_t        index)
552 {
553 	ipc_port_request_t ipr, table;
554 	ipc_port_t request = IP_NULL;
555 
556 	require_ip_active(port);
557 	table = port->ip_requests;
558 	assert(table != IPR_NULL);
559 
560 	assert(index != IE_REQ_NONE);
561 	ipr = &table[index];
562 	assert(ipr->ipr_name == name);
563 	request = IPR_SOR_PORT(ipr->ipr_soright);
564 
565 	/* return ipr to the free list inside the table */
566 	ipr->ipr_name = MACH_PORT_NULL;
567 	ipr->ipr_next = table->ipr_next;
568 	table->ipr_next = index;
569 
570 	return request;
571 }
572 
573 /*
574  *	Routine:	ipc_port_pdrequest
575  *	Purpose:
576  *		Make a port-deleted request, returning the
577  *		previously registered send-once right.
578  *		Just cancels the previous request if notify is IP_NULL.
579  *	Conditions:
580  *		The port is locked and active.  It is unlocked.
581  *		Consumes a ref for notify (if non-null), and
582  *		returns previous with a ref (if non-null).
583  */
584 
585 void
ipc_port_pdrequest(ipc_port_t port,ipc_port_t notify,ipc_port_t * previousp)586 ipc_port_pdrequest(
587 	ipc_port_t      port,
588 	ipc_port_t      notify,
589 	ipc_port_t      *previousp)
590 {
591 	ipc_port_t previous;
592 	require_ip_active(port);
593 
594 	previous = port->ip_pdrequest;
595 	port->ip_pdrequest = notify;
596 	ip_mq_unlock(port);
597 
598 	*previousp = previous;
599 }
600 
601 /*
602  *	Routine:	ipc_port_nsrequest
603  *	Purpose:
604  *		Make a no-senders request, returning the
605  *		previously registered send-once right.
606  *		Just cancels the previous request if notify is IP_NULL.
607  *	Conditions:
608  *		The port is locked and active.  It is unlocked.
609  *		Consumes a ref for notify (if non-null), and
610  *		returns previous with a ref (if non-null).
611  */
612 
613 void
ipc_port_nsrequest(ipc_port_t port,mach_port_mscount_t sync,ipc_port_t notify,ipc_port_t * previousp)614 ipc_port_nsrequest(
615 	ipc_port_t              port,
616 	mach_port_mscount_t     sync,
617 	ipc_port_t              notify,
618 	ipc_port_t              *previousp)
619 {
620 	ipc_port_t previous;
621 	mach_port_mscount_t mscount;
622 	require_ip_active(port);
623 
624 	assert(!ip_in_space(port, ipc_space_kernel));
625 	assert(!port->ip_kobject_nsrequest);
626 
627 	previous = port->ip_nsrequest;
628 	mscount = port->ip_mscount;
629 
630 
631 	if ((port->ip_srights == 0) && (sync <= mscount) &&
632 	    (notify != IP_NULL)) {
633 		port->ip_nsrequest = IP_NULL;
634 		ip_mq_unlock(port);
635 		ipc_notify_no_senders(notify, mscount, /* kobject */ false);
636 	} else {
637 		port->ip_nsrequest = notify;
638 		ip_mq_unlock(port);
639 	}
640 
641 	*previousp = previous;
642 }
643 
644 
645 /*
646  *	Routine:	ipc_port_clear_receiver
647  *	Purpose:
648  *		Prepares a receive right for transmission/destruction,
649  *		optionally performs mqueue destruction (with port lock held)
650  *
651  *	Conditions:
652  *		The port is locked and active.
653  *	Returns:
654  *		If should_destroy is TRUE, then the return value indicates
655  *		whether the caller needs to reap kmsg structures that should
656  *		be destroyed (by calling ipc_kmsg_reap_delayed)
657  *
658  *              If should_destroy is FALSE, this always returns FALSE
659  */
660 
661 boolean_t
ipc_port_clear_receiver(ipc_port_t port,boolean_t should_destroy)662 ipc_port_clear_receiver(
663 	ipc_port_t      port,
664 	boolean_t       should_destroy)
665 {
666 	ipc_mqueue_t    mqueue = &port->ip_messages;
667 	boolean_t       reap_messages = FALSE;
668 
669 	/*
670 	 * Pull ourselves out of any sets to which we belong.
671 	 * We hold the write space lock or the receive entry has
672 	 * been deleted, so even though this acquires and releases
673 	 * the port lock, we know we won't be added to any other sets.
674 	 */
675 	if (ip_in_pset(port)) {
676 		ipc_pset_remove_from_all_unlock(port);
677 		/* port unlocked */
678 		ip_mq_lock(port);
679 		assert(!ip_in_pset(port));
680 	}
681 
682 	/*
683 	 * Send anyone waiting on the port's queue directly away.
684 	 * Also clear the mscount, seqno, guard bits
685 	 */
686 	if (ip_in_a_space(port)) {
687 		ipc_mqueue_changed(ip_get_receiver(port), &port->ip_waitq);
688 	} else {
689 		ipc_mqueue_changed(NULL, &port->ip_waitq);
690 	}
691 	port->ip_mscount = 0;
692 	mqueue->imq_seqno = 0;
693 	port->ip_context = port->ip_guarded = port->ip_strict_guard = 0;
694 	/*
695 	 * clear the immovable bit so the port can move back to anyone listening
696 	 * for the port destroy notification
697 	 */
698 	port->ip_immovable_receive = 0;
699 
700 	if (should_destroy) {
701 		/*
702 		 * Mark the port and mqueue invalid, preventing further send/receive
703 		 * operations from succeeding. It's important for this to be
704 		 * done under the same lock hold as the ipc_mqueue_changed
705 		 * call to avoid additional threads blocking on an mqueue
706 		 * that's being destroyed.
707 		 *
708 		 * The port active bit needs to be guarded under mqueue lock for
709 		 * turnstiles
710 		 */
711 
712 		/* port transitions to INACTIVE state */
713 		io_bits_andnot(ip_to_object(port), IO_BITS_ACTIVE);
714 		port->ip_receiver_name = MACH_PORT_NULL;
715 		port->ip_timestamp = ipc_port_timestamp();
716 
717 		reap_messages = ipc_mqueue_destroy_locked(mqueue);
718 	} else {
719 		/* port transtions to IN-LIMBO state */
720 		port->ip_receiver_name = MACH_PORT_NULL;
721 		port->ip_destination = IP_NULL;
722 	}
723 
724 	return reap_messages;
725 }
726 
727 /*
728  *	Routine:	ipc_port_init
729  *	Purpose:
730  *		Initializes a newly-allocated port.
731  *
732  *		The memory is expected to be zero initialized (allocated with Z_ZERO).
733  */
734 
735 void
ipc_port_init(ipc_port_t port,ipc_space_t space,ipc_port_init_flags_t flags,mach_port_name_t name)736 ipc_port_init(
737 	ipc_port_t              port,
738 	ipc_space_t             space,
739 	ipc_port_init_flags_t   flags,
740 	mach_port_name_t        name)
741 {
742 	int policy = SYNC_POLICY_FIFO | SYNC_POLICY_TURNSTILE_PROXY;
743 
744 	/* the port has been 0 initialized when called */
745 
746 	if (flags & IPC_PORT_INIT_FILTER_MESSAGE) {
747 		io_bits_or(ip_to_object(port), IP_BIT_FILTER_MSG);
748 	}
749 	if (flags & IPC_PORT_INIT_LOCKED) {
750 		policy |= SYNC_POLICY_INIT_LOCKED;
751 	}
752 
753 	/* must be done first, many ip_* bits live inside the waitq */
754 	waitq_init(&port->ip_waitq, policy);
755 	if (flags & IPC_PORT_INIT_TG_BLOCK_TRACKING) {
756 		port->ip_tg_block_tracking = true;
757 	}
758 	if (flags & IPC_PORT_INIT_SPECIAL_REPLY) {
759 		port->ip_specialreply = true;
760 		port->ip_immovable_receive = true;
761 	}
762 
763 	ipc_mqueue_init(&port->ip_messages);
764 #if MACH_ASSERT
765 	ipc_port_init_debug(port, __builtin_frame_address(0));
766 #endif  /* MACH_ASSERT */
767 
768 	/* port transitions to IN-SPACE state */
769 	port->ip_receiver_name = name;
770 	port->ip_receiver = space;
771 
772 	if (flags & IPC_PORT_INIT_MAKE_SEND_RIGHT) {
773 		port->ip_srights = 1;
774 		port->ip_mscount = 1;
775 	}
776 }
777 
778 /*
779  *	Routine:	ipc_port_alloc
780  *	Purpose:
781  *		Allocate a port.
782  *	Conditions:
783  *		Nothing locked.  If successful, the port is returned
784  *		locked.  (The caller doesn't have a reference.)
785  *	Returns:
786  *		KERN_SUCCESS		The port is allocated.
787  *		KERN_INVALID_TASK	The space is dead.
788  *		KERN_NO_SPACE		No room for an entry in the space.
789  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
790  */
791 
792 kern_return_t
ipc_port_alloc(ipc_space_t space,ipc_port_init_flags_t flags,mach_port_name_t * namep,ipc_port_t * portp)793 ipc_port_alloc(
794 	ipc_space_t             space,
795 	ipc_port_init_flags_t   flags,
796 	mach_port_name_t        *namep,
797 	ipc_port_t              *portp)
798 {
799 	ipc_port_t port;
800 	mach_port_name_t name;
801 	kern_return_t kr;
802 	mach_port_type_t type = MACH_PORT_TYPE_RECEIVE;
803 	mach_port_urefs_t urefs = 0;
804 
805 	if (flags & IPC_PORT_INIT_MAKE_SEND_RIGHT) {
806 		type |= MACH_PORT_TYPE_SEND;
807 		urefs = 1;
808 	}
809 	kr = ipc_object_alloc(space, IOT_PORT, type, urefs,
810 	    &name, (ipc_object_t *) &port);
811 	if (kr != KERN_SUCCESS) {
812 		return kr;
813 	}
814 
815 	/* space is locked */
816 	ipc_port_init(port, space, flags | IPC_PORT_INIT_LOCKED, name);
817 	/* port is locked */
818 #if MACH_ASSERT
819 	ipc_port_init_debug(port, __builtin_frame_address(0));
820 #endif  /* MACH_ASSERT */
821 
822 	/* unlock space after init */
823 	is_write_unlock(space);
824 
825 	*namep = name;
826 	*portp = port;
827 
828 	return KERN_SUCCESS;
829 }
830 
831 /*
832  *	Routine:	ipc_port_alloc_name
833  *	Purpose:
834  *		Allocate a port, with a specific name.
835  *	Conditions:
836  *		Nothing locked.  If successful, the port is returned
837  *		locked.  (The caller doesn't have a reference.)
838  *	Returns:
839  *		KERN_SUCCESS		The port is allocated.
840  *		KERN_INVALID_TASK	The space is dead.
841  *		KERN_NAME_EXISTS	The name already denotes a right.
842  *		KERN_RESOURCE_SHORTAGE	Couldn't allocate memory.
843  */
844 
845 kern_return_t
ipc_port_alloc_name(ipc_space_t space,ipc_port_init_flags_t flags,mach_port_name_t name,ipc_port_t * portp)846 ipc_port_alloc_name(
847 	ipc_space_t             space,
848 	ipc_port_init_flags_t   flags,
849 	mach_port_name_t        name,
850 	ipc_port_t              *portp)
851 {
852 	mach_port_type_t type = MACH_PORT_TYPE_RECEIVE;
853 	mach_port_urefs_t urefs = 0;
854 
855 	if (flags & IPC_PORT_INIT_MAKE_SEND_RIGHT) {
856 		type |= MACH_PORT_TYPE_SEND;
857 		urefs = 1;
858 	}
859 	flags |= IPC_PORT_INIT_LOCKED;
860 
861 	return ipc_object_alloc_name(space, IOT_PORT, type, urefs,
862 	           name, (ipc_object_t *)portp, ^(ipc_object_t object){
863 		ipc_port_init(ip_object_to_port(object), space, flags, name);
864 	});
865 }
866 
867 /*
868  *      Routine:	ipc_port_spnotify
869  *	Purpose:
870  *		Generate send-possible port notifications.
871  *	Conditions:
872  *		Nothing locked, reference held on port.
873  */
874 void
ipc_port_spnotify(ipc_port_t port)875 ipc_port_spnotify(
876 	ipc_port_t      port)
877 {
878 	ipc_port_request_index_t index = 0;
879 	ipc_table_elems_t size = 0;
880 
881 	/*
882 	 * If the port has no send-possible request
883 	 * armed, don't bother to lock the port.
884 	 */
885 	if (port->ip_sprequests == 0) {
886 		return;
887 	}
888 
889 	ip_mq_lock(port);
890 
891 #if IMPORTANCE_INHERITANCE
892 	if (port->ip_spimportant != 0) {
893 		port->ip_spimportant = 0;
894 		if (ipc_port_importance_delta(port, IPID_OPTION_NORMAL, -1) == TRUE) {
895 			ip_mq_lock(port);
896 		}
897 	}
898 #endif /* IMPORTANCE_INHERITANCE */
899 
900 	if (port->ip_sprequests == 0) {
901 		ip_mq_unlock(port);
902 		return;
903 	}
904 	port->ip_sprequests = 0;
905 
906 revalidate:
907 	if (ip_active(port)) {
908 		ipc_port_request_t requests;
909 
910 		/* table may change each time port unlocked (reload) */
911 		requests = port->ip_requests;
912 		assert(requests != IPR_NULL);
913 
914 		/*
915 		 * no need to go beyond table size when first
916 		 * we entered - those are future notifications.
917 		 */
918 		if (size == 0) {
919 			size = requests->ipr_size->its_size;
920 		}
921 
922 		/* no need to backtrack either */
923 		while (++index < size) {
924 			ipc_port_request_t ipr = &requests[index];
925 			mach_port_name_t name = ipr->ipr_name;
926 			ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
927 			boolean_t armed = IPR_SOR_SPARMED(ipr->ipr_soright);
928 
929 			if (MACH_PORT_VALID(name) && armed && IP_VALID(soright)) {
930 				/* claim send-once right - slot still inuse */
931 				ipr->ipr_soright = IP_NULL;
932 				ip_mq_unlock(port);
933 
934 				ipc_notify_send_possible(soright, name);
935 
936 				ip_mq_lock(port);
937 				goto revalidate;
938 			}
939 		}
940 	}
941 	ip_mq_unlock(port);
942 	return;
943 }
944 
945 /*
946  *      Routine:	ipc_port_dnnotify
947  *	Purpose:
948  *		Generate dead name notifications for
949  *		all outstanding dead-name and send-
950  *		possible requests.
951  *	Conditions:
952  *		Nothing locked.
953  *		Port must be inactive.
954  *		Reference held on port.
955  */
956 void
ipc_port_dnnotify(ipc_port_t port)957 ipc_port_dnnotify(
958 	ipc_port_t      port)
959 {
960 	ipc_port_request_t requests = port->ip_requests;
961 
962 	assert(!ip_active(port));
963 	if (requests != IPR_NULL) {
964 		ipc_table_size_t its = requests->ipr_size;
965 		ipc_table_elems_t size = its->its_size;
966 		ipc_port_request_index_t index;
967 		for (index = 1; index < size; index++) {
968 			ipc_port_request_t ipr = &requests[index];
969 			mach_port_name_t name = ipr->ipr_name;
970 			ipc_port_t soright = IPR_SOR_PORT(ipr->ipr_soright);
971 
972 			if (MACH_PORT_VALID(name) && IP_VALID(soright)) {
973 				ipc_notify_dead_name(soright, name);
974 			}
975 		}
976 	}
977 }
978 
979 /*
980  *	Routine:	ipc_port_destroy
981  *	Purpose:
982  *		Destroys a port.  Cleans up queued messages.
983  *
984  *		If the port has a backup, it doesn't get destroyed,
985  *		but is sent in a port-destroyed notification to the backup.
986  *	Conditions:
987  *		The port is locked and alive; nothing else locked.
988  *		The caller has a reference, which is consumed.
989  *		Afterwards, the port is unlocked and dead.
990  */
991 
992 void
ipc_port_destroy(ipc_port_t port)993 ipc_port_destroy(ipc_port_t port)
994 {
995 	ipc_port_t pdrequest;
996 	boolean_t special_reply = port->ip_specialreply;
997 	struct task_watchport_elem *watchport_elem = NULL;
998 	ipc_notify_nsenders_t nsrequest = { };
999 
1000 #if IMPORTANCE_INHERITANCE
1001 	ipc_importance_task_t release_imp_task = IIT_NULL;
1002 	thread_t self = current_thread();
1003 	boolean_t top = (self->ith_assertions == 0);
1004 	natural_t assertcnt = 0;
1005 #endif /* IMPORTANCE_INHERITANCE */
1006 
1007 	require_ip_active(port);
1008 	/* port->ip_receiver_name is garbage */
1009 	/* port->ip_receiver/port->ip_destination is garbage */
1010 
1011 	/* clear any reply-port context */
1012 	port->ip_reply_context = 0;
1013 
1014 	/* check for a backup port */
1015 	pdrequest = port->ip_pdrequest;
1016 
1017 	/*
1018 	 * Panic if a special reply has ip_pdrequest or ip_tempowner
1019 	 * set, as this causes a type confusion while accessing the
1020 	 * kdata union.
1021 	 */
1022 	if (special_reply && (pdrequest || port->ip_tempowner)) {
1023 		panic("ipc_port_destroy: invalid state");
1024 	}
1025 
1026 #if IMPORTANCE_INHERITANCE
1027 	/* determine how many assertions to drop and from whom */
1028 	if (port->ip_tempowner != 0) {
1029 		assert(top);
1030 		release_imp_task = ip_get_imp_task(port);
1031 		if (IIT_NULL != release_imp_task) {
1032 			port->ip_imp_task = IIT_NULL;
1033 			assertcnt = port->ip_impcount;
1034 		}
1035 		/* Otherwise, nothing to drop */
1036 	} else {
1037 		assertcnt = port->ip_impcount;
1038 		if (pdrequest != IP_NULL) {
1039 			/* mark in limbo for the journey */
1040 			port->ip_tempowner = 1;
1041 		}
1042 	}
1043 
1044 	if (top) {
1045 		self->ith_assertions = assertcnt;
1046 	}
1047 #endif /* IMPORTANCE_INHERITANCE */
1048 
1049 	if (pdrequest != IP_NULL) {
1050 		/* clear receiver, don't destroy the port */
1051 		(void)ipc_port_clear_receiver(port, FALSE);
1052 		assert(!ip_in_pset(port));
1053 		assert(port->ip_mscount == 0);
1054 
1055 		/* we assume the ref for pdrequest */
1056 		port->ip_pdrequest = IP_NULL;
1057 
1058 		if (port->ip_service_port) {
1059 			assert(port->ip_splabel != NULL);
1060 			if (ipc_service_port_label_is_special_pdrequest((ipc_service_port_label_t)port->ip_splabel)) {
1061 				ipc_service_port_label_set_flag(port->ip_splabel, ISPL_FLAGS_SEND_PD_NOTIFICATION);
1062 			}
1063 		}
1064 
1065 		watchport_elem = ipc_port_clear_watchport_elem_internal(port);
1066 		ipc_port_send_turnstile_recompute_push_locked(port);
1067 		/* port unlocked */
1068 
1069 		if (special_reply) {
1070 			ipc_port_adjust_special_reply_port(port,
1071 			    IPC_PORT_ADJUST_SR_ALLOW_SYNC_LINKAGE);
1072 		}
1073 
1074 		if (watchport_elem) {
1075 			task_watchport_elem_deallocate(watchport_elem);
1076 			watchport_elem = NULL;
1077 		}
1078 		/* consumes our refs for port and pdrequest */
1079 		ipc_notify_port_destroyed(pdrequest, port);
1080 
1081 		goto drop_assertions;
1082 	}
1083 
1084 	/*
1085 	 * The mach_msg_* paths don't hold a port lock, they only hold a
1086 	 * reference to the port object. If a thread raced us and is now
1087 	 * blocked waiting for message reception on this mqueue (or waiting
1088 	 * for ipc_mqueue_full), it will never be woken up. We call
1089 	 * ipc_port_clear_receiver() here, _after_ the port has been marked
1090 	 * inactive, to wakeup any threads which may be blocked and ensure
1091 	 * that no other thread can get lost waiting for a wake up on a
1092 	 * port/mqueue that's been destroyed.
1093 	 */
1094 	boolean_t reap_msgs = FALSE;
1095 	bool service_port = false;
1096 	ipc_service_port_label_t splabel = NULL;
1097 	reap_msgs = ipc_port_clear_receiver(port, TRUE); /* marks port and mqueue inactive */
1098 	assert(!ip_in_pset(port));
1099 	assert(port->ip_mscount == 0);
1100 
1101 	watchport_elem = ipc_port_clear_watchport_elem_internal(port);
1102 	nsrequest = ipc_notify_no_senders_prepare(port);
1103 
1104 	/* Deallocate the service/connection port label */
1105 	if (!ip_is_kolabeled(port)) {
1106 		splabel = port->ip_splabel;
1107 		service_port = port->ip_service_port;
1108 
1109 		port->ip_splabel = NULL;
1110 		port->ip_service_port = false;
1111 	}
1112 
1113 	ipc_port_send_turnstile_recompute_push_locked(port);
1114 	/* port unlocked */
1115 
1116 	/* Deallocate the watchport element */
1117 	if (watchport_elem) {
1118 		task_watchport_elem_deallocate(watchport_elem);
1119 		watchport_elem = NULL;
1120 	}
1121 
1122 	/* unlink the kmsg from special reply port */
1123 	if (special_reply) {
1124 		ipc_port_adjust_special_reply_port(port,
1125 		    IPC_PORT_ADJUST_SR_ALLOW_SYNC_LINKAGE);
1126 	}
1127 
1128 	if (splabel) {
1129 		ipc_service_port_label_dealloc(splabel, service_port);
1130 		splabel = NULL;
1131 	}
1132 
1133 	if (nsrequest.ns_notify) {
1134 		/*
1135 		 * ipc_notify_no_senders_prepare will consume
1136 		 * the reference for kobjects.
1137 		 */
1138 		assert(!nsrequest.ns_is_kobject);
1139 		ip_mq_lock(nsrequest.ns_notify);
1140 		ipc_notify_send_once_and_unlock(nsrequest.ns_notify); /* consumes ref */
1141 	}
1142 
1143 	/*
1144 	 * Reap any kmsg objects waiting to be destroyed.
1145 	 * This must be done after we've released the port lock.
1146 	 */
1147 	if (reap_msgs) {
1148 		ipc_kmsg_reap_delayed();
1149 	}
1150 
1151 	/* generate dead-name notifications */
1152 	ipc_port_dnnotify(port);
1153 
1154 	ipc_kobject_destroy(port);
1155 
1156 	ip_release(port); /* consume caller's ref */
1157 
1158 drop_assertions:
1159 #if IMPORTANCE_INHERITANCE
1160 	if (release_imp_task != IIT_NULL) {
1161 		if (assertcnt > 0) {
1162 			assert(top);
1163 			self->ith_assertions = 0;
1164 			assert(ipc_importance_task_is_any_receiver_type(release_imp_task));
1165 			ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
1166 		}
1167 		ipc_importance_task_release(release_imp_task);
1168 	} else if (assertcnt > 0) {
1169 		if (top) {
1170 			self->ith_assertions = 0;
1171 			release_imp_task = current_task()->task_imp_base;
1172 			if (ipc_importance_task_is_any_receiver_type(release_imp_task)) {
1173 				ipc_importance_task_drop_internal_assertion(release_imp_task, assertcnt);
1174 			}
1175 		}
1176 	}
1177 #endif /* IMPORTANCE_INHERITANCE */
1178 }
1179 
1180 /*
1181  *	Routine:	ipc_port_destination_chain_lock
1182  *	Purpose:
1183  *		Search for the end of the chain (a port not in transit),
1184  *		acquiring locks along the way, and return it in `base`.
1185  *
1186  *		Returns true if a reference was taken on `base`
1187  *
1188  *	Conditions:
1189  *		No ports locked.
1190  *		ipc_port_multiple_lock held.
1191  */
1192 boolean_t
ipc_port_destination_chain_lock(ipc_port_t port,ipc_port_t * base)1193 ipc_port_destination_chain_lock(
1194 	ipc_port_t port,
1195 	ipc_port_t *base)
1196 {
1197 	for (;;) {
1198 		ip_mq_lock(port);
1199 
1200 		if (!ip_active(port)) {
1201 			/*
1202 			 * Active ports that are ip_mq_lock()ed cannot go away.
1203 			 *
1204 			 * But inactive ports at the end of walking
1205 			 * an ip_destination chain are only protected
1206 			 * from space termination cleanup while the entire
1207 			 * chain of ports leading to them is held.
1208 			 *
1209 			 * Callers of this code tend to unlock the chain
1210 			 * in the same order than this walk which doesn't
1211 			 * protect `base` properly when it's inactive.
1212 			 *
1213 			 * In that case, take a reference that the caller
1214 			 * is responsible for releasing.
1215 			 */
1216 			ip_reference(port);
1217 			*base = port;
1218 			return true;
1219 		}
1220 
1221 		/* port is active */
1222 		if (!ip_in_transit(port)) {
1223 			*base = port;
1224 			return false;
1225 		}
1226 
1227 		port = ip_get_destination(port);
1228 	}
1229 }
1230 
1231 
1232 /*
1233  *	Routine:	ipc_port_check_circularity
1234  *	Purpose:
1235  *		Check if queueing "port" in a message for "dest"
1236  *		would create a circular group of ports and messages.
1237  *
1238  *		If no circularity (FALSE returned), then "port"
1239  *		is changed from "in limbo" to "in transit".
1240  *
1241  *		That is, we want to set port->ip_destination == dest,
1242  *		but guaranteeing that this doesn't create a circle
1243  *		port->ip_destination->ip_destination->... == port
1244  *
1245  *	Conditions:
1246  *		No ports locked.  References held for "port" and "dest".
1247  */
1248 
1249 boolean_t
ipc_port_check_circularity(ipc_port_t port,ipc_port_t dest)1250 ipc_port_check_circularity(
1251 	ipc_port_t      port,
1252 	ipc_port_t      dest)
1253 {
1254 #if IMPORTANCE_INHERITANCE
1255 	/* adjust importance counts at the same time */
1256 	return ipc_importance_check_circularity(port, dest);
1257 #else
1258 	ipc_port_t base;
1259 	struct task_watchport_elem *watchport_elem = NULL;
1260 	bool took_base_ref = false;
1261 
1262 	assert(port != IP_NULL);
1263 	assert(dest != IP_NULL);
1264 
1265 	if (port == dest) {
1266 		return TRUE;
1267 	}
1268 	base = dest;
1269 
1270 	/* Check if destination needs a turnstile */
1271 	ipc_port_send_turnstile_prepare(dest);
1272 
1273 	/*
1274 	 *	First try a quick check that can run in parallel.
1275 	 *	No circularity if dest is not in transit.
1276 	 */
1277 	ip_mq_lock(port);
1278 	if (ip_mq_lock_try(dest)) {
1279 		if (!ip_in_transit(dest)) {
1280 			goto not_circular;
1281 		}
1282 
1283 		/* dest is in transit; further checking necessary */
1284 
1285 		ip_mq_unlock(dest);
1286 	}
1287 	ip_mq_unlock(port);
1288 
1289 	ipc_port_multiple_lock(); /* massive serialization */
1290 
1291 	/*
1292 	 *	Search for the end of the chain (a port not in transit),
1293 	 *	acquiring locks along the way.
1294 	 */
1295 
1296 	took_base_ref = ipc_port_destination_chain_lock(dest, &base);
1297 	/* all ports in chain from dest to base, inclusive, are locked */
1298 
1299 	if (port == base) {
1300 		/* circularity detected! */
1301 
1302 		ipc_port_multiple_unlock();
1303 
1304 		/* port (== base) is in limbo */
1305 		require_ip_active(port);
1306 		assert(ip_in_limbo(port));
1307 		assert(!took_base_ref);
1308 
1309 		base = dest;
1310 		while (base != IP_NULL) {
1311 			ipc_port_t next;
1312 
1313 			/* dest is in transit or in limbo */
1314 			require_ip_active(base);
1315 			assert(!ip_in_a_space(base));
1316 
1317 			next = ip_get_destination(base);
1318 			ip_mq_unlock(base);
1319 			base = next;
1320 		}
1321 
1322 		ipc_port_send_turnstile_complete(dest);
1323 		return TRUE;
1324 	}
1325 
1326 	/*
1327 	 *	The guarantee:  lock port while the entire chain is locked.
1328 	 *	Once port is locked, we can take a reference to dest,
1329 	 *	add port to the chain, and unlock everything.
1330 	 */
1331 
1332 	ip_mq_lock(port);
1333 	ipc_port_multiple_unlock();
1334 
1335 not_circular:
1336 	require_ip_active(port);
1337 	assert(ip_in_limbo(port));
1338 
1339 	/* Clear the watchport boost */
1340 	watchport_elem = ipc_port_clear_watchport_elem_internal(port);
1341 
1342 	/* Check if the port is being enqueued as a part of sync bootstrap checkin */
1343 	if (dest->ip_specialreply && dest->ip_sync_bootstrap_checkin) {
1344 		port->ip_sync_bootstrap_checkin = 1;
1345 	}
1346 
1347 	ip_reference(dest);
1348 
1349 	/* port transitions to IN-TRANSIT state */
1350 	assert(port->ip_receiver_name == MACH_PORT_NULL);
1351 	port->ip_destination = dest;
1352 
1353 	/* Setup linkage for source port if it has sync ipc push */
1354 	struct turnstile *send_turnstile = TURNSTILE_NULL;
1355 	if (port_send_turnstile(port)) {
1356 		send_turnstile = turnstile_prepare((uintptr_t)port,
1357 		    port_send_turnstile_address(port),
1358 		    TURNSTILE_NULL, TURNSTILE_SYNC_IPC);
1359 
1360 		/*
1361 		 * What ipc_port_adjust_port_locked would do,
1362 		 * but we need to also drop even more locks before
1363 		 * calling turnstile_update_inheritor_complete().
1364 		 */
1365 		ipc_port_adjust_sync_link_state_locked(port, PORT_SYNC_LINK_ANY, NULL);
1366 
1367 		turnstile_update_inheritor(send_turnstile, port_send_turnstile(dest),
1368 		    (TURNSTILE_INHERITOR_TURNSTILE | TURNSTILE_IMMEDIATE_UPDATE));
1369 
1370 		/* update complete and turnstile complete called after dropping all locks */
1371 	}
1372 	/* now unlock chain */
1373 
1374 	ip_mq_unlock(port);
1375 
1376 	for (;;) {
1377 		ipc_port_t next;
1378 
1379 		if (dest == base) {
1380 			break;
1381 		}
1382 
1383 		/* port is IN-TRANSIT */
1384 		require_ip_active(dest);
1385 		assert(ip_in_transit(dest));
1386 
1387 		next = ip_get_destination(dest);
1388 		ip_mq_unlock(dest);
1389 		dest = next;
1390 	}
1391 
1392 	/* base is not IN-TRANSIT */
1393 	assert(!ip_in_transit(base));
1394 
1395 	ip_mq_unlock(base);
1396 	if (took_base_ref) {
1397 		ip_release(base);
1398 	}
1399 
1400 	/* All locks dropped, call turnstile_update_inheritor_complete for source port's turnstile */
1401 	if (send_turnstile) {
1402 		turnstile_update_inheritor_complete(send_turnstile, TURNSTILE_INTERLOCK_NOT_HELD);
1403 
1404 		/* Take the mq lock to call turnstile complete */
1405 		ip_mq_lock(port);
1406 		turnstile_complete((uintptr_t)port, port_send_turnstile_address(port), NULL, TURNSTILE_SYNC_IPC);
1407 		send_turnstile = TURNSTILE_NULL;
1408 		ip_mq_unlock(port);
1409 		turnstile_cleanup();
1410 	}
1411 
1412 	if (watchport_elem) {
1413 		task_watchport_elem_deallocate(watchport_elem);
1414 	}
1415 
1416 	return FALSE;
1417 #endif /* !IMPORTANCE_INHERITANCE */
1418 }
1419 
1420 /*
1421  *	Routine:	ipc_port_watchport_elem
1422  *	Purpose:
1423  *		Get the port's watchport elem field
1424  *
1425  *	Conditions:
1426  *		port locked
1427  */
1428 static struct task_watchport_elem *
ipc_port_watchport_elem(ipc_port_t port)1429 ipc_port_watchport_elem(ipc_port_t port)
1430 {
1431 	return port->ip_waitq.waitq_tspriv;
1432 }
1433 
1434 /*
1435  *	Routine:	ipc_port_update_watchport_elem
1436  *	Purpose:
1437  *		Set the port's watchport elem field
1438  *
1439  *	Conditions:
1440  *		port locked
1441  */
1442 static inline struct task_watchport_elem *
ipc_port_update_watchport_elem(ipc_port_t port,struct task_watchport_elem * we)1443 ipc_port_update_watchport_elem(ipc_port_t port, struct task_watchport_elem *we)
1444 {
1445 	assert(!port->ip_specialreply);
1446 	struct task_watchport_elem *old_we = ipc_port_watchport_elem(port);
1447 	port->ip_waitq.waitq_tspriv = we;
1448 	return old_we;
1449 }
1450 
1451 /*
1452  *	Routine:	ipc_special_reply_stash_pid_locked
1453  *	Purpose:
1454  *		Set the pid of process that copied out send once right to special reply port.
1455  *
1456  *	Conditions:
1457  *		port locked
1458  */
1459 static inline void
ipc_special_reply_stash_pid_locked(ipc_port_t port,int pid)1460 ipc_special_reply_stash_pid_locked(ipc_port_t port, int pid)
1461 {
1462 	assert(port->ip_specialreply);
1463 	port->ip_waitq.waitq_priv_pid = pid;
1464 	return;
1465 }
1466 
1467 /*
1468  *	Routine:	ipc_special_reply_get_pid_locked
1469  *	Purpose:
1470  *		Get the pid of process that copied out send once right to special reply port.
1471  *
1472  *	Conditions:
1473  *		port locked
1474  */
1475 int
ipc_special_reply_get_pid_locked(ipc_port_t port)1476 ipc_special_reply_get_pid_locked(ipc_port_t port)
1477 {
1478 	assert(port->ip_specialreply);
1479 	return port->ip_waitq.waitq_priv_pid;
1480 }
1481 
1482 /*
1483  * Update the recv turnstile inheritor for a port.
1484  *
1485  * Sync IPC through the port receive turnstile only happens for the special
1486  * reply port case. It has three sub-cases:
1487  *
1488  * 1. a send-once right is in transit, and pushes on the send turnstile of its
1489  *    destination mqueue.
1490  *
1491  * 2. a send-once right has been stashed on a knote it was copied out "through",
1492  *    as the first such copied out port.
1493  *
1494  * 3. a send-once right has been stashed on a knote it was copied out "through",
1495  *    as the second or more copied out port.
1496  */
1497 void
ipc_port_recv_update_inheritor(ipc_port_t port,struct turnstile * rcv_turnstile,turnstile_update_flags_t flags)1498 ipc_port_recv_update_inheritor(
1499 	ipc_port_t port,
1500 	struct turnstile *rcv_turnstile,
1501 	turnstile_update_flags_t flags)
1502 {
1503 	struct turnstile *inheritor = TURNSTILE_NULL;
1504 	struct knote *kn;
1505 
1506 	if (ip_active(port) && port->ip_specialreply) {
1507 		ip_mq_lock_held(port);
1508 
1509 		switch (port->ip_sync_link_state) {
1510 		case PORT_SYNC_LINK_PORT:
1511 			if (port->ip_sync_inheritor_port != NULL) {
1512 				inheritor = port_send_turnstile(port->ip_sync_inheritor_port);
1513 			}
1514 			break;
1515 
1516 		case PORT_SYNC_LINK_WORKLOOP_KNOTE:
1517 			kn = port->ip_sync_inheritor_knote;
1518 			inheritor = filt_ipc_kqueue_turnstile(kn);
1519 			break;
1520 
1521 		case PORT_SYNC_LINK_WORKLOOP_STASH:
1522 			inheritor = port->ip_sync_inheritor_ts;
1523 			break;
1524 		}
1525 	}
1526 
1527 	turnstile_update_inheritor(rcv_turnstile, inheritor,
1528 	    flags | TURNSTILE_INHERITOR_TURNSTILE);
1529 }
1530 
1531 /*
1532  * Update the send turnstile inheritor for a port.
1533  *
1534  * Sync IPC through the port send turnstile has 7 possible reasons to be linked:
1535  *
1536  * 1. a special reply port is part of sync ipc for bootstrap checkin and needs
1537  *    to push on thread doing the sync ipc.
1538  *
1539  * 2. a receive right is in transit, and pushes on the send turnstile of its
1540  *    destination mqueue.
1541  *
1542  * 3. port was passed as an exec watchport and port is pushing on main thread
1543  *    of the task.
1544  *
1545  * 4. a receive right has been stashed on a knote it was copied out "through",
1546  *    as the first such copied out port (same as PORT_SYNC_LINK_WORKLOOP_KNOTE
1547  *    for the special reply port)
1548  *
1549  * 5. a receive right has been stashed on a knote it was copied out "through",
1550  *    as the second or more copied out port (same as
1551  *    PORT_SYNC_LINK_WORKLOOP_STASH for the special reply port)
1552  *
1553  * 6. a receive right has been copied out as a part of sync bootstrap checkin
1554  *    and needs to push on thread doing the sync bootstrap checkin.
1555  *
1556  * 7. the receive right is monitored by a knote, and pushes on any that is
1557  *    registered on a workloop. filt_machport makes sure that if such a knote
1558  *    exists, it is kept as the first item in the knote list, so we never need
1559  *    to walk.
1560  */
1561 void
ipc_port_send_update_inheritor(ipc_port_t port,struct turnstile * send_turnstile,turnstile_update_flags_t flags)1562 ipc_port_send_update_inheritor(
1563 	ipc_port_t port,
1564 	struct turnstile *send_turnstile,
1565 	turnstile_update_flags_t flags)
1566 {
1567 	ipc_mqueue_t mqueue = &port->ip_messages;
1568 	turnstile_inheritor_t inheritor = TURNSTILE_INHERITOR_NULL;
1569 	struct knote *kn;
1570 	turnstile_update_flags_t inheritor_flags = TURNSTILE_INHERITOR_TURNSTILE;
1571 
1572 	ip_mq_lock_held(port);
1573 
1574 	if (!ip_active(port)) {
1575 		/* this port is no longer active, it should not push anywhere */
1576 	} else if (port->ip_specialreply) {
1577 		/* Case 1. */
1578 		if (port->ip_sync_bootstrap_checkin && prioritize_launch) {
1579 			inheritor = port->ip_messages.imq_srp_owner_thread;
1580 			inheritor_flags = TURNSTILE_INHERITOR_THREAD;
1581 		}
1582 	} else if (ip_in_transit(port)) {
1583 		/* Case 2. */
1584 		inheritor = port_send_turnstile(ip_get_destination(port));
1585 	} else if (ipc_port_watchport_elem(port) != NULL) {
1586 		/* Case 3. */
1587 		if (prioritize_launch) {
1588 			assert(port->ip_sync_link_state == PORT_SYNC_LINK_ANY);
1589 			inheritor = ipc_port_get_watchport_inheritor(port);
1590 			inheritor_flags = TURNSTILE_INHERITOR_THREAD;
1591 		}
1592 	} else if (port->ip_sync_link_state == PORT_SYNC_LINK_WORKLOOP_KNOTE) {
1593 		/* Case 4. */
1594 		inheritor = filt_ipc_kqueue_turnstile(mqueue->imq_inheritor_knote);
1595 	} else if (port->ip_sync_link_state == PORT_SYNC_LINK_WORKLOOP_STASH) {
1596 		/* Case 5. */
1597 		inheritor = mqueue->imq_inheritor_turnstile;
1598 	} else if (port->ip_sync_link_state == PORT_SYNC_LINK_RCV_THREAD) {
1599 		/* Case 6. */
1600 		if (prioritize_launch) {
1601 			inheritor = port->ip_messages.imq_inheritor_thread_ref;
1602 			inheritor_flags = TURNSTILE_INHERITOR_THREAD;
1603 		}
1604 	} else if ((kn = SLIST_FIRST(&port->ip_klist))) {
1605 		/* Case 7. Push on a workloop that is interested */
1606 		if (filt_machport_kqueue_has_turnstile(kn)) {
1607 			assert(port->ip_sync_link_state == PORT_SYNC_LINK_ANY);
1608 			inheritor = filt_ipc_kqueue_turnstile(kn);
1609 		}
1610 	}
1611 
1612 	turnstile_update_inheritor(send_turnstile, inheritor,
1613 	    flags | inheritor_flags);
1614 }
1615 
1616 /*
1617  *	Routine:	ipc_port_send_turnstile_prepare
1618  *	Purpose:
1619  *		Get a reference on port's send turnstile, if
1620  *		port does not have a send turnstile then allocate one.
1621  *
1622  *	Conditions:
1623  *		Nothing is locked.
1624  */
1625 void
ipc_port_send_turnstile_prepare(ipc_port_t port)1626 ipc_port_send_turnstile_prepare(ipc_port_t port)
1627 {
1628 	struct turnstile *turnstile = TURNSTILE_NULL;
1629 	struct turnstile *send_turnstile = TURNSTILE_NULL;
1630 
1631 retry_alloc:
1632 	ip_mq_lock(port);
1633 
1634 	if (port_send_turnstile(port) == NULL ||
1635 	    port_send_turnstile(port)->ts_port_ref == 0) {
1636 		if (turnstile == TURNSTILE_NULL) {
1637 			ip_mq_unlock(port);
1638 			turnstile = turnstile_alloc();
1639 			goto retry_alloc;
1640 		}
1641 
1642 		send_turnstile = turnstile_prepare((uintptr_t)port,
1643 		    port_send_turnstile_address(port),
1644 		    turnstile, TURNSTILE_SYNC_IPC);
1645 		turnstile = TURNSTILE_NULL;
1646 
1647 		ipc_port_send_update_inheritor(port, send_turnstile,
1648 		    TURNSTILE_IMMEDIATE_UPDATE);
1649 
1650 		/* turnstile complete will be called in ipc_port_send_turnstile_complete */
1651 	}
1652 
1653 	/* Increment turnstile counter */
1654 	port_send_turnstile(port)->ts_port_ref++;
1655 	ip_mq_unlock(port);
1656 
1657 	if (send_turnstile) {
1658 		turnstile_update_inheritor_complete(send_turnstile,
1659 		    TURNSTILE_INTERLOCK_NOT_HELD);
1660 	}
1661 	if (turnstile != TURNSTILE_NULL) {
1662 		turnstile_deallocate(turnstile);
1663 	}
1664 }
1665 
1666 
1667 /*
1668  *	Routine:	ipc_port_send_turnstile_complete
1669  *	Purpose:
1670  *		Drop a ref on the port's send turnstile, if the
1671  *		ref becomes zero, deallocate the turnstile.
1672  *
1673  *	Conditions:
1674  *		The space might be locked, use safe deallocate.
1675  */
1676 void
ipc_port_send_turnstile_complete(ipc_port_t port)1677 ipc_port_send_turnstile_complete(ipc_port_t port)
1678 {
1679 	struct turnstile *turnstile = TURNSTILE_NULL;
1680 
1681 	/* Drop turnstile count on dest port */
1682 	ip_mq_lock(port);
1683 
1684 	port_send_turnstile(port)->ts_port_ref--;
1685 	if (port_send_turnstile(port)->ts_port_ref == 0) {
1686 		turnstile_complete((uintptr_t)port, port_send_turnstile_address(port),
1687 		    &turnstile, TURNSTILE_SYNC_IPC);
1688 		assert(turnstile != TURNSTILE_NULL);
1689 	}
1690 	ip_mq_unlock(port);
1691 	turnstile_cleanup();
1692 
1693 	if (turnstile != TURNSTILE_NULL) {
1694 		turnstile_deallocate_safe(turnstile);
1695 		turnstile = TURNSTILE_NULL;
1696 	}
1697 }
1698 
1699 /*
1700  *	Routine:	ipc_port_rcv_turnstile
1701  *	Purpose:
1702  *		Get the port's receive turnstile
1703  *
1704  *	Conditions:
1705  *		mqueue locked or thread waiting on turnstile is locked.
1706  */
1707 static struct turnstile *
ipc_port_rcv_turnstile(ipc_port_t port)1708 ipc_port_rcv_turnstile(ipc_port_t port)
1709 {
1710 	return *port_rcv_turnstile_address(port);
1711 }
1712 
1713 
1714 /*
1715  *	Routine:	ipc_port_link_special_reply_port
1716  *	Purpose:
1717  *		Link the special reply port with the destination port.
1718  *              Allocates turnstile to dest port.
1719  *
1720  *	Conditions:
1721  *		Nothing is locked.
1722  */
1723 void
ipc_port_link_special_reply_port(ipc_port_t special_reply_port,ipc_port_t dest_port,boolean_t sync_bootstrap_checkin)1724 ipc_port_link_special_reply_port(
1725 	ipc_port_t special_reply_port,
1726 	ipc_port_t dest_port,
1727 	boolean_t sync_bootstrap_checkin)
1728 {
1729 	boolean_t drop_turnstile_ref = FALSE;
1730 	boolean_t special_reply = FALSE;
1731 
1732 	/* Check if dest_port needs a turnstile */
1733 	ipc_port_send_turnstile_prepare(dest_port);
1734 
1735 	/* Lock the special reply port and establish the linkage */
1736 	ip_mq_lock(special_reply_port);
1737 
1738 	special_reply = special_reply_port->ip_specialreply;
1739 
1740 	if (sync_bootstrap_checkin && special_reply) {
1741 		special_reply_port->ip_sync_bootstrap_checkin = 1;
1742 	}
1743 
1744 	/* Check if we need to drop the acquired turnstile ref on dest port */
1745 	if (!special_reply ||
1746 	    special_reply_port->ip_sync_link_state != PORT_SYNC_LINK_ANY ||
1747 	    special_reply_port->ip_sync_inheritor_port != IPC_PORT_NULL) {
1748 		drop_turnstile_ref = TRUE;
1749 	} else {
1750 		/* take a reference on dest_port */
1751 		ip_reference(dest_port);
1752 		special_reply_port->ip_sync_inheritor_port = dest_port;
1753 		special_reply_port->ip_sync_link_state = PORT_SYNC_LINK_PORT;
1754 	}
1755 
1756 	ip_mq_unlock(special_reply_port);
1757 
1758 	if (special_reply) {
1759 		/*
1760 		 * For special reply ports, if the destination port is
1761 		 * marked with the thread group blocked tracking flag,
1762 		 * callout to the performance controller.
1763 		 */
1764 		ipc_port_thread_group_blocked(dest_port);
1765 	}
1766 
1767 	if (drop_turnstile_ref) {
1768 		ipc_port_send_turnstile_complete(dest_port);
1769 	}
1770 
1771 	return;
1772 }
1773 
1774 /*
1775  *	Routine:	ipc_port_thread_group_blocked
1776  *	Purpose:
1777  *		Call thread_group_blocked callout if the port
1778  *	        has ip_tg_block_tracking bit set and the thread
1779  *	        has not made this callout already.
1780  *
1781  *	Conditions:
1782  *		Nothing is locked.
1783  */
1784 void
ipc_port_thread_group_blocked(ipc_port_t port __unused)1785 ipc_port_thread_group_blocked(ipc_port_t port __unused)
1786 {
1787 #if CONFIG_THREAD_GROUPS
1788 	bool port_tg_block_tracking = false;
1789 	thread_t self = current_thread();
1790 
1791 	if (self->thread_group == NULL ||
1792 	    (self->options & TH_OPT_IPC_TG_BLOCKED)) {
1793 		return;
1794 	}
1795 
1796 	port_tg_block_tracking = port->ip_tg_block_tracking;
1797 	if (!port_tg_block_tracking) {
1798 		return;
1799 	}
1800 
1801 	machine_thread_group_blocked(self->thread_group, NULL,
1802 	    PERFCONTROL_CALLOUT_BLOCKING_TG_RENDER_SERVER, self);
1803 
1804 	self->options |= TH_OPT_IPC_TG_BLOCKED;
1805 #endif
1806 }
1807 
1808 /*
1809  *	Routine:	ipc_port_thread_group_unblocked
1810  *	Purpose:
1811  *		Call thread_group_unblocked callout if the
1812  *		thread had previously made a thread_group_blocked
1813  *		callout before (indicated by TH_OPT_IPC_TG_BLOCKED
1814  *		flag on the thread).
1815  *
1816  *	Conditions:
1817  *		Nothing is locked.
1818  */
1819 void
ipc_port_thread_group_unblocked(void)1820 ipc_port_thread_group_unblocked(void)
1821 {
1822 #if CONFIG_THREAD_GROUPS
1823 	thread_t self = current_thread();
1824 
1825 	if (!(self->options & TH_OPT_IPC_TG_BLOCKED)) {
1826 		return;
1827 	}
1828 
1829 	machine_thread_group_unblocked(self->thread_group, NULL,
1830 	    PERFCONTROL_CALLOUT_BLOCKING_TG_RENDER_SERVER, self);
1831 
1832 	self->options &= ~TH_OPT_IPC_TG_BLOCKED;
1833 #endif
1834 }
1835 
1836 #if DEVELOPMENT || DEBUG
1837 inline void
ipc_special_reply_port_bits_reset(ipc_port_t special_reply_port)1838 ipc_special_reply_port_bits_reset(ipc_port_t special_reply_port)
1839 {
1840 	special_reply_port->ip_srp_lost_link = 0;
1841 	special_reply_port->ip_srp_msg_sent = 0;
1842 }
1843 
1844 static inline void
ipc_special_reply_port_msg_sent_reset(ipc_port_t special_reply_port)1845 ipc_special_reply_port_msg_sent_reset(ipc_port_t special_reply_port)
1846 {
1847 	if (special_reply_port->ip_specialreply == 1) {
1848 		special_reply_port->ip_srp_msg_sent = 0;
1849 	}
1850 }
1851 
1852 inline void
ipc_special_reply_port_msg_sent(ipc_port_t special_reply_port)1853 ipc_special_reply_port_msg_sent(ipc_port_t special_reply_port)
1854 {
1855 	if (special_reply_port->ip_specialreply == 1) {
1856 		special_reply_port->ip_srp_msg_sent = 1;
1857 	}
1858 }
1859 
1860 static inline void
ipc_special_reply_port_lost_link(ipc_port_t special_reply_port)1861 ipc_special_reply_port_lost_link(ipc_port_t special_reply_port)
1862 {
1863 	if (special_reply_port->ip_specialreply == 1 && special_reply_port->ip_srp_msg_sent == 0) {
1864 		special_reply_port->ip_srp_lost_link = 1;
1865 	}
1866 }
1867 
1868 #else /* DEVELOPMENT || DEBUG */
1869 inline void
ipc_special_reply_port_bits_reset(__unused ipc_port_t special_reply_port)1870 ipc_special_reply_port_bits_reset(__unused ipc_port_t special_reply_port)
1871 {
1872 	return;
1873 }
1874 
1875 static inline void
ipc_special_reply_port_msg_sent_reset(__unused ipc_port_t special_reply_port)1876 ipc_special_reply_port_msg_sent_reset(__unused ipc_port_t special_reply_port)
1877 {
1878 	return;
1879 }
1880 
1881 inline void
ipc_special_reply_port_msg_sent(__unused ipc_port_t special_reply_port)1882 ipc_special_reply_port_msg_sent(__unused ipc_port_t special_reply_port)
1883 {
1884 	return;
1885 }
1886 
1887 static inline void
ipc_special_reply_port_lost_link(__unused ipc_port_t special_reply_port)1888 ipc_special_reply_port_lost_link(__unused ipc_port_t special_reply_port)
1889 {
1890 	return;
1891 }
1892 #endif /* DEVELOPMENT || DEBUG */
1893 
1894 /*
1895  *	Routine:	ipc_port_adjust_special_reply_port_locked
1896  *	Purpose:
1897  *		If the special port has a turnstile, update its inheritor.
1898  *	Condition:
1899  *		Special reply port locked on entry.
1900  *		Special reply port unlocked on return.
1901  *		The passed in port is a special reply port.
1902  *	Returns:
1903  *		None.
1904  */
1905 void
ipc_port_adjust_special_reply_port_locked(ipc_port_t special_reply_port,struct knote * kn,uint8_t flags,boolean_t get_turnstile)1906 ipc_port_adjust_special_reply_port_locked(
1907 	ipc_port_t special_reply_port,
1908 	struct knote *kn,
1909 	uint8_t flags,
1910 	boolean_t get_turnstile)
1911 {
1912 	ipc_port_t dest_port = IPC_PORT_NULL;
1913 	int sync_link_state = PORT_SYNC_LINK_NO_LINKAGE;
1914 	turnstile_inheritor_t inheritor = TURNSTILE_INHERITOR_NULL;
1915 	struct turnstile *ts = TURNSTILE_NULL;
1916 	struct turnstile *port_stashed_turnstile = TURNSTILE_NULL;
1917 
1918 	ip_mq_lock_held(special_reply_port); // ip_sync_link_state is touched
1919 
1920 	if (!special_reply_port->ip_specialreply) {
1921 		// only mach_msg_receive_results_complete() calls this with any port
1922 		assert(get_turnstile);
1923 		goto not_special;
1924 	}
1925 
1926 	if (flags & IPC_PORT_ADJUST_SR_RECEIVED_MSG) {
1927 		ipc_special_reply_port_msg_sent_reset(special_reply_port);
1928 	}
1929 
1930 	if (flags & IPC_PORT_ADJUST_UNLINK_THREAD) {
1931 		special_reply_port->ip_messages.imq_srp_owner_thread = NULL;
1932 	}
1933 
1934 	if (flags & IPC_PORT_ADJUST_RESET_BOOSTRAP_CHECKIN) {
1935 		special_reply_port->ip_sync_bootstrap_checkin = 0;
1936 	}
1937 
1938 	/* Check if the special reply port is marked non-special */
1939 	if (special_reply_port->ip_sync_link_state == PORT_SYNC_LINK_ANY) {
1940 not_special:
1941 		if (get_turnstile) {
1942 			turnstile_complete((uintptr_t)special_reply_port,
1943 			    port_rcv_turnstile_address(special_reply_port), NULL, TURNSTILE_SYNC_IPC);
1944 		}
1945 		ip_mq_unlock(special_reply_port);
1946 		if (get_turnstile) {
1947 			turnstile_cleanup();
1948 		}
1949 		return;
1950 	}
1951 
1952 	if (flags & IPC_PORT_ADJUST_SR_LINK_WORKLOOP) {
1953 		if (ITH_KNOTE_VALID(kn, MACH_MSG_TYPE_PORT_SEND_ONCE)) {
1954 			inheritor = filt_machport_stash_port(kn, special_reply_port,
1955 			    &sync_link_state);
1956 		}
1957 	} else if (flags & IPC_PORT_ADJUST_SR_ALLOW_SYNC_LINKAGE) {
1958 		sync_link_state = PORT_SYNC_LINK_ANY;
1959 	}
1960 
1961 	/* Check if need to break linkage */
1962 	if (!get_turnstile && sync_link_state == PORT_SYNC_LINK_NO_LINKAGE &&
1963 	    special_reply_port->ip_sync_link_state == PORT_SYNC_LINK_NO_LINKAGE) {
1964 		ip_mq_unlock(special_reply_port);
1965 		return;
1966 	}
1967 
1968 	switch (special_reply_port->ip_sync_link_state) {
1969 	case PORT_SYNC_LINK_PORT:
1970 		dest_port = special_reply_port->ip_sync_inheritor_port;
1971 		special_reply_port->ip_sync_inheritor_port = IPC_PORT_NULL;
1972 		break;
1973 	case PORT_SYNC_LINK_WORKLOOP_KNOTE:
1974 		special_reply_port->ip_sync_inheritor_knote = NULL;
1975 		break;
1976 	case PORT_SYNC_LINK_WORKLOOP_STASH:
1977 		port_stashed_turnstile = special_reply_port->ip_sync_inheritor_ts;
1978 		special_reply_port->ip_sync_inheritor_ts = NULL;
1979 		break;
1980 	}
1981 
1982 	/*
1983 	 * Stash (or unstash) the server's PID in the ip_sorights field of the
1984 	 * special reply port, so that stackshot can later retrieve who the client
1985 	 * is blocked on.
1986 	 */
1987 	if (special_reply_port->ip_sync_link_state == PORT_SYNC_LINK_PORT &&
1988 	    sync_link_state == PORT_SYNC_LINK_NO_LINKAGE) {
1989 		ipc_special_reply_stash_pid_locked(special_reply_port, pid_from_task(current_task()));
1990 	} else if (special_reply_port->ip_sync_link_state == PORT_SYNC_LINK_NO_LINKAGE &&
1991 	    sync_link_state == PORT_SYNC_LINK_ANY) {
1992 		/* If we are resetting the special reply port, remove the stashed pid. */
1993 		ipc_special_reply_stash_pid_locked(special_reply_port, 0);
1994 	}
1995 
1996 	special_reply_port->ip_sync_link_state = sync_link_state;
1997 
1998 	switch (sync_link_state) {
1999 	case PORT_SYNC_LINK_WORKLOOP_KNOTE:
2000 		special_reply_port->ip_sync_inheritor_knote = kn;
2001 		break;
2002 	case PORT_SYNC_LINK_WORKLOOP_STASH:
2003 		turnstile_reference(inheritor);
2004 		special_reply_port->ip_sync_inheritor_ts = inheritor;
2005 		break;
2006 	case PORT_SYNC_LINK_NO_LINKAGE:
2007 		if (flags & IPC_PORT_ADJUST_SR_ENABLE_EVENT) {
2008 			ipc_special_reply_port_lost_link(special_reply_port);
2009 		}
2010 		break;
2011 	}
2012 
2013 	/* Get thread's turnstile donated to special reply port */
2014 	if (get_turnstile) {
2015 		turnstile_complete((uintptr_t)special_reply_port,
2016 		    port_rcv_turnstile_address(special_reply_port), NULL, TURNSTILE_SYNC_IPC);
2017 	} else {
2018 		ts = ipc_port_rcv_turnstile(special_reply_port);
2019 		if (ts) {
2020 			turnstile_reference(ts);
2021 			ipc_port_recv_update_inheritor(special_reply_port, ts,
2022 			    TURNSTILE_IMMEDIATE_UPDATE);
2023 		}
2024 	}
2025 
2026 	ip_mq_unlock(special_reply_port);
2027 
2028 	if (get_turnstile) {
2029 		turnstile_cleanup();
2030 	} else if (ts) {
2031 		/* Call turnstile cleanup after dropping the interlock */
2032 		turnstile_update_inheritor_complete(ts, TURNSTILE_INTERLOCK_NOT_HELD);
2033 		turnstile_deallocate_safe(ts);
2034 	}
2035 
2036 	if (port_stashed_turnstile) {
2037 		turnstile_deallocate_safe(port_stashed_turnstile);
2038 	}
2039 
2040 	/* Release the ref on the dest port and its turnstile */
2041 	if (dest_port) {
2042 		ipc_port_send_turnstile_complete(dest_port);
2043 		/* release the reference on the dest port, space lock might be held */
2044 		ip_release_safe(dest_port);
2045 	}
2046 }
2047 
2048 /*
2049  *	Routine:	ipc_port_adjust_special_reply_port
2050  *	Purpose:
2051  *		If the special port has a turnstile, update its inheritor.
2052  *	Condition:
2053  *		Nothing locked.
2054  *	Returns:
2055  *		None.
2056  */
2057 void
ipc_port_adjust_special_reply_port(ipc_port_t port,uint8_t flags)2058 ipc_port_adjust_special_reply_port(
2059 	ipc_port_t port,
2060 	uint8_t flags)
2061 {
2062 	if (port->ip_specialreply) {
2063 		ip_mq_lock(port);
2064 		ipc_port_adjust_special_reply_port_locked(port, NULL, flags, FALSE);
2065 	}
2066 }
2067 
2068 /*
2069  *	Routine:	ipc_port_adjust_sync_link_state_locked
2070  *	Purpose:
2071  *		Update the sync link state of the port and the
2072  *		turnstile inheritor.
2073  *	Condition:
2074  *		Port locked on entry.
2075  *		Port locked on return.
2076  *	Returns:
2077  *              None.
2078  */
2079 void
ipc_port_adjust_sync_link_state_locked(ipc_port_t port,int sync_link_state,turnstile_inheritor_t inheritor)2080 ipc_port_adjust_sync_link_state_locked(
2081 	ipc_port_t port,
2082 	int sync_link_state,
2083 	turnstile_inheritor_t inheritor)
2084 {
2085 	switch (port->ip_sync_link_state) {
2086 	case PORT_SYNC_LINK_RCV_THREAD:
2087 		/* deallocate the thread reference for the inheritor */
2088 		thread_deallocate_safe(port->ip_messages.imq_inheritor_thread_ref);
2089 		break;
2090 	case PORT_SYNC_LINK_WORKLOOP_STASH:
2091 		/* deallocate the turnstile reference for the inheritor */
2092 		turnstile_deallocate_safe(port->ip_messages.imq_inheritor_turnstile);
2093 		break;
2094 	}
2095 
2096 	klist_init(&port->ip_klist);
2097 
2098 	switch (sync_link_state) {
2099 	case PORT_SYNC_LINK_WORKLOOP_KNOTE:
2100 		port->ip_messages.imq_inheritor_knote = inheritor;
2101 		break;
2102 	case PORT_SYNC_LINK_WORKLOOP_STASH:
2103 		/* knote can be deleted by userspace, take a reference on turnstile */
2104 		turnstile_reference(inheritor);
2105 		port->ip_messages.imq_inheritor_turnstile = inheritor;
2106 		break;
2107 	case PORT_SYNC_LINK_RCV_THREAD:
2108 		/* The thread could exit without clearing port state, take a thread ref */
2109 		thread_reference((thread_t)inheritor);
2110 		port->ip_messages.imq_inheritor_thread_ref = inheritor;
2111 		break;
2112 	default:
2113 		klist_init(&port->ip_klist);
2114 		sync_link_state = PORT_SYNC_LINK_ANY;
2115 	}
2116 
2117 	port->ip_sync_link_state = sync_link_state;
2118 }
2119 
2120 
2121 /*
2122  *	Routine:	ipc_port_adjust_port_locked
2123  *	Purpose:
2124  *		If the port has a turnstile, update its inheritor.
2125  *	Condition:
2126  *		Port locked on entry.
2127  *		Port unlocked on return.
2128  *	Returns:
2129  *		None.
2130  */
2131 void
ipc_port_adjust_port_locked(ipc_port_t port,struct knote * kn,boolean_t sync_bootstrap_checkin)2132 ipc_port_adjust_port_locked(
2133 	ipc_port_t port,
2134 	struct knote *kn,
2135 	boolean_t sync_bootstrap_checkin)
2136 {
2137 	int sync_link_state = PORT_SYNC_LINK_ANY;
2138 	turnstile_inheritor_t inheritor = TURNSTILE_INHERITOR_NULL;
2139 
2140 	ip_mq_lock_held(port); // ip_sync_link_state is touched
2141 	assert(!port->ip_specialreply);
2142 
2143 	if (kn) {
2144 		inheritor = filt_machport_stash_port(kn, port, &sync_link_state);
2145 		if (sync_link_state == PORT_SYNC_LINK_WORKLOOP_KNOTE) {
2146 			inheritor = kn;
2147 		}
2148 	} else if (sync_bootstrap_checkin) {
2149 		inheritor = current_thread();
2150 		sync_link_state = PORT_SYNC_LINK_RCV_THREAD;
2151 	}
2152 
2153 	ipc_port_adjust_sync_link_state_locked(port, sync_link_state, inheritor);
2154 	port->ip_sync_bootstrap_checkin = 0;
2155 
2156 	ipc_port_send_turnstile_recompute_push_locked(port);
2157 	/* port unlocked */
2158 }
2159 
2160 /*
2161  *	Routine:	ipc_port_clear_sync_rcv_thread_boost_locked
2162  *	Purpose:
2163  *		If the port is pushing on rcv thread, clear it.
2164  *	Condition:
2165  *		Port locked on entry
2166  *		Port unlocked on return.
2167  *	Returns:
2168  *		None.
2169  */
2170 void
ipc_port_clear_sync_rcv_thread_boost_locked(ipc_port_t port)2171 ipc_port_clear_sync_rcv_thread_boost_locked(
2172 	ipc_port_t port)
2173 {
2174 	ip_mq_lock_held(port); // ip_sync_link_state is touched
2175 
2176 	if (port->ip_sync_link_state != PORT_SYNC_LINK_RCV_THREAD) {
2177 		ip_mq_unlock(port);
2178 		return;
2179 	}
2180 
2181 	ipc_port_adjust_sync_link_state_locked(port, PORT_SYNC_LINK_ANY, NULL);
2182 
2183 	ipc_port_send_turnstile_recompute_push_locked(port);
2184 	/* port unlocked */
2185 }
2186 
2187 /*
2188  *	Routine:	ipc_port_add_watchport_elem_locked
2189  *	Purpose:
2190  *		Transfer the turnstile boost of watchport to task calling exec.
2191  *	Condition:
2192  *		Port locked on entry.
2193  *		Port unlocked on return.
2194  *	Returns:
2195  *		KERN_SUCESS on success.
2196  *		KERN_FAILURE otherwise.
2197  */
2198 kern_return_t
ipc_port_add_watchport_elem_locked(ipc_port_t port,struct task_watchport_elem * watchport_elem,struct task_watchport_elem ** old_elem)2199 ipc_port_add_watchport_elem_locked(
2200 	ipc_port_t                 port,
2201 	struct task_watchport_elem *watchport_elem,
2202 	struct task_watchport_elem **old_elem)
2203 {
2204 	ip_mq_lock_held(port);
2205 
2206 	/* Watchport boost only works for non-special active ports mapped in an ipc space */
2207 	if (!ip_active(port) || port->ip_specialreply ||
2208 	    !ip_in_a_space(port)) {
2209 		ip_mq_unlock(port);
2210 		return KERN_FAILURE;
2211 	}
2212 
2213 	if (port->ip_sync_link_state != PORT_SYNC_LINK_ANY) {
2214 		/* Sever the linkage if the port was pushing on knote */
2215 		ipc_port_adjust_sync_link_state_locked(port, PORT_SYNC_LINK_ANY, NULL);
2216 	}
2217 
2218 	*old_elem = ipc_port_update_watchport_elem(port, watchport_elem);
2219 
2220 	ipc_port_send_turnstile_recompute_push_locked(port);
2221 	/* port unlocked */
2222 	return KERN_SUCCESS;
2223 }
2224 
2225 /*
2226  *	Routine:	ipc_port_clear_watchport_elem_internal_conditional_locked
2227  *	Purpose:
2228  *		Remove the turnstile boost of watchport and recompute the push.
2229  *	Condition:
2230  *		Port locked on entry.
2231  *		Port unlocked on return.
2232  *	Returns:
2233  *		KERN_SUCESS on success.
2234  *		KERN_FAILURE otherwise.
2235  */
2236 kern_return_t
ipc_port_clear_watchport_elem_internal_conditional_locked(ipc_port_t port,struct task_watchport_elem * watchport_elem)2237 ipc_port_clear_watchport_elem_internal_conditional_locked(
2238 	ipc_port_t                 port,
2239 	struct task_watchport_elem *watchport_elem)
2240 {
2241 	ip_mq_lock_held(port);
2242 
2243 	if (ipc_port_watchport_elem(port) != watchport_elem) {
2244 		ip_mq_unlock(port);
2245 		return KERN_FAILURE;
2246 	}
2247 
2248 	ipc_port_clear_watchport_elem_internal(port);
2249 	ipc_port_send_turnstile_recompute_push_locked(port);
2250 	/* port unlocked */
2251 	return KERN_SUCCESS;
2252 }
2253 
2254 /*
2255  *	Routine:	ipc_port_replace_watchport_elem_conditional_locked
2256  *	Purpose:
2257  *		Replace the turnstile boost of watchport and recompute the push.
2258  *	Condition:
2259  *		Port locked on entry.
2260  *		Port unlocked on return.
2261  *	Returns:
2262  *		KERN_SUCESS on success.
2263  *		KERN_FAILURE otherwise.
2264  */
2265 kern_return_t
ipc_port_replace_watchport_elem_conditional_locked(ipc_port_t port,struct task_watchport_elem * old_watchport_elem,struct task_watchport_elem * new_watchport_elem)2266 ipc_port_replace_watchport_elem_conditional_locked(
2267 	ipc_port_t                 port,
2268 	struct task_watchport_elem *old_watchport_elem,
2269 	struct task_watchport_elem *new_watchport_elem)
2270 {
2271 	ip_mq_lock_held(port);
2272 
2273 	if (ipc_port_watchport_elem(port) != old_watchport_elem) {
2274 		ip_mq_unlock(port);
2275 		return KERN_FAILURE;
2276 	}
2277 
2278 	ipc_port_update_watchport_elem(port, new_watchport_elem);
2279 	ipc_port_send_turnstile_recompute_push_locked(port);
2280 	/* port unlocked */
2281 	return KERN_SUCCESS;
2282 }
2283 
2284 /*
2285  *	Routine:	ipc_port_clear_watchport_elem_internal
2286  *	Purpose:
2287  *		Remove the turnstile boost of watchport.
2288  *	Condition:
2289  *		Port locked on entry.
2290  *		Port locked on return.
2291  *	Returns:
2292  *		Old task_watchport_elem returned.
2293  */
2294 struct task_watchport_elem *
ipc_port_clear_watchport_elem_internal(ipc_port_t port)2295 ipc_port_clear_watchport_elem_internal(
2296 	ipc_port_t                 port)
2297 {
2298 	ip_mq_lock_held(port);
2299 
2300 	if (port->ip_specialreply) {
2301 		return NULL;
2302 	}
2303 
2304 	return ipc_port_update_watchport_elem(port, NULL);
2305 }
2306 
2307 /*
2308  *	Routine:	ipc_port_send_turnstile_recompute_push_locked
2309  *	Purpose:
2310  *		Update send turnstile inheritor of port and recompute the push.
2311  *	Condition:
2312  *		Port locked on entry.
2313  *		Port unlocked on return.
2314  *	Returns:
2315  *		None.
2316  */
2317 static void
ipc_port_send_turnstile_recompute_push_locked(ipc_port_t port)2318 ipc_port_send_turnstile_recompute_push_locked(
2319 	ipc_port_t port)
2320 {
2321 	struct turnstile *send_turnstile = port_send_turnstile(port);
2322 	if (send_turnstile) {
2323 		turnstile_reference(send_turnstile);
2324 		ipc_port_send_update_inheritor(port, send_turnstile,
2325 		    TURNSTILE_IMMEDIATE_UPDATE);
2326 	}
2327 	ip_mq_unlock(port);
2328 
2329 	if (send_turnstile) {
2330 		turnstile_update_inheritor_complete(send_turnstile,
2331 		    TURNSTILE_INTERLOCK_NOT_HELD);
2332 		turnstile_deallocate_safe(send_turnstile);
2333 	}
2334 }
2335 
2336 /*
2337  *	Routine:	ipc_port_get_watchport_inheritor
2338  *	Purpose:
2339  *		Returns inheritor for watchport.
2340  *
2341  *	Conditions:
2342  *		mqueue locked.
2343  *	Returns:
2344  *		watchport inheritor.
2345  */
2346 static thread_t
ipc_port_get_watchport_inheritor(ipc_port_t port)2347 ipc_port_get_watchport_inheritor(
2348 	ipc_port_t port)
2349 {
2350 	ip_mq_lock_held(port);
2351 	return ipc_port_watchport_elem(port)->twe_task->watchports->tw_thread;
2352 }
2353 
2354 /*
2355  *	Routine:	ipc_port_get_receiver_task
2356  *	Purpose:
2357  *		Returns receiver task pointer and its pid (if any) for port.
2358  *
2359  *	Conditions:
2360  *		Nothing locked. The routine takes port lock.
2361  */
2362 pid_t
ipc_port_get_receiver_task(ipc_port_t port,uintptr_t * task)2363 ipc_port_get_receiver_task(ipc_port_t port, uintptr_t *task)
2364 {
2365 	task_t receiver = TASK_NULL;
2366 	pid_t pid = -1;
2367 
2368 	if (!port) {
2369 		goto out;
2370 	}
2371 
2372 	ip_mq_lock(port);
2373 	if (ip_in_a_space(port) &&
2374 	    !ip_in_space(port, ipc_space_kernel) &&
2375 	    !ip_in_space(port, ipc_space_reply)) {
2376 		receiver = port->ip_receiver->is_task;
2377 		pid = task_pid(receiver);
2378 	}
2379 	ip_mq_unlock(port);
2380 
2381 out:
2382 	if (task) {
2383 		*task = (uintptr_t)receiver;
2384 	}
2385 	return pid;
2386 }
2387 
2388 /*
2389  *	Routine:	ipc_port_impcount_delta
2390  *	Purpose:
2391  *		Adjust only the importance count associated with a port.
2392  *		If there are any adjustments to be made to receiver task,
2393  *		those are handled elsewhere.
2394  *
2395  *		For now, be defensive during deductions to make sure the
2396  *		impcount for the port doesn't underflow zero.  This will
2397  *		go away when the port boost addition is made atomic (see
2398  *		note in ipc_port_importance_delta()).
2399  *	Conditions:
2400  *		The port is referenced and locked.
2401  *		Nothing else is locked.
2402  */
2403 mach_port_delta_t
ipc_port_impcount_delta(ipc_port_t port,mach_port_delta_t delta,ipc_port_t __unused base)2404 ipc_port_impcount_delta(
2405 	ipc_port_t        port,
2406 	mach_port_delta_t delta,
2407 	ipc_port_t        __unused base)
2408 {
2409 	mach_port_delta_t absdelta;
2410 
2411 	if (!ip_active(port)) {
2412 		return 0;
2413 	}
2414 
2415 	/* adding/doing nothing is easy */
2416 	if (delta >= 0) {
2417 		port->ip_impcount += delta;
2418 		return delta;
2419 	}
2420 
2421 	absdelta = 0 - delta;
2422 	if (port->ip_impcount >= absdelta) {
2423 		port->ip_impcount -= absdelta;
2424 		return delta;
2425 	}
2426 
2427 #if (DEVELOPMENT || DEBUG)
2428 	if (ip_in_a_space(port)) {
2429 		task_t target_task = port->ip_receiver->is_task;
2430 		ipc_importance_task_t target_imp = target_task->task_imp_base;
2431 		const char *target_procname;
2432 		int target_pid;
2433 
2434 		if (target_imp != IIT_NULL) {
2435 			target_procname = target_imp->iit_procname;
2436 			target_pid = target_imp->iit_bsd_pid;
2437 		} else {
2438 			target_procname = "unknown";
2439 			target_pid = -1;
2440 		}
2441 		printf("Over-release of importance assertions for port 0x%x receiver pid %d (%s), "
2442 		    "dropping %d assertion(s) but port only has %d remaining.\n",
2443 		    ip_get_receiver_name(port),
2444 		    target_pid, target_procname,
2445 		    absdelta, port->ip_impcount);
2446 	} else if (base != IP_NULL) {
2447 		assert(ip_in_a_space(base));
2448 		task_t target_task = base->ip_receiver->is_task;
2449 		ipc_importance_task_t target_imp = target_task->task_imp_base;
2450 		const char *target_procname;
2451 		int target_pid;
2452 
2453 		if (target_imp != IIT_NULL) {
2454 			target_procname = target_imp->iit_procname;
2455 			target_pid = target_imp->iit_bsd_pid;
2456 		} else {
2457 			target_procname = "unknown";
2458 			target_pid = -1;
2459 		}
2460 		printf("Over-release of importance assertions for port 0x%lx "
2461 		    "enqueued on port 0x%x with receiver pid %d (%s), "
2462 		    "dropping %d assertion(s) but port only has %d remaining.\n",
2463 		    (unsigned long)VM_KERNEL_UNSLIDE_OR_PERM((uintptr_t)port),
2464 		    ip_get_receiver_name(base),
2465 		    target_pid, target_procname,
2466 		    absdelta, port->ip_impcount);
2467 	}
2468 #endif
2469 
2470 	delta = 0 - port->ip_impcount;
2471 	port->ip_impcount = 0;
2472 	return delta;
2473 }
2474 
2475 /*
2476  *	Routine:	ipc_port_importance_delta_internal
2477  *	Purpose:
2478  *		Adjust the importance count through the given port.
2479  *		If the port is in transit, apply the delta throughout
2480  *		the chain. Determine if the there is a task at the
2481  *		base of the chain that wants/needs to be adjusted,
2482  *		and if so, apply the delta.
2483  *	Conditions:
2484  *		The port is referenced and locked on entry.
2485  *		Importance may be locked.
2486  *		Nothing else is locked.
2487  *		The lock may be dropped on exit.
2488  *		Returns TRUE if lock was dropped.
2489  */
2490 #if IMPORTANCE_INHERITANCE
2491 
2492 boolean_t
ipc_port_importance_delta_internal(ipc_port_t port,natural_t options,mach_port_delta_t * deltap,ipc_importance_task_t * imp_task)2493 ipc_port_importance_delta_internal(
2494 	ipc_port_t              port,
2495 	natural_t               options,
2496 	mach_port_delta_t       *deltap,
2497 	ipc_importance_task_t   *imp_task)
2498 {
2499 	ipc_port_t next, base;
2500 	bool dropped = false;
2501 	bool took_base_ref = false;
2502 
2503 	*imp_task = IIT_NULL;
2504 
2505 	if (*deltap == 0) {
2506 		return FALSE;
2507 	}
2508 
2509 	assert(options == IPID_OPTION_NORMAL || options == IPID_OPTION_SENDPOSSIBLE);
2510 
2511 	base = port;
2512 
2513 	/* if port is in transit, have to search for end of chain */
2514 	if (ip_in_transit(port)) {
2515 		dropped = true;
2516 
2517 
2518 		ip_mq_unlock(port);
2519 		ipc_port_multiple_lock(); /* massive serialization */
2520 
2521 		took_base_ref = ipc_port_destination_chain_lock(port, &base);
2522 		/* all ports in chain from port to base, inclusive, are locked */
2523 
2524 		ipc_port_multiple_unlock();
2525 	}
2526 
2527 	/*
2528 	 * If the port lock is dropped b/c the port is in transit, there is a
2529 	 * race window where another thread can drain messages and/or fire a
2530 	 * send possible notification before we get here.
2531 	 *
2532 	 * We solve this race by checking to see if our caller armed the send
2533 	 * possible notification, whether or not it's been fired yet, and
2534 	 * whether or not we've already set the port's ip_spimportant bit. If
2535 	 * we don't need a send-possible boost, then we'll just apply a
2536 	 * harmless 0-boost to the port.
2537 	 */
2538 	if (options & IPID_OPTION_SENDPOSSIBLE) {
2539 		assert(*deltap == 1);
2540 		if (port->ip_sprequests && port->ip_spimportant == 0) {
2541 			port->ip_spimportant = 1;
2542 		} else {
2543 			*deltap = 0;
2544 		}
2545 	}
2546 
2547 	/* unlock down to the base, adjusting boost(s) at each level */
2548 	for (;;) {
2549 		*deltap = ipc_port_impcount_delta(port, *deltap, base);
2550 
2551 		if (port == base) {
2552 			break;
2553 		}
2554 
2555 		/* port is in transit */
2556 		assert(port->ip_tempowner == 0);
2557 		assert(ip_in_transit(port));
2558 		next = ip_get_destination(port);
2559 		ip_mq_unlock(port);
2560 		port = next;
2561 	}
2562 
2563 	/* find the task (if any) to boost according to the base */
2564 	if (ip_active(base)) {
2565 		if (base->ip_tempowner != 0) {
2566 			if (IIT_NULL != ip_get_imp_task(base)) {
2567 				*imp_task = ip_get_imp_task(base);
2568 			}
2569 			/* otherwise don't boost */
2570 		} else if (ip_in_a_space(base)) {
2571 			ipc_space_t space = ip_get_receiver(base);
2572 
2573 			/* only spaces with boost-accepting tasks */
2574 			if (space->is_task != TASK_NULL &&
2575 			    ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base)) {
2576 				*imp_task = space->is_task->task_imp_base;
2577 			}
2578 		}
2579 	}
2580 
2581 	/*
2582 	 * Only the base is locked.  If we have to hold or drop task
2583 	 * importance assertions, we'll have to drop that lock as well.
2584 	 */
2585 	if (*imp_task != IIT_NULL) {
2586 		/* take a reference before unlocking base */
2587 		ipc_importance_task_reference(*imp_task);
2588 	}
2589 
2590 	if (dropped) {
2591 		ip_mq_unlock(base);
2592 		if (took_base_ref) {
2593 			/* importance lock might be held */
2594 			ip_release_safe(base);
2595 		}
2596 	}
2597 
2598 	return dropped;
2599 }
2600 #endif /* IMPORTANCE_INHERITANCE */
2601 
2602 /*
2603  *	Routine:	ipc_port_importance_delta
2604  *	Purpose:
2605  *		Adjust the importance count through the given port.
2606  *		If the port is in transit, apply the delta throughout
2607  *		the chain.
2608  *
2609  *		If there is a task at the base of the chain that wants/needs
2610  *		to be adjusted, apply the delta.
2611  *	Conditions:
2612  *		The port is referenced and locked on entry.
2613  *		Nothing else is locked.
2614  *		The lock may be dropped on exit.
2615  *		Returns TRUE if lock was dropped.
2616  */
2617 #if IMPORTANCE_INHERITANCE
2618 
2619 boolean_t
ipc_port_importance_delta(ipc_port_t port,natural_t options,mach_port_delta_t delta)2620 ipc_port_importance_delta(
2621 	ipc_port_t              port,
2622 	natural_t               options,
2623 	mach_port_delta_t       delta)
2624 {
2625 	ipc_importance_task_t imp_task = IIT_NULL;
2626 	boolean_t dropped;
2627 
2628 	dropped = ipc_port_importance_delta_internal(port, options, &delta, &imp_task);
2629 
2630 	if (IIT_NULL == imp_task || delta == 0) {
2631 		return dropped;
2632 	}
2633 
2634 	if (!dropped) {
2635 		ip_mq_unlock(port);
2636 	}
2637 
2638 	assert(ipc_importance_task_is_any_receiver_type(imp_task));
2639 
2640 	if (delta > 0) {
2641 		ipc_importance_task_hold_internal_assertion(imp_task, delta);
2642 	} else {
2643 		ipc_importance_task_drop_internal_assertion(imp_task, -delta);
2644 	}
2645 
2646 	ipc_importance_task_release(imp_task);
2647 	return TRUE;
2648 }
2649 #endif /* IMPORTANCE_INHERITANCE */
2650 
2651 /*
2652  *	Routine:	ipc_port_make_send_locked
2653  *	Purpose:
2654  *		Make a naked send right from a receive right.
2655  *
2656  *		See ipc_port_make_send for more extensive documentation.
2657  *
2658  *	Conditions:
2659  *		port locked and active.
2660  */
2661 ipc_port_t
ipc_port_make_send_locked(ipc_port_t port)2662 ipc_port_make_send_locked(
2663 	ipc_port_t      port)
2664 {
2665 	require_ip_active(port);
2666 	port->ip_mscount++;
2667 	port->ip_srights++;
2668 	ip_reference(port);
2669 	return port;
2670 }
2671 
2672 /*
2673  *	Routine:	ipc_port_make_send
2674  *	Purpose:
2675  *		Make a naked send right from a receive right.
2676  *
2677  *		ipc_port_make_send should not be used in any generic IPC
2678  *		plumbing, as this is an operation that subsystem
2679  *		owners need to be able to synchronize against
2680  *		with the make-send-count and no-senders notifications.
2681  *
2682  *		It is especially important for kobject types,
2683  *		and in general MIG upcalls or replies from the kernel
2684  *		should never use MAKE_SEND dispositions, and prefer
2685  *		COPY_SEND or MOVE_SEND, so that subsystems can control
2686  *		where that send right comes from.
2687  */
2688 ipc_port_t
ipc_port_make_send(ipc_port_t port)2689 ipc_port_make_send(
2690 	ipc_port_t      port)
2691 {
2692 	if (!IP_VALID(port)) {
2693 		return port;
2694 	}
2695 
2696 	ip_mq_lock(port);
2697 	if (ip_active(port)) {
2698 		ipc_port_make_send_locked(port);
2699 		ip_mq_unlock(port);
2700 		return port;
2701 	}
2702 	ip_mq_unlock(port);
2703 	return IP_DEAD;
2704 }
2705 
2706 /*
2707  *	Routine:	ipc_port_copy_send_locked
2708  *	Purpose:
2709  *		Make a naked send right from another naked send right.
2710  *	Conditions:
2711  *		port locked.
2712  */
2713 void
ipc_port_copy_send_locked(ipc_port_t port)2714 ipc_port_copy_send_locked(
2715 	ipc_port_t      port)
2716 {
2717 	assert(port->ip_srights > 0);
2718 	port->ip_srights++;
2719 	ip_reference(port);
2720 }
2721 
2722 /*
2723  *	Routine:	ipc_port_copy_send
2724  *	Purpose:
2725  *		Make a naked send right from another naked send right.
2726  *			IP_NULL		-> IP_NULL
2727  *			IP_DEAD		-> IP_DEAD
2728  *			dead port	-> IP_DEAD
2729  *			live port	-> port + ref
2730  *	Conditions:
2731  *		Nothing locked except possibly a space.
2732  */
2733 
2734 ipc_port_t
ipc_port_copy_send(ipc_port_t port)2735 ipc_port_copy_send(
2736 	ipc_port_t      port)
2737 {
2738 	ipc_port_t sright;
2739 
2740 	if (!IP_VALID(port)) {
2741 		return port;
2742 	}
2743 
2744 	ip_mq_lock(port);
2745 	if (ip_active(port)) {
2746 		ipc_port_copy_send_locked(port);
2747 		sright = port;
2748 	} else {
2749 		sright = IP_DEAD;
2750 	}
2751 	ip_mq_unlock(port);
2752 
2753 	return sright;
2754 }
2755 
2756 /*
2757  *	Routine:	ipc_port_copyout_send
2758  *	Purpose:
2759  *		Copyout a naked send right (possibly null/dead),
2760  *		or if that fails, destroy the right.
2761  *	Conditions:
2762  *		Nothing locked.
2763  */
2764 
2765 static mach_port_name_t
ipc_port_copyout_send_internal(ipc_port_t sright,ipc_space_t space,ipc_object_copyout_flags_t flags)2766 ipc_port_copyout_send_internal(
2767 	ipc_port_t      sright,
2768 	ipc_space_t     space,
2769 	ipc_object_copyout_flags_t flags)
2770 {
2771 	mach_port_name_t name;
2772 
2773 	if (IP_VALID(sright)) {
2774 		kern_return_t kr;
2775 
2776 		kr = ipc_object_copyout(space, ip_to_object(sright),
2777 		    MACH_MSG_TYPE_PORT_SEND, flags, NULL, NULL, &name);
2778 		if (kr != KERN_SUCCESS) {
2779 			if (kr == KERN_INVALID_CAPABILITY) {
2780 				name = MACH_PORT_DEAD;
2781 			} else {
2782 				name = MACH_PORT_NULL;
2783 			}
2784 		}
2785 	} else {
2786 		name = CAST_MACH_PORT_TO_NAME(sright);
2787 	}
2788 
2789 	return name;
2790 }
2791 
2792 mach_port_name_t
ipc_port_copyout_send(ipc_port_t sright,ipc_space_t space)2793 ipc_port_copyout_send(
2794 	ipc_port_t      sright, /* can be invalid */
2795 	ipc_space_t     space)
2796 {
2797 	return ipc_port_copyout_send_internal(sright, space, IPC_OBJECT_COPYOUT_FLAGS_NONE);
2798 }
2799 
2800 /* Used by pthread kext to copyout thread port only */
2801 mach_port_name_t
ipc_port_copyout_send_pinned(ipc_port_t sright,ipc_space_t space)2802 ipc_port_copyout_send_pinned(
2803 	ipc_port_t      sright, /* can be invalid */
2804 	ipc_space_t     space)
2805 {
2806 	assert(space->is_task != TASK_NULL);
2807 
2808 	if (IP_VALID(sright)) {
2809 		assert(ip_kotype(sright) == IKOT_THREAD_CONTROL);
2810 	}
2811 
2812 	if (task_is_pinned(space->is_task)) {
2813 		return ipc_port_copyout_send_internal(sright, space, IPC_OBJECT_COPYOUT_FLAGS_PINNED);
2814 	} else {
2815 		return ipc_port_copyout_send_internal(sright, space, IPC_OBJECT_COPYOUT_FLAGS_NONE);
2816 	}
2817 }
2818 
2819 /*
2820  *	Routine:	ipc_port_release_send_and_unlock
2821  *	Purpose:
2822  *		Release a naked send right.
2823  *		Consumes a ref for the port.
2824  *	Conditions:
2825  *		Port is valid and locked on entry
2826  *		Port is unlocked on exit.
2827  */
2828 void
ipc_port_release_send_and_unlock(ipc_port_t port)2829 ipc_port_release_send_and_unlock(
2830 	ipc_port_t      port)
2831 {
2832 	ipc_notify_nsenders_t nsrequest = { };
2833 
2834 	if (port->ip_srights == 0) {
2835 		panic("Over-release of port %p send right!", port);
2836 	}
2837 	port->ip_srights--;
2838 
2839 	if (ip_active(port) && port->ip_srights == 0) {
2840 		nsrequest = ipc_notify_no_senders_prepare(port);
2841 	}
2842 
2843 	ip_mq_unlock(port);
2844 	ip_release(port);
2845 
2846 	ipc_notify_no_senders_emit(nsrequest);
2847 }
2848 
2849 /*
2850  *	Routine:	ipc_port_release_send
2851  *	Purpose:
2852  *		Release a naked send right.
2853  *		Consumes a ref for the port.
2854  *	Conditions:
2855  *		Nothing locked.
2856  */
2857 
2858 void
ipc_port_release_send(ipc_port_t port)2859 ipc_port_release_send(
2860 	ipc_port_t      port)
2861 {
2862 	if (IP_VALID(port)) {
2863 		ip_mq_lock(port);
2864 		ipc_port_release_send_and_unlock(port);
2865 	}
2866 }
2867 
2868 /*
2869  *	Routine:	ipc_port_make_sonce_locked
2870  *	Purpose:
2871  *		Make a naked send-once right from a receive right.
2872  *	Conditions:
2873  *		The port is locked and active.
2874  */
2875 
2876 ipc_port_t
ipc_port_make_sonce_locked(ipc_port_t port)2877 ipc_port_make_sonce_locked(
2878 	ipc_port_t      port)
2879 {
2880 	require_ip_active(port);
2881 	port->ip_sorights++;
2882 	ip_reference(port);
2883 	return port;
2884 }
2885 
2886 /*
2887  *	Routine:	ipc_port_make_sonce
2888  *	Purpose:
2889  *		Make a naked send-once right from a receive right.
2890  *	Conditions:
2891  *		The port is not locked.
2892  */
2893 
2894 ipc_port_t
ipc_port_make_sonce(ipc_port_t port)2895 ipc_port_make_sonce(
2896 	ipc_port_t      port)
2897 {
2898 	if (!IP_VALID(port)) {
2899 		return port;
2900 	}
2901 
2902 	ip_mq_lock(port);
2903 	if (ip_active(port)) {
2904 		ipc_port_make_sonce_locked(port);
2905 		ip_mq_unlock(port);
2906 		return port;
2907 	}
2908 	ip_mq_unlock(port);
2909 	return IP_DEAD;
2910 }
2911 
2912 /*
2913  *	Routine:	ipc_port_release_sonce
2914  *	Purpose:
2915  *		Release a naked send-once right.
2916  *		Consumes a ref for the port.
2917  *
2918  *		In normal situations, this is never used.
2919  *		Send-once rights are only consumed when
2920  *		a message (possibly a send-once notification)
2921  *		is sent to them.
2922  *	Conditions:
2923  *		The port is locked, possibly a space too.
2924  */
2925 void
ipc_port_release_sonce_and_unlock(ipc_port_t port)2926 ipc_port_release_sonce_and_unlock(
2927 	ipc_port_t      port)
2928 {
2929 	ip_mq_lock_held(port);
2930 
2931 	if (port->ip_sorights == 0) {
2932 		panic("Over-release of port %p send-once right!", port);
2933 	}
2934 
2935 	port->ip_sorights--;
2936 
2937 	if (port->ip_specialreply) {
2938 		ipc_port_adjust_special_reply_port_locked(port, NULL,
2939 		    IPC_PORT_ADJUST_RESET_BOOSTRAP_CHECKIN, FALSE);
2940 	} else {
2941 		ip_mq_unlock(port);
2942 	}
2943 
2944 	ip_release(port);
2945 }
2946 
2947 /*
2948  *	Routine:	ipc_port_release_sonce
2949  *	Purpose:
2950  *		Release a naked send-once right.
2951  *		Consumes a ref for the port.
2952  *
2953  *		In normal situations, this is never used.
2954  *		Send-once rights are only consumed when
2955  *		a message (possibly a send-once notification)
2956  *		is sent to them.
2957  *	Conditions:
2958  *		Nothing locked except possibly a space.
2959  */
2960 void
ipc_port_release_sonce(ipc_port_t port)2961 ipc_port_release_sonce(
2962 	ipc_port_t      port)
2963 {
2964 	if (IP_VALID(port)) {
2965 		ip_mq_lock(port);
2966 		ipc_port_release_sonce_and_unlock(port);
2967 	}
2968 }
2969 
2970 /*
2971  *	Routine:	ipc_port_release_receive
2972  *	Purpose:
2973  *		Release a naked (in limbo or in transit) receive right.
2974  *		Consumes a ref for the port; destroys the port.
2975  *	Conditions:
2976  *		Nothing locked.
2977  */
2978 
2979 void
ipc_port_release_receive(ipc_port_t port)2980 ipc_port_release_receive(
2981 	ipc_port_t      port)
2982 {
2983 	ipc_port_t dest;
2984 
2985 	if (!IP_VALID(port)) {
2986 		return;
2987 	}
2988 
2989 	ip_mq_lock(port);
2990 	require_ip_active(port);
2991 	assert(!ip_in_a_space(port));
2992 	dest = ip_get_destination(port);
2993 
2994 	ipc_port_destroy(port); /* consumes ref, unlocks */
2995 
2996 	if (dest != IP_NULL) {
2997 		ipc_port_send_turnstile_complete(dest);
2998 		ip_release(dest);
2999 	}
3000 }
3001 
3002 /*
3003  *	Routine:	ipc_port_alloc_special
3004  *	Purpose:
3005  *		Allocate a port in a special space.
3006  *		The new port is returned with one ref.
3007  *		If unsuccessful, IP_NULL is returned.
3008  *	Conditions:
3009  *		Nothing locked.
3010  */
3011 
3012 ipc_port_t
ipc_port_alloc_special(ipc_space_t space,ipc_port_init_flags_t flags)3013 ipc_port_alloc_special(
3014 	ipc_space_t             space,
3015 	ipc_port_init_flags_t   flags)
3016 {
3017 	ipc_port_t port;
3018 
3019 	port = ip_object_to_port(io_alloc(IOT_PORT, Z_WAITOK | Z_ZERO));
3020 	if (port == IP_NULL) {
3021 		return IP_NULL;
3022 	}
3023 
3024 	os_atomic_init(&port->ip_object.io_bits, io_makebits(TRUE, IOT_PORT, 0));
3025 	os_atomic_init(&port->ip_object.io_references, 1);
3026 
3027 	ipc_port_init(port, space, flags, MACH_PORT_SPECIAL_DEFAULT);
3028 	return port;
3029 }
3030 
3031 /*
3032  *	Routine:	ipc_port_dealloc_special_and_unlock
3033  *	Purpose:
3034  *		Deallocate a port in a special space.
3035  *		Consumes one ref for the port.
3036  *	Conditions:
3037  *		Port is locked.
3038  */
3039 
3040 void
ipc_port_dealloc_special_and_unlock(ipc_port_t port,__assert_only ipc_space_t space)3041 ipc_port_dealloc_special_and_unlock(
3042 	ipc_port_t                      port,
3043 	__assert_only ipc_space_t       space)
3044 {
3045 	require_ip_active(port);
3046 //	assert(port->ip_receiver_name != MACH_PORT_NULL);
3047 	assert(ip_in_space(port, space));
3048 
3049 	/*
3050 	 *	We clear ip_receiver_name and ip_receiver to simplify
3051 	 *	the ipc_space_kernel check in ipc_mqueue_send.
3052 	 */
3053 
3054 	/* port transtions to IN-LIMBO state */
3055 	port->ip_receiver_name = MACH_PORT_NULL;
3056 	port->ip_receiver = IS_NULL;
3057 
3058 	/* relevant part of ipc_port_clear_receiver */
3059 	port->ip_mscount = 0;
3060 	port->ip_messages.imq_seqno = 0;
3061 
3062 	ipc_port_destroy(port);
3063 }
3064 
3065 /*
3066  *	Routine:	ipc_port_dealloc_special
3067  *	Purpose:
3068  *		Deallocate a port in a special space.
3069  *		Consumes one ref for the port.
3070  *	Conditions:
3071  *		Nothing locked.
3072  */
3073 
3074 void
ipc_port_dealloc_special(ipc_port_t port,ipc_space_t space)3075 ipc_port_dealloc_special(
3076 	ipc_port_t        port,
3077 	ipc_space_t       space)
3078 {
3079 	ip_mq_lock(port);
3080 	ipc_port_dealloc_special_and_unlock(port, space);
3081 }
3082 
3083 /*
3084  *	Routine:	ipc_port_finalize
3085  *	Purpose:
3086  *		Called on last reference deallocate to
3087  *		free any remaining data associated with the
3088  *		port.
3089  *	Conditions:
3090  *		Nothing locked.
3091  */
3092 void
ipc_port_finalize(ipc_port_t port)3093 ipc_port_finalize(
3094 	ipc_port_t              port)
3095 {
3096 	ipc_port_request_t requests = port->ip_requests;
3097 
3098 	assert(port_send_turnstile(port) == TURNSTILE_NULL);
3099 	if (waitq_is_turnstile_proxy(&port->ip_waitq)) {
3100 		assert(ipc_port_rcv_turnstile(port) == TURNSTILE_NULL);
3101 	}
3102 
3103 	if (ip_active(port)) {
3104 		panic("Trying to free an active port. port %p", port);
3105 	}
3106 
3107 	if (requests != IPR_NULL) {
3108 		ipc_table_size_t its = requests->ipr_size;
3109 		it_requests_free(its, requests);
3110 		port->ip_requests = IPR_NULL;
3111 	}
3112 
3113 	/*
3114 	 * (81997111) now it is safe to deallocate the prealloc message.
3115 	 * Keep the IP_BIT_PREALLOC bit, it has to be sticky as the turnstile
3116 	 * code looks at it without holding locks.
3117 	 */
3118 	if (IP_PREALLOC(port)) {
3119 		ipc_kmsg_t kmsg = port->ip_premsg;
3120 
3121 		if (kmsg == IKM_NULL || ikm_prealloc_inuse_port(kmsg) ||
3122 		    kmsg->ikm_turnstile != TURNSTILE_NULL) {
3123 			panic("port(%p, %p): prealloc message in an invalid state",
3124 			    port, kmsg);
3125 		}
3126 
3127 		port->ip_premsg = IKM_NULL;
3128 		ipc_kmsg_free(kmsg);
3129 	}
3130 
3131 	waitq_deinit(&port->ip_waitq);
3132 }
3133 
3134 /*
3135  *	Routine:	kdp_mqueue_send_find_owner
3136  *	Purpose:
3137  *		Discover the owner of the ipc object that contains the input
3138  *		waitq object. The thread blocked on the waitq should be
3139  *		waiting for an IPC_MQUEUE_FULL event.
3140  *	Conditions:
3141  *		The 'waitinfo->wait_type' value should already be set to
3142  *		kThreadWaitPortSend.
3143  *	Note:
3144  *		If we find out that the containing port is actually in
3145  *		transit, we reset the wait_type field to reflect this.
3146  */
3147 void
kdp_mqueue_send_find_owner(struct waitq * waitq,__assert_only event64_t event,thread_waitinfo_t * waitinfo)3148 kdp_mqueue_send_find_owner(
3149 	struct waitq               *waitq,
3150 	__assert_only event64_t     event,
3151 	thread_waitinfo_t          *waitinfo)
3152 {
3153 	struct turnstile *turnstile;
3154 	assert(waitinfo->wait_type == kThreadWaitPortSend);
3155 	assert(event == IPC_MQUEUE_FULL);
3156 	assert(waitq_is_turnstile_queue(waitq));
3157 
3158 	turnstile = waitq_to_turnstile(waitq);
3159 	ipc_port_t port = (ipc_port_t)turnstile->ts_proprietor; /* we are blocking on send */
3160 
3161 	zone_id_require(ZONE_ID_IPC_PORT, sizeof(struct ipc_port), port);
3162 
3163 	waitinfo->owner = 0;
3164 	waitinfo->context  = VM_KERNEL_UNSLIDE_OR_PERM(port);
3165 	if (ip_mq_lock_held_kdp(port)) {
3166 		/*
3167 		 * someone has the port locked: it may be in an
3168 		 * inconsistent state: bail
3169 		 */
3170 		waitinfo->owner = STACKSHOT_WAITOWNER_PORT_LOCKED;
3171 		return;
3172 	}
3173 
3174 	/* now we are the only one accessing the port */
3175 	if (ip_active(port)) {
3176 		/*
3177 		 * In kdp context, port must be left unlocked throughout.
3178 		 * Therefore can't use union field accessor helpers, manually strip PAC
3179 		 * and compare raw pointer.
3180 		 */
3181 		void *raw_ptr = ip_get_receiver_ptr_noauth(port);
3182 
3183 		if (port->ip_tempowner) {
3184 			ipc_importance_task_t imp_task = ip_get_imp_task(port);
3185 			if (imp_task != IIT_NULL && imp_task->iit_task != NULL) {
3186 				/* port is held by a tempowner */
3187 				waitinfo->owner = pid_from_task(port->ip_imp_task->iit_task);
3188 			} else {
3189 				waitinfo->owner = STACKSHOT_WAITOWNER_INTRANSIT;
3190 			}
3191 		} else if (ip_in_a_space(port)) { /* no port lock needed */
3192 			if ((ipc_space_t)raw_ptr == ipc_space_kernel) { /* access union field as ip_receiver */
3193 				/*
3194 				 * The kernel pid is 0, make this
3195 				 * distinguishable from no-owner and
3196 				 * inconsistent port state.
3197 				 */
3198 				waitinfo->owner = STACKSHOT_WAITOWNER_KERNEL;
3199 			} else {
3200 				waitinfo->owner = pid_from_task(((ipc_space_t)raw_ptr)->is_task);
3201 			}
3202 		} else if ((ipc_port_t)raw_ptr != IP_NULL) { /* access union field as ip_destination */
3203 			waitinfo->wait_type = kThreadWaitPortSendInTransit;
3204 			waitinfo->owner     = VM_KERNEL_UNSLIDE_OR_PERM((ipc_port_t)raw_ptr);
3205 		}
3206 	}
3207 }
3208 
3209 /*
3210  *	Routine:	kdp_mqueue_recv_find_owner
3211  *	Purpose:
3212  *		Discover the "owner" of the ipc object that contains the input
3213  *		waitq object. The thread blocked on the waitq is trying to
3214  *		receive on the mqueue.
3215  *	Conditions:
3216  *		The 'waitinfo->wait_type' value should already be set to
3217  *		kThreadWaitPortReceive.
3218  *	Note:
3219  *		If we find that we are actualy waiting on a port set, we reset
3220  *		the wait_type field to reflect this.
3221  */
3222 void
kdp_mqueue_recv_find_owner(struct waitq * waitq,__assert_only event64_t event,thread_waitinfo_t * waitinfo)3223 kdp_mqueue_recv_find_owner(
3224 	struct waitq               *waitq,
3225 	__assert_only event64_t     event,
3226 	thread_waitinfo_t          *waitinfo)
3227 {
3228 	assert(waitinfo->wait_type == kThreadWaitPortReceive);
3229 	assert(event == IPC_MQUEUE_RECEIVE);
3230 
3231 	waitinfo->owner = 0;
3232 	if (waitq_is_set(waitq)) {
3233 		ipc_pset_t set = ips_from_waitq(waitq);
3234 
3235 		zone_id_require(ZONE_ID_IPC_PORT_SET, sizeof(struct ipc_pset), set);
3236 
3237 		/* Reset wait type to specify waiting on port set receive */
3238 		waitinfo->wait_type = kThreadWaitPortSetReceive;
3239 		waitinfo->context   = VM_KERNEL_UNSLIDE_OR_PERM(set);
3240 		if (ips_mq_lock_held_kdp(set)) {
3241 			waitinfo->owner = STACKSHOT_WAITOWNER_PSET_LOCKED;
3242 		}
3243 		/* There is no specific owner "at the other end" of a port set, so leave unset. */
3244 	} else {
3245 		ipc_port_t port = ip_from_waitq(waitq);
3246 
3247 		zone_id_require(ZONE_ID_IPC_PORT, sizeof(struct ipc_port), port);
3248 
3249 		waitinfo->context = VM_KERNEL_UNSLIDE_OR_PERM(port);
3250 		if (ip_mq_lock_held_kdp(port)) {
3251 			waitinfo->owner = STACKSHOT_WAITOWNER_PORT_LOCKED;
3252 			return;
3253 		}
3254 
3255 		if (ip_active(port)) {
3256 			if (ip_in_a_space(port)) { /* no port lock needed */
3257 				waitinfo->owner = ip_get_receiver_name(port);
3258 			} else {
3259 				waitinfo->owner = STACKSHOT_WAITOWNER_INTRANSIT;
3260 			}
3261 		}
3262 	}
3263 }
3264 
3265 void
ipc_port_set_label(ipc_port_t port,ipc_label_t label)3266 ipc_port_set_label(
3267 	ipc_port_t              port,
3268 	ipc_label_t             label)
3269 {
3270 	ipc_kobject_label_t labelp;
3271 
3272 	assert(!ip_is_kolabeled(port));
3273 
3274 	labelp = zalloc_flags(ipc_kobject_label_zone, Z_WAITOK | Z_ZERO | Z_NOFAIL);
3275 	labelp->ikol_label = label;
3276 
3277 	port->ip_kolabel = labelp;
3278 	io_bits_or(ip_to_object(port), IO_BITS_KOLABEL);
3279 }
3280 
3281 #if MACH_ASSERT
3282 #include <kern/machine.h>
3283 
3284 unsigned long   port_count = 0;
3285 unsigned long   port_count_warning = 20000;
3286 unsigned long   port_timestamp = 0;
3287 
3288 void            db_port_stack_trace(
3289 	ipc_port_t      port);
3290 void            db_ref(
3291 	int             refs);
3292 int             db_port_walk(
3293 	unsigned int    verbose,
3294 	unsigned int    display,
3295 	unsigned int    ref_search,
3296 	unsigned int    ref_target);
3297 
3298 #ifdef MACH_BSD
3299 extern int proc_pid(struct proc*);
3300 #endif /* MACH_BSD */
3301 
3302 /*
3303  *	Initialize all of the debugging state in a port.
3304  *	Insert the port into a global list of all allocated ports.
3305  */
3306 void
ipc_port_init_debug(ipc_port_t port,void * fp)3307 ipc_port_init_debug(ipc_port_t port, void *fp)
3308 {
3309 	port->ip_thread = current_thread();
3310 	port->ip_timetrack = port_timestamp++;
3311 
3312 	if (ipc_portbt) {
3313 		struct backtrace_control ctl = {
3314 			.btc_frame_addr = (uintptr_t)fp,
3315 		};
3316 		backtrace(port->ip_callstack, IP_CALLSTACK_MAX, &ctl, NULL);
3317 	}
3318 
3319 #ifdef MACH_BSD
3320 	task_t task = current_task_early();
3321 	if (task != TASK_NULL) {
3322 		struct proc* proc = (struct proc*) get_bsdtask_info(task);
3323 		if (proc) {
3324 			port->ip_spares[0] = proc_pid(proc);
3325 		}
3326 	}
3327 #endif /* MACH_BSD */
3328 }
3329 
3330 #endif  /* MACH_ASSERT */
3331