#include <IOKit/IOLib.h>
#include <IOKit/IOService.h>
#include <IOKit/smc/AppleSMCFamily.h>
#include "KextAudit.h"
#define super IOService
OSDefineMetaClassAndStructors(KextAudit, IOService);
void
KextAudit::free(void)
{
super::free();
}
bool
KextAudit::init(OSDictionary *dict)
{
return super::init(dict);
}
IOService *
KextAudit::probe(IOService *provider, SInt32 *score)
{
return super::probe(provider, score);
}
bool KextAudit::notifyBridgeWithReplySync(struct KextAuditLoadNotificationKext *kaln,
struct KextAuditBridgeResponse *kabr)
{
bool result = false;
uint8_t status;
SMCResult sr;
IOLockLock(_kalnLock);
status = (uint8_t)BootPolicyNotReady;
sr = fSMCDriver->smcWriteKey(SMCKEY_EFI_MULTIBOOT_STATUS, sizeof(status), &status);
if (sr != kSMCSuccess) {
DEBUG_LOG("FAILED to write EFI_MULTIBOOT_STATUS SMC key!");
goto error;
}
sr = fSMCDriver->smcWriteKey(SMCKEY_KEXT_AUDIT_IDENTITY, sizeof(*kaln), kaln);
if (sr != kSMCSuccess) {
DEBUG_LOG("FAILED to write KEXT_AUDIT_IDENTITY SMC key!");
goto error;
}
status = BOOT_STATE_KERNEL_AUDIT_LOAD;
sr = fSMCDriver->smcWriteKey(SMCKEY_EFI_BOOT_STATUS, sizeof(status), &status);
if (sr != kSMCSuccess) {
DEBUG_LOG("FAILED to write EFI_BOOT_STATUS SMC key!");
goto error;
}
do {
sr = fSMCDriver->smcReadKey(SMCKEY_EFI_MULTIBOOT_STATUS, sizeof(status), &status);
if (sr != kSMCSuccess) {
DEBUG_LOG("FAILED to poll EFI_MULTIBOOT_STATUS SMC key for load status!!");
goto error;
}
IOSleep(kKextAuditPollIntervalMs);
} while (status != BootPolicyOk);
kabr->status = kKALNStatusBridgeAck;
result = true;
error:
IOLockUnlock(_kalnLock);
return result;
}
bool
KextAudit::testBridgeConnection(struct KextAuditBridgeResponse *kabr)
{
bool result = false;
uint8_t status;
SMCResult sr;
IOLockLock(_kalnLock);
status = (uint8_t)BootPolicyNotReady;
sr = fSMCDriver->smcWriteKey(SMCKEY_EFI_MULTIBOOT_STATUS, sizeof(status), &status);
if (sr != kSMCSuccess) {
DEBUG_LOG("TEST: FAILED to write EFI_MULTIBOOT_STATUS SMC key!");
goto error;
}
status = BOOT_STATE_KEXT_AUDIT_TEST;
sr = fSMCDriver->smcWriteKey(SMCKEY_EFI_BOOT_STATUS, sizeof(status), &status);
if (sr != kSMCSuccess) {
DEBUG_LOG("TEST: FAILED to write EFI_BOOT_STATUS SMC key!");
goto error;
}
do {
sr = fSMCDriver->smcReadKey(SMCKEY_EFI_MULTIBOOT_STATUS, sizeof(status), &status);
if (sr != kSMCSuccess) {
DEBUG_LOG("TEST: FAILED to poll EFI_MULTIBOOT_STATUS SMC key for load status!!");
goto error;
}
IOSleep(kKextAuditPollIntervalMs);
} while (status != BootPolicyOk);
kabr->status = kKALNStatusBridgeAck;
result = true;
error:
IOLockUnlock(_kalnLock);
return result;
}
bool
KextAudit::start(IOService *provider)
{
DEBUG_LOG("start");
const OSSymbol *ucClassName;
bool result = true;
result = super::start(provider);
if (!result) {
DEBUG_LOG("Could not start provider");
goto error;
}
fSMCDriver = OSDynamicCast(AppleSMCFamily, provider);
if (!fSMCDriver) {
DEBUG_LOG("Provider is not AppleSMCFamily");
result = false;
goto error;
}
ucClassName = OSSymbol::withCStringNoCopy("KextAuditUserClient");
if (ucClassName) {
setProperty(gIOUserClientClassKey, (OSObject *)ucClassName);
ucClassName->release();
}
_kalnLock = IOLockAlloc();
if (!_kalnLock) {
DEBUG_LOG("Can't initialize _kalnLock!");
result = false;
goto error;
}
registerService();
error:
return result;
}
void
KextAudit::stop(IOService *provider)
{
IOLog("%s called!?", __FUNCTION__);
}
bool
KextAudit::terminate(IOOptionBits options)
{
IOLog("%s called!?", __FUNCTION__);
return false;
}