kextd_serialize_kextload.c [plain text]
#include <mach/mach_port.h>
#include <IOKit/kext/OSKext.h>
#include "kext_tools_util.h"
#include "kextd_globals.h"
#include <dispatch/dispatch.h>
dispatch_source_t _gKextutilLock = NULL;
void kextd_process_kernel_requests(void);
static void removeKextutilLock(void)
{
if (_gKextutilLock) {
dispatch_source_cancel(_gKextutilLock);
}
if (gKernelRequestsPending) {
kextd_process_kernel_requests();
}
CFRunLoopWakeUp(CFRunLoopGetCurrent());
return;
}
kern_return_t _kextmanager_lock_kextload(
mach_port_t server,
mach_port_t client,
int * lockstatus)
{
kern_return_t mig_result = KERN_FAILURE;
int result = ELAST + 1;
if (!lockstatus) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"kextmanager_lock_kextload requires non-NULL lockstatus.");
mig_result = KERN_SUCCESS;
result = EINVAL;
goto finish;
}
if (gClientUID != 0) {
OSKextLog( NULL,
kOSKextLogErrorLevel,
"Non-root process doesn't need to lock as it will fail to load.");
mig_result = KERN_SUCCESS;
result = EPERM;
goto finish;
}
if (_gKextutilLock) {
mig_result = KERN_SUCCESS;
result = EBUSY;
goto finish;
}
result = ENOMEM;
_gKextutilLock = dispatch_source_create(DISPATCH_SOURCE_TYPE_MACH_SEND, client,
DISPATCH_MACH_SEND_DEAD, dispatch_get_main_queue());
if (_gKextutilLock) {
dispatch_source_set_event_handler(_gKextutilLock, ^{
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"Client exited without releasing kextutil lock.");
removeKextutilLock();
});
dispatch_source_set_cancel_handler(_gKextutilLock, ^{
dispatch_release(_gKextutilLock);
mach_port_deallocate(mach_task_self(), client);
_gKextutilLock = NULL;
});
dispatch_resume(_gKextutilLock);
mig_result = KERN_SUCCESS;
result = 0;
}
finish:
if (mig_result == KERN_SUCCESS && result != 0) {
mach_port_deallocate(mach_task_self(), client);
}
if (mig_result != KERN_SUCCESS) {
if (gClientUID == 0) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"Trouble while locking for kextutil - %s.",
safe_mach_error_string(mig_result));
}
removeKextutilLock();
} else if (lockstatus) {
*lockstatus = result; }
return mig_result;
}
kern_return_t _kextmanager_unlock_kextload(
mach_port_t server,
mach_port_t client)
{
kern_return_t mig_result = KERN_FAILURE;
if (gClientUID != 0) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"Non-root kextutil doesn't need to lock/unlock.");
mig_result = KERN_SUCCESS;
goto finish;
}
if (client != (mach_port_t)dispatch_source_get_handle(_gKextutilLock)) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"%d not used to lock for kextutil.", client);
goto finish;
}
removeKextutilLock();
mig_result = KERN_SUCCESS;
finish:
if (mig_result == KERN_SUCCESS) {
mach_port_deallocate(mach_task_self(), client);
}
return mig_result;
}