exception.c
1 /* 2 * Copyright (c) 2000-2020 Apple Computer, 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 */ 58 59 #include <mach/mach_types.h> 60 #include <mach/boolean.h> 61 #include <mach/kern_return.h> 62 #include <mach/message.h> 63 #include <mach/port.h> 64 #include <mach/mig_errors.h> 65 #include <mach/task.h> 66 #include <mach/thread_status.h> 67 #include <mach/exception_types.h> 68 #include <mach/exc.h> 69 #include <mach/mach_exc.h> 70 71 #include <ipc/port.h> 72 #include <ipc/ipc_entry.h> 73 #include <ipc/ipc_object.h> 74 #include <ipc/ipc_notify.h> 75 #include <ipc/ipc_space.h> 76 #include <ipc/ipc_pset.h> 77 #include <ipc/ipc_machdep.h> 78 79 #include <kern/ipc_tt.h> 80 #include <kern/task.h> 81 #include <kern/thread.h> 82 #include <kern/processor.h> 83 #include <kern/sched.h> 84 #include <kern/sched_prim.h> 85 #include <kern/host.h> 86 #include <kern/misc_protos.h> 87 #include <kern/ux_handler.h> 88 89 #include <vm/vm_map.h> 90 91 #include <security/mac_mach_internal.h> 92 #include <string.h> 93 94 #include <pexpert/pexpert.h> 95 96 bool panic_on_exception_triage = false; 97 98 unsigned long c_thr_exc_raise = 0; 99 unsigned long c_thr_exc_raise_state = 0; 100 unsigned long c_thr_exc_raise_state_id = 0; 101 unsigned long c_tsk_exc_raise = 0; 102 unsigned long c_tsk_exc_raise_state = 0; 103 unsigned long c_tsk_exc_raise_state_id = 0; 104 105 /* forward declarations */ 106 kern_return_t exception_deliver( 107 thread_t thread, 108 exception_type_t exception, 109 mach_exception_data_t code, 110 mach_msg_type_number_t codeCnt, 111 struct exception_action *excp, 112 lck_mtx_t *mutex); 113 114 static kern_return_t 115 check_exc_receiver_dependency( 116 exception_type_t exception, 117 struct exception_action *excp, 118 lck_mtx_t *mutex); 119 120 #ifdef MACH_BSD 121 kern_return_t bsd_exception( 122 exception_type_t exception, 123 mach_exception_data_t code, 124 mach_msg_type_number_t codeCnt); 125 #endif /* MACH_BSD */ 126 127 #if __has_feature(ptrauth_calls) 128 extern int exit_with_pac_exception( 129 void *proc, 130 exception_type_t exception, 131 mach_exception_code_t code, 132 mach_exception_subcode_t subcode); 133 134 extern bool proc_is_traced(void *p); 135 #endif /* __has_feature(ptrauth_calls) */ 136 137 /* 138 * Routine: exception_init 139 * Purpose: 140 * Global initialization of state for exceptions. 141 * Conditions: 142 * None. 143 */ 144 void 145 exception_init(void) 146 { 147 int tmp = 0; 148 149 if (PE_parse_boot_argn("-panic_on_exception_triage", &tmp, sizeof(tmp))) { 150 panic_on_exception_triage = true; 151 } 152 } 153 154 /* 155 * Routine: exception_deliver 156 * Purpose: 157 * Make an upcall to the exception server provided. 158 * Conditions: 159 * Nothing locked and no resources held. 160 * Called from an exception context, so 161 * thread_exception_return and thread_kdb_return 162 * are possible. 163 * Returns: 164 * KERN_SUCCESS if the exception was handled 165 */ 166 kern_return_t 167 exception_deliver( 168 thread_t thread, 169 exception_type_t exception, 170 mach_exception_data_t code, 171 mach_msg_type_number_t codeCnt, 172 struct exception_action *excp, 173 lck_mtx_t *mutex) 174 { 175 ipc_port_t exc_port = IPC_PORT_NULL; 176 exception_data_type_t small_code[EXCEPTION_CODE_MAX]; 177 int code64; 178 int behavior; 179 int flavor; 180 kern_return_t kr; 181 task_t task; 182 ipc_port_t thread_port = IPC_PORT_NULL, task_port = IPC_PORT_NULL; 183 184 /* 185 * Save work if we are terminating. 186 * Just go back to our AST handler. 187 */ 188 if (!thread->active && !thread->inspection) { 189 return KERN_SUCCESS; 190 } 191 192 /* 193 * If there are no exception actions defined for this entity, 194 * we can't deliver here. 195 */ 196 if (excp == NULL) { 197 return KERN_FAILURE; 198 } 199 200 assert(exception < EXC_TYPES_COUNT); 201 if (exception >= EXC_TYPES_COUNT) { 202 return KERN_FAILURE; 203 } 204 205 excp = &excp[exception]; 206 207 /* 208 * Snapshot the exception action data under lock for consistency. 209 * Hold a reference to the port over the exception_raise_* calls 210 * so it can't be destroyed. This seems like overkill, but keeps 211 * the port from disappearing between now and when 212 * ipc_object_copyin_from_kernel is finally called. 213 */ 214 lck_mtx_lock(mutex); 215 exc_port = excp->port; 216 if (!IP_VALID(exc_port)) { 217 lck_mtx_unlock(mutex); 218 return KERN_FAILURE; 219 } 220 ip_lock(exc_port); 221 if (!ip_active(exc_port)) { 222 ip_unlock(exc_port); 223 lck_mtx_unlock(mutex); 224 return KERN_FAILURE; 225 } 226 ip_reference(exc_port); 227 exc_port->ip_srights++; 228 ip_unlock(exc_port); 229 230 flavor = excp->flavor; 231 behavior = excp->behavior; 232 lck_mtx_unlock(mutex); 233 234 code64 = (behavior & MACH_EXCEPTION_CODES); 235 behavior &= ~MACH_EXCEPTION_MASK; 236 237 if (!code64) { 238 small_code[0] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[0]); 239 small_code[1] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[1]); 240 } 241 242 task = thread->task; 243 244 #if CONFIG_MACF 245 /* Now is a reasonably good time to check if the exception action is 246 * permitted for this process, because after this point we will send 247 * the message out almost certainly. 248 * As with other failures, exception_triage_thread will go on 249 * to the next level. 250 */ 251 252 /* The global exception-to-signal translation port is safe to be an exception handler. */ 253 if (is_ux_handler_port(exc_port) == FALSE && 254 mac_exc_action_check_exception_send(task, excp) != 0) { 255 kr = KERN_FAILURE; 256 goto out_release_right; 257 } 258 #endif 259 260 if (behavior != EXCEPTION_STATE) { 261 task_reference(task); 262 task_port = convert_task_to_port(task); 263 /* task ref consumed */ 264 thread_reference(thread); 265 thread_port = convert_thread_to_port(thread); 266 /* thread ref consumed */ 267 } 268 269 switch (behavior) { 270 case EXCEPTION_STATE: { 271 mach_msg_type_number_t state_cnt; 272 thread_state_data_t state; 273 274 c_thr_exc_raise_state++; 275 state_cnt = _MachineStateCount[flavor]; 276 kr = thread_getstatus_to_user(thread, flavor, 277 (thread_state_t)state, 278 &state_cnt); 279 if (kr == KERN_SUCCESS) { 280 if (code64) { 281 kr = mach_exception_raise_state(exc_port, 282 exception, 283 code, 284 codeCnt, 285 &flavor, 286 state, state_cnt, 287 state, &state_cnt); 288 } else { 289 kr = exception_raise_state(exc_port, exception, 290 small_code, 291 codeCnt, 292 &flavor, 293 state, state_cnt, 294 state, &state_cnt); 295 } 296 if (kr == KERN_SUCCESS) { 297 if (exception != EXC_CORPSE_NOTIFY) { 298 kr = thread_setstatus_from_user(thread, flavor, 299 (thread_state_t)state, 300 state_cnt); 301 } 302 goto out_release_right; 303 } 304 } 305 306 goto out_release_right; 307 } 308 309 case EXCEPTION_DEFAULT: 310 c_thr_exc_raise++; 311 if (code64) { 312 kr = mach_exception_raise(exc_port, 313 thread_port, 314 task_port, 315 exception, 316 code, 317 codeCnt); 318 } else { 319 kr = exception_raise(exc_port, 320 thread_port, 321 task_port, 322 exception, 323 small_code, 324 codeCnt); 325 } 326 327 goto out_release_right; 328 329 case EXCEPTION_STATE_IDENTITY: { 330 mach_msg_type_number_t state_cnt; 331 thread_state_data_t state; 332 333 c_thr_exc_raise_state_id++; 334 state_cnt = _MachineStateCount[flavor]; 335 kr = thread_getstatus_to_user(thread, flavor, 336 (thread_state_t)state, 337 &state_cnt); 338 if (kr == KERN_SUCCESS) { 339 if (code64) { 340 kr = mach_exception_raise_state_identity( 341 exc_port, 342 thread_port, 343 task_port, 344 exception, 345 code, 346 codeCnt, 347 &flavor, 348 state, state_cnt, 349 state, &state_cnt); 350 } else { 351 kr = exception_raise_state_identity(exc_port, 352 thread_port, 353 task_port, 354 exception, 355 small_code, 356 codeCnt, 357 &flavor, 358 state, state_cnt, 359 state, &state_cnt); 360 } 361 362 if (kr == KERN_SUCCESS) { 363 if (exception != EXC_CORPSE_NOTIFY) { 364 kr = thread_setstatus_from_user(thread, flavor, 365 (thread_state_t)state, 366 state_cnt); 367 } 368 goto out_release_right; 369 } 370 } 371 372 goto out_release_right; 373 } 374 375 default: 376 panic("bad exception behavior!"); 377 return KERN_FAILURE; 378 }/* switch */ 379 380 out_release_right: 381 382 if (task_port) { 383 ipc_port_release_send(task_port); 384 } 385 386 if (thread_port) { 387 ipc_port_release_send(thread_port); 388 } 389 390 if (exc_port) { 391 ipc_port_release_send(exc_port); 392 } 393 394 return kr; 395 } 396 397 /* 398 * Routine: check_exc_receiver_dependency 399 * Purpose: 400 * Verify that the port destined for receiving this exception is not 401 * on the current task. This would cause hang in kernel for 402 * EXC_CRASH primarily. Note: If port is transferred 403 * between check and delivery then deadlock may happen. 404 * 405 * Conditions: 406 * Nothing locked and no resources held. 407 * Called from an exception context. 408 * Returns: 409 * KERN_SUCCESS if its ok to send exception message. 410 */ 411 kern_return_t 412 check_exc_receiver_dependency( 413 exception_type_t exception, 414 struct exception_action *excp, 415 lck_mtx_t *mutex) 416 { 417 kern_return_t retval = KERN_SUCCESS; 418 419 if (excp == NULL || exception != EXC_CRASH) { 420 return retval; 421 } 422 423 task_t task = current_task(); 424 lck_mtx_lock(mutex); 425 ipc_port_t xport = excp[exception].port; 426 if (IP_VALID(xport) 427 && ip_active(xport) 428 && task->itk_space == xport->ip_receiver) { 429 retval = KERN_FAILURE; 430 } 431 lck_mtx_unlock(mutex); 432 return retval; 433 } 434 435 436 /* 437 * Routine: exception_triage_thread 438 * Purpose: 439 * The thread caught an exception. 440 * We make an up-call to the thread's exception server. 441 * Conditions: 442 * Nothing locked and no resources held. 443 * Called from an exception context, so 444 * thread_exception_return and thread_kdb_return 445 * are possible. 446 * Returns: 447 * KERN_SUCCESS if exception is handled by any of the handlers. 448 */ 449 kern_return_t 450 exception_triage_thread( 451 exception_type_t exception, 452 mach_exception_data_t code, 453 mach_msg_type_number_t codeCnt, 454 thread_t thread) 455 { 456 task_t task; 457 host_priv_t host_priv; 458 lck_mtx_t *mutex; 459 kern_return_t kr = KERN_FAILURE; 460 461 462 assert(exception != EXC_RPC_ALERT); 463 464 /* 465 * If this behavior has been requested by the the kernel 466 * (due to the boot environment), we should panic if we 467 * enter this function. This is intended as a debugging 468 * aid; it should allow us to debug why we caught an 469 * exception in environments where debugging is especially 470 * difficult. 471 */ 472 if (panic_on_exception_triage) { 473 panic("called exception_triage when it was forbidden by the boot environment"); 474 } 475 476 /* 477 * Try to raise the exception at the activation level. 478 */ 479 mutex = &thread->mutex; 480 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, thread->exc_actions, mutex)) { 481 kr = exception_deliver(thread, exception, code, codeCnt, thread->exc_actions, mutex); 482 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) { 483 goto out; 484 } 485 } 486 487 /* 488 * Maybe the task level will handle it. 489 */ 490 task = thread->task; 491 mutex = &task->itk_lock_data; 492 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, task->exc_actions, mutex)) { 493 kr = exception_deliver(thread, exception, code, codeCnt, task->exc_actions, mutex); 494 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) { 495 goto out; 496 } 497 } 498 499 /* 500 * How about at the host level? 501 */ 502 host_priv = host_priv_self(); 503 mutex = &host_priv->lock; 504 505 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, host_priv->exc_actions, mutex)) { 506 kr = exception_deliver(thread, exception, code, codeCnt, host_priv->exc_actions, mutex); 507 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) { 508 goto out; 509 } 510 } 511 512 out: 513 #ifndef __DARLING__ 514 if ((exception != EXC_CRASH) && (exception != EXC_RESOURCE) && 515 (exception != EXC_GUARD) && (exception != EXC_CORPSE_NOTIFY)) { 516 thread_exception_return(); 517 } 518 #endif // __DARLING__ 519 return kr; 520 } 521 522 /* 523 * Routine: exception_triage 524 * Purpose: 525 * The current thread caught an exception. 526 * We make an up-call to the thread's exception server. 527 * Conditions: 528 * Nothing locked and no resources held. 529 * Called from an exception context, so 530 * thread_exception_return and thread_kdb_return 531 * are possible. 532 * Returns: 533 * KERN_SUCCESS if exception is handled by any of the handlers. 534 */ 535 int debug4k_panic_on_exception = 0; 536 kern_return_t 537 exception_triage( 538 exception_type_t exception, 539 mach_exception_data_t code, 540 mach_msg_type_number_t codeCnt) 541 { 542 thread_t thread = current_thread(); 543 if (VM_MAP_PAGE_SIZE(thread->task->map) < PAGE_SIZE) { 544 DEBUG4K_EXC("thread %p task %p map %p exception %d codes 0x%llx 0x%llx \n", thread, thread->task, thread->task->map, exception, code[0], code[1]); 545 if (debug4k_panic_on_exception) { 546 panic("DEBUG4K %s:%d thread %p task %p map %p exception %d codes 0x%llx 0x%llx \n", __FUNCTION__, __LINE__, thread, thread->task, thread->task->map, exception, code[0], code[1]); 547 } 548 } 549 #if __has_feature(ptrauth_calls) 550 /* 551 * If it is a ptrauth violation, then check if the task has the TF_PAC_EXC_FATAL 552 * flag set and isn't being ptraced. If so, terminate the task via exit_with_reason 553 */ 554 if (exception & EXC_PTRAUTH_BIT) { 555 exception &= ~EXC_PTRAUTH_BIT; 556 557 boolean_t traced_flag = FALSE; 558 task_t task = thread->task; 559 void *proc = task->bsd_info; 560 561 if (task->bsd_info) { 562 traced_flag = proc_is_traced(proc); 563 } 564 565 if (task_is_pac_exception_fatal(current_task()) && !traced_flag) { 566 exit_with_pac_exception(proc, exception, code[0], code[1]); 567 thread_exception_return(); 568 /* NOT_REACHABLE */ 569 } 570 } 571 #endif /* __has_feature(ptrauth_calls) */ 572 return exception_triage_thread(exception, code, codeCnt, thread); 573 } 574 575 kern_return_t 576 bsd_exception( 577 exception_type_t exception, 578 mach_exception_data_t code, 579 mach_msg_type_number_t codeCnt) 580 { 581 task_t task; 582 lck_mtx_t *mutex; 583 thread_t self = current_thread(); 584 kern_return_t kr; 585 586 /* 587 * Maybe the task level will handle it. 588 */ 589 task = current_task(); 590 mutex = &task->itk_lock_data; 591 592 kr = exception_deliver(self, exception, code, codeCnt, task->exc_actions, mutex); 593 594 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) { 595 return KERN_SUCCESS; 596 } 597 return KERN_FAILURE; 598 } 599 600 601 /* 602 * Raise an exception on a task. 603 * This should tell launchd to launch Crash Reporter for this task. 604 */ 605 kern_return_t 606 task_exception_notify(exception_type_t exception, 607 mach_exception_data_type_t exccode, mach_exception_data_type_t excsubcode) 608 { 609 mach_exception_data_type_t code[EXCEPTION_CODE_MAX]; 610 wait_interrupt_t wsave; 611 kern_return_t kr = KERN_SUCCESS; 612 613 code[0] = exccode; 614 code[1] = excsubcode; 615 616 wsave = thread_interrupt_level(THREAD_UNINT); 617 kr = exception_triage(exception, code, EXCEPTION_CODE_MAX); 618 (void) thread_interrupt_level(wsave); 619 return kr; 620 } 621 622 623 /* 624 * Handle interface for special performance monitoring 625 * This is a special case of the host exception handler 626 */ 627 kern_return_t 628 sys_perf_notify(thread_t thread, int pid) 629 { 630 host_priv_t hostp; 631 ipc_port_t xport; 632 wait_interrupt_t wsave; 633 kern_return_t ret; 634 635 hostp = host_priv_self(); /* Get the host privileged ports */ 636 mach_exception_data_type_t code[EXCEPTION_CODE_MAX]; 637 code[0] = 0xFF000001; /* Set terminate code */ 638 code[1] = pid; /* Pass out the pid */ 639 640 struct task *task = thread->task; 641 xport = hostp->exc_actions[EXC_RPC_ALERT].port; 642 643 /* Make sure we're not catching our own exception */ 644 if (!IP_VALID(xport) || 645 !ip_active(xport) || 646 task->itk_space == xport->data.receiver) { 647 return KERN_FAILURE; 648 } 649 650 wsave = thread_interrupt_level(THREAD_UNINT); 651 ret = exception_deliver( 652 thread, 653 EXC_RPC_ALERT, 654 code, 655 2, 656 hostp->exc_actions, 657 &hostp->lock); 658 (void)thread_interrupt_level(wsave); 659 660 return ret; 661 }