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