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