]>
Commit | Line | Data |
---|---|---|
1c79356b | 1 | /* |
f427ee49 | 2 | * Copyright (c) 2000-2020 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/ipc_tt.h> |
80 | #include <kern/task.h> | |
81 | #include <kern/thread.h> | |
1c79356b A |
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> | |
d9a64523 A |
87 | #include <kern/ux_handler.h> |
88 | ||
f427ee49 A |
89 | #include <vm/vm_map.h> |
90 | ||
39037602 | 91 | #include <security/mac_mach_internal.h> |
1c79356b | 92 | #include <string.h> |
d9a64523 | 93 | |
316670eb | 94 | #include <pexpert/pexpert.h> |
1c79356b | 95 | |
cb323159 | 96 | bool panic_on_exception_triage = false; |
3e170ce0 | 97 | |
1c79356b A |
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 | ||
91447636 | 105 | /* forward declarations */ |
2d21ac55 | 106 | kern_return_t exception_deliver( |
0a7de745 A |
107 | thread_t thread, |
108 | exception_type_t exception, | |
109 | mach_exception_data_t code, | |
91447636 A |
110 | mach_msg_type_number_t codeCnt, |
111 | struct exception_action *excp, | |
0a7de745 | 112 | lck_mtx_t *mutex); |
91447636 | 113 | |
fe8ab488 | 114 | static kern_return_t |
3e170ce0 | 115 | check_exc_receiver_dependency( |
0a7de745 A |
116 | exception_type_t exception, |
117 | struct exception_action *excp, | |
fe8ab488 A |
118 | lck_mtx_t *mutex); |
119 | ||
91447636 A |
120 | #ifdef MACH_BSD |
121 | kern_return_t bsd_exception( | |
0a7de745 A |
122 | exception_type_t exception, |
123 | mach_exception_data_t code, | |
91447636 A |
124 | mach_msg_type_number_t codeCnt); |
125 | #endif /* MACH_BSD */ | |
1c79356b | 126 | |
eb6b6ca3 A |
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 | ||
cb323159 A |
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 | ||
1c79356b A |
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: | |
2d21ac55 | 164 | * KERN_SUCCESS if the exception was handled |
1c79356b | 165 | */ |
0a7de745 | 166 | kern_return_t |
1c79356b | 167 | exception_deliver( |
0a7de745 A |
168 | thread_t thread, |
169 | exception_type_t exception, | |
170 | mach_exception_data_t code, | |
1c79356b A |
171 | mach_msg_type_number_t codeCnt, |
172 | struct exception_action *excp, | |
0a7de745 | 173 | lck_mtx_t *mutex) |
1c79356b | 174 | { |
0a7de745 A |
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; | |
39037602 | 181 | task_t task; |
5ba3f43e | 182 | ipc_port_t thread_port = IPC_PORT_NULL, task_port = IPC_PORT_NULL; |
1c79356b A |
183 | |
184 | /* | |
185 | * Save work if we are terminating. | |
186 | * Just go back to our AST handler. | |
187 | */ | |
0a7de745 | 188 | if (!thread->active && !thread->inspection) { |
2d21ac55 | 189 | return KERN_SUCCESS; |
0a7de745 | 190 | } |
1c79356b | 191 | |
39236c6e A |
192 | /* |
193 | * If there are no exception actions defined for this entity, | |
194 | * we can't deliver here. | |
195 | */ | |
0a7de745 | 196 | if (excp == NULL) { |
39236c6e | 197 | return KERN_FAILURE; |
0a7de745 | 198 | } |
39236c6e A |
199 | |
200 | assert(exception < EXC_TYPES_COUNT); | |
0a7de745 | 201 | if (exception >= EXC_TYPES_COUNT) { |
39236c6e | 202 | return KERN_FAILURE; |
0a7de745 | 203 | } |
39236c6e A |
204 | |
205 | excp = &excp[exception]; | |
206 | ||
1c79356b A |
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 | */ | |
b0d623f7 | 214 | lck_mtx_lock(mutex); |
1c79356b A |
215 | exc_port = excp->port; |
216 | if (!IP_VALID(exc_port)) { | |
b0d623f7 | 217 | lck_mtx_unlock(mutex); |
2d21ac55 | 218 | return KERN_FAILURE; |
1c79356b A |
219 | } |
220 | ip_lock(exc_port); | |
221 | if (!ip_active(exc_port)) { | |
222 | ip_unlock(exc_port); | |
b0d623f7 | 223 | lck_mtx_unlock(mutex); |
2d21ac55 | 224 | return KERN_FAILURE; |
1c79356b | 225 | } |
0a7de745 | 226 | ip_reference(exc_port); |
1c79356b A |
227 | exc_port->ip_srights++; |
228 | ip_unlock(exc_port); | |
229 | ||
230 | flavor = excp->flavor; | |
231 | behavior = excp->behavior; | |
b0d623f7 | 232 | lck_mtx_unlock(mutex); |
1c79356b | 233 | |
2d21ac55 | 234 | code64 = (behavior & MACH_EXCEPTION_CODES); |
cb323159 | 235 | behavior &= ~MACH_EXCEPTION_MASK; |
2d21ac55 A |
236 | |
237 | if (!code64) { | |
b0d623f7 A |
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]); | |
2d21ac55 A |
240 | } |
241 | ||
39037602 A |
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 | */ | |
d9a64523 A |
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) { | |
5ba3f43e A |
255 | kr = KERN_FAILURE; |
256 | goto out_release_right; | |
39037602 A |
257 | } |
258 | #endif | |
259 | ||
5ba3f43e | 260 | if (behavior != EXCEPTION_STATE) { |
cb323159 A |
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 */ | |
39037602 | 267 | } |
2d21ac55 | 268 | |
1c79356b A |
269 | switch (behavior) { |
270 | case EXCEPTION_STATE: { | |
271 | mach_msg_type_number_t state_cnt; | |
55e303ae | 272 | thread_state_data_t state; |
1c79356b A |
273 | |
274 | c_thr_exc_raise_state++; | |
91447636 | 275 | state_cnt = _MachineStateCount[flavor]; |
d9a64523 | 276 | kr = thread_getstatus_to_user(thread, flavor, |
0a7de745 A |
277 | (thread_state_t)state, |
278 | &state_cnt); | |
1c79356b | 279 | if (kr == KERN_SUCCESS) { |
2d21ac55 | 280 | if (code64) { |
0a7de745 A |
281 | kr = mach_exception_raise_state(exc_port, |
282 | exception, | |
283 | code, | |
284 | codeCnt, | |
285 | &flavor, | |
286 | state, state_cnt, | |
287 | state, &state_cnt); | |
2d21ac55 A |
288 | } else { |
289 | kr = exception_raise_state(exc_port, exception, | |
0a7de745 A |
290 | small_code, |
291 | codeCnt, | |
292 | &flavor, | |
293 | state, state_cnt, | |
294 | state, &state_cnt); | |
2d21ac55 | 295 | } |
5ba3f43e | 296 | if (kr == KERN_SUCCESS) { |
0a7de745 | 297 | if (exception != EXC_CORPSE_NOTIFY) { |
d9a64523 | 298 | kr = thread_setstatus_from_user(thread, flavor, |
0a7de745 A |
299 | (thread_state_t)state, |
300 | state_cnt); | |
301 | } | |
5ba3f43e A |
302 | goto out_release_right; |
303 | } | |
1c79356b A |
304 | } |
305 | ||
5ba3f43e | 306 | goto out_release_right; |
1c79356b A |
307 | } |
308 | ||
309 | case EXCEPTION_DEFAULT: | |
310 | c_thr_exc_raise++; | |
2d21ac55 A |
311 | if (code64) { |
312 | kr = mach_exception_raise(exc_port, | |
0a7de745 A |
313 | thread_port, |
314 | task_port, | |
315 | exception, | |
316 | code, | |
317 | codeCnt); | |
2d21ac55 A |
318 | } else { |
319 | kr = exception_raise(exc_port, | |
0a7de745 A |
320 | thread_port, |
321 | task_port, | |
322 | exception, | |
323 | small_code, | |
324 | codeCnt); | |
2d21ac55 | 325 | } |
1c79356b | 326 | |
5ba3f43e | 327 | goto out_release_right; |
1c79356b A |
328 | |
329 | case EXCEPTION_STATE_IDENTITY: { | |
330 | mach_msg_type_number_t state_cnt; | |
55e303ae | 331 | thread_state_data_t state; |
1c79356b A |
332 | |
333 | c_thr_exc_raise_state_id++; | |
91447636 | 334 | state_cnt = _MachineStateCount[flavor]; |
d9a64523 | 335 | kr = thread_getstatus_to_user(thread, flavor, |
0a7de745 A |
336 | (thread_state_t)state, |
337 | &state_cnt); | |
1c79356b | 338 | if (kr == KERN_SUCCESS) { |
2d21ac55 A |
339 | if (code64) { |
340 | kr = mach_exception_raise_state_identity( | |
0a7de745 A |
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); | |
2d21ac55 A |
350 | } else { |
351 | kr = exception_raise_state_identity(exc_port, | |
0a7de745 A |
352 | thread_port, |
353 | task_port, | |
354 | exception, | |
355 | small_code, | |
356 | codeCnt, | |
357 | &flavor, | |
358 | state, state_cnt, | |
359 | state, &state_cnt); | |
2d21ac55 | 360 | } |
5ba3f43e A |
361 | |
362 | if (kr == KERN_SUCCESS) { | |
0a7de745 | 363 | if (exception != EXC_CORPSE_NOTIFY) { |
d9a64523 | 364 | kr = thread_setstatus_from_user(thread, flavor, |
0a7de745 A |
365 | (thread_state_t)state, |
366 | state_cnt); | |
367 | } | |
5ba3f43e A |
368 | goto out_release_right; |
369 | } | |
1c79356b A |
370 | } |
371 | ||
5ba3f43e | 372 | goto out_release_right; |
1c79356b | 373 | } |
2d21ac55 | 374 | |
1c79356b | 375 | default: |
0a7de745 A |
376 | panic("bad exception behavior!"); |
377 | return KERN_FAILURE; | |
1c79356b | 378 | }/* switch */ |
5ba3f43e A |
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; | |
1c79356b A |
395 | } |
396 | ||
fe8ab488 | 397 | /* |
3e170ce0 | 398 | * Routine: check_exc_receiver_dependency |
fe8ab488 A |
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 | |
3e170ce0 | 412 | check_exc_receiver_dependency( |
fe8ab488 A |
413 | exception_type_t exception, |
414 | struct exception_action *excp, | |
415 | lck_mtx_t *mutex) | |
416 | { | |
417 | kern_return_t retval = KERN_SUCCESS; | |
418 | ||
0a7de745 | 419 | if (excp == NULL || exception != EXC_CRASH) { |
fe8ab488 | 420 | return retval; |
0a7de745 | 421 | } |
fe8ab488 A |
422 | |
423 | task_t task = current_task(); | |
424 | lck_mtx_lock(mutex); | |
425 | ipc_port_t xport = excp[exception].port; | |
0a7de745 A |
426 | if (IP_VALID(xport) |
427 | && ip_active(xport) | |
428 | && task->itk_space == xport->ip_receiver) { | |
fe8ab488 | 429 | retval = KERN_FAILURE; |
0a7de745 | 430 | } |
fe8ab488 A |
431 | lck_mtx_unlock(mutex); |
432 | return retval; | |
433 | } | |
434 | ||
39037602 | 435 | |
1c79356b | 436 | /* |
39037602 | 437 | * Routine: exception_triage_thread |
1c79356b | 438 | * Purpose: |
39037602 | 439 | * The thread caught an exception. |
1c79356b A |
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: | |
3e170ce0 | 447 | * KERN_SUCCESS if exception is handled by any of the handlers. |
1c79356b | 448 | */ |
3e170ce0 | 449 | kern_return_t |
39037602 | 450 | exception_triage_thread( |
0a7de745 A |
451 | exception_type_t exception, |
452 | mach_exception_data_t code, | |
39037602 | 453 | mach_msg_type_number_t codeCnt, |
0a7de745 | 454 | thread_t thread) |
1c79356b | 455 | { |
0a7de745 A |
456 | task_t task; |
457 | host_priv_t host_priv; | |
458 | lck_mtx_t *mutex; | |
459 | kern_return_t kr = KERN_FAILURE; | |
1c79356b | 460 | |
f427ee49 | 461 | |
1c79356b A |
462 | assert(exception != EXC_RPC_ALERT); |
463 | ||
3e170ce0 A |
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 | ||
1c79356b A |
476 | /* |
477 | * Try to raise the exception at the activation level. | |
478 | */ | |
b0d623f7 | 479 | mutex = &thread->mutex; |
0a7de745 | 480 | if (KERN_SUCCESS == check_exc_receiver_dependency(exception, thread->exc_actions, mutex)) { |
fe8ab488 | 481 | kr = exception_deliver(thread, exception, code, codeCnt, thread->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 | * Maybe the task level will handle it. | |
489 | */ | |
39037602 A |
490 | task = thread->task; |
491 | mutex = &task->itk_lock_data; | |
0a7de745 | 492 | if (KERN_SUCCESS == check_exc_receiver_dependency(exception, task->exc_actions, mutex)) { |
fe8ab488 | 493 | kr = exception_deliver(thread, exception, code, codeCnt, task->exc_actions, mutex); |
0a7de745 | 494 | if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) { |
fe8ab488 | 495 | goto out; |
0a7de745 | 496 | } |
fe8ab488 | 497 | } |
1c79356b A |
498 | |
499 | /* | |
500 | * How about at the host level? | |
501 | */ | |
502 | host_priv = host_priv_self(); | |
b0d623f7 | 503 | mutex = &host_priv->lock; |
5ba3f43e | 504 | |
0a7de745 | 505 | if (KERN_SUCCESS == check_exc_receiver_dependency(exception, host_priv->exc_actions, mutex)) { |
fe8ab488 | 506 | kr = exception_deliver(thread, exception, code, codeCnt, host_priv->exc_actions, mutex); |
0a7de745 | 507 | if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) { |
fe8ab488 | 508 | goto out; |
0a7de745 | 509 | } |
fe8ab488 | 510 | } |
1c79356b | 511 | |
2d21ac55 | 512 | out: |
39236c6e | 513 | if ((exception != EXC_CRASH) && (exception != EXC_RESOURCE) && |
0a7de745 | 514 | (exception != EXC_GUARD) && (exception != EXC_CORPSE_NOTIFY)) { |
2d21ac55 | 515 | thread_exception_return(); |
0a7de745 | 516 | } |
3e170ce0 | 517 | return kr; |
1c79356b | 518 | } |
9bccf70c | 519 | |
39037602 A |
520 | /* |
521 | * Routine: exception_triage | |
522 | * Purpose: | |
523 | * The current thread caught an exception. | |
524 | * We make an up-call to the thread's exception server. | |
525 | * Conditions: | |
526 | * Nothing locked and no resources held. | |
527 | * Called from an exception context, so | |
528 | * thread_exception_return and thread_kdb_return | |
529 | * are possible. | |
530 | * Returns: | |
531 | * KERN_SUCCESS if exception is handled by any of the handlers. | |
532 | */ | |
f427ee49 | 533 | int debug4k_panic_on_exception = 0; |
39037602 A |
534 | kern_return_t |
535 | exception_triage( | |
0a7de745 A |
536 | exception_type_t exception, |
537 | mach_exception_data_t code, | |
39037602 A |
538 | mach_msg_type_number_t codeCnt) |
539 | { | |
540 | thread_t thread = current_thread(); | |
f427ee49 A |
541 | if (VM_MAP_PAGE_SIZE(thread->task->map) < PAGE_SIZE) { |
542 | 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]); | |
543 | if (debug4k_panic_on_exception) { | |
544 | 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]); | |
545 | } | |
546 | } | |
eb6b6ca3 A |
547 | #if __has_feature(ptrauth_calls) |
548 | /* | |
549 | * If it is a ptrauth violation, then check if the task has the TF_PAC_EXC_FATAL | |
550 | * flag set and isn't being ptraced. If so, terminate the task via exit_with_reason | |
551 | */ | |
552 | if (exception & EXC_PTRAUTH_BIT) { | |
553 | exception &= ~EXC_PTRAUTH_BIT; | |
554 | ||
555 | boolean_t traced_flag = FALSE; | |
556 | task_t task = thread->task; | |
557 | void *proc = task->bsd_info; | |
558 | ||
559 | if (task->bsd_info) { | |
560 | traced_flag = proc_is_traced(proc); | |
561 | } | |
562 | ||
563 | if (task_is_pac_exception_fatal(current_task()) && !traced_flag) { | |
564 | exit_with_pac_exception(proc, exception, code[0], code[1]); | |
565 | thread_exception_return(); | |
566 | /* NOT_REACHABLE */ | |
567 | } | |
568 | } | |
569 | #endif /* __has_feature(ptrauth_calls) */ | |
39037602 A |
570 | return exception_triage_thread(exception, code, codeCnt, thread); |
571 | } | |
572 | ||
9bccf70c A |
573 | kern_return_t |
574 | bsd_exception( | |
0a7de745 A |
575 | exception_type_t exception, |
576 | mach_exception_data_t code, | |
9bccf70c A |
577 | mach_msg_type_number_t codeCnt) |
578 | { | |
0a7de745 A |
579 | task_t task; |
580 | lck_mtx_t *mutex; | |
581 | thread_t self = current_thread(); | |
582 | kern_return_t kr; | |
9bccf70c A |
583 | |
584 | /* | |
585 | * Maybe the task level will handle it. | |
586 | */ | |
587 | task = current_task(); | |
39037602 | 588 | mutex = &task->itk_lock_data; |
9bccf70c | 589 | |
39236c6e | 590 | kr = exception_deliver(self, exception, code, codeCnt, task->exc_actions, mutex); |
9bccf70c | 591 | |
0a7de745 A |
592 | if (kr == KERN_SUCCESS || kr == MACH_RCV_PORT_DIED) { |
593 | return KERN_SUCCESS; | |
594 | } | |
595 | return KERN_FAILURE; | |
2d21ac55 | 596 | } |
9bccf70c | 597 | |
9bccf70c | 598 | |
2d21ac55 | 599 | /* |
316670eb | 600 | * Raise an exception on a task. |
2d21ac55 A |
601 | * This should tell launchd to launch Crash Reporter for this task. |
602 | */ | |
0a7de745 A |
603 | kern_return_t |
604 | task_exception_notify(exception_type_t exception, | |
605 | mach_exception_data_type_t exccode, mach_exception_data_type_t excsubcode) | |
2d21ac55 | 606 | { |
0a7de745 A |
607 | mach_exception_data_type_t code[EXCEPTION_CODE_MAX]; |
608 | wait_interrupt_t wsave; | |
3e170ce0 | 609 | kern_return_t kr = KERN_SUCCESS; |
9bccf70c | 610 | |
2d21ac55 A |
611 | code[0] = exccode; |
612 | code[1] = excsubcode; | |
9bccf70c | 613 | |
2d21ac55 | 614 | wsave = thread_interrupt_level(THREAD_UNINT); |
3e170ce0 | 615 | kr = exception_triage(exception, code, EXCEPTION_CODE_MAX); |
2d21ac55 | 616 | (void) thread_interrupt_level(wsave); |
3e170ce0 | 617 | return kr; |
9bccf70c A |
618 | } |
619 | ||
55e303ae | 620 | |
55e303ae | 621 | /* |
2d21ac55 | 622 | * Handle interface for special performance monitoring |
55e303ae A |
623 | * This is a special case of the host exception handler |
624 | */ | |
0a7de745 A |
625 | kern_return_t |
626 | sys_perf_notify(thread_t thread, int pid) | |
55e303ae | 627 | { |
0a7de745 A |
628 | host_priv_t hostp; |
629 | ipc_port_t xport; | |
630 | wait_interrupt_t wsave; | |
631 | kern_return_t ret; | |
55e303ae | 632 | |
0a7de745 A |
633 | hostp = host_priv_self(); /* Get the host privileged ports */ |
634 | mach_exception_data_type_t code[EXCEPTION_CODE_MAX]; | |
635 | code[0] = 0xFF000001; /* Set terminate code */ | |
636 | code[1] = pid; /* Pass out the pid */ | |
55e303ae | 637 | |
2d21ac55 | 638 | struct task *task = thread->task; |
0a7de745 | 639 | xport = hostp->exc_actions[EXC_RPC_ALERT].port; |
55e303ae | 640 | |
2d21ac55 A |
641 | /* Make sure we're not catching our own exception */ |
642 | if (!IP_VALID(xport) || | |
0a7de745 A |
643 | !ip_active(xport) || |
644 | task->itk_space == xport->data.receiver) { | |
645 | return KERN_FAILURE; | |
55e303ae | 646 | } |
2d21ac55 | 647 | |
0a7de745 | 648 | wsave = thread_interrupt_level(THREAD_UNINT); |
2d21ac55 | 649 | ret = exception_deliver( |
0a7de745 A |
650 | thread, |
651 | EXC_RPC_ALERT, | |
652 | code, | |
653 | 2, | |
654 | hostp->exc_actions, | |
655 | &hostp->lock); | |
2d21ac55 A |
656 | (void)thread_interrupt_level(wsave); |
657 | ||
0a7de745 | 658 | return ret; |
55e303ae | 659 | } |