xref: /xnu-8020.121.3/osfmk/ipc/ipc_importance.c (revision fdd8201d7b966f0c3ea610489d29bd841d358941) !
1 /*
2  * Copyright (c) 2013-2020 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 #include <mach/mach_types.h>
30 #include <mach/notify.h>
31 #include <ipc/ipc_types.h>
32 #include <ipc/ipc_importance.h>
33 #include <ipc/ipc_port.h>
34 #include <ipc/ipc_voucher.h>
35 #include <kern/ipc_kobject.h>
36 #include <kern/ipc_tt.h>
37 #include <kern/mach_param.h>
38 #include <kern/misc_protos.h>
39 #include <kern/zalloc.h>
40 #include <kern/queue.h>
41 #include <kern/task.h>
42 #include <kern/policy_internal.h>
43 
44 #include <sys/kdebug.h>
45 
46 #include <mach/mach_voucher_attr_control.h>
47 #include <mach/machine/sdt.h>
48 
49 extern int      proc_pid(void *);
50 extern int      proc_selfpid(void);
51 extern uint64_t proc_uniqueid(void *p);
52 extern char     *proc_name_address(void *p);
53 
54 /*
55  * Globals for delayed boost drop processing.
56  */
57 static queue_head_t ipc_importance_delayed_drop_queue;
58 static thread_call_t ipc_importance_delayed_drop_call;
59 static uint64_t ipc_importance_delayed_drop_timestamp;
60 static boolean_t ipc_importance_delayed_drop_call_requested = FALSE;
61 
62 #define DENAP_DROP_TARGET (1000 * NSEC_PER_MSEC) /* optimum denap delay */
63 #define DENAP_DROP_SKEW    (100 * NSEC_PER_MSEC) /* request skew for wakeup */
64 #define DENAP_DROP_LEEWAY  (2 * DENAP_DROP_SKEW)  /* specified wakeup leeway */
65 
66 #define DENAP_DROP_DELAY (DENAP_DROP_TARGET + DENAP_DROP_SKEW)
67 #define DENAP_DROP_FLAGS (THREAD_CALL_DELAY_SYS_NORMAL | THREAD_CALL_DELAY_LEEWAY)
68 
69 /*
70  * Importance Voucher Attribute Manager
71  */
72 static LCK_SPIN_DECLARE_ATTR(ipc_importance_lock_data, &ipc_lck_grp, &ipc_lck_attr);
73 
74 #define ipc_importance_lock() \
75 	lck_spin_lock_grp(&ipc_importance_lock_data, &ipc_lck_grp)
76 #define ipc_importance_lock_try() \
77 	lck_spin_try_lock_grp(&ipc_importance_lock_data, &ipc_lck_grp)
78 #define ipc_importance_unlock() \
79 	lck_spin_unlock(&ipc_importance_lock_data)
80 #define ipc_importance_assert_held() \
81 	lck_spin_assert(&ipc_importance_lock_data, LCK_ASSERT_OWNED)
82 
83 #if IIE_REF_DEBUG
84 #define incr_ref_counter(x) (os_atomic_inc(&(x), relaxed))
85 
86 static inline
87 uint32_t
ipc_importance_reference_internal(ipc_importance_elem_t elem)88 ipc_importance_reference_internal(ipc_importance_elem_t elem)
89 {
90 	incr_ref_counter(elem->iie_refs_added);
91 	return os_atomic_inc(&elem->iie_bits, relaxed) & IIE_REFS_MASK;
92 }
93 
94 static inline
95 uint32_t
ipc_importance_release_internal(ipc_importance_elem_t elem)96 ipc_importance_release_internal(ipc_importance_elem_t elem)
97 {
98 	incr_ref_counter(elem->iie_refs_dropped);
99 	return os_atomic_dec(&elem->iie_bits, relaxed) & IIE_REFS_MASK;
100 }
101 
102 static inline
103 uint32_t
ipc_importance_task_reference_internal(ipc_importance_task_t task_imp)104 ipc_importance_task_reference_internal(ipc_importance_task_t task_imp)
105 {
106 	uint32_t out;
107 	out = ipc_importance_reference_internal(&task_imp->iit_elem);
108 	incr_ref_counter(task_imp->iit_elem.iie_task_refs_added);
109 	return out;
110 }
111 
112 static inline
113 uint32_t
ipc_importance_task_release_internal(ipc_importance_task_t task_imp)114 ipc_importance_task_release_internal(ipc_importance_task_t task_imp)
115 {
116 	uint32_t out;
117 
118 	assert(1 < IIT_REFS(task_imp));
119 	incr_ref_counter(task_imp->iit_elem.iie_task_refs_dropped);
120 	out = ipc_importance_release_internal(&task_imp->iit_elem);
121 	return out;
122 }
123 
124 static inline
125 void
ipc_importance_counter_init(ipc_importance_elem_t elem)126 ipc_importance_counter_init(ipc_importance_elem_t elem)
127 {
128 	elem->iie_refs_added = 0;
129 	elem->iie_refs_dropped = 0;
130 	elem->iie_kmsg_refs_added = 0;
131 	elem->iie_kmsg_refs_inherited = 0;
132 	elem->iie_kmsg_refs_coalesced = 0;
133 	elem->iie_kmsg_refs_dropped = 0;
134 	elem->iie_task_refs_added = 0;
135 	elem->iie_task_refs_added_inherit_from = 0;
136 	elem->iie_task_refs_added_transition = 0;
137 	elem->iie_task_refs_self_added = 0;
138 	elem->iie_task_refs_inherited = 0;
139 	elem->iie_task_refs_coalesced = 0;
140 	elem->iie_task_refs_dropped = 0;
141 }
142 #else
143 #define incr_ref_counter(x)
144 #endif
145 
146 #if DEVELOPMENT || DEBUG
147 static queue_head_t global_iit_alloc_queue =
148     QUEUE_HEAD_INITIALIZER(global_iit_alloc_queue);
149 #endif
150 
151 static ZONE_DEFINE_TYPE(ipc_importance_task_zone, "ipc task importance",
152     struct ipc_importance_task, ZC_ZFREE_CLEARMEM);
153 static ZONE_DEFINE_TYPE(ipc_importance_inherit_zone, "ipc importance inherit",
154     struct ipc_importance_inherit, ZC_ZFREE_CLEARMEM);
155 static zone_t ipc_importance_inherit_zone;
156 
157 static ipc_voucher_attr_control_t ipc_importance_control;
158 
159 static boolean_t ipc_importance_task_check_transition(ipc_importance_task_t task_imp,
160     iit_update_type_t type, uint32_t delta);
161 
162 static void ipc_importance_task_propagate_assertion_locked(ipc_importance_task_t task_imp,
163     iit_update_type_t type, boolean_t update_task_imp);
164 
165 static ipc_importance_inherit_t ipc_importance_inherit_from_task(task_t from_task, task_t to_task);
166 
167 /*
168  *	Routine:	ipc_importance_kmsg_link
169  *	Purpose:
170  *		Link the kmsg onto the appropriate propagation chain.
171  *		If the element is a task importance, we link directly
172  *		on its propagation chain. Otherwise, we link onto the
173  *		destination task of the inherit.
174  *	Conditions:
175  *		Importance lock held.
176  *		Caller is donating an importance elem reference to the kmsg.
177  */
178 static void
ipc_importance_kmsg_link(ipc_kmsg_t kmsg,ipc_importance_elem_t elem)179 ipc_importance_kmsg_link(
180 	ipc_kmsg_t              kmsg,
181 	ipc_importance_elem_t   elem)
182 {
183 	ipc_importance_elem_t link_elem;
184 
185 	assert(IIE_NULL == kmsg->ikm_importance);
186 
187 	link_elem = (IIE_TYPE_INHERIT == IIE_TYPE(elem)) ?
188 	    (ipc_importance_elem_t)((ipc_importance_inherit_t)elem)->iii_to_task :
189 	    elem;
190 
191 	queue_enter(&link_elem->iie_kmsgs, kmsg, ipc_kmsg_t, ikm_inheritance);
192 	kmsg->ikm_importance = elem;
193 }
194 
195 /*
196  *	Routine:	ipc_importance_kmsg_unlink
197  *	Purpose:
198  *		Unlink the kmsg from its current propagation chain.
199  *		If the element is a task importance, we unlink directly
200  *		from its propagation chain. Otherwise, we unlink from the
201  *		destination task of the inherit.
202  *	Returns:
203  *		The reference to the importance element it was linked on.
204  *	Conditions:
205  *		Importance lock held.
206  *		Caller is responsible for dropping reference on returned elem.
207  */
208 static ipc_importance_elem_t
ipc_importance_kmsg_unlink(ipc_kmsg_t kmsg)209 ipc_importance_kmsg_unlink(
210 	ipc_kmsg_t              kmsg)
211 {
212 	ipc_importance_elem_t elem = kmsg->ikm_importance;
213 
214 	if (IIE_NULL != elem) {
215 		ipc_importance_elem_t unlink_elem;
216 
217 		unlink_elem = (IIE_TYPE_INHERIT == IIE_TYPE(elem)) ?
218 		    (ipc_importance_elem_t)((ipc_importance_inherit_t)elem)->iii_to_task :
219 		    elem;
220 
221 		queue_remove(&unlink_elem->iie_kmsgs, kmsg, ipc_kmsg_t, ikm_inheritance);
222 		kmsg->ikm_importance = IIE_NULL;
223 	}
224 	return elem;
225 }
226 
227 /*
228  *	Routine:	ipc_importance_inherit_link
229  *	Purpose:
230  *		Link the inherit onto the appropriate propagation chain.
231  *		If the element is a task importance, we link directly
232  *		on its propagation chain. Otherwise, we link onto the
233  *		destination task of the inherit.
234  *	Conditions:
235  *		Importance lock held.
236  *		Caller is donating an elem importance reference to the inherit.
237  */
238 static void
ipc_importance_inherit_link(ipc_importance_inherit_t inherit,ipc_importance_elem_t elem)239 ipc_importance_inherit_link(
240 	ipc_importance_inherit_t inherit,
241 	ipc_importance_elem_t elem)
242 {
243 	ipc_importance_task_t link_task;
244 
245 	assert(IIE_NULL == inherit->iii_from_elem);
246 	link_task = (IIE_TYPE_INHERIT == IIE_TYPE(elem)) ?
247 	    ((ipc_importance_inherit_t)elem)->iii_to_task :
248 	    (ipc_importance_task_t)elem;
249 
250 	queue_enter(&link_task->iit_inherits, inherit,
251 	    ipc_importance_inherit_t, iii_inheritance);
252 	inherit->iii_from_elem = elem;
253 }
254 
255 /*
256  *	Routine:	ipc_importance_inherit_find
257  *	Purpose:
258  *		Find an existing inherit that links the from element to the
259  *		to_task at a given nesting depth.  As inherits from other
260  *		inherits are actually linked off the original inherit's donation
261  *		receiving task, we have to conduct our search from there if
262  *		the from element is an inherit.
263  *	Returns:
264  *		A pointer (not a reference) to the matching inherit.
265  *	Conditions:
266  *		Importance lock held.
267  */
268 static ipc_importance_inherit_t
ipc_importance_inherit_find(ipc_importance_elem_t from,ipc_importance_task_t to_task,unsigned int depth)269 ipc_importance_inherit_find(
270 	ipc_importance_elem_t from,
271 	ipc_importance_task_t to_task,
272 	unsigned int depth)
273 {
274 	ipc_importance_task_t link_task;
275 	ipc_importance_inherit_t inherit;
276 
277 	link_task = (IIE_TYPE_INHERIT == IIE_TYPE(from)) ?
278 	    ((ipc_importance_inherit_t)from)->iii_to_task :
279 	    (ipc_importance_task_t)from;
280 
281 	queue_iterate(&link_task->iit_inherits, inherit,
282 	    ipc_importance_inherit_t, iii_inheritance) {
283 		if (inherit->iii_to_task == to_task && inherit->iii_depth == depth) {
284 			return inherit;
285 		}
286 	}
287 	return III_NULL;
288 }
289 
290 /*
291  *	Routine:	ipc_importance_inherit_unlink
292  *	Purpose:
293  *		Unlink the inherit from its current propagation chain.
294  *		If the element is a task importance, we unlink directly
295  *		from its propagation chain. Otherwise, we unlink from the
296  *		destination task of the inherit.
297  *	Returns:
298  *		The reference to the importance element it was linked on.
299  *	Conditions:
300  *		Importance lock held.
301  *		Caller is responsible for dropping reference on returned elem.
302  */
303 static ipc_importance_elem_t
ipc_importance_inherit_unlink(ipc_importance_inherit_t inherit)304 ipc_importance_inherit_unlink(
305 	ipc_importance_inherit_t inherit)
306 {
307 	ipc_importance_elem_t elem = inherit->iii_from_elem;
308 
309 	if (IIE_NULL != elem) {
310 		ipc_importance_task_t unlink_task;
311 
312 		unlink_task = (IIE_TYPE_INHERIT == IIE_TYPE(elem)) ?
313 		    ((ipc_importance_inherit_t)elem)->iii_to_task :
314 		    (ipc_importance_task_t)elem;
315 
316 		queue_remove(&unlink_task->iit_inherits, inherit,
317 		    ipc_importance_inherit_t, iii_inheritance);
318 		inherit->iii_from_elem = IIE_NULL;
319 	}
320 	return elem;
321 }
322 
323 /*
324  *	Routine:	ipc_importance_reference
325  *	Purpose:
326  *		Add a reference to the importance element.
327  *	Conditions:
328  *		Caller must hold a reference on the element.
329  */
330 void
ipc_importance_reference(ipc_importance_elem_t elem)331 ipc_importance_reference(ipc_importance_elem_t elem)
332 {
333 	assert(0 < IIE_REFS(elem));
334 	ipc_importance_reference_internal(elem);
335 }
336 
337 /*
338  *	Routine:	ipc_importance_release_locked
339  *	Purpose:
340  *		Release a reference on an importance attribute value,
341  *		unlinking and deallocating the attribute if the last reference.
342  *	Conditions:
343  *		Entered with importance lock held, leaves with it unlocked.
344  */
345 static void
ipc_importance_release_locked(ipc_importance_elem_t elem)346 ipc_importance_release_locked(ipc_importance_elem_t elem)
347 {
348 	assert(0 < IIE_REFS(elem));
349 
350 #if IMPORTANCE_DEBUG
351 	ipc_importance_inherit_t temp_inherit;
352 	ipc_importance_task_t link_task;
353 	ipc_kmsg_t temp_kmsg;
354 	uint32_t expected = 0;
355 
356 	if (0 < elem->iie_made) {
357 		expected++;
358 	}
359 
360 	link_task = (IIE_TYPE_INHERIT == IIE_TYPE(elem)) ?
361 	    ((ipc_importance_inherit_t)elem)->iii_to_task :
362 	    (ipc_importance_task_t)elem;
363 
364 	queue_iterate(&link_task->iit_kmsgs, temp_kmsg, ipc_kmsg_t, ikm_inheritance)
365 	if (temp_kmsg->ikm_importance == elem) {
366 		expected++;
367 	}
368 	queue_iterate(&link_task->iit_inherits, temp_inherit,
369 	    ipc_importance_inherit_t, iii_inheritance)
370 	if (temp_inherit->iii_from_elem == elem) {
371 		expected++;
372 	}
373 	if (IIE_REFS(elem) < expected + 1) {
374 		panic("ipc_importance_release_locked (%p)", elem);
375 	}
376 #endif /* IMPORTANCE_DEBUG */
377 
378 	if (0 < ipc_importance_release_internal(elem)) {
379 		ipc_importance_unlock();
380 		return;
381 	}
382 
383 	/* last ref */
384 
385 	switch (IIE_TYPE(elem)) {
386 	/* just a "from" task reference to drop */
387 	case IIE_TYPE_TASK:
388 	{
389 		ipc_importance_task_t task_elem;
390 
391 		task_elem = (ipc_importance_task_t)elem;
392 
393 		/* the task can't still hold a reference on the task importance */
394 		assert(TASK_NULL == task_elem->iit_task);
395 
396 #if DEVELOPMENT || DEBUG
397 		queue_remove(&global_iit_alloc_queue, task_elem, ipc_importance_task_t, iit_allocation);
398 #endif
399 
400 		ipc_importance_unlock();
401 
402 		zfree(ipc_importance_task_zone, task_elem);
403 		break;
404 	}
405 
406 	/* dropping an inherit element */
407 	case IIE_TYPE_INHERIT:
408 	{
409 		ipc_importance_inherit_t inherit = (ipc_importance_inherit_t)elem;
410 		ipc_importance_task_t to_task = inherit->iii_to_task;
411 		ipc_importance_elem_t from_elem;
412 
413 		assert(IIT_NULL != to_task);
414 		assert(ipc_importance_task_is_any_receiver_type(to_task));
415 
416 		/* unlink the inherit from its source element */
417 		from_elem = ipc_importance_inherit_unlink(inherit);
418 		assert(IIE_NULL != from_elem);
419 
420 		/*
421 		 * The attribute might have pending external boosts if the attribute
422 		 * was given out during exec, drop them from the appropriate destination
423 		 * task.
424 		 *
425 		 * The attribute will not have any pending external boosts if the
426 		 * attribute was given out to voucher system since it would have been
427 		 * dropped by ipc_importance_release_value, but there is not way to
428 		 * detect that, thus if the attribute has a pending external boost,
429 		 * drop them from the appropriate destination task.
430 		 *
431 		 * The inherit attribute from exec and voucher system would not
432 		 * get deduped to each other, thus dropping the external boost
433 		 * from destination task at two different places will not have
434 		 * any unintended side effects.
435 		 */
436 		assert(inherit->iii_externcnt >= inherit->iii_externdrop);
437 		if (inherit->iii_donating) {
438 			uint32_t assertcnt = III_EXTERN(inherit);
439 
440 			assert(ipc_importance_task_is_any_receiver_type(to_task));
441 			assert(to_task->iit_externcnt >= inherit->iii_externcnt);
442 			assert(to_task->iit_externdrop >= inherit->iii_externdrop);
443 			to_task->iit_externcnt -= inherit->iii_externcnt;
444 			to_task->iit_externdrop -= inherit->iii_externdrop;
445 			inherit->iii_externcnt = 0;
446 			inherit->iii_externdrop = 0;
447 			inherit->iii_donating = FALSE;
448 
449 			/* adjust the internal assertions - and propagate as needed */
450 			if (ipc_importance_task_check_transition(to_task, IIT_UPDATE_DROP, assertcnt)) {
451 				ipc_importance_task_propagate_assertion_locked(to_task, IIT_UPDATE_DROP, TRUE);
452 			}
453 		} else {
454 			inherit->iii_externcnt = 0;
455 			inherit->iii_externdrop = 0;
456 		}
457 
458 		/* release the reference on the source element */
459 		ipc_importance_release_locked(from_elem);
460 		/* unlocked on return */
461 
462 		/* release the reference on the destination task */
463 		ipc_importance_task_release(to_task);
464 
465 		/* free the inherit */
466 		zfree(ipc_importance_inherit_zone, inherit);
467 		break;
468 	}
469 	}
470 }
471 
472 /*
473  *	Routine:	ipc_importance_release
474  *	Purpose:
475  *		Release a reference on an importance attribute value,
476  *		unlinking and deallocating the attribute if the last reference.
477  *	Conditions:
478  *		nothing locked on entrance, nothing locked on exit.
479  *		May block.
480  */
481 void
ipc_importance_release(ipc_importance_elem_t elem)482 ipc_importance_release(ipc_importance_elem_t elem)
483 {
484 	if (IIE_NULL == elem) {
485 		return;
486 	}
487 
488 	ipc_importance_lock();
489 	ipc_importance_release_locked(elem);
490 	/* unlocked */
491 }
492 
493 /*
494  *	Routine:	ipc_importance_task_reference
495  *
496  *
497  *	Purpose:
498  *		Retain a reference on a task importance attribute value.
499  *	Conditions:
500  *		nothing locked on entrance, nothing locked on exit.
501  *		caller holds a reference already.
502  */
503 void
ipc_importance_task_reference(ipc_importance_task_t task_elem)504 ipc_importance_task_reference(ipc_importance_task_t task_elem)
505 {
506 	if (IIT_NULL == task_elem) {
507 		return;
508 	}
509 #if IIE_REF_DEBUG
510 	incr_ref_counter(task_elem->iit_elem.iie_task_refs_added);
511 #endif
512 	ipc_importance_reference(&task_elem->iit_elem);
513 }
514 
515 /*
516  *	Routine:	ipc_importance_task_release
517  *	Purpose:
518  *		Release a reference on a task importance attribute value,
519  *		unlinking and deallocating the attribute if the last reference.
520  *	Conditions:
521  *		nothing locked on entrance, nothing locked on exit.
522  *		May block.
523  */
524 void
ipc_importance_task_release(ipc_importance_task_t task_elem)525 ipc_importance_task_release(ipc_importance_task_t task_elem)
526 {
527 	if (IIT_NULL == task_elem) {
528 		return;
529 	}
530 
531 	ipc_importance_lock();
532 #if IIE_REF_DEBUG
533 	incr_ref_counter(task_elem->iit_elem.iie_task_refs_dropped);
534 #endif
535 	ipc_importance_release_locked(&task_elem->iit_elem);
536 	/* unlocked */
537 }
538 
539 /*
540  *	Routine:	ipc_importance_task_release_locked
541  *	Purpose:
542  *		Release a reference on a task importance attribute value,
543  *		unlinking and deallocating the attribute if the last reference.
544  *	Conditions:
545  *		importance lock held on entry, nothing locked on exit.
546  *		May block.
547  */
548 static void
ipc_importance_task_release_locked(ipc_importance_task_t task_elem)549 ipc_importance_task_release_locked(ipc_importance_task_t task_elem)
550 {
551 	if (IIT_NULL == task_elem) {
552 		ipc_importance_unlock();
553 		return;
554 	}
555 #if IIE_REF_DEBUG
556 	incr_ref_counter(task_elem->iit_elem.iie_task_refs_dropped);
557 #endif
558 	ipc_importance_release_locked(&task_elem->iit_elem);
559 	/* unlocked */
560 }
561 
562 /*
563  * Routines for importance donation/inheritance/boosting
564  */
565 
566 
567 /*
568  * External importance assertions are managed by the process in userspace
569  * Internal importance assertions are the responsibility of the kernel
570  * Assertions are changed from internal to external via task_importance_externalize_assertion
571  */
572 
573 /*
574  *	Routine:	ipc_importance_task_check_transition
575  *	Purpose:
576  *		Increase or decrement the internal task importance counter of the
577  *		specified task and determine if propagation and a task policy
578  *		update is required.
579  *
580  *		If it is already enqueued for a policy update, steal it from that queue
581  *		(as we are reversing that update before it happens).
582  *
583  *	Conditions:
584  *		Called with the importance lock held.
585  *		It is the caller's responsibility to perform the propagation of the
586  *		transition and/or policy changes by checking the return value.
587  */
588 static boolean_t
ipc_importance_task_check_transition(ipc_importance_task_t task_imp,iit_update_type_t type,uint32_t delta)589 ipc_importance_task_check_transition(
590 	ipc_importance_task_t task_imp,
591 	iit_update_type_t type,
592 	uint32_t delta)
593 {
594 #if IMPORTANCE_TRACE
595 	task_t target_task = task_imp->iit_task;
596 #endif
597 	boolean_t boost = (IIT_UPDATE_HOLD == type);
598 	boolean_t before_boosted, after_boosted;
599 
600 	ipc_importance_assert_held();
601 
602 	if (!ipc_importance_task_is_any_receiver_type(task_imp)) {
603 		return FALSE;
604 	}
605 
606 #if IMPORTANCE_TRACE
607 	int target_pid = task_pid(target_task);
608 
609 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_ASSERTION, (((boost) ? IMP_HOLD : IMP_DROP) | TASK_POLICY_INTERNAL))) | DBG_FUNC_START,
610 	    proc_selfpid(), target_pid, task_imp->iit_assertcnt, IIT_EXTERN(task_imp), 0);
611 #endif
612 
613 	/* snapshot the effective boosting status before making any changes */
614 	before_boosted = (task_imp->iit_assertcnt > 0);
615 
616 	/* Adjust the assertcnt appropriately */
617 	if (boost) {
618 		task_imp->iit_assertcnt += delta;
619 #if IMPORTANCE_TRACE
620 		DTRACE_BOOST6(send_boost, task_t, target_task, int, target_pid,
621 		    task_t, current_task(), int, proc_selfpid(), int, delta, int, task_imp->iit_assertcnt);
622 #endif
623 	} else {
624 		// assert(delta <= task_imp->iit_assertcnt);
625 		if (task_imp->iit_assertcnt < delta + IIT_EXTERN(task_imp)) {
626 			/* TODO: Turn this back into a panic <rdar://problem/12592649> */
627 			task_imp->iit_assertcnt = IIT_EXTERN(task_imp);
628 		} else {
629 			task_imp->iit_assertcnt -= delta;
630 		}
631 #if IMPORTANCE_TRACE
632 		// This convers both legacy and voucher-based importance.
633 		DTRACE_BOOST4(drop_boost, task_t, target_task, int, target_pid, int, delta, int, task_imp->iit_assertcnt);
634 #endif
635 	}
636 
637 #if IMPORTANCE_TRACE
638 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_ASSERTION, (((boost) ? IMP_HOLD : IMP_DROP) | TASK_POLICY_INTERNAL))) | DBG_FUNC_END,
639 	    proc_selfpid(), target_pid, task_imp->iit_assertcnt, IIT_EXTERN(task_imp), 0);
640 #endif
641 
642 	/* did the change result in an effective donor status change? */
643 	after_boosted = (task_imp->iit_assertcnt > 0);
644 
645 	if (after_boosted != before_boosted) {
646 		/*
647 		 * If the task importance is already on an update queue, we just reversed the need for a
648 		 * pending policy update.  If the queue is any other than the delayed-drop-queue, pull it
649 		 * off that queue and release the reference it got going onto the update queue.  If it is
650 		 * the delayed-drop-queue we leave it in place in case it comes back into the drop state
651 		 * before its time delay is up.
652 		 *
653 		 * We still need to propagate the change downstream to reverse the assertcnt effects,
654 		 * but we no longer need to update this task's boost policy state.
655 		 *
656 		 * Otherwise, mark it as needing a policy update.
657 		 */
658 		assert(0 == task_imp->iit_updatepolicy);
659 		if (NULL != task_imp->iit_updateq) {
660 			if (&ipc_importance_delayed_drop_queue != task_imp->iit_updateq) {
661 				queue_remove(task_imp->iit_updateq, task_imp, ipc_importance_task_t, iit_updates);
662 				task_imp->iit_updateq = NULL;
663 				ipc_importance_task_release_internal(task_imp); /* can't be last ref */
664 			}
665 		} else {
666 			task_imp->iit_updatepolicy = 1;
667 		}
668 		return TRUE;
669 	}
670 
671 	return FALSE;
672 }
673 
674 
675 /*
676  *	Routine:	ipc_importance_task_propagate_helper
677  *	Purpose:
678  *		Increase or decrement the internal task importance counter of all
679  *		importance tasks inheriting from the specified one.  If this causes
680  *		that importance task to change state, add it to the list of tasks
681  *		to do a policy update against.
682  *	Conditions:
683  *		Called with the importance lock held.
684  *		It is the caller's responsibility to iterate down the generated list
685  *		and propagate any subsequent assertion changes from there.
686  */
687 static void
ipc_importance_task_propagate_helper(ipc_importance_task_t task_imp,iit_update_type_t type,queue_t propagation)688 ipc_importance_task_propagate_helper(
689 	ipc_importance_task_t task_imp,
690 	iit_update_type_t type,
691 	queue_t propagation)
692 {
693 	ipc_importance_task_t temp_task_imp;
694 
695 	/*
696 	 * iterate the downstream kmsgs, adjust their boosts,
697 	 * and capture the next task to adjust for each message
698 	 */
699 
700 	ipc_kmsg_t temp_kmsg;
701 
702 	queue_iterate(&task_imp->iit_kmsgs, temp_kmsg, ipc_kmsg_t, ikm_inheritance) {
703 		mach_msg_header_t *hdr = temp_kmsg->ikm_header;
704 		mach_port_delta_t delta;
705 		ipc_port_t port;
706 
707 		/* toggle the kmsg importance bit as a barrier to parallel adjusts */
708 		if (IIT_UPDATE_HOLD == type) {
709 			if (MACH_MSGH_BITS_RAISED_IMPORTANCE(hdr->msgh_bits)) {
710 				continue;
711 			}
712 
713 			/* mark the message as now carrying importance */
714 			hdr->msgh_bits |= MACH_MSGH_BITS_RAISEIMP;
715 			delta = 1;
716 		} else {
717 			if (!MACH_MSGH_BITS_RAISED_IMPORTANCE(hdr->msgh_bits)) {
718 				continue;
719 			}
720 
721 			/* clear the message as now carrying importance */
722 			hdr->msgh_bits &= ~MACH_MSGH_BITS_RAISEIMP;
723 			delta = -1;
724 		}
725 
726 		/* determine the task importance to adjust as result (if any) */
727 		port = hdr->msgh_remote_port;
728 		assert(IP_VALID(port));
729 		ip_mq_lock(port);
730 		temp_task_imp = IIT_NULL;
731 		if (!ipc_port_importance_delta_internal(port, IPID_OPTION_NORMAL, &delta, &temp_task_imp)) {
732 			ip_mq_unlock(port);
733 		}
734 
735 		/* no task importance to adjust associated with the port? */
736 		if (IIT_NULL == temp_task_imp) {
737 			continue;
738 		}
739 
740 		/* hold a reference on temp_task_imp */
741 
742 		/* Adjust the task assertions and determine if an edge was crossed */
743 		if (ipc_importance_task_check_transition(temp_task_imp, type, 1)) {
744 			incr_ref_counter(temp_task_imp->iit_elem.iie_task_refs_added_transition);
745 			queue_enter(propagation, temp_task_imp, ipc_importance_task_t, iit_props);
746 			/* reference donated */
747 		} else {
748 			ipc_importance_task_release_internal(temp_task_imp);
749 		}
750 	}
751 
752 	/*
753 	 * iterate the downstream importance inherits
754 	 * and capture the next task importance to boost for each
755 	 */
756 	ipc_importance_inherit_t temp_inherit;
757 
758 	queue_iterate(&task_imp->iit_inherits, temp_inherit, ipc_importance_inherit_t, iii_inheritance) {
759 		uint32_t assertcnt = III_EXTERN(temp_inherit);
760 
761 		temp_task_imp = temp_inherit->iii_to_task;
762 		assert(IIT_NULL != temp_task_imp);
763 
764 		if (IIT_UPDATE_HOLD == type) {
765 			/* if no undropped externcnts in the inherit, nothing to do */
766 			if (0 == assertcnt) {
767 				assert(temp_inherit->iii_donating == FALSE);
768 				continue;
769 			}
770 
771 			/* nothing to do if the inherit is already donating (forced donation) */
772 			if (temp_inherit->iii_donating) {
773 				continue;
774 			}
775 
776 			/* mark it donating and contribute to the task externcnts */
777 			temp_inherit->iii_donating = TRUE;
778 			temp_task_imp->iit_externcnt += temp_inherit->iii_externcnt;
779 			temp_task_imp->iit_externdrop += temp_inherit->iii_externdrop;
780 		} else {
781 			/* if no contributing assertions, move on */
782 			if (0 == assertcnt) {
783 				assert(temp_inherit->iii_donating == FALSE);
784 				continue;
785 			}
786 
787 			/* nothing to do if the inherit is not donating */
788 			if (!temp_inherit->iii_donating) {
789 				continue;
790 			}
791 
792 			/* mark it no longer donating */
793 			temp_inherit->iii_donating = FALSE;
794 
795 			/* remove the contribution the inherit made to the to-task */
796 			assert(IIT_EXTERN(temp_task_imp) >= III_EXTERN(temp_inherit));
797 			assert(temp_task_imp->iit_externcnt >= temp_inherit->iii_externcnt);
798 			assert(temp_task_imp->iit_externdrop >= temp_inherit->iii_externdrop);
799 			temp_task_imp->iit_externcnt -= temp_inherit->iii_externcnt;
800 			temp_task_imp->iit_externdrop -= temp_inherit->iii_externdrop;
801 		}
802 
803 		/* Adjust the task assertions and determine if an edge was crossed */
804 		assert(ipc_importance_task_is_any_receiver_type(temp_task_imp));
805 		if (ipc_importance_task_check_transition(temp_task_imp, type, assertcnt)) {
806 			ipc_importance_task_reference(temp_task_imp);
807 			incr_ref_counter(temp_task_imp->iit_elem.iie_task_refs_added_transition);
808 			queue_enter(propagation, temp_task_imp, ipc_importance_task_t, iit_props);
809 		}
810 	}
811 }
812 
813 /*
814  *	Routine:	ipc_importance_task_process_updates
815  *	Purpose:
816  *	        Process the queue of task importances and apply the policy
817  *		update called for.  Only process tasks in the queue with an
818  *		update timestamp less than the supplied max.
819  *	Conditions:
820  *		Called and returns with importance locked.
821  *		May drop importance lock and block temporarily.
822  */
823 static void
ipc_importance_task_process_updates(queue_t supplied_queue,boolean_t boost,uint64_t max_timestamp)824 ipc_importance_task_process_updates(
825 	queue_t   supplied_queue,
826 	boolean_t boost,
827 	uint64_t  max_timestamp)
828 {
829 	ipc_importance_task_t task_imp;
830 	queue_head_t second_chance;
831 	queue_t queue = supplied_queue;
832 
833 	/*
834 	 * This queue will hold the task's we couldn't trylock on first pass.
835 	 * By using a second (private) queue, we guarantee all tasks that get
836 	 * entered on this queue have a timestamp under the maximum.
837 	 */
838 	queue_init(&second_chance);
839 
840 	/* process any resulting policy updates */
841 retry:
842 	while (!queue_empty(queue)) {
843 		task_t target_task;
844 		struct task_pend_token pend_token = {};
845 
846 		task_imp = (ipc_importance_task_t)queue_first(queue);
847 		assert(0 == task_imp->iit_updatepolicy);
848 		assert(queue == task_imp->iit_updateq);
849 
850 		/* if timestamp is too big, we're done */
851 		if (task_imp->iit_updatetime > max_timestamp) {
852 			break;
853 		}
854 
855 		/* we were given a reference on each task in the queue */
856 
857 		/* remove it from the supplied queue */
858 		queue_remove(queue, task_imp, ipc_importance_task_t, iit_updates);
859 		task_imp->iit_updateq = NULL;
860 
861 		target_task = task_imp->iit_task;
862 
863 		/* Is it well on the way to exiting? */
864 		if (TASK_NULL == target_task) {
865 			ipc_importance_task_release_locked(task_imp);
866 			/* importance unlocked */
867 			ipc_importance_lock();
868 			continue;
869 		}
870 
871 		/* Has the update been reversed on the hysteresis queue? */
872 		if (0 < task_imp->iit_assertcnt &&
873 		    queue == &ipc_importance_delayed_drop_queue) {
874 			ipc_importance_task_release_locked(task_imp);
875 			/* importance unlocked */
876 			ipc_importance_lock();
877 			continue;
878 		}
879 
880 		/*
881 		 * Can we get the task lock out-of-order?
882 		 * If not, stick this back on the second-chance queue.
883 		 */
884 		if (!task_lock_try(target_task)) {
885 			boolean_t should_wait_lock = (queue == &second_chance);
886 			task_imp->iit_updateq = &second_chance;
887 
888 			/*
889 			 * If we're already processing second-chances on
890 			 * tasks, keep this task on the front of the queue.
891 			 * We will wait for the task lock before coming
892 			 * back and trying again, and we have a better
893 			 * chance of re-acquiring the lock if we come back
894 			 * to it right away.
895 			 */
896 			if (should_wait_lock) {
897 				task_reference(target_task);
898 				queue_enter_first(&second_chance, task_imp,
899 				    ipc_importance_task_t, iit_updates);
900 			} else {
901 				queue_enter(&second_chance, task_imp,
902 				    ipc_importance_task_t, iit_updates);
903 			}
904 			ipc_importance_unlock();
905 
906 			if (should_wait_lock) {
907 				task_lock(target_task);
908 				task_unlock(target_task);
909 				task_deallocate(target_task);
910 			}
911 
912 			ipc_importance_lock();
913 			continue;
914 		}
915 
916 		/* is it going away? */
917 		if (!target_task->active) {
918 			task_unlock(target_task);
919 			ipc_importance_task_release_locked(task_imp);
920 			/* importance unlocked */
921 			ipc_importance_lock();
922 			continue;
923 		}
924 
925 		/* take a task reference for while we don't have the importance lock */
926 		task_reference(target_task);
927 
928 		/* count the transition */
929 		if (boost) {
930 			task_imp->iit_transitions++;
931 		}
932 
933 		ipc_importance_unlock();
934 
935 		/* apply the policy adjust to the target task (while it is still locked) */
936 		task_update_boost_locked(target_task, boost, &pend_token);
937 
938 		/* complete the policy update with the task unlocked */
939 		ipc_importance_task_release(task_imp);
940 		task_unlock(target_task);
941 		task_policy_update_complete_unlocked(target_task, &pend_token);
942 		task_deallocate(target_task);
943 
944 		ipc_importance_lock();
945 	}
946 
947 	/* If there are tasks we couldn't update the first time, try again */
948 	if (!queue_empty(&second_chance)) {
949 		queue = &second_chance;
950 		goto retry;
951 	}
952 }
953 
954 
955 /*
956  *	Routine:	ipc_importance_task_delayed_drop_scan
957  *	Purpose:
958  *	        The thread call routine to scan the delayed drop queue,
959  *		requesting all updates with a deadline up to the last target
960  *		for the thread-call (which is DENAP_DROP_SKEW beyond the first
961  *		thread's optimum delay).
962  *		update to drop its boost.
963  *	Conditions:
964  *		Nothing locked
965  */
966 static void
ipc_importance_task_delayed_drop_scan(__unused void * arg1,__unused void * arg2)967 ipc_importance_task_delayed_drop_scan(
968 	__unused void *arg1,
969 	__unused void *arg2)
970 {
971 	ipc_importance_lock();
972 
973 	/* process all queued task drops with timestamps up to TARGET(first)+SKEW */
974 	ipc_importance_task_process_updates(&ipc_importance_delayed_drop_queue,
975 	    FALSE,
976 	    ipc_importance_delayed_drop_timestamp);
977 
978 	/* importance lock may have been temporarily dropped */
979 
980 	/* If there are any entries left in the queue, re-arm the call here */
981 	if (!queue_empty(&ipc_importance_delayed_drop_queue)) {
982 		ipc_importance_task_t task_imp;
983 		uint64_t deadline;
984 		uint64_t leeway;
985 
986 		task_imp = (ipc_importance_task_t)queue_first(&ipc_importance_delayed_drop_queue);
987 
988 		nanoseconds_to_absolutetime(DENAP_DROP_DELAY, &deadline);
989 		deadline += task_imp->iit_updatetime;
990 		ipc_importance_delayed_drop_timestamp = deadline;
991 
992 		nanoseconds_to_absolutetime(DENAP_DROP_LEEWAY, &leeway);
993 
994 		thread_call_enter_delayed_with_leeway(
995 			ipc_importance_delayed_drop_call,
996 			NULL,
997 			deadline,
998 			leeway,
999 			DENAP_DROP_FLAGS);
1000 	} else {
1001 		ipc_importance_delayed_drop_call_requested = FALSE;
1002 	}
1003 	ipc_importance_unlock();
1004 }
1005 
1006 /*
1007  *	Routine:	ipc_importance_task_delayed_drop
1008  *	Purpose:
1009  *		Queue the specified task importance for delayed policy
1010  *		update to drop its boost.
1011  *	Conditions:
1012  *		Called with the importance lock held.
1013  */
1014 static void
ipc_importance_task_delayed_drop(ipc_importance_task_t task_imp)1015 ipc_importance_task_delayed_drop(ipc_importance_task_t task_imp)
1016 {
1017 	uint64_t timestamp = mach_absolute_time(); /* no mach_approximate_time() in kernel */
1018 
1019 	assert(ipc_importance_delayed_drop_call != NULL);
1020 
1021 	/*
1022 	 * If still on an update queue from a previous change,
1023 	 * remove it first (and use that reference).  Otherwise, take
1024 	 * a new reference for the delay drop update queue.
1025 	 */
1026 	if (NULL != task_imp->iit_updateq) {
1027 		queue_remove(task_imp->iit_updateq, task_imp,
1028 		    ipc_importance_task_t, iit_updates);
1029 	} else {
1030 		ipc_importance_task_reference_internal(task_imp);
1031 	}
1032 
1033 	task_imp->iit_updateq = &ipc_importance_delayed_drop_queue;
1034 	task_imp->iit_updatetime = timestamp;
1035 
1036 	queue_enter(&ipc_importance_delayed_drop_queue, task_imp,
1037 	    ipc_importance_task_t, iit_updates);
1038 
1039 	/* request the delayed thread-call if not already requested */
1040 	if (!ipc_importance_delayed_drop_call_requested) {
1041 		uint64_t deadline;
1042 		uint64_t leeway;
1043 
1044 		nanoseconds_to_absolutetime(DENAP_DROP_DELAY, &deadline);
1045 		deadline += task_imp->iit_updatetime;
1046 		ipc_importance_delayed_drop_timestamp = deadline;
1047 
1048 		nanoseconds_to_absolutetime(DENAP_DROP_LEEWAY, &leeway);
1049 
1050 		ipc_importance_delayed_drop_call_requested = TRUE;
1051 		thread_call_enter_delayed_with_leeway(
1052 			ipc_importance_delayed_drop_call,
1053 			NULL,
1054 			deadline,
1055 			leeway,
1056 			DENAP_DROP_FLAGS);
1057 	}
1058 }
1059 
1060 
1061 /*
1062  *	Routine:	ipc_importance_task_propagate_assertion_locked
1063  *	Purpose:
1064  *		Propagate the importance transition type to every item
1065  *		If this causes a boost to be applied, determine if that
1066  *		boost should propagate downstream.
1067  *	Conditions:
1068  *		Called with the importance lock held.
1069  */
1070 static void
ipc_importance_task_propagate_assertion_locked(ipc_importance_task_t task_imp,iit_update_type_t type,boolean_t update_task_imp)1071 ipc_importance_task_propagate_assertion_locked(
1072 	ipc_importance_task_t task_imp,
1073 	iit_update_type_t type,
1074 	boolean_t update_task_imp)
1075 {
1076 	boolean_t boost = (IIT_UPDATE_HOLD == type);
1077 	ipc_importance_task_t temp_task_imp;
1078 	queue_head_t propagate;
1079 	queue_head_t updates;
1080 
1081 	queue_init(&updates);
1082 	queue_init(&propagate);
1083 
1084 	ipc_importance_assert_held();
1085 
1086 	/*
1087 	 * If we're going to update the policy for the provided task,
1088 	 * enqueue it on the propagate queue itself.  Otherwise, only
1089 	 * enqueue downstream things.
1090 	 */
1091 	if (update_task_imp) {
1092 		ipc_importance_task_reference(task_imp);
1093 		incr_ref_counter(task_imp->iit_elem.iie_task_refs_added_transition);
1094 		queue_enter(&propagate, task_imp, ipc_importance_task_t, iit_props);
1095 	} else {
1096 		ipc_importance_task_propagate_helper(task_imp, type, &propagate);
1097 	}
1098 
1099 	/*
1100 	 * for each item on the propagation list, propagate any change downstream,
1101 	 * adding new tasks to propagate further if they transistioned as well.
1102 	 */
1103 	while (!queue_empty(&propagate)) {
1104 		boolean_t need_update;
1105 
1106 		queue_remove_first(&propagate, temp_task_imp, ipc_importance_task_t, iit_props);
1107 		/* hold a reference on temp_task_imp */
1108 
1109 		assert(IIT_NULL != temp_task_imp);
1110 
1111 		/* only propagate for receivers not already marked as a donor */
1112 		if (!ipc_importance_task_is_marked_donor(temp_task_imp) &&
1113 		    ipc_importance_task_is_marked_receiver(temp_task_imp)) {
1114 			ipc_importance_task_propagate_helper(temp_task_imp, type, &propagate);
1115 		}
1116 
1117 		/* if we have a policy update to apply, enqueue a reference for later processing */
1118 		need_update = (0 != temp_task_imp->iit_updatepolicy);
1119 		temp_task_imp->iit_updatepolicy = 0;
1120 		if (need_update && TASK_NULL != temp_task_imp->iit_task) {
1121 			if (NULL == temp_task_imp->iit_updateq) {
1122 				/*
1123 				 * If a downstream task that needs an update is subjects to AppNap,
1124 				 * drop boosts according to the delay hysteresis.  Otherwise,
1125 				 * immediate update it.
1126 				 */
1127 				if (!boost && temp_task_imp != task_imp &&
1128 				    ipc_importance_delayed_drop_call != NULL &&
1129 				    ipc_importance_task_is_marked_denap_receiver(temp_task_imp)) {
1130 					ipc_importance_task_delayed_drop(temp_task_imp);
1131 				} else {
1132 					temp_task_imp->iit_updatetime = 0;
1133 					temp_task_imp->iit_updateq = &updates;
1134 					ipc_importance_task_reference_internal(temp_task_imp);
1135 					if (boost) {
1136 						queue_enter(&updates, temp_task_imp,
1137 						    ipc_importance_task_t, iit_updates);
1138 					} else {
1139 						queue_enter_first(&updates, temp_task_imp,
1140 						    ipc_importance_task_t, iit_updates);
1141 					}
1142 				}
1143 			} else {
1144 				/* Must already be on the AppNap hysteresis queue */
1145 				assert(ipc_importance_delayed_drop_call != NULL);
1146 				assert(ipc_importance_task_is_marked_denap_receiver(temp_task_imp));
1147 			}
1148 		}
1149 
1150 		ipc_importance_task_release_internal(temp_task_imp);
1151 	}
1152 
1153 	/* apply updates to task (may drop importance lock) */
1154 	if (!queue_empty(&updates)) {
1155 		ipc_importance_task_process_updates(&updates, boost, 0);
1156 	}
1157 }
1158 
1159 /*
1160  *	Routine:	ipc_importance_task_hold_internal_assertion_locked
1161  *	Purpose:
1162  *		Increment the assertion count on the task importance.
1163  *		If this results in a boost state change in that task,
1164  *		prepare to update task policy for this task AND, if
1165  *		if not just waking out of App Nap, all down-stream
1166  *		tasks that have a similar transition through inheriting
1167  *		this update.
1168  *	Conditions:
1169  *		importance locked on entry and exit.
1170  *		May temporarily drop importance lock and block.
1171  */
1172 static kern_return_t
ipc_importance_task_hold_internal_assertion_locked(ipc_importance_task_t task_imp,uint32_t count)1173 ipc_importance_task_hold_internal_assertion_locked(ipc_importance_task_t task_imp, uint32_t count)
1174 {
1175 	if (ipc_importance_task_check_transition(task_imp, IIT_UPDATE_HOLD, count)) {
1176 		ipc_importance_task_propagate_assertion_locked(task_imp, IIT_UPDATE_HOLD, TRUE);
1177 	}
1178 	return KERN_SUCCESS;
1179 }
1180 
1181 /*
1182  *	Routine:	ipc_importance_task_drop_internal_assertion_locked
1183  *	Purpose:
1184  *		Decrement the assertion count on the task importance.
1185  *		If this results in a boost state change in that task,
1186  *		prepare to update task policy for this task AND, if
1187  *		if not just waking out of App Nap, all down-stream
1188  *		tasks that have a similar transition through inheriting
1189  *		this update.
1190  *	Conditions:
1191  *		importance locked on entry and exit.
1192  *		May temporarily drop importance lock and block.
1193  */
1194 static kern_return_t
ipc_importance_task_drop_internal_assertion_locked(ipc_importance_task_t task_imp,uint32_t count)1195 ipc_importance_task_drop_internal_assertion_locked(ipc_importance_task_t task_imp, uint32_t count)
1196 {
1197 	if (ipc_importance_task_check_transition(task_imp, IIT_UPDATE_DROP, count)) {
1198 		ipc_importance_task_propagate_assertion_locked(task_imp, IIT_UPDATE_DROP, TRUE);
1199 	}
1200 	return KERN_SUCCESS;
1201 }
1202 
1203 /*
1204  *      Routine:        ipc_importance_task_hold_internal_assertion
1205  *      Purpose:
1206  *              Increment the assertion count on the task importance.
1207  *              If this results in a 0->1 change in that count,
1208  *              prepare to update task policy for this task AND
1209  *              (potentially) all down-stream tasks that have a
1210  *		similar transition through inheriting this update.
1211  *      Conditions:
1212  *              Nothing locked
1213  *              May block after dropping importance lock.
1214  */
1215 int
ipc_importance_task_hold_internal_assertion(ipc_importance_task_t task_imp,uint32_t count)1216 ipc_importance_task_hold_internal_assertion(ipc_importance_task_t task_imp, uint32_t count)
1217 {
1218 	int ret = KERN_SUCCESS;
1219 
1220 	if (ipc_importance_task_is_any_receiver_type(task_imp)) {
1221 		ipc_importance_lock();
1222 		ret = ipc_importance_task_hold_internal_assertion_locked(task_imp, count);
1223 		ipc_importance_unlock();
1224 	}
1225 	return ret;
1226 }
1227 
1228 /*
1229  *	Routine:	ipc_importance_task_drop_internal_assertion
1230  *	Purpose:
1231  *		Decrement the assertion count on the task importance.
1232  *		If this results in a X->0 change in that count,
1233  *		prepare to update task policy for this task AND
1234  *		all down-stream tasks that have a similar transition
1235  *		through inheriting this drop update.
1236  *	Conditions:
1237  *		Nothing locked on entry.
1238  *		May block after dropping importance lock.
1239  */
1240 kern_return_t
ipc_importance_task_drop_internal_assertion(ipc_importance_task_t task_imp,uint32_t count)1241 ipc_importance_task_drop_internal_assertion(ipc_importance_task_t task_imp, uint32_t count)
1242 {
1243 	kern_return_t ret = KERN_SUCCESS;
1244 
1245 	if (ipc_importance_task_is_any_receiver_type(task_imp)) {
1246 		ipc_importance_lock();
1247 		ret = ipc_importance_task_drop_internal_assertion_locked(task_imp, count);
1248 		ipc_importance_unlock();
1249 	}
1250 	return ret;
1251 }
1252 
1253 /*
1254  *      Routine:        ipc_importance_task_hold_file_lock_assertion
1255  *      Purpose:
1256  *              Increment the file lock assertion count on the task importance.
1257  *              If this results in a 0->1 change in that count,
1258  *              prepare to update task policy for this task AND
1259  *              (potentially) all down-stream tasks that have a
1260  *		similar transition through inheriting this update.
1261  *      Conditions:
1262  *              Nothing locked
1263  *              May block after dropping importance lock.
1264  */
1265 kern_return_t
ipc_importance_task_hold_file_lock_assertion(ipc_importance_task_t task_imp,uint32_t count)1266 ipc_importance_task_hold_file_lock_assertion(ipc_importance_task_t task_imp, uint32_t count)
1267 {
1268 	kern_return_t ret = KERN_SUCCESS;
1269 
1270 	if (ipc_importance_task_is_any_receiver_type(task_imp)) {
1271 		ipc_importance_lock();
1272 		ret = ipc_importance_task_hold_internal_assertion_locked(task_imp, count);
1273 		if (KERN_SUCCESS == ret) {
1274 			task_imp->iit_filelocks += count;
1275 		}
1276 		ipc_importance_unlock();
1277 	}
1278 	return ret;
1279 }
1280 
1281 /*
1282  *	Routine:	ipc_importance_task_drop_file_lock_assertion
1283  *	Purpose:
1284  *		Decrement the assertion count on the task importance.
1285  *		If this results in a X->0 change in that count,
1286  *		prepare to update task policy for this task AND
1287  *		all down-stream tasks that have a similar transition
1288  *		through inheriting this drop update.
1289  *	Conditions:
1290  *		Nothing locked on entry.
1291  *		May block after dropping importance lock.
1292  */
1293 kern_return_t
ipc_importance_task_drop_file_lock_assertion(ipc_importance_task_t task_imp,uint32_t count)1294 ipc_importance_task_drop_file_lock_assertion(ipc_importance_task_t task_imp, uint32_t count)
1295 {
1296 	kern_return_t ret = KERN_SUCCESS;
1297 
1298 	if (ipc_importance_task_is_any_receiver_type(task_imp)) {
1299 		ipc_importance_lock();
1300 		if (count <= task_imp->iit_filelocks) {
1301 			task_imp->iit_filelocks -= count;
1302 			ret = ipc_importance_task_drop_internal_assertion_locked(task_imp, count);
1303 		} else {
1304 			ret = KERN_INVALID_ARGUMENT;
1305 		}
1306 		ipc_importance_unlock();
1307 	}
1308 	return ret;
1309 }
1310 
1311 /*
1312  *	Routine:	ipc_importance_task_hold_legacy_external_assertion
1313  *	Purpose:
1314  *		Increment the external assertion count on the task importance.
1315  *		This cannot result in an 0->1 transition, as the caller must
1316  *		already hold an external boost.
1317  *	Conditions:
1318  *		Nothing locked on entry.
1319  *		May block after dropping importance lock.
1320  *		A queue of task importance structures is returned
1321  *		by ipc_importance_task_hold_assertion_locked(). Each
1322  *		needs to be updated (outside the importance lock hold).
1323  */
1324 kern_return_t
ipc_importance_task_hold_legacy_external_assertion(ipc_importance_task_t task_imp,uint32_t count)1325 ipc_importance_task_hold_legacy_external_assertion(ipc_importance_task_t task_imp, uint32_t count)
1326 {
1327 	task_t target_task;
1328 	uint32_t target_assertcnt;
1329 	uint32_t target_externcnt;
1330 	uint32_t target_legacycnt;
1331 
1332 	kern_return_t ret;
1333 
1334 	ipc_importance_lock();
1335 	target_task = task_imp->iit_task;
1336 
1337 #if IMPORTANCE_TRACE
1338 	int target_pid = task_pid(target_task);
1339 
1340 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_ASSERTION, (IMP_HOLD | TASK_POLICY_EXTERNAL))) | DBG_FUNC_START,
1341 	    proc_selfpid(), target_pid, task_imp->iit_assertcnt, IIT_LEGACY_EXTERN(task_imp), 0);
1342 #endif
1343 
1344 	if (IIT_LEGACY_EXTERN(task_imp) == 0) {
1345 		/* Only allowed to take a new boost assertion when holding an external boost */
1346 		/* save data for diagnostic printf below */
1347 		target_assertcnt = task_imp->iit_assertcnt;
1348 		target_externcnt = IIT_EXTERN(task_imp);
1349 		target_legacycnt = IIT_LEGACY_EXTERN(task_imp);
1350 		ret = KERN_FAILURE;
1351 		count = 0;
1352 	} else {
1353 		assert(ipc_importance_task_is_any_receiver_type(task_imp));
1354 		assert(0 < task_imp->iit_assertcnt);
1355 		assert(0 < IIT_EXTERN(task_imp));
1356 		task_imp->iit_assertcnt += count;
1357 		task_imp->iit_externcnt += count;
1358 		task_imp->iit_legacy_externcnt += count;
1359 		ret = KERN_SUCCESS;
1360 	}
1361 	ipc_importance_unlock();
1362 
1363 #if IMPORTANCE_TRACE
1364 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_ASSERTION, (IMP_HOLD | TASK_POLICY_EXTERNAL))) | DBG_FUNC_END,
1365 	    proc_selfpid(), target_pid, task_imp->iit_assertcnt, IIT_LEGACY_EXTERN(task_imp), 0);
1366 	// This covers the legacy case where a task takes an extra boost.
1367 	DTRACE_BOOST5(receive_boost, task_t, target_task, int, target_pid, int, proc_selfpid(), int, count, int, task_imp->iit_assertcnt);
1368 #endif
1369 
1370 	if (KERN_FAILURE == ret && target_task != TASK_NULL) {
1371 		printf("BUG in process %s[%d]: "
1372 		    "attempt to acquire an additional legacy external boost assertion without holding an existing legacy external assertion. "
1373 		    "(%d total, %d external, %d legacy-external)\n",
1374 		    proc_name_address(target_task->bsd_info), task_pid(target_task),
1375 		    target_assertcnt, target_externcnt, target_legacycnt);
1376 	}
1377 
1378 	return ret;
1379 }
1380 
1381 /*
1382  *	Routine:	ipc_importance_task_drop_legacy_external_assertion
1383  *	Purpose:
1384  *		Drop the legacy external assertion count on the task and
1385  *		reflect that change to total external assertion count and
1386  *		then onto the internal importance count.
1387  *
1388  *		If this results in a X->0 change in the internal,
1389  *		count, prepare to update task policy for this task AND
1390  *		all down-stream tasks that have a similar transition
1391  *		through inheriting this update.
1392  *	Conditions:
1393  *		Nothing locked on entry.
1394  */
1395 kern_return_t
ipc_importance_task_drop_legacy_external_assertion(ipc_importance_task_t task_imp,uint32_t count)1396 ipc_importance_task_drop_legacy_external_assertion(ipc_importance_task_t task_imp, uint32_t count)
1397 {
1398 	int ret = KERN_SUCCESS;
1399 	task_t target_task;
1400 	uint32_t target_assertcnt;
1401 	uint32_t target_externcnt;
1402 	uint32_t target_legacycnt;
1403 
1404 	if (count > 1) {
1405 		return KERN_INVALID_ARGUMENT;
1406 	}
1407 
1408 	ipc_importance_lock();
1409 	target_task = task_imp->iit_task;
1410 
1411 #if IMPORTANCE_TRACE
1412 	int target_pid = task_pid(target_task);
1413 
1414 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_ASSERTION, (IMP_DROP | TASK_POLICY_EXTERNAL))) | DBG_FUNC_START,
1415 	    proc_selfpid(), target_pid, task_imp->iit_assertcnt, IIT_LEGACY_EXTERN(task_imp), 0);
1416 #endif
1417 
1418 	if (count > IIT_LEGACY_EXTERN(task_imp)) {
1419 		/* Process over-released its boost count - save data for diagnostic printf */
1420 		/* TODO: If count > 1, we should clear out as many external assertions as there are left. */
1421 		target_assertcnt = task_imp->iit_assertcnt;
1422 		target_externcnt = IIT_EXTERN(task_imp);
1423 		target_legacycnt = IIT_LEGACY_EXTERN(task_imp);
1424 		ret = KERN_FAILURE;
1425 	} else {
1426 		/*
1427 		 * decrement legacy external count from the top level and reflect
1428 		 * into internal for this and all subsequent updates.
1429 		 */
1430 		assert(ipc_importance_task_is_any_receiver_type(task_imp));
1431 		assert(IIT_EXTERN(task_imp) >= count);
1432 
1433 		task_imp->iit_legacy_externdrop += count;
1434 		task_imp->iit_externdrop += count;
1435 
1436 		/* reset extern counters (if appropriate) */
1437 		if (IIT_LEGACY_EXTERN(task_imp) == 0) {
1438 			if (IIT_EXTERN(task_imp) != 0) {
1439 				task_imp->iit_externcnt -= task_imp->iit_legacy_externcnt;
1440 				task_imp->iit_externdrop -= task_imp->iit_legacy_externdrop;
1441 			} else {
1442 				task_imp->iit_externcnt = 0;
1443 				task_imp->iit_externdrop = 0;
1444 			}
1445 			task_imp->iit_legacy_externcnt = 0;
1446 			task_imp->iit_legacy_externdrop = 0;
1447 		}
1448 
1449 		/* reflect the drop to the internal assertion count (and effect any importance change) */
1450 		if (ipc_importance_task_check_transition(task_imp, IIT_UPDATE_DROP, count)) {
1451 			ipc_importance_task_propagate_assertion_locked(task_imp, IIT_UPDATE_DROP, TRUE);
1452 		}
1453 		ret = KERN_SUCCESS;
1454 	}
1455 
1456 #if IMPORTANCE_TRACE
1457 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_ASSERTION, (IMP_DROP | TASK_POLICY_EXTERNAL))) | DBG_FUNC_END,
1458 	    proc_selfpid(), target_pid, task_imp->iit_assertcnt, IIT_LEGACY_EXTERN(task_imp), 0);
1459 #endif
1460 
1461 	ipc_importance_unlock();
1462 
1463 	/* delayed printf for user-supplied data failures */
1464 	if (KERN_FAILURE == ret && TASK_NULL != target_task) {
1465 		printf("BUG in process %s[%d]: over-released legacy external boost assertions (%d total, %d external, %d legacy-external)\n",
1466 		    proc_name_address(target_task->bsd_info), task_pid(target_task),
1467 		    target_assertcnt, target_externcnt, target_legacycnt);
1468 	}
1469 
1470 	return ret;
1471 }
1472 
1473 
1474 #if LEGACY_IMPORTANCE_DELIVERY
1475 /* Transfer an assertion to legacy userspace responsibility */
1476 static kern_return_t
ipc_importance_task_externalize_legacy_assertion(ipc_importance_task_t task_imp,uint32_t count,__unused int sender_pid)1477 ipc_importance_task_externalize_legacy_assertion(ipc_importance_task_t task_imp, uint32_t count, __unused int sender_pid)
1478 {
1479 	task_t target_task;
1480 
1481 	assert(IIT_NULL != task_imp);
1482 	target_task = task_imp->iit_task;
1483 
1484 	if (TASK_NULL == target_task ||
1485 	    !ipc_importance_task_is_any_receiver_type(task_imp)) {
1486 		return KERN_FAILURE;
1487 	}
1488 
1489 #if IMPORTANCE_TRACE
1490 	int target_pid = task_pid(target_task);
1491 
1492 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_ASSERTION, IMP_EXTERN)) | DBG_FUNC_START,
1493 	    proc_selfpid(), target_pid, task_imp->iit_assertcnt, IIT_EXTERN(task_imp), 0);
1494 #endif
1495 
1496 	ipc_importance_lock();
1497 	/* assert(task_imp->iit_assertcnt >= IIT_EXTERN(task_imp) + count); */
1498 	assert(IIT_EXTERN(task_imp) >= IIT_LEGACY_EXTERN(task_imp));
1499 	task_imp->iit_legacy_externcnt += count;
1500 	task_imp->iit_externcnt += count;
1501 	ipc_importance_unlock();
1502 
1503 #if IMPORTANCE_TRACE
1504 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_ASSERTION, IMP_EXTERN)) | DBG_FUNC_END,
1505 	    proc_selfpid(), target_pid, task_imp->iit_assertcnt, IIT_LEGACY_EXTERN(task_imp), 0);
1506 	// This is the legacy boosting path
1507 	DTRACE_BOOST5(receive_boost, task_t, target_task, int, target_pid, int, sender_pid, int, count, int, IIT_LEGACY_EXTERN(task_imp));
1508 #endif /* IMPORTANCE_TRACE */
1509 
1510 	return KERN_SUCCESS;
1511 }
1512 #endif /* LEGACY_IMPORTANCE_DELIVERY */
1513 
1514 /*
1515  *	Routine:	ipc_importance_task_update_live_donor
1516  *	Purpose:
1517  *		Read the live donor status and update the live_donor bit/propagate the change in importance.
1518  *	Conditions:
1519  *		Nothing locked on entrance, nothing locked on exit.
1520  *
1521  *		TODO: Need tracepoints around this function...
1522  */
1523 void
ipc_importance_task_update_live_donor(ipc_importance_task_t task_imp)1524 ipc_importance_task_update_live_donor(ipc_importance_task_t task_imp)
1525 {
1526 	uint32_t task_live_donor;
1527 	boolean_t before_donor;
1528 	boolean_t after_donor;
1529 	task_t target_task;
1530 
1531 	assert(task_imp != NULL);
1532 
1533 	/*
1534 	 * Nothing to do if the task is not marked as expecting
1535 	 * live donor updates.
1536 	 */
1537 	if (!ipc_importance_task_is_marked_live_donor(task_imp)) {
1538 		return;
1539 	}
1540 
1541 	ipc_importance_lock();
1542 
1543 	/* If the task got disconnected on the way here, no use (or ability) adjusting live donor status */
1544 	target_task = task_imp->iit_task;
1545 	if (TASK_NULL == target_task) {
1546 		ipc_importance_unlock();
1547 		return;
1548 	}
1549 	before_donor = ipc_importance_task_is_marked_donor(task_imp);
1550 
1551 	/* snapshot task live donor status - may change, but another call will accompany the change */
1552 	task_live_donor = target_task->effective_policy.tep_live_donor;
1553 
1554 #if IMPORTANCE_TRACE
1555 	int target_pid = task_pid(target_task);
1556 
1557 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
1558 	    (IMPORTANCE_CODE(IMP_DONOR_CHANGE, IMP_DONOR_UPDATE_LIVE_DONOR_STATE)) | DBG_FUNC_START,
1559 	    target_pid, task_imp->iit_donor, task_live_donor, before_donor, 0);
1560 #endif
1561 
1562 	/* update the task importance live donor status based on the task's value */
1563 	task_imp->iit_donor = task_live_donor;
1564 
1565 	after_donor = ipc_importance_task_is_marked_donor(task_imp);
1566 
1567 	/* Has the effectiveness of being a donor changed as a result of this update? */
1568 	if (before_donor != after_donor) {
1569 		iit_update_type_t type;
1570 
1571 		/* propagate assertions without updating the current task policy (already handled) */
1572 		if (0 == before_donor) {
1573 			task_imp->iit_transitions++;
1574 			type = IIT_UPDATE_HOLD;
1575 		} else {
1576 			type = IIT_UPDATE_DROP;
1577 		}
1578 		ipc_importance_task_propagate_assertion_locked(task_imp, type, FALSE);
1579 	}
1580 
1581 #if IMPORTANCE_TRACE
1582 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
1583 	    (IMPORTANCE_CODE(IMP_DONOR_CHANGE, IMP_DONOR_UPDATE_LIVE_DONOR_STATE)) | DBG_FUNC_END,
1584 	    target_pid, task_imp->iit_donor, task_live_donor, after_donor, 0);
1585 #endif
1586 
1587 	ipc_importance_unlock();
1588 }
1589 
1590 
1591 /*
1592  *	Routine:	ipc_importance_task_mark_donor
1593  *	Purpose:
1594  *		Set the task importance donor flag.
1595  *	Conditions:
1596  *		Nothing locked on entrance, nothing locked on exit.
1597  *
1598  *		This is only called while the task is being constructed,
1599  *		so no need to update task policy or propagate downstream.
1600  */
1601 void
ipc_importance_task_mark_donor(ipc_importance_task_t task_imp,boolean_t donating)1602 ipc_importance_task_mark_donor(ipc_importance_task_t task_imp, boolean_t donating)
1603 {
1604 	assert(task_imp != NULL);
1605 
1606 	ipc_importance_lock();
1607 
1608 	int old_donor = task_imp->iit_donor;
1609 
1610 	task_imp->iit_donor = (donating ? 1 : 0);
1611 
1612 	if (task_imp->iit_donor > 0 && old_donor == 0) {
1613 		task_imp->iit_transitions++;
1614 	}
1615 
1616 	KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE,
1617 	    (IMPORTANCE_CODE(IMP_DONOR_CHANGE, IMP_DONOR_INIT_DONOR_STATE)) | DBG_FUNC_NONE,
1618 	    task_pid(task_imp->iit_task), donating,
1619 	    old_donor, task_imp->iit_donor, 0);
1620 
1621 	ipc_importance_unlock();
1622 }
1623 
1624 /*
1625  *	Routine:	ipc_importance_task_marked_donor
1626  *	Purpose:
1627  *		Query the donor flag for the given task importance.
1628  *	Conditions:
1629  *		May be called without taking the importance lock.
1630  *		In that case, donor status can change so you must
1631  *		check only once for each donation event.
1632  */
1633 boolean_t
ipc_importance_task_is_marked_donor(ipc_importance_task_t task_imp)1634 ipc_importance_task_is_marked_donor(ipc_importance_task_t task_imp)
1635 {
1636 	if (IIT_NULL == task_imp) {
1637 		return FALSE;
1638 	}
1639 	return 0 != task_imp->iit_donor;
1640 }
1641 
1642 /*
1643  *	Routine:	ipc_importance_task_mark_live_donor
1644  *	Purpose:
1645  *		Indicate that the task is eligible for live donor updates.
1646  *	Conditions:
1647  *		Nothing locked on entrance, nothing locked on exit.
1648  *
1649  *		This is only called while the task is being constructed.
1650  */
1651 void
ipc_importance_task_mark_live_donor(ipc_importance_task_t task_imp,boolean_t live_donating)1652 ipc_importance_task_mark_live_donor(ipc_importance_task_t task_imp, boolean_t live_donating)
1653 {
1654 	assert(task_imp != NULL);
1655 
1656 	ipc_importance_lock();
1657 	task_imp->iit_live_donor = (live_donating ? 1 : 0);
1658 	ipc_importance_unlock();
1659 }
1660 
1661 /*
1662  *	Routine:	ipc_importance_task_is_marked_live_donor
1663  *	Purpose:
1664  *		Query the live donor and donor flags for the given task importance.
1665  *	Conditions:
1666  *		May be called without taking the importance lock.
1667  *		In that case, donor status can change so you must
1668  *		check only once for each donation event.
1669  */
1670 boolean_t
ipc_importance_task_is_marked_live_donor(ipc_importance_task_t task_imp)1671 ipc_importance_task_is_marked_live_donor(ipc_importance_task_t task_imp)
1672 {
1673 	if (IIT_NULL == task_imp) {
1674 		return FALSE;
1675 	}
1676 	return 0 != task_imp->iit_live_donor;
1677 }
1678 
1679 /*
1680  *	Routine:	ipc_importance_task_is_donor
1681  *	Purpose:
1682  *		Query the full donor status for the given task importance.
1683  *	Conditions:
1684  *		May be called without taking the importance lock.
1685  *		In that case, donor status can change so you must
1686  *		check only once for each donation event.
1687  */
1688 boolean_t
ipc_importance_task_is_donor(ipc_importance_task_t task_imp)1689 ipc_importance_task_is_donor(ipc_importance_task_t task_imp)
1690 {
1691 	if (IIT_NULL == task_imp) {
1692 		return FALSE;
1693 	}
1694 	return ipc_importance_task_is_marked_donor(task_imp) ||
1695 	       (ipc_importance_task_is_marked_receiver(task_imp) &&
1696 	       task_imp->iit_assertcnt > 0);
1697 }
1698 
1699 /*
1700  *	Routine:	ipc_importance_task_is_never_donor
1701  *	Purpose:
1702  *		Query if a given task can ever donate importance.
1703  *	Conditions:
1704  *		May be called without taking the importance lock.
1705  *		Condition is permanent for a give task.
1706  */
1707 boolean_t
ipc_importance_task_is_never_donor(ipc_importance_task_t task_imp)1708 ipc_importance_task_is_never_donor(ipc_importance_task_t task_imp)
1709 {
1710 	if (IIT_NULL == task_imp) {
1711 		return TRUE;
1712 	}
1713 	return !ipc_importance_task_is_marked_donor(task_imp) &&
1714 	       !ipc_importance_task_is_marked_live_donor(task_imp) &&
1715 	       !ipc_importance_task_is_marked_receiver(task_imp);
1716 }
1717 
1718 /*
1719  *	Routine:	ipc_importance_task_mark_receiver
1720  *	Purpose:
1721  *		Update the task importance receiver flag.
1722  *	Conditions:
1723  *		Nothing locked on entrance, nothing locked on exit.
1724  *		This can only be invoked before the task is discoverable,
1725  *		so no worries about atomicity(?)
1726  */
1727 void
ipc_importance_task_mark_receiver(ipc_importance_task_t task_imp,boolean_t receiving)1728 ipc_importance_task_mark_receiver(ipc_importance_task_t task_imp, boolean_t receiving)
1729 {
1730 	assert(task_imp != NULL);
1731 
1732 	ipc_importance_lock();
1733 	if (receiving) {
1734 		assert(task_imp->iit_assertcnt == 0);
1735 		assert(task_imp->iit_externcnt == 0);
1736 		assert(task_imp->iit_externdrop == 0);
1737 		assert(task_imp->iit_denap == 0);
1738 		task_imp->iit_receiver = 1;  /* task can receive importance boost */
1739 	} else if (task_imp->iit_receiver) {
1740 		assert(task_imp->iit_denap == 0);
1741 		if (task_imp->iit_assertcnt != 0 || IIT_EXTERN(task_imp) != 0) {
1742 			panic("disabling imp_receiver on task with pending importance boosts!");
1743 		}
1744 		task_imp->iit_receiver = 0;
1745 	}
1746 	ipc_importance_unlock();
1747 }
1748 
1749 
1750 /*
1751  *	Routine:	ipc_importance_task_marked_receiver
1752  *	Purpose:
1753  *		Query the receiver flag for the given task importance.
1754  *	Conditions:
1755  *		May be called without taking the importance lock as
1756  *		the importance flag can never change after task init.
1757  */
1758 boolean_t
ipc_importance_task_is_marked_receiver(ipc_importance_task_t task_imp)1759 ipc_importance_task_is_marked_receiver(ipc_importance_task_t task_imp)
1760 {
1761 	return IIT_NULL != task_imp && 0 != task_imp->iit_receiver;
1762 }
1763 
1764 
1765 /*
1766  *	Routine:	ipc_importance_task_mark_denap_receiver
1767  *	Purpose:
1768  *		Update the task importance de-nap receiver flag.
1769  *	Conditions:
1770  *		Nothing locked on entrance, nothing locked on exit.
1771  *		This can only be invoked before the task is discoverable,
1772  *		so no worries about atomicity(?)
1773  */
1774 void
ipc_importance_task_mark_denap_receiver(ipc_importance_task_t task_imp,boolean_t denap)1775 ipc_importance_task_mark_denap_receiver(ipc_importance_task_t task_imp, boolean_t denap)
1776 {
1777 	assert(task_imp != NULL);
1778 
1779 	ipc_importance_lock();
1780 	if (denap) {
1781 		assert(task_imp->iit_assertcnt == 0);
1782 		assert(task_imp->iit_externcnt == 0);
1783 		assert(task_imp->iit_receiver == 0);
1784 		task_imp->iit_denap = 1;  /* task can receive de-nap boost */
1785 	} else if (task_imp->iit_denap) {
1786 		assert(task_imp->iit_receiver == 0);
1787 		if (0 < task_imp->iit_assertcnt || 0 < IIT_EXTERN(task_imp)) {
1788 			panic("disabling de-nap on task with pending de-nap boosts!");
1789 		}
1790 		task_imp->iit_denap = 0;
1791 	}
1792 	ipc_importance_unlock();
1793 }
1794 
1795 
1796 /*
1797  *	Routine:	ipc_importance_task_marked_denap_receiver
1798  *	Purpose:
1799  *		Query the de-nap receiver flag for the given task importance.
1800  *	Conditions:
1801  *		May be called without taking the importance lock as
1802  *		the de-nap flag can never change after task init.
1803  */
1804 boolean_t
ipc_importance_task_is_marked_denap_receiver(ipc_importance_task_t task_imp)1805 ipc_importance_task_is_marked_denap_receiver(ipc_importance_task_t task_imp)
1806 {
1807 	return IIT_NULL != task_imp && 0 != task_imp->iit_denap;
1808 }
1809 
1810 /*
1811  *	Routine:	ipc_importance_task_is_denap_receiver
1812  *	Purpose:
1813  *		Query the full de-nap receiver status for the given task importance.
1814  *		For now, that is simply whether the receiver flag is set.
1815  *	Conditions:
1816  *		May be called without taking the importance lock as
1817  *		the de-nap receiver flag can never change after task init.
1818  */
1819 boolean_t
ipc_importance_task_is_denap_receiver(ipc_importance_task_t task_imp)1820 ipc_importance_task_is_denap_receiver(ipc_importance_task_t task_imp)
1821 {
1822 	return ipc_importance_task_is_marked_denap_receiver(task_imp);
1823 }
1824 
1825 /*
1826  *	Routine:	ipc_importance_task_is_any_receiver_type
1827  *	Purpose:
1828  *		Query if the task is marked to receive boosts - either
1829  *		importance or denap.
1830  *	Conditions:
1831  *		May be called without taking the importance lock as both
1832  *		the importance and de-nap receiver flags can never change
1833  *		after task init.
1834  */
1835 boolean_t
ipc_importance_task_is_any_receiver_type(ipc_importance_task_t task_imp)1836 ipc_importance_task_is_any_receiver_type(ipc_importance_task_t task_imp)
1837 {
1838 	return ipc_importance_task_is_marked_receiver(task_imp) ||
1839 	       ipc_importance_task_is_marked_denap_receiver(task_imp);
1840 }
1841 
1842 #if 0 /* currently unused */
1843 
1844 /*
1845  *	Routine:	ipc_importance_inherit_reference
1846  *	Purpose:
1847  *		Add a reference to the inherit importance element.
1848  *	Conditions:
1849  *		Caller most hold a reference on the inherit element.
1850  */
1851 static inline void
1852 ipc_importance_inherit_reference(ipc_importance_inherit_t inherit)
1853 {
1854 	ipc_importance_reference(&inherit->iii_elem);
1855 }
1856 #endif /* currently unused */
1857 
1858 /*
1859  *	Routine:	ipc_importance_inherit_release_locked
1860  *	Purpose:
1861  *		Release a reference on an inherit importance attribute value,
1862  *		unlinking and deallocating the attribute if the last reference.
1863  *	Conditions:
1864  *		Entered with importance lock held, leaves with it unlocked.
1865  */
1866 static inline void
ipc_importance_inherit_release_locked(ipc_importance_inherit_t inherit)1867 ipc_importance_inherit_release_locked(ipc_importance_inherit_t inherit)
1868 {
1869 	ipc_importance_release_locked(&inherit->iii_elem);
1870 }
1871 
1872 #if 0 /* currently unused */
1873 /*
1874  *	Routine:	ipc_importance_inherit_release
1875  *	Purpose:
1876  *		Release a reference on an inherit importance attribute value,
1877  *		unlinking and deallocating the attribute if the last reference.
1878  *	Conditions:
1879  *		nothing locked on entrance, nothing locked on exit.
1880  *		May block.
1881  */
1882 void
1883 ipc_importance_inherit_release(ipc_importance_inherit_t inherit)
1884 {
1885 	if (III_NULL != inherit) {
1886 		ipc_importance_release(&inherit->iii_elem);
1887 	}
1888 }
1889 #endif /* 0 currently unused */
1890 
1891 /*
1892  *	Routine:	ipc_importance_for_task
1893  *	Purpose:
1894  *		Create a reference for the specified task's base importance
1895  *		element.  If the base importance element doesn't exist, make it and
1896  *		bind it to the active task.  If the task is inactive, there isn't
1897  *		any need to return a new reference.
1898  *	Conditions:
1899  *		If made is true, a "made" reference is returned (for donating to
1900  *		the voucher system).  Otherwise	an internal reference is returned.
1901  *
1902  *		Nothing locked on entry.  May block.
1903  */
1904 ipc_importance_task_t
ipc_importance_for_task(task_t task,boolean_t made)1905 ipc_importance_for_task(task_t task, boolean_t made)
1906 {
1907 	ipc_importance_task_t task_elem;
1908 	boolean_t first_pass = TRUE;
1909 
1910 	assert(TASK_NULL != task);
1911 
1912 retry:
1913 	/* No use returning anything for inactive task */
1914 	if (!task->active) {
1915 		return IIT_NULL;
1916 	}
1917 
1918 	ipc_importance_lock();
1919 	task_elem = task->task_imp_base;
1920 	if (IIT_NULL != task_elem) {
1921 		/* Add a made reference (borrowing active task ref to do it) */
1922 		if (made) {
1923 			if (0 == task_elem->iit_made++) {
1924 				assert(IIT_REFS_MAX > IIT_REFS(task_elem));
1925 				ipc_importance_task_reference_internal(task_elem);
1926 			}
1927 		} else {
1928 			assert(IIT_REFS_MAX > IIT_REFS(task_elem));
1929 			ipc_importance_task_reference_internal(task_elem);
1930 		}
1931 		ipc_importance_unlock();
1932 		return task_elem;
1933 	}
1934 	ipc_importance_unlock();
1935 
1936 	if (!first_pass) {
1937 		return IIT_NULL;
1938 	}
1939 	first_pass = FALSE;
1940 
1941 	/* Need to make one - may race with others (be prepared to drop) */
1942 	task_elem = zalloc_flags(ipc_importance_task_zone, Z_WAITOK | Z_ZERO);
1943 	if (IIT_NULL == task_elem) {
1944 		goto retry;
1945 	}
1946 
1947 	task_elem->iit_bits = IIE_TYPE_TASK | 2; /* one for task, one for return/made */
1948 	task_elem->iit_made = (made) ? 1 : 0;
1949 	task_elem->iit_task = task; /* take actual ref when we're sure */
1950 #if IIE_REF_DEBUG
1951 	ipc_importance_counter_init(&task_elem->iit_elem);
1952 #endif
1953 	queue_init(&task_elem->iit_kmsgs);
1954 	queue_init(&task_elem->iit_inherits);
1955 
1956 	ipc_importance_lock();
1957 	if (!task->active) {
1958 		ipc_importance_unlock();
1959 		zfree(ipc_importance_task_zone, task_elem);
1960 		return IIT_NULL;
1961 	}
1962 
1963 	/* did we lose the race? */
1964 	if (IIT_NULL != task->task_imp_base) {
1965 		ipc_importance_unlock();
1966 		zfree(ipc_importance_task_zone, task_elem);
1967 		goto retry;
1968 	}
1969 
1970 	/* we won the race */
1971 	task->task_imp_base = task_elem;
1972 	task_reference_grp(task, TASK_GRP_INTERNAL);
1973 #if DEVELOPMENT || DEBUG
1974 	queue_enter(&global_iit_alloc_queue, task_elem, ipc_importance_task_t, iit_allocation);
1975 	task_importance_update_owner_info(task);
1976 #endif
1977 	ipc_importance_unlock();
1978 
1979 	return task_elem;
1980 }
1981 
1982 #if DEVELOPMENT || DEBUG
1983 void
task_importance_update_owner_info(task_t task)1984 task_importance_update_owner_info(task_t task)
1985 {
1986 	if (task != TASK_NULL && task->task_imp_base != IIT_NULL) {
1987 		ipc_importance_task_t task_elem = task->task_imp_base;
1988 
1989 		task_elem->iit_bsd_pid = task_pid(task);
1990 		if (task->bsd_info) {
1991 			strncpy(&task_elem->iit_procname[0], proc_name_address(task->bsd_info), 16);
1992 			task_elem->iit_procname[16] = '\0';
1993 		} else {
1994 			strncpy(&task_elem->iit_procname[0], "unknown", 16);
1995 		}
1996 	}
1997 }
1998 #endif
1999 
2000 static int
task_importance_task_get_pid(ipc_importance_task_t iit)2001 task_importance_task_get_pid(ipc_importance_task_t iit)
2002 {
2003 #if DEVELOPMENT || DEBUG
2004 	return (int)iit->iit_bsd_pid;
2005 #else
2006 	return task_pid(iit->iit_task);
2007 #endif
2008 }
2009 
2010 /*
2011  *	Routine:	ipc_importance_reset_locked
2012  *	Purpose:
2013  *		Reset a task's IPC importance (the task is going away or exec'ing)
2014  *
2015  *		Remove the donor bit and legacy externalized assertions from the
2016  *		current task importance and see if that wipes out downstream donations.
2017  *	Conditions:
2018  *		importance lock held.
2019  */
2020 
2021 static void
ipc_importance_reset_locked(ipc_importance_task_t task_imp,boolean_t donor)2022 ipc_importance_reset_locked(ipc_importance_task_t task_imp, boolean_t donor)
2023 {
2024 	boolean_t before_donor, after_donor;
2025 
2026 	/* remove the donor bit, live-donor bit and externalized boosts */
2027 	before_donor = ipc_importance_task_is_donor(task_imp);
2028 	if (donor) {
2029 		task_imp->iit_donor = 0;
2030 	}
2031 	assert(IIT_LEGACY_EXTERN(task_imp) <= IIT_EXTERN(task_imp));
2032 	assert(task_imp->iit_legacy_externcnt <= task_imp->iit_externcnt);
2033 	assert(task_imp->iit_legacy_externdrop <= task_imp->iit_externdrop);
2034 	task_imp->iit_externcnt -= task_imp->iit_legacy_externcnt;
2035 	task_imp->iit_externdrop -= task_imp->iit_legacy_externdrop;
2036 
2037 	/* assert(IIT_LEGACY_EXTERN(task_imp) <= task_imp->iit_assertcnt); */
2038 	if (IIT_EXTERN(task_imp) < task_imp->iit_assertcnt) {
2039 		task_imp->iit_assertcnt -= IIT_LEGACY_EXTERN(task_imp);
2040 	} else {
2041 		task_imp->iit_assertcnt = IIT_EXTERN(task_imp);
2042 	}
2043 	task_imp->iit_legacy_externcnt = 0;
2044 	task_imp->iit_legacy_externdrop = 0;
2045 	after_donor = ipc_importance_task_is_donor(task_imp);
2046 
2047 	/* propagate a downstream drop if there was a change in donor status */
2048 	if (after_donor != before_donor) {
2049 		ipc_importance_task_propagate_assertion_locked(task_imp, IIT_UPDATE_DROP, FALSE);
2050 	}
2051 }
2052 
2053 /*
2054  *	Routine:	ipc_importance_reset
2055  *	Purpose:
2056  *		Reset a task's IPC importance
2057  *
2058  *		The task is being reset, although staying around. Arrange to have the
2059  *		external state of the task reset from the importance.
2060  *	Conditions:
2061  *		importance lock not held.
2062  */
2063 
2064 void
ipc_importance_reset(ipc_importance_task_t task_imp,boolean_t donor)2065 ipc_importance_reset(ipc_importance_task_t task_imp, boolean_t donor)
2066 {
2067 	if (IIT_NULL == task_imp) {
2068 		return;
2069 	}
2070 	ipc_importance_lock();
2071 	ipc_importance_reset_locked(task_imp, donor);
2072 	ipc_importance_unlock();
2073 }
2074 
2075 /*
2076  *	Routine:	ipc_importance_disconnect_task
2077  *	Purpose:
2078  *		Disconnect a task from its importance.
2079  *
2080  *		Clear the task pointer from the importance and drop the
2081  *		reference the task held on the importance object.  Before
2082  *		doing that, reset the effects the current task holds on
2083  *		the importance and see if that wipes out downstream donations.
2084  *
2085  *		We allow the upstream boosts to continue to affect downstream
2086  *		even though the local task is being effectively pulled from
2087  *		the chain.
2088  *	Conditions:
2089  *		Nothing locked.
2090  */
2091 void
ipc_importance_disconnect_task(task_t task)2092 ipc_importance_disconnect_task(task_t task)
2093 {
2094 	ipc_importance_task_t task_imp;
2095 
2096 	task_lock(task);
2097 	ipc_importance_lock();
2098 	task_imp = task->task_imp_base;
2099 
2100 	/* did somebody beat us to it? */
2101 	if (IIT_NULL == task_imp) {
2102 		ipc_importance_unlock();
2103 		task_unlock(task);
2104 		return;
2105 	}
2106 
2107 	/* disconnect the task from this importance */
2108 	assert(task_imp->iit_task == task);
2109 	task_imp->iit_task = TASK_NULL;
2110 	task->task_imp_base = IIT_NULL;
2111 	task_unlock(task);
2112 
2113 	/* reset the effects the current task hold on the importance */
2114 	ipc_importance_reset_locked(task_imp, TRUE);
2115 
2116 	ipc_importance_task_release_locked(task_imp);
2117 	/* importance unlocked */
2118 
2119 	/* deallocate the task now that the importance is unlocked */
2120 	task_deallocate_grp(task, TASK_GRP_INTERNAL);
2121 }
2122 
2123 /*
2124  *	Routine:	ipc_importance_exec_switch_task
2125  *	Purpose:
2126  *		Switch importance task base from old task to new task in exec.
2127  *
2128  *		Create an ipc importance linkage from old task to new task,
2129  *		once the linkage is created, switch the importance task base
2130  *		from old task to new task. After the switch, the linkage will
2131  *		represent importance linkage from new task to old task with
2132  *		watch port importance inheritance linked to new task.
2133  *	Conditions:
2134  *		Nothing locked.
2135  *		Returns a reference on importance inherit.
2136  */
2137 ipc_importance_inherit_t
ipc_importance_exec_switch_task(task_t old_task,task_t new_task)2138 ipc_importance_exec_switch_task(
2139 	task_t old_task,
2140 	task_t new_task)
2141 {
2142 	ipc_importance_inherit_t inherit = III_NULL;
2143 	ipc_importance_task_t old_task_imp = IIT_NULL;
2144 	ipc_importance_task_t new_task_imp = IIT_NULL;
2145 
2146 	task_importance_reset(old_task);
2147 
2148 	/* Create an importance linkage from old_task to new_task */
2149 	inherit = ipc_importance_inherit_from_task(old_task, new_task);
2150 
2151 	/* Switch task importance base from old task to new task */
2152 	ipc_importance_lock();
2153 
2154 	old_task_imp = old_task->task_imp_base;
2155 	new_task_imp = new_task->task_imp_base;
2156 
2157 	old_task_imp->iit_task = new_task;
2158 	new_task_imp->iit_task = old_task;
2159 
2160 	old_task->task_imp_base = new_task_imp;
2161 	new_task->task_imp_base = old_task_imp;
2162 
2163 #if DEVELOPMENT || DEBUG
2164 	/*
2165 	 * Update the pid an proc name for importance base if any
2166 	 */
2167 	task_importance_update_owner_info(new_task);
2168 #endif
2169 	ipc_importance_unlock();
2170 
2171 	return inherit;
2172 }
2173 
2174 /*
2175  *	Routine:	ipc_importance_check_circularity
2176  *	Purpose:
2177  *		Check if queueing "port" in a message for "dest"
2178  *		would create a circular group of ports and messages.
2179  *
2180  *		If no circularity (FALSE returned), then "port"
2181  *		is changed from "in limbo" to "in transit".
2182  *
2183  *		That is, we want to set port->ip_destination == dest,
2184  *		but guaranteeing that this doesn't create a circle
2185  *		port->ip_destination->ip_destination->... == port
2186  *
2187  *		Additionally, if port was successfully changed to "in transit",
2188  *		propagate boost assertions from the "in limbo" port to all
2189  *		the ports in the chain, and, if the destination task accepts
2190  *		boosts, to the destination task.
2191  *
2192  *	Conditions:
2193  *		No ports locked.  References held for "port" and "dest".
2194  */
2195 
2196 boolean_t
ipc_importance_check_circularity(ipc_port_t port,ipc_port_t dest)2197 ipc_importance_check_circularity(
2198 	ipc_port_t      port,
2199 	ipc_port_t      dest)
2200 {
2201 	ipc_importance_task_t imp_task = IIT_NULL;
2202 	ipc_importance_task_t release_imp_task = IIT_NULL;
2203 	boolean_t imp_lock_held = FALSE;
2204 	int assertcnt = 0;
2205 	ipc_port_t base;
2206 	struct turnstile *send_turnstile = TURNSTILE_NULL;
2207 	struct task_watchport_elem *watchport_elem = NULL;
2208 	bool took_base_ref = false;
2209 
2210 	assert(port != IP_NULL);
2211 	assert(dest != IP_NULL);
2212 
2213 	if (port == dest) {
2214 		return TRUE;
2215 	}
2216 	base = dest;
2217 
2218 	/* Check if destination needs a turnstile */
2219 	ipc_port_send_turnstile_prepare(dest);
2220 
2221 	/* port is in limbo, so donation status is safe to latch */
2222 	if (port->ip_impdonation != 0) {
2223 		imp_lock_held = TRUE;
2224 		ipc_importance_lock();
2225 	}
2226 
2227 	/*
2228 	 *	First try a quick check that can run in parallel.
2229 	 *	No circularity if dest is not in transit.
2230 	 */
2231 	ip_mq_lock(port);
2232 
2233 	/*
2234 	 * Even if port is just carrying assertions for others,
2235 	 * we need the importance lock.
2236 	 */
2237 	if (port->ip_impcount > 0 && !imp_lock_held) {
2238 		if (!ipc_importance_lock_try()) {
2239 			ip_mq_unlock(port);
2240 			ipc_importance_lock();
2241 			ip_mq_lock(port);
2242 		}
2243 		imp_lock_held = TRUE;
2244 	}
2245 
2246 	if (ip_mq_lock_try(dest)) {
2247 		if (!ip_in_transit(dest)) {
2248 			goto not_circular;
2249 		}
2250 
2251 		/* dest is in transit; further checking necessary */
2252 
2253 		ip_mq_unlock(dest);
2254 	}
2255 	ip_mq_unlock(port);
2256 
2257 	/*
2258 	 * We're about to pay the cost to serialize,
2259 	 * just go ahead and grab importance lock.
2260 	 */
2261 	if (!imp_lock_held) {
2262 		ipc_importance_lock();
2263 		imp_lock_held = TRUE;
2264 	}
2265 
2266 	ipc_port_multiple_lock(); /* massive serialization */
2267 
2268 	took_base_ref = ipc_port_destination_chain_lock(dest, &base);
2269 	/* all ports in chain from dest to base, inclusive, are locked */
2270 
2271 	if (port == base) {
2272 		/* circularity detected! */
2273 
2274 		ipc_port_multiple_unlock();
2275 
2276 		/* port (== base) is in limbo */
2277 
2278 		require_ip_active(port);
2279 		assert(ip_in_limbo(port));
2280 		assert(!took_base_ref);
2281 
2282 		base = dest;
2283 		while (base != IP_NULL) {
2284 			ipc_port_t next;
2285 
2286 			/* base is in transit or in limbo */
2287 
2288 			require_ip_active(base);
2289 			assert(base->ip_receiver_name == MACH_PORT_NULL);
2290 			next = ip_get_destination(base);
2291 			ip_mq_unlock(base);
2292 			base = next;
2293 		}
2294 
2295 		if (imp_lock_held) {
2296 			ipc_importance_unlock();
2297 		}
2298 
2299 		ipc_port_send_turnstile_complete(dest);
2300 		return TRUE;
2301 	}
2302 
2303 	/*
2304 	 *	The guarantee:  lock port while the entire chain is locked.
2305 	 *	Once port is locked, we can take a reference to dest,
2306 	 *	add port to the chain, and unlock everything.
2307 	 */
2308 
2309 	ip_mq_lock(port);
2310 	ipc_port_multiple_unlock();
2311 
2312 not_circular:
2313 	/* port is in limbo */
2314 	require_ip_active(port);
2315 	assert(ip_in_limbo(port));
2316 
2317 	/* Port is being enqueued in a kmsg, remove the watchport boost in order to push on destination port */
2318 	watchport_elem = ipc_port_clear_watchport_elem_internal(port);
2319 
2320 	/* Check if the port is being enqueued as a part of sync bootstrap checkin */
2321 	if (dest->ip_specialreply && dest->ip_sync_bootstrap_checkin) {
2322 		port->ip_sync_bootstrap_checkin = 1;
2323 	}
2324 
2325 	ip_reference(dest);
2326 
2327 	/* port transitions to IN-TRANSIT state */
2328 	assert(port->ip_receiver_name == MACH_PORT_NULL);
2329 	port->ip_destination = dest;
2330 
2331 	/* must have been in limbo or still bound to a task */
2332 	assert(port->ip_tempowner != 0);
2333 
2334 	/*
2335 	 * We delayed dropping assertions from a specific task.
2336 	 * Cache that info now (we'll drop assertions and the
2337 	 * task reference below).
2338 	 */
2339 	release_imp_task = ip_get_imp_task(port);
2340 	if (IIT_NULL != release_imp_task) {
2341 		port->ip_imp_task = IIT_NULL;
2342 	}
2343 	assertcnt = port->ip_impcount;
2344 
2345 	/* take the port out of limbo w.r.t. assertions */
2346 	port->ip_tempowner = 0;
2347 
2348 	/*
2349 	 * Setup linkage for source port if it has a send turnstile i.e. it has
2350 	 * a thread waiting in send or has a port enqueued in it or has sync ipc
2351 	 * push from a special reply port.
2352 	 */
2353 	if (port_send_turnstile(port)) {
2354 		send_turnstile = turnstile_prepare((uintptr_t)port,
2355 		    port_send_turnstile_address(port),
2356 		    TURNSTILE_NULL, TURNSTILE_SYNC_IPC);
2357 
2358 		turnstile_update_inheritor(send_turnstile, port_send_turnstile(dest),
2359 		    (TURNSTILE_INHERITOR_TURNSTILE | TURNSTILE_IMMEDIATE_UPDATE));
2360 
2361 		/* update complete and turnstile complete called after dropping all locks */
2362 	}
2363 	/* now unlock chain */
2364 
2365 	ip_mq_unlock(port);
2366 
2367 	for (;;) {
2368 		ipc_port_t next;
2369 		/* every port along chain track assertions behind it */
2370 		ipc_port_impcount_delta(dest, assertcnt, base);
2371 
2372 		if (dest == base) {
2373 			break;
2374 		}
2375 
2376 		/* port is in transit */
2377 
2378 		require_ip_active(dest);
2379 		assert(ip_in_transit(dest));
2380 		assert(dest->ip_tempowner == 0);
2381 
2382 		next = ip_get_destination(dest);
2383 		ip_mq_unlock(dest);
2384 		dest = next;
2385 	}
2386 
2387 	/* base is not in transit */
2388 	assert(!ip_in_transit(base));
2389 
2390 	/*
2391 	 * Find the task to boost (if any).
2392 	 * We will boost "through" ports that don't know
2393 	 * about inheritance to deliver receive rights that
2394 	 * do.
2395 	 */
2396 	if (ip_active(base) && (assertcnt > 0)) {
2397 		assert(imp_lock_held);
2398 		if (base->ip_tempowner != 0) {
2399 			if (IIT_NULL != ip_get_imp_task(base)) {
2400 				/* specified tempowner task */
2401 				imp_task = ip_get_imp_task(base);
2402 				assert(ipc_importance_task_is_any_receiver_type(imp_task));
2403 			}
2404 			/* otherwise don't boost current task */
2405 		} else if (ip_in_a_space(base)) {
2406 			ipc_space_t space = ip_get_receiver(base);
2407 			/* only spaces with boost-accepting tasks */
2408 			if (space->is_task != TASK_NULL &&
2409 			    ipc_importance_task_is_any_receiver_type(space->is_task->task_imp_base)) {
2410 				imp_task = space->is_task->task_imp_base;
2411 			}
2412 		}
2413 
2414 		/* take reference before unlocking base */
2415 		if (imp_task != IIT_NULL) {
2416 			ipc_importance_task_reference(imp_task);
2417 		}
2418 	}
2419 
2420 	ip_mq_unlock(base);
2421 
2422 	/* All locks dropped, call turnstile_update_inheritor_complete for source port's turnstile */
2423 	if (send_turnstile) {
2424 		turnstile_update_inheritor_complete(send_turnstile, TURNSTILE_INTERLOCK_NOT_HELD);
2425 
2426 		/* Take the port lock to call turnstile complete */
2427 		ip_mq_lock(port);
2428 		turnstile_complete((uintptr_t)port, port_send_turnstile_address(port), NULL, TURNSTILE_SYNC_IPC);
2429 		send_turnstile = TURNSTILE_NULL;
2430 		ip_mq_unlock(port);
2431 		turnstile_cleanup();
2432 	}
2433 
2434 	/*
2435 	 * Transfer assertions now that the ports are unlocked.
2436 	 * Avoid extra overhead if transferring to/from the same task.
2437 	 *
2438 	 * NOTE: If a transfer is occurring, the new assertions will
2439 	 * be added to imp_task BEFORE the importance lock is unlocked.
2440 	 * This is critical - to avoid decrements coming from the kmsgs
2441 	 * beating the increment to the task.
2442 	 */
2443 	boolean_t transfer_assertions = (imp_task != release_imp_task);
2444 
2445 	if (imp_task != IIT_NULL) {
2446 		assert(imp_lock_held);
2447 		if (transfer_assertions) {
2448 			ipc_importance_task_hold_internal_assertion_locked(imp_task, assertcnt);
2449 		}
2450 	}
2451 
2452 	if (release_imp_task != IIT_NULL) {
2453 		assert(imp_lock_held);
2454 		if (transfer_assertions) {
2455 			ipc_importance_task_drop_internal_assertion_locked(release_imp_task, assertcnt);
2456 		}
2457 	}
2458 
2459 	if (imp_lock_held) {
2460 		ipc_importance_unlock();
2461 	}
2462 
2463 	if (took_base_ref) {
2464 		ip_release(base);
2465 	}
2466 
2467 	if (imp_task != IIT_NULL) {
2468 		ipc_importance_task_release(imp_task);
2469 	}
2470 
2471 	if (release_imp_task != IIT_NULL) {
2472 		ipc_importance_task_release(release_imp_task);
2473 	}
2474 
2475 	if (watchport_elem) {
2476 		task_watchport_elem_deallocate(watchport_elem);
2477 	}
2478 
2479 	return FALSE;
2480 }
2481 
2482 /*
2483  *	Routine:	ipc_importance_send
2484  *	Purpose:
2485  *		Post the importance voucher attribute [if sent] or a static
2486  *		importance boost depending upon options and conditions.
2487  *	Conditions:
2488  *		Destination port locked on entry and exit, may be dropped during the call.
2489  *	Returns:
2490  *		A boolean identifying if the port lock was tempoarily dropped.
2491  */
2492 boolean_t
ipc_importance_send(ipc_kmsg_t kmsg,mach_msg_option_t option)2493 ipc_importance_send(
2494 	ipc_kmsg_t              kmsg,
2495 	mach_msg_option_t       option)
2496 {
2497 	ipc_port_t port = kmsg->ikm_header->msgh_remote_port;
2498 	ipc_port_t voucher_port;
2499 	boolean_t port_lock_dropped = FALSE;
2500 	ipc_importance_elem_t elem;
2501 	task_t task;
2502 	ipc_importance_task_t task_imp;
2503 	kern_return_t kr;
2504 
2505 	assert(IP_VALID(port));
2506 
2507 	/* If no donation to be made, return quickly */
2508 	if ((port->ip_impdonation == 0) ||
2509 	    (option & MACH_SEND_NOIMPORTANCE) != 0) {
2510 		return port_lock_dropped;
2511 	}
2512 
2513 	task = current_task();
2514 
2515 	/* If forced sending a static boost, go update the port */
2516 	if ((option & MACH_SEND_IMPORTANCE) != 0) {
2517 		/* acquire the importance lock while trying to hang on to port lock */
2518 		if (!ipc_importance_lock_try()) {
2519 			port_lock_dropped = TRUE;
2520 			ip_mq_unlock(port);
2521 			ipc_importance_lock();
2522 		}
2523 		goto portupdate;
2524 	}
2525 
2526 	task_imp = task->task_imp_base;
2527 
2528 	/* If the sender can never donate importance, nothing to do */
2529 	if (ipc_importance_task_is_never_donor(task_imp)) {
2530 		return port_lock_dropped;
2531 	}
2532 
2533 	elem = IIE_NULL;
2534 
2535 	/* If importance receiver and passing a voucher, look for importance in there */
2536 	voucher_port = ipc_kmsg_get_voucher_port(kmsg);
2537 	if (IP_VALID(voucher_port) &&
2538 	    ipc_importance_task_is_marked_receiver(task_imp)) {
2539 		mach_voucher_attr_value_handle_t vals[MACH_VOUCHER_ATTR_VALUE_MAX_NESTED];
2540 		mach_voucher_attr_value_handle_array_size_t val_count;
2541 		ipc_voucher_t voucher;
2542 
2543 		assert(ip_kotype(voucher_port) == IKOT_VOUCHER);
2544 		voucher = (ipc_voucher_t)ipc_kobject_get_raw(voucher_port,
2545 		    IKOT_VOUCHER);
2546 
2547 		/* check to see if the voucher has an importance attribute */
2548 		val_count = MACH_VOUCHER_ATTR_VALUE_MAX_NESTED;
2549 		kr = mach_voucher_attr_control_get_values(ipc_importance_control, voucher,
2550 		    vals, &val_count);
2551 		assert(KERN_SUCCESS == kr);
2552 
2553 		/*
2554 		 * Only use importance associated with our task (either directly
2555 		 * or through an inherit that donates to our task).
2556 		 */
2557 		if (0 < val_count) {
2558 			ipc_importance_elem_t check_elem;
2559 
2560 			check_elem = (ipc_importance_elem_t)vals[0];
2561 			assert(IIE_NULL != check_elem);
2562 			if (IIE_TYPE_INHERIT == IIE_TYPE(check_elem)) {
2563 				ipc_importance_inherit_t inherit;
2564 				inherit = (ipc_importance_inherit_t) check_elem;
2565 				if (inherit->iii_to_task == task_imp) {
2566 					elem = check_elem;
2567 				}
2568 			} else if (check_elem == (ipc_importance_elem_t)task_imp) {
2569 				elem = check_elem;
2570 			}
2571 		}
2572 	}
2573 
2574 	/* If we haven't found an importance attribute to send yet, use the task's */
2575 	if (IIE_NULL == elem) {
2576 		elem = (ipc_importance_elem_t)task_imp;
2577 	}
2578 
2579 	/* take a reference for the message to hold */
2580 	ipc_importance_reference_internal(elem);
2581 
2582 	/* acquire the importance lock while trying to hang on to port lock */
2583 	if (!ipc_importance_lock_try()) {
2584 		port_lock_dropped = TRUE;
2585 		ip_mq_unlock(port);
2586 		ipc_importance_lock();
2587 	}
2588 
2589 	/* link kmsg onto the donor element propagation chain */
2590 	ipc_importance_kmsg_link(kmsg, elem);
2591 	/* elem reference transfered to kmsg */
2592 
2593 	incr_ref_counter(elem->iie_kmsg_refs_added);
2594 
2595 	/* If the sender isn't currently a donor, no need to apply boost */
2596 	if (!ipc_importance_task_is_donor(task_imp)) {
2597 		ipc_importance_unlock();
2598 
2599 		/* re-acquire port lock, if needed */
2600 		if (TRUE == port_lock_dropped) {
2601 			ip_mq_lock(port);
2602 		}
2603 
2604 		return port_lock_dropped;
2605 	}
2606 
2607 portupdate:
2608 	/* Mark the fact that we are (currently) donating through this message */
2609 	kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_RAISEIMP;
2610 
2611 	/*
2612 	 * If we need to relock the port, do it with the importance still locked.
2613 	 * This assures we get to add the importance boost through the port to
2614 	 * the task BEFORE anyone else can attempt to undo that operation if
2615 	 * the sender lost donor status.
2616 	 */
2617 	if (TRUE == port_lock_dropped) {
2618 		ip_mq_lock(port);
2619 	}
2620 
2621 	ipc_importance_assert_held();
2622 
2623 #if IMPORTANCE_TRACE
2624 	if (kdebug_enable) {
2625 		mach_msg_max_trailer_t *dbgtrailer = (mach_msg_max_trailer_t *)
2626 		    ((vm_offset_t)kmsg->ikm_header + mach_round_msg(kmsg->ikm_header->msgh_size));
2627 		unsigned int sender_pid = dbgtrailer->msgh_audit.val[5];
2628 		mach_msg_id_t imp_msgh_id = kmsg->ikm_header->msgh_id;
2629 		KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_MSG, IMP_MSG_SEND)) | DBG_FUNC_START,
2630 		    task_pid(task), sender_pid, imp_msgh_id, 0, 0);
2631 	}
2632 #endif /* IMPORTANCE_TRACE */
2633 
2634 	mach_port_delta_t delta = 1;
2635 	boolean_t need_port_lock;
2636 	task_imp = IIT_NULL;
2637 
2638 	/* adjust port boost count (with importance and port locked) */
2639 	need_port_lock = ipc_port_importance_delta_internal(port, IPID_OPTION_NORMAL, &delta, &task_imp);
2640 	/* hold a reference on task_imp */
2641 
2642 	/* if we need to adjust a task importance as a result, apply that here */
2643 	if (IIT_NULL != task_imp && delta != 0) {
2644 		assert(delta == 1);
2645 
2646 		/* if this results in a change of state, propagate the transistion */
2647 		if (ipc_importance_task_check_transition(task_imp, IIT_UPDATE_HOLD, delta)) {
2648 			/* can't hold the port lock during task transition(s) */
2649 			if (!need_port_lock) {
2650 				need_port_lock = TRUE;
2651 				ip_mq_unlock(port);
2652 			}
2653 			ipc_importance_task_propagate_assertion_locked(task_imp, IIT_UPDATE_HOLD, TRUE);
2654 		}
2655 	}
2656 
2657 	if (task_imp) {
2658 		ipc_importance_task_release_locked(task_imp);
2659 		/* importance unlocked */
2660 	} else {
2661 		ipc_importance_unlock();
2662 	}
2663 
2664 	if (need_port_lock) {
2665 		port_lock_dropped = TRUE;
2666 		ip_mq_lock(port);
2667 	}
2668 
2669 	return port_lock_dropped;
2670 }
2671 
2672 /*
2673  *	Routine:	ipc_importance_inherit_from_kmsg
2674  *	Purpose:
2675  *		Create a "made" reference for an importance attribute representing
2676  *		an inheritance between the sender of a message (if linked) and the
2677  *		current task importance.  If the message is not linked, a static
2678  *		boost may be created, based on the boost state of the message.
2679  *
2680  *		Any transfer from kmsg linkage to inherit linkage must be atomic.
2681  *
2682  *		If the task is inactive, there isn't any need to return a new reference.
2683  *	Conditions:
2684  *		Nothing locked on entry.  May block.
2685  */
2686 static ipc_importance_inherit_t
ipc_importance_inherit_from_kmsg(ipc_kmsg_t kmsg)2687 ipc_importance_inherit_from_kmsg(ipc_kmsg_t kmsg)
2688 {
2689 	ipc_importance_task_t   task_imp = IIT_NULL;
2690 	ipc_importance_elem_t   from_elem = kmsg->ikm_importance;
2691 	ipc_importance_elem_t   elem;
2692 	task_t  task_self = current_task();
2693 
2694 	ipc_port_t port = kmsg->ikm_header->msgh_remote_port;
2695 	ipc_importance_inherit_t inherit = III_NULL;
2696 	ipc_importance_inherit_t alloc = III_NULL;
2697 	boolean_t cleared_self_donation = FALSE;
2698 	boolean_t donating;
2699 	uint32_t depth = 1;
2700 
2701 	/* The kmsg must have an importance donor or static boost to proceed */
2702 	if (IIE_NULL == kmsg->ikm_importance &&
2703 	    !MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits)) {
2704 		return III_NULL;
2705 	}
2706 
2707 	/*
2708 	 * No need to set up an inherit linkage if the dest isn't a receiver
2709 	 * of one type or the other.
2710 	 */
2711 	if (!ipc_importance_task_is_any_receiver_type(task_self->task_imp_base)) {
2712 		ipc_importance_lock();
2713 		goto out_locked;
2714 	}
2715 
2716 	/* Grab a reference on the importance of the destination */
2717 	task_imp = ipc_importance_for_task(task_self, FALSE);
2718 
2719 	ipc_importance_lock();
2720 
2721 	if (IIT_NULL == task_imp) {
2722 		goto out_locked;
2723 	}
2724 
2725 	incr_ref_counter(task_imp->iit_elem.iie_task_refs_added_inherit_from);
2726 
2727 	/* If message is already associated with an inherit... */
2728 	if (IIE_TYPE_INHERIT == IIE_TYPE(from_elem)) {
2729 		ipc_importance_inherit_t from_inherit = (ipc_importance_inherit_t)from_elem;
2730 
2731 		/* already targeting our task? - just use it */
2732 		if (from_inherit->iii_to_task == task_imp) {
2733 			/* clear self-donation if not also present in inherit */
2734 			if (!from_inherit->iii_donating &&
2735 			    MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits)) {
2736 				kmsg->ikm_header->msgh_bits &= ~MACH_MSGH_BITS_RAISEIMP;
2737 				cleared_self_donation = TRUE;
2738 			}
2739 			inherit = from_inherit;
2740 		} else if (III_DEPTH_MAX == III_DEPTH(from_inherit)) {
2741 			ipc_importance_task_t to_task;
2742 			ipc_importance_elem_t unlinked_from;
2743 
2744 			/*
2745 			 * Chain too long. Switch to looking
2746 			 * directly at the from_inherit's to-task
2747 			 * as our source of importance.
2748 			 */
2749 			to_task = from_inherit->iii_to_task;
2750 			ipc_importance_task_reference(to_task);
2751 			from_elem = (ipc_importance_elem_t)to_task;
2752 			depth = III_DEPTH_RESET | 1;
2753 
2754 			/* Fixup the kmsg linkage to reflect change */
2755 			unlinked_from = ipc_importance_kmsg_unlink(kmsg);
2756 			assert(unlinked_from == (ipc_importance_elem_t)from_inherit);
2757 			ipc_importance_kmsg_link(kmsg, from_elem);
2758 			ipc_importance_inherit_release_locked(from_inherit);
2759 			/* importance unlocked */
2760 			ipc_importance_lock();
2761 		} else {
2762 			/* inheriting from an inherit */
2763 			depth = from_inherit->iii_depth + 1;
2764 		}
2765 	}
2766 
2767 	/*
2768 	 * Don't allow a task to inherit from itself (would keep it permanently
2769 	 * boosted even if all other donors to the task went away).
2770 	 */
2771 
2772 	if (from_elem == (ipc_importance_elem_t)task_imp) {
2773 		goto out_locked;
2774 	}
2775 
2776 	/*
2777 	 * But if the message isn't associated with any linked source, it is
2778 	 * intended to be permanently boosting (static boost from kernel).
2779 	 * In that case DO let the process permanently boost itself.
2780 	 */
2781 	if (IIE_NULL == from_elem) {
2782 		assert(MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits));
2783 		ipc_importance_task_reference_internal(task_imp);
2784 		from_elem = (ipc_importance_elem_t)task_imp;
2785 	}
2786 
2787 	/*
2788 	 * Now that we have the from_elem figured out,
2789 	 * check to see if we already have an inherit for this pairing
2790 	 */
2791 	while (III_NULL == inherit) {
2792 		inherit = ipc_importance_inherit_find(from_elem, task_imp, depth);
2793 
2794 		/* Do we have to allocate a new inherit */
2795 		if (III_NULL == inherit) {
2796 			if (III_NULL != alloc) {
2797 				break;
2798 			}
2799 
2800 			/* allocate space */
2801 			ipc_importance_unlock();
2802 			alloc = (ipc_importance_inherit_t)
2803 			    zalloc(ipc_importance_inherit_zone);
2804 			ipc_importance_lock();
2805 		}
2806 	}
2807 
2808 	/* snapshot the donating status while we have importance locked */
2809 	donating = MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits);
2810 
2811 	if (III_NULL != inherit) {
2812 		/* We found one, piggyback on that */
2813 		assert(0 < III_REFS(inherit));
2814 		assert(0 < IIE_REFS(inherit->iii_from_elem));
2815 		assert(inherit->iii_externcnt >= inherit->iii_made);
2816 
2817 		/* add in a made reference */
2818 		if (0 == inherit->iii_made++) {
2819 			assert(III_REFS_MAX > III_REFS(inherit));
2820 			ipc_importance_inherit_reference_internal(inherit);
2821 		}
2822 
2823 		/* Reflect the inherit's change of status into the task boosts */
2824 		if (0 == III_EXTERN(inherit)) {
2825 			assert(!inherit->iii_donating);
2826 			inherit->iii_donating = donating;
2827 			if (donating) {
2828 				task_imp->iit_externcnt += inherit->iii_externcnt;
2829 				task_imp->iit_externdrop += inherit->iii_externdrop;
2830 			}
2831 		} else {
2832 			assert(donating == inherit->iii_donating);
2833 		}
2834 
2835 		/* add in a external reference for this use of the inherit */
2836 		inherit->iii_externcnt++;
2837 	} else {
2838 		/* initialize the previously allocated space */
2839 		inherit = alloc;
2840 		inherit->iii_bits = IIE_TYPE_INHERIT | 1;
2841 		inherit->iii_made = 1;
2842 		inherit->iii_externcnt = 1;
2843 		inherit->iii_externdrop = 0;
2844 		inherit->iii_depth = depth;
2845 		inherit->iii_to_task = task_imp;
2846 		inherit->iii_from_elem = IIE_NULL;
2847 		queue_init(&inherit->iii_kmsgs);
2848 
2849 		if (donating) {
2850 			inherit->iii_donating = TRUE;
2851 		} else {
2852 			inherit->iii_donating = FALSE;
2853 		}
2854 
2855 		/*
2856 		 * Chain our new inherit on the element it inherits from.
2857 		 * The new inherit takes our reference on from_elem.
2858 		 */
2859 		ipc_importance_inherit_link(inherit, from_elem);
2860 
2861 #if IIE_REF_DEBUG
2862 		ipc_importance_counter_init(&inherit->iii_elem);
2863 		from_elem->iie_kmsg_refs_inherited++;
2864 		task_imp->iit_elem.iie_task_refs_inherited++;
2865 #endif
2866 	}
2867 
2868 out_locked:
2869 	/*
2870 	 * for those paths that came straight here: snapshot the donating status
2871 	 * (this should match previous snapshot for other paths).
2872 	 */
2873 	donating = MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits);
2874 
2875 	/* unlink the kmsg inheritance (if any) */
2876 	elem = ipc_importance_kmsg_unlink(kmsg);
2877 	assert(elem == from_elem);
2878 
2879 	/* If found inherit and donating, reflect that in the task externcnt */
2880 	if (III_NULL != inherit && donating) {
2881 		task_imp->iit_externcnt++;
2882 		/* The owner of receive right might have changed, take the internal assertion */
2883 		ipc_importance_task_hold_internal_assertion_locked(task_imp, 1);
2884 		/* may have dropped and retaken importance lock */
2885 	}
2886 
2887 	/* If we didn't create a new inherit, we have some resources to release */
2888 	if (III_NULL == inherit || inherit != alloc) {
2889 		if (IIE_NULL != from_elem) {
2890 			if (III_NULL != inherit) {
2891 				incr_ref_counter(from_elem->iie_kmsg_refs_coalesced);
2892 			} else {
2893 				incr_ref_counter(from_elem->iie_kmsg_refs_dropped);
2894 			}
2895 			ipc_importance_release_locked(from_elem);
2896 			/* importance unlocked */
2897 		} else {
2898 			ipc_importance_unlock();
2899 		}
2900 
2901 		if (IIT_NULL != task_imp) {
2902 			if (III_NULL != inherit) {
2903 				incr_ref_counter(task_imp->iit_elem.iie_task_refs_coalesced);
2904 			}
2905 			ipc_importance_task_release(task_imp);
2906 		}
2907 
2908 		if (III_NULL != alloc) {
2909 			zfree(ipc_importance_inherit_zone, alloc);
2910 		}
2911 	} else {
2912 		/* from_elem and task_imp references transferred to new inherit */
2913 		ipc_importance_unlock();
2914 	}
2915 
2916 	/*
2917 	 * decrement port boost count
2918 	 * This is OK to do without the importance lock as we atomically
2919 	 * unlinked the kmsg and snapshot the donating state while holding
2920 	 * the importance lock
2921 	 */
2922 	if (donating || cleared_self_donation) {
2923 		ip_mq_lock(port);
2924 		/* drop importance from port and destination task */
2925 		if (ipc_port_importance_delta(port, IPID_OPTION_NORMAL, -1) == FALSE) {
2926 			ip_mq_unlock(port);
2927 		}
2928 	}
2929 
2930 	if (III_NULL != inherit) {
2931 		/* have an associated importance attr, even if currently not donating */
2932 		kmsg->ikm_header->msgh_bits |= MACH_MSGH_BITS_RAISEIMP;
2933 	} else {
2934 		/* we won't have an importance attribute associated with our message */
2935 		kmsg->ikm_header->msgh_bits &= ~MACH_MSGH_BITS_RAISEIMP;
2936 	}
2937 
2938 	return inherit;
2939 }
2940 
2941 /*
2942  *	Routine:	ipc_importance_inherit_from_task
2943  *	Purpose:
2944  *		Create a reference for an importance attribute representing
2945  *		an inheritance between the to_task and from_task. The iii
2946  *		created will be marked as III_FLAGS_FOR_OTHERS.
2947  *
2948  *		It will not dedup any iii which are not marked as III_FLAGS_FOR_OTHERS.
2949  *
2950  *		If the task is inactive, there isn't any need to return a new reference.
2951  *	Conditions:
2952  *		Nothing locked on entry.  May block.
2953  *		It should not be called from voucher subsystem.
2954  */
2955 static ipc_importance_inherit_t
ipc_importance_inherit_from_task(task_t from_task,task_t to_task)2956 ipc_importance_inherit_from_task(
2957 	task_t from_task,
2958 	task_t to_task)
2959 {
2960 	ipc_importance_task_t   to_task_imp = IIT_NULL;
2961 	ipc_importance_task_t   from_task_imp = IIT_NULL;
2962 	ipc_importance_elem_t   from_elem = IIE_NULL;
2963 
2964 	ipc_importance_inherit_t inherit = III_NULL;
2965 	ipc_importance_inherit_t alloc = III_NULL;
2966 	boolean_t donating;
2967 	uint32_t depth = 1;
2968 
2969 	to_task_imp = ipc_importance_for_task(to_task, FALSE);
2970 	from_task_imp = ipc_importance_for_task(from_task, FALSE);
2971 	from_elem = (ipc_importance_elem_t)from_task_imp;
2972 
2973 	ipc_importance_lock();
2974 
2975 	if (IIT_NULL == to_task_imp || IIT_NULL == from_task_imp) {
2976 		goto out_locked;
2977 	}
2978 
2979 	/*
2980 	 * No need to set up an inherit linkage if the to_task or from_task
2981 	 * isn't a receiver of one type or the other.
2982 	 */
2983 	if (!ipc_importance_task_is_any_receiver_type(to_task_imp) ||
2984 	    !ipc_importance_task_is_any_receiver_type(from_task_imp)) {
2985 		goto out_locked;
2986 	}
2987 
2988 	/* Do not allow to create a linkage to self */
2989 	if (to_task_imp == from_task_imp) {
2990 		goto out_locked;
2991 	}
2992 
2993 	incr_ref_counter(to_task_imp->iit_elem.iie_task_refs_added_inherit_from);
2994 	incr_ref_counter(from_elem->iie_kmsg_refs_added);
2995 
2996 	/*
2997 	 * Now that we have the from_elem figured out,
2998 	 * check to see if we already have an inherit for this pairing
2999 	 */
3000 	while (III_NULL == inherit) {
3001 		inherit = ipc_importance_inherit_find(from_elem, to_task_imp, depth);
3002 
3003 		/* Do we have to allocate a new inherit */
3004 		if (III_NULL == inherit) {
3005 			if (III_NULL != alloc) {
3006 				break;
3007 			}
3008 
3009 			/* allocate space */
3010 			ipc_importance_unlock();
3011 			alloc = (ipc_importance_inherit_t)
3012 			    zalloc(ipc_importance_inherit_zone);
3013 			ipc_importance_lock();
3014 		}
3015 	}
3016 
3017 	/* snapshot the donating status while we have importance locked */
3018 	donating = ipc_importance_task_is_donor(from_task_imp);
3019 
3020 	if (III_NULL != inherit) {
3021 		/* We found one, piggyback on that */
3022 		assert(0 < III_REFS(inherit));
3023 		assert(0 < IIE_REFS(inherit->iii_from_elem));
3024 
3025 		/* Take a reference for inherit */
3026 		assert(III_REFS_MAX > III_REFS(inherit));
3027 		ipc_importance_inherit_reference_internal(inherit);
3028 
3029 		/* Reflect the inherit's change of status into the task boosts */
3030 		if (0 == III_EXTERN(inherit)) {
3031 			assert(!inherit->iii_donating);
3032 			inherit->iii_donating = donating;
3033 			if (donating) {
3034 				to_task_imp->iit_externcnt += inherit->iii_externcnt;
3035 				to_task_imp->iit_externdrop += inherit->iii_externdrop;
3036 			}
3037 		} else {
3038 			assert(donating == inherit->iii_donating);
3039 		}
3040 
3041 		/* add in a external reference for this use of the inherit */
3042 		inherit->iii_externcnt++;
3043 	} else {
3044 		/* initialize the previously allocated space */
3045 		inherit = alloc;
3046 		inherit->iii_bits = IIE_TYPE_INHERIT | 1;
3047 		inherit->iii_made = 0;
3048 		inherit->iii_externcnt = 1;
3049 		inherit->iii_externdrop = 0;
3050 		inherit->iii_depth = depth;
3051 		inherit->iii_to_task = to_task_imp;
3052 		inherit->iii_from_elem = IIE_NULL;
3053 		queue_init(&inherit->iii_kmsgs);
3054 
3055 		if (donating) {
3056 			inherit->iii_donating = TRUE;
3057 		} else {
3058 			inherit->iii_donating = FALSE;
3059 		}
3060 
3061 		/*
3062 		 * Chain our new inherit on the element it inherits from.
3063 		 * The new inherit takes our reference on from_elem.
3064 		 */
3065 		ipc_importance_inherit_link(inherit, from_elem);
3066 
3067 #if IIE_REF_DEBUG
3068 		ipc_importance_counter_init(&inherit->iii_elem);
3069 		from_elem->iie_kmsg_refs_inherited++;
3070 		task_imp->iit_elem.iie_task_refs_inherited++;
3071 #endif
3072 	}
3073 
3074 out_locked:
3075 
3076 	/* If found inherit and donating, reflect that in the task externcnt */
3077 	if (III_NULL != inherit && donating) {
3078 		to_task_imp->iit_externcnt++;
3079 		/* take the internal assertion */
3080 		ipc_importance_task_hold_internal_assertion_locked(to_task_imp, 1);
3081 		/* may have dropped and retaken importance lock */
3082 	}
3083 
3084 	/* If we didn't create a new inherit, we have some resources to release */
3085 	if (III_NULL == inherit || inherit != alloc) {
3086 		if (IIE_NULL != from_elem) {
3087 			if (III_NULL != inherit) {
3088 				incr_ref_counter(from_elem->iie_kmsg_refs_coalesced);
3089 			} else {
3090 				incr_ref_counter(from_elem->iie_kmsg_refs_dropped);
3091 			}
3092 			ipc_importance_release_locked(from_elem);
3093 			/* importance unlocked */
3094 		} else {
3095 			ipc_importance_unlock();
3096 		}
3097 
3098 		if (IIT_NULL != to_task_imp) {
3099 			if (III_NULL != inherit) {
3100 				incr_ref_counter(to_task_imp->iit_elem.iie_task_refs_coalesced);
3101 			}
3102 			ipc_importance_task_release(to_task_imp);
3103 		}
3104 
3105 		if (III_NULL != alloc) {
3106 			zfree(ipc_importance_inherit_zone, alloc);
3107 		}
3108 	} else {
3109 		/* from_elem and to_task_imp references transferred to new inherit */
3110 		ipc_importance_unlock();
3111 	}
3112 
3113 	return inherit;
3114 }
3115 
3116 /*
3117  *	Routine:	ipc_importance_receive
3118  *	Purpose:
3119  *		Process importance attributes in a received message.
3120  *
3121  *		If an importance voucher attribute was sent, transform
3122  *		that into an attribute value reflecting the inheritance
3123  *		from the sender to the receiver.
3124  *
3125  *		If a static boost is received (or the voucher isn't on
3126  *		a voucher-based boost), export a static boost.
3127  *	Conditions:
3128  *		Nothing locked.
3129  */
3130 void
ipc_importance_receive(ipc_kmsg_t kmsg,mach_msg_option_t option)3131 ipc_importance_receive(
3132 	ipc_kmsg_t              kmsg,
3133 	mach_msg_option_t       option)
3134 {
3135 	int impresult = -1;
3136 
3137 #if IMPORTANCE_TRACE || LEGACY_IMPORTANCE_DELIVERY
3138 	task_t task_self = current_task();
3139 	unsigned int sender_pid = ((mach_msg_max_trailer_t *)
3140 	    ((vm_offset_t)kmsg->ikm_header +
3141 	    mach_round_msg(kmsg->ikm_header->msgh_size)))->msgh_audit.val[5];
3142 #endif
3143 
3144 	/* convert to a voucher with an inherit importance attribute? */
3145 	if ((option & MACH_RCV_VOUCHER) != 0) {
3146 		uint8_t recipes[2 * sizeof(ipc_voucher_attr_recipe_data_t) +
3147 		sizeof(mach_voucher_attr_value_handle_t)];
3148 		ipc_voucher_attr_raw_recipe_array_size_t recipe_size = 0;
3149 		ipc_voucher_attr_recipe_t recipe = (ipc_voucher_attr_recipe_t)recipes;
3150 		ipc_port_t voucher_port = ipc_kmsg_get_voucher_port(kmsg);
3151 		ipc_voucher_t recv_voucher;
3152 		mach_voucher_attr_value_handle_t handle;
3153 		ipc_importance_inherit_t inherit;
3154 		kern_return_t kr;
3155 
3156 		/* set up recipe to copy the old voucher */
3157 		if (IP_VALID(voucher_port)) {
3158 			ipc_voucher_t sent_voucher;
3159 
3160 			sent_voucher = (ipc_voucher_t)ipc_kobject_get_raw(voucher_port,
3161 			    IKOT_VOUCHER);
3162 
3163 			recipe->key = MACH_VOUCHER_ATTR_KEY_ALL;
3164 			recipe->command = MACH_VOUCHER_ATTR_COPY;
3165 			recipe->previous_voucher = sent_voucher;
3166 			recipe->content_size = 0;
3167 			recipe_size += sizeof(*recipe);
3168 		}
3169 
3170 		/*
3171 		 * create an inheritance attribute from the kmsg (may be NULL)
3172 		 * transferring any boosts from the kmsg linkage through the
3173 		 * port directly to the new inheritance object.
3174 		 */
3175 		inherit = ipc_importance_inherit_from_kmsg(kmsg);
3176 		handle = (mach_voucher_attr_value_handle_t)inherit;
3177 
3178 		assert(IIE_NULL == kmsg->ikm_importance);
3179 
3180 		/*
3181 		 * Only create a new voucher if we have an inherit object
3182 		 * (from the ikm_importance field of the incoming message), OR
3183 		 * we have a valid incoming voucher. If we have neither of
3184 		 * these things then there is no need to create a new voucher.
3185 		 */
3186 		if (IP_VALID(voucher_port) || inherit != III_NULL) {
3187 			/* replace the importance attribute with the handle we created */
3188 			/*  our made reference on the inherit is donated to the voucher */
3189 			recipe = (ipc_voucher_attr_recipe_t)&recipes[recipe_size];
3190 			recipe->key = MACH_VOUCHER_ATTR_KEY_IMPORTANCE;
3191 			recipe->command = MACH_VOUCHER_ATTR_SET_VALUE_HANDLE;
3192 			recipe->previous_voucher = IPC_VOUCHER_NULL;
3193 			recipe->content_size = sizeof(mach_voucher_attr_value_handle_t);
3194 			*(mach_voucher_attr_value_handle_t *)(void *)recipe->content = handle;
3195 			recipe_size += sizeof(*recipe) + sizeof(mach_voucher_attr_value_handle_t);
3196 
3197 			kr = ipc_voucher_attr_control_create_mach_voucher(ipc_importance_control,
3198 			    recipes,
3199 			    recipe_size,
3200 			    &recv_voucher);
3201 			assert(KERN_SUCCESS == kr);
3202 
3203 			/* swap the voucher port (and set voucher bits in case it didn't already exist) */
3204 			kmsg->ikm_header->msgh_bits |= (MACH_MSG_TYPE_MOVE_SEND << 16);
3205 			ipc_port_release_send(voucher_port);
3206 			voucher_port = convert_voucher_to_port(recv_voucher);
3207 			ipc_kmsg_set_voucher_port(kmsg, voucher_port, MACH_MSG_TYPE_MOVE_SEND);
3208 			if (III_NULL != inherit) {
3209 				impresult = 2;
3210 			}
3211 		}
3212 	} else { /* Don't want a voucher */
3213 		/* got linked importance? have to drop */
3214 		if (IIE_NULL != kmsg->ikm_importance) {
3215 			ipc_importance_elem_t elem;
3216 
3217 			ipc_importance_lock();
3218 			elem = ipc_importance_kmsg_unlink(kmsg);
3219 #if IIE_REF_DEBUG
3220 			elem->iie_kmsg_refs_dropped++;
3221 #endif
3222 			ipc_importance_release_locked(elem);
3223 			/* importance unlocked */
3224 		}
3225 
3226 		/* With kmsg unlinked, can safely examine message importance attribute. */
3227 		if (MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits)) {
3228 			ipc_port_t port = kmsg->ikm_header->msgh_remote_port;
3229 #if LEGACY_IMPORTANCE_DELIVERY
3230 			ipc_importance_task_t task_imp = task_self->task_imp_base;
3231 
3232 			/* The owner of receive right might have changed, take the internal assertion */
3233 			if (KERN_SUCCESS == ipc_importance_task_hold_internal_assertion(task_imp, 1)) {
3234 				ipc_importance_task_externalize_legacy_assertion(task_imp, 1, sender_pid);
3235 				impresult = 1;
3236 			} else
3237 #endif
3238 			{
3239 				/* The importance boost never applied to task (clear the bit) */
3240 				kmsg->ikm_header->msgh_bits &= ~MACH_MSGH_BITS_RAISEIMP;
3241 				impresult = 0;
3242 			}
3243 
3244 			/* Drop the boost on the port and the owner of the receive right */
3245 			ip_mq_lock(port);
3246 			if (ipc_port_importance_delta(port, IPID_OPTION_NORMAL, -1) == FALSE) {
3247 				ip_mq_unlock(port);
3248 			}
3249 		}
3250 	}
3251 
3252 #if IMPORTANCE_TRACE
3253 	if (-1 < impresult) {
3254 		KERNEL_DEBUG_CONSTANT_IST(KDEBUG_TRACE, (IMPORTANCE_CODE(IMP_MSG, IMP_MSG_DELV)) | DBG_FUNC_NONE,
3255 		    sender_pid, task_pid(task_self),
3256 		    kmsg->ikm_header->msgh_id, impresult, 0);
3257 	}
3258 	if (impresult == 2) {
3259 		/*
3260 		 * This probe only covers new voucher-based path.  Legacy importance
3261 		 * will trigger the probe in ipc_importance_task_externalize_assertion()
3262 		 * above and have impresult==1 here.
3263 		 */
3264 		DTRACE_BOOST5(receive_boost, task_t, task_self, int, task_pid(task_self),
3265 		    int, sender_pid, int, 1, int, task_self->task_imp_base->iit_assertcnt);
3266 	}
3267 #endif /* IMPORTANCE_TRACE */
3268 }
3269 
3270 /*
3271  *	Routine:	ipc_importance_unreceive
3272  *	Purpose:
3273  *		Undo receive of importance attributes in a message.
3274  *
3275  *	Conditions:
3276  *		Nothing locked.
3277  */
3278 void
ipc_importance_unreceive(ipc_kmsg_t kmsg,mach_msg_option_t __unused option)3279 ipc_importance_unreceive(
3280 	ipc_kmsg_t              kmsg,
3281 	mach_msg_option_t       __unused option)
3282 {
3283 	/* importance should already be in the voucher and out of the kmsg */
3284 	assert(IIE_NULL == kmsg->ikm_importance);
3285 
3286 	/* See if there is a legacy boost to be dropped from receiver */
3287 	if (MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits)) {
3288 		ipc_importance_task_t task_imp;
3289 
3290 		kmsg->ikm_header->msgh_bits &= ~MACH_MSGH_BITS_RAISEIMP;
3291 		task_imp = current_task()->task_imp_base;
3292 
3293 		if (!IP_VALID(ipc_kmsg_get_voucher_port(kmsg)) && IIT_NULL != task_imp) {
3294 			ipc_importance_task_drop_legacy_external_assertion(task_imp, 1);
3295 		}
3296 		/*
3297 		 * ipc_kmsg_copyout_dest_to_user() will consume the voucher
3298 		 * and any contained importance.
3299 		 */
3300 	}
3301 }
3302 
3303 /*
3304  *	Routine:	ipc_importance_clean
3305  *	Purpose:
3306  *		Clean up importance state in a kmsg that is being cleaned.
3307  *		Unlink the importance chain if one was set up, and drop
3308  *		the reference this kmsg held on the donor.  Then check to
3309  *		if importance was carried to the port, and remove that if
3310  *		needed.
3311  *	Conditions:
3312  *		Nothing locked.
3313  */
3314 void
ipc_importance_clean(ipc_kmsg_t kmsg)3315 ipc_importance_clean(
3316 	ipc_kmsg_t              kmsg)
3317 {
3318 	ipc_port_t              port;
3319 
3320 	/* Is the kmsg still linked? If so, remove that first */
3321 	if (IIE_NULL != kmsg->ikm_importance) {
3322 		ipc_importance_elem_t   elem;
3323 
3324 		ipc_importance_lock();
3325 		elem = ipc_importance_kmsg_unlink(kmsg);
3326 		assert(IIE_NULL != elem);
3327 		ipc_importance_release_locked(elem);
3328 		/* importance unlocked */
3329 	}
3330 
3331 	/* See if there is a legacy importance boost to be dropped from port */
3332 	if (MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits)) {
3333 		kmsg->ikm_header->msgh_bits &= ~MACH_MSGH_BITS_RAISEIMP;
3334 		port = kmsg->ikm_header->msgh_remote_port;
3335 		if (IP_VALID(port)) {
3336 			ip_mq_lock(port);
3337 			/* inactive ports already had their importance boosts dropped */
3338 			if (!ip_active(port) ||
3339 			    ipc_port_importance_delta(port, IPID_OPTION_NORMAL, -1) == FALSE) {
3340 				ip_mq_unlock(port);
3341 			}
3342 		}
3343 	}
3344 }
3345 
3346 void
ipc_importance_assert_clean(__assert_only ipc_kmsg_t kmsg)3347 ipc_importance_assert_clean(__assert_only ipc_kmsg_t kmsg)
3348 {
3349 	assert(IIE_NULL == kmsg->ikm_importance);
3350 	assert(!MACH_MSGH_BITS_RAISED_IMPORTANCE(kmsg->ikm_header->msgh_bits));
3351 }
3352 
3353 /*
3354  * IPC Importance Attribute Manager definition
3355  */
3356 
3357 static kern_return_t
3358 ipc_importance_release_value(
3359 	ipc_voucher_attr_manager_t              manager,
3360 	mach_voucher_attr_key_t                 key,
3361 	mach_voucher_attr_value_handle_t        value,
3362 	mach_voucher_attr_value_reference_t     sync);
3363 
3364 static kern_return_t
3365 ipc_importance_get_value(
3366 	ipc_voucher_attr_manager_t                      manager,
3367 	mach_voucher_attr_key_t                         key,
3368 	mach_voucher_attr_recipe_command_t              command,
3369 	mach_voucher_attr_value_handle_array_t          prev_values,
3370 	mach_voucher_attr_value_handle_array_size_t     prev_value_count,
3371 	mach_voucher_attr_content_t                     content,
3372 	mach_voucher_attr_content_size_t                content_size,
3373 	mach_voucher_attr_value_handle_t                *out_value,
3374 	mach_voucher_attr_value_flags_t                 *out_flags,
3375 	ipc_voucher_t                                   *out_value_voucher);
3376 
3377 static kern_return_t
3378 ipc_importance_extract_content(
3379 	ipc_voucher_attr_manager_t                      manager,
3380 	mach_voucher_attr_key_t                         key,
3381 	mach_voucher_attr_value_handle_array_t          values,
3382 	mach_voucher_attr_value_handle_array_size_t     value_count,
3383 	mach_voucher_attr_recipe_command_t              *out_command,
3384 	mach_voucher_attr_content_t                     out_content,
3385 	mach_voucher_attr_content_size_t                *in_out_content_size);
3386 
3387 static kern_return_t
3388 ipc_importance_command(
3389 	ipc_voucher_attr_manager_t                      manager,
3390 	mach_voucher_attr_key_t                         key,
3391 	mach_voucher_attr_value_handle_array_t          values,
3392 	mach_msg_type_number_t                          value_count,
3393 	mach_voucher_attr_command_t                     command,
3394 	mach_voucher_attr_content_t                     in_content,
3395 	mach_voucher_attr_content_size_t                in_content_size,
3396 	mach_voucher_attr_content_t                     out_content,
3397 	mach_voucher_attr_content_size_t                *out_content_size);
3398 
3399 static void
3400 ipc_importance_manager_release(
3401 	ipc_voucher_attr_manager_t              manager);
3402 
3403 const struct ipc_voucher_attr_manager ipc_importance_manager = {
3404 	.ivam_release_value =   ipc_importance_release_value,
3405 	.ivam_get_value =       ipc_importance_get_value,
3406 	.ivam_extract_content = ipc_importance_extract_content,
3407 	.ivam_command =         ipc_importance_command,
3408 	.ivam_release =         ipc_importance_manager_release,
3409 	.ivam_flags =           IVAM_FLAGS_NONE,
3410 };
3411 
3412 #define IMPORTANCE_ASSERT_KEY(key) assert(MACH_VOUCHER_ATTR_KEY_IMPORTANCE == (key))
3413 #define IMPORTANCE_ASSERT_MANAGER(manager) assert(&ipc_importance_manager == (manager))
3414 
3415 /*
3416  *	Routine:	ipc_importance_release_value [Voucher Attribute Manager Interface]
3417  *	Purpose:
3418  *		Release what the voucher system believes is the last "made" reference
3419  *		on an importance attribute value handle.  The sync parameter is used to
3420  *		avoid races with new made references concurrently being returned to the
3421  *		voucher system in other threads.
3422  *	Conditions:
3423  *		Nothing locked on entry.  May block.
3424  */
3425 static kern_return_t
ipc_importance_release_value(ipc_voucher_attr_manager_t __assert_only manager,mach_voucher_attr_key_t __assert_only key,mach_voucher_attr_value_handle_t value,mach_voucher_attr_value_reference_t sync)3426 ipc_importance_release_value(
3427 	ipc_voucher_attr_manager_t              __assert_only manager,
3428 	mach_voucher_attr_key_t                 __assert_only key,
3429 	mach_voucher_attr_value_handle_t        value,
3430 	mach_voucher_attr_value_reference_t     sync)
3431 {
3432 	ipc_importance_elem_t elem;
3433 
3434 	IMPORTANCE_ASSERT_MANAGER(manager);
3435 	IMPORTANCE_ASSERT_KEY(key);
3436 	assert(0 < sync);
3437 
3438 	elem = (ipc_importance_elem_t)value;
3439 
3440 	ipc_importance_lock();
3441 
3442 	/* Any oustanding made refs? */
3443 	if (sync != elem->iie_made) {
3444 		assert(sync < elem->iie_made);
3445 		ipc_importance_unlock();
3446 		return KERN_FAILURE;
3447 	}
3448 
3449 	/* clear made */
3450 	elem->iie_made = 0;
3451 
3452 	/*
3453 	 * If there are pending external boosts represented by this attribute,
3454 	 * drop them from the apropriate task
3455 	 */
3456 	if (IIE_TYPE_INHERIT == IIE_TYPE(elem)) {
3457 		ipc_importance_inherit_t inherit = (ipc_importance_inherit_t)elem;
3458 
3459 		assert(inherit->iii_externcnt >= inherit->iii_externdrop);
3460 
3461 		if (inherit->iii_donating) {
3462 			ipc_importance_task_t imp_task = inherit->iii_to_task;
3463 			uint32_t assertcnt = III_EXTERN(inherit);
3464 
3465 			assert(ipc_importance_task_is_any_receiver_type(imp_task));
3466 			assert(imp_task->iit_externcnt >= inherit->iii_externcnt);
3467 			assert(imp_task->iit_externdrop >= inherit->iii_externdrop);
3468 			imp_task->iit_externcnt -= inherit->iii_externcnt;
3469 			imp_task->iit_externdrop -= inherit->iii_externdrop;
3470 			inherit->iii_externcnt = 0;
3471 			inherit->iii_externdrop = 0;
3472 			inherit->iii_donating = FALSE;
3473 
3474 			/* adjust the internal assertions - and propagate if needed */
3475 			if (ipc_importance_task_check_transition(imp_task, IIT_UPDATE_DROP, assertcnt)) {
3476 				ipc_importance_task_propagate_assertion_locked(imp_task, IIT_UPDATE_DROP, TRUE);
3477 			}
3478 		} else {
3479 			inherit->iii_externcnt = 0;
3480 			inherit->iii_externdrop = 0;
3481 		}
3482 	}
3483 
3484 	/* drop the made reference on elem */
3485 	ipc_importance_release_locked(elem);
3486 	/* returns unlocked */
3487 
3488 	return KERN_SUCCESS;
3489 }
3490 
3491 
3492 /*
3493  *	Routine:	ipc_importance_get_value [Voucher Attribute Manager Interface]
3494  *	Purpose:
3495  *		Convert command and content data into a reference on a [potentially new]
3496  *		attribute value.  The importance attribute manager will only allow the
3497  *		caller to get a value for the current task's importance, or to redeem
3498  *		an importance attribute from an existing voucher.
3499  *	Conditions:
3500  *		Nothing locked on entry.  May block.
3501  */
3502 static kern_return_t
ipc_importance_get_value(ipc_voucher_attr_manager_t __assert_only manager,mach_voucher_attr_key_t __assert_only key,mach_voucher_attr_recipe_command_t command,mach_voucher_attr_value_handle_array_t prev_values,mach_voucher_attr_value_handle_array_size_t prev_value_count,mach_voucher_attr_content_t __unused content,mach_voucher_attr_content_size_t content_size,mach_voucher_attr_value_handle_t * out_value,mach_voucher_attr_value_flags_t * out_flags,ipc_voucher_t * out_value_voucher)3503 ipc_importance_get_value(
3504 	ipc_voucher_attr_manager_t                      __assert_only manager,
3505 	mach_voucher_attr_key_t                         __assert_only key,
3506 	mach_voucher_attr_recipe_command_t              command,
3507 	mach_voucher_attr_value_handle_array_t          prev_values,
3508 	mach_voucher_attr_value_handle_array_size_t     prev_value_count,
3509 	mach_voucher_attr_content_t                     __unused content,
3510 	mach_voucher_attr_content_size_t                content_size,
3511 	mach_voucher_attr_value_handle_t                *out_value,
3512 	mach_voucher_attr_value_flags_t                 *out_flags,
3513 	ipc_voucher_t                                   *out_value_voucher)
3514 {
3515 	ipc_importance_elem_t elem;
3516 	task_t self;
3517 
3518 	IMPORTANCE_ASSERT_MANAGER(manager);
3519 	IMPORTANCE_ASSERT_KEY(key);
3520 
3521 	if (0 != content_size) {
3522 		return KERN_INVALID_ARGUMENT;
3523 	}
3524 
3525 	*out_flags = MACH_VOUCHER_ATTR_VALUE_FLAGS_NONE;
3526 	/* never an out voucher */
3527 
3528 	switch (command) {
3529 	case MACH_VOUCHER_ATTR_REDEEM:
3530 
3531 		/* redeem of previous values is the value */
3532 		if (0 < prev_value_count) {
3533 			elem = (ipc_importance_elem_t)prev_values[0];
3534 			assert(IIE_NULL != elem);
3535 
3536 			ipc_importance_lock();
3537 			assert(0 < elem->iie_made);
3538 			elem->iie_made++;
3539 			ipc_importance_unlock();
3540 
3541 			*out_value = prev_values[0];
3542 			return KERN_SUCCESS;
3543 		}
3544 
3545 		/* redeem of default is default */
3546 		*out_value = 0;
3547 		*out_value_voucher = IPC_VOUCHER_NULL;
3548 		return KERN_SUCCESS;
3549 
3550 	case MACH_VOUCHER_ATTR_IMPORTANCE_SELF:
3551 		self = current_task();
3552 
3553 		elem = (ipc_importance_elem_t)ipc_importance_for_task(self, TRUE);
3554 		/* made reference added (or IIE_NULL which isn't referenced) */
3555 
3556 		*out_value = (mach_voucher_attr_value_handle_t)elem;
3557 		*out_value_voucher = IPC_VOUCHER_NULL;
3558 		return KERN_SUCCESS;
3559 
3560 	default:
3561 		/*
3562 		 * every other command is unknown
3563 		 *
3564 		 * Specifically, there is no mechanism provided to construct an
3565 		 * importance attribute for a task/process from just a pid or
3566 		 * task port.  It has to be copied (or redeemed) from a previous
3567 		 * voucher that has it.
3568 		 */
3569 		return KERN_INVALID_ARGUMENT;
3570 	}
3571 }
3572 
3573 /*
3574  *	Routine:	ipc_importance_extract_content [Voucher Attribute Manager Interface]
3575  *	Purpose:
3576  *		Extract meaning from the attribute value present in a voucher.  While
3577  *		the real goal is to provide commands and data that can reproduce the
3578  *		voucher's value "out of thin air", this isn't possible with importance
3579  *		attribute values.  Instead, return debug info to help track down dependencies.
3580  *	Conditions:
3581  *		Nothing locked on entry.  May block.
3582  */
3583 static kern_return_t
ipc_importance_extract_content(ipc_voucher_attr_manager_t __assert_only manager,mach_voucher_attr_key_t __assert_only key,mach_voucher_attr_value_handle_array_t values,mach_voucher_attr_value_handle_array_size_t value_count,mach_voucher_attr_recipe_command_t * out_command,mach_voucher_attr_content_t out_content,mach_voucher_attr_content_size_t * in_out_content_size)3584 ipc_importance_extract_content(
3585 	ipc_voucher_attr_manager_t                      __assert_only manager,
3586 	mach_voucher_attr_key_t                         __assert_only key,
3587 	mach_voucher_attr_value_handle_array_t          values,
3588 	mach_voucher_attr_value_handle_array_size_t     value_count,
3589 	mach_voucher_attr_recipe_command_t              *out_command,
3590 	mach_voucher_attr_content_t                     out_content,
3591 	mach_voucher_attr_content_size_t                *in_out_content_size)
3592 {
3593 	ipc_importance_elem_t elem;
3594 	unsigned int i;
3595 
3596 	char *buf = (char *)out_content;
3597 	mach_voucher_attr_content_size_t size = *in_out_content_size;
3598 	mach_voucher_attr_content_size_t pos = 0;
3599 	__unused int pid;
3600 
3601 	IMPORTANCE_ASSERT_MANAGER(manager);
3602 	IMPORTANCE_ASSERT_KEY(key);
3603 
3604 	/* the first non-default value provides the data */
3605 	for (i = 0; i < value_count; i++) {
3606 		elem = (ipc_importance_elem_t)values[i];
3607 		if (IIE_NULL == elem) {
3608 			continue;
3609 		}
3610 
3611 		pos += scnprintf(buf + pos, size - pos, "Importance for ");
3612 
3613 		for (;;) {
3614 			ipc_importance_inherit_t inherit = III_NULL;
3615 			ipc_importance_task_t task_imp;
3616 
3617 			if (IIE_TYPE_TASK == IIE_TYPE(elem)) {
3618 				task_imp = (ipc_importance_task_t)elem;
3619 			} else {
3620 				inherit = (ipc_importance_inherit_t)elem;
3621 				task_imp = inherit->iii_to_task;
3622 			}
3623 #if DEVELOPMENT || DEBUG
3624 			pos += scnprintf(buf + pos, size - pos, "%s[%d]",
3625 			    task_imp->iit_procname, task_imp->iit_bsd_pid);
3626 #else
3627 			ipc_importance_lock();
3628 			pid = task_importance_task_get_pid(task_imp);
3629 			ipc_importance_unlock();
3630 			pos += scnprintf(buf + pos, size - pos, "pid %d", pid);
3631 #endif /* DEVELOPMENT || DEBUG */
3632 
3633 			if (III_NULL == inherit) {
3634 				break;
3635 			}
3636 			pos += scnprintf(buf + pos, size - pos,
3637 			    " (%d of %d boosts) %s from ",
3638 			    III_EXTERN(inherit), inherit->iii_externcnt,
3639 			    (inherit->iii_donating) ? "donated" : "linked");
3640 			elem = inherit->iii_from_elem;
3641 		}
3642 
3643 		pos++; /* account for terminating \0 */
3644 		break;
3645 	}
3646 	*out_command = MACH_VOUCHER_ATTR_NOOP; /* cannot be used to regenerate value */
3647 	*in_out_content_size = pos;
3648 	return KERN_SUCCESS;
3649 }
3650 
3651 /*
3652  *	Routine:	ipc_importance_command [Voucher Attribute Manager Interface]
3653  *	Purpose:
3654  *		Run commands against the importance attribute value found in a voucher.
3655  *		No such commands are currently supported.
3656  *	Conditions:
3657  *		Nothing locked on entry.  May block.
3658  */
3659 static kern_return_t
ipc_importance_command(ipc_voucher_attr_manager_t __assert_only manager,mach_voucher_attr_key_t __assert_only key,mach_voucher_attr_value_handle_array_t values,mach_msg_type_number_t value_count,mach_voucher_attr_command_t command,mach_voucher_attr_content_t in_content,mach_voucher_attr_content_size_t in_content_size,mach_voucher_attr_content_t out_content,mach_voucher_attr_content_size_t * out_content_size)3660 ipc_importance_command(
3661 	ipc_voucher_attr_manager_t              __assert_only manager,
3662 	mach_voucher_attr_key_t                 __assert_only key,
3663 	mach_voucher_attr_value_handle_array_t  values,
3664 	mach_msg_type_number_t                  value_count,
3665 	mach_voucher_attr_command_t             command,
3666 	mach_voucher_attr_content_t             in_content,
3667 	mach_voucher_attr_content_size_t        in_content_size,
3668 	mach_voucher_attr_content_t             out_content,
3669 	mach_voucher_attr_content_size_t        *out_content_size)
3670 {
3671 	ipc_importance_inherit_t inherit;
3672 	ipc_importance_task_t to_task;
3673 	uint32_t refs, *outrefsp;
3674 	mach_msg_type_number_t i;
3675 	uint32_t externcnt;
3676 
3677 	IMPORTANCE_ASSERT_MANAGER(manager);
3678 	IMPORTANCE_ASSERT_KEY(key);
3679 
3680 	if (in_content_size != sizeof(refs) ||
3681 	    (*out_content_size != 0 && *out_content_size != sizeof(refs))) {
3682 		return KERN_INVALID_ARGUMENT;
3683 	}
3684 	refs = *(uint32_t *)(void *)in_content;
3685 	outrefsp = (*out_content_size != 0) ? (uint32_t *)(void *)out_content : NULL;
3686 
3687 	if (MACH_VOUCHER_IMPORTANCE_ATTR_DROP_EXTERNAL != command) {
3688 		return KERN_NOT_SUPPORTED;
3689 	}
3690 
3691 	/* the first non-default value of the apropos type provides the data */
3692 	inherit = III_NULL;
3693 	for (i = 0; i < value_count; i++) {
3694 		ipc_importance_elem_t elem = (ipc_importance_elem_t)values[i];
3695 
3696 		if (IIE_NULL != elem && IIE_TYPE_INHERIT == IIE_TYPE(elem)) {
3697 			inherit = (ipc_importance_inherit_t)elem;
3698 			break;
3699 		}
3700 	}
3701 	if (III_NULL == inherit) {
3702 		return KERN_INVALID_ARGUMENT;
3703 	}
3704 
3705 	ipc_importance_lock();
3706 
3707 	if (0 == refs) {
3708 		if (NULL != outrefsp) {
3709 			*outrefsp = III_EXTERN(inherit);
3710 		}
3711 		ipc_importance_unlock();
3712 		return KERN_SUCCESS;
3713 	}
3714 
3715 	to_task = inherit->iii_to_task;
3716 	assert(ipc_importance_task_is_any_receiver_type(to_task));
3717 
3718 	/* if not donating to a denap receiver, it was called incorrectly */
3719 	if (!ipc_importance_task_is_marked_denap_receiver(to_task)) {
3720 		ipc_importance_unlock();
3721 		return KERN_INVALID_TASK; /* keeps dispatch happy */
3722 	}
3723 
3724 	/* Enough external references left to drop? */
3725 	if (III_EXTERN(inherit) < refs) {
3726 		ipc_importance_unlock();
3727 		return KERN_FAILURE;
3728 	}
3729 
3730 	/* re-base external and internal counters at the inherit and the to-task (if apropos) */
3731 	if (inherit->iii_donating) {
3732 		assert(IIT_EXTERN(to_task) >= III_EXTERN(inherit));
3733 		assert(to_task->iit_externcnt >= inherit->iii_externcnt);
3734 		assert(to_task->iit_externdrop >= inherit->iii_externdrop);
3735 		inherit->iii_externdrop += refs;
3736 		to_task->iit_externdrop += refs;
3737 		externcnt = III_EXTERN(inherit);
3738 		if (0 == externcnt) {
3739 			inherit->iii_donating = FALSE;
3740 			to_task->iit_externcnt -= inherit->iii_externcnt;
3741 			to_task->iit_externdrop -= inherit->iii_externdrop;
3742 
3743 
3744 			/* Start AppNap delay hysteresis - even if not the last boost for the task. */
3745 			if (ipc_importance_delayed_drop_call != NULL &&
3746 			    ipc_importance_task_is_marked_denap_receiver(to_task)) {
3747 				ipc_importance_task_delayed_drop(to_task);
3748 			}
3749 
3750 			/* drop task assertions associated with the dropped boosts */
3751 			if (ipc_importance_task_check_transition(to_task, IIT_UPDATE_DROP, refs)) {
3752 				ipc_importance_task_propagate_assertion_locked(to_task, IIT_UPDATE_DROP, TRUE);
3753 				/* may have dropped and retaken importance lock */
3754 			}
3755 		} else {
3756 			/* assert(to_task->iit_assertcnt >= refs + externcnt); */
3757 			/* defensive deduction in case of assertcnt underflow */
3758 			if (to_task->iit_assertcnt > refs + externcnt) {
3759 				to_task->iit_assertcnt -= refs;
3760 			} else {
3761 				to_task->iit_assertcnt = externcnt;
3762 			}
3763 		}
3764 	} else {
3765 		inherit->iii_externdrop += refs;
3766 		externcnt = III_EXTERN(inherit);
3767 	}
3768 
3769 	/* capture result (if requested) */
3770 	if (NULL != outrefsp) {
3771 		*outrefsp = externcnt;
3772 	}
3773 
3774 	ipc_importance_unlock();
3775 	return KERN_SUCCESS;
3776 }
3777 
3778 /*
3779  *	Routine:	ipc_importance_manager_release [Voucher Attribute Manager Interface]
3780  *	Purpose:
3781  *		Release the Voucher system's reference on the IPC importance attribute
3782  *		manager.
3783  *	Conditions:
3784  *		As this can only occur after the manager drops the Attribute control
3785  *		reference granted back at registration time, and that reference is never
3786  *		dropped, this should never be called.
3787  */
3788 __abortlike
3789 static void
ipc_importance_manager_release(ipc_voucher_attr_manager_t __assert_only manager)3790 ipc_importance_manager_release(
3791 	ipc_voucher_attr_manager_t              __assert_only manager)
3792 {
3793 	IMPORTANCE_ASSERT_MANAGER(manager);
3794 	panic("Voucher importance manager released");
3795 }
3796 
3797 /*
3798  *	Routine:	ipc_importance_init
3799  *	Purpose:
3800  *		Initialize the  IPC importance manager.
3801  *	Conditions:
3802  *		Zones and Vouchers are already initialized.
3803  */
3804 void
ipc_importance_init(void)3805 ipc_importance_init(void)
3806 {
3807 	kern_return_t kr;
3808 
3809 	kr = ipc_register_well_known_mach_voucher_attr_manager(&ipc_importance_manager,
3810 	    (mach_voucher_attr_value_handle_t)0,
3811 	    MACH_VOUCHER_ATTR_KEY_IMPORTANCE,
3812 	    &ipc_importance_control);
3813 	if (KERN_SUCCESS != kr) {
3814 		printf("Voucher importance manager register returned %d", kr);
3815 	}
3816 }
3817 
3818 /*
3819  *	Routine:	ipc_importance_thread_call_init
3820  *	Purpose:
3821  *		Initialize the IPC importance code dependent upon
3822  *		thread-call support being available.
3823  *	Conditions:
3824  *		Thread-call mechanism is already initialized.
3825  */
3826 __startup_func
3827 static void
ipc_importance_thread_call_init(void)3828 ipc_importance_thread_call_init(void)
3829 {
3830 	/* initialize delayed drop queue and thread-call */
3831 	queue_init(&ipc_importance_delayed_drop_queue);
3832 	ipc_importance_delayed_drop_call =
3833 	    thread_call_allocate(ipc_importance_task_delayed_drop_scan, NULL);
3834 	if (NULL == ipc_importance_delayed_drop_call) {
3835 		panic("ipc_importance_init");
3836 	}
3837 }
3838 STARTUP(THREAD_CALL, STARTUP_RANK_MIDDLE, ipc_importance_thread_call_init);
3839 
3840 /*
3841  * Routing: task_importance_list_pids
3842  * Purpose: list pids where task in donating importance.
3843  * Conditions: To be called only from kdp stackshot code.
3844  *             Will panic the system otherwise.
3845  */
3846 extern int
task_importance_list_pids(task_t task,int flags,char * pid_list,unsigned int max_count)3847 task_importance_list_pids(task_t task, int flags, char *pid_list, unsigned int max_count)
3848 {
3849 	if (kdp_lck_spin_is_acquired(&ipc_importance_lock_data) ||
3850 	    max_count < 1 ||
3851 	    task->task_imp_base == IIT_NULL ||
3852 	    pid_list == NULL ||
3853 	    flags != TASK_IMP_LIST_DONATING_PIDS) {
3854 		return 0;
3855 	}
3856 	unsigned int pidcount = 0;
3857 	task_t temp_task;
3858 	ipc_importance_task_t task_imp = task->task_imp_base;
3859 	ipc_kmsg_t temp_kmsg;
3860 	ipc_importance_inherit_t temp_inherit;
3861 	ipc_importance_elem_t elem;
3862 	int target_pid = 0, previous_pid;
3863 
3864 	queue_iterate(&task_imp->iit_inherits, temp_inherit, ipc_importance_inherit_t, iii_inheritance) {
3865 		/* check space in buffer */
3866 		if (pidcount >= max_count) {
3867 			break;
3868 		}
3869 		previous_pid = target_pid;
3870 		target_pid = -1;
3871 
3872 		if (temp_inherit->iii_donating) {
3873 			target_pid = task_importance_task_get_pid(temp_inherit->iii_to_task);
3874 		}
3875 
3876 		if (target_pid != -1 && previous_pid != target_pid) {
3877 			memcpy(pid_list, &target_pid, sizeof(target_pid));
3878 			pid_list += sizeof(target_pid);
3879 			pidcount++;
3880 		}
3881 	}
3882 
3883 	target_pid = 0;
3884 	queue_iterate(&task_imp->iit_kmsgs, temp_kmsg, ipc_kmsg_t, ikm_inheritance) {
3885 		if (pidcount >= max_count) {
3886 			break;
3887 		}
3888 		previous_pid = target_pid;
3889 		target_pid = -1;
3890 		elem = temp_kmsg->ikm_importance;
3891 		temp_task = TASK_NULL;
3892 
3893 		if (elem == IIE_NULL) {
3894 			continue;
3895 		}
3896 
3897 		if (!(temp_kmsg->ikm_header && MACH_MSGH_BITS_RAISED_IMPORTANCE(temp_kmsg->ikm_header->msgh_bits))) {
3898 			continue;
3899 		}
3900 
3901 		if (IIE_TYPE_TASK == IIE_TYPE(elem)) {
3902 			ipc_importance_task_t temp_iit = (ipc_importance_task_t)elem;
3903 			target_pid = task_importance_task_get_pid(temp_iit);
3904 		} else {
3905 			temp_inherit = (ipc_importance_inherit_t)elem;
3906 			target_pid = task_importance_task_get_pid(temp_inherit->iii_to_task);
3907 		}
3908 
3909 		if (target_pid != -1 && previous_pid != target_pid) {
3910 			memcpy(pid_list, &target_pid, sizeof(target_pid));
3911 			pid_list += sizeof(target_pid);
3912 			pidcount++;
3913 		}
3914 	}
3915 
3916 	return pidcount;
3917 }
3918