2 * Copyright (c) 2012-2013, 2015 Apple Inc. All rights reserved.
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
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.
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
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.
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
34 * A corpse is a state of process that is past the point of its death. This means that process has
35 * completed all its termination operations like releasing file descriptors, mach ports, sockets and
36 * other constructs used to identify a process. For all the processes this mimics the behavior as if
37 * the process has died and no longer available by any means.
39 * Why do we need Corpses?
40 * -----------------------
41 * For crash inspection we need to inspect the state and data that is associated with process so that
42 * crash reporting infrastructure can build backtraces, find leaks etc. For example a crash
44 * Corpses functionality in kernel
45 * ===============================
46 * The corpse functionality is an extension of existing exception reporting mechanisms we have. The
47 * exception_triage calls will try to deliver the first round of exceptions allowing
48 * task/debugger/ReportCrash/launchd level exception handlers to respond to exception. If even after
49 * notification the exception is not handled, then the process begins the death operations and during
50 * proc_prepareexit, we decide to create a corpse for inspection. Following is a sample run through
51 * of events and data shuffling that happens when corpses is enabled.
53 * * a process causes an exception during normal execution of threads.
54 * * The exception generated by either mach(e.g GUARDED_MARCHPORT) or bsd(eg SIGABORT, GUARDED_FD
55 * etc) side is passed through the exception_triage() function to follow the thread -> task -> host
56 * level exception handling system. This set of steps are same as before and allow for existing
57 * crash reporting systems (both internal and 3rd party) to catch and create reports as required.
58 * * If above exception handling returns failed (when nobody handles the notification), then the
59 * proc_prepareexit path has logic to decide to create corpse.
60 * * The task_mark_corpse function allocates userspace vm memory and attaches the information
61 * kcdata_descriptor_t to task->corpse_info field of task.
62 * - All the task's threads are marked with the "inspection" flag which signals the termination
63 * daemon to not reap them but hold until they are being inspected.
64 * - task flags t_flags reflect the corpse bit and also a PENDING_CORPSE bit. PENDING_CORPSE
65 * prevents task_terminate from stripping important data from task.
66 * - It marks all the threads to terminate and return to AST for termination.
67 * - The allocation logic takes into account the rate limiting policy of allowing only
68 * TOTAL_CORPSES_ALLOWED in flight.
69 * * The proc exit threads continues and collects required information in the allocated vm region.
70 * Once complete it marks itself for termination.
71 * * In the thread_terminate_self(), the last thread to enter will do a call to proc_exit().
72 * Following this is a check to see if task is marked for corpse notification and will
73 * invoke the the task_deliver_crash_notification().
74 * * Once EXC_CORPSE_NOTIFY is delivered, it removes the PENDING_CORPSE flag from task (and
75 * inspection flag from all its threads) and allows task_terminate to go ahead and continue
76 * the mach task termination process.
77 * * ASIDE: The rest of the threads that are reaching the thread_terminate_daemon() with the
78 * inspection flag set are just bounced to another holding queue (crashed_threads_queue).
79 * Only after the corpse notification these are pulled out from holding queue and enqueued
80 * back to termination queue
85 * The kernel (task_mark_corpse()) makes a vm allocation in the dead task's vm space (with tag
86 * VM_MEMORY_CORPSEINFO (80)). Within this memory all corpse information is saved by various
88 * * bsd proc exit path may write down pid, parent pid, number of file descriptors etc
89 * * mach side may append data regarding ledger usage, memory stats etc
90 * See detailed info about the memory structure and format in kern_cdata.h documentation.
92 * Configuring Corpses functionality
93 * =================================
94 * boot-arg: -no_corpses disables the corpse generation. This can be added/removed without affecting
95 * any other subsystem.
96 * TOTAL_CORPSES_ALLOWED : (recompilation required) - Changing this number allows for controlling
97 * the number of corpse instances to be held for inspection before allowing memory to be reclaimed
99 * CORPSEINFO_ALLOCATION_SIZE: is the default size of vm allocation. If in future there is much more
100 * data to be put in, then please re-tune this parameter.
102 * Debugging/Visibility
103 * ====================
104 * * lldbmacros for thread and task summary are updated to show "C" flag for corpse task/threads.
105 * * there are macros to see list of threads in termination queue (dumpthread_terminate_queue)
106 * and holding queue (dumpcrashed_thread_queue).
107 * * In case of corpse creation is disabled of ignored then the system log is updated with
108 * printf data with reason.
110 * Limitations of Corpses
111 * ======================
112 * With holding off memory for inspection, it creates vm pressure which might not be desirable
113 * on low memory devices. There are limits to max corpses being inspected at a time which is
114 * marked by TOTAL_CORPSES_ALLOWED.
119 #include <stdatomic.h>
120 #include <kern/assert.h>
121 #include <mach/mach_types.h>
122 #include <mach/boolean.h>
123 #include <mach/vm_param.h>
124 #include <kern/kern_types.h>
125 #include <kern/mach_param.h>
126 #include <kern/thread.h>
127 #include <kern/task.h>
128 #include <corpses/task_corpse.h>
129 #include <kern/kalloc.h>
130 #include <kern/kern_cdata.h>
131 #include <mach/mach_vm.h>
132 #include <kern/exc_guard.h>
135 #include <security/mac_mach_internal.h>
139 * Exported interfaces
141 #include <mach/task_server.h>
143 union corpse_creation_gate
{
145 uint16_t user_faults
;
151 static _Atomic
uint32_t inflight_corpses
;
152 unsigned long total_corpses_created
= 0;
153 boolean_t corpse_enabled_config
= TRUE
;
155 /* bootarg to turn on corpse forking for EXC_RESOURCE */
156 int exc_via_corpse_forking
= 1;
158 /* bootarg to generate corpse for fatal high memory watermark violation */
159 int corpse_for_fatal_memkill
= 1;
162 static inline int IS_64BIT_PROCESS(__unused
void *p
) { return 0; }
164 extern int IS_64BIT_PROCESS(void *);
166 extern void gather_populate_corpse_crashinfo(void *p
, task_t task
,
167 mach_exception_data_type_t code
, mach_exception_data_type_t subcode
,
168 uint64_t *udata_buffer
, int num_udata
, void *reason
);
169 extern void *proc_find(int pid
);
170 extern int proc_rele(void *p
);
175 int exc_corpse_forking
;
177 if (PE_parse_boot_argn("-no_corpses", temp_buf
, sizeof(temp_buf
))) {
178 corpse_enabled_config
= FALSE
;
180 if (PE_parse_boot_argn("exc_via_corpse_forking", &exc_corpse_forking
, sizeof(exc_corpse_forking
))) {
181 exc_via_corpse_forking
= exc_corpse_forking
;
183 if (PE_parse_boot_argn("corpse_for_fatal_memkill", &fatal_memkill
, sizeof(fatal_memkill
))) {
184 corpse_for_fatal_memkill
= fatal_memkill
;
189 * Routine: corpses_enabled
190 * returns FALSE if not enabled
192 boolean_t
corpses_enabled()
194 return corpse_enabled_config
;
198 total_corpses_count(void)
200 union corpse_creation_gate gate
;
202 gate
.value
= atomic_load_explicit(&inflight_corpses
, memory_order_relaxed
);
207 * Routine: task_crashinfo_get_ref()
208 * Grab a slot at creating a corpse.
209 * Returns: KERN_SUCCESS if the policy allows for creating a corpse.
212 task_crashinfo_get_ref(uint16_t kcd_u_flags
)
214 union corpse_creation_gate oldgate
, newgate
;
216 assert(kcd_u_flags
& CORPSE_CRASHINFO_HAS_REF
);
218 oldgate
.value
= atomic_load_explicit(&inflight_corpses
, memory_order_relaxed
);
221 if (kcd_u_flags
& CORPSE_CRASHINFO_USER_FAULT
) {
222 if (newgate
.user_faults
++ >= TOTAL_USER_FAULTS_ALLOWED
) {
223 return KERN_RESOURCE_SHORTAGE
;
226 if (newgate
.corpses
++ >= TOTAL_CORPSES_ALLOWED
) {
227 return KERN_RESOURCE_SHORTAGE
;
230 // this reloads the value in oldgate
231 if (atomic_compare_exchange_strong_explicit(&inflight_corpses
,
232 &oldgate
.value
, newgate
.value
, memory_order_relaxed
,
233 memory_order_relaxed
)) {
240 * Routine: task_crashinfo_release_ref
241 * release the slot for corpse being used.
244 task_crashinfo_release_ref(uint16_t kcd_u_flags
)
246 union corpse_creation_gate oldgate
, newgate
;
248 assert(kcd_u_flags
& CORPSE_CRASHINFO_HAS_REF
);
250 oldgate
.value
= atomic_load_explicit(&inflight_corpses
, memory_order_relaxed
);
253 if (kcd_u_flags
& CORPSE_CRASHINFO_USER_FAULT
) {
254 if (newgate
.user_faults
-- == 0) {
255 panic("corpse in flight count over-release");
258 if (newgate
.corpses
-- == 0) {
259 panic("corpse in flight count over-release");
261 // this reloads the value in oldgate
262 if (atomic_compare_exchange_strong_explicit(&inflight_corpses
,
263 &oldgate
.value
, newgate
.value
, memory_order_relaxed
,
264 memory_order_relaxed
)) {
272 task_crashinfo_alloc_init(mach_vm_address_t crash_data_p
, unsigned size
,
273 uint32_t kc_u_flags
, unsigned kc_flags
)
275 kcdata_descriptor_t kcdata
;
277 if (kc_u_flags
& CORPSE_CRASHINFO_HAS_REF
) {
278 if (KERN_SUCCESS
!= task_crashinfo_get_ref(kc_u_flags
)) {
283 kcdata
= kcdata_memory_alloc_init(crash_data_p
, TASK_CRASHINFO_BEGIN
, size
,
286 kcdata
->kcd_user_flags
= kc_u_flags
;
287 } else if (kc_u_flags
& CORPSE_CRASHINFO_HAS_REF
) {
288 task_crashinfo_release_ref(kc_u_flags
);
295 * Free up the memory associated with task_crashinfo_data
298 task_crashinfo_destroy(kcdata_descriptor_t data
)
301 return KERN_INVALID_ARGUMENT
;
303 if (data
->kcd_user_flags
& CORPSE_CRASHINFO_HAS_REF
) {
304 task_crashinfo_release_ref(data
->kcd_user_flags
);
306 return kcdata_memory_destroy(data
);
310 * Routine: task_get_corpseinfo
311 * params: task - task which has corpse info setup.
312 * returns: crash info data attached to task.
313 * NULL if task is null or has no corpse info
315 kcdata_descriptor_t
task_get_corpseinfo(task_t task
)
317 kcdata_descriptor_t retval
= NULL
;
319 retval
= task
->corpse_info
;
325 * Routine: task_add_to_corpse_task_list
326 * params: task - task to be added to corpse task list
330 task_add_to_corpse_task_list(task_t corpse_task
)
332 lck_mtx_lock(&tasks_corpse_lock
);
333 queue_enter(&corpse_tasks
, corpse_task
, task_t
, corpse_tasks
);
334 lck_mtx_unlock(&tasks_corpse_lock
);
338 * Routine: task_remove_from_corpse_task_list
339 * params: task - task to be removed from corpse task list
343 task_remove_from_corpse_task_list(task_t corpse_task
)
345 lck_mtx_lock(&tasks_corpse_lock
);
346 queue_remove(&corpse_tasks
, corpse_task
, task_t
, corpse_tasks
);
347 lck_mtx_unlock(&tasks_corpse_lock
);
351 * Routine: task_purge_all_corpses
356 task_purge_all_corpses(void)
360 printf("Purging corpses......\n\n");
362 lck_mtx_lock(&tasks_corpse_lock
);
363 /* Iterate through all the corpse tasks and clear all map entries */
364 queue_iterate(&corpse_tasks
, task
, task_t
, corpse_tasks
) {
365 vm_map_remove(task
->map
,
366 task
->map
->min_offset
,
367 task
->map
->max_offset
,
371 * + remove immutable mappings
373 (VM_MAP_REMOVE_NO_UNNESTING
|
374 VM_MAP_REMOVE_IMMUTABLE
));
377 lck_mtx_unlock(&tasks_corpse_lock
);
381 * Routine: task_generate_corpse
382 * params: task - task to fork a corpse
383 * corpse_task - task port of the generated corpse
384 * returns: KERN_SUCCESS on Success.
385 * KERN_FAILURE on Failure.
386 * KERN_NOT_SUPPORTED on corpse disabled.
387 * KERN_RESOURCE_SHORTAGE on memory alloc failure or reaching max corpse.
390 task_generate_corpse(
392 ipc_port_t
*corpse_task_port
)
396 thread_t thread
, th_iter
;
397 ipc_port_t corpse_port
;
398 ipc_port_t old_notify
;
400 if (task
== kernel_task
|| task
== TASK_NULL
|| task
== current_task()) {
401 return KERN_INVALID_ARGUMENT
;
405 if (task_is_a_corpse_fork(task
)) {
407 return KERN_INVALID_ARGUMENT
;
411 /* Generate a corpse for the given task, will return with a ref on corpse task */
412 kr
= task_generate_corpse_internal(task
, &new_task
, &thread
, 0, 0, 0, NULL
);
413 if (kr
!= KERN_SUCCESS
) {
416 assert(thread
== THREAD_NULL
);
418 /* wait for all the threads in the task to terminate */
420 task_wait_till_threads_terminate_locked(new_task
);
422 /* Reset thread ports of all the threads in task */
423 queue_iterate(&new_task
->threads
, th_iter
, thread_t
, task_threads
)
425 /* Do not reset the thread port for inactive threads */
426 if (th_iter
->corpse_dup
== FALSE
) {
427 ipc_thread_reset(th_iter
);
430 task_unlock(new_task
);
432 /* transfer the task ref to port and arm the no-senders notification */
433 corpse_port
= convert_task_to_port(new_task
);
434 assert(IP_NULL
!= corpse_port
);
436 ip_lock(corpse_port
);
437 assert(ip_active(corpse_port
));
438 ipc_port_nsrequest(corpse_port
, corpse_port
->ip_mscount
, ipc_port_make_sonce_locked(corpse_port
), &old_notify
);
441 assert(IP_NULL
== old_notify
);
442 *corpse_task_port
= corpse_port
;
447 * Routine: task_enqueue_exception_with_corpse
448 * params: task - task to generate a corpse and enqueue it
449 * etype - EXC_RESOURCE or EXC_GUARD
450 * code - exception code to be enqueued
451 * codeCnt - code array count - code and subcode
453 * returns: KERN_SUCCESS on Success.
454 * KERN_FAILURE on Failure.
455 * KERN_INVALID_ARGUMENT on invalid arguments passed.
456 * KERN_NOT_SUPPORTED on corpse disabled.
457 * KERN_RESOURCE_SHORTAGE on memory alloc failure or reaching max corpse.
460 task_enqueue_exception_with_corpse(
462 exception_type_t etype
,
463 mach_exception_data_t code
,
464 mach_msg_type_number_t codeCnt
,
467 task_t new_task
= TASK_NULL
;
468 thread_t thread
= THREAD_NULL
;
472 return KERN_INVALID_ARGUMENT
;
475 /* Generate a corpse for the given task, will return with a ref on corpse task */
476 kr
= task_generate_corpse_internal(task
, &new_task
, &thread
,
477 etype
, code
[0], code
[1], reason
);
478 if (kr
== KERN_SUCCESS
) {
479 assert(thread
!= THREAD_NULL
);
480 assert(new_task
!= TASK_NULL
);
481 assert(etype
== EXC_RESOURCE
|| etype
== EXC_GUARD
);
482 thread_exception_enqueue(new_task
, thread
, etype
);
488 * Routine: task_generate_corpse_internal
489 * params: task - task to fork a corpse
490 * corpse_task - task of the generated corpse
491 * exc_thread - equivalent thread in corpse enqueuing exception
492 * etype - EXC_RESOURCE or EXC_GUARD or 0
493 * code - mach exception code to be passed in corpse blob
494 * subcode - mach exception subcode to be passed in corpse blob
495 * returns: KERN_SUCCESS on Success.
496 * KERN_FAILURE on Failure.
497 * KERN_NOT_SUPPORTED on corpse disabled.
498 * KERN_RESOURCE_SHORTAGE on memory alloc failure or reaching max corpse.
501 task_generate_corpse_internal(
504 thread_t
*exc_thread
,
505 exception_type_t etype
,
506 mach_exception_data_type_t code
,
507 mach_exception_data_type_t subcode
,
510 task_t new_task
= TASK_NULL
;
511 thread_t thread
= THREAD_NULL
;
512 thread_t thread_next
= THREAD_NULL
;
514 struct proc
*p
= NULL
;
517 uint64_t *udata_buffer
= NULL
;
520 uint16_t kc_u_flags
= CORPSE_CRASHINFO_HAS_REF
;
523 struct label
*label
= NULL
;
526 if (!corpses_enabled()) {
527 return KERN_NOT_SUPPORTED
;
530 if (etype
== EXC_GUARD
&& EXC_GUARD_DECODE_GUARD_TYPE(code
) == GUARD_TYPE_USER
) {
531 kc_u_flags
|= CORPSE_CRASHINFO_USER_FAULT
;
534 kr
= task_crashinfo_get_ref(kc_u_flags
);
535 if (kr
!= KERN_SUCCESS
) {
539 /* Having a task reference does not guarantee a proc reference */
540 p
= proc_find(task_pid(task
));
542 kr
= KERN_INVALID_TASK
;
543 goto error_task_generate_corpse
;
546 is64bit
= IS_64BIT_PROCESS(p
);
547 t_flags
= TF_CORPSE_FORK
| TF_PENDING_CORPSE
| TF_CORPSE
| (is64bit
? TF_64B_ADDR
: TF_NONE
);
550 /* Create the corpse label credentials from the process. */
551 label
= mac_exc_create_label_for_proc(p
);
554 /* Create a task for corpse */
555 kr
= task_create_internal(task
,
562 if (kr
!= KERN_SUCCESS
) {
563 goto error_task_generate_corpse
;
566 /* Create and copy threads from task, returns a ref to thread */
567 kr
= task_duplicate_map_and_threads(task
, p
, new_task
, &thread
,
568 &udata_buffer
, &size
, &num_udata
);
569 if (kr
!= KERN_SUCCESS
) {
570 goto error_task_generate_corpse
;
573 kr
= task_collect_crash_info(new_task
,
578 if (kr
!= KERN_SUCCESS
) {
579 goto error_task_generate_corpse
;
582 /* transfer our references to the corpse info */
583 assert(new_task
->corpse_info
->kcd_user_flags
== 0);
584 new_task
->corpse_info
->kcd_user_flags
= kc_u_flags
;
587 kr
= task_start_halt(new_task
);
588 if (kr
!= KERN_SUCCESS
) {
589 goto error_task_generate_corpse
;
592 /* terminate the ipc space */
593 ipc_space_terminate(new_task
->itk_space
);
595 /* Populate the corpse blob, use the proc struct of task instead of corpse task */
596 gather_populate_corpse_crashinfo(p
, new_task
,
597 code
, subcode
, udata_buffer
, num_udata
, reason
);
599 /* Add it to global corpse task list */
600 task_add_to_corpse_task_list(new_task
);
602 *corpse_task
= new_task
;
603 *exc_thread
= thread
;
605 error_task_generate_corpse
:
608 mac_exc_free_label(label
);
612 /* Release the proc reference */
617 if (kr
!= KERN_SUCCESS
) {
618 if (thread
!= THREAD_NULL
) {
619 thread_deallocate(thread
);
621 if (new_task
!= TASK_NULL
) {
623 /* Terminate all the other threads in the task. */
624 queue_iterate(&new_task
->threads
, thread_next
, thread_t
, task_threads
)
626 thread_terminate_internal(thread_next
);
628 /* wait for all the threads in the task to terminate */
629 task_wait_till_threads_terminate_locked(new_task
);
630 task_unlock(new_task
);
632 task_clear_corpse(new_task
);
633 task_terminate_internal(new_task
);
634 task_deallocate(new_task
);
637 task_crashinfo_release_ref(kc_u_flags
);
640 /* Free the udata buffer allocated in task_duplicate_map_and_threads */
641 if (udata_buffer
!= NULL
) {
642 kfree(udata_buffer
, size
);
649 * Routine: task_map_corpse_info
650 * params: task - Map the corpse info in task's address space
651 * corpse_task - task port of the corpse
652 * kcd_addr_begin - address of the mapped corpse info
653 * kcd_addr_begin - size of the mapped corpse info
654 * returns: KERN_SUCCESS on Success.
655 * KERN_FAILURE on Failure.
656 * KERN_INVALID_ARGUMENT on invalid arguments.
657 * Note: Temporary function, will be deleted soon.
660 task_map_corpse_info(
663 vm_address_t
*kcd_addr_begin
,
667 mach_vm_address_t kcd_addr_begin_64
;
668 mach_vm_size_t size_64
;
670 kr
= task_map_corpse_info_64(task
, corpse_task
, &kcd_addr_begin_64
, &size_64
);
671 if (kr
!= KERN_SUCCESS
) {
675 *kcd_addr_begin
= (vm_address_t
)kcd_addr_begin_64
;
676 *kcd_size
= (uint32_t) size_64
;
681 * Routine: task_map_corpse_info_64
682 * params: task - Map the corpse info in task's address space
683 * corpse_task - task port of the corpse
684 * kcd_addr_begin - address of the mapped corpse info (takes mach_vm_addess_t *)
685 * kcd_addr_begin - size of the mapped corpse info (takes mach_vm_size_t *)
686 * returns: KERN_SUCCESS on Success.
687 * KERN_FAILURE on Failure.
688 * KERN_INVALID_ARGUMENT on invalid arguments.
691 task_map_corpse_info_64(
694 mach_vm_address_t
*kcd_addr_begin
,
695 mach_vm_size_t
*kcd_size
)
698 mach_vm_offset_t crash_data_ptr
= 0;
699 mach_vm_size_t size
= CORPSEINFO_ALLOCATION_SIZE
;
700 void *corpse_info_kernel
= NULL
;
702 if (task
== TASK_NULL
|| task_is_a_corpse_fork(task
)) {
703 return KERN_INVALID_ARGUMENT
;
706 if (corpse_task
== TASK_NULL
|| !task_is_a_corpse(corpse_task
) ||
707 kcdata_memory_get_begin_addr(corpse_task
->corpse_info
) == NULL
) {
708 return KERN_INVALID_ARGUMENT
;
710 corpse_info_kernel
= kcdata_memory_get_begin_addr(corpse_task
->corpse_info
);
711 kr
= mach_vm_allocate_kernel(task
->map
, &crash_data_ptr
, size
,
712 VM_FLAGS_ANYWHERE
, VM_MEMORY_CORPSEINFO
);
713 if (kr
!= KERN_SUCCESS
) {
716 copyout(corpse_info_kernel
, crash_data_ptr
, size
);
717 *kcd_addr_begin
= crash_data_ptr
;
724 task_corpse_get_crashed_thread_id(task_t corpse_task
)
726 return corpse_task
->crashed_thread_id
;