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