]>
Commit | Line | Data |
---|---|---|
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. */ | |
36 | extern void kmem_free(vm_map_t, vm_offset_t, vm_size_t); | |
37 | extern kern_return_t kmem_alloc_wired(vm_map_t, vm_offset_t *, vm_size_t); | |
38 | ||
39 | ||
40 | /* Globals */ | |
41 | static off_t imagesizelimit = (4 * 4096); | |
42 | ||
43 | /* Information about the current panic image */ | |
44 | static int image_bits = 32; /* Bitdepth */ | |
45 | ||
46 | static char *image_pathname = NULL; /* path to it */ | |
47 | static size_t image_pathlen = 0; /* and the length of the pathname */ | |
48 | ||
49 | static vm_offset_t image_ptr = NULL; /* the image itself */ | |
50 | static off_t image_size = 0; /* and the imagesize */ | |
51 | ||
52 | ||
53 | __private_extern__ void | |
54 | get_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 | ||
61 | static int | |
62 | panicimage_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 | ||
138 | out: | |
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 | |
147 | sysctl_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 | } | |
228 | errout: | |
229 | FREE_ZONE(imname, MAXPATHLEN, M_NAMEI); | |
230 | return (error); | |
231 | } | |
232 | } |