]> git.saurik.com Git - apple/xnu.git/blame - osfmk/kern/exception.c
xnu-6153.61.1.tar.gz
[apple/xnu.git] / osfmk / kern / exception.c
CommitLineData
1c79356b 1/*
91447636 2 * Copyright (c) 2000-2004 Apple Computer, Inc. All rights reserved.
1c79356b 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
0a7de745 5 *
2d21ac55
A
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.
0a7de745 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
0a7de745 17 *
2d21ac55
A
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
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
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.
0a7de745 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/*
29 * @OSF_COPYRIGHT@
30 */
0a7de745 31/*
1c79356b
A
32 * Mach Operating System
33 * Copyright (c) 1991,1990,1989,1988,1987 Carnegie Mellon University
34 * All Rights Reserved.
0a7de745 35 *
1c79356b
A
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.
0a7de745 41 *
1c79356b
A
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.
0a7de745 45 *
1c79356b 46 * Carnegie Mellon requests users of this software to return to
0a7de745 47 *
1c79356b
A
48 * Software Distribution Coordinator or Software.Distribution@CS.CMU.EDU
49 * School of Computer Science
50 * Carnegie Mellon University
51 * Pittsburgh PA 15213-3890
0a7de745 52 *
1c79356b
A
53 * any improvements or extensions that they make and grant Carnegie Mellon
54 * the rights to redistribute these changes.
55 */
56/*
57 */
58
55e303ae 59#include <mach/mach_types.h>
1c79356b
A
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>
91447636 65#include <mach/task.h>
1c79356b
A
66#include <mach/thread_status.h>
67#include <mach/exception_types.h>
2d21ac55
A
68#include <mach/exc.h>
69#include <mach/mach_exc.h>
d9a64523 70
1c79356b
A
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>
d9a64523 78
1c79356b
A
79#include <kern/counters.h>
80#include <kern/ipc_tt.h>
81#include <kern/task.h>
82#include <kern/thread.h>
1c79356b
A
83#include <kern/processor.h>
84#include <kern/sched.h>
85#include <kern/sched_prim.h>
86#include <kern/host.h>
87#include <kern/misc_protos.h>
d9a64523
A
88#include <kern/ux_handler.h>
89
39037602 90#include <security/mac_mach_internal.h>
1c79356b 91#include <string.h>
d9a64523 92
316670eb 93#include <pexpert/pexpert.h>
1c79356b 94
cb323159 95bool panic_on_exception_triage = false;
3e170ce0 96
1c79356b
A
97unsigned long c_thr_exc_raise = 0;
98unsigned long c_thr_exc_raise_state = 0;
99unsigned long c_thr_exc_raise_state_id = 0;
100unsigned long c_tsk_exc_raise = 0;
101unsigned long c_tsk_exc_raise_state = 0;
102unsigned long c_tsk_exc_raise_state_id = 0;
103
91447636 104/* forward declarations */
2d21ac55 105kern_return_t exception_deliver(
0a7de745
A
106 thread_t thread,
107 exception_type_t exception,
108 mach_exception_data_t code,
91447636
A
109 mach_msg_type_number_t codeCnt,
110 struct exception_action *excp,
0a7de745 111 lck_mtx_t *mutex);
91447636 112
fe8ab488 113static kern_return_t
3e170ce0 114check_exc_receiver_dependency(
0a7de745
A
115 exception_type_t exception,
116 struct exception_action *excp,
fe8ab488
A
117 lck_mtx_t *mutex);
118
91447636
A
119#ifdef MACH_BSD
120kern_return_t bsd_exception(
0a7de745
A
121 exception_type_t exception,
122 mach_exception_data_t code,
91447636
A
123 mach_msg_type_number_t codeCnt);
124#endif /* MACH_BSD */
1c79356b 125
cb323159
A
126/*
127 * Routine: exception_init
128 * Purpose:
129 * Global initialization of state for exceptions.
130 * Conditions:
131 * None.
132 */
133void
134exception_init(void)
135{
136 int tmp = 0;
137
138 if (PE_parse_boot_argn("-panic_on_exception_triage", &tmp, sizeof(tmp))) {
139 panic_on_exception_triage = true;
140 }
141}
142
1c79356b
A
143/*
144 * Routine: exception_deliver
145 * Purpose:
146 * Make an upcall to the exception server provided.
147 * Conditions:
148 * Nothing locked and no resources held.
149 * Called from an exception context, so
150 * thread_exception_return and thread_kdb_return
151 * are possible.
152 * Returns:
2d21ac55 153 * KERN_SUCCESS if the exception was handled
1c79356b 154 */
0a7de745 155kern_return_t
1c79356b 156exception_deliver(
0a7de745
A
157 thread_t thread,
158 exception_type_t exception,
159 mach_exception_data_t code,
1c79356b
A
160 mach_msg_type_number_t codeCnt,
161 struct exception_action *excp,
0a7de745 162 lck_mtx_t *mutex)
1c79356b 163{
0a7de745
A
164 ipc_port_t exc_port = IPC_PORT_NULL;
165 exception_data_type_t small_code[EXCEPTION_CODE_MAX];
166 int code64;
167 int behavior;
168 int flavor;
169 kern_return_t kr;
39037602 170 task_t task;
5ba3f43e 171 ipc_port_t thread_port = IPC_PORT_NULL, task_port = IPC_PORT_NULL;
1c79356b
A
172
173 /*
174 * Save work if we are terminating.
175 * Just go back to our AST handler.
176 */
0a7de745 177 if (!thread->active && !thread->inspection) {
2d21ac55 178 return KERN_SUCCESS;
0a7de745 179 }
1c79356b 180
39236c6e
A
181 /*
182 * If there are no exception actions defined for this entity,
183 * we can't deliver here.
184 */
0a7de745 185 if (excp == NULL) {
39236c6e 186 return KERN_FAILURE;
0a7de745 187 }
39236c6e
A
188
189 assert(exception < EXC_TYPES_COUNT);
0a7de745 190 if (exception >= EXC_TYPES_COUNT) {
39236c6e 191 return KERN_FAILURE;
0a7de745 192 }
39236c6e
A
193
194 excp = &excp[exception];
195
1c79356b
A
196 /*
197 * Snapshot the exception action data under lock for consistency.
198 * Hold a reference to the port over the exception_raise_* calls
199 * so it can't be destroyed. This seems like overkill, but keeps
200 * the port from disappearing between now and when
201 * ipc_object_copyin_from_kernel is finally called.
202 */
b0d623f7 203 lck_mtx_lock(mutex);
1c79356b
A
204 exc_port = excp->port;
205 if (!IP_VALID(exc_port)) {
b0d623f7 206 lck_mtx_unlock(mutex);
2d21ac55 207 return KERN_FAILURE;
1c79356b
A
208 }
209 ip_lock(exc_port);
210 if (!ip_active(exc_port)) {
211 ip_unlock(exc_port);
b0d623f7 212 lck_mtx_unlock(mutex);
2d21ac55 213 return KERN_FAILURE;
1c79356b 214 }
0a7de745 215 ip_reference(exc_port);
1c79356b
A
216 exc_port->ip_srights++;
217 ip_unlock(exc_port);
218
219 flavor = excp->flavor;
220 behavior = excp->behavior;
b0d623f7 221 lck_mtx_unlock(mutex);
1c79356b 222
2d21ac55 223 code64 = (behavior & MACH_EXCEPTION_CODES);
cb323159 224 behavior &= ~MACH_EXCEPTION_MASK;
2d21ac55
A
225
226 if (!code64) {
b0d623f7
A
227 small_code[0] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[0]);
228 small_code[1] = CAST_DOWN_EXPLICIT(exception_data_type_t, code[1]);
2d21ac55
A
229 }
230
39037602
A
231 task = thread->task;
232
233#if CONFIG_MACF
234 /* Now is a reasonably good time to check if the exception action is
235 * permitted for this process, because after this point we will send
236 * the message out almost certainly.
237 * As with other failures, exception_triage_thread will go on
238 * to the next level.
239 */
d9a64523
A
240
241 /* The global exception-to-signal translation port is safe to be an exception handler. */
242 if (is_ux_handler_port(exc_port) == FALSE &&
243 mac_exc_action_check_exception_send(task, excp) != 0) {
5ba3f43e
A
244 kr = KERN_FAILURE;
245 goto out_release_right;
39037602
A
246 }
247#endif
248
5ba3f43e 249 if (behavior != EXCEPTION_STATE) {
cb323159
A
250 task_reference(task);
251 task_port = convert_task_to_port(task);
252 /* task ref consumed */
253 thread_reference(thread);
254 thread_port = convert_thread_to_port(thread);
255 /* thread ref consumed */
39037602 256 }
2d21ac55 257
1c79356b
A
258 switch (behavior) {
259 case EXCEPTION_STATE: {
260 mach_msg_type_number_t state_cnt;
55e303ae 261 thread_state_data_t state;
1c79356b
A
262
263 c_thr_exc_raise_state++;
91447636 264 state_cnt = _MachineStateCount[flavor];
d9a64523 265 kr = thread_getstatus_to_user(thread, flavor,
0a7de745
A
266 (thread_state_t)state,
267 &state_cnt);
1c79356b 268 if (kr == KERN_SUCCESS) {
2d21ac55 269 if (code64) {
0a7de745
A
270 kr = mach_exception_raise_state(exc_port,
271 exception,
272 code,
273 codeCnt,
274 &flavor,
275 state, state_cnt,
276 state, &state_cnt);
2d21ac55
A
277 } else {
278 kr = exception_raise_state(exc_port, exception,
0a7de745
A
279 small_code,
280 codeCnt,
281 &flavor,
282 state, state_cnt,
283 state, &state_cnt);
2d21ac55 284 }
5ba3f43e 285 if (kr == KERN_SUCCESS) {
0a7de745 286 if (exception != EXC_CORPSE_NOTIFY) {
d9a64523 287 kr = thread_setstatus_from_user(thread, flavor,
0a7de745
A
288 (thread_state_t)state,
289 state_cnt);
290 }
5ba3f43e
A
291 goto out_release_right;
292 }
1c79356b
A
293 }
294
5ba3f43e 295 goto out_release_right;
1c79356b
A
296 }
297
298 case EXCEPTION_DEFAULT:
299 c_thr_exc_raise++;
2d21ac55
A
300 if (code64) {
301 kr = mach_exception_raise(exc_port,
0a7de745
A
302 thread_port,
303 task_port,
304 exception,
305 code,
306 codeCnt);
2d21ac55
A
307 } else {
308 kr = exception_raise(exc_port,
0a7de745
A
309 thread_port,
310 task_port,
311 exception,
312 small_code,
313 codeCnt);
2d21ac55 314 }
1c79356b 315
5ba3f43e 316 goto out_release_right;
1c79356b
A
317
318 case EXCEPTION_STATE_IDENTITY: {
319 mach_msg_type_number_t state_cnt;
55e303ae 320 thread_state_data_t state;
1c79356b
A
321
322 c_thr_exc_raise_state_id++;
91447636 323 state_cnt = _MachineStateCount[flavor];
d9a64523 324 kr = thread_getstatus_to_user(thread, flavor,
0a7de745
A
325 (thread_state_t)state,
326 &state_cnt);
1c79356b 327 if (kr == KERN_SUCCESS) {
2d21ac55
A
328 if (code64) {
329 kr = mach_exception_raise_state_identity(
0a7de745
A
330 exc_port,
331 thread_port,
332 task_port,
333 exception,
334 code,
335 codeCnt,
336 &flavor,
337 state, state_cnt,
338 state, &state_cnt);
2d21ac55
A
339 } else {
340 kr = exception_raise_state_identity(exc_port,
0a7de745
A
341 thread_port,
342 task_port,
343 exception,
344 small_code,
345 codeCnt,
346 &flavor,
347 state, state_cnt,
348 state, &state_cnt);
2d21ac55 349 }
5ba3f43e
A
350
351 if (kr == KERN_SUCCESS) {
0a7de745 352 if (exception != EXC_CORPSE_NOTIFY) {
d9a64523 353 kr = thread_setstatus_from_user(thread, flavor,
0a7de745
A
354 (thread_state_t)state,
355 state_cnt);
356 }
5ba3f43e
A
357 goto out_release_right;
358 }
1c79356b
A
359 }
360
5ba3f43e 361 goto out_release_right;
1c79356b 362 }
2d21ac55 363
1c79356b 364 default:
0a7de745
A
365 panic("bad exception behavior!");
366 return KERN_FAILURE;
1c79356b 367 }/* switch */
5ba3f43e
A
368
369out_release_right:
370
371 if (task_port) {
372 ipc_port_release_send(task_port);
373 }
374
375 if (thread_port) {
376 ipc_port_release_send(thread_port);
377 }
378
379 if (exc_port) {
380 ipc_port_release_send(exc_port);
381 }
382
383 return kr;
1c79356b
A
384}
385
fe8ab488 386/*
3e170ce0 387 * Routine: check_exc_receiver_dependency
fe8ab488
A
388 * Purpose:
389 * Verify that the port destined for receiving this exception is not
390 * on the current task. This would cause hang in kernel for
391 * EXC_CRASH primarily. Note: If port is transferred
392 * between check and delivery then deadlock may happen.
393 *
394 * Conditions:
395 * Nothing locked and no resources held.
396 * Called from an exception context.
397 * Returns:
398 * KERN_SUCCESS if its ok to send exception message.
399 */
400kern_return_t
3e170ce0 401check_exc_receiver_dependency(
fe8ab488
A
402 exception_type_t exception,
403 struct exception_action *excp,
404 lck_mtx_t *mutex)
405{
406 kern_return_t retval = KERN_SUCCESS;
407
0a7de745 408 if (excp == NULL || exception != EXC_CRASH) {
fe8ab488 409 return retval;
0a7de745 410 }
fe8ab488
A
411
412 task_t task = current_task();
413 lck_mtx_lock(mutex);
414 ipc_port_t xport = excp[exception].port;
0a7de745
A
415 if (IP_VALID(xport)
416 && ip_active(xport)
417 && task->itk_space == xport->ip_receiver) {
fe8ab488 418 retval = KERN_FAILURE;
0a7de745 419 }
fe8ab488
A
420 lck_mtx_unlock(mutex);
421 return retval;
422}
423
39037602 424
1c79356b 425/*
39037602 426 * Routine: exception_triage_thread
1c79356b 427 * Purpose:
39037602 428 * The thread caught an exception.
1c79356b
A
429 * We make an up-call to the thread's exception server.
430 * Conditions:
431 * Nothing locked and no resources held.
432 * Called from an exception context, so
433 * thread_exception_return and thread_kdb_return
434 * are possible.
435 * Returns:
3e170ce0 436 * KERN_SUCCESS if exception is handled by any of the handlers.
1c79356b 437 */
3e170ce0 438kern_return_t
39037602 439exception_triage_thread(
0a7de745
A
440 exception_type_t exception,
441 mach_exception_data_t code,
39037602 442 mach_msg_type_number_t codeCnt,
0a7de745 443 thread_t thread)
1c79356b 444{
0a7de745
A
445 task_t task;
446 host_priv_t host_priv;
447 lck_mtx_t *mutex;
448 kern_return_t kr = KERN_FAILURE;
1c79356b
A
449
450 assert(exception != EXC_RPC_ALERT);
451
3e170ce0
A
452 /*
453 * If this behavior has been requested by the the kernel
454 * (due to the boot environment), we should panic if we
455 * enter this function. This is intended as a debugging
456 * aid; it should allow us to debug why we caught an
457 * exception in environments where debugging is especially
458 * difficult.
459 */
460 if (panic_on_exception_triage) {
461 panic("called exception_triage when it was forbidden by the boot environment");
462 }
463
1c79356b
A
464 /*
465 * Try to raise the exception at the activation level.
466 */
b0d623f7 467 mutex = &thread->mutex;
0a7de745 468 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, thread->exc_actions, mutex)) {
fe8ab488 469 kr = exception_deliver(thread, exception, code, codeCnt, thread->exc_actions, mutex);
0a7de745 470 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
fe8ab488 471 goto out;
0a7de745 472 }
fe8ab488 473 }
1c79356b
A
474
475 /*
476 * Maybe the task level will handle it.
477 */
39037602
A
478 task = thread->task;
479 mutex = &task->itk_lock_data;
0a7de745 480 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, task->exc_actions, mutex)) {
fe8ab488 481 kr = exception_deliver(thread, exception, code, codeCnt, task->exc_actions, mutex);
0a7de745 482 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
fe8ab488 483 goto out;
0a7de745 484 }
fe8ab488 485 }
1c79356b
A
486
487 /*
488 * How about at the host level?
489 */
490 host_priv = host_priv_self();
b0d623f7 491 mutex = &host_priv->lock;
5ba3f43e 492
0a7de745 493 if (KERN_SUCCESS == check_exc_receiver_dependency(exception, host_priv->exc_actions, mutex)) {
fe8ab488 494 kr = exception_deliver(thread, exception, code, codeCnt, host_priv->exc_actions, mutex);
0a7de745 495 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
fe8ab488 496 goto out;
0a7de745 497 }
fe8ab488 498 }
1c79356b 499
2d21ac55 500out:
39236c6e 501 if ((exception != EXC_CRASH) && (exception != EXC_RESOURCE) &&
0a7de745 502 (exception != EXC_GUARD) && (exception != EXC_CORPSE_NOTIFY)) {
2d21ac55 503 thread_exception_return();
0a7de745 504 }
3e170ce0 505 return kr;
1c79356b 506}
9bccf70c 507
39037602
A
508/*
509 * Routine: exception_triage
510 * Purpose:
511 * The current thread caught an exception.
512 * We make an up-call to the thread's exception server.
513 * Conditions:
514 * Nothing locked and no resources held.
515 * Called from an exception context, so
516 * thread_exception_return and thread_kdb_return
517 * are possible.
518 * Returns:
519 * KERN_SUCCESS if exception is handled by any of the handlers.
520 */
521kern_return_t
522exception_triage(
0a7de745
A
523 exception_type_t exception,
524 mach_exception_data_t code,
39037602
A
525 mach_msg_type_number_t codeCnt)
526{
527 thread_t thread = current_thread();
528 return exception_triage_thread(exception, code, codeCnt, thread);
529}
530
9bccf70c
A
531kern_return_t
532bsd_exception(
0a7de745
A
533 exception_type_t exception,
534 mach_exception_data_t code,
9bccf70c
A
535 mach_msg_type_number_t codeCnt)
536{
0a7de745
A
537 task_t task;
538 lck_mtx_t *mutex;
539 thread_t self = current_thread();
540 kern_return_t kr;
9bccf70c
A
541
542 /*
543 * Maybe the task level will handle it.
544 */
545 task = current_task();
39037602 546 mutex = &task->itk_lock_data;
9bccf70c 547
39236c6e 548 kr = exception_deliver(self, exception, code, codeCnt, task->exc_actions, mutex);
9bccf70c 549
0a7de745
A
550 if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) {
551 return KERN_SUCCESS;
552 }
553 return KERN_FAILURE;
2d21ac55 554}
9bccf70c 555
9bccf70c 556
2d21ac55 557/*
316670eb 558 * Raise an exception on a task.
2d21ac55
A
559 * This should tell launchd to launch Crash Reporter for this task.
560 */
0a7de745
A
561kern_return_t
562task_exception_notify(exception_type_t exception,
563 mach_exception_data_type_t exccode, mach_exception_data_type_t excsubcode)
2d21ac55 564{
0a7de745
A
565 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
566 wait_interrupt_t wsave;
3e170ce0 567 kern_return_t kr = KERN_SUCCESS;
9bccf70c 568
2d21ac55
A
569 code[0] = exccode;
570 code[1] = excsubcode;
9bccf70c 571
2d21ac55 572 wsave = thread_interrupt_level(THREAD_UNINT);
3e170ce0 573 kr = exception_triage(exception, code, EXCEPTION_CODE_MAX);
2d21ac55 574 (void) thread_interrupt_level(wsave);
3e170ce0 575 return kr;
9bccf70c
A
576}
577
55e303ae 578
55e303ae 579/*
2d21ac55 580 * Handle interface for special performance monitoring
55e303ae
A
581 * This is a special case of the host exception handler
582 */
0a7de745
A
583kern_return_t
584sys_perf_notify(thread_t thread, int pid)
55e303ae 585{
0a7de745
A
586 host_priv_t hostp;
587 ipc_port_t xport;
588 wait_interrupt_t wsave;
589 kern_return_t ret;
55e303ae 590
0a7de745
A
591 hostp = host_priv_self(); /* Get the host privileged ports */
592 mach_exception_data_type_t code[EXCEPTION_CODE_MAX];
593 code[0] = 0xFF000001; /* Set terminate code */
594 code[1] = pid; /* Pass out the pid */
55e303ae 595
2d21ac55 596 struct task *task = thread->task;
0a7de745 597 xport = hostp->exc_actions[EXC_RPC_ALERT].port;
55e303ae 598
2d21ac55
A
599 /* Make sure we're not catching our own exception */
600 if (!IP_VALID(xport) ||
0a7de745
A
601 !ip_active(xport) ||
602 task->itk_space == xport->data.receiver) {
603 return KERN_FAILURE;
55e303ae 604 }
2d21ac55 605
0a7de745 606 wsave = thread_interrupt_level(THREAD_UNINT);
2d21ac55 607 ret = exception_deliver(
0a7de745
A
608 thread,
609 EXC_RPC_ALERT,
610 code,
611 2,
612 hostp->exc_actions,
613 &hostp->lock);
2d21ac55
A
614 (void)thread_interrupt_level(wsave);
615
0a7de745 616 return ret;
55e303ae 617}