#include <asl.h>
#include <IOKit/kext/OSKext.h>
#include <IOKit/kext/OSKextPrivate.h>
#include <IOKit/IOKitLib.h>
#include <Security/Security.h>
#include <sys/sysctl.h>
#include <servers/bootstrap.h>
#include <IOKit/kext/kextmanager_types.h>
#include "security.h"
#include "kext_tools_util.h"
#define USE_OLD_EXCEPTION_LIST 1
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 getAdhocSignatureHash(CFURLRef kextURL, char ** signatureBuffer);
static void filterKextLoadForMT(OSKextRef aKext, CFMutableArrayRef *kextList);
static Boolean hashIsInExceptionList(CFURLRef theKextURL, CFDictionaryRef theDict);
#if USE_OLD_EXCEPTION_LIST
static Boolean bundleIdIsInExceptionList(OSKextRef theKext, CFDictionaryRef theDict);
#endif
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 getAdhocSignatureHash(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 rules2 = NULL; CFMutableDictionaryRef omitPlugins = NULL; CFMutableDictionaryRef frameworksDict = NULL; CFMutableDictionaryRef topDict = NULL; char * tempBufPtr = NULL; CFNumberRef myNumValue = NULL; CFNumberRef myRealValue = NULL;
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;
}
rules2 = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (rules2 == NULL) {
OSKextLogMemError();
goto finish;
}
omitPlugins = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (omitPlugins == NULL) {
OSKextLogMemError();
goto finish;
}
frameworksDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (frameworksDict == NULL) {
OSKextLogMemError();
goto finish;
}
topDict = CFDictionaryCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (topDict == NULL) {
OSKextLogMemError();
goto finish;
}
int myNum = 100;
myNumValue = CFNumberCreate(kCFAllocatorDefault,
kCFNumberIntType, &myNum);
if (myNumValue == NULL) {
OSKextLogMemError();
goto finish;
}
CFDictionarySetValue(omitPlugins, CFSTR("omit"), kCFBooleanTrue);
CFDictionarySetValue(omitPlugins, CFSTR("weight"), myNumValue);
CFDictionarySetValue(rules, CFSTR("^.*"), kCFBooleanTrue);
CFDictionarySetValue(rules, CFSTR("^PlugIns/"), omitPlugins);
CFDictionarySetValue(resourceRules, CFSTR("rules"), rules);
float myRealNum = 0.0;
myRealValue = CFNumberCreate(kCFAllocatorDefault,
kCFNumberFloatType, &myRealNum);
if (myRealValue == NULL) {
OSKextLogMemError();
goto finish;
}
CFDictionarySetValue(frameworksDict, CFSTR("nested"), kCFBooleanTrue);
CFDictionarySetValue(frameworksDict, CFSTR("weight"), myRealValue);
CFDictionarySetValue(rules2,
CFSTR("^(Frameworks|SharedFrameworks|Plugins|Plug-ins|XPCServices|Helpers|MacOS)/"),
frameworksDict);
CFDictionarySetValue(rules2, CFSTR("^.*"), kCFBooleanTrue);
CFDictionarySetValue(rules2, CFSTR("^PlugIns/"), omitPlugins);
CFDictionarySetValue(topDict, CFSTR("top"), kCFBooleanTrue);
CFDictionarySetValue(topDict, CFSTR("weight"), myRealValue);
CFDictionarySetValue(rules2,
CFSTR("^[^/]+$"),
topDict);
CFDictionarySetValue(resourceRules, CFSTR("rules2"), rules2);
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 - kextURL %@"),
__func__,
kextURL);
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(rules2);
SAFE_RELEASE(omitPlugins);
SAFE_RELEASE(frameworksDict);
SAFE_RELEASE(topDict);
SAFE_RELEASE(myNumValue);
SAFE_RELEASE(myRealValue);
*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);
getAdhocSignatureHash(kextURL, &hashCString);
if (hashCString) {
hashString = CFStringCreateWithCString(kCFAllocatorDefault,
hashCString,
kCFStringEncodingUTF8);
}
}
else {
CFStringRef myCFString = NULL; myCFString = OSKextGetIdentifier(aKext);
status = checkKextSignature(aKext, true, false);
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,
Boolean earlyBoot)
{
OSStatus result = errSecCSSignatureFailed;
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;
}
if (earlyBoot) {
result = SecStaticCodeCheckValidity(staticCodeRef,
kSecCSNoNetworkAccess,
requirementRef);
}
else {
result = SecStaticCodeCheckValidity(staticCodeRef,
kSecCSEnforceRevocationChecks,
requirementRef);
}
if ( result != 0 &&
checkExceptionList &&
isInExceptionList(aKext, kextURL, 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,
CFURLRef theKextURL,
Boolean useCache)
{
Boolean result = false;
CFURLRef kextURL = NULL; CFStringRef kextID = NULL; OSKextRef excludelistKext = NULL; CFDictionaryRef tempDict = NULL; #if USE_OLD_EXCEPTION_LIST
static CFDictionaryRef sExceptionListDict = NULL; #endif
static CFDictionaryRef sExceptionHashListDict = NULL;
if (useCache == false || sExceptionHashListDict == NULL) {
if (sExceptionHashListDict) {
SAFE_RELEASE_NULL(sExceptionHashListDict);
}
kextID = CFStringCreateWithCString(kCFAllocatorDefault,
"com.apple.driver.KextExcludeList",
kCFStringEncodingUTF8);
if (kextID == NULL) {
OSKextLogStringError( NULL);
goto finish;
}
excludelistKext = OSKextCreateWithIdentifier(kCFAllocatorDefault,
kextID);
if (excludelistKext == NULL) {
goto finish;
}
if (isDevMode() == false) {
if (checkKextSignature(excludelistKext, false, false) != 0) {
char kextPath[PATH_MAX];
if (!CFURLGetFileSystemRepresentation(OSKextGetURL(excludelistKext),
false,
(UInt8 *)kextPath,
sizeof(kextPath))) {
strlcpy(kextPath, "(unknown)", sizeof(kextPath));
}
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogArchiveFlag |
kOSKextLogAuthenticationFlag | kOSKextLogGeneralFlag,
"%s has invalid signature; Trust cache is disabled.",
kextPath);
goto finish;
}
}
tempDict = OSKextGetValueForInfoDictionaryKey(
excludelistKext,
CFSTR("OSKextSigExceptionHashList") );
if (tempDict) {
if ((unsigned int)CFDictionaryGetCount(tempDict) > 0) {
sExceptionHashListDict = CFDictionaryCreateCopy(NULL, tempDict);
if (sExceptionHashListDict == NULL) {
OSKextLogMemError();
}
}
}
}
#if USE_OLD_EXCEPTION_LIST
if (useCache == false || sExceptionListDict == NULL) {
if (sExceptionListDict) {
SAFE_RELEASE_NULL(sExceptionListDict);
}
if (kextID == NULL) {
kextID = CFStringCreateWithCString(kCFAllocatorDefault,
"com.apple.driver.KextExcludeList",
kCFStringEncodingUTF8);
if (kextID == NULL) {
OSKextLogStringError( NULL);
goto finish;
}
}
if (excludelistKext == NULL) {
excludelistKext = OSKextCreateWithIdentifier(kCFAllocatorDefault,
kextID);
if (excludelistKext == NULL) {
goto finish;
}
}
if (isDevMode() == false) {
if (checkKextSignature(excludelistKext, false, false) != 0) {
char kextPath[PATH_MAX];
if (!CFURLGetFileSystemRepresentation(OSKextGetURL(excludelistKext),
false,
(UInt8 *)kextPath,
sizeof(kextPath))) {
strlcpy(kextPath, "(unknown)", sizeof(kextPath));
}
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogArchiveFlag |
kOSKextLogAuthenticationFlag | kOSKextLogGeneralFlag,
"%s has invalid signature; Trust cache is disabled.",
kextPath);
goto finish;
}
}
tempDict = OSKextGetValueForInfoDictionaryKey(
excludelistKext,
CFSTR("OSKextSigExceptionList"));
if (tempDict) {
if ((unsigned int)CFDictionaryGetCount(tempDict) > 0) {
sExceptionListDict = CFDictionaryCreateCopy(NULL, tempDict);
if (sExceptionListDict == NULL) {
OSKextLogMemError();
}
}
}
}
#endif
if (theKext == NULL) {
goto finish;
}
if (sExceptionHashListDict) {
if (theKextURL == NULL) {
kextURL = CFURLCopyAbsoluteURL(OSKextGetURL(theKext));
if (kextURL == NULL) {
OSKextLogMemError();
goto finish;
}
theKextURL = kextURL;
}
if (hashIsInExceptionList(theKextURL, sExceptionHashListDict)) {
result = true;
goto finish;
}
}
#if USE_OLD_EXCEPTION_LIST
if (sExceptionListDict) {
if (bundleIdIsInExceptionList(theKext, sExceptionListDict)) {
result = true;
goto finish;
}
}
#endif
finish:
SAFE_RELEASE(kextURL);
SAFE_RELEASE(kextID);
SAFE_RELEASE(excludelistKext);
return result;
}
#if USE_OLD_EXCEPTION_LIST
static Boolean bundleIdIsInExceptionList(OSKextRef theKext,
CFDictionaryRef theDict)
{
Boolean result = false;
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(theDict, 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:
return result;
}
#endif
static Boolean hashIsInExceptionList(CFURLRef theKextURL,
CFDictionaryRef theDict)
{
Boolean result = false;
char * hashCString = NULL; CFStringRef hashString = NULL; CFStringRef kextInfoString = NULL;
if (theKextURL == NULL) {
goto finish;
}
getAdhocSignatureHash(theKextURL, &hashCString);
if (hashCString == NULL) {
goto finish;
}
hashString = CFStringCreateWithCString(kCFAllocatorDefault,
hashCString,
kCFStringEncodingUTF8);
if (hashString == NULL) {
OSKextLogMemError();
goto finish;
}
kextInfoString = CFDictionaryGetValue(theDict, hashString);
if (kextInfoString == NULL ||
CFGetTypeID(kextInfoString) != CFStringGetTypeID()) {
goto finish;
}
OSKextLogCFString(NULL,
kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
CFSTR("kext %@ is in hash exception list, allowing to load"),
theKextURL);
result = true;
finish:
SAFE_RELEASE(hashString);
SAFE_FREE(hashCString);
return result;
}
#define KEXT_DEV_MODE_STRING "kext-dev-mode="
Boolean isDevMode(void)
{
Boolean result = false;
uint64_t kext_dev_mode;
size_t bufsize;
char bootargs_buffer[1024], *dev_mode_ptr;
bufsize = sizeof(bootargs_buffer);
if (sysctlbyname("kern.bootargs", bootargs_buffer, &bufsize, NULL, 0) < 0) {
return(false);
}
dev_mode_ptr = strnstr(bootargs_buffer,
KEXT_DEV_MODE_STRING,
sizeof(bootargs_buffer));
if (dev_mode_ptr &&
(dev_mode_ptr == &bootargs_buffer[0] || *(dev_mode_ptr - 1) == ' ')) {
kext_dev_mode = strtoul(dev_mode_ptr + strlen(KEXT_DEV_MODE_STRING),
NULL, 10);
if (kext_dev_mode == 1) {
result = true;
}
}
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);
}
Boolean isInSystemLibraryExtensionsFolder(OSKextRef theKext)
{
CFStringRef myKextPath = NULL; Boolean myResult = false;
myKextPath = copyKextPath(theKext);
if ( myKextPath ) {
if ( CFStringHasPrefix(myKextPath,
CFSTR(_kOSKextSystemLibraryExtensionsFolder)) ) {
myResult = true;
}
}
SAFE_RELEASE(myKextPath);
return(myResult);
}
Boolean isInvalidSignatureAllowed(void)
{
Boolean result = false;
if (isDevMode()) {
result = true;
}
return(result);
}
#include <Security/SecKeychainPriv.h>
int callSecKeychainMDSInstall( void )
{
static int calledOnce = 0;
static int result = 0;
if (calledOnce) return(result);
calledOnce++;
if (isKextdRunning() == FALSE) {
OSStatus err;
err = SecKeychainMDSInstall();
if (err != errSecSuccess) {
OSKextLog( NULL,
kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
"Error in security framework, error %d.", (int) err);
result = err;
}
}
return(result);
}
Boolean isKextdRunning(void)
{
mach_port_t kextd_port = MACH_PORT_NULL;
kern_return_t kern_result = 0;
kern_result = bootstrap_look_up(bootstrap_port,
(char *)KEXTD_SERVER_NAME,
&kextd_port);
if (kern_result == kOSReturnSuccess && kextd_port != MACH_PORT_NULL) {
return( TRUE );
}
return( FALSE );
}