]>
Commit | Line | Data |
---|---|---|
9bccf70c | 1 | /* |
2d21ac55 | 2 | * Copyright (c) 2002-2006 Apple Computer, Inc. All rights reserved. |
9bccf70c | 3 | * |
2d21ac55 | 4 | * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ |
9bccf70c | 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@ |
9bccf70c A |
27 | */ |
28 | ||
29 | #include <sys/param.h> | |
30 | #include <sys/fcntl.h> | |
31 | #include <sys/malloc.h> | |
9bccf70c | 32 | #include <sys/proc.h> |
9bccf70c A |
33 | #include <sys/sysctl.h> |
34 | #include <sys/vnode.h> | |
35 | #include <sys/vm.h> | |
91447636 | 36 | #include <sys/systm.h> |
9bccf70c | 37 | |
91447636 | 38 | #include <mach/mach_types.h> |
9bccf70c | 39 | #include <mach/kern_return.h> |
91447636 A |
40 | #include <kern/kern_types.h> |
41 | #include <vm/vm_kern.h> | |
9bccf70c | 42 | |
9bccf70c | 43 | |
91447636 A |
44 | /* prototypes not exported by osfmk/console. */ |
45 | extern void panic_dialog_test( void ); | |
46 | extern int panic_dialog_set_image( const unsigned char * ptr, unsigned int size ); | |
47 | extern void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size ); | |
9bccf70c | 48 | |
91447636 | 49 | /* make the compiler happy */ |
6d2010ae | 50 | static int sysctl_dopanicinfo SYSCTL_HANDLER_ARGS; |
9bccf70c | 51 | |
9bccf70c | 52 | |
91447636 A |
53 | #define PANIC_IMAGE_SIZE_LIMIT (32 * 4096) /* 128K - Maximum amount of memory consumed for the panic UI */ |
54 | #define KERN_PANICINFO_TEST (KERN_PANICINFO_IMAGE+2) /* Allow the panic UI to be tested by root without causing a panic */ | |
9bccf70c | 55 | |
91447636 A |
56 | /* Local data */ |
57 | static int image_size_limit = PANIC_IMAGE_SIZE_LIMIT; | |
9bccf70c | 58 | |
6d2010ae A |
59 | /* XXX Should be STATIC for dtrace debugging.. */ |
60 | static int | |
61 | sysctl_dopanicinfo SYSCTL_HANDLER_ARGS | |
9bccf70c | 62 | { |
6d2010ae A |
63 | __unused int cmd = oidp->oid_arg2; /* subcommand*/ |
64 | int *name = arg1; /* oid element argument vector */ | |
65 | int namelen = arg2; /* number of oid element arguments */ | |
66 | user_addr_t oldp = req->oldptr; /* user buffer copy out address */ | |
67 | size_t *oldlenp = &req->oldlen; /* user buffer copy out size */ | |
68 | user_addr_t newp = req->newptr; /* user buffer copy in address */ | |
69 | size_t newlen = req->newlen; /* user buffer copy in size */ | |
9bccf70c | 70 | int error = 0; |
6d2010ae A |
71 | proc_t p = current_proc(); |
72 | ||
91447636 A |
73 | vm_offset_t newimage = (vm_offset_t )NULL; |
74 | kern_return_t kret; | |
75 | unsigned char * prev_image_ptr; | |
76 | unsigned int prev_image_size; | |
77 | ||
9bccf70c A |
78 | /* all sysctl names at this level are terminal */ |
79 | if (namelen != 1) | |
80 | return (ENOTDIR); /* overloaded */ | |
81 | ||
6d2010ae A |
82 | /* must be super user to muck with image */ |
83 | if ( (error = proc_suser(p)) ) | |
91447636 A |
84 | return (error); |
85 | ||
9bccf70c A |
86 | switch (name[0]) { |
87 | default: | |
91447636 A |
88 | return (ENOTSUP); |
89 | ||
90 | case KERN_PANICINFO_TEST: | |
91 | ||
92 | panic_dialog_test(); | |
6d2010ae | 93 | break; |
91447636 | 94 | |
9bccf70c | 95 | case KERN_PANICINFO_MAXSIZE: |
91447636 A |
96 | |
97 | /* return the image size limits */ | |
98 | ||
99 | newlen = 0; | |
100 | newp = USER_ADDR_NULL; | |
101 | ||
102 | error = sysctl_int(oldp, oldlenp, newp, newlen, &image_size_limit); | |
103 | ||
6d2010ae | 104 | break; |
9bccf70c | 105 | |
91447636 A |
106 | case KERN_PANICINFO_IMAGE: |
107 | ||
108 | /* If we have a new image, allocate wired kernel memory and copy it in from user space */ | |
109 | if ( newp != USER_ADDR_NULL ) { | |
110 | ||
111 | /* check the length of the incoming image before allocating space for it. */ | |
6d2010ae A |
112 | if ( newlen > (size_t)image_size_limit ) { |
113 | error = ENOMEM; | |
114 | break; | |
115 | } | |
91447636 A |
116 | |
117 | /* allocate some kernel wired memory for the new image */ | |
b0d623f7 | 118 | kret = kmem_alloc(kernel_map, &newimage, (vm_size_t)round_page(newlen)); |
91447636 A |
119 | |
120 | if (kret != KERN_SUCCESS) { | |
121 | switch (kret) { | |
122 | default: | |
123 | error = EINVAL; | |
124 | break; | |
125 | case KERN_NO_SPACE: | |
126 | case KERN_RESOURCE_SHORTAGE: | |
127 | error = ENOMEM; | |
128 | break; | |
129 | case KERN_PROTECTION_FAILURE: | |
130 | error = EPERM; | |
131 | break; | |
132 | } | |
6d2010ae | 133 | break; |
91447636 A |
134 | } |
135 | ||
136 | /* copy the image in from user space */ | |
137 | if ( (error = copyin(newp, (char *) newimage, newlen)) ) | |
9bccf70c A |
138 | goto errout; |
139 | ||
91447636 A |
140 | } else { /* setup to make the default image active */ |
141 | ||
142 | newimage = (vm_offset_t )NULL; | |
143 | newlen = 0; | |
144 | } | |
145 | ||
146 | /* get the current image location and size */ | |
147 | panic_dialog_get_image( &prev_image_ptr, &prev_image_size ); | |
148 | ||
149 | /* did the caller request a copy of the previous image ? */ | |
150 | if ( oldp != USER_ADDR_NULL ) { | |
151 | if ( *oldlenp < prev_image_size ) { | |
152 | error = ERANGE; | |
153 | goto errout; | |
9bccf70c A |
154 | } |
155 | ||
91447636 A |
156 | /* copy the image to user space or zero the size if the default image is active */ |
157 | if ( prev_image_ptr != NULL ) { | |
158 | if ( (error = copyout( prev_image_ptr, oldp, prev_image_size )) ) | |
159 | goto errout; | |
9bccf70c | 160 | |
91447636 A |
161 | *oldlenp = prev_image_size; |
162 | } | |
163 | else /* tell the user that the default image is active */ | |
164 | *oldlenp = 0; | |
165 | } | |
9bccf70c | 166 | |
91447636 A |
167 | /* Make the new image active, or reactivate the default image. |
168 | But, handle the special case of asking for the current image | |
169 | without changing the current image. | |
170 | */ | |
9bccf70c | 171 | |
91447636 A |
172 | if ( !(oldp && newp == USER_ADDR_NULL) ) { |
173 | if ( (error = panic_dialog_set_image( (unsigned char *) newimage, newlen )) ) | |
174 | goto errout; | |
9bccf70c | 175 | |
91447636 A |
176 | /* free the wired memory used by the previous image */ |
177 | if ( prev_image_ptr != NULL ) { | |
b0d623f7 A |
178 | (void)kmem_free(kernel_map, (vm_offset_t) prev_image_ptr, (vm_size_t)round_page(prev_image_size)); |
179 | printf("Panic UI memory freed (%p)\n", (void *)round_page(prev_image_size)); | |
91447636 | 180 | } |
9bccf70c | 181 | } |
91447636 | 182 | |
6d2010ae | 183 | break; |
91447636 | 184 | |
9bccf70c | 185 | errout: |
91447636 | 186 | if ( newimage != (vm_offset_t )NULL ) |
b0d623f7 | 187 | (void)kmem_free(kernel_map, newimage, (vm_size_t)round_page(newlen)); |
91447636 | 188 | |
6d2010ae | 189 | break; |
9bccf70c | 190 | } |
6d2010ae A |
191 | |
192 | /* adjust index so we return the right required/consumed amount */ | |
193 | if (!error) | |
194 | req->oldidx += req->oldlen; | |
195 | ||
196 | return (error); | |
9bccf70c | 197 | } |
6d2010ae A |
198 | SYSCTL_PROC(_kern, KERN_PANICINFO, panicinfo, CTLTYPE_NODE|CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY, |
199 | 0, /* Pointer argument (arg1) */ | |
200 | 0, /* Integer argument (arg2) */ | |
201 | sysctl_dopanicinfo, /* Handler function */ | |
202 | NULL, /* Data pointer */ | |
203 | ""); |