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