]> git.saurik.com Git - apple/xnu.git/blame - osfmk/corpses/corpse.c
xnu-3789.41.3.tar.gz
[apple/xnu.git] / osfmk / corpses / corpse.c
CommitLineData
3e170ce0
A
1/*
2 * Copyright (c) 2012-2013, 2015 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
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.
14 *
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
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.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29
30/*
31 * Corpses Overview
32 * ================
33 *
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.
38 *
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
43 *
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.
52 *
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
81 *
82 *
83 * Corpse info format
84 * ==================
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
87 * subsystems like
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.
91 *
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
98 * by system.
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.
101 *
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.
109 *
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.
115 *
116 */
117
118
119#include <kern/assert.h>
120#include <mach/mach_types.h>
121#include <mach/boolean.h>
122#include <mach/vm_param.h>
123#include <kern/kern_types.h>
124#include <kern/mach_param.h>
125#include <kern/thread.h>
126#include <kern/task.h>
127#include <corpses/task_corpse.h>
128#include <kern/kalloc.h>
129#include <kern/kern_cdata.h>
130#include <mach/mach_vm.h>
131
39037602
A
132#if CONFIG_MACF
133#include <security/mac_mach_internal.h>
134#endif
135
136/*
137 * Exported interfaces
138 */
139#include <mach/task_server.h>
140
3e170ce0
A
141unsigned long total_corpses_count = 0;
142unsigned long total_corpses_created = 0;
143boolean_t corpse_enabled_config = TRUE;
144
39037602
A
145/* bootarg to turn on corpse forking for EXC_RESOURCE */
146int exc_via_corpse_forking = 1;
147
148/* bootarg to unify corpse blob allocation */
149int unify_corpse_blob_alloc = 1;
150
151/* bootarg to generate corpse for fatal high memory watermark violation */
152int corpse_for_fatal_memkill = 1;
153
3e170ce0 154kcdata_descriptor_t task_get_corpseinfo(task_t task);
39037602
A
155kcdata_descriptor_t task_crashinfo_alloc_init(mach_vm_address_t crash_data_p, unsigned size, int get_corpseref, unsigned flags);
156kern_return_t task_crashinfo_destroy(kcdata_descriptor_t data, int release_corpseref);
3e170ce0
A
157static kern_return_t task_crashinfo_get_ref();
158static kern_return_t task_crashinfo_release_ref();
39037602
A
159extern int IS_64BIT_PROCESS(void *);
160extern void gather_populate_corpse_crashinfo(void *p, void *crash_info_ptr, mach_exception_data_type_t code, mach_exception_data_type_t subcode, uint64_t *udata_buffer, int num_udata);
161extern void *proc_find(int pid);
162extern int proc_rele(void *p);
3e170ce0
A
163
164
165void corpses_init(){
166 char temp_buf[20];
39037602
A
167 int exc_corpse_forking;
168 int corpse_blob_alloc;
169 int fatal_memkill;
3e170ce0
A
170 if (PE_parse_boot_argn("-no_corpses", temp_buf, sizeof(temp_buf))) {
171 corpse_enabled_config = FALSE;
172 }
39037602
A
173 if (PE_parse_boot_argn("exc_via_corpse_forking", &exc_corpse_forking, sizeof(exc_corpse_forking))) {
174 exc_via_corpse_forking = exc_corpse_forking;
175 }
176 if (PE_parse_boot_argn("unify_corpse_blob_alloc", &corpse_blob_alloc, sizeof(corpse_blob_alloc))) {
177 unify_corpse_blob_alloc = corpse_blob_alloc;
178 }
179 if (PE_parse_boot_argn("corpse_for_fatal_memkill", &fatal_memkill, sizeof(fatal_memkill))) {
180 corpse_for_fatal_memkill = fatal_memkill;
181 }
3e170ce0
A
182}
183
184/*
185 * Routine: corpses_enabled
186 * returns FALSE if not enabled
187 */
188boolean_t corpses_enabled()
189{
190 return corpse_enabled_config;
191}
192
193/*
194 * Routine: task_crashinfo_get_ref()
195 * Grab a slot at creating a corpse.
196 * Returns: KERN_SUCCESS if the policy allows for creating a corpse.
197 */
198kern_return_t task_crashinfo_get_ref()
199{
200 unsigned long counter = total_corpses_count;
201 counter = OSIncrementAtomic((SInt32 *)&total_corpses_count);
202 if (counter >= TOTAL_CORPSES_ALLOWED) {
203 OSDecrementAtomic((SInt32 *)&total_corpses_count);
204 return KERN_RESOURCE_SHORTAGE;
205 }
206 OSIncrementAtomicLong((volatile long *)&total_corpses_created);
207 return KERN_SUCCESS;
208}
209
210/*
211 * Routine: task_crashinfo_release_ref
212 * release the slot for corpse being used.
213 */
214kern_return_t task_crashinfo_release_ref()
215{
216 unsigned long __assert_only counter;
217 counter = OSDecrementAtomic((SInt32 *)&total_corpses_count);
218 assert(counter > 0);
219 return KERN_SUCCESS;
220}
221
222
39037602 223kcdata_descriptor_t task_crashinfo_alloc_init(mach_vm_address_t crash_data_p, unsigned size, int get_corpseref, unsigned flags)
3e170ce0 224{
39037602 225 if(get_corpseref && KERN_SUCCESS != task_crashinfo_get_ref()) {
3e170ce0
A
226 return NULL;
227 }
228
39037602 229 return kcdata_memory_alloc_init(crash_data_p, TASK_CRASHINFO_BEGIN, size, flags);
3e170ce0
A
230}
231
232
233/*
234 * Free up the memory associated with task_crashinfo_data
235 */
39037602 236kern_return_t task_crashinfo_destroy(kcdata_descriptor_t data, int release_corpseref)
3e170ce0
A
237{
238 if (!data) {
239 return KERN_INVALID_ARGUMENT;
240 }
241
39037602
A
242 if (release_corpseref)
243 task_crashinfo_release_ref();
3e170ce0
A
244 return kcdata_memory_destroy(data);
245}
246
247/*
248 * Routine: task_get_corpseinfo
249 * params: task - task which has corpse info setup.
250 * returns: crash info data attached to task.
251 * NULL if task is null or has no corpse info
252 */
253kcdata_descriptor_t task_get_corpseinfo(task_t task)
254{
255 kcdata_descriptor_t retval = NULL;
256 if (task != NULL){
257 retval = task->corpse_info;
258 }
259 return retval;
260}
261
39037602
A
262/*
263 * Routine: task_add_to_corpse_task_list
264 * params: task - task to be added to corpse task list
265 * returns: None.
266 */
267void
268task_add_to_corpse_task_list(task_t corpse_task)
269{
270 lck_mtx_lock(&tasks_corpse_lock);
271 queue_enter(&corpse_tasks, corpse_task, task_t, corpse_tasks);
272 lck_mtx_unlock(&tasks_corpse_lock);
273}
274
275/*
276 * Routine: task_remove_from_corpse_task_list
277 * params: task - task to be removed from corpse task list
278 * returns: None.
279 */
280void
281task_remove_from_corpse_task_list(task_t corpse_task)
282{
283 lck_mtx_lock(&tasks_corpse_lock);
284 queue_remove(&corpse_tasks, corpse_task, task_t, corpse_tasks);
285 lck_mtx_unlock(&tasks_corpse_lock);
286}
287
288/*
289 * Routine: task_purge_all_corpses
290 * params: None.
291 * returns: None.
292 */
293void
294task_purge_all_corpses(void)
295{
296 task_t task;
297
298 printf("Purging corpses......\n\n");
299
300 lck_mtx_lock(&tasks_corpse_lock);
301 /* Iterate through all the corpse tasks and clear all map entries */
302 queue_iterate(&corpse_tasks, task, task_t, corpse_tasks) {
303 vm_map_remove(task->map,
304 task->map->min_offset,
305 task->map->max_offset,
306 /* no unnesting on final cleanup: */
307 VM_MAP_REMOVE_NO_UNNESTING);
308 }
309
310 lck_mtx_unlock(&tasks_corpse_lock);
311}
312
313/*
314 * Routine: task_generate_corpse
315 * params: task - task to fork a corpse
316 * corpse_task - task port of the generated corpse
317 * returns: KERN_SUCCESS on Success.
318 * KERN_FAILURE on Failure.
319 * KERN_NO_SUPPORTED on corpse disabled.
320 * KERN_RESOURCE_SHORTAGE on memory alloc failure or reaching max corpse.
321 */
322kern_return_t
323task_generate_corpse(
324 task_t task,
325 ipc_port_t *corpse_task_port)
326{
327 task_t new_task;
328 kern_return_t kr;
329 thread_t thread, th_iter;
330 ipc_port_t corpse_port;
331 ipc_port_t old_notify;
332
333 if (task == kernel_task || task == TASK_NULL || task == current_task()) {
334 return KERN_INVALID_ARGUMENT;
335 }
336
337 task_lock(task);
338 if (task_is_a_corpse_fork(task)) {
339 task_unlock(task);
340 return KERN_INVALID_ARGUMENT;
341 }
342 task_unlock(task);
343
344 /* Generate a corpse for the given task, will return with a ref on corpse task */
345 kr = task_generate_corpse_internal(task, &new_task, &thread, 0, 0);
346 if (kr != KERN_SUCCESS) {
347 return kr;
348 }
349 assert(thread == THREAD_NULL);
350
351 /* wait for all the threads in the task to terminate */
352 task_lock(new_task);
353 task_wait_till_threads_terminate_locked(new_task);
354
355 /* Reset thread ports of all the threads in task */
356 queue_iterate(&new_task->threads, th_iter, thread_t, task_threads)
357 {
358 /* Do not reset the thread port for inactive threads */
359 if (th_iter->corpse_dup == FALSE) {
360 ipc_thread_reset(th_iter);
361 }
362 }
363 task_unlock(new_task);
364
365 /* transfer the task ref to port and arm the no-senders notification */
366 corpse_port = convert_task_to_port(new_task);
367 assert(IP_NULL != corpse_port);
368
369 ip_lock(corpse_port);
370 assert(ip_active(corpse_port));
371 ipc_port_nsrequest(corpse_port, corpse_port->ip_mscount, ipc_port_make_sonce_locked(corpse_port), &old_notify);
372 /* port unlocked */
373
374 assert(IP_NULL == old_notify);
375 *corpse_task_port = corpse_port;
376 return KERN_SUCCESS;
377}
378
379/*
380 * Routine: task_enqueue_exception_with_corpse
381 * params: task - task to generate a corpse and enqueue it
382 * code - exception code to be enqueued
383 * codeCnt - code array count - code and subcode
384 */
385void
386task_enqueue_exception_with_corpse(
387 task_t task,
388 mach_exception_data_t code,
389 mach_msg_type_number_t codeCnt)
390{
391 task_t new_task = TASK_NULL;
392 thread_t thread = THREAD_NULL;
393 kern_return_t kr;
394
395 if (codeCnt < 2) {
396 return;
397 }
398
399 /* Generate a corpse for the given task, will return with a ref on corpse task */
400 kr = task_generate_corpse_internal(task, &new_task, &thread, code[0], code[1]);
401 if (kr != KERN_SUCCESS) {
402 return;
403 }
404
405 assert(thread != THREAD_NULL);
406 assert(new_task != TASK_NULL);
407 thread_exception_enqueue(new_task, thread);
408
409 return;
410}
411
412/*
413 * Routine: task_generate_corpse_internal
414 * params: task - task to fork a corpse
415 * corpse_task - task of the generated corpse
416 * exc_thread - equivalent thread in corpse enqueuing exception
417 * code - mach exception code to be passed in corpse blob
418 * subcode - mach excpetion subcode to be passed in corpse blob
419 * returns: KERN_SUCCESS on Success.
420 * KERN_FAILURE on Failure.
421 * KERN_NO_SUPPORTED on corpse disabled.
422 * KERN_RESOURCE_SHORTAGE on memory alloc failure or reaching max corpse.
423 */
424kern_return_t
425task_generate_corpse_internal(
426 task_t task,
427 task_t *corpse_task,
428 thread_t *exc_thread,
429 mach_exception_data_type_t code,
430 mach_exception_data_type_t subcode)
431{
432 task_t new_task = TASK_NULL;
433 thread_t thread = THREAD_NULL;
434 thread_t thread_next = THREAD_NULL;
435 kern_return_t kr;
436 struct proc *p = NULL;
437 int is64bit;
438 int t_flags;
439 uint64_t *udata_buffer = NULL;
440 int size = 0;
441 int num_udata = 0;
442 boolean_t release_corpse_ref = FALSE;
443
444 if (!corpses_enabled()) {
445 return KERN_NOT_SUPPORTED;
446 }
447
448 kr = task_crashinfo_get_ref();
449 if (kr != KERN_SUCCESS) {
450 return kr;
451 }
452 release_corpse_ref = TRUE;
453
454 /* Having a task reference does not guarantee a proc reference */
455 p = proc_find(task_pid(task));
456 if (p == NULL) {
457 kr = KERN_INVALID_TASK;
458 goto error_task_generate_corpse;
459 }
460
461 is64bit = IS_64BIT_PROCESS(p);
462 t_flags = TF_CORPSE_FORK | TF_PENDING_CORPSE | TF_CORPSE | (is64bit ? TF_64B_ADDR : TF_NONE);
463
464 /* Create a task for corpse */
465 kr = task_create_internal(task,
466 NULL,
467 TRUE,
468 is64bit,
469 t_flags,
743345f9 470 TPF_NONE,
39037602
A
471 &new_task);
472 if (kr != KERN_SUCCESS) {
473 goto error_task_generate_corpse;
474 }
475
476 /* Create and copy threads from task, returns a ref to thread */
477 kr = task_duplicate_map_and_threads(task, p, new_task, &thread,
478 is64bit, &udata_buffer, &size, &num_udata);
479 if (kr != KERN_SUCCESS) {
480 goto error_task_generate_corpse;
481 }
482
483 kr = task_collect_crash_info(new_task, p, TRUE);
484 if (kr != KERN_SUCCESS) {
485 goto error_task_generate_corpse;
486 }
487
488 /* The corpse_info field in task in initialized, call to task_deallocate will drop corpse ref */
489 release_corpse_ref = FALSE;
490
491 kr = task_start_halt(new_task);
492 if (kr != KERN_SUCCESS) {
493 goto error_task_generate_corpse;
494 }
495
496 /* terminate the ipc space */
497 ipc_space_terminate(new_task->itk_space);
498
499 /* Populate the corpse blob, use the proc struct of task instead of corpse task */
500 gather_populate_corpse_crashinfo(p, task_get_corpseinfo(new_task), code, subcode, udata_buffer, num_udata);
501
502 /* Add it to global corpse task list */
503 task_add_to_corpse_task_list(new_task);
504
505 *corpse_task = new_task;
506 *exc_thread = thread;
507
508error_task_generate_corpse:
509 /* Release the proc reference */
510 if (p != NULL) {
511 proc_rele(p);
512 }
3e170ce0 513
39037602
A
514 if (kr != KERN_SUCCESS) {
515 if (thread != THREAD_NULL) {
516 thread_deallocate(thread);
517 }
518 if (new_task != TASK_NULL) {
519 task_lock(new_task);
520 /* Terminate all the other threads in the task. */
521 queue_iterate(&new_task->threads, thread_next, thread_t, task_threads)
522 {
523 thread_terminate_internal(thread_next);
524 }
525 /* wait for all the threads in the task to terminate */
526 task_wait_till_threads_terminate_locked(new_task);
527 task_unlock(new_task);
528
529 task_clear_corpse(new_task);
530 task_terminate_internal(new_task);
531 task_deallocate(new_task);
532 }
533 if (release_corpse_ref) {
534 task_crashinfo_release_ref();
535 }
536 }
537 /* Free the udata buffer allocated in task_duplicate_map_and_threads */
538 if (udata_buffer != NULL) {
539 kfree(udata_buffer, size);
540 }
541
542 return kr;
543}
544
545/*
546 * Routine: task_map_corpse_info
547 * params: task - Map the corpse info in task's address space
548 * corpse_task - task port of the corpse
549 * kcd_addr_begin - address of the mapped corpse info
550 * kcd_addr_begin - size of the mapped corpse info
551 * returns: KERN_SUCCESS on Success.
552 * KERN_FAILURE on Failure.
553 * KERN_INVALID_ARGUMENT on invalid arguments.
554 * Note: Temporary function, will be deleted soon.
555 */
556kern_return_t
557task_map_corpse_info(
558 task_t task,
559 task_t corpse_task,
560 vm_address_t *kcd_addr_begin,
561 uint32_t *kcd_size)
562{
563 kern_return_t kr;
564 mach_vm_address_t kcd_addr_begin_64;
565 mach_vm_size_t size_64;
566
567 kr = task_map_corpse_info_64(task, corpse_task, &kcd_addr_begin_64, &size_64);
568 if (kr != KERN_SUCCESS) {
569 return kr;
570 }
571
572 *kcd_addr_begin = (vm_address_t)kcd_addr_begin_64;
573 *kcd_size = (uint32_t) size_64;
574 return KERN_SUCCESS;
575}
576
577/*
578 * Routine: task_map_corpse_info_64
579 * params: task - Map the corpse info in task's address space
580 * corpse_task - task port of the corpse
581 * kcd_addr_begin - address of the mapped corpse info (takes mach_vm_addess_t *)
582 * kcd_addr_begin - size of the mapped corpse info (takes mach_vm_size_t *)
583 * returns: KERN_SUCCESS on Success.
584 * KERN_FAILURE on Failure.
585 * KERN_INVALID_ARGUMENT on invalid arguments.
586 */
587kern_return_t
588task_map_corpse_info_64(
589 task_t task,
590 task_t corpse_task,
591 mach_vm_address_t *kcd_addr_begin,
592 mach_vm_size_t *kcd_size)
593{
594 kern_return_t kr;
595 mach_vm_offset_t crash_data_ptr = 0;
596 mach_vm_size_t size = CORPSEINFO_ALLOCATION_SIZE;
597
598 if (task == TASK_NULL || task_is_a_corpse_fork(task)) {
599 return KERN_INVALID_ARGUMENT;
600 }
601
602 if (corpse_task == TASK_NULL || !task_is_a_corpse(corpse_task) ||
603 corpse_task->corpse_info == NULL || corpse_task->corpse_info_kernel == NULL) {
604 return KERN_INVALID_ARGUMENT;
605 }
606 kr = mach_vm_allocate(task->map, &crash_data_ptr, size,
607 (VM_MAKE_TAG(VM_MEMORY_CORPSEINFO) | VM_FLAGS_ANYWHERE));
608 if (kr != KERN_SUCCESS) {
609 return kr;
610 }
611 copyout(corpse_task->corpse_info_kernel, crash_data_ptr, size);
612 *kcd_addr_begin = crash_data_ptr;
613 *kcd_size = size;
614
615 return KERN_SUCCESS;
616}