static int allocate_user_kernel_buffer(size_t size, void **buf) { int err = 0; // The user space daemon is requesting a new circular queue. // Make sure the requested size is within sane size bounds. if (size > MAX_KMEM || size < MIN_KMEM) { err = -EINVAL; goto error_exit; } // Record the requested buffer size. osquery.buf_size = size; // Allocate a contiguous region of memory. osquery.buffer = IOMallocAligned(osquery.buf_size, PAGE_SIZE); // Cannot proceed if no memory to back the circular queue is available. if (osquery.buffer == NULL) { err = -EINVAL; goto error_exit; } // Zero memory for safety, this memory will be shared with user space. bzero(osquery.buffer, osquery.buf_size); // This buffer will be shared, create a descriptor. osquery.md = IOMemoryDescriptor::withAddressRange((mach_vm_address_t)osquery.buffer, osquery.buf_size, kIODirectionInOut, kernel_task); if (osquery.md == NULL) { err = -EINVAL; goto error_exit; } // Now map the buffer into the user space process as read only. osquery.mm = osquery.md->createMappingInTask( current_task(), NULL, kIOMapAnywhere | kIOMapReadOnly); if (osquery.mm == NULL) { err = -EINVAL; goto error_exit; } // The virtual address will be shared back to the user space queue manager. *buf = (void *)osquery.mm->getAddress(); // Initialize the kernel space queue manager with the new buffer. osquery_cqueue_init(&osquery.cqueue, osquery.buffer, osquery.buf_size); return 0; error_exit: // A drop-through error handler will clean up any intermediate allocations. cleanup_user_kernel_buffer(); return err; }
static int allocate_user_kernel_buffer(size_t size, void **buf) { int err = 0; if (size > MAX_KMEM || size < MIN_KMEM) { err = -EINVAL; goto error_exit; } osquery.buf_size = size; osquery.buffer = IOMallocAligned(osquery.buf_size, PAGE_SIZE); if (osquery.buffer == NULL) { err = -EINVAL; goto error_exit; } bzero(osquery.buffer, osquery.buf_size); // Zero memory for safety. osquery.md = IOMemoryDescriptor::withAddressRange((mach_vm_address_t)osquery.buffer, osquery.buf_size, kIODirectionInOut, kernel_task); if (osquery.md == NULL) { err = -EINVAL; goto error_exit; } osquery.mm = osquery.md->createMappingInTask(current_task(), NULL, kIOMapAnywhere | kIOMapReadOnly); if (osquery.mm == NULL) { err = -EINVAL; goto error_exit; } *buf = (void *)osquery.mm->getAddress(); osquery_cqueue_init(&osquery.cqueue, osquery.buffer, osquery.buf_size); return 0; error_exit: cleanup_user_kernel_buffer(); return err; }