]> git.saurik.com Git - apple/xnu.git/blame - osfmk/corpses/corpse.c
xnu-4570.71.2.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
5ba3f43e 119#include <stdatomic.h>
3e170ce0
A
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>
5ba3f43e 132#include <kern/exc_guard.h>
3e170ce0 133
39037602
A
134#if CONFIG_MACF
135#include <security/mac_mach_internal.h>
136#endif
137
138/*
139 * Exported interfaces
140 */
141#include <mach/task_server.h>
142
5ba3f43e
A
143union corpse_creation_gate {
144 struct {
145 uint16_t user_faults;
146 uint16_t corpses;
147 };
148 uint32_t value;
149};
150
151static _Atomic uint32_t inflight_corpses;
3e170ce0
A
152unsigned long total_corpses_created = 0;
153boolean_t corpse_enabled_config = TRUE;
154
39037602
A
155/* bootarg to turn on corpse forking for EXC_RESOURCE */
156int exc_via_corpse_forking = 1;
157
39037602
A
158/* bootarg to generate corpse for fatal high memory watermark violation */
159int corpse_for_fatal_memkill = 1;
160
5ba3f43e
A
161#ifdef __arm__
162static inline int IS_64BIT_PROCESS(__unused void *p) { return 0; }
163#else
39037602 164extern int IS_64BIT_PROCESS(void *);
5ba3f43e
A
165#endif /* __arm__ */
166extern 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);
39037602
A
169extern void *proc_find(int pid);
170extern int proc_rele(void *p);
3e170ce0
A
171
172
173void corpses_init(){
174 char temp_buf[20];
39037602 175 int exc_corpse_forking;
39037602 176 int fatal_memkill;
3e170ce0
A
177 if (PE_parse_boot_argn("-no_corpses", temp_buf, sizeof(temp_buf))) {
178 corpse_enabled_config = FALSE;
179 }
39037602
A
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;
182 }
39037602
A
183 if (PE_parse_boot_argn("corpse_for_fatal_memkill", &fatal_memkill, sizeof(fatal_memkill))) {
184 corpse_for_fatal_memkill = fatal_memkill;
185 }
3e170ce0
A
186}
187
188/*
189 * Routine: corpses_enabled
190 * returns FALSE if not enabled
191 */
192boolean_t corpses_enabled()
193{
194 return corpse_enabled_config;
195}
196
5ba3f43e
A
197unsigned long
198total_corpses_count(void)
199{
200 union corpse_creation_gate gate;
201
202 gate.value = atomic_load_explicit(&inflight_corpses, memory_order_relaxed);
203 return gate.corpses;
204}
205
3e170ce0
A
206/*
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.
210 */
5ba3f43e
A
211static kern_return_t
212task_crashinfo_get_ref(uint16_t kcd_u_flags)
3e170ce0 213{
5ba3f43e
A
214 union corpse_creation_gate oldgate, newgate;
215
216 assert(kcd_u_flags & CORPSE_CRASHINFO_HAS_REF);
217
218 oldgate.value = atomic_load_explicit(&inflight_corpses, memory_order_relaxed);
219 for (;;) {
220 newgate = oldgate;
221 if (kcd_u_flags & CORPSE_CRASHINFO_USER_FAULT) {
222 if (newgate.user_faults++ >= TOTAL_USER_FAULTS_ALLOWED) {
223 return KERN_RESOURCE_SHORTAGE;
224 }
225 }
226 if (newgate.corpses++ >= TOTAL_CORPSES_ALLOWED) {
227 return KERN_RESOURCE_SHORTAGE;
228 }
229
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)) {
234 return KERN_SUCCESS;
235 }
3e170ce0 236 }
3e170ce0
A
237}
238
239/*
240 * Routine: task_crashinfo_release_ref
241 * release the slot for corpse being used.
242 */
5ba3f43e
A
243static kern_return_t
244task_crashinfo_release_ref(uint16_t kcd_u_flags)
3e170ce0 245{
5ba3f43e
A
246 union corpse_creation_gate oldgate, newgate;
247
248 assert(kcd_u_flags & CORPSE_CRASHINFO_HAS_REF);
249
250 oldgate.value = atomic_load_explicit(&inflight_corpses, memory_order_relaxed);
251 for (;;) {
252 newgate = oldgate;
253 if (kcd_u_flags & CORPSE_CRASHINFO_USER_FAULT) {
254 if (newgate.user_faults-- == 0) {
255 panic("corpse in flight count over-release");
256 }
257 }
258 if (newgate.corpses-- == 0) {
259 panic("corpse in flight count over-release");
260 }
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)) {
265 return KERN_SUCCESS;
266 }
267 }
3e170ce0
A
268}
269
270
5ba3f43e
A
271kcdata_descriptor_t
272task_crashinfo_alloc_init(mach_vm_address_t crash_data_p, unsigned size,
273 uint32_t kc_u_flags, unsigned kc_flags)
3e170ce0 274{
5ba3f43e
A
275 kcdata_descriptor_t kcdata;
276
277 if (kc_u_flags & CORPSE_CRASHINFO_HAS_REF) {
278 if (KERN_SUCCESS != task_crashinfo_get_ref(kc_u_flags)) {
279 return NULL;
280 }
3e170ce0
A
281 }
282
5ba3f43e
A
283 kcdata = kcdata_memory_alloc_init(crash_data_p, TASK_CRASHINFO_BEGIN, size,
284 kc_flags);
285 if (kcdata) {
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);
289 }
290 return kcdata;
3e170ce0
A
291}
292
293
294/*
295 * Free up the memory associated with task_crashinfo_data
296 */
5ba3f43e
A
297kern_return_t
298task_crashinfo_destroy(kcdata_descriptor_t data)
3e170ce0
A
299{
300 if (!data) {
301 return KERN_INVALID_ARGUMENT;
302 }
5ba3f43e
A
303 if (data->kcd_user_flags & CORPSE_CRASHINFO_HAS_REF) {
304 task_crashinfo_release_ref(data->kcd_user_flags);
305 }
3e170ce0
A
306 return kcdata_memory_destroy(data);
307}
308
309/*
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
314 */
315kcdata_descriptor_t task_get_corpseinfo(task_t task)
316{
317 kcdata_descriptor_t retval = NULL;
318 if (task != NULL){
319 retval = task->corpse_info;
320 }
321 return retval;
322}
323
39037602
A
324/*
325 * Routine: task_add_to_corpse_task_list
326 * params: task - task to be added to corpse task list
327 * returns: None.
328 */
329void
330task_add_to_corpse_task_list(task_t corpse_task)
331{
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);
335}
336
337/*
338 * Routine: task_remove_from_corpse_task_list
339 * params: task - task to be removed from corpse task list
340 * returns: None.
341 */
342void
343task_remove_from_corpse_task_list(task_t corpse_task)
344{
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);
348}
349
350/*
351 * Routine: task_purge_all_corpses
352 * params: None.
353 * returns: None.
354 */
355void
356task_purge_all_corpses(void)
357{
358 task_t task;
359
360 printf("Purging corpses......\n\n");
361
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,
5ba3f43e
A
366 task->map->min_offset,
367 task->map->max_offset,
368 /*
369 * Final cleanup:
370 * + no unnesting
371 * + remove immutable mappings
372 */
373 (VM_MAP_REMOVE_NO_UNNESTING |
374 VM_MAP_REMOVE_IMMUTABLE));
39037602
A
375 }
376
377 lck_mtx_unlock(&tasks_corpse_lock);
378}
379
380/*
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.
5ba3f43e 386 * KERN_NOT_SUPPORTED on corpse disabled.
39037602
A
387 * KERN_RESOURCE_SHORTAGE on memory alloc failure or reaching max corpse.
388 */
389kern_return_t
390task_generate_corpse(
391 task_t task,
392 ipc_port_t *corpse_task_port)
393{
394 task_t new_task;
395 kern_return_t kr;
396 thread_t thread, th_iter;
397 ipc_port_t corpse_port;
398 ipc_port_t old_notify;
399
400 if (task == kernel_task || task == TASK_NULL || task == current_task()) {
401 return KERN_INVALID_ARGUMENT;
402 }
403
404 task_lock(task);
405 if (task_is_a_corpse_fork(task)) {
406 task_unlock(task);
407 return KERN_INVALID_ARGUMENT;
408 }
409 task_unlock(task);
410
411 /* Generate a corpse for the given task, will return with a ref on corpse task */
5ba3f43e 412 kr = task_generate_corpse_internal(task, &new_task, &thread, 0, 0, 0, NULL);
39037602
A
413 if (kr != KERN_SUCCESS) {
414 return kr;
415 }
416 assert(thread == THREAD_NULL);
417
418 /* wait for all the threads in the task to terminate */
419 task_lock(new_task);
420 task_wait_till_threads_terminate_locked(new_task);
421
422 /* Reset thread ports of all the threads in task */
423 queue_iterate(&new_task->threads, th_iter, thread_t, task_threads)
424 {
425 /* Do not reset the thread port for inactive threads */
426 if (th_iter->corpse_dup == FALSE) {
427 ipc_thread_reset(th_iter);
428 }
429 }
430 task_unlock(new_task);
431
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);
435
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);
439 /* port unlocked */
440
441 assert(IP_NULL == old_notify);
442 *corpse_task_port = corpse_port;
443 return KERN_SUCCESS;
444}
445
446/*
447 * Routine: task_enqueue_exception_with_corpse
448 * params: task - task to generate a corpse and enqueue it
5ba3f43e 449 * etype - EXC_RESOURCE or EXC_GUARD
39037602
A
450 * code - exception code to be enqueued
451 * codeCnt - code array count - code and subcode
5ba3f43e
A
452 *
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.
39037602 458 */
5ba3f43e 459kern_return_t
39037602
A
460task_enqueue_exception_with_corpse(
461 task_t task,
5ba3f43e 462 exception_type_t etype,
39037602 463 mach_exception_data_t code,
5ba3f43e
A
464 mach_msg_type_number_t codeCnt,
465 void *reason)
39037602
A
466{
467 task_t new_task = TASK_NULL;
468 thread_t thread = THREAD_NULL;
469 kern_return_t kr;
470
471 if (codeCnt < 2) {
5ba3f43e 472 return KERN_INVALID_ARGUMENT;
39037602
A
473 }
474
475 /* Generate a corpse for the given task, will return with a ref on corpse task */
5ba3f43e
A
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);
39037602 483 }
5ba3f43e 484 return kr;
39037602
A
485}
486
487/*
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
5ba3f43e 492 * etype - EXC_RESOURCE or EXC_GUARD or 0
39037602 493 * code - mach exception code to be passed in corpse blob
5ba3f43e 494 * subcode - mach exception subcode to be passed in corpse blob
39037602
A
495 * returns: KERN_SUCCESS on Success.
496 * KERN_FAILURE on Failure.
5ba3f43e 497 * KERN_NOT_SUPPORTED on corpse disabled.
39037602
A
498 * KERN_RESOURCE_SHORTAGE on memory alloc failure or reaching max corpse.
499 */
500kern_return_t
501task_generate_corpse_internal(
502 task_t task,
503 task_t *corpse_task,
504 thread_t *exc_thread,
5ba3f43e 505 exception_type_t etype,
39037602 506 mach_exception_data_type_t code,
5ba3f43e
A
507 mach_exception_data_type_t subcode,
508 void *reason)
39037602
A
509{
510 task_t new_task = TASK_NULL;
511 thread_t thread = THREAD_NULL;
512 thread_t thread_next = THREAD_NULL;
513 kern_return_t kr;
514 struct proc *p = NULL;
515 int is64bit;
516 int t_flags;
517 uint64_t *udata_buffer = NULL;
518 int size = 0;
519 int num_udata = 0;
5ba3f43e 520 uint16_t kc_u_flags = CORPSE_CRASHINFO_HAS_REF;
39037602 521
5ba3f43e
A
522#if CONFIG_MACF
523 struct label *label = NULL;
524#endif
525
39037602
A
526 if (!corpses_enabled()) {
527 return KERN_NOT_SUPPORTED;
528 }
529
5ba3f43e
A
530 if (etype == EXC_GUARD && EXC_GUARD_DECODE_GUARD_TYPE(code) == GUARD_TYPE_USER) {
531 kc_u_flags |= CORPSE_CRASHINFO_USER_FAULT;
532 }
533
534 kr = task_crashinfo_get_ref(kc_u_flags);
39037602
A
535 if (kr != KERN_SUCCESS) {
536 return kr;
537 }
39037602
A
538
539 /* Having a task reference does not guarantee a proc reference */
540 p = proc_find(task_pid(task));
541 if (p == NULL) {
542 kr = KERN_INVALID_TASK;
543 goto error_task_generate_corpse;
544 }
545
546 is64bit = IS_64BIT_PROCESS(p);
547 t_flags = TF_CORPSE_FORK | TF_PENDING_CORPSE | TF_CORPSE | (is64bit ? TF_64B_ADDR : TF_NONE);
548
5ba3f43e
A
549#if CONFIG_MACF
550 /* Create the corpse label credentials from the process. */
551 label = mac_exc_create_label_for_proc(p);
552#endif
553
39037602
A
554 /* Create a task for corpse */
555 kr = task_create_internal(task,
556 NULL,
557 TRUE,
558 is64bit,
559 t_flags,
743345f9 560 TPF_NONE,
39037602
A
561 &new_task);
562 if (kr != KERN_SUCCESS) {
563 goto error_task_generate_corpse;
564 }
565
566 /* Create and copy threads from task, returns a ref to thread */
567 kr = task_duplicate_map_and_threads(task, p, new_task, &thread,
813fb2f6 568 &udata_buffer, &size, &num_udata);
39037602
A
569 if (kr != KERN_SUCCESS) {
570 goto error_task_generate_corpse;
571 }
572
5ba3f43e
A
573 kr = task_collect_crash_info(new_task,
574#if CONFIG_MACF
575 label,
576#endif
577 TRUE);
39037602
A
578 if (kr != KERN_SUCCESS) {
579 goto error_task_generate_corpse;
580 }
581
5ba3f43e
A
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;
585 kc_u_flags = 0;
39037602
A
586
587 kr = task_start_halt(new_task);
588 if (kr != KERN_SUCCESS) {
589 goto error_task_generate_corpse;
590 }
591
592 /* terminate the ipc space */
593 ipc_space_terminate(new_task->itk_space);
594
595 /* Populate the corpse blob, use the proc struct of task instead of corpse task */
5ba3f43e
A
596 gather_populate_corpse_crashinfo(p, new_task,
597 code, subcode, udata_buffer, num_udata, reason);
39037602
A
598
599 /* Add it to global corpse task list */
600 task_add_to_corpse_task_list(new_task);
601
602 *corpse_task = new_task;
603 *exc_thread = thread;
604
605error_task_generate_corpse:
5ba3f43e
A
606#if CONFIG_MACF
607 if (label) {
608 mac_exc_free_label(label);
609 }
610#endif
611
39037602
A
612 /* Release the proc reference */
613 if (p != NULL) {
614 proc_rele(p);
615 }
3e170ce0 616
39037602
A
617 if (kr != KERN_SUCCESS) {
618 if (thread != THREAD_NULL) {
619 thread_deallocate(thread);
620 }
621 if (new_task != TASK_NULL) {
622 task_lock(new_task);
623 /* Terminate all the other threads in the task. */
624 queue_iterate(&new_task->threads, thread_next, thread_t, task_threads)
625 {
626 thread_terminate_internal(thread_next);
627 }
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);
631
632 task_clear_corpse(new_task);
633 task_terminate_internal(new_task);
634 task_deallocate(new_task);
635 }
5ba3f43e
A
636 if (kc_u_flags) {
637 task_crashinfo_release_ref(kc_u_flags);
39037602
A
638 }
639 }
640 /* Free the udata buffer allocated in task_duplicate_map_and_threads */
641 if (udata_buffer != NULL) {
642 kfree(udata_buffer, size);
643 }
644
645 return kr;
646}
647
648/*
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.
658 */
659kern_return_t
660task_map_corpse_info(
661 task_t task,
662 task_t corpse_task,
663 vm_address_t *kcd_addr_begin,
664 uint32_t *kcd_size)
665{
666 kern_return_t kr;
667 mach_vm_address_t kcd_addr_begin_64;
668 mach_vm_size_t size_64;
669
670 kr = task_map_corpse_info_64(task, corpse_task, &kcd_addr_begin_64, &size_64);
671 if (kr != KERN_SUCCESS) {
672 return kr;
673 }
674
675 *kcd_addr_begin = (vm_address_t)kcd_addr_begin_64;
676 *kcd_size = (uint32_t) size_64;
677 return KERN_SUCCESS;
678}
679
680/*
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.
689 */
690kern_return_t
691task_map_corpse_info_64(
692 task_t task,
693 task_t corpse_task,
694 mach_vm_address_t *kcd_addr_begin,
695 mach_vm_size_t *kcd_size)
696{
697 kern_return_t kr;
698 mach_vm_offset_t crash_data_ptr = 0;
699 mach_vm_size_t size = CORPSEINFO_ALLOCATION_SIZE;
5ba3f43e 700 void *corpse_info_kernel = NULL;
39037602
A
701
702 if (task == TASK_NULL || task_is_a_corpse_fork(task)) {
703 return KERN_INVALID_ARGUMENT;
704 }
705
706 if (corpse_task == TASK_NULL || !task_is_a_corpse(corpse_task) ||
5ba3f43e 707 kcdata_memory_get_begin_addr(corpse_task->corpse_info) == NULL) {
39037602
A
708 return KERN_INVALID_ARGUMENT;
709 }
5ba3f43e
A
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);
39037602
A
713 if (kr != KERN_SUCCESS) {
714 return kr;
715 }
5ba3f43e 716 copyout(corpse_info_kernel, crash_data_ptr, size);
39037602
A
717 *kcd_addr_begin = crash_data_ptr;
718 *kcd_size = size;
719
720 return KERN_SUCCESS;
721}
5ba3f43e
A
722
723uint64_t
724task_corpse_get_crashed_thread_id(task_t corpse_task)
725{
726 return corpse_task->crashed_thread_id;
727}