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