serialize_kextload.c [plain text]
#include "globals.h"
#include "logging.h"
CFMachPortRef _kextload_lock = NULL;
static CFRunLoopSourceRef _sKextloadLockRunLoopSource = NULL;
static void _kextload_lock_died(CFMachPortRef port, void * info);
static void removeKextloadLock(void)
{
if (_kextload_lock) {
mach_port_t machPort;
CFMachPortSetInvalidationCallBack(_kextload_lock, NULL);
machPort = CFMachPortGetPort(_kextload_lock);
CFRelease(_kextload_lock);
_kextload_lock = NULL;
mach_port_deallocate(mach_task_self(), machPort);
}
if (_sKextloadLockRunLoopSource) {
CFRunLoopSourceInvalidate(_sKextloadLockRunLoopSource);
CFRelease(_sKextloadLockRunLoopSource);
_sKextloadLockRunLoopSource = NULL;
}
CFRunLoopSourceSignal(gKernelRequestRunLoopSource);
CFRunLoopWakeUp(gMainRunLoop);
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;
if (!lockstatus) {
kextd_error_log("kextmanager_lock_kextload requires non-NULL lockstatus");
mig_result = KERN_SUCCESS;
result = EINVAL;
goto finish;
}
if (gClientUID != 0) {
kextd_error_log("non-root kextload doesn't need to lock");
mig_result = KERN_SUCCESS;
result = EPERM;
goto finish;
}
if (_kextload_lock) {
mig_result = KERN_SUCCESS;
result = EBUSY;
goto finish;
}
result = ENOMEM;
_kextload_lock = CFMachPortCreateWithPort(kCFAllocatorDefault,
client, NULL,
NULL, false);
if (!_kextload_lock) {
goto finish;
}
CFMachPortSetInvalidationCallBack(_kextload_lock, _kextload_lock_died);
_sKextloadLockRunLoopSource = CFMachPortCreateRunLoopSource(
kCFAllocatorDefault, _kextload_lock, 0);
if (!_sKextloadLockRunLoopSource) {
goto finish;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), _sKextloadLockRunLoopSource,
kCFRunLoopDefaultMode);
mig_result = KERN_SUCCESS;
result = 0;
finish:
if (mig_result != KERN_SUCCESS) {
if (gClientUID == 0) {
kextd_error_log("trouble while locking for kextload");
}
removeKextloadLock();
} else {
*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) {
kextd_error_log("non-root kextload doesn't need to lock/unlock");
mig_result = KERN_SUCCESS;
goto finish;
}
if (client != CFMachPortGetPort(_kextload_lock)) {
kextd_error_log("%d not used to lock for kextload", client);
goto finish;
}
removeKextloadLock();
mig_result = KERN_SUCCESS;
finish:
mach_port_deallocate(mach_task_self(), client);
return mig_result;
}
static void _kextload_lock_died(CFMachPortRef port, void * info)
{
if (port == _kextload_lock) {
kextd_error_log("client exited without releasing kextload lock");
removeKextloadLock();
}
return;
}