osfmk/kern/ipc_tt.c

xnu source @ f6217f8 2025-10-16 · 4982 lines · view on GitHub
1/* 2 * Copyright (c) 2000-2010 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_COPYRIGHT@ 30 */ 31/* 32 * Mach Operating System 33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University 34 * All Rights Reserved. 35 * 36 * Permission to use, copy, modify and distribute this software and its 37 * documentation is hereby granted, provided that both the copyright 38 * notice and this permission notice appear in all copies of the 39 * software, derivative works or modified versions, and any portions 40 * thereof, and that both notices appear in supporting documentation. 41 * 42 * CARNEGIE MELLON ALLOWS FREE USE OF THIS SOFTWARE IN ITS "AS IS" 43 * CONDITION. CARNEGIE MELLON DISCLAIMS ANY LIABILITY OF ANY KIND FOR 44 * ANY DAMAGES WHATSOEVER RESULTING FROM THE USE OF THIS SOFTWARE. 45 * 46 * Carnegie Mellon requests users of this software to return to 47 * 48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU 49 * School of Computer Science 50 * Carnegie Mellon University 51 * Pittsburgh PA 15213-3890 52 * 53 * any improvements or extensions that they make and grant Carnegie Mellon 54 * the rights to redistribute these changes. 55 */ 56/* 57 * NOTICE: This file was modified by McAfee Research in 2004 to introduce 58 * support for mandatory and extensible security protections. This notice 59 * is included in support of clause 2.2 (b) of the Apple Public License, 60 * Version 2.0. 61 */ 62/* 63 */ 64 65/* 66 * File: ipc_tt.c 67 * Purpose: 68 * Task and thread related IPC functions. 69 */ 70 71#include <IOKit/IOBSD.h> // IOTaskHasEntitlement 72 73#include <ipc/ipc_policy.h> 74#include <mach/mach_types.h> 75#include <mach/boolean.h> 76#include <mach/kern_return.h> 77#include <mach/mach_param.h> 78#include <mach/task_special_ports.h> 79#include <mach/thread_special_ports.h> 80#include <mach/thread_status.h> 81#include <mach/exception_types.h> 82#include <mach/memory_object_types.h> 83#include <mach/mach_traps.h> 84#include <mach/task_server.h> 85#include <mach/thread_act_server.h> 86#include <mach/mach_host_server.h> 87#include <mach/host_priv_server.h> 88#include <mach/vm_map_server.h> 89 90#include <kern/exc_guard.h> 91#include <kern/kern_types.h> 92#include <kern/host.h> 93#include <kern/ipc_kobject.h> 94#include <kern/ipc_tt.h> 95#include <kern/kalloc.h> 96#include <kern/thread.h> 97#include <kern/ux_handler.h> 98#include <kern/misc_protos.h> 99#include <kdp/kdp_dyld.h> 100 101#include <sys/proc_ro.h> 102 103#include <vm/vm_map_xnu.h> 104#include <vm/vm_pageout.h> 105#include <vm/vm_protos.h> 106#include <mach/vm_types.h> 107#include <libkern/coreanalytics/coreanalytics.h> 108 109#include <security/mac_mach_internal.h> 110 111#if CONFIG_CSR 112#include <sys/csr.h> 113#endif 114 115#include <sys/code_signing.h> /* for developer mode state */ 116 117#if !defined(XNU_TARGET_OS_OSX) && !SECURE_KERNEL 118extern int cs_relax_platform_task_ports; 119#endif 120 121extern boolean_t IOCurrentTaskHasEntitlement(const char *); 122extern boolean_t proc_is_simulated(const proc_t); 123extern struct proc* current_proc(void); 124 125/* bootarg to create lightweight corpse for thread identity lockdown */ 126TUNABLE(bool, thid_should_crash, "thid_should_crash", true); 127 128/* Allows the process to call `[thread,task]_set_exception_ports */ 129#define SET_EXCEPTION_ENTITLEMENT "com.apple.private.set-exception-port" 130 131/* 132 * Entitlement to disallow setting the exception port of task/thread unless you 133 * are being debugged or are setting up the hardened task exception handler 134 */ 135#define IPC_ONLY_ONE_EXCEPTION_PORT "com.apple.security.only-one-exception-port" 136 137CA_EVENT(set_exception, 138 CA_STATIC_STRING(CA_PROCNAME_LEN), current_proc, 139 CA_STATIC_STRING(CA_PROCNAME_LEN), thread_proc, 140 CA_INT, mask, 141 CA_STATIC_STRING(6), level); 142 143__options_decl(ipc_reply_port_type_t, uint32_t, { 144 IRPT_NONE = 0x00, 145 IRPT_USER = 0x01, 146 IRPT_KERNEL = 0x02, 147}); 148 149/* forward declarations */ 150static kern_return_t special_port_allowed_with_task_flavor(int which, mach_task_flavor_t flavor); 151static kern_return_t special_port_allowed_with_thread_flavor(int which, mach_thread_flavor_t flavor); 152static void ipc_port_bind_special_reply_port_locked(ipc_port_t port, ipc_reply_port_type_t reply_type); 153static void ipc_port_unbind_special_reply_port(thread_t thread, ipc_reply_port_type_t reply_type); 154extern kern_return_t task_conversion_eval(task_t caller, task_t victim, int flavor); 155static thread_inspect_t convert_port_to_thread_inspect_no_eval(ipc_port_t port); 156static ipc_port_t convert_thread_to_port_with_flavor(thread_t, thread_ro_t, mach_thread_flavor_t flavor); 157ipc_port_t convert_task_to_port_with_flavor(task_t task, mach_task_flavor_t flavor, task_grp_t grp); 158kern_return_t task_set_special_port(task_t task, int which, ipc_port_t port); 159kern_return_t task_get_special_port(task_t task, int which, ipc_port_t *portp); 160 161/* 162 * Routine: ipc_task_init 163 * Purpose: 164 * Initialize a task's IPC state. 165 * 166 * If non-null, some state will be inherited from the parent. 167 * The parent must be appropriately initialized. 168 * Conditions: 169 * Nothing locked. 170 */ 171 172void 173ipc_task_init( 174 task_t task, 175 task_t parent) 176{ 177 ipc_space_t space; 178 ipc_port_t kport; 179 ipc_port_t nport; 180 kern_return_t kr; 181 struct label *temp_label; 182 int i; 183 184 185 kr = ipc_space_create(IPC_LABEL_NONE, &space); 186 if (kr != KERN_SUCCESS) { 187 panic("ipc_task_init"); 188 } 189 190 space->is_task = task; 191 192 kport = ipc_kobject_alloc_port(IKO_NULL, IKOT_TASK_CONTROL, 193 IPC_KOBJECT_ALLOC_NONE); 194 195 nport = ipc_kobject_alloc_port(IKO_NULL, IKOT_TASK_NAME, 196 IPC_KOBJECT_ALLOC_NONE); 197 198 itk_lock_init(task); 199 task->itk_task_ports[TASK_FLAVOR_CONTROL] = kport; 200 task->itk_task_ports[TASK_FLAVOR_NAME] = nport; 201 202 /* Lazily allocated on-demand */ 203 task->itk_task_ports[TASK_FLAVOR_INSPECT] = IP_NULL; 204 task->itk_task_ports[TASK_FLAVOR_READ] = IP_NULL; 205 task->itk_dyld_notify = NULL; 206#if CONFIG_PROC_RESOURCE_LIMITS 207 task->itk_resource_notify = NULL; 208#endif /* CONFIG_PROC_RESOURCE_LIMITS */ 209 210 task->itk_resume = IP_NULL; /* Lazily allocated on-demand */ 211#if CONFIG_CSR 212 if (task_is_a_corpse_fork(task)) { 213 /* 214 * No sender's notification for corpse would not 215 * work with a naked send right in kernel. 216 */ 217 task->itk_settable_self = IP_NULL; 218 } else { 219 /* we just made the port, no need to triple check */ 220 task->itk_settable_self = ipc_port_make_send_any(kport); 221 } 222#endif /* CONFIG_CSR */ 223 task->itk_debug_control = IP_NULL; 224 task->itk_space = space; 225 226#if CONFIG_MACF 227 task->exc_actions[0].label = NULL; 228 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 229 mac_exc_associate_action_label(&task->exc_actions[i], 230 mac_exc_create_label(&task->exc_actions[i])); 231 } 232#endif 233 234 /* always zero-out the first (unused) array element */ 235 bzero(&task->exc_actions[0], sizeof(task->exc_actions[0])); 236 /* We don't need to inherit this */ 237 bzero(&task->hardened_exception_action, sizeof(task->hardened_exception_action)); 238 239 if (parent == TASK_NULL) { 240 ipc_port_t port = IP_NULL; 241 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 242 task->exc_actions[i].port = IP_NULL; 243 task->exc_actions[i].flavor = 0; 244 task->exc_actions[i].behavior = 0; 245 task->exc_actions[i].privileged = FALSE; 246 }/* for */ 247 248 kr = host_get_host_port(host_priv_self(), &port); 249 assert(kr == KERN_SUCCESS); 250 task->itk_host = port; 251 252 task->itk_bootstrap = IP_NULL; 253 task->itk_task_access = IP_NULL; 254 255 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) { 256 task->itk_registered[i] = IP_NULL; 257 } 258 } else { 259 itk_lock(parent); 260 assert(parent->itk_task_ports[TASK_FLAVOR_CONTROL] != IP_NULL); 261 262 /* inherit registered ports */ 263 264 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) { 265 task->itk_registered[i] = 266 ipc_port_copy_send_any(parent->itk_registered[i]); 267 } 268 269 /* inherit exception and bootstrap ports */ 270 271 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 272 temp_label = task->exc_actions[i].label; 273 task->exc_actions[i] = parent->exc_actions[i]; 274 task->exc_actions[i].port = 275 exception_port_copy_send(parent->exc_actions[i].port); 276 task->exc_actions[i].label = temp_label; 277#if CONFIG_MACF 278 mac_exc_inherit_action_label(parent->exc_actions + i, 279 task->exc_actions + i); 280#endif 281 } 282 283 task->itk_host = host_port_copy_send(parent->itk_host); 284 285 task->itk_bootstrap = 286 ipc_port_copy_send_mqueue(parent->itk_bootstrap); 287 288 task->itk_task_access = 289 ipc_port_copy_send_mqueue(parent->itk_task_access); 290 291 itk_unlock(parent); 292 } 293} 294 295/* 296 * Routine: ipc_task_copyout_control_port 297 * Purpose: 298 * Copyout the task control port as pinned 299 * and stash the send right name in the port 300 */ 301void 302ipc_task_copyout_control_port( 303 task_t task) 304{ 305 ipc_port_t kport = task->itk_task_ports[TASK_FLAVOR_CONTROL]; 306 mach_port_name_t name; 307 ipc_port_t pport; 308 309#if CONFIG_CSR 310 assert(kport == task->itk_settable_self); 311#endif /* CONFIG_CSR */ 312 assert(!task_is_a_corpse(task)); 313 314 pport = ipc_port_make_send_any(kport); 315 /* 316 * mach_task_self() is pinned, memorize the name we gave it 317 * in ip_receiver_name (it's an abuse as this port really 318 * isn't a message queue, but the field is up for grabs 319 * and otherwise `MACH_PORT_SPECIAL_DEFAULT` for special ports). 320 * 321 * port_name_to_task* use this to fastpath IPCs. 322 * 323 * ipc_task_disable() will revert this when the task dies. 324 */ 325 name = ipc_port_copyout_send_pinned(pport, task->itk_space); 326 if (MACH_PORT_VALID(name)) { 327 pport->ip_receiver_name = name; 328 } 329} 330 331/* 332 * Routine: ipc_thread_set_immovable_pinned 333 * Purpose: 334 * Copyout the task control port as pinned and immovable 335 * and stash the send right name in the port 336 * Notes: 337 * Consumes a thread ref; produces a naked send right 338 * which may be invalid. 339 */ 340void 341ipc_thread_set_immovable_pinned( 342 thread_t thread) 343{ 344 ipc_port_t kport = convert_thread_to_port_immovable(thread); 345 346 task_t task = get_threadtask(thread); 347 mach_port_name_t name; 348 349#if CONFIG_CSR 350 assert(kport == thread->t_tro->tro_settable_self_port); 351#endif /* CONFIG_CSR */ 352 assert(!task_is_a_corpse(task)); 353 354 name = ipc_port_copyout_send_pinned(kport, task->itk_space); 355} 356 357/* 358 * Routine: ipc_task_enable 359 * Purpose: 360 * Enable a task for IPC access. 361 * Conditions: 362 * Nothing locked. 363 */ 364void 365ipc_task_enable( 366 task_t task) 367{ 368 ipc_port_t kport; 369 ipc_port_t nport; 370 ipc_port_t iport; 371 ipc_port_t rdport; 372 373 ipc_space_set_policy(task->itk_space, ipc_policy_for_task(task)); 374 375 itk_lock(task); 376 if (!task->active) { 377 /* 378 * task has been terminated before we can enable IPC access. 379 * The check is to make sure we don't accidentally re-enable 380 * the task ports _after_ they've been disabled during 381 * task_terminate_internal(), in which case we will hit the 382 * !task->ipc_active assertion in ipc_task_terminate(). 383 * 384 * Technically we should grab task lock when checking task 385 * active bit, but since task termination unsets task->active 386 * _before_ calling ipc_task_disable(), we can always see the 387 * truth with just itk_lock() and bail if disable has been called. 388 */ 389 itk_unlock(task); 390 return; 391 } 392 393 assert(task_is_a_corpse(task) || task->map->owning_task == task); /* verify vm_map_setup called */ 394 assert(!task->ipc_active || task_is_a_corpse(task)); 395 task->ipc_active = true; 396 397 kport = task->itk_task_ports[TASK_FLAVOR_CONTROL]; 398 if (kport != IP_NULL) { 399 ipc_kobject_enable(kport, task, IKOT_TASK_CONTROL); 400 } 401 nport = task->itk_task_ports[TASK_FLAVOR_NAME]; 402 if (nport != IP_NULL) { 403 ipc_kobject_enable(nport, task, IKOT_TASK_NAME); 404 } 405 iport = task->itk_task_ports[TASK_FLAVOR_INSPECT]; 406 if (iport != IP_NULL) { 407 ipc_kobject_enable(iport, task, IKOT_TASK_INSPECT); 408 } 409 rdport = task->itk_task_ports[TASK_FLAVOR_READ]; 410 if (rdport != IP_NULL) { 411 ipc_kobject_enable(rdport, task, IKOT_TASK_READ); 412 } 413 414 itk_unlock(task); 415} 416 417/* 418 * Routine: ipc_task_disable 419 * Purpose: 420 * Disable IPC access to a task. 421 * Conditions: 422 * Nothing locked. 423 */ 424 425void 426ipc_task_disable( 427 task_t task) 428{ 429 ipc_port_t kport; 430 ipc_port_t nport; 431 ipc_port_t iport; 432 ipc_port_t rdport; 433 ipc_port_t rport; 434 435 itk_lock(task); 436 437 /* 438 * This innocuous looking line is load bearing. 439 * 440 * It is used to disable the creation of lazy made ports. 441 * We must do so before we drop the last reference on the task, 442 * as task ports do not own a reference on the task, and 443 * convert_port_to_task* will crash trying to resurect a task. 444 */ 445 task->ipc_active = false; 446 447 kport = task->itk_task_ports[TASK_FLAVOR_CONTROL]; 448 if (kport != IP_NULL) { 449 ipc_kobject_disable(kport, IKOT_TASK_CONTROL); 450 } 451 nport = task->itk_task_ports[TASK_FLAVOR_NAME]; 452 if (nport != IP_NULL) { 453 ipc_kobject_disable(nport, IKOT_TASK_NAME); 454 } 455 iport = task->itk_task_ports[TASK_FLAVOR_INSPECT]; 456 if (iport != IP_NULL) { 457 ipc_kobject_disable(iport, IKOT_TASK_INSPECT); 458 } 459 rdport = task->itk_task_ports[TASK_FLAVOR_READ]; 460 if (rdport != IP_NULL) { 461 /* clears ikol_alt_port */ 462 ipc_kobject_disable(rdport, IKOT_TASK_READ); 463 } 464 465 rport = task->itk_resume; 466 if (rport != IP_NULL) { 467 /* 468 * From this point onwards this task is no longer accepting 469 * resumptions. 470 * 471 * There are still outstanding suspensions on this task, 472 * even as it is being torn down. Disconnect the task 473 * from the rport, thereby "orphaning" the rport. The rport 474 * itself will go away only when the last suspension holder 475 * destroys his SO right to it -- when he either 476 * exits, or tries to actually use that last SO right to 477 * resume this (now non-existent) task. 478 */ 479 ipc_kobject_disable(rport, IKOT_TASK_RESUME); 480 } 481 itk_unlock(task); 482} 483 484/* 485 * Routine: ipc_task_terminate 486 * Purpose: 487 * Clean up and destroy a task's IPC state. 488 * Conditions: 489 * Nothing locked. The task must be suspended. 490 * (Or the current thread must be in the task.) 491 */ 492 493void 494ipc_task_terminate( 495 task_t task) 496{ 497 ipc_port_t kport; 498 ipc_port_t nport; 499 ipc_port_t iport; 500 ipc_port_t rdport; 501 ipc_port_t rport; 502#if CONFIG_CSR 503 ipc_port_t sself; 504#endif /* CONFIG_CSR */ 505 ipc_port_t *notifiers_ptr = NULL; 506 507 itk_lock(task); 508 509 /* 510 * If we ever failed to clear ipc_active before the last reference 511 * was dropped, lazy ports might be made and used after the last 512 * reference is dropped and cause use after free (see comment in 513 * ipc_task_disable()). 514 */ 515 assert(!task->ipc_active); 516 517 kport = task->itk_task_ports[TASK_FLAVOR_CONTROL]; 518#if CONFIG_CSR 519 sself = task->itk_settable_self; 520#endif /* CONFIG_CSR */ 521 522 if (kport == IP_NULL) { 523 /* the task is already terminated (can this happen?) */ 524 itk_unlock(task); 525 return; 526 } 527 task->itk_task_ports[TASK_FLAVOR_CONTROL] = IP_NULL; 528 529 rdport = task->itk_task_ports[TASK_FLAVOR_READ]; 530 task->itk_task_ports[TASK_FLAVOR_READ] = IP_NULL; 531 532 iport = task->itk_task_ports[TASK_FLAVOR_INSPECT]; 533 task->itk_task_ports[TASK_FLAVOR_INSPECT] = IP_NULL; 534 535 nport = task->itk_task_ports[TASK_FLAVOR_NAME]; 536 assert(nport != IP_NULL); 537 task->itk_task_ports[TASK_FLAVOR_NAME] = IP_NULL; 538 539 if (task->itk_dyld_notify) { 540 notifiers_ptr = task->itk_dyld_notify; 541 task->itk_dyld_notify = NULL; 542 } 543 544 rport = task->itk_resume; 545 task->itk_resume = IP_NULL; 546 547 itk_unlock(task); 548 549 /* release the naked send rights */ 550#if CONFIG_CSR 551 if (IP_VALID(sself)) { 552 ipc_port_release_send(sself); 553 } 554#endif /* CONFIG_CSR */ 555 556 if (notifiers_ptr) { 557 for (int i = 0; i < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; i++) { 558 if (IP_VALID(notifiers_ptr[i])) { 559 ipc_port_release_send(notifiers_ptr[i]); 560 } 561 } 562 kfree_type(ipc_port_t, DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT, notifiers_ptr); 563 } 564 565 if (IP_VALID(task->hardened_exception_action.ea.port)) { 566 ipc_port_release_send(task->hardened_exception_action.ea.port); 567 } 568 569 for (int i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 570 if (IP_VALID(task->exc_actions[i].port)) { 571 ipc_port_release_send(task->exc_actions[i].port); 572 } 573#if CONFIG_MACF 574 mac_exc_free_action_label(task->exc_actions + i); 575#endif 576 } 577 578 if (IP_VALID(task->itk_host)) { 579 ipc_port_release_send(task->itk_host); 580 } 581 582 if (IP_VALID(task->itk_bootstrap)) { 583 ipc_port_release_send(task->itk_bootstrap); 584 } 585 586 if (IP_VALID(task->itk_task_access)) { 587 ipc_port_release_send(task->itk_task_access); 588 } 589 590 if (IP_VALID(task->itk_debug_control)) { 591 ipc_port_release_send(task->itk_debug_control); 592 } 593 594#if CONFIG_PROC_RESOURCE_LIMITS 595 if (IP_VALID(task->itk_resource_notify)) { 596 ipc_port_release_send(task->itk_resource_notify); 597 } 598#endif /* CONFIG_PROC_RESOURCE_LIMITS */ 599 600 for (int i = 0; i < TASK_PORT_REGISTER_MAX; i++) { 601 if (IP_VALID(task->itk_registered[i])) { 602 ipc_port_release_send(task->itk_registered[i]); 603 } 604 } 605 606 /* clears read port ikol_alt_port, must be done first */ 607 if (rdport != IP_NULL) { 608 ipc_kobject_dealloc_port(rdport, IPC_KOBJECT_NO_MSCOUNT, 609 IKOT_TASK_READ); 610 } 611 ipc_kobject_dealloc_port(kport, IPC_KOBJECT_NO_MSCOUNT, 612 IKOT_TASK_CONTROL); 613 614 /* destroy other kernel ports */ 615 ipc_kobject_dealloc_port(nport, IPC_KOBJECT_NO_MSCOUNT, 616 IKOT_TASK_NAME); 617 if (iport != IP_NULL) { 618 ipc_kobject_dealloc_port(iport, IPC_KOBJECT_NO_MSCOUNT, 619 IKOT_TASK_INSPECT); 620 } 621 if (rport != IP_NULL) { 622 ipc_kobject_dealloc_port(rport, IPC_KOBJECT_NO_MSCOUNT, 623 IKOT_TASK_RESUME); 624 } 625 626 itk_lock_destroy(task); 627} 628 629/* 630 * Routine: ipc_task_reset 631 * Purpose: 632 * Reset a task's IPC state to protect it when 633 * it enters an elevated security context. The 634 * task name port can remain the same - since it 635 * represents no specific privilege. 636 * Conditions: 637 * Nothing locked. The task must be suspended. 638 * (Or the current thread must be in the task.) 639 */ 640 641void 642ipc_task_reset( 643 task_t task) 644{ 645 ipc_port_t old_kport, new_kport; 646#if CONFIG_CSR 647 ipc_port_t old_sself; 648#endif /* CONFIG_CSR */ 649 ipc_port_t old_rdport; 650 ipc_port_t old_iport; 651 ipc_port_t old_exc_actions[EXC_TYPES_COUNT]; 652 ipc_port_t old_hardened_exception; 653 ipc_port_t *notifiers_ptr = NULL; 654 655#if CONFIG_MACF 656 /* Fresh label to unset credentials in existing labels. */ 657 struct label *unset_label = mac_exc_create_label(NULL); 658#endif 659 660 new_kport = ipc_kobject_alloc_port((ipc_kobject_t)task, 661 IKOT_TASK_CONTROL, IPC_KOBJECT_ALLOC_NONE); 662 /* 663 * ipc_task_reset() only happens during sugid or corpsify. 664 * 665 * (1) sugid happens early in exec_mach_imgact(), 666 * at which point the old task port has not been enabled, 667 * and is left movable. 668 * (2) corpse cannot execute more code so the notion of the immovable 669 * task port is bogus, and should appear as if it doesn't have one. 670 * 671 */ 672 itk_lock(task); 673 674 old_kport = task->itk_task_ports[TASK_FLAVOR_CONTROL]; 675 old_rdport = task->itk_task_ports[TASK_FLAVOR_READ]; 676 old_iport = task->itk_task_ports[TASK_FLAVOR_INSPECT]; 677 678 if (old_kport == IP_NULL) { 679 /* the task is already terminated (can this happen?) */ 680 itk_unlock(task); 681 ipc_kobject_dealloc_port(new_kport, IPC_KOBJECT_NO_MSCOUNT, IKOT_TASK_CONTROL); 682#if CONFIG_MACF 683 mac_exc_free_label(unset_label); 684#endif 685 return; 686 } 687 688 task->itk_task_ports[TASK_FLAVOR_CONTROL] = new_kport; 689 690#if CONFIG_CSR 691 old_sself = task->itk_settable_self; 692 if (task_is_a_corpse(task)) { 693 /* No extra send right for coprse, needed to arm no-sender notification */ 694 task->itk_settable_self = IP_NULL; 695 } else { 696 /* we just made the port, no need to triple check */ 697 task->itk_settable_self = ipc_port_make_send_any(new_kport); 698 } 699#endif /* CONFIG_CSR */ 700 701 ipc_kobject_disable(old_kport, IKOT_TASK_CONTROL); 702 703 /* Reset the read and inspect flavors of task port */ 704 task->itk_task_ports[TASK_FLAVOR_READ] = IP_NULL; 705 task->itk_task_ports[TASK_FLAVOR_INSPECT] = IP_NULL; 706 707 if (IP_VALID(task->hardened_exception_action.ea.port) 708 && !task->hardened_exception_action.ea.privileged) { 709 old_hardened_exception = task->hardened_exception_action.ea.port; 710 task->hardened_exception_action.ea.port = IP_NULL; 711 } 712 713 for (int i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 714 old_exc_actions[i] = IP_NULL; 715 716 if (i == EXC_CORPSE_NOTIFY && task_corpse_pending_report(task)) { 717 continue; 718 } 719 720 if (!task->exc_actions[i].privileged) { 721#if CONFIG_MACF 722 mac_exc_update_action_label(task->exc_actions + i, unset_label); 723#endif 724 old_exc_actions[i] = task->exc_actions[i].port; 725 task->exc_actions[i].port = IP_NULL; 726 } 727 }/* for */ 728 729 if (IP_VALID(task->itk_debug_control)) { 730 ipc_port_release_send(task->itk_debug_control); 731 } 732 task->itk_debug_control = IP_NULL; 733 734 if (task->itk_dyld_notify) { 735 notifiers_ptr = task->itk_dyld_notify; 736 task->itk_dyld_notify = NULL; 737 } 738 739 itk_unlock(task); 740 741#if CONFIG_MACF 742 mac_exc_free_label(unset_label); 743#endif 744 745 /* release the naked send rights */ 746#if CONFIG_CSR 747 if (IP_VALID(old_sself)) { 748 ipc_port_release_send(old_sself); 749 } 750#endif /* CONFIG_CSR */ 751 752 if (notifiers_ptr) { 753 for (int i = 0; i < DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT; i++) { 754 if (IP_VALID(notifiers_ptr[i])) { 755 ipc_port_release_send(notifiers_ptr[i]); 756 } 757 } 758 kfree_type(ipc_port_t, DYLD_MAX_PROCESS_INFO_NOTIFY_COUNT, notifiers_ptr); 759 } 760 761 ipc_port_release_send(old_hardened_exception); 762 763 for (int i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 764 if (IP_VALID(old_exc_actions[i])) { 765 ipc_port_release_send(old_exc_actions[i]); 766 } 767 } 768 769 /* destroy all task port flavors */ 770 if (old_rdport != IP_NULL) { 771 /* read port ikol_alt_port may point to kport, dealloc first */ 772 ipc_kobject_dealloc_port(old_rdport, IPC_KOBJECT_NO_MSCOUNT, 773 IKOT_TASK_READ); 774 } 775 ipc_kobject_dealloc_port(old_kport, IPC_KOBJECT_NO_MSCOUNT, 776 IKOT_TASK_CONTROL); 777 778 if (old_iport != IP_NULL) { 779 ipc_kobject_dealloc_port(old_iport, IPC_KOBJECT_NO_MSCOUNT, 780 IKOT_TASK_INSPECT); 781 } 782} 783 784/* 785 * Routine: ipc_thread_init 786 * Purpose: 787 * Initialize a thread's IPC state. 788 * Conditions: 789 * Nothing locked. 790 */ 791 792void 793ipc_thread_init( 794 __unused task_t task, 795 thread_t thread, 796 thread_ro_t tro) 797{ 798 ipc_port_t kport; 799 800 /* 801 * pthreads are subsequently pinned via 802 * ipc_port_copyout_send_pinned() whereas raw threads are left 803 * unpinned. 804 */ 805 kport = ipc_kobject_alloc_port(thread, IKOT_THREAD_CONTROL, 806 IPC_KOBJECT_ALLOC_NONE); 807 808 /* we just made the port, no need to triple check */ 809#if CONFIG_CSR 810 tro->tro_settable_self_port = ipc_port_make_send_any(kport); 811#endif /* CONFIG_CSR */ 812 tro->tro_ports[THREAD_FLAVOR_CONTROL] = kport; 813 814 thread->ith_special_reply_port = NULL; 815 816#if IMPORTANCE_INHERITANCE 817 thread->ith_assertions = 0; 818#endif 819 820 thread->ipc_active = true; 821 ipc_kmsg_queue_init(&thread->ith_messages); 822 823 thread->ith_kernel_reply_port = IP_NULL; 824} 825 826struct thread_init_exc_actions { 827 struct exception_action array[EXC_TYPES_COUNT]; 828}; 829 830static void 831ipc_thread_init_exc_actions(thread_ro_t tro) 832{ 833 struct exception_action *actions; 834 835 actions = kalloc_type(struct thread_init_exc_actions, 836 Z_WAITOK | Z_ZERO | Z_NOFAIL)->array; 837 838#if CONFIG_MACF 839 for (size_t i = 0; i < EXC_TYPES_COUNT; ++i) { 840 mac_exc_associate_action_label(&actions[i], 841 mac_exc_create_label(&actions[i])); 842 } 843#endif 844 845 zalloc_ro_update_field(ZONE_ID_THREAD_RO, tro, tro_exc_actions, &actions); 846} 847 848static void 849ipc_thread_destroy_exc_actions(thread_ro_t tro) 850{ 851 struct exception_action *actions = tro->tro_exc_actions; 852 853 if (actions) { 854#if CONFIG_MACF 855 for (size_t i = 0; i < EXC_TYPES_COUNT; ++i) { 856 mac_exc_free_action_label(actions + i); 857 } 858#endif 859 860 zalloc_ro_clear_field(ZONE_ID_THREAD_RO, tro, tro_exc_actions); 861 struct thread_init_exc_actions *tr_actions = 862 (struct thread_init_exc_actions *)actions; 863 kfree_type(struct thread_init_exc_actions, tr_actions); 864 } 865} 866 867static void 868ipc_thread_ro_update_ports( 869 thread_ro_t tro, 870 const struct thread_ro *tro_tpl) 871{ 872 vm_size_t offs = offsetof(struct thread_ro, tro_ports); 873 vm_size_t size = sizeof(tro_tpl->tro_ports) 874#if CONFIG_CSR 875 + sizeof(struct ipc_port *); 876#else 877 ; 878#endif /* CONFIG_CSR */ 879 880#if CONFIG_CSR 881 static_assert(offsetof(struct thread_ro, tro_settable_self_port) == 882 offsetof(struct thread_ro, tro_ports) + 883 sizeof(tro_tpl->tro_ports)); 884#endif /* CONFIG_CSR */ 885 886 zalloc_ro_mut(ZONE_ID_THREAD_RO, tro, 887 offs, &tro_tpl->tro_ports, size); 888} 889 890/* 891 * Routine: ipc_thread_disable 892 * Purpose: 893 * Clean up and destroy a thread's IPC state. 894 * Conditions: 895 * Thread locked. 896 */ 897void 898ipc_thread_disable( 899 thread_t thread) 900{ 901 thread_ro_t tro = get_thread_ro(thread); 902 ipc_port_t kport = tro->tro_ports[THREAD_FLAVOR_CONTROL]; 903 ipc_port_t iport = tro->tro_ports[THREAD_FLAVOR_INSPECT]; 904 ipc_port_t rdport = tro->tro_ports[THREAD_FLAVOR_READ]; 905 906 /* 907 * This innocuous looking line is load bearing. 908 * 909 * It is used to disable the creation of lazy made ports. 910 * We must do so before we drop the last reference on the thread, 911 * as thread ports do not own a reference on the thread, and 912 * convert_port_to_thread* will crash trying to resurect a thread. 913 */ 914 thread->ipc_active = false; 915 916 if (kport != IP_NULL) { 917 ipc_kobject_disable(kport, IKOT_THREAD_CONTROL); 918 } 919 920 if (iport != IP_NULL) { 921 ipc_kobject_disable(iport, IKOT_THREAD_INSPECT); 922 } 923 924 if (rdport != IP_NULL) { 925 /* clears ikol_alt_port */ 926 ipc_kobject_disable(rdport, IKOT_THREAD_READ); 927 } 928 929 /* unbind the thread special reply port */ 930 if (IP_VALID(thread->ith_special_reply_port)) { 931 ipc_port_unbind_special_reply_port(thread, IRPT_USER); 932 } 933} 934 935/* 936 * Routine: ipc_thread_terminate 937 * Purpose: 938 * Clean up and destroy a thread's IPC state. 939 * Conditions: 940 * Nothing locked. 941 */ 942 943void 944ipc_thread_terminate( 945 thread_t thread) 946{ 947 thread_ro_t tro = get_thread_ro(thread); 948 ipc_port_t kport = IP_NULL; 949 ipc_port_t iport = IP_NULL; 950 ipc_port_t rdport = IP_NULL; 951#if CONFIG_CSR 952 ipc_port_t sport = IP_NULL; 953#endif /* CONFIG_CSR */ 954 955 thread_mtx_lock(thread); 956 957 /* 958 * If we ever failed to clear ipc_active before the last reference 959 * was dropped, lazy ports might be made and used after the last 960 * reference is dropped and cause use after free (see comment in 961 * ipc_thread_disable()). 962 */ 963 assert(!thread->ipc_active); 964 965 kport = tro->tro_ports[THREAD_FLAVOR_CONTROL]; 966 iport = tro->tro_ports[THREAD_FLAVOR_INSPECT]; 967 rdport = tro->tro_ports[THREAD_FLAVOR_READ]; 968#if CONFIG_CSR 969 sport = tro->tro_settable_self_port; 970#endif /* CONFIG_CSR */ 971 972 if (kport != IP_NULL) { 973#if CONFIG_CSR 974 if (IP_VALID(sport)) { 975 ipc_port_release_send(sport); 976 } 977#endif /* CONFIG_CSR */ 978 979 ipc_thread_ro_update_ports(tro, &(struct thread_ro){ }); 980 981 if (tro->tro_exc_actions != NULL) { 982 for (int i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 983 if (IP_VALID(tro->tro_exc_actions[i].port)) { 984 ipc_port_release_send(tro->tro_exc_actions[i].port); 985 } 986 } 987 ipc_thread_destroy_exc_actions(tro); 988 } 989 } 990 991#if IMPORTANCE_INHERITANCE 992 assert(thread->ith_assertions == 0); 993#endif 994 995 assert(ipc_kmsg_queue_empty(&thread->ith_messages)); 996 thread_mtx_unlock(thread); 997 998 /* clears read port ikol_alt_port, must be done first */ 999 if (rdport != IP_NULL) { 1000 ipc_kobject_dealloc_port(rdport, IPC_KOBJECT_NO_MSCOUNT, 1001 IKOT_THREAD_READ); 1002 } 1003 1004 if (kport != IP_NULL) { 1005 ipc_kobject_dealloc_port(kport, IPC_KOBJECT_NO_MSCOUNT, 1006 IKOT_THREAD_CONTROL); 1007 } 1008 if (iport != IP_NULL) { 1009 ipc_kobject_dealloc_port(iport, IPC_KOBJECT_NO_MSCOUNT, 1010 IKOT_THREAD_INSPECT); 1011 } 1012 if (thread->ith_kernel_reply_port != IP_NULL) { 1013 thread_dealloc_kernel_special_reply_port(thread); 1014 } 1015} 1016 1017/* 1018 * Routine: ipc_thread_reset 1019 * Purpose: 1020 * Reset the IPC state for a given Mach thread when 1021 * its task enters an elevated security context. 1022 * All flavors of thread port and its exception ports have 1023 * to be reset. Its RPC reply port cannot have any 1024 * rights outstanding, so it should be fine. The thread 1025 * inspect and read port are set to NULL. 1026 * Conditions: 1027 * Nothing locked. 1028 */ 1029 1030void 1031ipc_thread_reset( 1032 thread_t thread) 1033{ 1034 thread_ro_t tro = get_thread_ro(thread); 1035 ipc_port_t old_kport, new_kport; 1036#if CONFIG_CSR 1037 ipc_port_t old_sself; 1038#endif /* CONFIG_CSR */ 1039 ipc_port_t old_rdport; 1040 ipc_port_t old_iport; 1041 ipc_port_t old_exc_actions[EXC_TYPES_COUNT]; 1042 boolean_t has_old_exc_actions = FALSE; 1043 int i; 1044 1045#if CONFIG_MACF 1046 struct label *new_label = mac_exc_create_label(NULL); 1047#endif 1048 1049 new_kport = ipc_kobject_alloc_port((ipc_kobject_t)thread, 1050 IKOT_THREAD_CONTROL, IPC_KOBJECT_ALLOC_NONE); 1051 /* 1052 * ipc_thread_reset() only happens during sugid or corpsify. 1053 * 1054 * (1) sugid happens early in exec_mach_imgact(), at which point 1055 * the old thread port is still movable. 1056 * (2) corpse cannot execute more code so the notion of the immovable 1057 * thread port is bogus, and should appear as if it doesn't have one. 1058 */ 1059 1060 thread_mtx_lock(thread); 1061 1062 old_kport = tro->tro_ports[THREAD_FLAVOR_CONTROL]; 1063 old_rdport = tro->tro_ports[THREAD_FLAVOR_READ]; 1064 old_iport = tro->tro_ports[THREAD_FLAVOR_INSPECT]; 1065 1066#if CONFIG_CSR 1067 old_sself = tro->tro_settable_self_port; 1068#endif /* CONFIG_CSR */ 1069 1070 if (old_kport == IP_NULL && thread->inspection == FALSE) { 1071 /* thread is already terminated (can this happen?) */ 1072 thread_mtx_unlock(thread); 1073 ipc_kobject_dealloc_port(new_kport, IPC_KOBJECT_NO_MSCOUNT, 1074 IKOT_THREAD_CONTROL); 1075#if CONFIG_MACF 1076 mac_exc_free_label(new_label); 1077#endif 1078 return; 1079 } 1080 1081 thread->ipc_active = true; 1082 1083 struct thread_ro tpl = { 1084 .tro_ports[THREAD_FLAVOR_CONTROL] = new_kport, 1085 /* we just made the port, no need to triple check */ 1086#if CONFIG_CSR 1087 .tro_settable_self_port = ipc_port_make_send_any(new_kport), 1088#endif /* CONFIG_CSR */ 1089 }; 1090 1091 ipc_thread_ro_update_ports(tro, &tpl); 1092 1093 if (old_kport != IP_NULL) { 1094 (void)ipc_kobject_disable(old_kport, IKOT_THREAD_CONTROL); 1095 } 1096 if (old_rdport != IP_NULL) { 1097 /* clears ikol_alt_port */ 1098 (void)ipc_kobject_disable(old_rdport, IKOT_THREAD_READ); 1099 } 1100 if (old_iport != IP_NULL) { 1101 (void)ipc_kobject_disable(old_iport, IKOT_THREAD_INSPECT); 1102 } 1103 1104 /* 1105 * Only ports that were set by root-owned processes 1106 * (privileged ports) should survive 1107 */ 1108 if (tro->tro_exc_actions != NULL) { 1109 has_old_exc_actions = TRUE; 1110 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 1111 if (tro->tro_exc_actions[i].privileged) { 1112 old_exc_actions[i] = IP_NULL; 1113 } else { 1114#if CONFIG_MACF 1115 mac_exc_update_action_label(tro->tro_exc_actions + i, new_label); 1116#endif 1117 old_exc_actions[i] = tro->tro_exc_actions[i].port; 1118 tro->tro_exc_actions[i].port = IP_NULL; 1119 } 1120 } 1121 } 1122 1123 thread_mtx_unlock(thread); 1124 1125#if CONFIG_MACF 1126 mac_exc_free_label(new_label); 1127#endif 1128 1129 /* release the naked send rights */ 1130#if CONFIG_CSR 1131 if (IP_VALID(old_sself)) { 1132 ipc_port_release_send(old_sself); 1133 } 1134#endif /* CONFIG_CSR */ 1135 1136 if (has_old_exc_actions) { 1137 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 1138 ipc_port_release_send(old_exc_actions[i]); 1139 } 1140 } 1141 1142 /* destroy the kernel ports */ 1143 if (old_rdport != IP_NULL) { 1144 ipc_kobject_dealloc_port(old_rdport, IPC_KOBJECT_NO_MSCOUNT, 1145 IKOT_THREAD_READ); 1146 /* ikol_alt_port cleared */ 1147 } 1148 if (old_kport != IP_NULL) { 1149 ipc_kobject_dealloc_port(old_kport, IPC_KOBJECT_NO_MSCOUNT, 1150 IKOT_THREAD_CONTROL); 1151 } 1152 1153 if (old_iport != IP_NULL) { 1154 ipc_kobject_dealloc_port(old_iport, IPC_KOBJECT_NO_MSCOUNT, 1155 IKOT_THREAD_INSPECT); 1156 } 1157 1158 /* unbind the thread special reply port */ 1159 if (IP_VALID(thread->ith_special_reply_port)) { 1160 ipc_port_unbind_special_reply_port(thread, IRPT_USER); 1161 } 1162} 1163 1164/* 1165 * Routine: retrieve_task_self_fast 1166 * Purpose: 1167 * Optimized version of retrieve_task_self, 1168 * that only works for the current task. 1169 * 1170 * Return a send right (possibly null/dead) 1171 * for the task's user-visible self port. 1172 * Conditions: 1173 * Nothing locked. 1174 */ 1175 1176static ipc_port_t 1177retrieve_task_self_fast( 1178 task_t task) 1179{ 1180 ipc_port_t port = IP_NULL; 1181 ipc_port_t kport = task->itk_task_ports[TASK_FLAVOR_CONTROL]; 1182 1183 assert(task == current_task()); 1184 1185 itk_lock(task); 1186 assert(kport != IP_NULL); 1187 1188#if CONFIG_CSR 1189 if (task->itk_settable_self != kport) { 1190 port = ipc_port_copy_send_mqueue(task->itk_settable_self); 1191 } else 1192#endif 1193 { 1194 port = ipc_kobject_make_send(kport, task, IKOT_TASK_CONTROL); 1195 } 1196 1197 itk_unlock(task); 1198 1199 return port; 1200} 1201 1202/* 1203 * Routine: mach_task_is_self 1204 * Purpose: 1205 * [MIG call] Checks if the task (control/read/inspect/name/movable) 1206 * port is pointing to current_task. 1207 */ 1208kern_return_t 1209mach_task_is_self( 1210 task_t task, 1211 boolean_t *is_self) 1212{ 1213 if (task == TASK_NULL) { 1214 return KERN_INVALID_ARGUMENT; 1215 } 1216 1217 *is_self = (task == current_task()); 1218 1219 return KERN_SUCCESS; 1220} 1221 1222/* 1223 * Routine: retrieve_thread_self_fast 1224 * Purpose: 1225 * Return a send right (possibly null/dead) 1226 * for the thread's user-visible self port. 1227 * 1228 * Only works for the current thread. 1229 * 1230 * Conditions: 1231 * Nothing locked. 1232 */ 1233 1234ipc_port_t 1235retrieve_thread_self_fast( 1236 thread_t thread) 1237{ 1238 thread_ro_t tro = get_thread_ro(thread); 1239 ipc_port_t port = IP_NULL; 1240 1241 assert(thread == current_thread()); 1242 1243 thread_mtx_lock(thread); 1244 1245#if CONFIG_CSR 1246 if (tro->tro_settable_self_port != tro->tro_ports[THREAD_FLAVOR_CONTROL]) { 1247 port = ipc_port_copy_send_mqueue(tro->tro_settable_self_port); 1248 } else 1249#endif 1250 { 1251 port = ipc_kobject_make_send(tro->tro_ports[THREAD_FLAVOR_CONTROL], 1252 thread, IKOT_THREAD_CONTROL); 1253 } 1254 1255 thread_mtx_unlock(thread); 1256 1257 return port; 1258} 1259 1260/* 1261 * Routine: task_self_trap [mach trap] 1262 * Purpose: 1263 * Give the caller send rights for their own task port. 1264 * Conditions: 1265 * Nothing locked. 1266 * Returns: 1267 * MACH_PORT_NULL if there are any resource failures 1268 * or other errors. 1269 */ 1270 1271mach_port_name_t 1272task_self_trap( 1273 __unused struct task_self_trap_args *args) 1274{ 1275 task_t task = current_task(); 1276 ipc_port_t sright; 1277 1278 sright = retrieve_task_self_fast(task); 1279 return ipc_port_copyout_send(sright, task->itk_space); 1280} 1281 1282/* 1283 * Routine: thread_self_trap [mach trap] 1284 * Purpose: 1285 * Give the caller send rights for his own thread port. 1286 * Conditions: 1287 * Nothing locked. 1288 * Returns: 1289 * MACH_PORT_NULL if there are any resource failures 1290 * or other errors. 1291 */ 1292 1293mach_port_name_t 1294thread_self_trap( 1295 __unused struct thread_self_trap_args *args) 1296{ 1297 thread_t thread = current_thread(); 1298 ipc_space_t space = current_space(); 1299 ipc_port_t sright; 1300 mach_port_name_t name; 1301 1302 sright = retrieve_thread_self_fast(thread); 1303 name = ipc_port_copyout_send(sright, space); 1304 return name; 1305} 1306 1307/* 1308 * Routine: mach_reply_port [mach trap] 1309 * Purpose: 1310 * Allocate a port for the caller. 1311 * Conditions: 1312 * Nothing locked. 1313 * Returns: 1314 * MACH_PORT_NULL if there are any resource failures 1315 * or other errors. 1316 */ 1317 1318mach_port_name_t 1319mach_reply_port( 1320 __unused struct mach_reply_port_args *args) 1321{ 1322 ipc_port_t port; 1323 mach_port_name_t name; 1324 kern_return_t kr; 1325 1326 kr = ipc_port_alloc(current_space(), IPC_OBJECT_LABEL(IOT_PORT), 1327 IP_INIT_NONE, &name, &port); 1328 if (kr == KERN_SUCCESS) { 1329 ip_mq_unlock(port); 1330 } else { 1331 name = MACH_PORT_NULL; 1332 } 1333 return name; 1334} 1335 1336/* 1337 * Routine: thread_get_special_reply_port [mach trap] 1338 * Purpose: 1339 * Allocate a special reply port for the calling thread. 1340 * Conditions: 1341 * Nothing locked. 1342 * Returns: 1343 * mach_port_name_t: send right & receive right for special reply port. 1344 * MACH_PORT_NULL if there are any resource failures 1345 * or other errors. 1346 */ 1347 1348mach_port_name_t 1349thread_get_special_reply_port( 1350 __unused struct thread_get_special_reply_port_args *args) 1351{ 1352 ipc_port_t port; 1353 mach_port_name_t name; 1354 kern_return_t kr; 1355 thread_t thread = current_thread(); 1356 1357 /* unbind the thread special reply port */ 1358 if (IP_VALID(thread->ith_special_reply_port)) { 1359 ipc_port_unbind_special_reply_port(thread, IRPT_USER); 1360 } 1361 1362 kr = ipc_port_alloc(current_space(), IPC_OBJECT_LABEL(IOT_SPECIAL_REPLY_PORT), 1363 IP_INIT_MAKE_SEND_RIGHT, &name, &port); 1364 if (kr == KERN_SUCCESS) { 1365 ipc_port_bind_special_reply_port_locked(port, IRPT_USER); 1366 ip_mq_unlock(port); 1367 } else { 1368 name = MACH_PORT_NULL; 1369 } 1370 return name; 1371} 1372 1373/* 1374 * Routine: thread_get_kernel_special_reply_port 1375 * Purpose: 1376 * Allocate a kernel special reply port for the calling thread. 1377 * Conditions: 1378 * Nothing locked. 1379 * Returns: 1380 * Creates and sets kernel special reply port. 1381 * KERN_SUCCESS on Success. 1382 * KERN_FAILURE on Failure. 1383 */ 1384 1385kern_return_t 1386thread_get_kernel_special_reply_port(void) 1387{ 1388 ipc_port_t port = IP_NULL; 1389 thread_t thread = current_thread(); 1390 1391 /* unbind the thread special reply port */ 1392 if (IP_VALID(thread->ith_kernel_reply_port)) { 1393 ipc_port_unbind_special_reply_port(thread, IRPT_KERNEL); 1394 } 1395 1396 port = ipc_port_alloc_special(ipc_space_reply, 1397 IPC_OBJECT_LABEL(IOT_SPECIAL_REPLY_PORT), IP_INIT_NONE); 1398 ipc_port_bind_special_reply_port_locked(port, IRPT_KERNEL); 1399 ip_mq_unlock(port); 1400 1401 /* release the reference returned by ipc_port_alloc_special */ 1402 ip_release(port); 1403 1404 return KERN_SUCCESS; 1405} 1406 1407/* 1408 * Routine: ipc_port_bind_special_reply_port_locked 1409 * Purpose: 1410 * Bind the given port to current thread as a special reply port. 1411 * Conditions: 1412 * Port locked. 1413 * Returns: 1414 * None. 1415 */ 1416 1417static void 1418ipc_port_bind_special_reply_port_locked( 1419 ipc_port_t port, 1420 ipc_reply_port_type_t reply_type) 1421{ 1422 thread_t thread = current_thread(); 1423 ipc_port_t *reply_portp; 1424 1425 if (reply_type == IRPT_USER) { 1426 reply_portp = &thread->ith_special_reply_port; 1427 } else { 1428 reply_portp = &thread->ith_kernel_reply_port; 1429 } 1430 1431 assert(*reply_portp == NULL); 1432 assert(ip_is_special_reply_port(port)); 1433 assert(port->ip_sync_link_state == PORT_SYNC_LINK_ANY); 1434 1435 ip_reference(port); 1436 *reply_portp = port; 1437 port->ip_messages.imq_srp_owner_thread = thread; 1438 1439 ipc_special_reply_port_bits_reset(port); 1440} 1441 1442/* 1443 * Routine: ipc_port_unbind_special_reply_port 1444 * Purpose: 1445 * Unbind the thread's special reply port. 1446 * If the special port has threads waiting on turnstile, 1447 * update it's inheritor. 1448 * Condition: 1449 * Nothing locked. 1450 * Returns: 1451 * None. 1452 */ 1453static void 1454ipc_port_unbind_special_reply_port( 1455 thread_t thread, 1456 ipc_reply_port_type_t reply_type) 1457{ 1458 ipc_port_t *reply_portp; 1459 1460 if (reply_type == IRPT_USER) { 1461 reply_portp = &thread->ith_special_reply_port; 1462 } else { 1463 reply_portp = &thread->ith_kernel_reply_port; 1464 } 1465 1466 ipc_port_t special_reply_port = *reply_portp; 1467 1468 ip_mq_lock(special_reply_port); 1469 1470 *reply_portp = NULL; 1471 ipc_port_adjust_special_reply_port_locked(special_reply_port, NULL, 1472 IPC_PORT_ADJUST_UNLINK_THREAD, FALSE); 1473 /* port unlocked */ 1474 1475 /* Destroy the port if its kernel special reply, else just release a ref */ 1476 if (reply_type == IRPT_USER) { 1477 ip_release(special_reply_port); 1478 } else { 1479 ip_mq_lock(special_reply_port); 1480 ipc_port_destroy(special_reply_port); 1481 } 1482} 1483 1484/* 1485 * Routine: thread_dealloc_kernel_special_reply_port 1486 * Purpose: 1487 * Unbind the thread's kernel special reply port. 1488 * If the special port has threads waiting on turnstile, 1489 * update it's inheritor. 1490 * Condition: 1491 * Called on current thread or a terminated thread. 1492 * Returns: 1493 * None. 1494 */ 1495 1496void 1497thread_dealloc_kernel_special_reply_port(thread_t thread) 1498{ 1499 ipc_port_unbind_special_reply_port(thread, IRPT_KERNEL); 1500} 1501 1502/* 1503 * Routine: thread_get_special_port [kernel call] 1504 * Purpose: 1505 * Clones a send right for one of the thread's 1506 * special ports. 1507 * Conditions: 1508 * Nothing locked. 1509 * Returns: 1510 * KERN_SUCCESS Extracted a send right. 1511 * KERN_INVALID_ARGUMENT The thread is null. 1512 * KERN_FAILURE The thread is dead. 1513 * KERN_INVALID_ARGUMENT Invalid special port. 1514 */ 1515 1516kern_return_t 1517thread_get_special_port( 1518 thread_inspect_t thread, 1519 int which, 1520 ipc_port_t *portp); 1521 1522static kern_return_t 1523thread_get_special_port_internal( 1524 thread_inspect_t thread, 1525 thread_ro_t tro, 1526 int which, 1527 ipc_port_t *portp, 1528 mach_thread_flavor_t flavor) 1529{ 1530 kern_return_t kr; 1531 ipc_port_t port; 1532 1533 if ((kr = special_port_allowed_with_thread_flavor(which, flavor)) != KERN_SUCCESS) { 1534 return kr; 1535 } 1536 1537 thread_mtx_lock(thread); 1538 if (!thread->active) { 1539 thread_mtx_unlock(thread); 1540 return KERN_FAILURE; 1541 } 1542 1543 switch (which) { 1544 case THREAD_KERNEL_PORT: 1545 port = tro->tro_ports[THREAD_FLAVOR_CONTROL]; 1546#if CONFIG_CSR 1547 if (tro->tro_settable_self_port != port) { 1548 port = ipc_port_copy_send_mqueue(tro->tro_settable_self_port); 1549 } else 1550#endif /* CONFIG_CSR */ 1551 { 1552 port = ipc_kobject_copy_send(port, thread, IKOT_THREAD_CONTROL); 1553 } 1554 thread_mtx_unlock(thread); 1555 break; 1556 1557 case THREAD_READ_PORT: 1558 case THREAD_INSPECT_PORT: 1559 thread_mtx_unlock(thread); 1560 mach_thread_flavor_t current_flavor = (which == THREAD_READ_PORT) ? 1561 THREAD_FLAVOR_READ : THREAD_FLAVOR_INSPECT; 1562 /* convert_thread_to_port_with_flavor consumes a thread reference */ 1563 thread_reference(thread); 1564 port = convert_thread_to_port_with_flavor(thread, tro, current_flavor); 1565 break; 1566 1567 default: 1568 thread_mtx_unlock(thread); 1569 return KERN_INVALID_ARGUMENT; 1570 } 1571 1572 *portp = port; 1573 return KERN_SUCCESS; 1574} 1575 1576kern_return_t 1577thread_get_special_port( 1578 thread_inspect_t thread, 1579 int which, 1580 ipc_port_t *portp) 1581{ 1582 if (thread == THREAD_NULL) { 1583 return KERN_INVALID_ARGUMENT; 1584 } 1585 1586 return thread_get_special_port_internal(thread, get_thread_ro(thread), 1587 which, portp, THREAD_FLAVOR_CONTROL); 1588} 1589 1590kern_return_t 1591thread_get_special_port_from_user( 1592 mach_port_t port, 1593 int which, 1594 ipc_port_t *portp) 1595{ 1596 thread_ro_t tro; 1597 ipc_kobject_type_t kotype; 1598 mach_thread_flavor_t flavor; 1599 kern_return_t kr = KERN_SUCCESS; 1600 1601 thread_t thread = convert_port_to_thread_inspect_no_eval(port); 1602 1603 if (thread == THREAD_NULL) { 1604 return KERN_INVALID_ARGUMENT; 1605 } 1606 1607 tro = get_thread_ro(thread); 1608 kotype = ip_type(port); 1609 1610 if (which == THREAD_KERNEL_PORT && tro->tro_task == current_task()) { 1611#if CONFIG_MACF 1612 /* 1613 * only check for threads belong to current_task, 1614 * because foreign thread ports are always movable 1615 */ 1616 if (mac_task_check_get_movable_control_port()) { 1617 kr = KERN_DENIED; 1618 goto out; 1619 } 1620#endif 1621 /* 1622 * if `mac_task_check_get_movable_control_port` returned 0, 1623 * then we must also have a movable task. 1624 * see `task_set_exc_guard_default` 1625 */ 1626 assert(!task_is_immovable(current_task())); 1627 } 1628 1629 switch (kotype) { 1630 case IKOT_THREAD_CONTROL: 1631 flavor = THREAD_FLAVOR_CONTROL; 1632 break; 1633 case IKOT_THREAD_READ: 1634 flavor = THREAD_FLAVOR_READ; 1635 break; 1636 case IKOT_THREAD_INSPECT: 1637 flavor = THREAD_FLAVOR_INSPECT; 1638 break; 1639 default: 1640 panic("strange kobject type"); 1641 } 1642 1643 kr = thread_get_special_port_internal(thread, tro, which, portp, flavor); 1644out: 1645 thread_deallocate(thread); 1646 return kr; 1647} 1648 1649static kern_return_t 1650special_port_allowed_with_thread_flavor( 1651 int which, 1652 mach_thread_flavor_t flavor) 1653{ 1654 switch (flavor) { 1655 case THREAD_FLAVOR_CONTROL: 1656 return KERN_SUCCESS; 1657 1658 case THREAD_FLAVOR_READ: 1659 1660 switch (which) { 1661 case THREAD_READ_PORT: 1662 case THREAD_INSPECT_PORT: 1663 return KERN_SUCCESS; 1664 default: 1665 return KERN_INVALID_CAPABILITY; 1666 } 1667 1668 case THREAD_FLAVOR_INSPECT: 1669 1670 switch (which) { 1671 case THREAD_INSPECT_PORT: 1672 return KERN_SUCCESS; 1673 default: 1674 return KERN_INVALID_CAPABILITY; 1675 } 1676 1677 default: 1678 return KERN_INVALID_CAPABILITY; 1679 } 1680} 1681 1682/* 1683 * Routine: thread_set_special_port [kernel call] 1684 * Purpose: 1685 * Changes one of the thread's special ports, 1686 * setting it to the supplied send right. 1687 * Conditions: 1688 * Nothing locked. If successful, consumes 1689 * the supplied send right. 1690 * Returns: 1691 * KERN_SUCCESS Changed the special port. 1692 * KERN_INVALID_ARGUMENT The thread is null. 1693 * KERN_INVALID_RIGHT Port is marked as immovable. 1694 * KERN_FAILURE The thread is dead. 1695 * KERN_INVALID_ARGUMENT Invalid special port. 1696 * KERN_NO_ACCESS Restricted access to set port. 1697 */ 1698 1699kern_return_t 1700thread_set_special_port( 1701 thread_t thread, 1702 int which, 1703 ipc_port_t port) 1704{ 1705 kern_return_t result = KERN_SUCCESS; 1706 thread_ro_t tro = NULL; 1707 ipc_port_t old = IP_NULL; 1708 1709 if (thread == THREAD_NULL) { 1710 return KERN_INVALID_ARGUMENT; 1711 } 1712 1713 /* 1714 * rdar://70585367 1715 * disallow immovable send so other process can't retrieve it through thread_get_special_port() 1716 */ 1717 if (!ipc_can_stash_naked_send(port)) { 1718 return KERN_INVALID_RIGHT; 1719 } 1720 1721 switch (which) { 1722 case THREAD_KERNEL_PORT: 1723#if CONFIG_CSR 1724 if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) == 0) { 1725 /* 1726 * Only allow setting of thread-self 1727 * special port from user-space when SIP is 1728 * disabled (for Mach-on-Mach emulation). 1729 */ 1730 tro = get_thread_ro(thread); 1731 1732 thread_mtx_lock(thread); 1733 if (thread->active) { 1734 old = tro->tro_settable_self_port; 1735 zalloc_ro_update_field(ZONE_ID_THREAD_RO, 1736 tro, tro_settable_self_port, &port); 1737 } else { 1738 result = KERN_FAILURE; 1739 } 1740 thread_mtx_unlock(thread); 1741 1742 if (IP_VALID(old)) { 1743 ipc_port_release_send(old); 1744 } 1745 1746 return result; 1747 } 1748#else 1749 (void)old; 1750 (void)result; 1751 (void)tro; 1752#endif /* CONFIG_CSR */ 1753 return KERN_NO_ACCESS; 1754 1755 default: 1756 return KERN_INVALID_ARGUMENT; 1757 } 1758} 1759 1760static inline mach_task_flavor_t 1761task_special_type_to_flavor(task_special_port_t which) 1762{ 1763 switch (which) { 1764 case TASK_KERNEL_PORT: 1765 return TASK_FLAVOR_CONTROL; 1766 case TASK_NAME_PORT: 1767 return TASK_FLAVOR_NAME; 1768 case TASK_INSPECT_PORT: 1769 return TASK_FLAVOR_INSPECT; 1770 case TASK_READ_PORT: 1771 return TASK_FLAVOR_READ; 1772 default: 1773 break; 1774 } 1775 panic("invalid special port: %d", which); 1776} 1777 1778/* 1779 * Routine: task_get_special_port [kernel call] 1780 * Purpose: 1781 * Clones a send right for one of the task's 1782 * special ports. 1783 * Conditions: 1784 * Nothing locked. 1785 * Returns: 1786 * KERN_SUCCESS Extracted a send right. 1787 * KERN_INVALID_ARGUMENT The task is null. 1788 * KERN_FAILURE The task/space is dead. 1789 * KERN_INVALID_ARGUMENT Invalid special port. 1790 */ 1791 1792static kern_return_t 1793task_get_special_port_internal( 1794 task_t task, 1795 int which, 1796 ipc_port_t *portp, 1797 mach_task_flavor_t flavor) 1798{ 1799 kern_return_t kr; 1800 ipc_port_t port; 1801 1802 if (task == TASK_NULL) { 1803 return KERN_INVALID_ARGUMENT; 1804 } 1805 1806 if ((kr = special_port_allowed_with_task_flavor(which, flavor)) != KERN_SUCCESS) { 1807 return kr; 1808 } 1809 1810 itk_lock(task); 1811 if (!task->ipc_active) { 1812 itk_unlock(task); 1813 return KERN_FAILURE; 1814 } 1815 1816 switch (which) { 1817 case TASK_KERNEL_PORT: 1818 port = task->itk_task_ports[TASK_FLAVOR_CONTROL]; 1819#if CONFIG_CSR 1820 if (task->itk_settable_self != port) { 1821 port = ipc_port_copy_send_mqueue(task->itk_settable_self); 1822 } else 1823#endif /* CONFIG_CSR */ 1824 { 1825 port = ipc_kobject_copy_send(port, task, IKOT_TASK_CONTROL); 1826 } 1827 itk_unlock(task); 1828 break; 1829 1830 case TASK_READ_PORT: 1831 case TASK_INSPECT_PORT: 1832 itk_unlock(task); 1833 mach_task_flavor_t current_flavor = task_special_type_to_flavor(which); 1834 /* convert_task_to_port_with_flavor consumes a task reference */ 1835 task_reference(task); 1836 port = convert_task_to_port_with_flavor(task, current_flavor, TASK_GRP_KERNEL); 1837 break; 1838 1839 case TASK_NAME_PORT: 1840 port = ipc_kobject_make_send(task->itk_task_ports[TASK_FLAVOR_NAME], 1841 task, IKOT_TASK_NAME); 1842 itk_unlock(task); 1843 break; 1844 1845 case TASK_HOST_PORT: 1846 port = host_port_copy_send(task->itk_host); 1847 itk_unlock(task); 1848 break; 1849 1850 case TASK_BOOTSTRAP_PORT: 1851 port = ipc_port_copy_send_mqueue(task->itk_bootstrap); 1852 itk_unlock(task); 1853 break; 1854 1855 case TASK_ACCESS_PORT: 1856 port = ipc_port_copy_send_mqueue(task->itk_task_access); 1857 itk_unlock(task); 1858 break; 1859 1860 case TASK_DEBUG_CONTROL_PORT: 1861 port = ipc_port_copy_send_mqueue(task->itk_debug_control); 1862 itk_unlock(task); 1863 break; 1864 1865#if CONFIG_PROC_RESOURCE_LIMITS 1866 case TASK_RESOURCE_NOTIFY_PORT: 1867 port = ipc_port_copy_send_mqueue(task->itk_resource_notify); 1868 itk_unlock(task); 1869 break; 1870#endif /* CONFIG_PROC_RESOURCE_LIMITS */ 1871 1872 default: 1873 itk_unlock(task); 1874 return KERN_INVALID_ARGUMENT; 1875 } 1876 1877 *portp = port; 1878 return KERN_SUCCESS; 1879} 1880 1881/* Kernel/Kext call only and skips MACF checks. MIG uses task_get_special_port_from_user(). */ 1882kern_return_t 1883task_get_special_port( 1884 task_t task, 1885 int which, 1886 ipc_port_t *portp) 1887{ 1888 return task_get_special_port_internal(task, which, portp, TASK_FLAVOR_CONTROL); 1889} 1890 1891/* MIG call only. Kernel/Kext uses task_get_special_port() */ 1892kern_return_t 1893task_get_special_port_from_user( 1894 mach_port_t port, 1895 int which, 1896 ipc_port_t *portp) 1897{ 1898 ipc_kobject_type_t kotype; 1899 mach_task_flavor_t flavor; 1900 kern_return_t kr = KERN_SUCCESS; 1901 1902 task_t task = convert_port_to_task_inspect_no_eval(port); 1903 1904 if (task == TASK_NULL) { 1905 return KERN_INVALID_ARGUMENT; 1906 } 1907 1908 kotype = ip_type(port); 1909 1910#if CONFIG_MACF 1911 if (mac_task_check_get_task_special_port(current_task(), task, which)) { 1912 kr = KERN_DENIED; 1913 goto out; 1914 } 1915#endif 1916 1917 if (which == TASK_KERNEL_PORT && task == current_task()) { 1918#if CONFIG_MACF 1919 /* 1920 * only check for current_task, 1921 * because foreign task ports are always movable 1922 */ 1923 if (mac_task_check_get_movable_control_port()) { 1924 kr = KERN_DENIED; 1925 goto out; 1926 } 1927#endif 1928 /* 1929 * if `mac_task_check_get_movable_control_port` returned 0, 1930 * then we must also have a movable task. 1931 * see `task_set_exc_guard_default` 1932 */ 1933 assert(!task_is_immovable(current_task())); 1934 } 1935 1936 switch (kotype) { 1937 case IKOT_TASK_CONTROL: 1938 flavor = TASK_FLAVOR_CONTROL; 1939 break; 1940 case IKOT_TASK_READ: 1941 flavor = TASK_FLAVOR_READ; 1942 break; 1943 case IKOT_TASK_INSPECT: 1944 flavor = TASK_FLAVOR_INSPECT; 1945 break; 1946 default: 1947 panic("strange kobject type"); 1948 } 1949 1950 kr = task_get_special_port_internal(task, which, portp, flavor); 1951out: 1952 task_deallocate(task); 1953 return kr; 1954} 1955 1956static kern_return_t 1957special_port_allowed_with_task_flavor( 1958 int which, 1959 mach_task_flavor_t flavor) 1960{ 1961 switch (flavor) { 1962 case TASK_FLAVOR_CONTROL: 1963 return KERN_SUCCESS; 1964 1965 case TASK_FLAVOR_READ: 1966 1967 switch (which) { 1968 case TASK_READ_PORT: 1969 case TASK_INSPECT_PORT: 1970 case TASK_NAME_PORT: 1971 return KERN_SUCCESS; 1972 default: 1973 return KERN_INVALID_CAPABILITY; 1974 } 1975 1976 case TASK_FLAVOR_INSPECT: 1977 1978 switch (which) { 1979 case TASK_INSPECT_PORT: 1980 case TASK_NAME_PORT: 1981 return KERN_SUCCESS; 1982 default: 1983 return KERN_INVALID_CAPABILITY; 1984 } 1985 1986 default: 1987 return KERN_INVALID_CAPABILITY; 1988 } 1989} 1990 1991/* 1992 * Routine: task_set_special_port [MIG call] 1993 * Purpose: 1994 * Changes one of the task's special ports, 1995 * setting it to the supplied send right. 1996 * Conditions: 1997 * Nothing locked. If successful, consumes 1998 * the supplied send right. 1999 * Returns: 2000 * KERN_SUCCESS Changed the special port. 2001 * KERN_INVALID_ARGUMENT The task is null. 2002 * KERN_INVALID_RIGHT Port is marked as immovable. 2003 * KERN_FAILURE The task/space is dead. 2004 * KERN_INVALID_ARGUMENT Invalid special port. 2005 * KERN_NO_ACCESS Restricted access to set port. 2006 */ 2007 2008kern_return_t 2009task_set_special_port_from_user( 2010 task_t task, 2011 int which, 2012 ipc_port_t port) 2013{ 2014 if (task == TASK_NULL) { 2015 return KERN_INVALID_ARGUMENT; 2016 } 2017 2018#if CONFIG_MACF 2019 if (mac_task_check_set_task_special_port(current_task(), task, which, port)) { 2020 return KERN_DENIED; 2021 } 2022#endif 2023 2024 return task_set_special_port(task, which, port); 2025} 2026 2027/* Kernel call only. MIG uses task_set_special_port_from_user() */ 2028kern_return_t 2029task_set_special_port( 2030 task_t task, 2031 int which, 2032 ipc_port_t port) 2033{ 2034 if (task == TASK_NULL) { 2035 return KERN_INVALID_ARGUMENT; 2036 } 2037 2038 if (task_is_driver(current_task())) { 2039 return KERN_NO_ACCESS; 2040 } 2041 2042 /* 2043 * rdar://70585367 2044 * disallow immovable send so other process can't retrieve it through task_get_special_port() 2045 */ 2046 if (!ipc_can_stash_naked_send(port)) { 2047 return KERN_INVALID_RIGHT; 2048 } 2049 2050 2051 switch (which) { 2052 case TASK_KERNEL_PORT: 2053 case TASK_HOST_PORT: 2054#if CONFIG_CSR 2055 if (csr_check(CSR_ALLOW_KERNEL_DEBUGGER) == 0) { 2056 /* 2057 * Only allow setting of task-self / task-host 2058 * special ports from user-space when SIP is 2059 * disabled (for Mach-on-Mach emulation). 2060 */ 2061 break; 2062 } 2063#endif 2064 return KERN_NO_ACCESS; 2065 default: 2066 break; 2067 } 2068 2069 return task_set_special_port_internal(task, which, port); 2070} 2071 2072/* 2073 * Routine: task_set_special_port_internal 2074 * Purpose: 2075 * Changes one of the task's special ports, 2076 * setting it to the supplied send right. 2077 * Conditions: 2078 * Nothing locked. If successful, consumes 2079 * the supplied send right. 2080 * Returns: 2081 * KERN_SUCCESS Changed the special port. 2082 * KERN_INVALID_ARGUMENT The task is null. 2083 * KERN_FAILURE The task/space is dead. 2084 * KERN_INVALID_ARGUMENT Invalid special port. 2085 * KERN_NO_ACCESS Restricted access to overwrite port. 2086 */ 2087 2088kern_return_t 2089task_set_special_port_internal( 2090 task_t task, 2091 int which, 2092 ipc_port_t port) 2093{ 2094 ipc_port_t old = IP_NULL; 2095 kern_return_t rc = KERN_INVALID_ARGUMENT; 2096 2097 if (task == TASK_NULL) { 2098 goto out; 2099 } 2100 2101 itk_lock(task); 2102 /* 2103 * Allow setting special port during the span of ipc_task_init() to 2104 * ipc_task_terminate(). posix_spawn() port actions can set special 2105 * ports on target task _before_ task IPC access is enabled. 2106 */ 2107 if (task->itk_task_ports[TASK_FLAVOR_CONTROL] == IP_NULL) { 2108 rc = KERN_FAILURE; 2109 goto out_unlock; 2110 } 2111 2112 switch (which) { 2113#if CONFIG_CSR 2114 case TASK_KERNEL_PORT: 2115 old = task->itk_settable_self; 2116 task->itk_settable_self = port; 2117 break; 2118#endif /* CONFIG_CSR */ 2119 2120 case TASK_HOST_PORT: 2121 old = task->itk_host; 2122 task->itk_host = port; 2123 break; 2124 2125 case TASK_BOOTSTRAP_PORT: 2126 old = task->itk_bootstrap; 2127 task->itk_bootstrap = port; 2128 break; 2129 2130 /* Never allow overwrite of the task access port */ 2131 case TASK_ACCESS_PORT: 2132 if (IP_VALID(task->itk_task_access)) { 2133 rc = KERN_NO_ACCESS; 2134 goto out_unlock; 2135 } 2136 task->itk_task_access = port; 2137 break; 2138 2139 case TASK_DEBUG_CONTROL_PORT: 2140 old = task->itk_debug_control; 2141 task->itk_debug_control = port; 2142 break; 2143 2144#if CONFIG_PROC_RESOURCE_LIMITS 2145 case TASK_RESOURCE_NOTIFY_PORT: 2146 old = task->itk_resource_notify; 2147 task->itk_resource_notify = port; 2148 break; 2149#endif /* CONFIG_PROC_RESOURCE_LIMITS */ 2150 2151 default: 2152 rc = KERN_INVALID_ARGUMENT; 2153 goto out_unlock; 2154 }/* switch */ 2155 2156 rc = KERN_SUCCESS; 2157 2158out_unlock: 2159 itk_unlock(task); 2160 2161 if (IP_VALID(old)) { 2162 ipc_port_release_send(old); 2163 } 2164out: 2165 return rc; 2166} 2167/* 2168 * Routine: mach_ports_register [kernel call] 2169 * Purpose: 2170 * Stash a handful of port send rights in the task. 2171 * Child tasks will inherit these rights, but they 2172 * must use mach_ports_lookup to acquire them. 2173 * 2174 * The rights are supplied in a (wired) kalloc'd segment. 2175 * Rights which aren't supplied are assumed to be null. 2176 * Conditions: 2177 * Nothing locked. If successful, consumes 2178 * the supplied rights and memory. 2179 * Returns: 2180 * KERN_SUCCESS Stashed the port rights. 2181 * KERN_INVALID_RIGHT Port in array is marked immovable. 2182 * KERN_INVALID_ARGUMENT The task is null. 2183 * KERN_INVALID_ARGUMENT The task is dead. 2184 * KERN_INVALID_ARGUMENT The memory param is null. 2185 * KERN_INVALID_ARGUMENT Too many port rights supplied. 2186 */ 2187 2188kern_return_t 2189_kernelrpc_mach_ports_register3( 2190 task_t task, 2191 mach_port_t port1, 2192 mach_port_t port2, 2193 mach_port_t port3) 2194{ 2195 ipc_port_t ports[TASK_PORT_REGISTER_MAX] = { 2196 port1, port2, port3, 2197 }; 2198 2199 if (task == TASK_NULL) { 2200 return KERN_INVALID_ARGUMENT; 2201 } 2202 2203 for (int i = 0; i < TASK_PORT_REGISTER_MAX; i++) { 2204 /* 2205 * rdar://70585367 2206 * disallow immovable send so other process can't retrieve it through mach_ports_lookup() 2207 */ 2208 if (!ipc_can_stash_naked_send(ports[i])) { 2209 return KERN_INVALID_RIGHT; 2210 } 2211 } 2212 2213 itk_lock(task); 2214 if (!task->ipc_active) { 2215 itk_unlock(task); 2216 return KERN_INVALID_ARGUMENT; 2217 } 2218 2219 /* 2220 * Replace the old send rights with the new. 2221 * Release the old rights after unlocking. 2222 */ 2223 2224 for (int i = 0; i < TASK_PORT_REGISTER_MAX; i++) { 2225 ipc_port_t old; 2226 2227 old = task->itk_registered[i]; 2228 task->itk_registered[i] = ports[i]; 2229 ports[i] = old; 2230 } 2231 2232 itk_unlock(task); 2233 2234 for (int i = 0; i < TASK_PORT_REGISTER_MAX; i++) { 2235 ipc_port_release_send(ports[i]); 2236 } 2237 2238 return KERN_SUCCESS; 2239} 2240 2241/* 2242 * Routine: mach_ports_lookup [kernel call] 2243 * Purpose: 2244 * Retrieves (clones) the stashed port send rights. 2245 * Conditions: 2246 * Nothing locked. If successful, the caller gets 2247 * rights and memory. 2248 * Returns: 2249 * KERN_SUCCESS Retrieved the send rights. 2250 * KERN_INVALID_ARGUMENT The task is null. 2251 * KERN_INVALID_ARGUMENT The task is dead. 2252 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 2253 */ 2254 2255kern_return_t 2256_kernelrpc_mach_ports_lookup3( 2257 task_t task, 2258 ipc_port_t *port1, 2259 ipc_port_t *port2, 2260 ipc_port_t *port3) 2261{ 2262 if (task == TASK_NULL) { 2263 return KERN_INVALID_ARGUMENT; 2264 } 2265 2266 itk_lock(task); 2267 if (!task->ipc_active) { 2268 itk_unlock(task); 2269 return KERN_INVALID_ARGUMENT; 2270 } 2271 2272 *port1 = ipc_port_copy_send_any(task->itk_registered[0]); 2273 *port2 = ipc_port_copy_send_any(task->itk_registered[1]); 2274 *port3 = ipc_port_copy_send_any(task->itk_registered[2]); 2275 2276 itk_unlock(task); 2277 2278 return KERN_SUCCESS; 2279} 2280 2281static kern_return_t 2282task_conversion_eval_internal( 2283 task_t caller, 2284 task_t victim, 2285 boolean_t out_trans, 2286 int flavor) /* control or read */ 2287{ 2288 boolean_t allow_kern_task_out_trans; 2289 boolean_t allow_kern_task; 2290 2291 assert(flavor == TASK_FLAVOR_CONTROL || flavor == TASK_FLAVOR_READ); 2292 assert(flavor == THREAD_FLAVOR_CONTROL || flavor == THREAD_FLAVOR_READ); 2293 2294#if defined(SECURE_KERNEL) 2295 /* 2296 * On secure kernel platforms, reject converting kernel task/threads to port 2297 * and sending it to user space. 2298 */ 2299 allow_kern_task_out_trans = FALSE; 2300#else 2301 allow_kern_task_out_trans = TRUE; 2302#endif 2303 2304 allow_kern_task = out_trans && allow_kern_task_out_trans; 2305 2306 if (victim == TASK_NULL) { 2307 return KERN_INVALID_SECURITY; 2308 } 2309 2310 task_require(victim); 2311 2312 /* 2313 * If Developer Mode is not enabled, deny attempts to translate foreign task's 2314 * control port completely. Read port or corpse is okay. 2315 */ 2316 if (!developer_mode_state()) { 2317 if ((caller != victim) && 2318 (flavor == TASK_FLAVOR_CONTROL) && !task_is_a_corpse(victim)) { 2319#if XNU_TARGET_OS_OSX 2320 return KERN_INVALID_SECURITY; 2321#else 2322 /* 2323 * All control ports are immovable. 2324 * Return an error for outtrans, but panic on intrans. 2325 */ 2326 if (out_trans) { 2327 return KERN_INVALID_SECURITY; 2328 } else { 2329 panic("Just like pineapple on pizza, this task/thread port doesn't belong here."); 2330 } 2331#endif /* XNU_TARGET_OS_OSX */ 2332 } 2333 } 2334 2335 /* 2336 * Tasks are allowed to resolve their own task ports, and the kernel is 2337 * allowed to resolve anyone's task port (subject to Developer Mode check). 2338 */ 2339 if (caller == kernel_task) { 2340 return KERN_SUCCESS; 2341 } 2342 2343 if (caller == victim) { 2344 return KERN_SUCCESS; 2345 } 2346 2347 /* 2348 * Only the kernel can resolve the kernel's task port. We've established 2349 * by this point that the caller is not kernel_task. 2350 */ 2351 if (victim == kernel_task && !allow_kern_task) { 2352 return KERN_INVALID_SECURITY; 2353 } 2354 2355#if !defined(XNU_TARGET_OS_OSX) 2356 /* 2357 * On platforms other than macOS, only a platform binary can resolve the task port 2358 * of another platform binary. 2359 */ 2360 if (task_get_platform_binary(victim) && !task_get_platform_binary(caller)) { 2361#if SECURE_KERNEL 2362 return KERN_INVALID_SECURITY; 2363#else 2364 if (cs_relax_platform_task_ports) { 2365 return KERN_SUCCESS; 2366 } else { 2367 return KERN_INVALID_SECURITY; 2368 } 2369#endif /* SECURE_KERNEL */ 2370 } 2371#endif /* !defined(XNU_TARGET_OS_OSX) */ 2372 2373 return KERN_SUCCESS; 2374} 2375 2376kern_return_t 2377task_conversion_eval(task_t caller, task_t victim, int flavor) 2378{ 2379 /* flavor is mach_task_flavor_t or mach_thread_flavor_t */ 2380 static_assert(TASK_FLAVOR_CONTROL == THREAD_FLAVOR_CONTROL); 2381 static_assert(TASK_FLAVOR_READ == THREAD_FLAVOR_READ); 2382 return task_conversion_eval_internal(caller, victim, FALSE, flavor); 2383} 2384 2385static kern_return_t 2386task_conversion_eval_out_trans(task_t caller, task_t victim, int flavor) 2387{ 2388 assert(flavor == TASK_FLAVOR_CONTROL || flavor == THREAD_FLAVOR_CONTROL); 2389 return task_conversion_eval_internal(caller, victim, TRUE, flavor); 2390} 2391 2392/* 2393 * Routine: task_port_kotype_valid_for_flavor 2394 * Purpose: 2395 * Check whether the kobject type of a mach port 2396 * is valid for conversion to a task of given flavor. 2397 */ 2398static boolean_t 2399task_port_kotype_valid_for_flavor( 2400 natural_t kotype, 2401 mach_task_flavor_t flavor) 2402{ 2403 switch (flavor) { 2404 /* Ascending capability */ 2405 case TASK_FLAVOR_NAME: 2406 if (kotype == IKOT_TASK_NAME) { 2407 return TRUE; 2408 } 2409 OS_FALLTHROUGH; 2410 case TASK_FLAVOR_INSPECT: 2411 if (kotype == IKOT_TASK_INSPECT) { 2412 return TRUE; 2413 } 2414 OS_FALLTHROUGH; 2415 case TASK_FLAVOR_READ: 2416 if (kotype == IKOT_TASK_READ) { 2417 return TRUE; 2418 } 2419 OS_FALLTHROUGH; 2420 case TASK_FLAVOR_CONTROL: 2421 if (kotype == IKOT_TASK_CONTROL) { 2422 return TRUE; 2423 } 2424 break; 2425 default: 2426 panic("strange task flavor"); 2427 } 2428 2429 return FALSE; 2430} 2431 2432/* 2433 * Routine: convert_port_to_task_with_flavor_locked_noref 2434 * Purpose: 2435 * Internal helper routine to convert from a locked port to a task. 2436 * Args: 2437 * port - target port 2438 * flavor - requested task port flavor 2439 * options - port translation options 2440 * Conditions: 2441 * Port is locked and active. 2442 */ 2443static task_t 2444convert_port_to_task_with_flavor_locked_noref( 2445 ipc_port_t port, 2446 mach_task_flavor_t flavor, 2447 port_intrans_options_t options) 2448{ 2449 ipc_kobject_type_t type = ip_type(port); 2450 task_t task; 2451 2452 ip_mq_lock_held(port); 2453 require_ip_active(port); 2454 2455 if (!task_port_kotype_valid_for_flavor(type, flavor)) { 2456 return TASK_NULL; 2457 } 2458 2459 task = ipc_kobject_get_locked(port, type); 2460 if (task == TASK_NULL) { 2461 return TASK_NULL; 2462 } 2463 2464 if (!(options & PORT_INTRANS_ALLOW_CORPSE_TASK) && task_is_a_corpse(task)) { 2465 assert(flavor == TASK_FLAVOR_CONTROL); 2466 return TASK_NULL; 2467 } 2468 2469 /* TODO: rdar://42389187 */ 2470 if (flavor == TASK_FLAVOR_NAME || flavor == TASK_FLAVOR_INSPECT) { 2471 assert(options & PORT_INTRANS_SKIP_TASK_EVAL); 2472 } 2473 2474 if (!(options & PORT_INTRANS_SKIP_TASK_EVAL) && 2475 task_conversion_eval(current_task(), task, flavor)) { 2476 return TASK_NULL; 2477 } 2478 2479 return task; 2480} 2481 2482/* 2483 * Routine: convert_port_to_task_with_flavor_locked 2484 * Purpose: 2485 * Internal helper routine to convert from a locked port to a task. 2486 * Args: 2487 * port - target port 2488 * flavor - requested task port flavor 2489 * options - port translation options 2490 * grp - task reference group 2491 * Conditions: 2492 * Port is locked and active. 2493 * Produces task ref or TASK_NULL. 2494 */ 2495static task_t 2496convert_port_to_task_with_flavor_locked( 2497 ipc_port_t port, 2498 mach_task_flavor_t flavor, 2499 port_intrans_options_t options, 2500 task_grp_t grp) 2501{ 2502 task_t task; 2503 2504 task = convert_port_to_task_with_flavor_locked_noref(port, flavor, 2505 options); 2506 2507 if (task != TASK_NULL) { 2508 task_reference_grp(task, grp); 2509 } 2510 2511 return task; 2512} 2513 2514/* 2515 * Routine: convert_port_to_task_with_flavor 2516 * Purpose: 2517 * Internal helper for converting from a port to a task. 2518 * Doesn't consume the port ref; produces a task ref, 2519 * which may be null. 2520 * Args: 2521 * port - target port 2522 * flavor - requested task port flavor 2523 * options - port translation options 2524 * grp - task reference group 2525 * Conditions: 2526 * Nothing locked. 2527 */ 2528static task_t 2529convert_port_to_task_with_flavor( 2530 ipc_port_t port, 2531 mach_task_flavor_t flavor, 2532 port_intrans_options_t options, 2533 task_grp_t grp) 2534{ 2535 task_t task = TASK_NULL; 2536 task_t self = current_task(); 2537 2538 if (IP_VALID(port)) { 2539 if (port == self->itk_task_ports[TASK_FLAVOR_CONTROL]) { 2540 task_reference_grp(self, grp); 2541 return self; 2542 } 2543 2544 ip_mq_lock(port); 2545 if (ip_active(port)) { 2546 task = convert_port_to_task_with_flavor_locked(port, 2547 flavor, options, grp); 2548 } 2549 ip_mq_unlock(port); 2550 } 2551 2552 return task; 2553} 2554 2555task_t 2556convert_port_to_task( 2557 ipc_port_t port) 2558{ 2559 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_CONTROL, 2560 PORT_INTRANS_OPTIONS_NONE, TASK_GRP_KERNEL); 2561} 2562 2563task_t 2564convert_port_to_task_mig( 2565 ipc_port_t port) 2566{ 2567 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_CONTROL, 2568 PORT_INTRANS_OPTIONS_NONE, TASK_GRP_MIG); 2569} 2570 2571task_read_t 2572convert_port_to_task_read( 2573 ipc_port_t port) 2574{ 2575 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_READ, 2576 PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_KERNEL); 2577} 2578 2579task_read_t 2580convert_port_to_task_read_no_eval( 2581 ipc_port_t port) 2582{ 2583 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_READ, 2584 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_KERNEL); 2585} 2586 2587task_read_t 2588convert_port_to_task_read_mig( 2589 ipc_port_t port) 2590{ 2591 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_READ, 2592 PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_MIG); 2593} 2594 2595task_inspect_t 2596convert_port_to_task_inspect( 2597 ipc_port_t port) 2598{ 2599 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_INSPECT, 2600 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_KERNEL); 2601} 2602 2603task_inspect_t 2604convert_port_to_task_inspect_no_eval( 2605 ipc_port_t port) 2606{ 2607 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_INSPECT, 2608 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_KERNEL); 2609} 2610 2611task_inspect_t 2612convert_port_to_task_inspect_mig( 2613 ipc_port_t port) 2614{ 2615 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_INSPECT, 2616 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_MIG); 2617} 2618 2619task_name_t 2620convert_port_to_task_name( 2621 ipc_port_t port) 2622{ 2623 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_NAME, 2624 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_KERNEL); 2625} 2626 2627task_name_t 2628convert_port_to_task_name_mig( 2629 ipc_port_t port) 2630{ 2631 return convert_port_to_task_with_flavor(port, TASK_FLAVOR_NAME, 2632 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_MIG); 2633} 2634 2635/* 2636 * Routine: convert_port_to_task_policy 2637 * Purpose: 2638 * Convert from a port to a task. 2639 * Doesn't consume the port ref; produces a task ref, 2640 * which may be null. 2641 * If the port is being used with task_port_set(), any task port 2642 * type other than TASK_CONTROL requires an entitlement. If the 2643 * port is being used with task_port_get(), TASK_NAME requires an 2644 * entitlement. 2645 * Conditions: 2646 * Nothing locked. 2647 */ 2648static task_t 2649convert_port_to_task_policy_mig(ipc_port_t port, boolean_t set) 2650{ 2651 task_t task = TASK_NULL; 2652 2653 if (!IP_VALID(port)) { 2654 return TASK_NULL; 2655 } 2656 2657 task = set ? 2658 convert_port_to_task_mig(port) : 2659 convert_port_to_task_inspect_mig(port); 2660 2661 if (task == TASK_NULL && 2662 IOCurrentTaskHasEntitlement("com.apple.private.task_policy")) { 2663 task = convert_port_to_task_name_mig(port); 2664 } 2665 2666 return task; 2667} 2668 2669task_policy_set_t 2670convert_port_to_task_policy_set_mig(ipc_port_t port) 2671{ 2672 return convert_port_to_task_policy_mig(port, true); 2673} 2674 2675task_policy_get_t 2676convert_port_to_task_policy_get_mig(ipc_port_t port) 2677{ 2678 return convert_port_to_task_policy_mig(port, false); 2679} 2680 2681/* 2682 * Routine: convert_port_to_task_suspension_token 2683 * Purpose: 2684 * Convert from a port to a task suspension token. 2685 * Doesn't consume the port ref; produces a suspension token ref, 2686 * which may be null. 2687 * Conditions: 2688 * Nothing locked. 2689 */ 2690static task_suspension_token_t 2691convert_port_to_task_suspension_token_grp( 2692 ipc_port_t port, 2693 task_grp_t grp) 2694{ 2695 task_suspension_token_t task = TASK_NULL; 2696 2697 if (IP_VALID(port)) { 2698 ip_mq_lock(port); 2699 task = ipc_kobject_get_locked(port, IKOT_TASK_RESUME); 2700 if (task != TASK_NULL) { 2701 task_reference_grp(task, grp); 2702 } 2703 ip_mq_unlock(port); 2704 } 2705 2706 return task; 2707} 2708 2709task_suspension_token_t 2710convert_port_to_task_suspension_token_external( 2711 ipc_port_t port) 2712{ 2713 return convert_port_to_task_suspension_token_grp(port, TASK_GRP_EXTERNAL); 2714} 2715 2716task_suspension_token_t 2717convert_port_to_task_suspension_token_mig( 2718 ipc_port_t port) 2719{ 2720 return convert_port_to_task_suspension_token_grp(port, TASK_GRP_MIG); 2721} 2722 2723task_suspension_token_t 2724convert_port_to_task_suspension_token_kernel( 2725 ipc_port_t port) 2726{ 2727 return convert_port_to_task_suspension_token_grp(port, TASK_GRP_KERNEL); 2728} 2729 2730/* 2731 * Routine: convert_port_to_space_with_flavor 2732 * Purpose: 2733 * Internal helper for converting from a port to a space. 2734 * Doesn't consume the port ref; produces a space ref, 2735 * which may be null. 2736 * Args: 2737 * port - target port 2738 * flavor - requested ipc space flavor 2739 * options - port translation options 2740 * Conditions: 2741 * Nothing locked. 2742 */ 2743static ipc_space_t 2744convert_port_to_space_with_flavor( 2745 ipc_port_t port, 2746 mach_task_flavor_t flavor, 2747 port_intrans_options_t options) 2748{ 2749 ipc_space_t space = IPC_SPACE_NULL; 2750 task_t task = TASK_NULL; 2751 2752 assert(flavor != TASK_FLAVOR_NAME); 2753 2754 if (IP_VALID(port)) { 2755 ip_mq_lock(port); 2756 if (ip_active(port)) { 2757 task = convert_port_to_task_with_flavor_locked_noref(port, 2758 flavor, options); 2759 } 2760 2761 /* 2762 * Because we hold the port lock and we could resolve a task, 2763 * even if we're racing with task termination, we know that 2764 * ipc_task_disable() hasn't been called yet. 2765 * 2766 * We try to sniff if `task->active` flipped to accelerate 2767 * resolving the race, but this isn't load bearing. 2768 * 2769 * The space will be torn down _after_ ipc_task_disable() returns, 2770 * so it is valid to take a reference on it now. 2771 */ 2772 if (task && task->active) { 2773 space = task->itk_space; 2774 is_reference(space); 2775 } 2776 ip_mq_unlock(port); 2777 } 2778 2779 return space; 2780} 2781 2782ipc_space_t 2783convert_port_to_space( 2784 ipc_port_t port) 2785{ 2786 return convert_port_to_space_with_flavor(port, TASK_FLAVOR_CONTROL, 2787 PORT_INTRANS_OPTIONS_NONE); 2788} 2789 2790ipc_space_read_t 2791convert_port_to_space_read( 2792 ipc_port_t port) 2793{ 2794 return convert_port_to_space_with_flavor(port, TASK_FLAVOR_READ, 2795 PORT_INTRANS_ALLOW_CORPSE_TASK); 2796} 2797 2798ipc_space_read_t 2799convert_port_to_space_read_no_eval( 2800 ipc_port_t port) 2801{ 2802 return convert_port_to_space_with_flavor(port, TASK_FLAVOR_READ, 2803 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK); 2804} 2805 2806ipc_space_inspect_t 2807convert_port_to_space_inspect( 2808 ipc_port_t port) 2809{ 2810 return convert_port_to_space_with_flavor(port, TASK_FLAVOR_INSPECT, 2811 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK); 2812} 2813 2814/* 2815 * Routine: convert_port_to_map_with_flavor 2816 * Purpose: 2817 * Internal helper for converting from a port to a map. 2818 * Doesn't consume the port ref; produces a map ref, 2819 * which may be null. 2820 * Args: 2821 * port - target port 2822 * flavor - requested vm map flavor 2823 * options - port translation options 2824 * Conditions: 2825 * Nothing locked. 2826 */ 2827static vm_map_t 2828convert_port_to_map_with_flavor( 2829 ipc_port_t port, 2830 mach_task_flavor_t flavor, 2831 port_intrans_options_t options) 2832{ 2833 task_t task = TASK_NULL; 2834 vm_map_t map = VM_MAP_NULL; 2835 2836 /* there is no vm_map_inspect_t routines at the moment. */ 2837 assert(flavor != TASK_FLAVOR_NAME && flavor != TASK_FLAVOR_INSPECT); 2838 assert((options & PORT_INTRANS_SKIP_TASK_EVAL) == 0); 2839 2840 if (IP_VALID(port)) { 2841 ip_mq_lock(port); 2842 2843 if (ip_active(port)) { 2844 task = convert_port_to_task_with_flavor_locked_noref(port, 2845 flavor, options); 2846 } 2847 2848 /* 2849 * Because we hold the port lock and we could resolve a task, 2850 * even if we're racing with task termination, we know that 2851 * ipc_task_disable() hasn't been called yet. 2852 * 2853 * We try to sniff if `task->active` flipped to accelerate 2854 * resolving the race, but this isn't load bearing. 2855 * 2856 * The vm map will be torn down _after_ ipc_task_disable() returns, 2857 * so it is valid to take a reference on it now. 2858 */ 2859 if (task && task->active) { 2860 map = task->map; 2861 2862 if (map->pmap == kernel_pmap) { 2863 panic("userspace has control access to a " 2864 "kernel map %p through task %p", map, task); 2865 } 2866 2867 pmap_require(map->pmap); 2868 vm_map_reference(map); 2869 } 2870 2871 ip_mq_unlock(port); 2872 } 2873 2874 return map; 2875} 2876 2877vm_map_t 2878convert_port_to_map( 2879 ipc_port_t port) 2880{ 2881 return convert_port_to_map_with_flavor(port, TASK_FLAVOR_CONTROL, 2882 PORT_INTRANS_OPTIONS_NONE); 2883} 2884 2885vm_map_read_t 2886convert_port_to_map_read( 2887 ipc_port_t port) 2888{ 2889 return convert_port_to_map_with_flavor(port, TASK_FLAVOR_READ, 2890 PORT_INTRANS_ALLOW_CORPSE_TASK); 2891} 2892 2893vm_map_inspect_t 2894convert_port_to_map_inspect( 2895 __unused ipc_port_t port) 2896{ 2897 /* there is no vm_map_inspect_t routines at the moment. */ 2898 return VM_MAP_INSPECT_NULL; 2899} 2900 2901/* 2902 * Routine: thread_port_kotype_valid_for_flavor 2903 * Purpose: 2904 * Check whether the kobject type of a mach port 2905 * is valid for conversion to a thread of given flavor. 2906 */ 2907static boolean_t 2908thread_port_kotype_valid_for_flavor( 2909 natural_t kotype, 2910 mach_thread_flavor_t flavor) 2911{ 2912 switch (flavor) { 2913 /* Ascending capability */ 2914 case THREAD_FLAVOR_INSPECT: 2915 if (kotype == IKOT_THREAD_INSPECT) { 2916 return TRUE; 2917 } 2918 OS_FALLTHROUGH; 2919 case THREAD_FLAVOR_READ: 2920 if (kotype == IKOT_THREAD_READ) { 2921 return TRUE; 2922 } 2923 OS_FALLTHROUGH; 2924 case THREAD_FLAVOR_CONTROL: 2925 if (kotype == IKOT_THREAD_CONTROL) { 2926 return TRUE; 2927 } 2928 break; 2929 default: 2930 panic("strange thread flavor"); 2931 } 2932 2933 return FALSE; 2934} 2935 2936/* 2937 * Routine: convert_port_to_thread_with_flavor_locked 2938 * Purpose: 2939 * Internal helper routine to convert from a locked port to a thread. 2940 * Args: 2941 * port - target port 2942 * flavor - requested thread port flavor 2943 * options - port translation options 2944 * Conditions: 2945 * Port is locked and active. 2946 * Produces a thread ref or THREAD_NULL. 2947 */ 2948static thread_t 2949convert_port_to_thread_with_flavor_locked( 2950 ipc_port_t port, 2951 mach_thread_flavor_t flavor, 2952 port_intrans_options_t options) 2953{ 2954 thread_t thread = THREAD_NULL; 2955 task_t task; 2956 ipc_kobject_type_t type = ip_type(port); 2957 2958 ip_mq_lock_held(port); 2959 require_ip_active(port); 2960 2961 if (!thread_port_kotype_valid_for_flavor(type, flavor)) { 2962 return THREAD_NULL; 2963 } 2964 2965 thread = ipc_kobject_get_locked(port, type); 2966 2967 if (thread == THREAD_NULL) { 2968 return THREAD_NULL; 2969 } 2970 2971 if (options & PORT_INTRANS_THREAD_NOT_CURRENT_THREAD) { 2972 if (thread == current_thread()) { 2973 return THREAD_NULL; 2974 } 2975 } 2976 2977 task = get_threadtask(thread); 2978 2979 if (options & PORT_INTRANS_THREAD_IN_CURRENT_TASK) { 2980 if (task != current_task()) { 2981 return THREAD_NULL; 2982 } 2983 } else { 2984 if (!(options & PORT_INTRANS_ALLOW_CORPSE_TASK) && task_is_a_corpse(task)) { 2985 assert(flavor == THREAD_FLAVOR_CONTROL); 2986 return THREAD_NULL; 2987 } 2988 /* TODO: rdar://42389187 */ 2989 if (flavor == THREAD_FLAVOR_INSPECT) { 2990 assert(options & PORT_INTRANS_SKIP_TASK_EVAL); 2991 } 2992 2993 if (!(options & PORT_INTRANS_SKIP_TASK_EVAL) && 2994 task_conversion_eval(current_task(), task, flavor) != KERN_SUCCESS) { 2995 return THREAD_NULL; 2996 } 2997 } 2998 2999 thread_reference(thread); 3000 return thread; 3001} 3002 3003/* 3004 * Routine: convert_port_to_thread_with_flavor 3005 * Purpose: 3006 * Internal helper for converting from a port to a thread. 3007 * Doesn't consume the port ref; produces a thread ref, 3008 * which may be null. 3009 * Args: 3010 * port - target port 3011 * flavor - requested thread port flavor 3012 * options - port translation options 3013 * Conditions: 3014 * Nothing locked. 3015 */ 3016static thread_t 3017convert_port_to_thread_with_flavor( 3018 ipc_port_t port, 3019 mach_thread_flavor_t flavor, 3020 port_intrans_options_t options) 3021{ 3022 thread_t thread = THREAD_NULL; 3023 3024 if (IP_VALID(port)) { 3025 ip_mq_lock(port); 3026 if (ip_active(port)) { 3027 thread = convert_port_to_thread_with_flavor_locked(port, 3028 flavor, options); 3029 } 3030 ip_mq_unlock(port); 3031 } 3032 3033 return thread; 3034} 3035 3036thread_t 3037convert_port_to_thread( 3038 ipc_port_t port) 3039{ 3040 return convert_port_to_thread_with_flavor(port, THREAD_FLAVOR_CONTROL, 3041 PORT_INTRANS_OPTIONS_NONE); 3042} 3043 3044thread_read_t 3045convert_port_to_thread_read( 3046 ipc_port_t port) 3047{ 3048 return convert_port_to_thread_with_flavor(port, THREAD_FLAVOR_READ, 3049 PORT_INTRANS_ALLOW_CORPSE_TASK); 3050} 3051 3052static thread_read_t 3053convert_port_to_thread_read_no_eval( 3054 ipc_port_t port) 3055{ 3056 return convert_port_to_thread_with_flavor(port, THREAD_FLAVOR_READ, 3057 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK); 3058} 3059 3060thread_inspect_t 3061convert_port_to_thread_inspect( 3062 ipc_port_t port) 3063{ 3064 return convert_port_to_thread_with_flavor(port, THREAD_FLAVOR_INSPECT, 3065 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK); 3066} 3067 3068static thread_inspect_t 3069convert_port_to_thread_inspect_no_eval( 3070 ipc_port_t port) 3071{ 3072 return convert_port_to_thread_with_flavor(port, THREAD_FLAVOR_INSPECT, 3073 PORT_INTRANS_SKIP_TASK_EVAL | PORT_INTRANS_ALLOW_CORPSE_TASK); 3074} 3075 3076static inline ipc_kobject_type_t 3077thread_flavor_to_kotype(mach_thread_flavor_t flavor) 3078{ 3079 switch (flavor) { 3080 case THREAD_FLAVOR_CONTROL: 3081 return IKOT_THREAD_CONTROL; 3082 case THREAD_FLAVOR_READ: 3083 return IKOT_THREAD_READ; 3084 default: 3085 return IKOT_THREAD_INSPECT; 3086 } 3087} 3088 3089 3090ipc_port_t 3091convert_thread_to_port_immovable( 3092 thread_t thread) 3093{ 3094 thread_ro_t tro = get_thread_ro(thread); 3095 ipc_port_t port = IP_NULL; 3096 3097 thread_mtx_lock(thread); 3098 3099 if (thread->ipc_active) { 3100 port = ipc_kobject_make_send(tro->tro_ports[THREAD_FLAVOR_CONTROL], 3101 thread, IKOT_THREAD_CONTROL); 3102 } 3103 3104 thread_mtx_unlock(thread); 3105 thread_deallocate(thread); 3106 return port; 3107} 3108 3109/* 3110 * Routine: convert_thread_to_port_with_flavor 3111 * Purpose: 3112 * Convert from a thread to a port of given flavor. 3113 * Consumes a thread ref; produces a naked send right 3114 * which may be invalid. 3115 * Conditions: 3116 * Nothing locked. 3117 */ 3118static ipc_port_t 3119convert_thread_to_port_with_flavor( 3120 thread_t thread, 3121 thread_ro_t tro, 3122 mach_thread_flavor_t flavor) 3123{ 3124 ipc_kobject_type_t kotype = thread_flavor_to_kotype(flavor); 3125 ipc_port_t port = IP_NULL; 3126 3127 thread_mtx_lock(thread); 3128 3129 /* 3130 * out-trans of weaker flavors are still permitted, but in-trans 3131 * is separately enforced. 3132 */ 3133 if (flavor == THREAD_FLAVOR_CONTROL && 3134 task_conversion_eval_out_trans(current_task(), tro->tro_task, flavor)) { 3135 /* denied by security policy, make the port appear dead */ 3136 port = IP_DEAD; 3137 goto exit; 3138 } 3139 3140 if (!thread->ipc_active) { 3141 goto exit; 3142 } 3143 3144 port = tro->tro_ports[flavor]; 3145 if (flavor == THREAD_FLAVOR_CONTROL) { 3146 port = ipc_kobject_make_send(port, thread, IKOT_THREAD_CONTROL); 3147 } else if (IP_VALID(port)) { 3148 (void)ipc_kobject_make_send(port, thread, kotype); 3149 } else { 3150 ipc_object_label_t label = IPC_OBJECT_LABEL(kotype); 3151 3152 /* 3153 * If Developer Mode is off, substitute read port for control 3154 * port if copying out to owning task's space, for the sake of 3155 * in-process exception handler. 3156 * 3157 * Also see: exception_deliver(). 3158 */ 3159 if (!developer_mode_state() && flavor == THREAD_FLAVOR_READ) { 3160 label = ipc_kobject_label_alloc(kotype, 3161 IPC_LABEL_SUBST_THREAD_READ, tro->tro_ports[THREAD_FLAVOR_CONTROL]); 3162 } 3163 3164 /* 3165 * Claim a send right on the thread read/inspect port, and request a no-senders 3166 * notification on that port (if none outstanding). A thread reference is not 3167 * donated here even though the ports are created lazily because it doesn't own the 3168 * kobject that it points to. Threads manage their lifetime explicitly and 3169 * have to synchronize with each other, between the task/thread terminating and the 3170 * send-once notification firing, and this is done under the thread mutex 3171 * rather than with atomics. 3172 */ 3173 port = ipc_kobject_alloc_port(thread, label, 3174 IPC_KOBJECT_ALLOC_MAKE_SEND); 3175 3176 zalloc_ro_update_field(ZONE_ID_THREAD_RO, 3177 tro, tro_ports[flavor], &port); 3178 } 3179 3180exit: 3181 thread_mtx_unlock(thread); 3182 thread_deallocate(thread); 3183 return port; 3184} 3185 3186ipc_port_t 3187convert_thread_to_port( 3188 thread_t thread) 3189{ 3190 thread_ro_t tro = get_thread_ro(thread); 3191 return convert_thread_to_port_with_flavor(thread, tro, THREAD_FLAVOR_CONTROL); 3192} 3193 3194ipc_port_t 3195convert_thread_read_to_port(thread_read_t thread) 3196{ 3197 thread_ro_t tro = get_thread_ro(thread); 3198 return convert_thread_to_port_with_flavor(thread, tro, THREAD_FLAVOR_READ); 3199} 3200 3201ipc_port_t 3202convert_thread_inspect_to_port(thread_inspect_t thread) 3203{ 3204 thread_ro_t tro = get_thread_ro(thread); 3205 return convert_thread_to_port_with_flavor(thread, tro, THREAD_FLAVOR_INSPECT); 3206} 3207 3208void 3209convert_thread_array_to_ports( 3210 thread_act_array_t array, 3211 size_t count, 3212 mach_thread_flavor_t flavor) 3213{ 3214 thread_t *thread_list = (thread_t *)array; 3215 3216 for (size_t i = 0; i < count; i++) { 3217 thread_t thread = thread_list[i]; 3218 ipc_port_t port; 3219 3220 switch (flavor) { 3221 case THREAD_FLAVOR_CONTROL: 3222 port = convert_thread_to_port(thread); 3223 break; 3224 case THREAD_FLAVOR_READ: 3225 port = convert_thread_read_to_port(thread); 3226 break; 3227 case THREAD_FLAVOR_INSPECT: 3228 port = convert_thread_inspect_to_port(thread); 3229 break; 3230 } 3231 3232 array[i].port = port; 3233 } 3234} 3235 3236 3237/* 3238 * Routine: port_name_to_thread 3239 * Purpose: 3240 * Convert from a port name to a thread reference 3241 * A name of MACH_PORT_NULL is valid for the null thread. 3242 * Conditions: 3243 * Nothing locked. 3244 */ 3245thread_t 3246port_name_to_thread( 3247 mach_port_name_t name, 3248 port_intrans_options_t options) 3249{ 3250 thread_t thread = THREAD_NULL; 3251 ipc_port_t kport; 3252 kern_return_t kr; 3253 3254 if (MACH_PORT_VALID(name)) { 3255 kr = ipc_port_translate_send(current_space(), name, &kport); 3256 if (kr == KERN_SUCCESS) { 3257 /* port is locked and active */ 3258 assert(!(options & PORT_INTRANS_ALLOW_CORPSE_TASK) && 3259 !(options & PORT_INTRANS_SKIP_TASK_EVAL)); 3260 thread = convert_port_to_thread_with_flavor_locked(kport, 3261 THREAD_FLAVOR_CONTROL, options); 3262 ip_mq_unlock(kport); 3263 } 3264 } 3265 3266 return thread; 3267} 3268 3269/* 3270 * Routine: port_name_is_pinned_self 3271 * Purpose: 3272 * Returns whether this port name is for the pinned 3273 * mach_task_self (if it exists). 3274 * 3275 * task_self_trap() will memorize the name the port has 3276 * in the space in ip_receiver_name when it gets pinned, 3277 * which we can use to fast-track this answer without 3278 * taking any lock. 3279 * 3280 * ipc_task_disable() will set `ip_receiver_name` back to 3281 * MACH_PORT_SPECIAL_DEFAULT. 3282 * 3283 * Conditions: 3284 * self must be current_task() 3285 * Nothing locked. 3286 */ 3287static bool 3288port_name_is_pinned_self( 3289 task_t self, 3290 mach_port_name_t name) 3291{ 3292 ipc_port_t kport = self->itk_task_ports[TASK_FLAVOR_CONTROL]; 3293 return MACH_PORT_VALID(name) && name != MACH_PORT_SPECIAL_DEFAULT && 3294 ip_get_receiver_name(kport) == name; 3295} 3296 3297/* 3298 * Routine: port_name_to_current_task*_noref 3299 * Purpose: 3300 * Convert from a port name to current_task() 3301 * A name of MACH_PORT_NULL is valid for the null task. 3302 * 3303 * If current_task() is in the process of being terminated, 3304 * this might return a non NULL task even when port_name_to_task() 3305 * would. 3306 * 3307 * However, this is an acceptable race that can't be controlled by 3308 * userspace, and that downstream code using the returned task 3309 * has to handle anyway. 3310 * 3311 * ipc_space_disable() does try to narrow this race, 3312 * by causing port_name_is_pinned_self() to fail. 3313 * 3314 * Returns: 3315 * current_task() if the port name was for current_task() 3316 * at the appropriate flavor. 3317 * 3318 * TASK_NULL otherwise. 3319 * 3320 * Conditions: 3321 * Nothing locked. 3322 */ 3323static task_t 3324port_name_to_current_task_internal_noref( 3325 mach_port_name_t name, 3326 mach_task_flavor_t flavor) 3327{ 3328 ipc_port_t kport; 3329 kern_return_t kr; 3330 task_t task = TASK_NULL; 3331 task_t self = current_task(); 3332 3333 if (port_name_is_pinned_self(self, name)) { 3334 return self; 3335 } 3336 3337 if (MACH_PORT_VALID(name)) { 3338 kr = ipc_port_translate_send(self->itk_space, name, &kport); 3339 if (kr == KERN_SUCCESS) { 3340 ipc_kobject_type_t type = ip_type(kport); 3341 if (task_port_kotype_valid_for_flavor(type, flavor)) { 3342 task = ipc_kobject_get_locked(kport, type); 3343 } 3344 ip_mq_unlock(kport); 3345 if (task != self) { 3346 task = TASK_NULL; 3347 } 3348 } 3349 } 3350 3351 return task; 3352} 3353 3354task_t 3355port_name_to_current_task_noref( 3356 mach_port_name_t name) 3357{ 3358 return port_name_to_current_task_internal_noref(name, TASK_FLAVOR_CONTROL); 3359} 3360 3361task_read_t 3362port_name_to_current_task_read_noref( 3363 mach_port_name_t name) 3364{ 3365 return port_name_to_current_task_internal_noref(name, TASK_FLAVOR_READ); 3366} 3367 3368/* 3369 * Routine: port_name_to_task_grp 3370 * Purpose: 3371 * Convert from a port name to a task reference 3372 * A name of MACH_PORT_NULL is valid for the null task. 3373 * Acquire a send right if [inout] @kportp is non-null. 3374 * Conditions: 3375 * Nothing locked. 3376 */ 3377static task_t 3378port_name_to_task_grp( 3379 mach_port_name_t name, 3380 mach_task_flavor_t flavor, 3381 port_intrans_options_t options, 3382 task_grp_t grp, 3383 ipc_port_t *kportp) 3384{ 3385 ipc_port_t kport; 3386 kern_return_t kr; 3387 task_t task = TASK_NULL; 3388 task_t self = current_task(); 3389 3390 if (!kportp && port_name_is_pinned_self(self, name)) { 3391 task_reference_grp(self, grp); 3392 return self; 3393 } 3394 3395 if (MACH_PORT_VALID(name)) { 3396 kr = ipc_port_translate_send(self->itk_space, name, &kport); 3397 if (kr == KERN_SUCCESS) { 3398 /* port is locked and active */ 3399 task = convert_port_to_task_with_flavor_locked(kport, 3400 flavor, options, grp); 3401 if (kportp) { 3402 /* send right requested */ 3403 ipc_port_copy_send_any_locked(kport); 3404 *kportp = kport; 3405 } 3406 ip_mq_unlock(kport); 3407 } 3408 } 3409 return task; 3410} 3411 3412task_t 3413port_name_to_task_external( 3414 mach_port_name_t name) 3415{ 3416 return port_name_to_task_grp(name, TASK_FLAVOR_CONTROL, PORT_INTRANS_OPTIONS_NONE, TASK_GRP_EXTERNAL, NULL); 3417} 3418 3419task_t 3420port_name_to_task_kernel( 3421 mach_port_name_t name) 3422{ 3423 return port_name_to_task_grp(name, TASK_FLAVOR_CONTROL, PORT_INTRANS_OPTIONS_NONE, TASK_GRP_KERNEL, NULL); 3424} 3425 3426/* 3427 * Routine: port_name_to_task_read 3428 * Purpose: 3429 * Convert from a port name to a task reference 3430 * A name of MACH_PORT_NULL is valid for the null task. 3431 * Conditions: 3432 * Nothing locked. 3433 */ 3434task_read_t 3435port_name_to_task_read( 3436 mach_port_name_t name) 3437{ 3438 return port_name_to_task_grp(name, TASK_FLAVOR_READ, PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_KERNEL, NULL); 3439} 3440 3441/* 3442 * Routine: port_name_to_task_read_and_send_right 3443 * Purpose: 3444 * Convert from a port name to a task reference 3445 * A name of MACH_PORT_NULL is valid for the null task. 3446 * Conditions: 3447 * On success, ipc port returned with a +1 send right. 3448 */ 3449task_read_t 3450port_name_to_task_read_and_send_right( 3451 mach_port_name_t name, 3452 ipc_port_t *kportp) 3453{ 3454 return port_name_to_task_grp(name, TASK_FLAVOR_READ, PORT_INTRANS_ALLOW_CORPSE_TASK, TASK_GRP_KERNEL, kportp); 3455} 3456 3457/* 3458 * Routine: port_name_to_task_read_no_eval 3459 * Purpose: 3460 * Convert from a port name to a task reference 3461 * A name of MACH_PORT_NULL is valid for the null task. 3462 * Skips task_conversion_eval() during conversion. 3463 * Conditions: 3464 * Nothing locked. 3465 */ 3466task_read_t 3467port_name_to_task_read_no_eval( 3468 mach_port_name_t name) 3469{ 3470 port_intrans_options_t options = PORT_INTRANS_SKIP_TASK_EVAL | 3471 PORT_INTRANS_ALLOW_CORPSE_TASK; 3472 return port_name_to_task_grp(name, TASK_FLAVOR_READ, options, TASK_GRP_KERNEL, NULL); 3473} 3474 3475/* 3476 * Routine: port_name_to_task_name 3477 * Purpose: 3478 * Convert from a port name to a task reference 3479 * A name of MACH_PORT_NULL is valid for the null task. 3480 * Conditions: 3481 * Nothing locked. 3482 */ 3483task_name_t 3484port_name_to_task_name( 3485 mach_port_name_t name) 3486{ 3487 port_intrans_options_t options = PORT_INTRANS_SKIP_TASK_EVAL | 3488 PORT_INTRANS_ALLOW_CORPSE_TASK; 3489 return port_name_to_task_grp(name, TASK_FLAVOR_NAME, options, TASK_GRP_KERNEL, NULL); 3490} 3491 3492/* 3493 * Routine: port_name_to_task_id_token 3494 * Purpose: 3495 * Convert from a port name to a task identity token reference 3496 * Conditions: 3497 * Nothing locked. 3498 */ 3499task_id_token_t 3500port_name_to_task_id_token( 3501 mach_port_name_t name) 3502{ 3503 ipc_port_t port; 3504 kern_return_t kr; 3505 task_id_token_t token = TASK_ID_TOKEN_NULL; 3506 3507 if (MACH_PORT_VALID(name)) { 3508 kr = ipc_port_translate_send(current_space(), name, &port); 3509 if (kr == KERN_SUCCESS) { 3510 token = convert_port_to_task_id_token(port); 3511 ip_mq_unlock(port); 3512 } 3513 } 3514 return token; 3515} 3516 3517/* 3518 * Routine: port_name_to_host 3519 * Purpose: 3520 * Convert from a port name to a host pointer. 3521 * NOTE: This does _not_ return a +1 reference to the host_t 3522 * Conditions: 3523 * Nothing locked. 3524 */ 3525host_t 3526port_name_to_host( 3527 mach_port_name_t name) 3528{ 3529 host_t host = HOST_NULL; 3530 kern_return_t kr; 3531 ipc_port_t port; 3532 3533 if (MACH_PORT_VALID(name)) { 3534 kr = ipc_port_translate_send(current_space(), name, &port); 3535 if (kr == KERN_SUCCESS) { 3536 host = convert_port_to_host(port); 3537 ip_mq_unlock(port); 3538 } 3539 } 3540 return host; 3541} 3542 3543static inline ipc_kobject_type_t 3544task_flavor_to_kotype(mach_task_flavor_t flavor) 3545{ 3546 switch (flavor) { 3547 case TASK_FLAVOR_CONTROL: 3548 return IKOT_TASK_CONTROL; 3549 case TASK_FLAVOR_READ: 3550 return IKOT_TASK_READ; 3551 case TASK_FLAVOR_INSPECT: 3552 return IKOT_TASK_INSPECT; 3553 default: 3554 return IKOT_TASK_NAME; 3555 } 3556} 3557 3558/* 3559 * Routine: convert_task_to_port_with_flavor 3560 * Purpose: 3561 * Convert from a task to a port of given flavor. 3562 * Consumes a task ref; produces a naked send right 3563 * which may be invalid. 3564 * Conditions: 3565 * Nothing locked. 3566 */ 3567ipc_port_t 3568convert_task_to_port_with_flavor( 3569 task_t task, 3570 mach_task_flavor_t flavor, 3571 task_grp_t grp) 3572{ 3573 ipc_kobject_type_t kotype = task_flavor_to_kotype(flavor); 3574 ipc_port_t port = IP_NULL; 3575 3576 itk_lock(task); 3577 3578 if (!task->ipc_active) { 3579 goto exit; 3580 } 3581 3582 /* 3583 * out-trans of weaker flavors are still permitted, but in-trans 3584 * is separately enforced. 3585 */ 3586 if (flavor == TASK_FLAVOR_CONTROL && 3587 task_conversion_eval_out_trans(current_task(), task, flavor)) { 3588 /* denied by security policy, make the port appear dead */ 3589 port = IP_DEAD; 3590 goto exit; 3591 } 3592 3593 switch (flavor) { 3594 case TASK_FLAVOR_CONTROL: 3595 case TASK_FLAVOR_NAME: 3596 port = ipc_kobject_make_send(task->itk_task_ports[flavor], 3597 task, kotype); 3598 break; 3599 /* 3600 * Claim a send right on the task read/inspect port, 3601 * and request a no-senders notification on that port 3602 * (if none outstanding). 3603 * 3604 * The task's itk_lock is used to synchronize the handling 3605 * of the no-senders notification with the task termination. 3606 */ 3607 case TASK_FLAVOR_READ: 3608 case TASK_FLAVOR_INSPECT: 3609 port = task->itk_task_ports[flavor]; 3610 if (IP_VALID(port)) { 3611 (void)ipc_kobject_make_send(port, task, kotype); 3612 } else { 3613 ipc_object_label_t label = IPC_OBJECT_LABEL(kotype); 3614 3615 /* 3616 * If Developer Mode is off, substitute read port for control port if 3617 * copying out to owning task's space, for the sake of in-process 3618 * exception handler. 3619 * 3620 * Also see: exception_deliver(). 3621 */ 3622 if (!developer_mode_state() && flavor == TASK_FLAVOR_READ) { 3623 label = ipc_kobject_label_alloc(kotype, 3624 IPC_LABEL_SUBST_TASK_READ, task->itk_task_ports[TASK_FLAVOR_CONTROL]); 3625 } 3626 3627 port = ipc_kobject_alloc_port(task, label, 3628 IPC_KOBJECT_ALLOC_MAKE_SEND); 3629 task->itk_task_ports[flavor] = port; 3630 } 3631 break; 3632 } 3633 3634exit: 3635 itk_unlock(task); 3636 task_deallocate_grp(task, grp); 3637 return port; 3638} 3639 3640ipc_port_t 3641convert_corpse_to_port_and_nsrequest( 3642 task_t corpse) 3643{ 3644 ipc_port_t port = IP_NULL; 3645 3646 assert(task_is_a_corpse(corpse)); 3647 itk_lock(corpse); 3648 port = corpse->itk_task_ports[TASK_FLAVOR_CONTROL]; 3649 port = ipc_kobject_make_send(port, corpse, IKOT_TASK_CONTROL); 3650 itk_unlock(corpse); 3651 3652 task_deallocate(corpse); 3653 return port; 3654} 3655 3656ipc_port_t 3657convert_task_to_port( 3658 task_t task) 3659{ 3660 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_CONTROL, TASK_GRP_KERNEL); 3661} 3662 3663ipc_port_t 3664convert_task_read_to_port( 3665 task_read_t task) 3666{ 3667 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_READ, TASK_GRP_KERNEL); 3668} 3669 3670ipc_port_t 3671convert_task_inspect_to_port( 3672 task_inspect_t task) 3673{ 3674 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_INSPECT, TASK_GRP_KERNEL); 3675} 3676 3677ipc_port_t 3678convert_task_name_to_port( 3679 task_name_t task) 3680{ 3681 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_NAME, TASK_GRP_KERNEL); 3682} 3683 3684ipc_port_t 3685convert_task_to_port_external(task_t task) 3686{ 3687 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_CONTROL, TASK_GRP_EXTERNAL); 3688} 3689 3690ipc_port_t 3691convert_task_read_to_port_external(task_t task) 3692{ 3693 return convert_task_to_port_with_flavor(task, TASK_FLAVOR_READ, TASK_GRP_EXTERNAL); 3694} 3695 3696void 3697convert_task_array_to_ports( 3698 task_array_t array, 3699 size_t count, 3700 mach_task_flavor_t flavor) 3701{ 3702 task_t *task_list = (task_t *)array; 3703 3704 for (size_t i = 0; i < count; i++) { 3705 task_t task = task_list[i]; 3706 ipc_port_t port; 3707 3708 switch (flavor) { 3709 case TASK_FLAVOR_CONTROL: 3710 /* copyout determines immovability, see `should_mark_immovable_send` */ 3711 port = convert_task_to_port(task); 3712 break; 3713 case TASK_FLAVOR_READ: 3714 port = convert_task_read_to_port(task); 3715 break; 3716 case TASK_FLAVOR_INSPECT: 3717 port = convert_task_inspect_to_port(task); 3718 break; 3719 case TASK_FLAVOR_NAME: 3720 port = convert_task_name_to_port(task); 3721 break; 3722 } 3723 3724 array[i].port = port; 3725 } 3726} 3727 3728/* 3729 * Routine: convert_task_suspend_token_to_port 3730 * Purpose: 3731 * Convert from a task suspension token to a port. 3732 * Consumes a task suspension token ref; produces a naked send-once right 3733 * which may be invalid. 3734 * Conditions: 3735 * Nothing locked. 3736 */ 3737static ipc_port_t 3738convert_task_suspension_token_to_port_grp( 3739 task_suspension_token_t task, 3740 task_grp_t grp) 3741{ 3742 ipc_port_t port; 3743 3744 task_lock(task); 3745 if (task->active) { 3746 itk_lock(task); 3747 if (task->itk_resume == IP_NULL) { 3748 task->itk_resume = ipc_kobject_alloc_port((ipc_kobject_t) task, 3749 IKOT_TASK_RESUME, IPC_KOBJECT_ALLOC_NONE); 3750 } 3751 3752 /* 3753 * Create a send-once right for each instance of a direct user-called 3754 * task_suspend2 call. Each time one of these send-once rights is abandoned, 3755 * the notification handler will resume the target task. 3756 */ 3757 port = task->itk_resume; 3758 ipc_kobject_require(port, task, IKOT_TASK_RESUME); 3759 port = ipc_port_make_sonce(port); 3760 itk_unlock(task); 3761 assert(IP_VALID(port)); 3762 } else { 3763 port = IP_NULL; 3764 } 3765 3766 task_unlock(task); 3767 task_suspension_token_deallocate_grp(task, grp); 3768 3769 return port; 3770} 3771 3772ipc_port_t 3773convert_task_suspension_token_to_port_external( 3774 task_suspension_token_t task) 3775{ 3776 return convert_task_suspension_token_to_port_grp(task, TASK_GRP_EXTERNAL); 3777} 3778 3779ipc_port_t 3780convert_task_suspension_token_to_port_mig( 3781 task_suspension_token_t task) 3782{ 3783 return convert_task_suspension_token_to_port_grp(task, TASK_GRP_MIG); 3784} 3785 3786/* 3787 * Routine: space_deallocate 3788 * Purpose: 3789 * Deallocate a space ref produced by convert_port_to_space. 3790 * Conditions: 3791 * Nothing locked. 3792 */ 3793 3794void 3795space_deallocate( 3796 ipc_space_t space) 3797{ 3798 if (space != IS_NULL) { 3799 is_release(space); 3800 } 3801} 3802 3803/* 3804 * Routine: space_read_deallocate 3805 * Purpose: 3806 * Deallocate a space read ref produced by convert_port_to_space_read. 3807 * Conditions: 3808 * Nothing locked. 3809 */ 3810 3811void 3812space_read_deallocate( 3813 ipc_space_read_t space) 3814{ 3815 if (space != IS_INSPECT_NULL) { 3816 is_release((ipc_space_t)space); 3817 } 3818} 3819 3820/* 3821 * Routine: space_inspect_deallocate 3822 * Purpose: 3823 * Deallocate a space inspect ref produced by convert_port_to_space_inspect. 3824 * Conditions: 3825 * Nothing locked. 3826 */ 3827 3828void 3829space_inspect_deallocate( 3830 ipc_space_inspect_t space) 3831{ 3832 if (space != IS_INSPECT_NULL) { 3833 is_release((ipc_space_t)space); 3834 } 3835} 3836 3837 3838static boolean_t 3839behavior_is_identity_protected(int new_behavior) 3840{ 3841 return ((new_behavior & ~MACH_EXCEPTION_MASK) == EXCEPTION_IDENTITY_PROTECTED) || 3842 ((new_behavior & ~MACH_EXCEPTION_MASK) == EXCEPTION_STATE) || 3843 ((new_behavior & ~MACH_EXCEPTION_MASK) == EXCEPTION_STATE_IDENTITY_PROTECTED); 3844} 3845 3846static void 3847send_set_exception_telemetry(const task_t excepting_task, const exception_mask_t mask) 3848{ 3849 ca_event_t ca_event = CA_EVENT_ALLOCATE(set_exception); 3850 CA_EVENT_TYPE(set_exception) * event = ca_event->data; 3851 3852 task_procname(current_task(), (char *) &event->current_proc, sizeof(event->current_proc)); 3853 task_procname(excepting_task, (char *) &event->thread_proc, sizeof(event->thread_proc)); 3854 event->mask = mask; 3855 3856 CA_EVENT_SEND(ca_event); 3857} 3858 3859/* Returns whether the violation should be ignored */ 3860static boolean_t 3861set_exception_behavior_violation(const task_t excepting_task, const exception_mask_t mask, int new_behavior) 3862{ 3863 if (thid_should_crash) { 3864 /* create lightweight corpse */ 3865 mach_port_guard_exception(new_behavior, mask, kGUARD_EXC_EXCEPTION_BEHAVIOR_ENFORCE); 3866 } 3867 3868 /* always report the proc name to CA */ 3869 send_set_exception_telemetry(excepting_task, mask); 3870 3871 /* if the bootarg has been manually set to false, ignore the violation */ 3872 return !thid_should_crash; 3873} 3874 3875static bool 3876exception_exposes_protected_ports(const ipc_port_t new_port) 3877{ 3878 /* 3879 * sending exceptions to invalid port does not pose risk 3880 * ux_handler port is an immovable, read-only kobject port; doesn't need protection. 3881 */ 3882 return IP_VALID(new_port) && !is_ux_handler_port(new_port); 3883} 3884 3885static bool 3886exception_ports_frozen(task_t excepting_task) 3887{ 3888 return excepting_task && 3889 (task_ro_flags_get(excepting_task) & TFRO_FREEZE_EXCEPTION_PORTS); 3890} 3891 3892#if XNU_TARGET_OS_OSX && CONFIG_CSR 3893static bool 3894SIP_is_enabled() 3895{ 3896 return csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0; 3897} 3898#endif /* XNU_TARGET_OS_OSX && CONFIG_CSR*/ 3899 3900static bool 3901exception_is_identity_protected(const ipc_port_t new_port, int new_behavior, 3902 const task_t excepting_task, const exception_mask_t mask) 3903{ 3904 ipc_space_policy_t policy = {}; 3905 3906 /* excepting_task is NULL if we are setting a host exception port. */ 3907 if (excepting_task) { 3908 policy = ipc_policy_for_task(excepting_task); 3909 } 3910 3911 if (exception_exposes_protected_ports(new_port) 3912 && (!excepting_task || ipc_should_apply_policy(policy, IPC_POLICY_ENHANCED_V1)) 3913 && !behavior_is_identity_protected(new_behavior) 3914#if CONFIG_CSR 3915 && SIP_is_enabled() /* cannot enforce if SIP is disabled */ 3916#endif /* CONFIG_CSR */ 3917#if CONFIG_ROSETTA 3918 && !task_is_translated(current_task()) 3919#endif /* CONFIG_ROSETTA */ 3920 && !proc_is_simulated(current_proc()) 3921 ) { 3922 return set_exception_behavior_violation(excepting_task, mask, new_behavior); 3923 } 3924 3925 return true; 3926} 3927 3928static boolean_t 3929set_exception_behavior_allowed(const ipc_port_t new_port, int new_behavior, 3930 const task_t excepting_task, const exception_mask_t mask, const bool hardened_exception) 3931{ 3932 const char *excepting_task_name = ""; 3933 const char *cur_task_name = ""; 3934 3935 if (excepting_task) { 3936 excepting_task_name = task_best_name(excepting_task); 3937 } 3938 if (current_task()) { 3939 cur_task_name = task_best_name(current_task()); 3940 } 3941 3942 /* Allow debuggers, tests, and tooling to set exception ports however they wish */ 3943 if (IOCurrentTaskHasEntitlement(SET_EXCEPTION_ENTITLEMENT)) { 3944 kprintf("Allowing set_exception_ports from [%s] on [%s] for " 3945 "entitled process/debugger\n", cur_task_name, excepting_task_name); 3946 return true; 3947 } 3948 3949 /* excepting_task can be NULL if setting the host port */ 3950 if (excepting_task) { 3951 /* 3952 * Only allow hardened set_exception_port calls on hardened tasks 3953 * that opt in via entitlement 3954 */ 3955 ipc_space_policy_t pol = ipc_policy_for_task(excepting_task); 3956 bool only_one_exception_port = 3957 IOTaskHasEntitlement(excepting_task, IPC_ONLY_ONE_EXCEPTION_PORT) 3958 && ipc_should_apply_policy(pol, IPC_SPACE_POLICY_ENHANCED_V1); 3959 3960 if (!hardened_exception && only_one_exception_port) { 3961 kprintf("Disallowing set_exception_ports from [%s] on [%s] due " 3962 "to only_one_exception_port policy\n", cur_task_name, excepting_task_name); 3963 return set_exception_behavior_violation(excepting_task, mask, new_behavior); 3964 } 3965 } 3966 3967 /* Everyone else follows the standard policy and must use identity protected exceptions */ 3968 return exception_is_identity_protected(new_port, new_behavior, excepting_task, mask); 3969} 3970 3971/* 3972 * Routine: set_exception_ports_validation 3973 * Purpose: 3974 * Common argument validation shared between all exception port 3975 * setting/swapping routines 3976 * Conditions: 3977 * Nothing locked. 3978 * Returns: 3979 * KERN_SUCCESS Setting the exception port is allowed 3980 * with these arguments 3981 * KERN_INVALID_ARGUMENT Invalid arguments 3982 * KERN_INVALID_RIGHT Incorrect port configuration 3983 * KERN_DENIED Denied by security policy 3984 */ 3985kern_return_t 3986set_exception_ports_validation( 3987 task_t task, 3988 exception_mask_t exception_mask, 3989 ipc_port_t new_port, 3990 exception_behavior_t new_behavior, 3991 thread_state_flavor_t new_flavor, 3992 bool hardened_exception) 3993{ 3994 if (exception_mask & ~EXC_MASK_VALID) { 3995 return KERN_INVALID_ARGUMENT; 3996 } 3997 3998 if (IP_VALID(new_port)) { 3999 switch (new_behavior & ~MACH_EXCEPTION_MASK) { 4000 case EXCEPTION_DEFAULT: 4001 case EXCEPTION_STATE: 4002 case EXCEPTION_STATE_IDENTITY: 4003 case EXCEPTION_IDENTITY_PROTECTED: 4004 case EXCEPTION_STATE_IDENTITY_PROTECTED: 4005 break; 4006 4007 default: 4008 return KERN_INVALID_ARGUMENT; 4009 } 4010 } 4011 4012 if (IP_VALID(new_port) && !ipc_is_valid_exception_port(task, new_port)) { 4013 return KERN_INVALID_RIGHT; 4014 } 4015 4016 4017 /* 4018 * Check the validity of the thread_state_flavor by calling the 4019 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in 4020 * osfmk/mach/ARCHITECTURE/thread_status.h 4021 */ 4022 if (new_flavor != 0 && !VALID_THREAD_STATE_FLAVOR(new_flavor)) { 4023 return KERN_INVALID_ARGUMENT; 4024 } 4025 4026 if (((new_behavior & ~MACH_EXCEPTION_MASK) == EXCEPTION_IDENTITY_PROTECTED || 4027 (new_behavior & MACH_EXCEPTION_BACKTRACE_PREFERRED)) 4028 && !(new_behavior & MACH_EXCEPTION_CODES)) { 4029 return KERN_INVALID_ARGUMENT; 4030 } 4031 4032 if (!set_exception_behavior_allowed(new_port, new_behavior, task, exception_mask, hardened_exception)) { 4033 return KERN_DENIED; 4034 } 4035 4036 return KERN_SUCCESS; 4037} 4038 4039/* 4040 * Routine: thread_set_exception_ports_internal 4041 * Purpose: 4042 * Set a new exception action on the thread 4043 * Conditions: 4044 * Arguments have been validated via `set_exception_ports_validation` 4045 * Nothing locked. 4046 * Returns: 4047 * KERN_SUCCESS Setting the exception port is allowed with these arguments 4048 * KERN_FAILURE Thread is inactive 4049 */ 4050kern_return_t 4051thread_set_exception_ports_internal( 4052 thread_t thread, 4053 exception_mask_t exception_mask, 4054 ipc_port_t new_port, 4055 exception_behavior_t new_behavior, 4056 thread_state_flavor_t new_flavor, 4057 boolean_t hardened) 4058{ 4059 ipc_port_t old_port[EXC_TYPES_COUNT]; 4060 thread_ro_t tro; 4061 boolean_t privileged = task_is_privileged(current_task()); 4062 4063#if CONFIG_MACF 4064 if (mac_task_check_set_thread_exception_ports(current_task(), get_threadtask(thread), exception_mask, new_behavior) != 0) { 4065 return KERN_NO_ACCESS; 4066 } 4067 4068 struct label *new_label = mac_exc_create_label_for_current_proc(); 4069#endif 4070 4071 tro = get_thread_ro(thread); 4072 thread_mtx_lock(thread); 4073 4074 if (!thread->active) { 4075 thread_mtx_unlock(thread); 4076#if CONFIG_MACF 4077 mac_exc_free_label(new_label); 4078#endif 4079 return KERN_FAILURE; 4080 } 4081 4082 if (tro->tro_exc_actions == NULL) { 4083 ipc_thread_init_exc_actions(tro); 4084 } 4085 for (size_t i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 4086 struct exception_action *action = &tro->tro_exc_actions[i]; 4087 4088 if ((exception_mask & (1 << i)) 4089#if CONFIG_MACF 4090 && mac_exc_update_action_label(action, new_label) == 0 4091#endif 4092 ) { 4093 old_port[i] = action->port; 4094 action->port = exception_port_copy_send(new_port); 4095 action->behavior = new_behavior; 4096 action->flavor = new_flavor; 4097 action->privileged = privileged; 4098 action->hardened = hardened; 4099 } else { 4100 old_port[i] = IP_NULL; 4101 } 4102 } 4103 4104 thread_mtx_unlock(thread); 4105 4106#if CONFIG_MACF 4107 mac_exc_free_label(new_label); 4108#endif 4109 4110 for (size_t i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 4111 if (IP_VALID(old_port[i])) { 4112 ipc_port_release_send(old_port[i]); 4113 } 4114 } 4115 4116 if (IP_VALID(new_port)) { /* consume send right */ 4117 ipc_port_release_send(new_port); 4118 } 4119 4120 return KERN_SUCCESS; 4121} 4122 4123/* 4124 * Routine: thread/task_set_exception_ports [kernel call] 4125 * Purpose: 4126 * Sets the thread/task exception port, flavor and 4127 * behavior for the exception types specified by the mask. 4128 * There will be one send right per exception per valid 4129 * port. 4130 * Conditions: 4131 * Nothing locked. If successful, consumes 4132 * the supplied send right. 4133 * Returns: 4134 * KERN_SUCCESS Changed the special port. 4135 * KERN_INVALID_ARGUMENT The thread is null, 4136 * Illegal mask bit set. 4137 * Illegal exception behavior 4138 * KERN_FAILURE The thread is dead. 4139 * KERN_NO_ACCESS Restricted access to set port 4140 */ 4141 4142kern_return_t 4143thread_set_exception_ports( 4144 thread_t thread, 4145 exception_mask_t exception_mask, 4146 ipc_port_t new_port, 4147 exception_behavior_t new_behavior, 4148 thread_state_flavor_t new_flavor) 4149{ 4150 if (thread == THREAD_NULL) { 4151 return KERN_INVALID_ARGUMENT; 4152 } 4153 bool hardened_exception_flow = false; 4154 kern_return_t kr = set_exception_ports_validation(get_threadtask(thread), 4155 exception_mask, new_port, new_behavior, new_flavor, hardened_exception_flow); 4156 if (kr != KERN_SUCCESS) { 4157 return kr; 4158 } 4159 4160 return thread_set_exception_ports_internal(thread, exception_mask, new_port, new_behavior, new_flavor, false); 4161} 4162 4163kern_return_t 4164task_set_exception_ports( 4165 task_t task, 4166 exception_mask_t exception_mask, 4167 ipc_port_t new_port, 4168 exception_behavior_t new_behavior, 4169 thread_state_flavor_t new_flavor) 4170{ 4171 ipc_port_t old_port[EXC_TYPES_COUNT]; 4172 boolean_t privileged = task_is_privileged(current_task()); 4173 register int i; 4174 4175 if (task == TASK_NULL) { 4176 return KERN_INVALID_ARGUMENT; 4177 } 4178 bool hardened_exception_flow = false; 4179 kern_return_t kr = set_exception_ports_validation(task, exception_mask, 4180 new_port, new_behavior, new_flavor, hardened_exception_flow); 4181 if (kr != KERN_SUCCESS) { 4182 return kr; 4183 } 4184 4185 4186#if CONFIG_MACF 4187 if (mac_task_check_set_task_exception_ports(current_task(), task, exception_mask, new_behavior) != 0) { 4188 return KERN_NO_ACCESS; 4189 } 4190 4191 struct label *new_label = mac_exc_create_label_for_current_proc(); 4192#endif 4193 4194 itk_lock(task); 4195 4196 /* 4197 * Allow setting exception port during the span of ipc_task_init() to 4198 * ipc_task_terminate(). posix_spawn() port actions can set exception 4199 * ports on target task _before_ task IPC access is enabled. 4200 */ 4201 if (task->itk_task_ports[TASK_FLAVOR_CONTROL] == IP_NULL) { 4202 itk_unlock(task); 4203#if CONFIG_MACF 4204 mac_exc_free_label(new_label); 4205#endif 4206 return KERN_FAILURE; 4207 } 4208 4209 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 4210 if ((exception_mask & (1 << i)) 4211#if CONFIG_MACF 4212 && mac_exc_update_action_label(&task->exc_actions[i], new_label) == 0 4213#endif 4214 ) { 4215 old_port[i] = task->exc_actions[i].port; 4216 task->exc_actions[i].port = 4217 exception_port_copy_send(new_port); 4218 task->exc_actions[i].behavior = new_behavior; 4219 task->exc_actions[i].flavor = new_flavor; 4220 task->exc_actions[i].privileged = privileged; 4221 } else { 4222 old_port[i] = IP_NULL; 4223 } 4224 } 4225 4226 itk_unlock(task); 4227 4228#if CONFIG_MACF 4229 mac_exc_free_label(new_label); 4230#endif 4231 4232 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 4233 if (IP_VALID(old_port[i])) { 4234 ipc_port_release_send(old_port[i]); 4235 } 4236 } 4237 4238 if (IP_VALID(new_port)) { /* consume send right */ 4239 ipc_port_release_send(new_port); 4240 } 4241 4242 return KERN_SUCCESS; 4243} 4244 4245/* 4246 * Routine: thread/task_swap_exception_ports [kernel call] 4247 * Purpose: 4248 * Sets the thread/task exception port, flavor and 4249 * behavior for the exception types specified by the 4250 * mask. 4251 * 4252 * The old ports, behavior and flavors are returned 4253 * Count specifies the array sizes on input and 4254 * the number of returned ports etc. on output. The 4255 * arrays must be large enough to hold all the returned 4256 * data, MIG returnes an error otherwise. The masks 4257 * array specifies the corresponding exception type(s). 4258 * 4259 * Conditions: 4260 * Nothing locked. If successful, consumes 4261 * the supplied send right. 4262 * 4263 * Returns upto [in} CountCnt elements. 4264 * Returns: 4265 * KERN_SUCCESS Changed the special port. 4266 * KERN_INVALID_ARGUMENT The thread is null, 4267 * Illegal mask bit set. 4268 * Illegal exception behavior 4269 * KERN_FAILURE The thread is dead. 4270 * KERN_NO_ACCESS Restricted access to set port 4271 */ 4272 4273kern_return_t 4274thread_swap_exception_ports( 4275 thread_t thread, 4276 exception_mask_t exception_mask, 4277 ipc_port_t new_port, 4278 exception_behavior_t new_behavior, 4279 thread_state_flavor_t new_flavor, 4280 exception_mask_array_t masks, 4281 mach_msg_type_number_t *CountCnt, 4282 exception_port_array_t ports, 4283 exception_behavior_array_t behaviors, 4284 thread_state_flavor_array_t flavors) 4285{ 4286 ipc_port_t old_port[EXC_TYPES_COUNT]; 4287 thread_ro_t tro; 4288 boolean_t privileged = task_is_privileged(current_task()); 4289 unsigned int i, j, count; 4290 4291 if (thread == THREAD_NULL) { 4292 return KERN_INVALID_ARGUMENT; 4293 } 4294 bool hardened_exception_flow = false; 4295 kern_return_t kr = set_exception_ports_validation(get_threadtask(thread), 4296 exception_mask, new_port, new_behavior, new_flavor, hardened_exception_flow); 4297 if (kr != KERN_SUCCESS) { 4298 return kr; 4299 } 4300 4301#if CONFIG_MACF 4302 if (mac_task_check_set_thread_exception_ports(current_task(), get_threadtask(thread), exception_mask, new_behavior) != 0) { 4303 return KERN_NO_ACCESS; 4304 } 4305 4306 struct label *new_label = mac_exc_create_label_for_current_proc(); 4307#endif 4308 4309 thread_mtx_lock(thread); 4310 4311 if (!thread->active) { 4312 thread_mtx_unlock(thread); 4313#if CONFIG_MACF 4314 mac_exc_free_label(new_label); 4315#endif 4316 return KERN_FAILURE; 4317 } 4318 4319 tro = get_thread_ro(thread); 4320 if (tro->tro_exc_actions == NULL) { 4321 ipc_thread_init_exc_actions(tro); 4322 } 4323 4324 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION); 4325 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) { 4326 struct exception_action *action = &tro->tro_exc_actions[i]; 4327 4328 if ((exception_mask & (1 << i)) 4329#if CONFIG_MACF 4330 && mac_exc_update_action_label(action, new_label) == 0 4331#endif 4332 ) { 4333 for (j = 0; j < count; ++j) { 4334 /* 4335 * search for an identical entry, if found 4336 * set corresponding mask for this exception. 4337 */ 4338 if (action->port == ports[j] && 4339 action->behavior == behaviors[j] && 4340 action->flavor == flavors[j]) { 4341 masks[j] |= (1 << i); 4342 break; 4343 } 4344 } 4345 4346 if (j == count) { 4347 masks[j] = (1 << i); 4348 ports[j] = exception_port_copy_send(action->port); 4349 4350 behaviors[j] = action->behavior; 4351 flavors[j] = action->flavor; 4352 ++count; 4353 } 4354 4355 old_port[i] = action->port; 4356 action->port = exception_port_copy_send(new_port); 4357 action->behavior = new_behavior; 4358 action->flavor = new_flavor; 4359 action->privileged = privileged; 4360 } else { 4361 old_port[i] = IP_NULL; 4362 } 4363 } 4364 4365 thread_mtx_unlock(thread); 4366 4367#if CONFIG_MACF 4368 mac_exc_free_label(new_label); 4369#endif 4370 4371 while (--i >= FIRST_EXCEPTION) { 4372 if (IP_VALID(old_port[i])) { 4373 ipc_port_release_send(old_port[i]); 4374 } 4375 } 4376 4377 if (IP_VALID(new_port)) { /* consume send right */ 4378 ipc_port_release_send(new_port); 4379 } 4380 4381 *CountCnt = count; 4382 4383 return KERN_SUCCESS; 4384} 4385 4386kern_return_t 4387task_swap_exception_ports( 4388 task_t task, 4389 exception_mask_t exception_mask, 4390 ipc_port_t new_port, 4391 exception_behavior_t new_behavior, 4392 thread_state_flavor_t new_flavor, 4393 exception_mask_array_t masks, 4394 mach_msg_type_number_t *CountCnt, 4395 exception_port_array_t ports, 4396 exception_behavior_array_t behaviors, 4397 thread_state_flavor_array_t flavors) 4398{ 4399 ipc_port_t old_port[EXC_TYPES_COUNT]; 4400 boolean_t privileged = task_is_privileged(current_task()); 4401 unsigned int i, j, count; 4402 4403#if CONFIG_MACF 4404 struct label *new_label; 4405#endif 4406 4407 if (task == TASK_NULL) { 4408 return KERN_INVALID_ARGUMENT; 4409 } 4410 bool hardened_exception_flow = false; 4411 kern_return_t kr = set_exception_ports_validation(task, exception_mask, 4412 new_port, new_behavior, new_flavor, hardened_exception_flow); 4413 if (kr != KERN_SUCCESS) { 4414 return kr; 4415 } 4416 4417#if CONFIG_MACF 4418 if (mac_task_check_set_task_exception_ports(current_task(), task, exception_mask, new_behavior) != 0) { 4419 return KERN_NO_ACCESS; 4420 } 4421 4422 new_label = mac_exc_create_label_for_current_proc(); 4423#endif 4424 4425 itk_lock(task); 4426 4427 if (!task->ipc_active) { 4428 itk_unlock(task); 4429#if CONFIG_MACF 4430 mac_exc_free_label(new_label); 4431#endif 4432 return KERN_FAILURE; 4433 } 4434 4435 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION); 4436 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) { 4437 if ((exception_mask & (1 << i)) 4438#if CONFIG_MACF 4439 && mac_exc_update_action_label(&task->exc_actions[i], new_label) == 0 4440#endif 4441 ) { 4442 for (j = 0; j < count; j++) { 4443 /* 4444 * search for an identical entry, if found 4445 * set corresponding mask for this exception. 4446 */ 4447 if (task->exc_actions[i].port == ports[j] && 4448 task->exc_actions[i].behavior == behaviors[j] && 4449 task->exc_actions[i].flavor == flavors[j]) { 4450 masks[j] |= (1 << i); 4451 break; 4452 } 4453 } 4454 4455 if (j == count) { 4456 masks[j] = (1 << i); 4457 ports[j] = exception_port_copy_send(task->exc_actions[i].port); 4458 behaviors[j] = task->exc_actions[i].behavior; 4459 flavors[j] = task->exc_actions[i].flavor; 4460 ++count; 4461 } 4462 4463 old_port[i] = task->exc_actions[i].port; 4464 4465 task->exc_actions[i].port = exception_port_copy_send(new_port); 4466 task->exc_actions[i].behavior = new_behavior; 4467 task->exc_actions[i].flavor = new_flavor; 4468 task->exc_actions[i].privileged = privileged; 4469 } else { 4470 old_port[i] = IP_NULL; 4471 } 4472 } 4473 4474 itk_unlock(task); 4475 4476#if CONFIG_MACF 4477 mac_exc_free_label(new_label); 4478#endif 4479 4480 while (--i >= FIRST_EXCEPTION) { 4481 if (IP_VALID(old_port[i])) { 4482 ipc_port_release_send(old_port[i]); 4483 } 4484 } 4485 4486 if (IP_VALID(new_port)) { /* consume send right */ 4487 ipc_port_release_send(new_port); 4488 } 4489 4490 *CountCnt = count; 4491 4492 return KERN_SUCCESS; 4493} 4494 4495/* 4496 * Routine: thread/task_get_exception_ports [kernel call] 4497 * Purpose: 4498 * Clones a send right for each of the thread/task's exception 4499 * ports specified in the mask and returns the behaviour 4500 * and flavor of said port. 4501 * 4502 * Returns upto [in} CountCnt elements. 4503 * 4504 * Conditions: 4505 * Nothing locked. 4506 * Returns: 4507 * KERN_SUCCESS Extracted a send right. 4508 * KERN_INVALID_ARGUMENT The thread is null, 4509 * Invalid special port, 4510 * Illegal mask bit set. 4511 * KERN_FAILURE The thread is dead. 4512 */ 4513static kern_return_t 4514thread_get_exception_ports_internal( 4515 thread_t thread, 4516 exception_mask_t exception_mask, 4517 exception_mask_array_t masks, 4518 mach_msg_type_number_t *CountCnt, 4519 exception_port_info_array_t ports_info, 4520 exception_port_array_t ports, 4521 exception_behavior_array_t behaviors, 4522 thread_state_flavor_array_t flavors) 4523{ 4524 unsigned int count; 4525 boolean_t info_only = (ports_info != NULL); 4526 thread_ro_t tro; 4527 ipc_port_t port_ptrs[EXC_TYPES_COUNT]; /* pointers only, does not hold right */ 4528 4529 if (thread == THREAD_NULL) { 4530 return KERN_INVALID_ARGUMENT; 4531 } 4532 4533 if (exception_mask & ~EXC_MASK_VALID) { 4534 return KERN_INVALID_ARGUMENT; 4535 } 4536 4537 if (!info_only && !ports) { 4538 return KERN_INVALID_ARGUMENT; 4539 } 4540 4541 /* 4542 * Allocate a save area for FP state before taking thread lock, 4543 * if necessary, to ensure that VM_KERNEL_ADDRHASH() doesn't cause 4544 * an FP state allocation while holding thread locks. 4545 */ 4546 ml_fp_save_area_prealloc(); 4547 4548 tro = get_thread_ro(thread); 4549 thread_mtx_lock(thread); 4550 4551 if (!thread->active) { 4552 thread_mtx_unlock(thread); 4553 4554 return KERN_FAILURE; 4555 } 4556 4557 count = 0; 4558 4559 if (tro->tro_exc_actions == NULL) { 4560 goto done; 4561 } 4562 4563 for (int i = FIRST_EXCEPTION, j = 0; i < EXC_TYPES_COUNT; ++i) { 4564 if (exception_mask & (1 << i)) { 4565 ipc_port_t exc_port = tro->tro_exc_actions[i].port; 4566 exception_behavior_t exc_behavior = tro->tro_exc_actions[i].behavior; 4567 thread_state_flavor_t exc_flavor = tro->tro_exc_actions[i].flavor; 4568 4569 for (j = 0; j < count; ++j) { 4570 /* 4571 * search for an identical entry, if found 4572 * set corresponding mask for this exception. 4573 */ 4574 if (exc_port == port_ptrs[j] && 4575 exc_behavior == behaviors[j] && 4576 exc_flavor == flavors[j]) { 4577 masks[j] |= (1 << i); 4578 break; 4579 } 4580 } 4581 4582 if (j == count && count < *CountCnt) { 4583 masks[j] = (1 << i); 4584 port_ptrs[j] = exc_port; 4585 4586 if (info_only) { 4587 if (!IP_VALID(exc_port)) { 4588 ports_info[j] = (ipc_info_port_t){ .iip_port_object = 0, .iip_receiver_object = 0 }; 4589 } else { 4590 task_t receiver = TASK_NULL; 4591 (void)ipc_port_get_receiver_task(exc_port, &receiver); 4592 ports_info[j].iip_port_object = (natural_t)VM_KERNEL_ADDRHASH(exc_port); 4593 ports_info[j].iip_receiver_object = receiver ? (natural_t)VM_KERNEL_ADDRHASH(receiver) : 0; 4594 } 4595 } else { 4596 ports[j] = exception_port_copy_send(exc_port); 4597 } 4598 behaviors[j] = exc_behavior; 4599 flavors[j] = exc_flavor; 4600 ++count; 4601 } 4602 } 4603 } 4604 4605done: 4606 thread_mtx_unlock(thread); 4607 4608 *CountCnt = count; 4609 4610 return KERN_SUCCESS; 4611} 4612 4613kern_return_t 4614thread_get_exception_ports( 4615 thread_t thread, 4616 exception_mask_t exception_mask, 4617 exception_mask_array_t masks, 4618 mach_msg_type_number_t *CountCnt, 4619 exception_port_array_t ports, 4620 exception_behavior_array_t behaviors, 4621 thread_state_flavor_array_t flavors) 4622{ 4623 return thread_get_exception_ports_internal(thread, exception_mask, masks, CountCnt, 4624 NULL, ports, behaviors, flavors); 4625} 4626 4627kern_return_t 4628thread_get_exception_ports_info( 4629 mach_port_t port, 4630 exception_mask_t exception_mask, 4631 exception_mask_array_t masks, 4632 mach_msg_type_number_t *CountCnt, 4633 exception_port_info_array_t ports_info, 4634 exception_behavior_array_t behaviors, 4635 thread_state_flavor_array_t flavors) 4636{ 4637 kern_return_t kr; 4638 4639 thread_t thread = convert_port_to_thread_read_no_eval(port); 4640 4641 if (thread == THREAD_NULL) { 4642 return KERN_INVALID_ARGUMENT; 4643 } 4644 4645 kr = thread_get_exception_ports_internal(thread, exception_mask, masks, CountCnt, 4646 ports_info, NULL, behaviors, flavors); 4647 4648 thread_deallocate(thread); 4649 return kr; 4650} 4651 4652kern_return_t 4653thread_get_exception_ports_from_user( 4654 mach_port_t port, 4655 exception_mask_t exception_mask, 4656 exception_mask_array_t masks, 4657 mach_msg_type_number_t *CountCnt, 4658 exception_port_array_t ports, 4659 exception_behavior_array_t behaviors, 4660 thread_state_flavor_array_t flavors) 4661{ 4662 kern_return_t kr; 4663 4664 thread_t thread = convert_port_to_thread(port); 4665 4666 if (thread == THREAD_NULL) { 4667 return KERN_INVALID_ARGUMENT; 4668 } 4669 4670 kr = thread_get_exception_ports(thread, exception_mask, masks, CountCnt, ports, behaviors, flavors); 4671 4672 thread_deallocate(thread); 4673 return kr; 4674} 4675 4676static kern_return_t 4677task_get_exception_ports_internal( 4678 task_t task, 4679 exception_mask_t exception_mask, 4680 exception_mask_array_t masks, 4681 mach_msg_type_number_t *CountCnt, 4682 exception_port_info_array_t ports_info, 4683 exception_port_array_t ports, 4684 exception_behavior_array_t behaviors, 4685 thread_state_flavor_array_t flavors) 4686{ 4687 unsigned int count; 4688 boolean_t info_only = (ports_info != NULL); 4689 ipc_port_t port_ptrs[EXC_TYPES_COUNT]; /* pointers only, does not hold right */ 4690 4691 if (task == TASK_NULL) { 4692 return KERN_INVALID_ARGUMENT; 4693 } 4694 4695 if (exception_mask & ~EXC_MASK_VALID) { 4696 return KERN_INVALID_ARGUMENT; 4697 } 4698 4699 if (!info_only && !ports) { 4700 return KERN_INVALID_ARGUMENT; 4701 } 4702 4703 /* 4704 * Allocate a save area for FP state before taking task lock, 4705 * if necessary, to ensure that VM_KERNEL_ADDRHASH() doesn't cause 4706 * an FP state allocation while holding task locks. 4707 */ 4708 ml_fp_save_area_prealloc(); 4709 4710 itk_lock(task); 4711 4712 if (!task->ipc_active) { 4713 itk_unlock(task); 4714 return KERN_FAILURE; 4715 } 4716 4717 count = 0; 4718 4719 for (int i = FIRST_EXCEPTION, j = 0; i < EXC_TYPES_COUNT; ++i) { 4720 if (exception_mask & (1 << i)) { 4721 ipc_port_t exc_port = task->exc_actions[i].port; 4722 exception_behavior_t exc_behavior = task->exc_actions[i].behavior; 4723 thread_state_flavor_t exc_flavor = task->exc_actions[i].flavor; 4724 4725 for (j = 0; j < count; ++j) { 4726 /* 4727 * search for an identical entry, if found 4728 * set corresponding mask for this exception. 4729 */ 4730 if (exc_port == port_ptrs[j] && 4731 exc_behavior == behaviors[j] && 4732 exc_flavor == flavors[j]) { 4733 masks[j] |= (1 << i); 4734 break; 4735 } 4736 } 4737 4738 if (j == count && count < *CountCnt) { 4739 masks[j] = (1 << i); 4740 port_ptrs[j] = exc_port; 4741 4742 if (info_only) { 4743 if (!IP_VALID(exc_port)) { 4744 ports_info[j] = (ipc_info_port_t){ .iip_port_object = 0, .iip_receiver_object = 0 }; 4745 } else { 4746 task_t receiver = TASK_NULL; 4747 (void)ipc_port_get_receiver_task(exc_port, &receiver); 4748 ports_info[j].iip_port_object = (natural_t)VM_KERNEL_ADDRHASH(exc_port); 4749 ports_info[j].iip_receiver_object = receiver ? (natural_t)VM_KERNEL_ADDRHASH(receiver) : 0; 4750 } 4751 } else { 4752 ports[j] = exception_port_copy_send(exc_port); 4753 } 4754 behaviors[j] = exc_behavior; 4755 flavors[j] = exc_flavor; 4756 ++count; 4757 } 4758 } 4759 } 4760 4761 itk_unlock(task); 4762 4763 *CountCnt = count; 4764 4765 return KERN_SUCCESS; 4766} 4767 4768kern_return_t 4769task_get_exception_ports( 4770 task_t task, 4771 exception_mask_t exception_mask, 4772 exception_mask_array_t masks, 4773 mach_msg_type_number_t *CountCnt, 4774 exception_port_array_t ports, 4775 exception_behavior_array_t behaviors, 4776 thread_state_flavor_array_t flavors) 4777{ 4778 return task_get_exception_ports_internal(task, exception_mask, masks, CountCnt, 4779 NULL, ports, behaviors, flavors); 4780} 4781 4782kern_return_t 4783task_get_exception_ports_info( 4784 mach_port_t port, 4785 exception_mask_t exception_mask, 4786 exception_mask_array_t masks, 4787 mach_msg_type_number_t *CountCnt, 4788 exception_port_info_array_t ports_info, 4789 exception_behavior_array_t behaviors, 4790 thread_state_flavor_array_t flavors) 4791{ 4792 kern_return_t kr; 4793 4794 task_t task = convert_port_to_task_read_no_eval(port); 4795 4796 if (task == TASK_NULL) { 4797 return KERN_INVALID_ARGUMENT; 4798 } 4799 4800 kr = task_get_exception_ports_internal(task, exception_mask, masks, CountCnt, 4801 ports_info, NULL, behaviors, flavors); 4802 4803 task_deallocate(task); 4804 return kr; 4805} 4806 4807kern_return_t 4808task_get_exception_ports_from_user( 4809 mach_port_t port, 4810 exception_mask_t exception_mask, 4811 exception_mask_array_t masks, 4812 mach_msg_type_number_t *CountCnt, 4813 exception_port_array_t ports, 4814 exception_behavior_array_t behaviors, 4815 thread_state_flavor_array_t flavors) 4816{ 4817 kern_return_t kr; 4818 4819 task_t task = convert_port_to_task(port); 4820 4821 if (task == TASK_NULL) { 4822 return KERN_INVALID_ARGUMENT; 4823 } 4824 4825 kr = task_get_exception_ports(task, exception_mask, masks, CountCnt, ports, behaviors, flavors); 4826 4827 task_deallocate(task); 4828 return kr; 4829} 4830 4831/* 4832 * Routine: ipc_thread_port_unpin 4833 * Purpose: 4834 * 4835 * Called on the thread when it's terminating so that the last ref 4836 * can be deallocated without a guard exception. 4837 * Conditions: 4838 * Thread mutex lock is held. 4839 */ 4840void 4841ipc_thread_port_unpin( 4842 ipc_port_t port) 4843{ 4844 ipc_object_unpin(current_space(), port); 4845} 4846 4847/* 4848 * Routine: task_register_hardened_exception_handler 4849 * Purpose: 4850 * Register a port as a hardened exception handler. 4851 * See task.defs for additional info 4852 * Conditions: 4853 * Nothing locked. 4854 * Limit of one hardened exception handler per task 4855 * Returns: 4856 * KERN_INVALID_ARGUMENT invalid thread 4857 * KERN_DENIED violating the security policy 4858 * KERN_NAME_EXISTS Already set a hardened exception handler 4859 * on this task 4860 * KERN_SUCCESS 4861 */ 4862kern_return_t 4863task_register_hardened_exception_handler( 4864 task_t task, 4865 uint32_t signed_pc_key, 4866 exception_mask_t exceptions_allowed, 4867 exception_behavior_t behaviors_allowed, 4868 thread_state_flavor_t flavors_allowed, 4869 mach_port_t new_port) 4870{ 4871 ipc_port_t old_port; 4872 4873 if (task == TASK_NULL) { 4874 return KERN_INVALID_ARGUMENT; 4875 } 4876 if (IP_VALID(new_port) && !ip_is_exception_port(new_port)) { 4877 return KERN_INVALID_ARGUMENT; 4878 } 4879 4880 4881 bool hardened_exception_flow = true; 4882 kern_return_t kr = set_exception_ports_validation(task, exceptions_allowed, 4883 new_port, behaviors_allowed, flavors_allowed, hardened_exception_flow); 4884 if (kr != KERN_SUCCESS) { 4885 return kr; 4886 } 4887 4888 /* You can only register one hardened exception handler */ 4889 if (exception_ports_frozen(task)) { 4890 return KERN_INVALID_ARGUMENT; 4891 } 4892 task_ro_flags_set(task, TFRO_FREEZE_EXCEPTION_PORTS); 4893 itk_lock(task); 4894 4895 /* No reason to allow setting this multiple times per task */ 4896 old_port = task->hardened_exception_action.ea.port; 4897 if (IP_VALID(old_port)) { 4898 itk_unlock(task); 4899 return KERN_NAME_EXISTS; 4900 } 4901 4902 /* Stash the semantics for this port on the task */ 4903 struct hardened_exception_action hea; 4904 hea.ea.port = new_port; /* Donate our send right to the task */ 4905 hea.ea.flavor = flavors_allowed; 4906 hea.ea.behavior = behaviors_allowed; 4907 hea.ea.privileged = false; 4908 hea.ea.label = NULL; 4909 hea.signed_pc_key = signed_pc_key; 4910 hea.exception = exceptions_allowed; 4911 4912 task->hardened_exception_action = hea; 4913 itk_unlock(task); 4914 4915 return KERN_SUCCESS; 4916} 4917 4918/* 4919 * Routine: thread_adopt_exception_handler 4920 * Purpose: 4921 * Adopt the hardened exception handler from the current task, 4922 * for this thread. 4923 * 4924 * Allows to set exception ports on a thread after exception ports 4925 * have been frozen for the task. 4926 * Conditions: 4927 * Nothing locked 4928 * Returns: 4929 * KERN_INVALID_ARGUMENT invalid thread 4930 * KERN_DENIED violating the security policy 4931 * KERN_SUCCESS 4932 */ 4933kern_return_t 4934thread_adopt_exception_handler( 4935 thread_t thread, 4936 mach_port_t exc_port, 4937 exception_mask_t exc_mask, 4938 exception_behavior_t behavior_mask, 4939 thread_state_flavor_t flavor_mask) 4940{ 4941 if (thread == THREAD_NULL) { 4942 return KERN_INVALID_ARGUMENT; 4943 } 4944 4945 task_t task = get_threadtask(thread); 4946 4947 if (task != current_task()) { 4948 return KERN_DENIED; 4949 } 4950 4951 /* We must have exactly one hardened exception port per task */ 4952 if (!exception_ports_frozen(task)) { 4953 return KERN_DENIED; 4954 } 4955 4956 /* Ensure we see a consistent state of the hardened exception action */ 4957 itk_lock(task); 4958 struct hardened_exception_action hea = task->hardened_exception_action; 4959 itk_unlock(task); 4960 4961 if (exc_port != IP_NULL && exc_port != hea.ea.port) { 4962 return KERN_DENIED; 4963 } 4964 /* Ensure that the new masks for this thread are a subset of the 4965 * allowable masks for this exception handler 4966 */ 4967 if (exc_mask & ~hea.exception || 4968 behavior_mask & ~hea.ea.behavior || 4969 flavor_mask & ~hea.ea.flavor) { 4970 return KERN_DENIED; 4971 } 4972 4973 assert(!IP_VALID(exc_port) || ip_is_exception_port(exc_port)); 4974 4975 /* 4976 * We can safely assume this will be valid because we called 4977 * set_exception_ports_validation on it when it was originally 4978 * set on the task 4979 */ 4980 return thread_set_exception_ports_internal(thread, exc_mask, exc_port, 4981 behavior_mask, flavor_mask, true); 4982}