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 <mach/mach_types.h> 72#include <mach/boolean.h> 73#include <mach/kern_return.h> 74#include <mach/mach_param.h> 75#include <mach/task_special_ports.h> 76#include <mach/thread_special_ports.h> 77#include <mach/thread_status.h> 78#include <mach/exception_types.h> 79#include <mach/memory_object_types.h> 80#include <mach/mach_traps.h> 81#include <mach/task_server.h> 82#include <mach/thread_act_server.h> 83#include <mach/mach_host_server.h> 84#include <mach/host_priv_server.h> 85#include <mach/vm_map_server.h> 86 87#include <kern/kern_types.h> 88#include <kern/host.h> 89#include <kern/ipc_kobject.h> 90#include <kern/ipc_tt.h> 91#include <kern/kalloc.h> 92#include <kern/thread.h> 93#include <kern/misc_protos.h> 94 95#include <vm/vm_map.h> 96#include <vm/vm_pageout.h> 97#include <vm/vm_protos.h> 98 99#include <security/mac_mach_internal.h> 100 101/* forward declarations */ 102task_t convert_port_to_locked_task(ipc_port_t port); 103 104 105/* 106 * Routine: ipc_task_init 107 * Purpose: 108 * Initialize a task's IPC state. 109 * 110 * If non-null, some state will be inherited from the parent. 111 * The parent must be appropriately initialized. 112 * Conditions: 113 * Nothing locked. 114 */ 115 116void 117ipc_task_init( 118 task_t task, 119 task_t parent) 120{ 121 ipc_space_t space; 122 ipc_port_t kport; 123 ipc_port_t nport; 124 kern_return_t kr; 125 int i; 126 127 128 kr = ipc_space_create(&ipc_table_entries[0], &space); 129 if (kr != KERN_SUCCESS) 130 panic("ipc_task_init"); 131 132 space->is_task = task; 133 134 kport = ipc_port_alloc_kernel(); 135 if (kport == IP_NULL) 136 panic("ipc_task_init"); 137 138 nport = ipc_port_alloc_kernel(); 139 if (nport == IP_NULL) 140 panic("ipc_task_init"); 141 142 itk_lock_init(task); 143 task->itk_self = kport; 144 task->itk_nself = nport; 145 task->itk_resume = IP_NULL; /* Lazily allocated on-demand */ 146 task->itk_sself = ipc_port_make_send(kport); 147 task->itk_space = space; 148 149#if CONFIG_MACF_MACH 150 if (parent) 151 mac_task_label_associate(parent, task, &parent->maclabel, 152 &task->maclabel, &kport->ip_label); 153 else 154 mac_task_label_associate_kernel(task, &task->maclabel, &kport->ip_label); 155#endif 156 157 if (parent == TASK_NULL) { 158 ipc_port_t port; 159 160 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 161 task->exc_actions[i].port = IP_NULL; 162 }/* for */ 163 164 kr = host_get_host_port(host_priv_self(), &port); 165 assert(kr == KERN_SUCCESS); 166 task->itk_host = port; 167 168 task->itk_bootstrap = IP_NULL; 169 task->itk_seatbelt = IP_NULL; 170 task->itk_gssd = IP_NULL; 171 task->itk_task_access = IP_NULL; 172 173 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) 174 task->itk_registered[i] = IP_NULL; 175 } else { 176 itk_lock(parent); 177 assert(parent->itk_self != IP_NULL); 178 179 /* inherit registered ports */ 180 181 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) 182 task->itk_registered[i] = 183 ipc_port_copy_send(parent->itk_registered[i]); 184 185 /* inherit exception and bootstrap ports */ 186 187 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 188 task->exc_actions[i].port = 189 ipc_port_copy_send(parent->exc_actions[i].port); 190 task->exc_actions[i].flavor = 191 parent->exc_actions[i].flavor; 192 task->exc_actions[i].behavior = 193 parent->exc_actions[i].behavior; 194 task->exc_actions[i].privileged = 195 parent->exc_actions[i].privileged; 196 }/* for */ 197 task->itk_host = 198 ipc_port_copy_send(parent->itk_host); 199 200 task->itk_bootstrap = 201 ipc_port_copy_send(parent->itk_bootstrap); 202 203 task->itk_seatbelt = 204 ipc_port_copy_send(parent->itk_seatbelt); 205 206 task->itk_gssd = 207 ipc_port_copy_send(parent->itk_gssd); 208 209 task->itk_task_access = 210 ipc_port_copy_send(parent->itk_task_access); 211 212 itk_unlock(parent); 213 } 214} 215 216/* 217 * Routine: ipc_task_enable 218 * Purpose: 219 * Enable a task for IPC access. 220 * Conditions: 221 * Nothing locked. 222 */ 223 224void 225ipc_task_enable( 226 task_t task) 227{ 228 ipc_port_t kport; 229 ipc_port_t nport; 230 231 itk_lock(task); 232 kport = task->itk_self; 233 if (kport != IP_NULL) 234 ipc_kobject_set(kport, (ipc_kobject_t) task, IKOT_TASK); 235 nport = task->itk_nself; 236 if (nport != IP_NULL) 237 ipc_kobject_set(nport, (ipc_kobject_t) task, IKOT_TASK_NAME); 238 itk_unlock(task); 239} 240 241/* 242 * Routine: ipc_task_disable 243 * Purpose: 244 * Disable IPC access to a task. 245 * Conditions: 246 * Nothing locked. 247 */ 248 249void 250ipc_task_disable( 251 task_t task) 252{ 253 ipc_port_t kport; 254 ipc_port_t nport; 255 ipc_port_t rport; 256 257 itk_lock(task); 258 kport = task->itk_self; 259 if (kport != IP_NULL) 260 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); 261 nport = task->itk_nself; 262 if (nport != IP_NULL) 263 ipc_kobject_set(nport, IKO_NULL, IKOT_NONE); 264 265 rport = task->itk_resume; 266 if (rport != IP_NULL) { 267 /* 268 * From this point onwards this task is no longer accepting 269 * resumptions. 270 * 271 * There are still outstanding suspensions on this task, 272 * even as it is being torn down. Disconnect the task 273 * from the rport, thereby "orphaning" the rport. The rport 274 * itself will go away only when the last suspension holder 275 * destroys his SO right to it -- when he either 276 * exits, or tries to actually use that last SO right to 277 * resume this (now non-existent) task. 278 */ 279 ipc_kobject_set(rport, IKO_NULL, IKOT_NONE); 280 } 281 itk_unlock(task); 282} 283 284/* 285 * Routine: ipc_task_terminate 286 * Purpose: 287 * Clean up and destroy a task's IPC state. 288 * Conditions: 289 * Nothing locked. The task must be suspended. 290 * (Or the current thread must be in the task.) 291 */ 292 293void 294ipc_task_terminate( 295 task_t task) 296{ 297 ipc_port_t kport; 298 ipc_port_t nport; 299 ipc_port_t rport; 300 int i; 301 302 itk_lock(task); 303 kport = task->itk_self; 304 305 if (kport == IP_NULL) { 306 /* the task is already terminated (can this happen?) */ 307 itk_unlock(task); 308 return; 309 } 310 task->itk_self = IP_NULL; 311 312 nport = task->itk_nself; 313 assert(nport != IP_NULL); 314 task->itk_nself = IP_NULL; 315 316 rport = task->itk_resume; 317 task->itk_resume = IP_NULL; 318 319 itk_unlock(task); 320 321 /* release the naked send rights */ 322 323 if (IP_VALID(task->itk_sself)) 324 ipc_port_release_send(task->itk_sself); 325 326 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 327 if (IP_VALID(task->exc_actions[i].port)) { 328 ipc_port_release_send(task->exc_actions[i].port); 329 } 330 } 331 332 if (IP_VALID(task->itk_host)) 333 ipc_port_release_send(task->itk_host); 334 335 if (IP_VALID(task->itk_bootstrap)) 336 ipc_port_release_send(task->itk_bootstrap); 337 338 if (IP_VALID(task->itk_seatbelt)) 339 ipc_port_release_send(task->itk_seatbelt); 340 341 if (IP_VALID(task->itk_gssd)) 342 ipc_port_release_send(task->itk_gssd); 343 344 if (IP_VALID(task->itk_task_access)) 345 ipc_port_release_send(task->itk_task_access); 346 347 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) 348 if (IP_VALID(task->itk_registered[i])) 349 ipc_port_release_send(task->itk_registered[i]); 350 351 /* destroy the kernel ports */ 352 ipc_port_dealloc_kernel(kport); 353 ipc_port_dealloc_kernel(nport); 354 if (rport != IP_NULL) 355 ipc_port_dealloc_kernel(rport); 356 357 itk_lock_destroy(task); 358} 359 360/* 361 * Routine: ipc_task_reset 362 * Purpose: 363 * Reset a task's IPC state to protect it when 364 * it enters an elevated security context. The 365 * task name port can remain the same - since 366 * it represents no specific privilege. 367 * Conditions: 368 * Nothing locked. The task must be suspended. 369 * (Or the current thread must be in the task.) 370 */ 371 372void 373ipc_task_reset( 374 task_t task) 375{ 376 ipc_port_t old_kport, new_kport; 377 ipc_port_t old_sself; 378 ipc_port_t old_exc_actions[EXC_TYPES_COUNT]; 379 int i; 380 381 new_kport = ipc_port_alloc_kernel(); 382 if (new_kport == IP_NULL) 383 panic("ipc_task_reset"); 384 385 itk_lock(task); 386 387 old_kport = task->itk_self; 388 389 if (old_kport == IP_NULL) { 390 /* the task is already terminated (can this happen?) */ 391 itk_unlock(task); 392 ipc_port_dealloc_kernel(new_kport); 393 return; 394 } 395 396 task->itk_self = new_kport; 397 old_sself = task->itk_sself; 398 task->itk_sself = ipc_port_make_send(new_kport); 399 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE); 400 ipc_kobject_set(new_kport, (ipc_kobject_t) task, IKOT_TASK); 401 402 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 403 if (!task->exc_actions[i].privileged) { 404 old_exc_actions[i] = task->exc_actions[i].port; 405 task->exc_actions[i].port = IP_NULL; 406 } else { 407 old_exc_actions[i] = IP_NULL; 408 } 409 }/* for */ 410 411 itk_unlock(task); 412 413 /* release the naked send rights */ 414 415 if (IP_VALID(old_sself)) 416 ipc_port_release_send(old_sself); 417 418 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 419 if (IP_VALID(old_exc_actions[i])) { 420 ipc_port_release_send(old_exc_actions[i]); 421 } 422 }/* for */ 423 424 /* destroy the kernel port */ 425 ipc_port_dealloc_kernel(old_kport); 426} 427 428/* 429 * Routine: ipc_thread_init 430 * Purpose: 431 * Initialize a thread's IPC state. 432 * Conditions: 433 * Nothing locked. 434 */ 435 436void 437ipc_thread_init( 438 thread_t thread) 439{ 440 ipc_port_t kport; 441 442 kport = ipc_port_alloc_kernel(); 443 if (kport == IP_NULL) 444 panic("ipc_thread_init"); 445 446 thread->ith_self = kport; 447 thread->ith_sself = ipc_port_make_send(kport); 448 thread->exc_actions = NULL; 449 450 ipc_kobject_set(kport, (ipc_kobject_t)thread, IKOT_THREAD); 451 452#if IMPORTANCE_INHERITANCE 453 thread->ith_assertions = 0; 454#endif 455 456 ipc_kmsg_queue_init(&thread->ith_messages); 457 458 thread->ith_rpc_reply = IP_NULL; 459} 460 461void 462ipc_thread_init_exc_actions( 463 thread_t thread) 464{ 465 assert(thread->exc_actions == NULL); 466 467 thread->exc_actions = kalloc(sizeof(struct exception_action) * EXC_TYPES_COUNT); 468 bzero(thread->exc_actions, sizeof(struct exception_action) * EXC_TYPES_COUNT); 469} 470 471void 472ipc_thread_destroy_exc_actions( 473 thread_t thread) 474{ 475 if (thread->exc_actions != NULL) { 476 kfree(thread->exc_actions, 477 sizeof(struct exception_action) * EXC_TYPES_COUNT); 478 thread->exc_actions = NULL; 479 } 480} 481 482void 483ipc_thread_disable( 484 thread_t thread) 485{ 486 ipc_port_t kport = thread->ith_self; 487 488 if (kport != IP_NULL) 489 ipc_kobject_set(kport, IKO_NULL, IKOT_NONE); 490} 491 492/* 493 * Routine: ipc_thread_terminate 494 * Purpose: 495 * Clean up and destroy a thread's IPC state. 496 * Conditions: 497 * Nothing locked. 498 */ 499 500void 501ipc_thread_terminate( 502 thread_t thread) 503{ 504 ipc_port_t kport = thread->ith_self; 505 506 if (kport != IP_NULL) { 507 int i; 508 509 if (IP_VALID(thread->ith_sself)) 510 ipc_port_release_send(thread->ith_sself); 511 512 thread->ith_sself = thread->ith_self = IP_NULL; 513 514 if (thread->exc_actions != NULL) { 515 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 516 if (IP_VALID(thread->exc_actions[i].port)) 517 ipc_port_release_send(thread->exc_actions[i].port); 518 } 519 ipc_thread_destroy_exc_actions(thread); 520 } 521 522 ipc_port_dealloc_kernel(kport); 523 } 524 525#if IMPORTANCE_INHERITANCE 526 assert(thread->ith_assertions == 0); 527#endif 528 529 assert(ipc_kmsg_queue_empty(&thread->ith_messages)); 530 531 if (thread->ith_rpc_reply != IP_NULL) 532 ipc_port_dealloc_reply(thread->ith_rpc_reply); 533 534 thread->ith_rpc_reply = IP_NULL; 535} 536 537/* 538 * Routine: ipc_thread_reset 539 * Purpose: 540 * Reset the IPC state for a given Mach thread when 541 * its task enters an elevated security context. 542 * Both the thread port and its exception ports have 543 * to be reset. Its RPC reply port cannot have any 544 * rights outstanding, so it should be fine. 545 * Conditions: 546 * Nothing locked. 547 */ 548 549void 550ipc_thread_reset( 551 thread_t thread) 552{ 553 ipc_port_t old_kport, new_kport; 554 ipc_port_t old_sself; 555 ipc_port_t old_exc_actions[EXC_TYPES_COUNT]; 556 boolean_t has_old_exc_actions = FALSE; 557 int i; 558 559 new_kport = ipc_port_alloc_kernel(); 560 if (new_kport == IP_NULL) 561 panic("ipc_task_reset"); 562 563 thread_mtx_lock(thread); 564 565 old_kport = thread->ith_self; 566 567 if (old_kport == IP_NULL) { 568 /* the is already terminated (can this happen?) */ 569 thread_mtx_unlock(thread); 570 ipc_port_dealloc_kernel(new_kport); 571 return; 572 } 573 574 thread->ith_self = new_kport; 575 old_sself = thread->ith_sself; 576 thread->ith_sself = ipc_port_make_send(new_kport); 577 ipc_kobject_set(old_kport, IKO_NULL, IKOT_NONE); 578 ipc_kobject_set(new_kport, (ipc_kobject_t) thread, IKOT_THREAD); 579 580 /* 581 * Only ports that were set by root-owned processes 582 * (privileged ports) should survive 583 */ 584 if (thread->exc_actions != NULL) { 585 has_old_exc_actions = TRUE; 586 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 587 if (thread->exc_actions[i].privileged) { 588 old_exc_actions[i] = IP_NULL; 589 } else { 590 old_exc_actions[i] = thread->exc_actions[i].port; 591 thread->exc_actions[i].port = IP_NULL; 592 } 593 } 594 } 595 596 thread_mtx_unlock(thread); 597 598 /* release the naked send rights */ 599 600 if (IP_VALID(old_sself)) 601 ipc_port_release_send(old_sself); 602 603 if (has_old_exc_actions) { 604 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; i++) { 605 ipc_port_release_send(old_exc_actions[i]); 606 } 607 } 608 609 /* destroy the kernel port */ 610 ipc_port_dealloc_kernel(old_kport); 611} 612 613/* 614 * Routine: retrieve_task_self_fast 615 * Purpose: 616 * Optimized version of retrieve_task_self, 617 * that only works for the current task. 618 * 619 * Return a send right (possibly null/dead) 620 * for the task's user-visible self port. 621 * Conditions: 622 * Nothing locked. 623 */ 624 625ipc_port_t 626retrieve_task_self_fast( 627 register task_t task) 628{ 629 register ipc_port_t port; 630 631 assert(task == current_task()); 632 633 itk_lock(task); 634 assert(task->itk_self != IP_NULL); 635 636 if ((port = task->itk_sself) == task->itk_self) { 637 /* no interposing */ 638 639 ip_lock(port); 640 assert(ip_active(port)); 641 ip_reference(port); 642 port->ip_srights++; 643 ip_unlock(port); 644 } else 645 port = ipc_port_copy_send(port); 646 itk_unlock(task); 647 648 return port; 649} 650 651/* 652 * Routine: retrieve_thread_self_fast 653 * Purpose: 654 * Return a send right (possibly null/dead) 655 * for the thread's user-visible self port. 656 * 657 * Only works for the current thread. 658 * 659 * Conditions: 660 * Nothing locked. 661 */ 662 663ipc_port_t 664retrieve_thread_self_fast( 665 thread_t thread) 666{ 667 register ipc_port_t port; 668 669 assert(thread == current_thread()); 670 671 thread_mtx_lock(thread); 672 673 assert(thread->ith_self != IP_NULL); 674 675 if ((port = thread->ith_sself) == thread->ith_self) { 676 /* no interposing */ 677 678 ip_lock(port); 679 assert(ip_active(port)); 680 ip_reference(port); 681 port->ip_srights++; 682 ip_unlock(port); 683 } 684 else 685 port = ipc_port_copy_send(port); 686 687 thread_mtx_unlock(thread); 688 689 return port; 690} 691 692/* 693 * Routine: task_self_trap [mach trap] 694 * Purpose: 695 * Give the caller send rights for his own task port. 696 * Conditions: 697 * Nothing locked. 698 * Returns: 699 * MACH_PORT_NULL if there are any resource failures 700 * or other errors. 701 */ 702 703mach_port_name_t 704task_self_trap( 705 __unused struct task_self_trap_args *args) 706{ 707 task_t task = current_task(); 708 ipc_port_t sright; 709 mach_port_name_t name; 710 711 sright = retrieve_task_self_fast(task); 712 name = ipc_port_copyout_send(sright, task->itk_space); 713 return name; 714} 715 716/* 717 * Routine: thread_self_trap [mach trap] 718 * Purpose: 719 * Give the caller send rights for his own thread port. 720 * Conditions: 721 * Nothing locked. 722 * Returns: 723 * MACH_PORT_NULL if there are any resource failures 724 * or other errors. 725 */ 726 727mach_port_name_t 728thread_self_trap( 729 __unused struct thread_self_trap_args *args) 730{ 731 thread_t thread = current_thread(); 732 task_t task = thread->task; 733 ipc_port_t sright; 734 mach_port_name_t name; 735 736 sright = retrieve_thread_self_fast(thread); 737 name = ipc_port_copyout_send(sright, task->itk_space); 738 return name; 739 740} 741 742/* 743 * Routine: mach_reply_port [mach trap] 744 * Purpose: 745 * Allocate a port for the caller. 746 * Conditions: 747 * Nothing locked. 748 * Returns: 749 * MACH_PORT_NULL if there are any resource failures 750 * or other errors. 751 */ 752 753mach_port_name_t 754mach_reply_port( 755 __unused struct mach_reply_port_args *args) 756{ 757 ipc_port_t port; 758 mach_port_name_t name; 759 kern_return_t kr; 760 761 kr = ipc_port_alloc(current_task()->itk_space, &name, &port); 762 if (kr == KERN_SUCCESS) 763 ip_unlock(port); 764 else 765 name = MACH_PORT_NULL; 766 return name; 767} 768 769/* 770 * Routine: thread_get_special_port [kernel call] 771 * Purpose: 772 * Clones a send right for one of the thread's 773 * special ports. 774 * Conditions: 775 * Nothing locked. 776 * Returns: 777 * KERN_SUCCESS Extracted a send right. 778 * KERN_INVALID_ARGUMENT The thread is null. 779 * KERN_FAILURE The thread is dead. 780 * KERN_INVALID_ARGUMENT Invalid special port. 781 */ 782 783kern_return_t 784thread_get_special_port( 785 thread_t thread, 786 int which, 787 ipc_port_t *portp) 788{ 789 kern_return_t result = KERN_SUCCESS; 790 ipc_port_t *whichp; 791 792 if (thread == THREAD_NULL) 793 return (KERN_INVALID_ARGUMENT); 794 795 switch (which) { 796 797 case THREAD_KERNEL_PORT: 798 whichp = &thread->ith_sself; 799 break; 800 801 default: 802 return (KERN_INVALID_ARGUMENT); 803 } 804 805 thread_mtx_lock(thread); 806 807 if (thread->active) 808 *portp = ipc_port_copy_send(*whichp); 809 else 810 result = KERN_FAILURE; 811 812 thread_mtx_unlock(thread); 813 814 return (result); 815} 816 817/* 818 * Routine: thread_set_special_port [kernel call] 819 * Purpose: 820 * Changes one of the thread's special ports, 821 * setting it to the supplied send right. 822 * Conditions: 823 * Nothing locked. If successful, consumes 824 * the supplied send right. 825 * Returns: 826 * KERN_SUCCESS Changed the special port. 827 * KERN_INVALID_ARGUMENT The thread is null. 828 * KERN_FAILURE The thread is dead. 829 * KERN_INVALID_ARGUMENT Invalid special port. 830 */ 831 832kern_return_t 833thread_set_special_port( 834 thread_t thread, 835 int which, 836 ipc_port_t port) 837{ 838 kern_return_t result = KERN_SUCCESS; 839 ipc_port_t *whichp, old = IP_NULL; 840 841 if (thread == THREAD_NULL) 842 return (KERN_INVALID_ARGUMENT); 843 844 switch (which) { 845 846 case THREAD_KERNEL_PORT: 847 whichp = &thread->ith_sself; 848 break; 849 850 default: 851 return (KERN_INVALID_ARGUMENT); 852 } 853 854 thread_mtx_lock(thread); 855 856 if (thread->active) { 857 old = *whichp; 858 *whichp = port; 859 } 860 else 861 result = KERN_FAILURE; 862 863 thread_mtx_unlock(thread); 864 865 if (IP_VALID(old)) 866 ipc_port_release_send(old); 867 868 return (result); 869} 870 871/* 872 * Routine: task_get_special_port [kernel call] 873 * Purpose: 874 * Clones a send right for one of the task's 875 * special ports. 876 * Conditions: 877 * Nothing locked. 878 * Returns: 879 * KERN_SUCCESS Extracted a send right. 880 * KERN_INVALID_ARGUMENT The task is null. 881 * KERN_FAILURE The task/space is dead. 882 * KERN_INVALID_ARGUMENT Invalid special port. 883 */ 884 885kern_return_t 886task_get_special_port( 887 task_t task, 888 int which, 889 ipc_port_t *portp) 890{ 891 ipc_port_t port; 892 893 if (task == TASK_NULL) 894 return KERN_INVALID_ARGUMENT; 895 896 itk_lock(task); 897 if (task->itk_self == IP_NULL) { 898 itk_unlock(task); 899 return KERN_FAILURE; 900 } 901 902 switch (which) { 903 case TASK_KERNEL_PORT: 904 port = ipc_port_copy_send(task->itk_sself); 905 break; 906 907 case TASK_NAME_PORT: 908 port = ipc_port_make_send(task->itk_nself); 909 break; 910 911 case TASK_HOST_PORT: 912 port = ipc_port_copy_send(task->itk_host); 913 break; 914 915 case TASK_BOOTSTRAP_PORT: 916 port = ipc_port_copy_send(task->itk_bootstrap); 917 break; 918 919 case TASK_SEATBELT_PORT: 920 port = ipc_port_copy_send(task->itk_seatbelt); 921 break; 922 923 case TASK_ACCESS_PORT: 924 port = ipc_port_copy_send(task->itk_task_access); 925 break; 926 927 default: 928 itk_unlock(task); 929 return KERN_INVALID_ARGUMENT; 930 } 931 itk_unlock(task); 932 933 *portp = port; 934 return KERN_SUCCESS; 935} 936 937/* 938 * Routine: task_set_special_port [kernel call] 939 * Purpose: 940 * Changes one of the task's special ports, 941 * setting it to the supplied send right. 942 * Conditions: 943 * Nothing locked. If successful, consumes 944 * the supplied send right. 945 * Returns: 946 * KERN_SUCCESS Changed the special port. 947 * KERN_INVALID_ARGUMENT The task is null. 948 * KERN_FAILURE The task/space is dead. 949 * KERN_INVALID_ARGUMENT Invalid special port. 950 * KERN_NO_ACCESS Attempted overwrite of seatbelt port. 951 */ 952 953kern_return_t 954task_set_special_port( 955 task_t task, 956 int which, 957 ipc_port_t port) 958{ 959 ipc_port_t *whichp; 960 ipc_port_t old; 961 962 if (task == TASK_NULL) 963 return KERN_INVALID_ARGUMENT; 964 965 switch (which) { 966 case TASK_KERNEL_PORT: 967 whichp = &task->itk_sself; 968 break; 969 970 case TASK_HOST_PORT: 971 whichp = &task->itk_host; 972 break; 973 974 case TASK_BOOTSTRAP_PORT: 975 whichp = &task->itk_bootstrap; 976 break; 977 978 case TASK_SEATBELT_PORT: 979 whichp = &task->itk_seatbelt; 980 break; 981 982 case TASK_ACCESS_PORT: 983 whichp = &task->itk_task_access; 984 break; 985 986 default: 987 return KERN_INVALID_ARGUMENT; 988 }/* switch */ 989 990 itk_lock(task); 991 if (task->itk_self == IP_NULL) { 992 itk_unlock(task); 993 return KERN_FAILURE; 994 } 995 996 /* do not allow overwrite of seatbelt or task access ports */ 997 if ((TASK_SEATBELT_PORT == which || TASK_ACCESS_PORT == which) 998 && IP_VALID(*whichp)) { 999 itk_unlock(task); 1000 return KERN_NO_ACCESS; 1001 } 1002 1003#if CONFIG_MACF_MACH 1004 if (mac_task_check_service(current_task(), task, "set_special_port")) { 1005 itk_unlock(task); 1006 return KERN_NO_ACCESS; 1007 } 1008#endif 1009 1010 old = *whichp; 1011 *whichp = port; 1012 itk_unlock(task); 1013 1014 if (IP_VALID(old)) 1015 ipc_port_release_send(old); 1016 return KERN_SUCCESS; 1017} 1018 1019 1020/* 1021 * Routine: mach_ports_register [kernel call] 1022 * Purpose: 1023 * Stash a handful of port send rights in the task. 1024 * Child tasks will inherit these rights, but they 1025 * must use mach_ports_lookup to acquire them. 1026 * 1027 * The rights are supplied in a (wired) kalloc'd segment. 1028 * Rights which aren't supplied are assumed to be null. 1029 * Conditions: 1030 * Nothing locked. If successful, consumes 1031 * the supplied rights and memory. 1032 * Returns: 1033 * KERN_SUCCESS Stashed the port rights. 1034 * KERN_INVALID_ARGUMENT The task is null. 1035 * KERN_INVALID_ARGUMENT The task is dead. 1036 * KERN_INVALID_ARGUMENT The memory param is null. 1037 * KERN_INVALID_ARGUMENT Too many port rights supplied. 1038 */ 1039 1040kern_return_t 1041mach_ports_register( 1042 task_t task, 1043 mach_port_array_t memory, 1044 mach_msg_type_number_t portsCnt) 1045{ 1046 ipc_port_t ports[TASK_PORT_REGISTER_MAX]; 1047 unsigned int i; 1048 1049 if ((task == TASK_NULL) || 1050 (portsCnt > TASK_PORT_REGISTER_MAX) || 1051 (portsCnt && memory == NULL)) 1052 return KERN_INVALID_ARGUMENT; 1053 1054 /* 1055 * Pad the port rights with nulls. 1056 */ 1057 1058 for (i = 0; i < portsCnt; i++) 1059 ports[i] = memory[i]; 1060 for (; i < TASK_PORT_REGISTER_MAX; i++) 1061 ports[i] = IP_NULL; 1062 1063 itk_lock(task); 1064 if (task->itk_self == IP_NULL) { 1065 itk_unlock(task); 1066 return KERN_INVALID_ARGUMENT; 1067 } 1068 1069 /* 1070 * Replace the old send rights with the new. 1071 * Release the old rights after unlocking. 1072 */ 1073 1074 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) { 1075 ipc_port_t old; 1076 1077 old = task->itk_registered[i]; 1078 task->itk_registered[i] = ports[i]; 1079 ports[i] = old; 1080 } 1081 1082 itk_unlock(task); 1083 1084 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) 1085 if (IP_VALID(ports[i])) 1086 ipc_port_release_send(ports[i]); 1087 1088 /* 1089 * Now that the operation is known to be successful, 1090 * we can free the memory. 1091 */ 1092 1093 if (portsCnt != 0) 1094 kfree(memory, 1095 (vm_size_t) (portsCnt * sizeof(mach_port_t))); 1096 1097 return KERN_SUCCESS; 1098} 1099 1100/* 1101 * Routine: mach_ports_lookup [kernel call] 1102 * Purpose: 1103 * Retrieves (clones) the stashed port send rights. 1104 * Conditions: 1105 * Nothing locked. If successful, the caller gets 1106 * rights and memory. 1107 * Returns: 1108 * KERN_SUCCESS Retrieved the send rights. 1109 * KERN_INVALID_ARGUMENT The task is null. 1110 * KERN_INVALID_ARGUMENT The task is dead. 1111 * KERN_RESOURCE_SHORTAGE Couldn't allocate memory. 1112 */ 1113 1114kern_return_t 1115mach_ports_lookup( 1116 task_t task, 1117 mach_port_array_t *portsp, 1118 mach_msg_type_number_t *portsCnt) 1119{ 1120 void *memory; 1121 vm_size_t size; 1122 ipc_port_t *ports; 1123 int i; 1124 1125 if (task == TASK_NULL) 1126 return KERN_INVALID_ARGUMENT; 1127 1128 size = (vm_size_t) (TASK_PORT_REGISTER_MAX * sizeof(ipc_port_t)); 1129 1130 memory = kalloc(size); 1131 if (memory == 0) 1132 return KERN_RESOURCE_SHORTAGE; 1133 1134 itk_lock(task); 1135 if (task->itk_self == IP_NULL) { 1136 itk_unlock(task); 1137 1138 kfree(memory, size); 1139 return KERN_INVALID_ARGUMENT; 1140 } 1141 1142 ports = (ipc_port_t *) memory; 1143 1144 /* 1145 * Clone port rights. Because kalloc'd memory 1146 * is wired, we won't fault while holding the task lock. 1147 */ 1148 1149 for (i = 0; i < TASK_PORT_REGISTER_MAX; i++) 1150 ports[i] = ipc_port_copy_send(task->itk_registered[i]); 1151 1152 itk_unlock(task); 1153 1154 *portsp = (mach_port_array_t) ports; 1155 *portsCnt = TASK_PORT_REGISTER_MAX; 1156 return KERN_SUCCESS; 1157} 1158 1159/* 1160 * Routine: convert_port_to_locked_task 1161 * Purpose: 1162 * Internal helper routine to convert from a port to a locked 1163 * task. Used by several routines that try to convert from a 1164 * task port to a reference on some task related object. 1165 * Conditions: 1166 * Nothing locked, blocking OK. 1167 */ 1168task_t 1169convert_port_to_locked_task(ipc_port_t port) 1170{ 1171 int try_failed_count = 0; 1172 1173 while (IP_VALID(port)) { 1174 task_t task; 1175 1176 ip_lock(port); 1177 if (!ip_active(port) || (ip_kotype(port) != IKOT_TASK)) { 1178 ip_unlock(port); 1179 return TASK_NULL; 1180 } 1181 task = (task_t) port->ip_kobject; 1182 assert(task != TASK_NULL); 1183 1184 /* 1185 * Normal lock ordering puts task_lock() before ip_lock(). 1186 * Attempt out-of-order locking here. 1187 */ 1188 if (task_lock_try(task)) { 1189 ip_unlock(port); 1190 return(task); 1191 } 1192 try_failed_count++; 1193 1194 ip_unlock(port); 1195 mutex_pause(try_failed_count); 1196 } 1197 return TASK_NULL; 1198} 1199 1200/* 1201 * Routine: convert_port_to_task 1202 * Purpose: 1203 * Convert from a port to a task. 1204 * Doesn't consume the port ref; produces a task ref, 1205 * which may be null. 1206 * Conditions: 1207 * Nothing locked. 1208 */ 1209task_t 1210convert_port_to_task( 1211 ipc_port_t port) 1212{ 1213 task_t task = TASK_NULL; 1214 1215 if (IP_VALID(port)) { 1216 ip_lock(port); 1217 1218 if ( ip_active(port) && 1219 ip_kotype(port) == IKOT_TASK ) { 1220 task = (task_t)port->ip_kobject; 1221 assert(task != TASK_NULL); 1222 1223 task_reference_internal(task); 1224 } 1225 1226 ip_unlock(port); 1227 } 1228 1229 return (task); 1230} 1231 1232/* 1233 * Routine: convert_port_to_task_name 1234 * Purpose: 1235 * Convert from a port to a task name. 1236 * Doesn't consume the port ref; produces a task name ref, 1237 * which may be null. 1238 * Conditions: 1239 * Nothing locked. 1240 */ 1241task_name_t 1242convert_port_to_task_name( 1243 ipc_port_t port) 1244{ 1245 task_name_t task = TASK_NULL; 1246 1247 if (IP_VALID(port)) { 1248 ip_lock(port); 1249 1250 if ( ip_active(port) && 1251 (ip_kotype(port) == IKOT_TASK || 1252 ip_kotype(port) == IKOT_TASK_NAME)) { 1253 task = (task_name_t)port->ip_kobject; 1254 assert(task != TASK_NAME_NULL); 1255 1256 task_reference_internal(task); 1257 } 1258 1259 ip_unlock(port); 1260 } 1261 1262 return (task); 1263} 1264 1265/* 1266 * Routine: convert_port_to_task_suspension_token 1267 * Purpose: 1268 * Convert from a port to a task suspension token. 1269 * Doesn't consume the port ref; produces a suspension token ref, 1270 * which may be null. 1271 * Conditions: 1272 * Nothing locked. 1273 */ 1274task_suspension_token_t 1275convert_port_to_task_suspension_token( 1276 ipc_port_t port) 1277{ 1278 task_suspension_token_t task = TASK_NULL; 1279 1280 if (IP_VALID(port)) { 1281 ip_lock(port); 1282 1283 if ( ip_active(port) && 1284 ip_kotype(port) == IKOT_TASK_RESUME) { 1285 task = (task_suspension_token_t)port->ip_kobject; 1286 assert(task != TASK_NULL); 1287 1288 task_reference_internal(task); 1289 } 1290 1291 ip_unlock(port); 1292 } 1293 1294 return (task); 1295} 1296 1297/* 1298 * Routine: convert_port_to_space 1299 * Purpose: 1300 * Convert from a port to a space. 1301 * Doesn't consume the port ref; produces a space ref, 1302 * which may be null. 1303 * Conditions: 1304 * Nothing locked. 1305 */ 1306ipc_space_t 1307convert_port_to_space( 1308 ipc_port_t port) 1309{ 1310 ipc_space_t space; 1311 task_t task; 1312 1313 task = convert_port_to_locked_task(port); 1314 1315 if (task == TASK_NULL) 1316 return IPC_SPACE_NULL; 1317 1318 if (!task->active) { 1319 task_unlock(task); 1320 return IPC_SPACE_NULL; 1321 } 1322 1323 space = task->itk_space; 1324 is_reference(space); 1325 task_unlock(task); 1326 return (space); 1327} 1328 1329/* 1330 * Routine: convert_port_to_map 1331 * Purpose: 1332 * Convert from a port to a map. 1333 * Doesn't consume the port ref; produces a map ref, 1334 * which may be null. 1335 * Conditions: 1336 * Nothing locked. 1337 */ 1338 1339vm_map_t 1340convert_port_to_map( 1341 ipc_port_t port) 1342{ 1343 task_t task; 1344 vm_map_t map; 1345 1346 task = convert_port_to_locked_task(port); 1347 1348 if (task == TASK_NULL) 1349 return VM_MAP_NULL; 1350 1351 if (!task->active) { 1352 task_unlock(task); 1353 return VM_MAP_NULL; 1354 } 1355 1356 map = task->map; 1357 vm_map_reference_swap(map); 1358 task_unlock(task); 1359 return map; 1360} 1361 1362 1363/* 1364 * Routine: convert_port_to_thread 1365 * Purpose: 1366 * Convert from a port to a thread. 1367 * Doesn't consume the port ref; produces an thread ref, 1368 * which may be null. 1369 * Conditions: 1370 * Nothing locked. 1371 */ 1372 1373thread_t 1374convert_port_to_thread( 1375 ipc_port_t port) 1376{ 1377 thread_t thread = THREAD_NULL; 1378 1379 if (IP_VALID(port)) { 1380 ip_lock(port); 1381 1382 if ( ip_active(port) && 1383 ip_kotype(port) == IKOT_THREAD ) { 1384 thread = (thread_t)port->ip_kobject; 1385 assert(thread != THREAD_NULL); 1386 1387 thread_reference_internal(thread); 1388 } 1389 1390 ip_unlock(port); 1391 } 1392 1393 return (thread); 1394} 1395 1396/* 1397 * Routine: port_name_to_thread 1398 * Purpose: 1399 * Convert from a port name to an thread reference 1400 * A name of MACH_PORT_NULL is valid for the null thread. 1401 * Conditions: 1402 * Nothing locked. 1403 */ 1404thread_t 1405port_name_to_thread( 1406 mach_port_name_t name) 1407{ 1408 thread_t thread = THREAD_NULL; 1409 ipc_port_t kport; 1410 1411 if (MACH_PORT_VALID(name)) { 1412 if (ipc_object_copyin(current_space(), name, 1413 MACH_MSG_TYPE_COPY_SEND, 1414 (ipc_object_t *)&kport) != KERN_SUCCESS) 1415 return (THREAD_NULL); 1416 1417 thread = convert_port_to_thread(kport); 1418 1419 if (IP_VALID(kport)) 1420 ipc_port_release_send(kport); 1421 } 1422 1423 return (thread); 1424} 1425 1426task_t 1427port_name_to_task( 1428 mach_port_name_t name) 1429{ 1430 ipc_port_t kern_port; 1431 kern_return_t kr; 1432 task_t task = TASK_NULL; 1433 1434 if (MACH_PORT_VALID(name)) { 1435 kr = ipc_object_copyin(current_space(), name, 1436 MACH_MSG_TYPE_COPY_SEND, 1437 (ipc_object_t *) &kern_port); 1438 if (kr != KERN_SUCCESS) 1439 return TASK_NULL; 1440 1441 task = convert_port_to_task(kern_port); 1442 1443 if (IP_VALID(kern_port)) 1444 ipc_port_release_send(kern_port); 1445 } 1446 return task; 1447} 1448 1449/* 1450 * Routine: convert_task_to_port 1451 * Purpose: 1452 * Convert from a task to a port. 1453 * Consumes a task ref; produces a naked send right 1454 * which may be invalid. 1455 * Conditions: 1456 * Nothing locked. 1457 */ 1458 1459ipc_port_t 1460convert_task_to_port( 1461 task_t task) 1462{ 1463 ipc_port_t port; 1464 1465 itk_lock(task); 1466 if (task->itk_self != IP_NULL) 1467 port = ipc_port_make_send(task->itk_self); 1468 else 1469 port = IP_NULL; 1470 itk_unlock(task); 1471 1472 task_deallocate(task); 1473 return port; 1474} 1475 1476/* 1477 * Routine: convert_task_suspend_token_to_port 1478 * Purpose: 1479 * Convert from a task suspension token to a port. 1480 * Consumes a task suspension token ref; produces a naked send-once right 1481 * which may be invalid. 1482 * Conditions: 1483 * Nothing locked. 1484 */ 1485ipc_port_t 1486convert_task_suspension_token_to_port( 1487 task_suspension_token_t task) 1488{ 1489 ipc_port_t port; 1490 1491 task_lock(task); 1492 if (task->active) { 1493 if (task->itk_resume == IP_NULL) { 1494 task->itk_resume = ipc_port_alloc_kernel(); 1495 if (!IP_VALID(task->itk_resume)) { 1496 panic("failed to create resume port"); 1497 } 1498 1499 ipc_kobject_set(task->itk_resume, (ipc_kobject_t) task, IKOT_TASK_RESUME); 1500 } 1501 1502 /* 1503 * Create a send-once right for each instance of a direct user-called 1504 * task_suspend2 call. Each time one of these send-once rights is abandoned, 1505 * the notification handler will resume the target task. 1506 */ 1507 port = ipc_port_make_sonce(task->itk_resume); 1508 assert(IP_VALID(port)); 1509 } else { 1510 port = IP_NULL; 1511 } 1512 1513 task_unlock(task); 1514 task_suspension_token_deallocate(task); 1515 1516 return port; 1517} 1518 1519 1520/* 1521 * Routine: convert_task_name_to_port 1522 * Purpose: 1523 * Convert from a task name ref to a port. 1524 * Consumes a task name ref; produces a naked send right 1525 * which may be invalid. 1526 * Conditions: 1527 * Nothing locked. 1528 */ 1529 1530ipc_port_t 1531convert_task_name_to_port( 1532 task_name_t task_name) 1533{ 1534 ipc_port_t port; 1535 1536 itk_lock(task_name); 1537 if (task_name->itk_nself != IP_NULL) 1538 port = ipc_port_make_send(task_name->itk_nself); 1539 else 1540 port = IP_NULL; 1541 itk_unlock(task_name); 1542 1543 task_name_deallocate(task_name); 1544 return port; 1545} 1546 1547/* 1548 * Routine: convert_thread_to_port 1549 * Purpose: 1550 * Convert from a thread to a port. 1551 * Consumes an thread ref; produces a naked send right 1552 * which may be invalid. 1553 * Conditions: 1554 * Nothing locked. 1555 */ 1556 1557ipc_port_t 1558convert_thread_to_port( 1559 thread_t thread) 1560{ 1561 ipc_port_t port; 1562 1563 thread_mtx_lock(thread); 1564 1565 if (thread->ith_self != IP_NULL) 1566 port = ipc_port_make_send(thread->ith_self); 1567 else 1568 port = IP_NULL; 1569 1570 thread_mtx_unlock(thread); 1571 1572 thread_deallocate(thread); 1573 1574 return (port); 1575} 1576 1577/* 1578 * Routine: space_deallocate 1579 * Purpose: 1580 * Deallocate a space ref produced by convert_port_to_space. 1581 * Conditions: 1582 * Nothing locked. 1583 */ 1584 1585void 1586space_deallocate( 1587 ipc_space_t space) 1588{ 1589 if (space != IS_NULL) 1590 is_release(space); 1591} 1592 1593/* 1594 * Routine: thread/task_set_exception_ports [kernel call] 1595 * Purpose: 1596 * Sets the thread/task exception port, flavor and 1597 * behavior for the exception types specified by the mask. 1598 * There will be one send right per exception per valid 1599 * port. 1600 * Conditions: 1601 * Nothing locked. If successful, consumes 1602 * the supplied send right. 1603 * Returns: 1604 * KERN_SUCCESS Changed the special port. 1605 * KERN_INVALID_ARGUMENT The thread is null, 1606 * Illegal mask bit set. 1607 * Illegal exception behavior 1608 * KERN_FAILURE The thread is dead. 1609 */ 1610 1611kern_return_t 1612thread_set_exception_ports( 1613 thread_t thread, 1614 exception_mask_t exception_mask, 1615 ipc_port_t new_port, 1616 exception_behavior_t new_behavior, 1617 thread_state_flavor_t new_flavor) 1618{ 1619 ipc_port_t old_port[EXC_TYPES_COUNT]; 1620 boolean_t privileged = current_task()->sec_token.val[0] == 0; 1621 register int i; 1622 1623 if (thread == THREAD_NULL) 1624 return (KERN_INVALID_ARGUMENT); 1625 1626 if (exception_mask & ~EXC_MASK_VALID) 1627 return (KERN_INVALID_ARGUMENT); 1628 1629 if (IP_VALID(new_port)) { 1630 switch (new_behavior & ~MACH_EXCEPTION_CODES) { 1631 1632 case EXCEPTION_DEFAULT: 1633 case EXCEPTION_STATE: 1634 case EXCEPTION_STATE_IDENTITY: 1635 break; 1636 1637 default: 1638 return (KERN_INVALID_ARGUMENT); 1639 } 1640 } 1641 1642 /* 1643 * Check the validity of the thread_state_flavor by calling the 1644 * VALID_THREAD_STATE_FLAVOR architecture dependent macro defined in 1645 * osfmk/mach/ARCHITECTURE/thread_status.h 1646 */ 1647 if (!VALID_THREAD_STATE_FLAVOR(new_flavor)) 1648 return (KERN_INVALID_ARGUMENT); 1649 1650 thread_mtx_lock(thread); 1651 1652 if (!thread->active) { 1653 thread_mtx_unlock(thread); 1654 1655 return (KERN_FAILURE); 1656 } 1657 1658 if (thread->exc_actions == NULL) { 1659 ipc_thread_init_exc_actions(thread); 1660 } 1661 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 1662 if (exception_mask & (1 << i)) { 1663 old_port[i] = thread->exc_actions[i].port; 1664 thread->exc_actions[i].port = ipc_port_copy_send(new_port); 1665 thread->exc_actions[i].behavior = new_behavior; 1666 thread->exc_actions[i].flavor = new_flavor; 1667 thread->exc_actions[i].privileged = privileged; 1668 } 1669 else 1670 old_port[i] = IP_NULL; 1671 } 1672 1673 thread_mtx_unlock(thread); 1674 1675 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) 1676 if (IP_VALID(old_port[i])) 1677 ipc_port_release_send(old_port[i]); 1678 1679 if (IP_VALID(new_port)) /* consume send right */ 1680 ipc_port_release_send(new_port); 1681 1682 return (KERN_SUCCESS); 1683} 1684 1685kern_return_t 1686task_set_exception_ports( 1687 task_t task, 1688 exception_mask_t exception_mask, 1689 ipc_port_t new_port, 1690 exception_behavior_t new_behavior, 1691 thread_state_flavor_t new_flavor) 1692{ 1693 ipc_port_t old_port[EXC_TYPES_COUNT]; 1694 boolean_t privileged = current_task()->sec_token.val[0] == 0; 1695 register int i; 1696 1697 if (task == TASK_NULL) 1698 return (KERN_INVALID_ARGUMENT); 1699 1700 if (exception_mask & ~EXC_MASK_VALID) 1701 return (KERN_INVALID_ARGUMENT); 1702 1703 if (IP_VALID(new_port)) { 1704 switch (new_behavior & ~MACH_EXCEPTION_CODES) { 1705 1706 case EXCEPTION_DEFAULT: 1707 case EXCEPTION_STATE: 1708 case EXCEPTION_STATE_IDENTITY: 1709 break; 1710 1711 default: 1712 return (KERN_INVALID_ARGUMENT); 1713 } 1714 } 1715 1716 itk_lock(task); 1717 1718 if (task->itk_self == IP_NULL) { 1719 itk_unlock(task); 1720 1721 return (KERN_FAILURE); 1722 } 1723 1724 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 1725 if (exception_mask & (1 << i)) { 1726 old_port[i] = task->exc_actions[i].port; 1727 task->exc_actions[i].port = 1728 ipc_port_copy_send(new_port); 1729 task->exc_actions[i].behavior = new_behavior; 1730 task->exc_actions[i].flavor = new_flavor; 1731 task->exc_actions[i].privileged = privileged; 1732 } 1733 else 1734 old_port[i] = IP_NULL; 1735 } 1736 1737 itk_unlock(task); 1738 1739 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) 1740 if (IP_VALID(old_port[i])) 1741 ipc_port_release_send(old_port[i]); 1742 1743 if (IP_VALID(new_port)) /* consume send right */ 1744 ipc_port_release_send(new_port); 1745 1746 return (KERN_SUCCESS); 1747} 1748 1749/* 1750 * Routine: thread/task_swap_exception_ports [kernel call] 1751 * Purpose: 1752 * Sets the thread/task exception port, flavor and 1753 * behavior for the exception types specified by the 1754 * mask. 1755 * 1756 * The old ports, behavior and flavors are returned 1757 * Count specifies the array sizes on input and 1758 * the number of returned ports etc. on output. The 1759 * arrays must be large enough to hold all the returned 1760 * data, MIG returnes an error otherwise. The masks 1761 * array specifies the corresponding exception type(s). 1762 * 1763 * Conditions: 1764 * Nothing locked. If successful, consumes 1765 * the supplied send right. 1766 * 1767 * Returns upto [in} CountCnt elements. 1768 * Returns: 1769 * KERN_SUCCESS Changed the special port. 1770 * KERN_INVALID_ARGUMENT The thread is null, 1771 * Illegal mask bit set. 1772 * Illegal exception behavior 1773 * KERN_FAILURE The thread is dead. 1774 */ 1775 1776kern_return_t 1777thread_swap_exception_ports( 1778 thread_t thread, 1779 exception_mask_t exception_mask, 1780 ipc_port_t new_port, 1781 exception_behavior_t new_behavior, 1782 thread_state_flavor_t new_flavor, 1783 exception_mask_array_t masks, 1784 mach_msg_type_number_t *CountCnt, 1785 exception_port_array_t ports, 1786 exception_behavior_array_t behaviors, 1787 thread_state_flavor_array_t flavors) 1788{ 1789 ipc_port_t old_port[EXC_TYPES_COUNT]; 1790 boolean_t privileged = current_task()->sec_token.val[0] == 0; 1791 unsigned int i, j, count; 1792 1793 if (thread == THREAD_NULL) 1794 return (KERN_INVALID_ARGUMENT); 1795 1796 if (exception_mask & ~EXC_MASK_VALID) 1797 return (KERN_INVALID_ARGUMENT); 1798 1799 if (IP_VALID(new_port)) { 1800 switch (new_behavior & ~MACH_EXCEPTION_CODES) { 1801 1802 case EXCEPTION_DEFAULT: 1803 case EXCEPTION_STATE: 1804 case EXCEPTION_STATE_IDENTITY: 1805 break; 1806 1807 default: 1808 return (KERN_INVALID_ARGUMENT); 1809 } 1810 } 1811 1812 thread_mtx_lock(thread); 1813 1814 if (!thread->active) { 1815 thread_mtx_unlock(thread); 1816 1817 return (KERN_FAILURE); 1818 } 1819 1820 if (thread->exc_actions == NULL) { 1821 ipc_thread_init_exc_actions(thread); 1822 } 1823 1824 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION); 1825 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) { 1826 if (exception_mask & (1 << i)) { 1827 for (j = 0; j < count; ++j) { 1828 /* 1829 * search for an identical entry, if found 1830 * set corresponding mask for this exception. 1831 */ 1832 if ( thread->exc_actions[i].port == ports[j] && 1833 thread->exc_actions[i].behavior == behaviors[j] && 1834 thread->exc_actions[i].flavor == flavors[j] ) { 1835 masks[j] |= (1 << i); 1836 break; 1837 } 1838 } 1839 1840 if (j == count) { 1841 masks[j] = (1 << i); 1842 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port); 1843 1844 behaviors[j] = thread->exc_actions[i].behavior; 1845 flavors[j] = thread->exc_actions[i].flavor; 1846 ++count; 1847 } 1848 1849 old_port[i] = thread->exc_actions[i].port; 1850 thread->exc_actions[i].port = ipc_port_copy_send(new_port); 1851 thread->exc_actions[i].behavior = new_behavior; 1852 thread->exc_actions[i].flavor = new_flavor; 1853 thread->exc_actions[i].privileged = privileged; 1854 } 1855 else 1856 old_port[i] = IP_NULL; 1857 } 1858 1859 thread_mtx_unlock(thread); 1860 1861 while (--i >= FIRST_EXCEPTION) { 1862 if (IP_VALID(old_port[i])) 1863 ipc_port_release_send(old_port[i]); 1864 } 1865 1866 if (IP_VALID(new_port)) /* consume send right */ 1867 ipc_port_release_send(new_port); 1868 1869 *CountCnt = count; 1870 1871 return (KERN_SUCCESS); 1872} 1873 1874kern_return_t 1875task_swap_exception_ports( 1876 task_t task, 1877 exception_mask_t exception_mask, 1878 ipc_port_t new_port, 1879 exception_behavior_t new_behavior, 1880 thread_state_flavor_t new_flavor, 1881 exception_mask_array_t masks, 1882 mach_msg_type_number_t *CountCnt, 1883 exception_port_array_t ports, 1884 exception_behavior_array_t behaviors, 1885 thread_state_flavor_array_t flavors) 1886{ 1887 ipc_port_t old_port[EXC_TYPES_COUNT]; 1888 boolean_t privileged = current_task()->sec_token.val[0] == 0; 1889 unsigned int i, j, count; 1890 1891 if (task == TASK_NULL) 1892 return (KERN_INVALID_ARGUMENT); 1893 1894 if (exception_mask & ~EXC_MASK_VALID) 1895 return (KERN_INVALID_ARGUMENT); 1896 1897 if (IP_VALID(new_port)) { 1898 switch (new_behavior & ~MACH_EXCEPTION_CODES) { 1899 1900 case EXCEPTION_DEFAULT: 1901 case EXCEPTION_STATE: 1902 case EXCEPTION_STATE_IDENTITY: 1903 break; 1904 1905 default: 1906 return (KERN_INVALID_ARGUMENT); 1907 } 1908 } 1909 1910 itk_lock(task); 1911 1912 if (task->itk_self == IP_NULL) { 1913 itk_unlock(task); 1914 1915 return (KERN_FAILURE); 1916 } 1917 1918 assert(EXC_TYPES_COUNT > FIRST_EXCEPTION); 1919 for (count = 0, i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT && count < *CountCnt; ++i) { 1920 if (exception_mask & (1 << i)) { 1921 for (j = 0; j < count; j++) { 1922 /* 1923 * search for an identical entry, if found 1924 * set corresponding mask for this exception. 1925 */ 1926 if ( task->exc_actions[i].port == ports[j] && 1927 task->exc_actions[i].behavior == behaviors[j] && 1928 task->exc_actions[i].flavor == flavors[j] ) { 1929 masks[j] |= (1 << i); 1930 break; 1931 } 1932 } 1933 1934 if (j == count) { 1935 masks[j] = (1 << i); 1936 ports[j] = ipc_port_copy_send(task->exc_actions[i].port); 1937 behaviors[j] = task->exc_actions[i].behavior; 1938 flavors[j] = task->exc_actions[i].flavor; 1939 ++count; 1940 } 1941 1942 old_port[i] = task->exc_actions[i].port; 1943 1944 task->exc_actions[i].port = ipc_port_copy_send(new_port); 1945 task->exc_actions[i].behavior = new_behavior; 1946 task->exc_actions[i].flavor = new_flavor; 1947 task->exc_actions[i].privileged = privileged; 1948 } 1949 else 1950 old_port[i] = IP_NULL; 1951 } 1952 1953 itk_unlock(task); 1954 1955 while (--i >= FIRST_EXCEPTION) { 1956 if (IP_VALID(old_port[i])) 1957 ipc_port_release_send(old_port[i]); 1958 } 1959 1960 if (IP_VALID(new_port)) /* consume send right */ 1961 ipc_port_release_send(new_port); 1962 1963 *CountCnt = count; 1964 1965 return (KERN_SUCCESS); 1966} 1967 1968/* 1969 * Routine: thread/task_get_exception_ports [kernel call] 1970 * Purpose: 1971 * Clones a send right for each of the thread/task's exception 1972 * ports specified in the mask and returns the behaviour 1973 * and flavor of said port. 1974 * 1975 * Returns upto [in} CountCnt elements. 1976 * 1977 * Conditions: 1978 * Nothing locked. 1979 * Returns: 1980 * KERN_SUCCESS Extracted a send right. 1981 * KERN_INVALID_ARGUMENT The thread is null, 1982 * Invalid special port, 1983 * Illegal mask bit set. 1984 * KERN_FAILURE The thread is dead. 1985 */ 1986 1987kern_return_t 1988thread_get_exception_ports( 1989 thread_t thread, 1990 exception_mask_t exception_mask, 1991 exception_mask_array_t masks, 1992 mach_msg_type_number_t *CountCnt, 1993 exception_port_array_t ports, 1994 exception_behavior_array_t behaviors, 1995 thread_state_flavor_array_t flavors) 1996{ 1997 unsigned int i, j, count; 1998 1999 if (thread == THREAD_NULL) 2000 return (KERN_INVALID_ARGUMENT); 2001 2002 if (exception_mask & ~EXC_MASK_VALID) 2003 return (KERN_INVALID_ARGUMENT); 2004 2005 thread_mtx_lock(thread); 2006 2007 if (!thread->active) { 2008 thread_mtx_unlock(thread); 2009 2010 return (KERN_FAILURE); 2011 } 2012 2013 count = 0; 2014 2015 if (thread->exc_actions == NULL) { 2016 goto done; 2017 } 2018 2019 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 2020 if (exception_mask & (1 << i)) { 2021 for (j = 0; j < count; ++j) { 2022 /* 2023 * search for an identical entry, if found 2024 * set corresponding mask for this exception. 2025 */ 2026 if ( thread->exc_actions[i].port == ports[j] && 2027 thread->exc_actions[i].behavior ==behaviors[j] && 2028 thread->exc_actions[i].flavor == flavors[j] ) { 2029 masks[j] |= (1 << i); 2030 break; 2031 } 2032 } 2033 2034 if (j == count) { 2035 masks[j] = (1 << i); 2036 ports[j] = ipc_port_copy_send(thread->exc_actions[i].port); 2037 behaviors[j] = thread->exc_actions[i].behavior; 2038 flavors[j] = thread->exc_actions[i].flavor; 2039 ++count; 2040 if (count >= *CountCnt) 2041 break; 2042 } 2043 } 2044 } 2045 2046done: 2047 thread_mtx_unlock(thread); 2048 2049 *CountCnt = count; 2050 2051 return (KERN_SUCCESS); 2052} 2053 2054kern_return_t 2055task_get_exception_ports( 2056 task_t task, 2057 exception_mask_t exception_mask, 2058 exception_mask_array_t masks, 2059 mach_msg_type_number_t *CountCnt, 2060 exception_port_array_t ports, 2061 exception_behavior_array_t behaviors, 2062 thread_state_flavor_array_t flavors) 2063{ 2064 unsigned int i, j, count; 2065 2066 if (task == TASK_NULL) 2067 return (KERN_INVALID_ARGUMENT); 2068 2069 if (exception_mask & ~EXC_MASK_VALID) 2070 return (KERN_INVALID_ARGUMENT); 2071 2072 itk_lock(task); 2073 2074 if (task->itk_self == IP_NULL) { 2075 itk_unlock(task); 2076 2077 return (KERN_FAILURE); 2078 } 2079 2080 count = 0; 2081 2082 for (i = FIRST_EXCEPTION; i < EXC_TYPES_COUNT; ++i) { 2083 if (exception_mask & (1 << i)) { 2084 for (j = 0; j < count; ++j) { 2085 /* 2086 * search for an identical entry, if found 2087 * set corresponding mask for this exception. 2088 */ 2089 if ( task->exc_actions[i].port == ports[j] && 2090 task->exc_actions[i].behavior == behaviors[j] && 2091 task->exc_actions[i].flavor == flavors[j] ) { 2092 masks[j] |= (1 << i); 2093 break; 2094 } 2095 } 2096 2097 if (j == count) { 2098 masks[j] = (1 << i); 2099 ports[j] = ipc_port_copy_send(task->exc_actions[i].port); 2100 behaviors[j] = task->exc_actions[i].behavior; 2101 flavors[j] = task->exc_actions[i].flavor; 2102 ++count; 2103 if (count > *CountCnt) 2104 break; 2105 } 2106 } 2107 } 2108 2109 itk_unlock(task); 2110 2111 *CountCnt = count; 2112 2113 return (KERN_SUCCESS); 2114} 2115