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