#include <asl.h>
#include <IOKit/kext/OSKext.h>
#include <IOKit/kext/OSKextPrivate.h>
#include <IOKit/IOKitLib.h>
#include <Security/Security.h>
#include "security.h"
#include "kext_tools_util.h"
static OSStatus checkRootCertificateIsApple(OSKextRef aKext);
static CFStringRef copyCDHash(SecStaticCodeRef code);
static CFStringRef copyIssuerCN(SecCertificateRef certificate);
static void copySigningInfo(CFURLRef kextURL,
CFStringRef* cdhash,
CFStringRef* teamId,
CFStringRef* subjectCN,
CFStringRef* issuerCN);
static CFArrayRef copySubjectCNArray(CFURLRef kextURL);
static CFStringRef copyTeamID(SecCertificateRef certificate);
static CFStringRef createArchitectureList(OSKextRef aKext, CFBooleanRef *isFat);
static void createHashForMT(CFURLRef kextURL, char ** signatureBuffer);
static void filterKextLoadForMT(OSKextRef aKext, CFMutableArrayRef *kextList);
void messageTraceExcludedKext(OSKextRef theKext)
{
CFStringRef versionString;
CFStringRef bundleIDString;
CFURLRef kextURL = NULL; CFStringRef filename = NULL; aslmsg amsg = NULL; char *versionCString = NULL; char *bundleIDCString = NULL; char *filenameCString = NULL;
kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(theKext));
if (!kextURL) {
OSKextLogMemError();
goto finish;
}
versionString = OSKextGetValueForInfoDictionaryKey(theKext,
kCFBundleVersionKey);
if (versionString) {
versionCString = createUTF8CStringForCFString(versionString);
}
bundleIDString = OSKextGetValueForInfoDictionaryKey(theKext,
kCFBundleIdentifierKey);
if (bundleIDString) {
bundleIDCString = createUTF8CStringForCFString(bundleIDString);
}
filename = CFURLCopyLastPathComponent(kextURL);
if (filename) {
filenameCString = createUTF8CStringForCFString(filename);
}
SAFE_RELEASE(filename);
amsg = asl_new(ASL_TYPE_MSG);
if (!amsg) {
OSKextLogMemError();
goto finish;
}
asl_set(amsg, kMessageTracerDomainKey, kMTKextBlockedDomain);
asl_set(amsg, kMessageTracerBundleIDKey,
bundleIDCString ? bundleIDCString : "");
asl_set(amsg, kMessageTracerVersionKey,
versionCString ? versionCString : "");
asl_set(amsg, kMessageTracerKextNameKey,
filenameCString ? filenameCString : "");
asl_log(NULL, amsg, ASL_LEVEL_NOTICE, "");
finish:
SAFE_FREE(versionCString);
SAFE_FREE(bundleIDCString);
SAFE_FREE(filenameCString);
SAFE_RELEASE(kextURL);
if (amsg) {
asl_free(amsg);
}
return;
}
static OSStatus checkRootCertificateIsApple(OSKextRef aKext)
{
OSStatus result = -1;
CFURLRef kextURL = NULL; SecStaticCodeRef staticCodeRef = NULL; SecRequirementRef requirementRef = NULL; CFStringRef myCFString;
CFStringRef requirementsString;
if (aKext == NULL) {
return result;
}
kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext));
if (!kextURL) {
OSKextLogMemError();
goto finish;
}
if (SecStaticCodeCreateWithPath(kextURL,
kSecCSDefaultFlags,
&staticCodeRef) != errSecSuccess ||
(staticCodeRef == NULL)) {
OSKextLogMemError();
goto finish;
}
myCFString = OSKextGetIdentifier(aKext);
if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) {
requirementsString = CFSTR("anchor apple");
}
else {
requirementsString = CFSTR("anchor apple generic");
}
if (SecRequirementCreateWithString(requirementsString,
kSecCSDefaultFlags,
&requirementRef) != errSecSuccess ||
(requirementRef == NULL)) {
OSKextLogMemError();
goto finish;
}
result = SecStaticCodeCheckValidity(staticCodeRef,
kSecCSDefaultFlags,
requirementRef);
if (result != 0) {
OSKextLogCFString(NULL,
kOSKextLogErrorLevel | kOSKextLogLoadFlag,
CFSTR("Invalid signature %ld for kext %@"),
(long)result, aKext);
}
finish:
SAFE_RELEASE(kextURL);
SAFE_RELEASE(staticCodeRef);
SAFE_RELEASE(requirementRef);
return result;
}
static void createHashForMT(CFURLRef kextURL, char ** signatureBuffer)
{
CFMutableDictionaryRef signdict = NULL; SecCodeSignerRef signerRef = NULL; SecStaticCodeRef staticCodeRef = NULL; CFDataRef signature = NULL; CFDictionaryRef signingDict = NULL; CFDataRef cdhash = NULL; CFMutableDictionaryRef resourceRules = NULL; CFMutableDictionaryRef rules = NULL; CFMutableDictionaryRef omitPlugins = NULL; char * tempBufPtr = NULL;
if (!kextURL || !signatureBuffer) {
return;
}
if (SecStaticCodeCreateWithPath(kextURL,
kSecCSDefaultFlags,
&staticCodeRef) != 0 ||
(staticCodeRef == NULL)) {
OSKextLogMemError();
goto finish;
}
signature = CFDataCreateMutable(NULL, 0);
if (signature == NULL) {
OSKextLogMemError();
goto finish;
}
signdict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (signdict == NULL) {
OSKextLogMemError();
goto finish;
}
CFDictionarySetValue(signdict, kSecCodeSignerIdentity, kCFNull);
CFDictionarySetValue(signdict, kSecCodeSignerDetached, signature);
resourceRules = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (resourceRules == NULL) {
OSKextLogMemError();
goto finish;
}
rules = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (rules == NULL) {
OSKextLogMemError();
goto finish;
}
omitPlugins = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (omitPlugins == NULL) {
OSKextLogMemError();
goto finish;
}
CFNumberRef myNumValue;
int myNum = 100;
myNumValue = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &myNum);
if (myNumValue == NULL) {
OSKextLogMemError();
goto finish;
}
CFDictionarySetValue(omitPlugins, CFSTR("omit"), kCFBooleanTrue);
CFDictionarySetValue(omitPlugins, CFSTR("weight"), myNumValue);
CFRelease( myNumValue );
CFDictionarySetValue(rules, CFSTR("^.*"), kCFBooleanTrue);
CFDictionarySetValue(rules, CFSTR("^PlugIns/"), omitPlugins);
CFDictionarySetValue(resourceRules, CFSTR("rules"), rules);
CFDictionarySetValue(signdict, kSecCodeSignerResourceRules, resourceRules);
if (SecCodeSignerCreate(signdict, kSecCSDefaultFlags, &signerRef) != 0) {
OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
"%s - SecCodeSignerCreate failed", __func__);
goto finish;
}
if (SecCodeSignerAddSignature(signerRef, staticCodeRef, kSecCSDefaultFlags) != 0) {
OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
"%s - SecCodeSignerAddSignature failed", __func__);
goto finish;
}
if (SecCodeSetDetachedSignature(staticCodeRef, signature, kSecCSDefaultFlags) != 0) {
OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
"%s - SecCodeSetDetachedSignature failed", __func__);
goto finish;
}
if (SecCodeCopySigningInformation(staticCodeRef, kSecCSDefaultFlags, &signingDict) != 0) {
OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
"%s - SecCodeCopySigningInformation failed", __func__);
goto finish;
}
cdhash = CFRetain(CFDictionaryGetValue(signingDict, kSecCodeInfoUnique));
if (cdhash) {
const UInt8 * hashDataPtr = NULL; CFIndex hashDataLen = 0;
hashDataPtr = CFDataGetBytePtr(cdhash);
hashDataLen = CFDataGetLength(cdhash);
tempBufPtr = (char *) malloc((hashDataLen + 1) * 2);
if (tempBufPtr == NULL) {
OSKextLogMemError();
goto finish;
}
#if 0
OSKextLogCFString( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
CFSTR("%s - cdhash %@"),
__func__,
cdhash);
#endif
bzero(tempBufPtr, ((hashDataLen + 1) * 2));
for (int i = 0; i < hashDataLen; i++) {
sprintf(tempBufPtr + (i * 2), "%02.2x", *(hashDataPtr + i));
}
}
finish:
SAFE_RELEASE(signdict);
SAFE_RELEASE(signerRef);
SAFE_RELEASE(staticCodeRef);
SAFE_RELEASE(signature);
SAFE_RELEASE(signingDict);
SAFE_RELEASE(cdhash);
SAFE_RELEASE(resourceRules);
SAFE_RELEASE(rules);
SAFE_RELEASE(omitPlugins);
*signatureBuffer = tempBufPtr;
}
static CFStringRef createArchitectureList(OSKextRef aKext, CFBooleanRef *isFat)
{
if (aKext == NULL || isFat == NULL) {
return NULL;
}
*isFat = kCFBooleanFalse;
const NXArchInfo ** archList = NULL; CFMutableArrayRef archNamesList = NULL; CFStringRef archNames = NULL; const char * archNameCString = NULL; int index = 0;
archList = OSKextCopyArchitectures(aKext);
if (!archList) {
goto finish;
}
archNamesList = CFArrayCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks);
if (!archNamesList) {
goto finish;
}
for (index=0; archList[index]; index++) {
archNameCString = archList[index]->name;
if (archNameCString) {
CFStringRef archName = NULL;
archName = CFStringCreateWithCString(kCFAllocatorDefault,
archNameCString,
kCFStringEncodingUTF8);
if (archName) {
CFArrayAppendValue(archNamesList, archName);
SAFE_RELEASE_NULL(archName);
}
}
}
if (index>1) {
*isFat = kCFBooleanTrue;
}
archNames = CFStringCreateByCombiningStrings(kCFAllocatorDefault,
archNamesList,
CFSTR(" "));
if (!archNames) {
goto finish;
}
finish:
SAFE_RELEASE(archNamesList);
SAFE_FREE(archList);
return archNames;
}
static CFStringRef copyTeamID(SecCertificateRef certificate)
{
if (!certificate ||
CFGetTypeID(certificate) !=SecCertificateGetTypeID()) {
return NULL;
}
CFDictionaryRef subjectDict = NULL; CFArrayRef subjectArray = NULL; CFDictionaryRef subjectInfo = NULL; CFStringRef teamID = NULL; CFErrorRef error = NULL;
CFMutableArrayRef certificateKeys = NULL; CFDictionaryRef certificateDict = NULL;
certificateKeys = CFArrayCreateMutable(kCFAllocatorDefault,
1,
&kCFTypeArrayCallBacks);
if (!certificateKeys) {
goto finish;
}
CFArrayAppendValue(certificateKeys, kSecOIDX509V1SubjectName);
certificateDict = SecCertificateCopyValues(certificate,
certificateKeys,
&error);
if (error != errSecSuccess ||
!certificateDict ||
CFGetTypeID(certificateDict) != CFDictionaryGetTypeID()) {
goto finish;
}
subjectDict = (CFDictionaryRef) CFDictionaryGetValue(certificateDict,
kSecOIDX509V1SubjectName);
if (!subjectDict ||
CFGetTypeID(subjectDict) != CFDictionaryGetTypeID()) {
goto finish;
}
subjectArray = (CFArrayRef) CFDictionaryGetValue(subjectDict,
kSecPropertyKeyValue);
if (!subjectArray ||
CFGetTypeID(subjectArray) != CFArrayGetTypeID()) {
goto finish;
}
for (int index=0; index<CFArrayGetCount(subjectArray); index++) {
subjectInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(subjectArray,
index);
if (!subjectInfo ||
CFGetTypeID(subjectInfo) != CFDictionaryGetTypeID()) {
continue;
}
CFStringRef label = NULL; label = CFDictionaryGetValue(subjectInfo,
kSecPropertyKeyLabel);
if (kCFCompareEqualTo == CFStringCompare(label,
CFSTR("0.9.2342.19200300.100.1.1"),
0)) {
teamID = CFDictionaryGetValue(subjectInfo,
kSecPropertyKeyValue);
if (teamID &&
CFGetTypeID(teamID) == CFStringGetTypeID()) {
CFRetain(teamID);
goto finish;
}
else {
teamID = NULL;
}
}
}
if (!teamID) {
for (int index=0; index<CFArrayGetCount(subjectArray); index++) {
subjectInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(subjectArray,
index);
if (!subjectInfo ||
CFGetTypeID(subjectInfo) != CFDictionaryGetTypeID()) {
continue;
}
CFStringRef label = NULL; label = CFDictionaryGetValue(subjectInfo,
kSecPropertyKeyLabel);
if (kCFCompareEqualTo == CFStringCompare(label,
CFSTR("2.5.4.11"),
0)) {
teamID = CFDictionaryGetValue(subjectInfo,
kSecPropertyKeyValue);
if (teamID &&
CFGetTypeID(teamID) == CFStringGetTypeID()) {
CFRetain(teamID);
goto finish;
}
else {
teamID = NULL;
}
}
}
}
finish:
if (!teamID && subjectArray) {
CFShow(subjectArray);
}
SAFE_RELEASE(certificateKeys);
SAFE_RELEASE(certificateDict);
return teamID;
}
static CFStringRef copyIssuerCN(SecCertificateRef certificate)
{
if (!certificate ||
CFGetTypeID(certificate) !=SecCertificateGetTypeID()) {
return NULL;
}
CFStringRef issuerCN = NULL; CFDictionaryRef issuerDict = NULL; CFArrayRef issuerArray = NULL; CFDictionaryRef issuerInfo = NULL; CFErrorRef error = NULL;
CFMutableArrayRef certificateKeys = NULL; CFDictionaryRef certificateDict = NULL;
certificateKeys = CFArrayCreateMutable(kCFAllocatorDefault,
1,
&kCFTypeArrayCallBacks);
if (!certificateKeys) {
goto finish;
}
CFArrayAppendValue(certificateKeys, kSecOIDX509V1IssuerName);
certificateDict = SecCertificateCopyValues(certificate,
certificateKeys,
&error);
if (error != errSecSuccess ||
!certificateDict ||
CFGetTypeID(certificateDict) != CFDictionaryGetTypeID()) {
goto finish;
}
issuerDict = (CFDictionaryRef) CFDictionaryGetValue(certificateDict,
kSecOIDX509V1IssuerName);
if (!issuerDict ||
CFGetTypeID(issuerDict) != CFDictionaryGetTypeID()) {
goto finish;
}
issuerArray = (CFArrayRef) CFDictionaryGetValue(issuerDict,
kSecPropertyKeyValue);
if (!issuerArray ||
CFGetTypeID(issuerArray) != CFArrayGetTypeID()) {
goto finish;
}
for (int index=0; index<CFArrayGetCount(issuerArray); index++) {
issuerInfo = (CFDictionaryRef) CFArrayGetValueAtIndex(issuerArray,
index);
if (!issuerInfo ||
CFGetTypeID(issuerInfo) != CFDictionaryGetTypeID()) {
continue;
}
CFStringRef label = NULL; label = CFDictionaryGetValue(issuerInfo,
kSecPropertyKeyLabel);
if (kCFCompareEqualTo == CFStringCompare(label,
CFSTR("2.5.4.3"),
0)) {
issuerCN = CFDictionaryGetValue(issuerInfo,
kSecPropertyKeyValue);
if (issuerCN &&
CFGetTypeID(issuerCN) == CFStringGetTypeID()) {
CFRetain(issuerCN);
goto finish;
}
else {
issuerCN = NULL;
}
}
}
finish:
SAFE_RELEASE(certificateDict);
SAFE_RELEASE(certificateKeys);
return issuerCN;
}
static CFStringRef copyCDHash(SecStaticCodeRef code)
{
CFDictionaryRef signingInfo = NULL; char * tempBufPtr = NULL; const UInt8 * hashDataPtr = NULL; CFDataRef cdhash = NULL; CFStringRef hash = NULL; CFIndex hashDataLen = 0;
SecCodeCopySigningInformation(code,
kSecCSDefaultFlags,
&signingInfo);
if (!signingInfo) {
goto finish;
}
cdhash = CFDictionaryGetValue(signingInfo, kSecCodeInfoUnique);
if (!cdhash ||
CFGetTypeID(cdhash) != CFDataGetTypeID()) {
goto finish;
}
hashDataPtr = CFDataGetBytePtr(cdhash);
hashDataLen = CFDataGetLength(cdhash);
tempBufPtr = (char *) malloc((hashDataLen + 1) * 2);
if (tempBufPtr == NULL) {
OSKextLogMemError();
goto finish;
}
bzero(tempBufPtr, ((hashDataLen + 1) * 2));
for (int i = 0; i < hashDataLen; i++) {
sprintf(tempBufPtr + (i * 2), "%02.2x", *(hashDataPtr + i));
}
if (tempBufPtr) {
hash = CFStringCreateWithCString(kCFAllocatorDefault,
tempBufPtr,
kCFStringEncodingUTF8);
}
finish:
SAFE_FREE(tempBufPtr);
SAFE_RELEASE(signingInfo);
return hash;
}
static void copySigningInfo(CFURLRef kextURL,
CFStringRef* cdhash,
CFStringRef* teamId,
CFStringRef* subjectCN,
CFStringRef* issuerCN)
{
if (!kextURL) {
return;
}
SecStaticCodeRef code = NULL; CFDictionaryRef information = NULL;
SecCertificateRef issuerCertificate = NULL; CFArrayRef certificateChain = NULL; OSStatus status;
CFIndex count;
if (SecStaticCodeCreateWithPath(kextURL,
kSecCSDefaultFlags,
&code) != 0
|| (code == NULL)) {
OSKextLogMemError();
goto finish;
}
if (cdhash) {
*cdhash = copyCDHash(code);
}
status = SecCodeCopySigningInformation(code,
kSecCSSigningInformation,
&information);
if (status != noErr) {
goto finish;
}
certificateChain = (CFArrayRef) CFDictionaryGetValue(information, kSecCodeInfoCertificates);
if (!certificateChain ||
CFGetTypeID(certificateChain) != CFArrayGetTypeID()) {
goto finish;
}
count = CFArrayGetCount(certificateChain);
if (count < 1) {
goto finish;
}
issuerCertificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificateChain, 0);
if (!issuerCertificate) {
goto finish;
}
if (subjectCN) {
SecCertificateCopyCommonName(issuerCertificate, subjectCN);
}
if (teamId) {
*teamId = copyTeamID(issuerCertificate);
}
if (issuerCN) {
*issuerCN = copyIssuerCN(issuerCertificate);
}
finish:
SAFE_RELEASE(code);
SAFE_RELEASE(information);
return;
}
static CFArrayRef copySubjectCNArray(CFURLRef kextURL)
{
if (!kextURL) {
return NULL;
}
CFMutableArrayRef subjectCNArray = NULL; CFArrayRef certificateChain = NULL; SecCertificateRef certificate = NULL;
SecStaticCodeRef code = NULL; CFDictionaryRef information = NULL;
OSStatus status;
CFIndex count;
subjectCNArray = CFArrayCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeArrayCallBacks);
if (!subjectCNArray) {
goto finish;
}
if (SecStaticCodeCreateWithPath(kextURL,
kSecCSDefaultFlags,
&code) != 0
|| (code == NULL)) {
OSKextLogMemError();
goto finish;
}
status = SecCodeCopySigningInformation(code,
kSecCSSigningInformation,
&information);
if (status != noErr) {
goto finish;
}
certificateChain = (CFArrayRef) CFDictionaryGetValue(information, kSecCodeInfoCertificates);
if (!certificateChain ||
CFGetTypeID(certificateChain) != CFArrayGetTypeID()) {
goto finish;
}
count = CFArrayGetCount(certificateChain);
if (count < 1) {
goto finish;
}
for (CFIndex i=0; i<count; i++) {
certificate = (SecCertificateRef) CFArrayGetValueAtIndex(certificateChain, i);
CFStringRef subjectCN = NULL; SecCertificateCopyCommonName(certificate, &subjectCN);
if (subjectCN) {
CFArrayAppendValue(subjectCNArray, subjectCN);
SAFE_RELEASE(subjectCN);
}
}
finish:
SAFE_RELEASE(code);
SAFE_RELEASE(information);
return subjectCNArray;
}
static void filterKextLoadForMT(OSKextRef aKext, CFMutableArrayRef *kextList)
{
if (aKext == NULL || kextList == NULL)
return;
CFStringRef versionString; CFStringRef bundleIDString; CFStringRef kextSigningCategory = NULL; CFBooleanRef isFat = kCFBooleanFalse; CFBooleanRef isSigned = kCFBooleanFalse;
CFURLRef kextURL = NULL; CFStringRef kextPath = NULL; CFStringRef filename = NULL; CFStringRef hashString = NULL; CFStringRef archString = NULL; CFStringRef teamId = NULL; CFStringRef subjectCN = NULL; CFStringRef issuerCN = NULL;
SecStaticCodeRef code = NULL; CFDictionaryRef information = NULL; CFMutableDictionaryRef kextDict = NULL;
char * hashCString = NULL;
OSStatus status = noErr;
if (isDebugSetInBootargs()) {
return;
}
kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext));
if (!kextURL) {
OSKextLogMemError();
goto finish;
}
kextPath = CFURLCopyFileSystemPath(kextURL, kCFURLPOSIXPathStyle);
if (!kextPath) {
OSKextLogMemError();
goto finish;
}
versionString = OSKextGetValueForInfoDictionaryKey(aKext,
kCFBundleVersionKey);
bundleIDString = OSKextGetValueForInfoDictionaryKey(aKext,
kCFBundleIdentifierKey);
filename = CFURLCopyLastPathComponent(kextURL);
archString = createArchitectureList(aKext, &isFat);
if (SecStaticCodeCreateWithPath(kextURL,
kSecCSDefaultFlags,
&code) != 0
|| (code == NULL)) {
OSKextLogMemError();
goto finish;
}
status = SecCodeCopySigningInformation(code,
kSecCSSigningInformation,
&information);
if (status != noErr) {
goto finish;
}
isSigned = CFDictionaryContainsKey(information, kSecCodeInfoIdentifier);
if (!isSigned) {
kextSigningCategory = CFSTR(kUnsignedKext);
createHashForMT(kextURL, &hashCString);
if (hashCString) {
hashString = CFStringCreateWithCString(kCFAllocatorDefault,
hashCString,
kCFStringEncodingUTF8);
}
}
else {
CFStringRef myCFString = NULL; myCFString = OSKextGetIdentifier(aKext);
status = checkKextSignature(aKext, true);
if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) {
if (status == noErr) {
kextSigningCategory = CFSTR(kAppleKextWithAppleRoot);
copySigningInfo(kextURL,
&hashString,
NULL,
NULL,
NULL);
}
else {
kextSigningCategory = CFSTR(kUnsignedKext);
copySigningInfo(kextURL,
&hashString,
&teamId,
NULL,
&issuerCN);
CFArrayRef subjectCNArray = NULL; subjectCNArray = copySubjectCNArray(kextURL);
if (subjectCNArray) {
subjectCN = CFStringCreateByCombiningStrings(kCFAllocatorDefault,
subjectCNArray,
CFSTR(";"));
SAFE_RELEASE(subjectCNArray);
}
}
}
else {
if (status == noErr) {
kextSigningCategory = CFSTR(k3rdPartyKextWithDevIdPlus);
copySigningInfo(kextURL,
&hashString,
&teamId,
&subjectCN,
&issuerCN);
}
else if (status == CSSMERR_TP_CERT_REVOKED) {
kextSigningCategory = CFSTR(k3rdPartyKextWithRevokedDevIdPlus);
copySigningInfo(kextURL,
&hashString,
&teamId,
&subjectCN,
&issuerCN);
}
else {
status = checkRootCertificateIsApple(aKext);
if (status == noErr) {
kextSigningCategory = CFSTR(k3rdPartyKextWithAppleRoot);
copySigningInfo(kextURL,
&hashString,
&teamId,
NULL,
&issuerCN);
CFArrayRef subjectCNArray = NULL; subjectCNArray = copySubjectCNArray(kextURL);
if (subjectCNArray) {
subjectCN = CFStringCreateByCombiningStrings(kCFAllocatorDefault,
subjectCNArray,
CFSTR(";"));
SAFE_RELEASE(subjectCNArray);
}
}
else {
kextSigningCategory = CFSTR(k3rdPartyKextWithoutAppleRoot);
copySigningInfo(kextURL,
&hashString,
NULL,
NULL,
NULL);
}
}
}
}
kextDict = CFDictionaryCreateMutable(kCFAllocatorDefault,
0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!kextDict) {
OSKextLogMemError();
goto finish;
}
if (bundleIDString) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerBundleIDKey),
bundleIDString);
}
if (versionString) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerVersionKey),
versionString);
}
if (filename) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerKextNameKey),
filename);
}
if (isFat != NULL) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerFatKey),
isFat);
}
if (archString) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerArchKey),
archString);
}
if (kextSigningCategory) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerSignatureTypeKey),
kextSigningCategory);
}
if (hashString) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerHashKey),
hashString);
}
if (teamId) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerTeamIdKey),
teamId);
}
if (subjectCN) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerSubjectCNKey),
subjectCN);
}
if (issuerCN) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerIssuerCNKey),
issuerCN);
}
if (kextPath) {
CFDictionaryAddValue(kextDict,
CFSTR(kMessageTracerPathKey),
kextPath);
}
CFArrayAppendValue(*kextList, kextDict);
finish:
SAFE_FREE(hashCString);
SAFE_RELEASE(kextURL);
SAFE_RELEASE(kextPath);
SAFE_RELEASE(filename);
SAFE_RELEASE(hashString);
SAFE_RELEASE(kextDict);
SAFE_RELEASE(archString);
SAFE_RELEASE(teamId);
SAFE_RELEASE(subjectCN);
SAFE_RELEASE(issuerCN);
SAFE_RELEASE(code);
SAFE_RELEASE(information);
return;
}
void
recordKextLoadListForMT(CFArrayRef kextList)
{
CFIndex count, i;
CFMutableArrayRef kextsToMessageTrace = NULL; OSKextRef aKext;
if (kextList && (count = CFArrayGetCount(kextList))) {
kextsToMessageTrace = CFArrayCreateMutable(kCFAllocatorDefault,
CFArrayGetCount(kextList),
&kCFTypeArrayCallBacks);
if (kextsToMessageTrace) {
for (i = 0; i < count; i ++) {
aKext = (OSKextRef)CFArrayGetValueAtIndex(kextList, i);
filterKextLoadForMT(aKext, &kextsToMessageTrace);
}
if (CFArrayGetCount(kextsToMessageTrace)) {
postNoteAboutKextLoadsMT(CFSTR("Loaded Kext Notification"),
kextsToMessageTrace);
}
SAFE_RELEASE(kextsToMessageTrace);
}
}
}
void recordKextLoadForMT(OSKextRef aKext)
{
CFMutableArrayRef myArray = NULL;
if (!aKext)
return;
myArray = CFArrayCreateMutable(kCFAllocatorDefault,
1,
&kCFTypeArrayCallBacks);
if (myArray) {
CFArrayAppendValue(myArray, aKext);
recordKextLoadListForMT(myArray);
SAFE_RELEASE(myArray);
}
}
OSStatus checkKextSignature(OSKextRef aKext, Boolean checkExceptionList)
{
OSStatus result = -1;
CFURLRef kextURL = NULL; SecStaticCodeRef staticCodeRef = NULL; SecRequirementRef requirementRef = NULL; CFStringRef myCFString;
CFStringRef requirementsString;
if (aKext == NULL) {
return result;
}
kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(aKext));
if (!kextURL) {
OSKextLogMemError();
goto finish;
}
if (SecStaticCodeCreateWithPath(kextURL,
kSecCSDefaultFlags,
&staticCodeRef) != errSecSuccess ||
(staticCodeRef == NULL)) {
OSKextLogMemError();
goto finish;
}
myCFString = OSKextGetIdentifier(aKext);
if (CFStringHasPrefix(myCFString, __kOSKextApplePrefix)) {
requirementsString = CFSTR("anchor apple");
}
else {
requirementsString =
CFSTR("anchor apple generic "
"and certificate 1[field.1.2.840.113635.100.6.2.6] "
"and certificate leaf[field.1.2.840.113635.100.6.1.13] "
"and certificate leaf[field.1.2.840.113635.100.6.1.18]" );
}
if (SecRequirementCreateWithString(requirementsString,
kSecCSDefaultFlags,
&requirementRef) != errSecSuccess ||
(requirementRef == NULL)) {
OSKextLogMemError();
goto finish;
}
result = SecStaticCodeCheckValidity(staticCodeRef,
kSecCSEnforceRevocationChecks,
requirementRef);
if ( result != 0 &&
checkExceptionList &&
isInExceptionList(aKext, true) ) {
result = 0;
}
finish:
SAFE_RELEASE(kextURL);
SAFE_RELEASE(staticCodeRef);
SAFE_RELEASE(requirementRef);
return result;
}
#define GET_CSTRING_PTR(the_cfstring, the_ptr, the_buffer, the_size) \
do { \
the_ptr = CFStringGetCStringPtr(the_cfstring, kCFStringEncodingUTF8); \
if (the_ptr == NULL) { \
the_buffer[0] = 0x00; \
the_ptr = the_buffer; \
CFStringGetCString(the_cfstring, the_buffer, the_size, kCFStringEncodingUTF8); \
} \
} while(0)
Boolean isInExceptionList(OSKextRef theKext, Boolean useCache)
{
Boolean result = false;
CFStringRef kextID = NULL; OSKextRef excludelistKext = NULL; CFDictionaryRef exceptionlistDict = NULL; static CFDictionaryRef myDictionary = NULL;
if (useCache == false || myDictionary == NULL) {
if (myDictionary != NULL) {
SAFE_RELEASE_NULL(myDictionary);
}
kextID = CFStringCreateWithCString(kCFAllocatorDefault,
"com.apple.driver.KextExcludeList",
kCFStringEncodingUTF8);
if (!kextID) {
OSKextLogStringError( NULL);
goto finish;
}
excludelistKext = OSKextCreateWithIdentifier(kCFAllocatorDefault,
kextID);
if (!excludelistKext) {
OSKextLog( NULL,
kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
"Warning: %s could not find com.apple.driver.KextExcludeList",
__FUNCTION__);
goto finish;
}
exceptionlistDict = OSKextGetValueForInfoDictionaryKey(
excludelistKext,
CFSTR("OSKextSigExceptionList"));
if (!exceptionlistDict) {
goto finish;
}
if ((unsigned int)CFDictionaryGetCount(exceptionlistDict) > 0) {
myDictionary = CFDictionaryCreateCopy(NULL, exceptionlistDict);
}
if (myDictionary == NULL) {
OSKextLogMemError();
goto finish;
}
}
if (theKext == NULL) {
goto finish;
}
CFStringRef bundleID = NULL; CFStringRef exceptionKextVersString = NULL; OSKextVersion kextVers = -1;
const char * versCString = NULL; OSKextVersion exceptionKextVers;
char versBuffer[256];
bundleID = OSKextGetIdentifier(theKext);
if (!bundleID) {
OSKextLog( NULL,
kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
"%s could not get bundleID",
__FUNCTION__);
goto finish;
}
kextVers = OSKextGetVersion(theKext);
if (!kextVers) {
OSKextLog( NULL,
kOSKextLogDebugLevel | kOSKextLogGeneralFlag,
"%s could not get kextVers",
__FUNCTION__);
goto finish;
}
exceptionKextVersString = CFDictionaryGetValue(myDictionary, bundleID);
if (!exceptionKextVersString) {
goto finish;
}
GET_CSTRING_PTR(exceptionKextVersString,
versCString,
versBuffer,
sizeof(versBuffer));
if (strlen(versCString) < 1) {
goto finish;
}
exceptionKextVers = OSKextParseVersionString(versCString);
if (kextVers <= exceptionKextVers) {
OSKextLogCFString(NULL,
kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
CFSTR("kext %@ %lld is in exception list, allowing to load"),
bundleID, kextVers);
result = true;
}
finish:
SAFE_RELEASE(kextID);
SAFE_RELEASE(excludelistKext);
return result;
}
Boolean isDebugSetInBootargs(void)
{
static int didOnce = 0;
static Boolean result = false;
io_registry_entry_t optionsNode = MACH_PORT_NULL; CFStringRef bootargsEntry = NULL;
if (didOnce) {
return(result);
}
optionsNode = IORegistryEntryFromPath(kIOMasterPortDefault,
"IODeviceTree:/options");
if (optionsNode) {
bootargsEntry = (CFStringRef)
IORegistryEntryCreateCFProperty(optionsNode,
CFSTR("boot-args"),
kCFAllocatorDefault, 0);
if (bootargsEntry &&
(CFGetTypeID(bootargsEntry) == CFStringGetTypeID())) {
CFRange findRange;
findRange = CFStringFind(bootargsEntry, CFSTR("debug"), 0);
if (findRange.length != 0) {
result = true;
}
}
}
didOnce++;
if (optionsNode) IOObjectRelease(optionsNode);
SAFE_RELEASE(bootargsEntry);
return(result);
}
Boolean isInLibraryExtensionsFolder(OSKextRef theKext)
{
CFStringRef myKextPath = NULL; Boolean myResult = false;
myKextPath = copyKextPath(theKext);
if ( myKextPath ) {
if ( CFStringHasPrefix(myKextPath,
CFSTR(_kOSKextLibraryExtensionsFolder)) ) {
myResult = true;
}
}
SAFE_RELEASE(myKextPath);
return(myResult);
}