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"
CFMachPortRef _gKextutilLock = NULL;
static CFRunLoopSourceRef _sKextloadLockRunLoopSource = NULL;
static void _gKextutilLock_died(CFMachPortRef port, void * info);
void kextd_process_kernel_requests(void);
static void removeKextloadLock(void)
{
if (_gKextutilLock) {
mach_port_t machPort;
CFMachPortSetInvalidationCallBack(_gKextutilLock, NULL);
machPort = CFMachPortGetPort(_gKextutilLock);
SAFE_RELEASE_NULL(_gKextutilLock);
mach_port_deallocate(mach_task_self(), machPort);
}
if (_sKextloadLockRunLoopSource) {
CFRunLoopSourceInvalidate(_sKextloadLockRunLoopSource);
SAFE_RELEASE_NULL(_sKextloadLockRunLoopSource);
}
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;
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 = CFMachPortCreateWithPort(kCFAllocatorDefault,
client, NULL,
NULL, false);
if (!_gKextutilLock) {
goto finish;
}
CFMachPortSetInvalidationCallBack(_gKextutilLock, _gKextutilLock_died);
_sKextloadLockRunLoopSource = CFMachPortCreateRunLoopSource(
kCFAllocatorDefault, _gKextutilLock, 0);
if (!_sKextloadLockRunLoopSource) {
goto finish;
}
CFRunLoopAddSource(CFRunLoopGetCurrent(), _sKextloadLockRunLoopSource,
kCFRunLoopDefaultMode);
mig_result = KERN_SUCCESS;
result = 0;
finish:
if (mig_result != KERN_SUCCESS) {
if (gClientUID == 0) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"Trouble while locking for kextload - %s.",
safe_mach_error_string(mig_result));
}
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) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"Non-root kextload doesn't need to lock/unlock.");
mig_result = KERN_SUCCESS;
goto finish;
}
if (client != CFMachPortGetPort(_gKextutilLock)) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"%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 _gKextutilLock_died(CFMachPortRef port, void * info)
{
if (port == _gKextutilLock) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogIPCFlag,
"Client exited without releasing kextload lock.");
removeKextloadLock();
}
return;
}