KextAuditUserClient.cpp [plain text]
#include <IOKit/IOLib.h>
#include <IOKit/IOUserClient.h>
#include "KextAuditUserClient.h"
#define super IOUserClient
OSDefineMetaClassAndStructors(KextAuditUserClient, IOUserClient);
KextAuditBridgeDeviceType
KextAuditUserClient::getBridgeDeviceType(void)
{
KextAuditBridgeDeviceType result = kKextAuditBridgeDeviceTypeNoCoprocessor;
OSObject *value = NULL;
OSData *num = NULL;
IORegistryEntry *defaults = IORegistryEntry::fromPath("IODeviceTree:/efi/platform");
if (!defaults) {
goto error;
}
value = defaults->getProperty("apple-coprocessor-version");
if (!value) {
goto error;
}
num = OSDynamicCast(OSData, value);
if (!num) {
goto error;
}
result = *(KextAuditBridgeDeviceType *)num->getBytesNoCopy(0, 4);
error:
OSSafeReleaseNULL(defaults);
return result;
}
IOReturn
KextAuditUserClient::externalMethod(uint32_t selector, IOExternalMethodArguments *args,
IOExternalMethodDispatch *dispatch, OSObject *target, void *reference)
{
IOReturn err = kIOReturnSuccess;
struct KextAuditLoadNotificationKext *kaln = (struct KextAuditLoadNotificationKext *)args->structureInput;
struct KextAuditBridgeResponse *kabr = (struct KextAuditBridgeResponse *)args->structureOutput;
if (!fUserClientHasEntitlement) {
DEBUG_LOG("User client does not have entitlement for KextAudit access");
err = kIOReturnNotPrivileged;
} else if (args->structureInputSize != kKALNStructSize) {
DEBUG_LOG("input structure is wrong size (was: %u expected: %d)",
args->structureInputSize, kKALNStructSize);
err = kIOReturnBadArgument;
} else if (args->structureOutputSize != sizeof(struct KextAuditBridgeResponse)) {
DEBUG_LOG("output structure is wrong size (was: %u expected: %lu)",
args->structureInputSize, sizeof(struct KextAuditBridgeResponse));
err = kIOReturnBadArgument;
}
if (err != kIOReturnSuccess) {
goto error;
}
if (fDeviceType < kKextAuditBridgeDeviceTypeT290) {
kabr->status = kKALNStatusNoBridge;
return kIOReturnSuccess;
}
switch (selector) {
case kKextAuditMethodNotifyLoad:
if (!VALID_KEXT_LOADTYPE(kaln->loadType)) {
err = kIOReturnBadArgument;
break;
}
if (!fProvider->notifyBridgeWithReplySync(kaln, kabr)) {
err = kIOReturnError;
break;
}
break;
#ifdef DEBUG
case kKextAuditMethodTest:
if (kaln->loadType > kKALTMax) {
err = kIOReturnBadArgument;
break;
} else if (kaln->loadType == kKALTMax) {
if (!fProvider->testBridgeConnection(kabr)) {
err = kIOReturnError;
}
break;
} else {
if (!fProvider->notifyBridgeWithReplySync(kaln, kabr)) {
err = kIOReturnError;
break;
}
}
break;
#endif
default:
DEBUG_LOG("Invalid selector");
err = kIOReturnBadArgument;
break;
}
error:
return err;
}
bool
KextAuditUserClient::initWithTask(task_t owningTask, void *securityID, UInt32 type, OSDictionary *properties)
{
OSObject *entitlement = NULL;
fUserClientHasEntitlement = false;
bool result = true;
if (!super::initWithTask(owningTask, securityID, type, properties)) {
DEBUG_LOG("Could not initialize IOUserClient with task");
result = false;
goto error;
}
if (IOUserClient::clientHasPrivilege(securityID, kIOClientPrivilegeAdministrator) != kIOReturnSuccess) {
DEBUG_LOG("User client does not have root privileges");
result = false;
goto error;
}
entitlement = IOUserClient::copyClientEntitlement(owningTask, kKextAuditUserAccessEntitlement);
if (!entitlement || entitlement != kOSBooleanTrue) {
DEBUG_LOG("User client does not have entitlement for access");
result = false;
goto error;
}
entitlement->release();
fUserClientHasEntitlement = true;
fTask = owningTask;
fDeviceType = getBridgeDeviceType();
error:
return result;
}
bool
KextAuditUserClient::start(IOService * provider)
{
bool result = true;
fProvider = OSDynamicCast(KextAudit, provider);
if (!fProvider) {
DEBUG_LOG("Could not find provider");
result = false;
goto error;
}
if (!super::start(provider)) {
DEBUG_LOG("Could not start provider");
fProvider = NULL;
result = false;
goto error;
}
error:
return result;
}
void
KextAuditUserClient::stop(IOService * provider)
{
super::stop(provider);
fProvider = NULL;
}
void
KextAuditUserClient::free(void)
{
if (fTask) {
fTask = NULL;
}
super::free();
}
IOReturn
KextAuditUserClient::clientClose(void)
{
terminate();
return kIOReturnSuccess;
}