xref: /xnu-12377.41.6/osfmk/kern/thread_act.c (revision bbb1b6f9e71b8cdde6e5cd6f4841f207dee3d828)
1 /*
2  * Copyright (c) 2000-2016 Apple Inc. All rights reserved.
3  *
4  * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5  *
6  * This file contains Original Code and/or Modifications of Original Code
7  * as defined in and that are subject to the Apple Public Source License
8  * Version 2.0 (the 'License'). You may not use this file except in
9  * compliance with the License. The rights granted to you under the License
10  * may not be used to create, or enable the creation or redistribution of,
11  * unlawful or unlicensed copies of an Apple operating system, or to
12  * circumvent, violate, or enable the circumvention or violation of, any
13  * terms of an Apple operating system software license agreement.
14  *
15  * Please obtain a copy of the License at
16  * http://www.opensource.apple.com/apsl/ and read it before using this file.
17  *
18  * The Original Code and all software distributed under the License are
19  * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20  * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21  * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22  * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23  * Please see the License for the specific language governing rights and
24  * limitations under the License.
25  *
26  * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27  */
28 /*
29  * @OSF_FREE_COPYRIGHT@
30  */
31 /*
32  * Copyright (c) 1993 The University of Utah and
33  * the Center for Software Science (CSS).  All rights reserved.
34  *
35  * Permission to use, copy, modify and distribute this software and its
36  * documentation is hereby granted, provided that both the copyright
37  * notice and this permission notice appear in all copies of the
38  * software, derivative works or modified versions, and any portions
39  * thereof, and that both notices appear in supporting documentation.
40  *
41  * THE UNIVERSITY OF UTAH AND CSS ALLOW FREE USE OF THIS SOFTWARE IN ITS "AS
42  * IS" CONDITION.  THE UNIVERSITY OF UTAH AND CSS DISCLAIM ANY LIABILITY OF
43  * ANY KIND FOR ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE.
44  *
45  * CSS requests users of this software to return to [email protected] any
46  * improvements that they make and grant CSS redistribution rights.
47  *
48  *	Author:	Bryan Ford, University of Utah CSS
49  *
50  *	Thread management routines
51  */
52 
53 #include <sys/kdebug.h>
54 #include <mach/mach_types.h>
55 #include <mach/kern_return.h>
56 #include <mach/thread_act_server.h>
57 #include <mach/thread_act.h>
58 
59 #include <kern/kern_types.h>
60 #include <kern/ast.h>
61 #include <kern/mach_param.h>
62 #include <kern/zalloc.h>
63 #include <kern/extmod_statistics.h>
64 #include <kern/thread.h>
65 #include <kern/task.h>
66 #include <kern/sched_prim.h>
67 #include <kern/misc_protos.h>
68 #include <kern/assert.h>
69 #include <kern/exception.h>
70 #include <kern/ipc_mig.h>
71 #include <kern/ipc_tt.h>
72 #include <kern/machine.h>
73 #include <kern/spl.h>
74 #include <kern/syscall_subr.h>
75 #include <kern/processor.h>
76 #include <kern/restartable.h>
77 #include <kern/timer.h>
78 #include <kern/affinity.h>
79 #include <kern/host.h>
80 #include <kern/exc_guard.h>
81 #include <ipc/ipc_policy.h>
82 #include <mach/arm/thread_status.h>
83 
84 #include <sys/code_signing.h>
85 
86 #include <stdatomic.h>
87 
88 #include <security/mac_mach_internal.h>
89 
90 static void act_abort(thread_t thread);
91 
92 static void thread_suspended(void *arg, wait_result_t result);
93 static void thread_set_apc_ast(thread_t thread);
94 static void thread_set_apc_ast_locked(thread_t thread);
95 
96 extern boolean_t IOTaskHasEntitlement(task_t task, const char *entitlement);
97 
98 /* bootarg to create lightweight corpse for thread set state lockdown */
99 TUNABLE(bool, tss_should_crash, "tss_should_crash", true);
100 
101 #define task_has_tss_entitlement(task) IOTaskHasEntitlement((task), \
102 	"com.apple.private.thread-set-state")
103 
104 static inline bool
thread_set_state_allowed(thread_t thread,int flavor,thread_set_status_flags_t flags)105 thread_set_state_allowed(
106 	thread_t                  thread,
107 	int                       flavor,
108 	thread_set_status_flags_t flags)
109 {
110 	task_t             curr_task   = TASK_NULL;
111 	task_t             target_task = TASK_NULL;
112 	ipc_space_policy_t target_pol;
113 	ipc_space_policy_t exception_tss_policy_level;
114 
115 #if DEVELOPMENT || DEBUG
116 	/* disable the feature if the boot-arg is disabled. */
117 	if (!tss_should_crash) {
118 		return true;
119 	}
120 #endif /* DEVELOPMENT || DEBUG */
121 
122 	/* No security check needed if neither of these two flags were set */
123 	if ((flags & TSSF_CHECK_ENTITLEMENT) == 0 &&
124 	    (thread->options & TH_IN_MACH_EXCEPTION) == 0) {
125 		return true;
126 	}
127 
128 	curr_task = current_task();
129 	target_task = get_threadtask(thread);
130 	target_pol = ipc_space_policy(get_task_ipcspace(target_task));
131 	/* Allow if the task is translated, simulated, or has IPC hardening turned off */
132 	if (!ipc_should_apply_policy(target_pol, IPC_SPACE_POLICY_DEFAULT)) {
133 		return true;
134 	}
135 
136 	/*
137 	 * Setting the thread state from a userspace mach exception handler is
138 	 * allowed iff it comes from the same process, or if the process is
139 	 * being debugged (in dev mode)
140 	 */
141 #if !(XNU_TARGET_OS_OSX || XNU_TARGET_OS_BRIDGE)
142 	exception_tss_policy_level = IPC_POLICY_ENHANCED_V1;
143 #else
144 	exception_tss_policy_level = IPC_POLICY_ENHANCED_V2;
145 #endif /* !(XNU_TARGET_OS_OSX || XNU_TARGET_OS_BRIDGE) */
146 	if ((thread->options & TH_IN_MACH_EXCEPTION) &&
147 	    target_task != curr_task &&
148 	    ipc_should_apply_policy(target_pol, exception_tss_policy_level) &&
149 	    (!is_address_space_debugged(get_bsdtask_info(target_task))) &&
150 	    !task_has_tss_entitlement(curr_task)) {
151 		mach_port_guard_exception(flavor, 0, kGUARD_EXC_THREAD_SET_STATE);
152 		return false;
153 	}
154 
155 	/* enhanced security binaries must have entitlement - all others ok */
156 	if ((flags & TSSF_CHECK_ENTITLEMENT) &&
157 	    !(thread->options & TH_IN_MACH_EXCEPTION) &&  /* Allowed for now - rdar://103085786 */
158 	    ipc_should_apply_policy(target_pol, IPC_POLICY_ENHANCED_V1) &&
159 	    FLAVOR_MODIFIES_CORE_CPU_REGISTERS(flavor) && /* only care about locking down PC/LR */
160 	    !task_has_tss_entitlement(curr_task)) {
161 		mach_port_guard_exception(flavor, 0, kGUARD_EXC_THREAD_SET_STATE);
162 		return false;
163 	}
164 
165 #if __has_feature(ptrauth_calls)
166 	/* Do not allow Fatal PAC exception binaries to set Debug state */
167 	if ((flags & TSSF_CHECK_ENTITLEMENT) &&
168 	    task_is_pac_exception_fatal(target_task) &&
169 	    machine_thread_state_is_debug_flavor(flavor) &&
170 	    !task_has_tss_entitlement(curr_task)) {
171 		mach_port_guard_exception(flavor, 0, kGUARD_EXC_THREAD_SET_STATE);
172 		return false;
173 	}
174 #endif /* __has_feature(ptrauth_calls) */
175 
176 	return true;
177 }
178 
179 /*
180  * Internal routine to mark a thread as started.
181  * Always called with the thread mutex locked.
182  */
183 void
thread_start(thread_t thread)184 thread_start(
185 	thread_t                        thread)
186 {
187 	clear_wait(thread, THREAD_AWAKENED);
188 	thread->started = TRUE;
189 }
190 
191 /*
192  * Internal routine to mark a thread as waiting
193  * right after it has been created.  The caller
194  * is responsible to call wakeup()/thread_wakeup()
195  * or thread_terminate() to get it going.
196  *
197  * Always called with the thread mutex locked.
198  *
199  * Task and task_threads mutexes also held
200  * (so nobody can set the thread running before
201  * this point)
202  *
203  * Converts TH_UNINT wait to THREAD_INTERRUPTIBLE
204  * to allow termination from this point forward.
205  */
206 void
thread_start_in_assert_wait(thread_t thread,struct waitq * waitq,event64_t event,wait_interrupt_t interruptible)207 thread_start_in_assert_wait(
208 	thread_t            thread,
209 	struct waitq       *waitq,
210 	event64_t           event,
211 	wait_interrupt_t    interruptible)
212 {
213 	wait_result_t wait_result;
214 	spl_t spl;
215 
216 	spl = splsched();
217 	waitq_lock(waitq);
218 
219 	/* clear out startup condition (safe because thread not started yet) */
220 	thread_lock(thread);
221 	assert(!thread->started);
222 	assert((thread->state & (TH_WAIT | TH_UNINT)) == (TH_WAIT | TH_UNINT));
223 	thread->state &= ~(TH_WAIT | TH_UNINT);
224 	thread_unlock(thread);
225 
226 	/* assert wait interruptibly forever */
227 	wait_result = waitq_assert_wait64_locked(waitq, event,
228 	    interruptible,
229 	    TIMEOUT_URGENCY_SYS_NORMAL,
230 	    TIMEOUT_WAIT_FOREVER,
231 	    TIMEOUT_NO_LEEWAY,
232 	    thread);
233 	assert(wait_result == THREAD_WAITING);
234 
235 	/* mark thread started while we still hold the waitq lock */
236 	thread_lock(thread);
237 	thread->started = TRUE;
238 	thread_unlock(thread);
239 
240 	waitq_unlock(waitq);
241 	splx(spl);
242 }
243 
244 /*
245  * Internal routine to terminate a thread.
246  * Sometimes called with task already locked.
247  *
248  * If thread is on core, cause AST check immediately;
249  * Otherwise, let the thread continue running in kernel
250  * until it hits AST.
251  */
252 kern_return_t
thread_terminate_internal(thread_t thread)253 thread_terminate_internal(
254 	thread_t                        thread)
255 {
256 	kern_return_t           result = KERN_SUCCESS;
257 
258 	thread_mtx_lock(thread);
259 
260 	if (thread->active) {
261 		thread->active = FALSE;
262 
263 		act_abort(thread);
264 
265 		if (thread->started) {
266 			clear_wait(thread, THREAD_INTERRUPTED);
267 		} else {
268 			thread_start(thread);
269 		}
270 	} else {
271 		result = KERN_TERMINATED;
272 	}
273 
274 	if (thread->affinity_set != NULL) {
275 		thread_affinity_terminate(thread);
276 	}
277 
278 	/* unconditionally unpin the thread in internal termination */
279 	ipc_thread_port_unpin(get_thread_ro(thread)->tro_ports[THREAD_FLAVOR_CONTROL]);
280 
281 	thread_mtx_unlock(thread);
282 
283 	if (thread != current_thread() && result == KERN_SUCCESS) {
284 		thread_wait(thread, FALSE);
285 	}
286 
287 	return result;
288 }
289 
290 kern_return_t
thread_terminate(thread_t thread)291 thread_terminate(
292 	thread_t                thread)
293 {
294 	task_t task;
295 
296 	if (thread == THREAD_NULL) {
297 		return KERN_INVALID_ARGUMENT;
298 	}
299 
300 	if (thread->state & TH_IDLE) {
301 		panic("idle thread calling thread_terminate!");
302 	}
303 
304 	task = get_threadtask(thread);
305 
306 	/* Kernel threads can't be terminated without their own cooperation */
307 	if (task == kernel_task && thread != current_thread()) {
308 		return KERN_FAILURE;
309 	}
310 
311 	kern_return_t result = thread_terminate_internal(thread);
312 
313 	/*
314 	 * If a kernel thread is terminating itself, force handle the APC_AST here.
315 	 * Kernel threads don't pass through the return-to-user AST checking code,
316 	 * but all threads must finish their own termination in thread_apc_ast.
317 	 */
318 	if (task == kernel_task) {
319 		assert(thread->active == FALSE);
320 		thread_ast_clear(thread, AST_APC);
321 		thread_apc_ast(thread);
322 
323 		panic("thread_terminate");
324 		/* NOTREACHED */
325 	}
326 
327 	return result;
328 }
329 
330 /*
331  * [MIG Call] Terminate a thread.
332  *
333  * Cannot be used on threads managed by pthread.
334  */
335 kern_return_t
thread_terminate_from_user(thread_t thread)336 thread_terminate_from_user(
337 	thread_t                thread)
338 {
339 	if (thread == THREAD_NULL) {
340 		return KERN_INVALID_ARGUMENT;
341 	}
342 
343 	if (thread_get_tag(thread) & THREAD_TAG_PTHREAD) {
344 		return KERN_DENIED;
345 	}
346 
347 	return thread_terminate(thread);
348 }
349 
350 /*
351  * Terminate a thread with immovable control port.
352  *
353  * Can only be used on threads managed by pthread. Exported in pthread_kern.
354  */
355 kern_return_t
thread_terminate_immovable(thread_t thread)356 thread_terminate_immovable(
357 	thread_t                thread)
358 {
359 	assert(thread == current_thread());
360 	assert(get_threadtask(thread) != kernel_task);
361 	assert(thread_get_tag(thread) & (THREAD_TAG_PTHREAD | THREAD_TAG_MAINTHREAD));
362 
363 	return thread_terminate_internal(thread);
364 }
365 
366 /*
367  * Suspend execution of the specified thread.
368  * This is a recursive-style suspension of the thread, a count of
369  * suspends is maintained.
370  *
371  * Called with thread mutex held.
372  */
373 void
thread_hold(thread_t thread)374 thread_hold(thread_t thread)
375 {
376 	if (thread->suspend_count++ == 0) {
377 		task_t task = get_threadtask(thread);
378 		thread_set_apc_ast(thread);
379 		assert(thread->suspend_parked == FALSE);
380 
381 		KDBG_RELEASE(MACHDBG_CODE(DBG_MACH_SUSPENSION, MACH_THREAD_SUSPEND) | DBG_FUNC_NONE,
382 		    thread->thread_id, thread->user_stop_count, task->pidsuspended);
383 	}
384 }
385 
386 /*
387  * Decrement internal suspension count, setting thread
388  * runnable when count falls to zero.
389  *
390  * Because the wait is abortsafe, we can't be guaranteed that the thread
391  * is currently actually waiting even if suspend_parked is set.
392  *
393  * Called with thread mutex held.
394  */
395 void
thread_release(thread_t thread)396 thread_release(thread_t thread)
397 {
398 	assertf(thread->suspend_count > 0, "thread %p over-resumed", thread);
399 
400 	/* fail-safe on non-assert builds */
401 	if (thread->suspend_count == 0) {
402 		return;
403 	}
404 
405 	if (--thread->suspend_count == 0) {
406 		if (!thread->started) {
407 			thread_start(thread);
408 		} else if (thread->suspend_parked) {
409 			thread->suspend_parked = FALSE;
410 			thread_wakeup_thread(&thread->suspend_count, thread);
411 		}
412 		KDBG_RELEASE(MACHDBG_CODE(DBG_MACH_SUSPENSION, MACH_THREAD_RESUME) | DBG_FUNC_NONE, thread->thread_id);
413 	}
414 }
415 
416 kern_return_t
thread_suspend(thread_t thread)417 thread_suspend(thread_t thread)
418 {
419 	kern_return_t result = KERN_SUCCESS;
420 
421 	if (thread == THREAD_NULL || get_threadtask(thread) == kernel_task) {
422 		return KERN_INVALID_ARGUMENT;
423 	}
424 
425 	thread_mtx_lock(thread);
426 
427 	if (thread->active) {
428 		if (thread->user_stop_count++ == 0) {
429 			thread_hold(thread);
430 		}
431 	} else {
432 		result = KERN_TERMINATED;
433 	}
434 
435 	thread_mtx_unlock(thread);
436 
437 	if (thread != current_thread() && result == KERN_SUCCESS) {
438 		thread_wait(thread, FALSE);
439 	}
440 
441 	return result;
442 }
443 
444 kern_return_t
thread_resume(thread_t thread)445 thread_resume(thread_t thread)
446 {
447 	kern_return_t result = KERN_SUCCESS;
448 
449 	if (thread == THREAD_NULL || get_threadtask(thread) == kernel_task) {
450 		return KERN_INVALID_ARGUMENT;
451 	}
452 
453 	thread_mtx_lock(thread);
454 
455 	if (thread->active) {
456 		if (thread->user_stop_count > 0) {
457 			if (--thread->user_stop_count == 0) {
458 				thread_release(thread);
459 			}
460 		} else {
461 			result = KERN_FAILURE;
462 		}
463 	} else {
464 		result = KERN_TERMINATED;
465 	}
466 
467 	thread_mtx_unlock(thread);
468 
469 	return result;
470 }
471 
472 /*
473  *	thread_depress_abort_from_user:
474  *
475  *	Prematurely abort priority depression if there is one.
476  */
477 kern_return_t
thread_depress_abort_from_user(thread_t thread)478 thread_depress_abort_from_user(thread_t thread)
479 {
480 	kern_return_t result;
481 
482 	if (thread == THREAD_NULL) {
483 		return KERN_INVALID_ARGUMENT;
484 	}
485 
486 	thread_mtx_lock(thread);
487 
488 	if (thread->active) {
489 		result = thread_depress_abort(thread);
490 	} else {
491 		result = KERN_TERMINATED;
492 	}
493 
494 	thread_mtx_unlock(thread);
495 
496 	return result;
497 }
498 
499 
500 /*
501  * Indicate that the thread should run the AST_APC callback
502  * to detect an abort condition.
503  *
504  * Called with thread mutex held.
505  */
506 static void
act_abort(thread_t thread)507 act_abort(
508 	thread_t        thread)
509 {
510 	spl_t           s = splsched();
511 
512 	thread_lock(thread);
513 
514 	if (!(thread->sched_flags & TH_SFLAG_ABORT)) {
515 		thread->sched_flags |= TH_SFLAG_ABORT;
516 		thread_set_apc_ast_locked(thread);
517 		thread_depress_abort_locked(thread);
518 	} else {
519 		thread->sched_flags &= ~TH_SFLAG_ABORTSAFELY;
520 	}
521 
522 	thread_unlock(thread);
523 	splx(s);
524 }
525 
526 kern_return_t
thread_abort(thread_t thread)527 thread_abort(
528 	thread_t        thread)
529 {
530 	kern_return_t   result = KERN_SUCCESS;
531 
532 	if (thread == THREAD_NULL) {
533 		return KERN_INVALID_ARGUMENT;
534 	}
535 
536 	thread_mtx_lock(thread);
537 
538 	if (thread->active) {
539 		act_abort(thread);
540 		clear_wait(thread, THREAD_INTERRUPTED);
541 	} else {
542 		result = KERN_TERMINATED;
543 	}
544 
545 	thread_mtx_unlock(thread);
546 
547 	return result;
548 }
549 
550 kern_return_t
thread_abort_safely(thread_t thread)551 thread_abort_safely(
552 	thread_t                thread)
553 {
554 	kern_return_t   result = KERN_SUCCESS;
555 
556 	if (thread == THREAD_NULL) {
557 		return KERN_INVALID_ARGUMENT;
558 	}
559 
560 	thread_mtx_lock(thread);
561 
562 	if (thread->active) {
563 		spl_t           s = splsched();
564 
565 		thread_lock(thread);
566 		if (!thread->at_safe_point ||
567 		    clear_wait_internal(thread, THREAD_INTERRUPTED) != KERN_SUCCESS) {
568 			if (!(thread->sched_flags & TH_SFLAG_ABORT)) {
569 				thread->sched_flags |= TH_SFLAG_ABORTED_MASK;
570 				thread_set_apc_ast_locked(thread);
571 				thread_depress_abort_locked(thread);
572 			}
573 		}
574 		thread_unlock(thread);
575 		splx(s);
576 	} else {
577 		result = KERN_TERMINATED;
578 	}
579 
580 	thread_mtx_unlock(thread);
581 
582 	return result;
583 }
584 
585 /*** backward compatibility hacks ***/
586 #include <mach/thread_info.h>
587 #include <mach/thread_special_ports.h>
588 #include <ipc/ipc_port.h>
589 
590 kern_return_t
thread_info(thread_t thread,thread_flavor_t flavor,thread_info_t thread_info_out,mach_msg_type_number_t * thread_info_count)591 thread_info(
592 	thread_t                        thread,
593 	thread_flavor_t                 flavor,
594 	thread_info_t                   thread_info_out,
595 	mach_msg_type_number_t  *thread_info_count)
596 {
597 	kern_return_t                   result;
598 
599 	if (thread == THREAD_NULL) {
600 		return KERN_INVALID_ARGUMENT;
601 	}
602 
603 	thread_mtx_lock(thread);
604 
605 	if (thread->active || thread->inspection) {
606 		result = thread_info_internal(
607 			thread, flavor, thread_info_out, thread_info_count);
608 	} else {
609 		result = KERN_TERMINATED;
610 	}
611 
612 	thread_mtx_unlock(thread);
613 
614 	return result;
615 }
616 
617 static inline kern_return_t
thread_get_state_internal(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t * state_count,thread_set_status_flags_t flags)618 thread_get_state_internal(
619 	thread_t                thread,
620 	int                                             flavor,
621 	thread_state_t                  state,                  /* pointer to OUT array */
622 	mach_msg_type_number_t  *state_count,   /*IN/OUT*/
623 	thread_set_status_flags_t  flags)
624 {
625 	kern_return_t           result = KERN_SUCCESS;
626 	boolean_t               to_user = !!(flags & TSSF_TRANSLATE_TO_USER);
627 
628 	if (thread == THREAD_NULL) {
629 		return KERN_INVALID_ARGUMENT;
630 	}
631 
632 	thread_mtx_lock(thread);
633 
634 	if (thread->active) {
635 		if (thread != current_thread()) {
636 			thread_hold(thread);
637 
638 			thread_mtx_unlock(thread);
639 
640 			if (thread_stop(thread, FALSE)) {
641 				thread_mtx_lock(thread);
642 				result = machine_thread_get_state(
643 					thread, flavor, state, state_count);
644 				thread_unstop(thread);
645 			} else {
646 				thread_mtx_lock(thread);
647 				result = KERN_ABORTED;
648 			}
649 
650 			thread_release(thread);
651 		} else {
652 			result = machine_thread_get_state(
653 				thread, flavor, state, state_count);
654 		}
655 	} else if (thread->inspection) {
656 		result = machine_thread_get_state(
657 			thread, flavor, state, state_count);
658 	} else {
659 		result = KERN_TERMINATED;
660 	}
661 
662 	if (to_user && result == KERN_SUCCESS) {
663 		result = machine_thread_state_convert_to_user(thread, flavor, state,
664 		    state_count, flags);
665 	}
666 
667 	thread_mtx_unlock(thread);
668 
669 	return result;
670 }
671 
672 /* No prototype, since thread_act_server.h has the _to_user version if KERNEL_SERVER */
673 
674 kern_return_t
675 thread_get_state(
676 	thread_t                thread,
677 	int                                             flavor,
678 	thread_state_t                  state,
679 	mach_msg_type_number_t  *state_count);
680 
681 kern_return_t
thread_get_state(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t * state_count)682 thread_get_state(
683 	thread_t                thread,
684 	int                                             flavor,
685 	thread_state_t                  state,                  /* pointer to OUT array */
686 	mach_msg_type_number_t  *state_count)   /*IN/OUT*/
687 {
688 	return thread_get_state_internal(thread, flavor, state, state_count, TSSF_FLAGS_NONE);
689 }
690 
691 kern_return_t
thread_get_state_to_user(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t * state_count)692 thread_get_state_to_user(
693 	thread_t                thread,
694 	int                                             flavor,
695 	thread_state_t                  state,                  /* pointer to OUT array */
696 	mach_msg_type_number_t  *state_count)   /*IN/OUT*/
697 {
698 	return thread_get_state_internal(thread, flavor, state, state_count, TSSF_TRANSLATE_TO_USER);
699 }
700 
701 /*
702  *	Change thread's machine-dependent state.  Called with nothing
703  *	locked.  Returns same way.
704  */
705 static inline kern_return_t
thread_set_state_internal(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t state_count,thread_state_t old_state,mach_msg_type_number_t old_state_count,thread_set_status_flags_t flags)706 thread_set_state_internal(
707 	thread_t                        thread,
708 	int                             flavor,
709 	thread_state_t                  state,
710 	mach_msg_type_number_t          state_count,
711 	thread_state_t                  old_state,
712 	mach_msg_type_number_t          old_state_count,
713 	thread_set_status_flags_t       flags)
714 {
715 	kern_return_t           result = KERN_SUCCESS;
716 	boolean_t               from_user = !!(flags & TSSF_TRANSLATE_TO_USER);
717 
718 	if (thread == THREAD_NULL) {
719 		return KERN_INVALID_ARGUMENT;
720 	}
721 
722 	/*
723 	 * process will be crashed with kGUARD_EXC_THREAD_SET_STATE
724 	 * if thread_set_state_allowed() return false.
725 	 */
726 	if (!thread_set_state_allowed(thread, flavor, flags)) {
727 		return KERN_NO_ACCESS;
728 	}
729 
730 	thread_mtx_lock(thread);
731 
732 	if (thread->active) {
733 		if (from_user) {
734 			result = machine_thread_state_convert_from_user(thread, flavor,
735 			    state, state_count, old_state, old_state_count, flags);
736 			if (result != KERN_SUCCESS) {
737 				goto out;
738 			}
739 		}
740 		if (thread != current_thread()) {
741 			thread_hold(thread);
742 
743 			thread_mtx_unlock(thread);
744 
745 			if (thread_stop(thread, TRUE)) {
746 				thread_mtx_lock(thread);
747 				result = machine_thread_set_state(
748 					thread, flavor, state, state_count);
749 				thread_unstop(thread);
750 			} else {
751 				thread_mtx_lock(thread);
752 				result = KERN_ABORTED;
753 			}
754 
755 			thread_release(thread);
756 		} else {
757 			result = machine_thread_set_state(
758 				thread, flavor, state, state_count);
759 		}
760 	} else {
761 		result = KERN_TERMINATED;
762 	}
763 
764 	if ((result == KERN_SUCCESS) && from_user) {
765 		extmod_statistics_incr_thread_set_state(thread);
766 	}
767 
768 out:
769 	thread_mtx_unlock(thread);
770 
771 	return result;
772 }
773 
774 /* No prototype, since thread_act_server.h has the _from_user version if KERNEL_SERVER */
775 kern_return_t
776 thread_set_state(
777 	thread_t                thread,
778 	int                                             flavor,
779 	thread_state_t                  state,
780 	mach_msg_type_number_t  state_count);
781 
782 kern_return_t
thread_set_state(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t state_count)783 thread_set_state(
784 	thread_t                thread,
785 	int                                             flavor,
786 	thread_state_t                  state,
787 	mach_msg_type_number_t  state_count)
788 {
789 	return thread_set_state_internal(thread, flavor, state, state_count, NULL, 0, TSSF_FLAGS_NONE);
790 }
791 
792 kern_return_t
thread_set_state_from_user(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t state_count)793 thread_set_state_from_user(
794 	thread_t                thread,
795 	int                                             flavor,
796 	thread_state_t                  state,
797 	mach_msg_type_number_t  state_count)
798 {
799 	return thread_set_state_internal(thread, flavor, state, state_count, NULL,
800 	           0, TSSF_TRANSLATE_TO_USER | TSSF_CHECK_ENTITLEMENT);
801 }
802 
803 kern_return_t
thread_convert_thread_state(thread_t thread,int direction,thread_state_flavor_t flavor,thread_state_t in_state,mach_msg_type_number_t in_state_count,thread_state_t out_state,mach_msg_type_number_t * out_state_count)804 thread_convert_thread_state(
805 	thread_t                thread,
806 	int                     direction,
807 	thread_state_flavor_t   flavor,
808 	thread_state_t          in_state,          /* pointer to IN array */
809 	mach_msg_type_number_t  in_state_count,
810 	thread_state_t          out_state,         /* pointer to OUT array */
811 	mach_msg_type_number_t  *out_state_count)   /*IN/OUT*/
812 {
813 	kern_return_t kr;
814 	thread_t to_thread = THREAD_NULL;
815 	thread_t from_thread = THREAD_NULL;
816 	mach_msg_type_number_t state_count = in_state_count;
817 
818 	if (direction != THREAD_CONVERT_THREAD_STATE_TO_SELF &&
819 	    direction != THREAD_CONVERT_THREAD_STATE_FROM_SELF) {
820 		return KERN_INVALID_ARGUMENT;
821 	}
822 
823 	if (thread == THREAD_NULL) {
824 		return KERN_INVALID_ARGUMENT;
825 	}
826 
827 	if (state_count > *out_state_count) {
828 		return KERN_INSUFFICIENT_BUFFER_SIZE;
829 	}
830 
831 	if (direction == THREAD_CONVERT_THREAD_STATE_FROM_SELF) {
832 		to_thread = thread;
833 		from_thread = current_thread();
834 	} else {
835 		to_thread = current_thread();
836 		from_thread = thread;
837 	}
838 
839 	/* Authenticate and convert thread state to kernel representation */
840 	kr = machine_thread_state_convert_from_user(from_thread, flavor,
841 	    in_state, state_count, NULL, 0, TSSF_FLAGS_NONE);
842 
843 	/* Return early if one of the thread was jop disabled while other wasn't */
844 	if (kr != KERN_SUCCESS) {
845 		return kr;
846 	}
847 
848 	/* Convert thread state to target thread user representation */
849 	kr = machine_thread_state_convert_to_user(to_thread, flavor,
850 	    in_state, &state_count, TSSF_PRESERVE_FLAGS);
851 
852 	if (kr == KERN_SUCCESS) {
853 		if (state_count <= *out_state_count) {
854 			memcpy(out_state, in_state, state_count * sizeof(uint32_t));
855 			*out_state_count = state_count;
856 		} else {
857 			kr = KERN_INSUFFICIENT_BUFFER_SIZE;
858 		}
859 	}
860 
861 	return kr;
862 }
863 
864 /*
865  * Kernel-internal "thread" interfaces used outside this file:
866  */
867 
868 /* Initialize (or re-initialize) a thread state.  Called from execve
869  * with nothing locked, returns same way.
870  */
871 kern_return_t
thread_state_initialize(thread_t thread)872 thread_state_initialize(
873 	thread_t                thread)
874 {
875 	kern_return_t           result = KERN_SUCCESS;
876 
877 	if (thread == THREAD_NULL) {
878 		return KERN_INVALID_ARGUMENT;
879 	}
880 
881 	thread_mtx_lock(thread);
882 
883 	if (thread->active) {
884 		if (thread != current_thread()) {
885 			/* Thread created in exec should be blocked in UNINT wait */
886 			assert(!(thread->state & TH_RUN));
887 		}
888 		machine_thread_state_initialize( thread );
889 	} else {
890 		result = KERN_TERMINATED;
891 	}
892 
893 	thread_mtx_unlock(thread);
894 
895 	return result;
896 }
897 
898 kern_return_t
thread_dup(thread_t target)899 thread_dup(
900 	thread_t        target)
901 {
902 	thread_t                        self = current_thread();
903 	kern_return_t           result = KERN_SUCCESS;
904 
905 	if (target == THREAD_NULL || target == self) {
906 		return KERN_INVALID_ARGUMENT;
907 	}
908 
909 	thread_mtx_lock(target);
910 
911 	if (target->active) {
912 		thread_hold(target);
913 
914 		thread_mtx_unlock(target);
915 
916 		if (thread_stop(target, TRUE)) {
917 			thread_mtx_lock(target);
918 			result = machine_thread_dup(self, target, FALSE);
919 
920 			if (self->affinity_set != AFFINITY_SET_NULL) {
921 				thread_affinity_dup(self, target);
922 			}
923 			thread_unstop(target);
924 		} else {
925 			thread_mtx_lock(target);
926 			result = KERN_ABORTED;
927 		}
928 
929 		thread_release(target);
930 	} else {
931 		result = KERN_TERMINATED;
932 	}
933 
934 	thread_mtx_unlock(target);
935 
936 	return result;
937 }
938 
939 
940 kern_return_t
thread_dup2(thread_t source,thread_t target)941 thread_dup2(
942 	thread_t        source,
943 	thread_t        target)
944 {
945 	kern_return_t           result = KERN_SUCCESS;
946 	uint32_t                active = 0;
947 
948 	if (source == THREAD_NULL || target == THREAD_NULL || target == source) {
949 		return KERN_INVALID_ARGUMENT;
950 	}
951 
952 	thread_mtx_lock(source);
953 	active = source->active;
954 	thread_mtx_unlock(source);
955 
956 	if (!active) {
957 		return KERN_TERMINATED;
958 	}
959 
960 	thread_mtx_lock(target);
961 
962 	if (target->active || target->inspection) {
963 		thread_hold(target);
964 
965 		thread_mtx_unlock(target);
966 
967 		if (thread_stop(target, TRUE)) {
968 			thread_mtx_lock(target);
969 			result = machine_thread_dup(source, target, TRUE);
970 			if (source->affinity_set != AFFINITY_SET_NULL) {
971 				thread_affinity_dup(source, target);
972 			}
973 			thread_unstop(target);
974 		} else {
975 			thread_mtx_lock(target);
976 			result = KERN_ABORTED;
977 		}
978 
979 		thread_release(target);
980 	} else {
981 		result = KERN_TERMINATED;
982 	}
983 
984 	thread_mtx_unlock(target);
985 
986 	return result;
987 }
988 
989 /*
990  *	thread_setstatus:
991  *
992  *	Set the status of the specified thread.
993  *	Called with (and returns with) no locks held.
994  */
995 kern_return_t
thread_setstatus(thread_t thread,int flavor,thread_state_t tstate,mach_msg_type_number_t count)996 thread_setstatus(
997 	thread_t                thread,
998 	int                                             flavor,
999 	thread_state_t                  tstate,
1000 	mach_msg_type_number_t  count)
1001 {
1002 	return thread_set_state(thread, flavor, tstate, count);
1003 }
1004 
1005 kern_return_t
thread_setstatus_from_user(thread_t thread,int flavor,thread_state_t tstate,mach_msg_type_number_t count,thread_state_t old_tstate,mach_msg_type_number_t old_count,thread_set_status_flags_t flags)1006 thread_setstatus_from_user(
1007 	thread_t                thread,
1008 	int                                             flavor,
1009 	thread_state_t                  tstate,
1010 	mach_msg_type_number_t  count,
1011 	thread_state_t                  old_tstate,
1012 	mach_msg_type_number_t  old_count,
1013 	thread_set_status_flags_t flags)
1014 {
1015 	return thread_set_state_internal(thread, flavor, tstate, count, old_tstate,
1016 	           old_count, flags | TSSF_TRANSLATE_TO_USER);
1017 }
1018 
1019 /*
1020  *	thread_getstatus:
1021  *
1022  *	Get the status of the specified thread.
1023  */
1024 kern_return_t
thread_getstatus(thread_t thread,int flavor,thread_state_t tstate,mach_msg_type_number_t * count)1025 thread_getstatus(
1026 	thread_t                thread,
1027 	int                                             flavor,
1028 	thread_state_t                  tstate,
1029 	mach_msg_type_number_t  *count)
1030 {
1031 	return thread_get_state(thread, flavor, tstate, count);
1032 }
1033 
1034 kern_return_t
thread_getstatus_to_user(thread_t thread,int flavor,thread_state_t tstate,mach_msg_type_number_t * count,thread_set_status_flags_t flags)1035 thread_getstatus_to_user(
1036 	thread_t                thread,
1037 	int                                             flavor,
1038 	thread_state_t                  tstate,
1039 	mach_msg_type_number_t  *count,
1040 	thread_set_status_flags_t flags)
1041 {
1042 	return thread_get_state_internal(thread, flavor, tstate, count, flags | TSSF_TRANSLATE_TO_USER);
1043 }
1044 
1045 /*
1046  *	Change thread's machine-dependent userspace TSD base.
1047  *  Called with nothing locked.  Returns same way.
1048  */
1049 kern_return_t
thread_set_tsd_base(thread_t thread,mach_vm_offset_t tsd_base)1050 thread_set_tsd_base(
1051 	thread_t                        thread,
1052 	mach_vm_offset_t        tsd_base)
1053 {
1054 	kern_return_t           result = KERN_SUCCESS;
1055 
1056 	if (thread == THREAD_NULL) {
1057 		return KERN_INVALID_ARGUMENT;
1058 	}
1059 
1060 	thread_mtx_lock(thread);
1061 
1062 	if (thread->active) {
1063 		if (thread != current_thread()) {
1064 			thread_hold(thread);
1065 
1066 			thread_mtx_unlock(thread);
1067 
1068 			if (thread_stop(thread, TRUE)) {
1069 				thread_mtx_lock(thread);
1070 				result = machine_thread_set_tsd_base(thread, tsd_base);
1071 				thread_unstop(thread);
1072 			} else {
1073 				thread_mtx_lock(thread);
1074 				result = KERN_ABORTED;
1075 			}
1076 
1077 			thread_release(thread);
1078 		} else {
1079 			result = machine_thread_set_tsd_base(thread, tsd_base);
1080 		}
1081 	} else {
1082 		result = KERN_TERMINATED;
1083 	}
1084 
1085 	thread_mtx_unlock(thread);
1086 
1087 	return result;
1088 }
1089 
1090 /*
1091  * thread_set_apc_ast:
1092  *
1093  * Register the AST_APC callback that handles suspension and
1094  * termination, if it hasn't been installed already.
1095  *
1096  * Called with the thread mutex held.
1097  */
1098 static void
thread_set_apc_ast(thread_t thread)1099 thread_set_apc_ast(thread_t thread)
1100 {
1101 	spl_t s = splsched();
1102 
1103 	thread_lock(thread);
1104 	thread_set_apc_ast_locked(thread);
1105 	thread_unlock(thread);
1106 
1107 	splx(s);
1108 }
1109 
1110 /*
1111  * thread_set_apc_ast_locked:
1112  *
1113  * Do the work of registering for the AST_APC callback.
1114  *
1115  * Called with the thread mutex and scheduling lock held.
1116  */
1117 static void
thread_set_apc_ast_locked(thread_t thread)1118 thread_set_apc_ast_locked(thread_t thread)
1119 {
1120 	thread_ast_set(thread, AST_APC);
1121 
1122 	if (thread == current_thread()) {
1123 		ast_propagate(thread);
1124 	} else {
1125 		processor_t processor = thread->last_processor;
1126 
1127 		if (processor != PROCESSOR_NULL &&
1128 		    processor->state == PROCESSOR_RUNNING &&
1129 		    processor->active_thread == thread) {
1130 			cause_ast_check(processor);
1131 		}
1132 	}
1133 }
1134 
1135 /*
1136  * Activation control support routines internal to this file:
1137  *
1138  */
1139 
1140 /*
1141  * thread_suspended
1142  *
1143  * Continuation routine for thread suspension.  It checks
1144  * to see whether there has been any new suspensions.  If so, it
1145  * installs the AST_APC handler again.
1146  */
1147 __attribute__((noreturn))
1148 static void
thread_suspended(__unused void * parameter,wait_result_t result)1149 thread_suspended(__unused void *parameter, wait_result_t result)
1150 {
1151 	thread_t thread = current_thread();
1152 
1153 	thread_mtx_lock(thread);
1154 
1155 	if (result == THREAD_INTERRUPTED) {
1156 		thread->suspend_parked = FALSE;
1157 	} else {
1158 		assert(thread->suspend_parked == FALSE);
1159 	}
1160 
1161 	if (thread->suspend_count > 0) {
1162 		thread_set_apc_ast(thread);
1163 	}
1164 
1165 	thread_mtx_unlock(thread);
1166 
1167 	thread_exception_return();
1168 	/*NOTREACHED*/
1169 }
1170 
1171 /*
1172  * thread_apc_ast - handles AST_APC and drives thread suspension and termination.
1173  * Called with nothing locked.  Returns (if it returns) the same way.
1174  */
1175 void
thread_apc_ast(thread_t thread)1176 thread_apc_ast(thread_t thread)
1177 {
1178 	thread_mtx_lock(thread);
1179 
1180 	assert(thread->suspend_parked == FALSE);
1181 
1182 	spl_t s = splsched();
1183 	thread_lock(thread);
1184 
1185 	/* TH_SFLAG_POLLDEPRESS is OK to have here */
1186 	assert((thread->sched_flags & TH_SFLAG_DEPRESS) == 0);
1187 
1188 	thread->sched_flags &= ~TH_SFLAG_ABORTED_MASK;
1189 	thread_unlock(thread);
1190 	splx(s);
1191 
1192 	if (!thread->active) {
1193 		/* Thread is ready to terminate, time to tear it down */
1194 		thread_mtx_unlock(thread);
1195 
1196 		thread_terminate_self();
1197 		/*NOTREACHED*/
1198 	}
1199 
1200 	/* If we're suspended, go to sleep and wait for someone to wake us up. */
1201 	if (thread->suspend_count > 0) {
1202 		thread->suspend_parked = TRUE;
1203 		assert_wait(&thread->suspend_count,
1204 		    THREAD_ABORTSAFE | THREAD_WAIT_NOREPORT_USER);
1205 		thread_mtx_unlock(thread);
1206 
1207 		thread_block(thread_suspended);
1208 		/*NOTREACHED*/
1209 	}
1210 
1211 	thread_mtx_unlock(thread);
1212 }
1213 
1214 #if CONFIG_ROSETTA
1215 extern kern_return_t
1216 exception_deliver(
1217 	thread_t                thread,
1218 	exception_type_t        exception,
1219 	mach_exception_data_t   code,
1220 	mach_msg_type_number_t  codeCnt,
1221 	struct exception_action *excp,
1222 	lck_mtx_t               *mutex);
1223 
1224 kern_return_t
thread_raise_exception(thread_t thread,exception_type_t exception,natural_t code_count,int64_t code,int64_t sub_code)1225 thread_raise_exception(
1226 	thread_t thread,
1227 	exception_type_t exception,
1228 	natural_t code_count,
1229 	int64_t code,
1230 	int64_t sub_code)
1231 {
1232 	task_t task;
1233 
1234 	if (thread == THREAD_NULL) {
1235 		return KERN_INVALID_ARGUMENT;
1236 	}
1237 
1238 	task = get_threadtask(thread);
1239 
1240 	if (task != current_task()) {
1241 		return KERN_FAILURE;
1242 	}
1243 
1244 	if (!task_is_translated(task)) {
1245 		return KERN_FAILURE;
1246 	}
1247 
1248 	if (exception == EXC_CRASH) {
1249 		return KERN_INVALID_ARGUMENT;
1250 	}
1251 
1252 	int64_t codes[] = { code, sub_code };
1253 	host_priv_t host_priv = host_priv_self();
1254 	kern_return_t kr = exception_deliver(thread, exception, codes, code_count, host_priv->exc_actions, &host_priv->lock);
1255 	if (kr != KERN_SUCCESS) {
1256 		return kr;
1257 	}
1258 
1259 	return thread_resume(thread);
1260 }
1261 #endif
1262 
1263 void
thread_debug_return_to_user_ast(thread_t thread)1264 thread_debug_return_to_user_ast(
1265 	thread_t thread)
1266 {
1267 #pragma unused(thread)
1268 #if MACH_ASSERT
1269 	if ((thread->sched_flags & TH_SFLAG_RW_PROMOTED) ||
1270 	    thread->rwlock_count > 0) {
1271 		panic("Returning to userspace with rw lock held, thread %p sched_flag %u rwlock_count %d", thread, thread->sched_flags, thread->rwlock_count);
1272 	}
1273 
1274 	if ((thread->sched_flags & TH_SFLAG_FLOOR_PROMOTED) ||
1275 	    thread->priority_floor_count > 0) {
1276 		panic("Returning to userspace with floor boost set, thread %p sched_flag %u priority_floor_count %d", thread, thread->sched_flags, thread->priority_floor_count);
1277 	}
1278 
1279 	if (thread->th_vm_faults_disabled) {
1280 		panic("Returning to userspace with vm faults disabled, thread %p", thread);
1281 	}
1282 
1283 #if CONFIG_EXCLAVES
1284 	assert3u(thread->th_exclaves_state & TH_EXCLAVES_STATE_ANY, ==, 0);
1285 #endif /* CONFIG_EXCLAVES */
1286 
1287 #endif /* MACH_ASSERT */
1288 }
1289 
1290 
1291 /* Prototype, see justification above */
1292 kern_return_t
1293 act_set_state(
1294 	thread_t                                thread,
1295 	int                                             flavor,
1296 	thread_state_t                  state,
1297 	mach_msg_type_number_t  count);
1298 
1299 kern_return_t
act_set_state(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t count)1300 act_set_state(
1301 	thread_t                                thread,
1302 	int                                             flavor,
1303 	thread_state_t                  state,
1304 	mach_msg_type_number_t  count)
1305 {
1306 	if (thread == current_thread()) {
1307 		return KERN_INVALID_ARGUMENT;
1308 	}
1309 
1310 	return thread_set_state(thread, flavor, state, count);
1311 }
1312 
1313 kern_return_t
act_set_state_from_user(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t count)1314 act_set_state_from_user(
1315 	thread_t                                thread,
1316 	int                                             flavor,
1317 	thread_state_t                  state,
1318 	mach_msg_type_number_t  count)
1319 {
1320 	if (thread == current_thread()) {
1321 		return KERN_INVALID_ARGUMENT;
1322 	}
1323 
1324 	return thread_set_state_from_user(thread, flavor, state, count);
1325 }
1326 
1327 /* Prototype, see justification above */
1328 kern_return_t
1329 act_get_state(
1330 	thread_t                                thread,
1331 	int                                             flavor,
1332 	thread_state_t                  state,
1333 	mach_msg_type_number_t  *count);
1334 
1335 kern_return_t
act_get_state(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t * count)1336 act_get_state(
1337 	thread_t                                thread,
1338 	int                                             flavor,
1339 	thread_state_t                  state,
1340 	mach_msg_type_number_t  *count)
1341 {
1342 	if (thread == current_thread()) {
1343 		return KERN_INVALID_ARGUMENT;
1344 	}
1345 
1346 	return thread_get_state(thread, flavor, state, count);
1347 }
1348 
1349 kern_return_t
act_get_state_to_user(thread_t thread,int flavor,thread_state_t state,mach_msg_type_number_t * count)1350 act_get_state_to_user(
1351 	thread_t                                thread,
1352 	int                                             flavor,
1353 	thread_state_t                  state,
1354 	mach_msg_type_number_t  *count)
1355 {
1356 	if (thread == current_thread()) {
1357 		return KERN_INVALID_ARGUMENT;
1358 	}
1359 
1360 	return thread_get_state_to_user(thread, flavor, state, count);
1361 }
1362 
1363 static void
act_set_ast(thread_t thread,ast_t ast)1364 act_set_ast(
1365 	thread_t   thread,
1366 	ast_t      ast)
1367 {
1368 	spl_t s = splsched();
1369 
1370 	if (thread == current_thread()) {
1371 		thread_ast_set(thread, ast);
1372 		ast_propagate(thread);
1373 	} else {
1374 		processor_t processor;
1375 
1376 		thread_lock(thread);
1377 		thread_ast_set(thread, ast);
1378 		processor = thread->last_processor;
1379 		if (processor != PROCESSOR_NULL &&
1380 		    processor->state == PROCESSOR_RUNNING &&
1381 		    processor->active_thread == thread) {
1382 			cause_ast_check(processor);
1383 		}
1384 		thread_unlock(thread);
1385 	}
1386 
1387 	splx(s);
1388 }
1389 
1390 /*
1391  * set AST on thread without causing an AST check
1392  * and without taking the thread lock
1393  *
1394  * If thread is not the current thread, then it may take
1395  * up until the next context switch or quantum expiration
1396  * on that thread for it to notice the AST.
1397  */
1398 static void
act_set_ast_async(thread_t thread,ast_t ast)1399 act_set_ast_async(thread_t  thread,
1400     ast_t     ast)
1401 {
1402 	thread_ast_set(thread, ast);
1403 
1404 	if (thread == current_thread()) {
1405 		spl_t s = splsched();
1406 		ast_propagate(thread);
1407 		splx(s);
1408 	}
1409 }
1410 
1411 void
act_set_debug_assert(void)1412 act_set_debug_assert(void)
1413 {
1414 	thread_t thread = current_thread();
1415 	if (thread_ast_peek(thread, AST_DEBUG_ASSERT) != AST_DEBUG_ASSERT) {
1416 		thread_ast_set(thread, AST_DEBUG_ASSERT);
1417 	}
1418 	if (ast_peek(AST_DEBUG_ASSERT) != AST_DEBUG_ASSERT) {
1419 		spl_t s = splsched();
1420 		ast_propagate(thread);
1421 		splx(s);
1422 	}
1423 }
1424 
1425 void
act_set_astbsd(thread_t thread)1426 act_set_astbsd(thread_t thread)
1427 {
1428 	act_set_ast(thread, AST_BSD);
1429 }
1430 
1431 void
act_set_astkevent(thread_t thread,uint16_t bits)1432 act_set_astkevent(thread_t thread, uint16_t bits)
1433 {
1434 	os_atomic_or(&thread->kevent_ast_bits, bits, relaxed);
1435 
1436 	/* kevent AST shouldn't send immediate IPIs */
1437 	act_set_ast_async(thread, AST_KEVENT);
1438 }
1439 
1440 uint16_t
act_clear_astkevent(thread_t thread,uint16_t bits)1441 act_clear_astkevent(thread_t thread, uint16_t bits)
1442 {
1443 	/*
1444 	 * avoid the atomic operation if none of the bits is set,
1445 	 * which will be the common case.
1446 	 */
1447 	uint16_t cur = os_atomic_load(&thread->kevent_ast_bits, relaxed);
1448 	if (cur & bits) {
1449 		cur = os_atomic_andnot_orig(&thread->kevent_ast_bits, bits, relaxed);
1450 	}
1451 	return cur & bits;
1452 }
1453 
1454 bool
act_set_ast_reset_pcs(task_t task,thread_t thread)1455 act_set_ast_reset_pcs(task_t task, thread_t thread)
1456 {
1457 	processor_t processor;
1458 	bool needs_wait = false;
1459 	spl_t s;
1460 
1461 	s = splsched();
1462 
1463 	if (thread == current_thread()) {
1464 		/*
1465 		 * this is called from the signal code,
1466 		 * just set the AST and move on
1467 		 */
1468 		thread_ast_set(thread, AST_RESET_PCS);
1469 		ast_propagate(thread);
1470 	} else {
1471 		thread_lock(thread);
1472 
1473 		assert(thread->t_rr_state.trr_ipi_ack_pending == 0);
1474 		assert(thread->t_rr_state.trr_sync_waiting == 0);
1475 
1476 		processor = thread->last_processor;
1477 		if (!thread->active) {
1478 			/*
1479 			 * ->active is being set before the thread is added
1480 			 * to the thread list (under the task lock which
1481 			 * the caller holds), and is reset before the thread
1482 			 * lock is being taken by thread_terminate_self().
1483 			 *
1484 			 * The result is that this will never fail to
1485 			 * set the AST on an thread that is active,
1486 			 * but will not set it past thread_terminate_self().
1487 			 */
1488 		} else if (processor != PROCESSOR_NULL &&
1489 		    processor->state == PROCESSOR_RUNNING &&
1490 		    processor->active_thread == thread) {
1491 			thread->t_rr_state.trr_ipi_ack_pending = true;
1492 			needs_wait = true;
1493 			thread_ast_set(thread, AST_RESET_PCS);
1494 			cause_ast_check(processor);
1495 		} else if (thread_reset_pcs_in_range(task, thread)) {
1496 			if (thread->t_rr_state.trr_fault_state) {
1497 				thread->t_rr_state.trr_fault_state =
1498 				    TRR_FAULT_OBSERVED;
1499 				needs_wait = true;
1500 			}
1501 			thread_ast_set(thread, AST_RESET_PCS);
1502 		}
1503 		thread_unlock(thread);
1504 	}
1505 
1506 	splx(s);
1507 
1508 	return needs_wait;
1509 }
1510 
1511 void
act_set_kperf(thread_t thread)1512 act_set_kperf(thread_t thread)
1513 {
1514 	/* safety check */
1515 	if (thread != current_thread()) {
1516 		if (!ml_get_interrupts_enabled()) {
1517 			panic("unsafe act_set_kperf operation");
1518 		}
1519 	}
1520 
1521 	act_set_ast(thread, AST_KPERF);
1522 }
1523 
1524 #if CONFIG_MACF
1525 void
act_set_astmacf(thread_t thread)1526 act_set_astmacf(
1527 	thread_t        thread)
1528 {
1529 	act_set_ast( thread, AST_MACF);
1530 }
1531 #endif
1532 
1533 void
act_set_astledger(thread_t thread)1534 act_set_astledger(thread_t thread)
1535 {
1536 	act_set_ast(thread, AST_LEDGER);
1537 }
1538 
1539 /*
1540  * The ledger AST may need to be set while already holding
1541  * the thread lock.  This routine skips sending the IPI,
1542  * allowing us to avoid the lock hold.
1543  *
1544  * However, it means the targeted thread must context switch
1545  * to recognize the ledger AST.
1546  */
1547 void
act_set_astledger_async(thread_t thread)1548 act_set_astledger_async(thread_t thread)
1549 {
1550 	act_set_ast_async(thread, AST_LEDGER);
1551 }
1552 
1553 void
act_set_io_telemetry_ast(thread_t thread)1554 act_set_io_telemetry_ast(thread_t thread)
1555 {
1556 	act_set_ast(thread, AST_TELEMETRY_IO);
1557 }
1558 
1559 void
act_set_macf_telemetry_ast(thread_t thread)1560 act_set_macf_telemetry_ast(thread_t thread)
1561 {
1562 	act_set_ast(thread, AST_TELEMETRY_MACF);
1563 }
1564 
1565 void
act_set_astproc_resource(thread_t thread)1566 act_set_astproc_resource(thread_t thread)
1567 {
1568 	act_set_ast(thread, AST_PROC_RESOURCE);
1569 }
1570