]> git.saurik.com Git - apple/xnu.git/blame - bsd/kern/kern_panicinfo.c
xnu-344.tar.gz
[apple/xnu.git] / bsd / kern / kern_panicinfo.c
CommitLineData
9bccf70c
A
1/*
2 * Copyright (c) 2002 Apple Computer, Inc. All rights reserved.
3 *
4 * @APPLE_LICENSE_HEADER_START@
5 *
6 * The contents of this file constitute Original Code as defined in and
7 * are subject to the Apple Public Source License Version 1.1 (the
8 * "License"). You may not use this file except in compliance with the
9 * License. Please obtain a copy of the License at
10 * http://www.apple.com/publicsource and read it before using this file.
11 *
12 * This Original Code and all software distributed under the License are
13 * distributed on an "AS IS" basis, WITHOUT WARRANTY OF ANY KIND, EITHER
14 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
15 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
16 * FITNESS FOR A PARTICULAR PURPOSE OR NON-INFRINGEMENT. Please see the
17 * License for the specific language governing rights and limitations
18 * under the License.
19 *
20 * @APPLE_LICENSE_HEADER_END@
21 */
22
23#include <sys/param.h>
24#include <sys/fcntl.h>
25#include <sys/malloc.h>
26#include <sys/namei.h>
27#include <sys/proc.h>
28#include <sys/stat.h>
29#include <sys/sysctl.h>
30#include <sys/vnode.h>
31#include <sys/vm.h>
32
33#include <mach/kern_return.h>
34
35/* prototypes not exported by osfmk. */
36extern void kmem_free(vm_map_t, vm_offset_t, vm_size_t);
37extern kern_return_t kmem_alloc_wired(vm_map_t, vm_offset_t *, vm_size_t);
38
39
40/* Globals */
41static off_t imagesizelimit = (4 * 4096);
42
43/* Information about the current panic image */
44static int image_bits = 32; /* Bitdepth */
45
46static char *image_pathname = NULL; /* path to it */
47static size_t image_pathlen = 0; /* and the length of the pathname */
48
49static vm_offset_t image_ptr = NULL; /* the image itself */
50static off_t image_size = 0; /* and the imagesize */
51
52
53__private_extern__ void
54get_panicimage(vm_offset_t *imageptr, vm_size_t *imagesize, int *imagebits)
55{
56 *imageptr = image_ptr;
57 *imagesize = image_size;
58 *imagebits = image_bits;
59}
60
61static int
62panicimage_from_file(
63 char *imname,
64 off_t sizelimit,
65 vm_offset_t *image,
66 off_t *filesize,
67 struct proc *p)
68{
69 int error = 0;
70 int error1 = 0;
71 int aresid;
72 struct nameidata nd;
73 struct vattr vattr;
74 struct vnode * vp;
75 kern_return_t kret;
76 struct pcred *pcred = p->p_cred;
77 struct ucred *cred = pcred->pc_ucred;
78 vm_offset_t iobuf;
79
80 /* Open the file */
81 NDINIT(&nd, LOOKUP, FOLLOW, UIO_SYSSPACE, imname, p);
82 error = vn_open(&nd, FREAD, S_IRUSR);
83 if (error)
84 return (error);
85 vp = nd.ni_vp;
86
87 if (vp->v_type != VREG) {
88 error = EFAULT;
89 goto out;
90 }
91
92 /* get the file size */
93 error = VOP_GETATTR(vp, &vattr, cred, p);
94 if (error)
95 goto out;
96
97 /* validate the file size */
98 if (vattr.va_size > sizelimit) {
99 error = EFBIG;
100 goto out;
101 }
102
103 /* allocate kernel wired memory */
104 kret = kmem_alloc_wired(kernel_map, &iobuf,
105 (vm_size_t)vattr.va_size);
106 if (kret != KERN_SUCCESS) {
107 switch (kret) {
108 default:
109 error = EINVAL;
110 break;
111 case KERN_NO_SPACE:
112 case KERN_RESOURCE_SHORTAGE:
113 error = ENOMEM;
114 break;
115 case KERN_PROTECTION_FAILURE:
116 error = EPERM;
117 break;
118 }
119 goto out;
120 }
121
122 /* read the file in the kernel buffer */
123 error = vn_rdwr(UIO_READ, vp, (caddr_t)iobuf, (int)vattr.va_size,
124 (off_t)0, UIO_SYSSPACE, IO_NODELOCKED|IO_UNIT,
125 cred, &aresid, p);
126 if (error) {
127 (void)kmem_free(kernel_map, iobuf, (vm_size_t)vattr.va_size);
128 goto out;
129 }
130
131 /*
132 * return the image to the caller
133 * freeing this memory is callers responsibility
134 */
135 *image = iobuf;
136 *filesize = (off_t)vattr.va_size;
137
138out:
139 VOP_UNLOCK(vp, 0, p);
140 error1 = vn_close(vp, FREAD, cred, p);
141 if (error == 0)
142 error = error1;
143 return (error);
144}
145
146__private_extern__ int
147sysctl_dopanicinfo(name, namelen, oldp, oldlenp, newp, newlen, p)
148 int *name;
149 u_int namelen;
150 void *oldp;
151 size_t *oldlenp;
152 void *newp;
153 size_t newlen;
154 struct proc *p;
155{
156 int error = 0;
157 int bitdepth = 32; /* default is 32 bits */
158 char *imname;
159
160 /* all sysctl names at this level are terminal */
161 if (namelen != 1)
162 return (ENOTDIR); /* overloaded */
163
164 switch (name[0]) {
165 default:
166 return (EOPNOTSUPP);
167 case KERN_PANICINFO_MAXSIZE:
168 if (newp != NULL && (error = suser(p->p_ucred, &p->p_acflag)))
169 return (error);
170 error = sysctl_quad(oldp, oldlenp, newp, newlen, &imagesizelimit);
171 return (error);
172
173 case KERN_PANICINFO_IMAGE16:
174 bitdepth = 16;
175 /* and fall through */
176 case KERN_PANICINFO_IMAGE32:
177 /* allocate a buffer for the image pathname */
178 MALLOC_ZONE(imname, char *, MAXPATHLEN, M_NAMEI, M_WAITOK);
179
180 if (!newp) {
181 bcopy(image_pathname, imname, image_pathlen);
182 imname[image_pathlen] = '\0';
183 } else
184 imname[0] = '\0';
185 error = sysctl_string(oldp, oldlenp, newp, newlen,
186 imname, MAXPATHLEN);
187 if (newp && !error) {
188 char *tmpstr, *oldstr;
189 off_t filesize = 0;
190 size_t len;
191 vm_offset_t image;
192 vm_offset_t oimage;
193 vm_size_t osize;
194
195 len = strlen(imname);
196 oldstr = image_pathname;
197
198 error = panicimage_from_file(imname, imagesizelimit,
199 &image, &filesize, p);
200 if (error)
201 goto errout;
202
203 /* release the old image */
204 if (image_ptr) {
205 oimage = image_ptr;
206 osize = image_size;
207 }
208
209 /* remember the new one */
210 image_ptr = image;
211 image_bits = bitdepth; /* new bith depth */
212 image_size = filesize; /* new imagesize */
213
214 if (oimage)
215 kmem_free(kernel_map, oimage, osize);
216
217 /* save the new name */
218 MALLOC(tmpstr, char *, len+1, M_TEMP, M_WAITOK);
219 bcopy(imname, tmpstr, len);
220 tmpstr[len] = '\0';
221
222 image_pathname = tmpstr; /* new pathname */
223 image_pathlen = len; /* new pathname length */
224
225 /* free the old name */
226 FREE(oldstr, M_TEMP);
227 }
228errout:
229 FREE_ZONE(imname, MAXPATHLEN, M_NAMEI);
230 return (error);
231 }
232}