]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_core.c
xnu-1504.9.26.tar.gz
[apple/xnu.git] / bsd / kern / kern_core.c
CommitLineData
1c79356b 1/*
2d21ac55 2 * Copyright (c) 2000-2006 Apple Computer, Inc. All rights reserved.
5d5c5d0d 3 *
2d21ac55 4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
1c79356b 5 *
2d21ac55
A
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
8f6c56a5 14 *
2d21ac55
A
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
8f6c56a5
A
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
2d21ac55
A
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
8f6c56a5 25 *
2d21ac55 26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
1c79356b
A
27 */
28/* Copyright (c) 1991 NeXT Computer, Inc. All rights reserved.
29 *
30 * File: bsd/kern/kern_core.c
31 *
32 * This file contains machine independent code for performing core dumps.
33 *
1c79356b
A
34 */
35
36#include <mach/vm_param.h>
37#include <mach/thread_status.h>
38
39#include <sys/param.h>
40#include <sys/systm.h>
41#include <sys/signalvar.h>
42#include <sys/resourcevar.h>
43#include <sys/namei.h>
91447636
A
44#include <sys/vnode_internal.h>
45#include <sys/proc_internal.h>
46#include <sys/kauth.h>
1c79356b
A
47#include <sys/timeb.h>
48#include <sys/times.h>
1c79356b 49#include <sys/acct.h>
91447636 50#include <sys/file_internal.h>
1c79356b
A
51#include <sys/uio.h>
52#include <sys/kernel.h>
53#include <sys/stat.h>
54
55#include <mach-o/loader.h>
56#include <mach/vm_region.h>
765c9de3 57#include <mach/vm_statistics.h>
1c79356b
A
58
59#include <vm/vm_kern.h>
91447636
A
60#include <vm/vm_protos.h> /* last */
61#include <vm/vm_map.h> /* current_map() */
62#include <mach/mach_vm.h> /* mach_vm_region_recurse() */
63#include <mach/task.h> /* task_suspend() */
64#include <kern/task.h> /* get_task_numacts() */
1c79356b 65
b0d623f7
A
66#include <security/audit/audit.h>
67
1c79356b
A
68typedef struct {
69 int flavor; /* the number for this flavor */
2d21ac55 70 mach_msg_type_number_t count; /* count of ints in this flavor */
1c79356b
A
71} mythread_state_flavor_t;
72
73#if defined (__ppc__)
2d21ac55
A
74/* 64 bit */
75mythread_state_flavor_t thread_flavor_array64[]={
76 {PPC_THREAD_STATE64 , PPC_THREAD_STATE64_COUNT},
77 {PPC_FLOAT_STATE, PPC_FLOAT_STATE_COUNT},
78 {PPC_EXCEPTION_STATE64, PPC_EXCEPTION_STATE64_COUNT},
79 {PPC_VECTOR_STATE, PPC_VECTOR_STATE_COUNT}
80 };
1c79356b 81
2d21ac55 82/* 32 bit */
1c79356b
A
83mythread_state_flavor_t thread_flavor_array[]={
84 {PPC_THREAD_STATE , PPC_THREAD_STATE_COUNT},
85 {PPC_FLOAT_STATE, PPC_FLOAT_STATE_COUNT},
55e303ae
A
86 {PPC_EXCEPTION_STATE, PPC_EXCEPTION_STATE_COUNT},
87 {PPC_VECTOR_STATE, PPC_VECTOR_STATE_COUNT}
1c79356b 88 };
2d21ac55 89
b0d623f7 90#elif defined (__i386__) || defined (__x86_64__)
1c79356b 91mythread_state_flavor_t thread_flavor_array [] = {
0c530ab8
A
92 {x86_THREAD_STATE, x86_THREAD_STATE_COUNT},
93 {x86_FLOAT_STATE, x86_FLOAT_STATE_COUNT},
94 {x86_EXCEPTION_STATE, x86_EXCEPTION_STATE_COUNT},
1c79356b 95 };
0c530ab8 96int mynum_flavors=3;
1c79356b
A
97#else
98#error architecture not supported
99#endif
100
101
102typedef struct {
103 vm_offset_t header;
104 int hoffset;
105 mythread_state_flavor_t *flavors;
106 int tstate_size;
2d21ac55 107 int flavor_count;
1c79356b
A
108} tir_t;
109
e5568f75 110/* XXX should be static */
91447636 111void collectth_state(thread_t th_act, void *tirp);
e5568f75
A
112
113/* XXX not in a Mach header anywhere */
91447636 114kern_return_t thread_getstatus(register thread_t act, int flavor,
e5568f75 115 thread_state_t tstate, mach_msg_type_number_t *count);
91447636 116void task_act_iterate_wth_args(task_t, void(*)(thread_t, void *), void *);
e5568f75 117
b0d623f7
A
118static cpu_type_t process_cpu_type(proc_t proc);
119static cpu_type_t process_cpu_subtype(proc_t proc);
e5568f75 120
593a1d5f
A
121#ifdef SECURE_KERNEL
122__private_extern__ int do_coredump = 0; /* default: don't dump cores */
123#else
91447636 124__private_extern__ int do_coredump = 1; /* default: dump cores */
593a1d5f 125#endif
91447636 126__private_extern__ int sugid_coredump = 0; /* default: but not SGUID binaries */
e5568f75 127
b0d623f7
A
128
129/* cpu_type returns only the most generic indication of the current CPU. */
130/* in a core we want to know the kind of process. */
131
132static cpu_type_t
133process_cpu_type(proc_t core_proc)
134{
135 cpu_type_t what_we_think;
136#if defined (__i386__) || defined (__x86_64__)
137 if (IS_64BIT_PROCESS(core_proc)) {
138 what_we_think = CPU_TYPE_X86_64;
139 } else {
140 what_we_think = CPU_TYPE_I386;
141 }
142#elif defined (__ppc__)
143 #pragma unused(core_proc)
144 what_we_think = CPU_TYPE_POWERPC;
145#endif
146 return what_we_think;
147}
148
149static cpu_type_t
150process_cpu_subtype(proc_t core_proc)
151{
152 cpu_type_t what_we_think;
153#if defined (__i386__) || defined (__x86_64__)
154 if (IS_64BIT_PROCESS(core_proc)) {
155 what_we_think = CPU_SUBTYPE_X86_64_ALL;
156 } else {
157 what_we_think = CPU_SUBTYPE_I386_ALL;
158 }
159#elif defined (__ppc__)
160 #pragma unused(core_proc)
161 what_we_think = CPU_SUBTYPE_POWERPC_ALL;
162#endif
163 return what_we_think;
164}
165
55e303ae 166void
91447636 167collectth_state(thread_t th_act, void *tirp)
1c79356b
A
168{
169 vm_offset_t header;
170 int hoffset, i ;
171 mythread_state_flavor_t *flavors;
172 struct thread_command *tc;
91447636
A
173 tir_t *t = (tir_t *)tirp;
174
1c79356b
A
175 /*
176 * Fill in thread command structure.
177 */
178 header = t->header;
179 hoffset = t->hoffset;
180 flavors = t->flavors;
181
182 tc = (struct thread_command *) (header + hoffset);
183 tc->cmd = LC_THREAD;
184 tc->cmdsize = sizeof(struct thread_command)
185 + t->tstate_size;
186 hoffset += sizeof(struct thread_command);
187 /*
188 * Follow with a struct thread_state_flavor and
189 * the appropriate thread state struct for each
190 * thread state flavor.
191 */
2d21ac55 192 for (i = 0; i < t->flavor_count; i++) {
1c79356b
A
193 *(mythread_state_flavor_t *)(header+hoffset) =
194 flavors[i];
195 hoffset += sizeof(mythread_state_flavor_t);
196 thread_getstatus(th_act, flavors[i].flavor,
e5568f75 197 (thread_state_t)(header+hoffset),
1c79356b
A
198 &flavors[i].count);
199 hoffset += flavors[i].count*sizeof(int);
200 }
201
202 t->hoffset = hoffset;
203}
e5568f75 204
2d21ac55 205
1c79356b 206/*
2d21ac55
A
207 * coredump
208 *
209 * Description: Create a core image on the file "core" for the process
210 * indicated
211 *
212 * Parameters: core_proc Process to dump core [*]
213 *
214 * Returns: 0 Success
215 * EFAULT Failed
216 *
217 * IMPORTANT: This function can only be called on the current process, due
218 * to assumptions below; see variable declaration section for
219 * details.
1c79356b
A
220 */
221#define MAX_TSTATE_FLAVORS 10
222int
2d21ac55 223coredump(proc_t core_proc)
1c79356b 224{
2d21ac55
A
225/* Begin assumptions that limit us to only the current process */
226 vfs_context_t ctx = vfs_context_current();
227 vm_map_t map = current_map();
228 task_t task = current_task();
229/* End assumptions */
230 kauth_cred_t cred = vfs_context_ucred(ctx);
231 int error = 0;
91447636 232 struct vnode_attr va;
1c79356b
A
233 int thread_count, segment_count;
234 int command_size, header_size, tstate_size;
91447636
A
235 int hoffset;
236 off_t foffset;
237 vm_map_offset_t vmoffset;
1c79356b 238 vm_offset_t header;
91447636 239 vm_map_size_t vmsize;
1c79356b
A
240 vm_prot_t prot;
241 vm_prot_t maxprot;
242 vm_inherit_t inherit;
2d21ac55
A
243 int error1 = 0;
244 char stack_name[MAXCOMLEN+6];
245 char *alloced_name = NULL;
e5568f75 246 char *name;
1c79356b 247 mythread_state_flavor_t flavors[MAX_TSTATE_FLAVORS];
e5568f75 248 vm_size_t mapsize;
1c79356b 249 int i;
2d21ac55 250 uint32_t nesting_depth = 0;
1c79356b
A
251 kern_return_t kret;
252 struct vm_region_submap_info_64 vbr;
2d21ac55 253 mach_msg_type_number_t vbrcount = 0;
1c79356b
A
254 tir_t tir1;
255 struct vnode * vp;
2d21ac55
A
256 struct mach_header *mh = NULL; /* protected by is_64 */
257 struct mach_header_64 *mh64 = NULL; /* protected by is_64 */
91447636
A
258 int is_64 = 0;
259 size_t mach_header_sz = sizeof(struct mach_header);
260 size_t segment_command_sz = sizeof(struct segment_command);
1c79356b 261
e5568f75
A
262 if (do_coredump == 0 || /* Not dumping at all */
263 ( (sugid_coredump == 0) && /* Not dumping SUID/SGID binaries */
91447636
A
264 ( (cred->cr_svuid != cred->cr_ruid) ||
265 (cred->cr_svgid != cred->cr_rgid)))) {
b0d623f7
A
266
267#if CONFIG_AUDIT
268 audit_proc_coredump(core_proc, NULL, EFAULT);
269#endif
1c79356b 270 return (EFAULT);
e5568f75 271 }
1c79356b 272
2d21ac55 273 if (IS_64BIT_PROCESS(core_proc)) {
91447636
A
274 is_64 = 1;
275 mach_header_sz = sizeof(struct mach_header_64);
276 segment_command_sz = sizeof(struct segment_command_64);
277 }
278
1c79356b
A
279 mapsize = get_vmmap_size(map);
280
2d21ac55 281 if (mapsize >= core_proc->p_rlimit[RLIMIT_CORE].rlim_cur)
1c79356b
A
282 return (EFAULT);
283 (void) task_suspend(task);
284
2d21ac55 285 MALLOC(alloced_name, char *, MAXPATHLEN, M_TEMP, M_NOWAIT | M_ZERO);
e5568f75 286
2d21ac55 287 /* create name according to sysctl'able format string */
e5568f75 288 /* if name creation fails, fall back to historical behaviour... */
b0d623f7
A
289 if (alloced_name == NULL ||
290 proc_core_name(core_proc->p_comm, kauth_cred_getuid(cred),
2d21ac55
A
291 core_proc->p_pid, alloced_name, MAXPATHLEN)) {
292 snprintf(stack_name, sizeof(stack_name),
293 "/cores/core.%d", core_proc->p_pid);
294 name = stack_name;
295 } else
296 name = alloced_name;
e5568f75 297
2d21ac55
A
298 if ((error = vnode_open(name, (O_CREAT | FWRITE | O_NOFOLLOW), S_IRUSR, VNODE_LOOKUP_NOFOLLOW, &vp, ctx)))
299 goto out2;
91447636
A
300
301 VATTR_INIT(&va);
302 VATTR_WANTED(&va, va_nlink);
1c79356b
A
303 /* Don't dump to non-regular files or files with links. */
304 if (vp->v_type != VREG ||
2d21ac55 305 vnode_getattr(vp, &va, ctx) || va.va_nlink != 1) {
1c79356b
A
306 error = EFAULT;
307 goto out;
308 }
309
91447636
A
310 VATTR_INIT(&va); /* better to do it here than waste more stack in vnode_setsize */
311 VATTR_SET(&va, va_data_size, 0);
2d21ac55
A
312 vnode_setattr(vp, &va, ctx);
313 core_proc->p_acflag |= ACORE;
1c79356b
A
314
315 /*
316 * If the task is modified while dumping the file
317 * (e.g., changes in threads or VM, the resulting
318 * file will not necessarily be correct.
319 */
320
321 thread_count = get_task_numacts(task);
322 segment_count = get_vmmap_entries(map); /* XXX */
2d21ac55
A
323#if defined (__ppc__)
324 if (is_64) {
325 tir1.flavor_count = sizeof(thread_flavor_array64)/sizeof(mythread_state_flavor_t);
326 bcopy(thread_flavor_array64, flavors,sizeof(thread_flavor_array64));
327 } else {
328#endif /* __ppc __ */
329 tir1.flavor_count = sizeof(thread_flavor_array)/sizeof(mythread_state_flavor_t);
330 bcopy(thread_flavor_array, flavors,sizeof(thread_flavor_array));
331#if defined (__ppc__)
332 }
333#endif /* __ppc __ */
1c79356b 334 tstate_size = 0;
2d21ac55 335 for (i = 0; i < tir1.flavor_count; i++)
1c79356b
A
336 tstate_size += sizeof(mythread_state_flavor_t) +
337 (flavors[i].count * sizeof(int));
91447636 338 command_size = segment_count * segment_command_sz +
1c79356b
A
339 thread_count*sizeof(struct thread_command) +
340 tstate_size*thread_count;
341
91447636 342 header_size = command_size + mach_header_sz;
1c79356b 343
b0d623f7
A
344 if (kmem_alloc(kernel_map, &header, (vm_size_t)header_size) != KERN_SUCCESS) {
345 error = ENOMEM;
346 goto out;
347 }
1c79356b
A
348
349 /*
350 * Set up Mach-O header.
351 */
91447636
A
352 if (is_64) {
353 mh64 = (struct mach_header_64 *)header;
354 mh64->magic = MH_MAGIC_64;
b0d623f7
A
355 mh64->cputype = process_cpu_type(core_proc);
356 mh64->cpusubtype = process_cpu_subtype(core_proc);
91447636
A
357 mh64->filetype = MH_CORE;
358 mh64->ncmds = segment_count + thread_count;
359 mh64->sizeofcmds = command_size;
360 mh64->reserved = 0; /* 8 byte alignment */
361 } else {
362 mh = (struct mach_header *)header;
363 mh->magic = MH_MAGIC;
b0d623f7
A
364 mh->cputype = process_cpu_type(core_proc);
365 mh->cpusubtype = process_cpu_subtype(core_proc);
91447636
A
366 mh->filetype = MH_CORE;
367 mh->ncmds = segment_count + thread_count;
368 mh->sizeofcmds = command_size;
369 }
370
371 hoffset = mach_header_sz; /* offset into header */
372 foffset = round_page(header_size); /* offset into file */
373 vmoffset = MACH_VM_MIN_ADDRESS; /* offset into VM */
374
55e303ae
A
375 /*
376 * We use to check for an error, here, now we try and get
1c79356b
A
377 * as much as we can
378 */
91447636
A
379 while (segment_count > 0) {
380 struct segment_command *sc;
381 struct segment_command_64 *sc64;
382
1c79356b
A
383 /*
384 * Get region information for next region.
385 */
386
387 while (1) {
388 vbrcount = VM_REGION_SUBMAP_INFO_COUNT_64;
91447636
A
389 if((kret = mach_vm_region_recurse(map,
390 &vmoffset, &vmsize, &nesting_depth,
391 (vm_region_recurse_info_t)&vbr,
392 &vbrcount)) != KERN_SUCCESS) {
393 break;
394 }
395 /*
396 * If we get a valid mapping back, but we're dumping
397 * a 32 bit process, and it's over the allowable
398 * address space of a 32 bit process, it's the same
399 * as if mach_vm_region_recurse() failed.
400 */
401 if (!(is_64) &&
402 (vmoffset + vmsize > VM_MAX_ADDRESS)) {
403 kret = KERN_INVALID_ADDRESS;
1c79356b
A
404 break;
405 }
406 if(vbr.is_submap) {
407 nesting_depth++;
408 continue;
409 } else {
410 break;
411 }
412 }
413 if(kret != KERN_SUCCESS)
414 break;
415
416 prot = vbr.protection;
417 maxprot = vbr.max_protection;
418 inherit = vbr.inheritance;
419 /*
420 * Fill in segment command structure.
421 */
91447636
A
422 if (is_64) {
423 sc64 = (struct segment_command_64 *)(header + hoffset);
424 sc64->cmd = LC_SEGMENT_64;
425 sc64->cmdsize = sizeof(struct segment_command_64);
426 /* segment name is zeroed by kmem_alloc */
427 sc64->segname[0] = 0;
428 sc64->vmaddr = vmoffset;
429 sc64->vmsize = vmsize;
430 sc64->fileoff = foffset;
431 sc64->filesize = vmsize;
432 sc64->maxprot = maxprot;
433 sc64->initprot = prot;
434 sc64->nsects = 0;
435 } else {
436 sc = (struct segment_command *) (header + hoffset);
437 sc->cmd = LC_SEGMENT;
438 sc->cmdsize = sizeof(struct segment_command);
439 /* segment name is zeroed by kmem_alloc */
440 sc->segname[0] = 0;
b0d623f7
A
441 sc->vmaddr = CAST_DOWN_EXPLICIT(vm_offset_t,vmoffset);
442 sc->vmsize = CAST_DOWN_EXPLICIT(vm_size_t,vmsize);
443 sc->fileoff = CAST_DOWN_EXPLICIT(uint32_t,foffset); /* will never truncate */
444 sc->filesize = CAST_DOWN_EXPLICIT(uint32_t,vmsize); /* will never truncate */
91447636
A
445 sc->maxprot = maxprot;
446 sc->initprot = prot;
447 sc->nsects = 0;
448 }
1c79356b
A
449
450 /*
451 * Write segment out. Try as hard as possible to
452 * get read access to the data.
453 */
454 if ((prot & VM_PROT_READ) == 0) {
91447636
A
455 mach_vm_protect(map, vmoffset, vmsize, FALSE,
456 prot|VM_PROT_READ);
1c79356b
A
457 }
458 /*
459 * Only actually perform write if we can read.
460 * Note: if we can't read, then we end up with
461 * a hole in the file.
462 */
55e303ae
A
463 if ((maxprot & VM_PROT_READ) == VM_PROT_READ
464 && vbr.user_tag != VM_MEMORY_IOKIT
465 && coredumpok(map,vmoffset)) {
b0d623f7
A
466
467 error = vn_rdwr_64(UIO_WRITE, vp, vmoffset, vmsize, foffset,
2d21ac55 468 (IS_64BIT_PROCESS(core_proc) ? UIO_USERSPACE64 : UIO_USERSPACE32),
b0d623f7
A
469 IO_NOCACHE|IO_NODELOCKED|IO_UNIT, cred, (int64_t *) 0, core_proc);
470
1c79356b
A
471 }
472
91447636
A
473 hoffset += segment_command_sz;
474 foffset += vmsize;
475 vmoffset += vmsize;
1c79356b
A
476 segment_count--;
477 }
478
91447636
A
479 /*
480 * If there are remaining segments which have not been written
481 * out because break in the loop above, then they were not counted
482 * because they exceed the real address space of the executable
483 * type: remove them from the header's count. This is OK, since
484 * we are allowed to have a sparse area following the segments.
485 */
486 if (is_64) {
487 mh64->ncmds -= segment_count;
2d21ac55 488 mh64->sizeofcmds -= segment_count * segment_command_sz;
91447636
A
489 } else {
490 mh->ncmds -= segment_count;
2d21ac55 491 mh->sizeofcmds -= segment_count * segment_command_sz;
91447636
A
492 }
493
1c79356b
A
494 tir1.header = header;
495 tir1.hoffset = hoffset;
496 tir1.flavors = flavors;
497 tir1.tstate_size = tstate_size;
498 task_act_iterate_wth_args(task, collectth_state,&tir1);
499
1c79356b
A
500 /*
501 * Write out the Mach header at the beginning of the
91447636 502 * file. OK to use a 32 bit write for this.
1c79356b
A
503 */
504 error = vn_rdwr(UIO_WRITE, vp, (caddr_t)header, header_size, (off_t)0,
b0d623f7 505 UIO_SYSSPACE, IO_NOCACHE|IO_NODELOCKED|IO_UNIT, cred, (int *) 0, core_proc);
1c79356b
A
506 kmem_free(kernel_map, header, header_size);
507out:
2d21ac55
A
508 error1 = vnode_close(vp, FWRITE, ctx);
509out2:
b0d623f7
A
510#if CONFIG_AUDIT
511 audit_proc_coredump(core_proc, name, error);
512#endif
2d21ac55
A
513 if (alloced_name != NULL)
514 FREE(alloced_name, M_TEMP);
1c79356b
A
515 if (error == 0)
516 error = error1;
91447636 517
55e303ae 518 return (error);
1c79356b 519}