#include <sys/param.h>
#include <sys/fcntl.h>
#include <sys/malloc.h>
#include <sys/proc.h>
#include <sys/sysctl.h>
#include <sys/vnode.h>
#include <sys/vm.h>
#include <sys/systm.h>
#include <mach/mach_types.h>
#include <mach/kern_return.h>
#include <kern/kern_types.h>
#include <vm/vm_kern.h>
extern void panic_dialog_test( void );
extern void noroot_icon_test(void);
extern int panic_dialog_set_image( const unsigned char * ptr, unsigned int size );
extern void panic_dialog_get_image( unsigned char ** ptr, unsigned int * size );
static int sysctl_dopanicinfo SYSCTL_HANDLER_ARGS;
#define PANIC_IMAGE_SIZE_LIMIT (32 * 4096)
static int image_size_limit = PANIC_IMAGE_SIZE_LIMIT;
static int
sysctl_dopanicinfo SYSCTL_HANDLER_ARGS
{
__unused int cmd = oidp->oid_arg2;
int *name = arg1;
int namelen = arg2;
user_addr_t oldp = req->oldptr;
size_t *oldlenp = &req->oldlen;
user_addr_t newp = req->newptr;
size_t newlen = req->newlen;
int error = 0;
proc_t p = current_proc();
vm_offset_t newimage = (vm_offset_t )NULL;
kern_return_t kret;
unsigned char * prev_image_ptr;
unsigned int prev_image_size;
if (namelen != 1)
return (ENOTDIR);
if ( (error = proc_suser(p)) )
return (error);
switch (name[0]) {
default:
return (ENOTSUP);
case KERN_PANICINFO_TEST:
panic_dialog_test();
break;
case KERN_PANICINFO_NOROOT_TEST:
printf("Testing noroot icon \n");
noroot_icon_test();
break;
case KERN_PANICINFO_MAXSIZE:
newlen = 0;
newp = USER_ADDR_NULL;
error = sysctl_int(oldp, oldlenp, newp, newlen, &image_size_limit);
break;
case KERN_PANICINFO_IMAGE:
if ( newp != USER_ADDR_NULL ) {
if ( newlen > (size_t)image_size_limit ) {
error = ENOMEM;
break;
}
kret = kmem_alloc(kernel_map, &newimage, (vm_size_t)round_page(newlen));
if (kret != KERN_SUCCESS) {
switch (kret) {
default:
error = EINVAL;
break;
case KERN_NO_SPACE:
case KERN_RESOURCE_SHORTAGE:
error = ENOMEM;
break;
case KERN_PROTECTION_FAILURE:
error = EPERM;
break;
}
break;
}
if ( (error = copyin(newp, (char *) newimage, newlen)) )
goto errout;
} else {
newimage = (vm_offset_t )NULL;
newlen = 0;
}
panic_dialog_get_image( &prev_image_ptr, &prev_image_size );
if ( oldp != USER_ADDR_NULL ) {
if ( *oldlenp < prev_image_size ) {
error = ERANGE;
goto errout;
}
if ( prev_image_ptr != NULL ) {
if ( (error = copyout( prev_image_ptr, oldp, prev_image_size )) )
goto errout;
*oldlenp = prev_image_size;
}
else
*oldlenp = 0;
}
if ( !(oldp && newp == USER_ADDR_NULL) ) {
if ( (error = panic_dialog_set_image( (unsigned char *) newimage, newlen )) )
goto errout;
if ( prev_image_ptr != NULL ) {
(void)kmem_free(kernel_map, (vm_offset_t) prev_image_ptr, (vm_size_t)round_page(prev_image_size));
printf("Panic UI memory freed (%p)\n", (void *)round_page(prev_image_size));
}
}
break;
errout:
if ( newimage != (vm_offset_t )NULL )
(void)kmem_free(kernel_map, newimage, (vm_size_t)round_page(newlen));
break;
}
if (!error)
req->oldidx += req->oldlen;
return (error);
}
SYSCTL_PROC(_kern, KERN_PANICINFO, panicinfo, CTLTYPE_NODE|CTLFLAG_RW | CTLFLAG_LOCKED | CTLFLAG_ANYBODY,
0,
0,
sysctl_dopanicinfo,
NULL,
"");