osfmk/kern/thread_act.c

xnu source @ f6217f8 2025-10-16 · 1569 lines · view on GitHub
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 css-dist@cs.utah.edu 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 90static void act_abort(thread_t thread); 91 92static void thread_suspended(void *arg, wait_result_t result); 93static void thread_set_apc_ast(thread_t thread); 94static void thread_set_apc_ast_locked(thread_t thread); 95 96extern boolean_t IOTaskHasEntitlement(task_t task, const char *entitlement); 97 98/* bootarg to create lightweight corpse for thread set state lockdown */ 99TUNABLE(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 104static inline bool 105thread_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 */ 183void 184thread_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 */ 206void 207thread_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 */ 252kern_return_t 253thread_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 290kern_return_t 291thread_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 */ 335kern_return_t 336thread_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 */ 355kern_return_t 356thread_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 */ 373void 374thread_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 */ 395void 396thread_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 416kern_return_t 417thread_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 444kern_return_t 445thread_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 */ 477kern_return_t 478thread_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 */ 506static void 507act_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 526kern_return_t 527thread_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 550kern_return_t 551thread_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 590kern_return_t 591thread_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 617static inline kern_return_t 618thread_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 674kern_return_t 675thread_get_state( 676 thread_t thread, 677 int flavor, 678 thread_state_t state, 679 mach_msg_type_number_t *state_count); 680 681kern_return_t 682thread_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 691kern_return_t 692thread_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 */ 705static inline kern_return_t 706thread_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 768out: 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 */ 775kern_return_t 776thread_set_state( 777 thread_t thread, 778 int flavor, 779 thread_state_t state, 780 mach_msg_type_number_t state_count); 781 782kern_return_t 783thread_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 792kern_return_t 793thread_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 803kern_return_t 804thread_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 */ 871kern_return_t 872thread_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 898kern_return_t 899thread_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 940kern_return_t 941thread_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 */ 995kern_return_t 996thread_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 1005kern_return_t 1006thread_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 */ 1024kern_return_t 1025thread_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 1034kern_return_t 1035thread_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 */ 1049kern_return_t 1050thread_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 */ 1098static void 1099thread_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 */ 1117static void 1118thread_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)) 1148static void 1149thread_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 */ 1175void 1176thread_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 1215extern kern_return_t 1216exception_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 1224kern_return_t 1225thread_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 1263void 1264thread_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 */ 1292kern_return_t 1293act_set_state( 1294 thread_t thread, 1295 int flavor, 1296 thread_state_t state, 1297 mach_msg_type_number_t count); 1298 1299kern_return_t 1300act_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 1313kern_return_t 1314act_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 */ 1328kern_return_t 1329act_get_state( 1330 thread_t thread, 1331 int flavor, 1332 thread_state_t state, 1333 mach_msg_type_number_t *count); 1334 1335kern_return_t 1336act_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 1349kern_return_t 1350act_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 1363static void 1364act_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 */ 1398static void 1399act_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 1411void 1412act_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 1425void 1426act_set_astbsd(thread_t thread) 1427{ 1428 act_set_ast(thread, AST_BSD); 1429} 1430 1431void 1432act_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 1440uint16_t 1441act_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 1454bool 1455act_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 1511void 1512act_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 1525void 1526act_set_astmacf( 1527 thread_t thread) 1528{ 1529 act_set_ast( thread, AST_MACF); 1530} 1531#endif 1532 1533void 1534act_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 */ 1547void 1548act_set_astledger_async(thread_t thread) 1549{ 1550 act_set_ast_async(thread, AST_LEDGER); 1551} 1552 1553void 1554act_set_io_telemetry_ast(thread_t thread) 1555{ 1556 act_set_ast(thread, AST_TELEMETRY_IO); 1557} 1558 1559void 1560act_set_macf_telemetry_ast(thread_t thread) 1561{ 1562 act_set_ast(thread, AST_TELEMETRY_MACF); 1563} 1564 1565void 1566act_set_astproc_resource(thread_t thread) 1567{ 1568 act_set_ast(thread, AST_PROC_RESOURCE); 1569}