#define _KEXT_KEYS
#include <libc.h>
#include <fts.h>
#include <CoreFoundation/CFRuntime.h>
#include <CoreFoundation/CFBundlePriv.h>
#include <mach/mach.h>
#include <mach/mach_port.h>
#include <mach/kmod.h>
#include <mach-o/kld.h>
#include <mach-o/fat.h>
#include <nlist.h>
#include <errno.h>
#include <pthread.h>
#include "KXKext.h"
#include "KXKext_private.h"
#include "paths.h"
#include "vers_rsrc.h"
#include "printPList.h"
CFStringRef kKXKextErrorKeyFileAccess = NULL;
CFStringRef kKXKextErrorKeyBundleNotInRepository = NULL;
CFStringRef kKXKextErrorKeyNotABundle = NULL;
CFStringRef kKXKextErrorKeyNotAKextBundle = NULL;
CFStringRef kKXKextErrorKeyBadPropertyList = NULL;
CFStringRef kKXKextErrorKeyMissingProperty = NULL;
CFStringRef kKXKextErrorKeyPropertyIsIllegalType = NULL;
CFStringRef kKXKextErrorKeyPropertyIsIllegalValue = NULL;
CFStringRef kKXKextErrorKeyIdentifierOrVersionTooLong = NULL;
CFStringRef kKXKextErrorKeyPersonalitiesNotNested = NULL;
CFStringRef kKXKextErrorKeyMissingExecutable = NULL;
CFStringRef kKXKextErrorKeyCompatibleVersionLaterThanVersion = NULL;
CFStringRef kKXKextErrorKeyExecutableBad = NULL;
CFStringRef kKXKextErrorKeyBundleIdentifierMismatch = NULL;
CFStringRef kKXKextErrorKeyBundleVersionMismatch = NULL;
CFStringRef kKXKextErrorKeyExecutableBadArch = NULL;
CFStringRef kKXKextErrorKeyStatFailure = NULL;
CFStringRef kKXKextErrorKeyFileNotFound = NULL;
CFStringRef kKXKextErrorKeyOwnerPermission = NULL;
CFStringRef kKXKextErrorKeyChecksum = NULL;
CFStringRef kKXKextErrorKeySignature = NULL;
CFStringRef kKXKextErrorKeyDependenciesUnresolvable = NULL;
CFStringRef kKXKextErrorKeyPossibleDependencyLoop = NULL;
CFStringRef kKXKextDependencyUnavailable = NULL;
CFStringRef kKXKextDependencyNoCompatibleVersion = NULL;
CFStringRef kKXKextDependencyCompatibleVersionUndeclared = NULL;
CFStringRef kKXKextIndirectDependencyUnresolvable = NULL;
CFStringRef kKXKextDependencyCircularReference = NULL;
typedef struct __KXKext {
CFRuntimeBase cfBase;
SInt32 logLevel;
KXKextManagerRef manager;
KXKextRepositoryRef repository;
CFDictionaryRef infoDictionary;
CFMutableArrayRef plugins;
KXKextRef container;
CFStringRef bundlePathInRepository;
CFStringRef bundleDirectoryName;
CFBundleRef bundle; CFURLRef bundleURL;
struct {
unsigned int declaresExecutable:1;
unsigned int isKernelResource:1;
unsigned int isValid:1; unsigned int isEligibleDuringSafeBoot:1;
unsigned int isEnabled:1;
unsigned int canAuthenticate:1;
unsigned int hasBeenAuthenticated:1;
unsigned int isAuthentic:1;
unsigned int canResolveDependencies:1;
unsigned int hasAllDependencies:1;
unsigned int isLoaded:1;
unsigned int otherVersionIsLoaded:1;
unsigned int loadFailed:1;
unsigned int hasIOKitDebugProperty:1;
unsigned int reserved:2;
} flags;
UInt32 version;
UInt32 compatibleVersion;
KXKextRef priorVersion; KXKextRef nextDuplicate;
CFMutableArrayRef directDependencies;
CFMutableDictionaryRef validationFailures;
CFMutableDictionaryRef authenticationFailures;
CFMutableDictionaryRef missingDependencies;
} __KXKext, * __KXKextRef;
static void __KXKextInitialize(void);
static CFStringRef __KXKextCopyDebugDescription(CFTypeRef cf);
static KXKextRef __KXKextCreatePrivate(
CFAllocatorRef allocator,
CFAllocatorContext * context);
static void __KXKextResetTestFlags(KXKextRef aKext);
static void __KXKextInitBlank(KXKextRef aKext);
static void __KXKextReleaseContents(CFTypeRef cf);
static Boolean __KXKextCheckLogLevel(
KXKextRef aKext,
SInt32 managerLogLevel,
SInt32 kextLogLevel,
Boolean exact);
static KXKextManagerError __KXKextValidate(KXKextRef aKext);
static KXKextManagerError __KXKextValidateExecutable(KXKextRef aKext,
Boolean requiresNewKextManager);
static CFMutableDictionaryRef __KXKextGetOrCreateValidationFailures(KXKextRef aKext);
static CFMutableDictionaryRef __KXKextGetOrCreateAuthenticationFailures(
KXKextRef aKext);
static CFMutableArrayRef __KXKextGetMissingProperties(KXKextRef aKext);
static CFMutableArrayRef __KXKextGetIllegalTypeProperties(KXKextRef aKext);
static CFMutableArrayRef __KXKextGetIllegalValueProperties(KXKextRef aKext);
static CFMutableArrayRef __KXKextGetMissingFiles(KXKextRef aKext);
static CFMutableArrayRef __KXKextGetBadOwnerPermsFiles(KXKextRef aKext);
static Boolean __KXKextCheckPropertyType(
KXKextRef aKext,
CFDictionaryRef aDictionary,
CFStringRef propKey,
CFArrayRef propPathArray,
Boolean isRequired,
CFTypeID expectedType,
CFTypeRef * rawValueOut);
static Boolean __KXKextCheckStringProperty(
KXKextRef aKext,
CFDictionaryRef aDictionary,
CFStringRef propKey,
CFArrayRef propPathArray,
Boolean isRequired,
CFStringRef expectedValue,
CFStringRef *stringValueOut);
static Boolean __KXKextCheckVersionProperty(
KXKextRef aKext,
CFDictionaryRef aDictionary,
CFStringRef propKey,
CFArrayRef propPathArray,
Boolean isRequired,
UInt32 *versionOut);
static Boolean __KXKextCheckPersonalityTypes(KXKextRef aKext,
CFTypeRef cfObj, CFMutableArrayRef propPathArray);
static KXKextManagerError __KXKextAuthenticateURLAndParents(KXKextRef aKext,
CFURLRef anURL,
CFURLRef topURL ,
CFMutableDictionaryRef checkedURLs);
static KXKextManagerError __KXKextAuthenticateURL(KXKextRef aKext,
CFURLRef anURL);
static KXKextManagerError __KXKextMakeFTSEntrySecure(KXKextRef aKext,
FTSENT * ftsentry);
static KXKextManagerError __KXKextCheckKmod(KXKextRef aKext,
CFURLRef kmodURL,
Boolean requiresNewKextManager);
static KXKextManagerError __KXKextResolveDependencies(KXKextRef aKext,
unsigned int recursionDepth);
static char * __KXKextCopyDgraphEntryName(KXKextRef aKext);
static char * __KXKextCopyDgraphKmodName(KXKextRef aKext);
static Boolean __KXKextAddDependenciesToDgraph(KXKextRef aKext,
CFArrayRef dependencies,
dgraph_t * dgraph);
static void __KXKextAddDependenciesToArray(KXKextRef aKext,
CFMutableArrayRef dependencyArray);
KXKextManagerError __KXKextRealizeFromCache(KXKextRef aKext);
CFDictionaryRef __KXKextCopyInfoDictionaryFromCache(
KXKextRef aKext,
CFDictionaryRef cDict,
Boolean makeSubstitutions);
CFDictionaryRef __KXKextCopyInfoDictionaryForCache(
KXKextRef aKext,
CFDictionaryRef infoDict,
Boolean makeSubstitutions);
CFTypeRef __KXKextCopyPListForCache(
KXKextRef aKext,
CFTypeRef pList,
Boolean * error);
static CFTypeID __kKXKextTypeID = _kCFRuntimeNotATypeID;
CFTypeID KXKextGetTypeID(void) {
return __kKXKextTypeID;
}
CFBundleRef KXKextGetBundle(KXKextRef aKext)
{
if (__KXKextRealizeFromCache(aKext) != kKXKextManagerErrorNone) {
return NULL;
}
return aKext->bundle;
}
CFDictionaryRef KXKextGetInfoDictionary(KXKextRef aKext)
{
return aKext->infoDictionary;
}
KXKextRef KXKextGetPriorVersionKext(KXKextRef aKext)
{
return aKext->priorVersion;
}
KXKextRef KXKextGetDuplicateVersionKext(KXKextRef aKext)
{
return aKext->nextDuplicate;
}
KXKextRepositoryRef KXKextGetRepository(KXKextRef aKext)
{
return aKext->repository;
}
KXKextManagerRef KXKextGetManager(KXKextRef aKext)
{
return KXKextRepositoryGetManager(aKext->repository);
}
CFStringRef KXKextGetBundlePathInRepository(KXKextRef aKext)
{
return aKext->bundlePathInRepository;
}
CFStringRef KXKextGetBundleDirectoryName(KXKextRef aKext)
{
return aKext->bundleDirectoryName;
}
CFStringRef KXKextCopyAbsolutePath(KXKextRef aKext)
{
CFStringRef absPath = NULL;
CFStringRef repositoryPath = NULL;
repositoryPath = KXKextRepositoryGetPath(aKext->repository);
if (!repositoryPath) {
goto finish;
}
absPath = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("%@/%@"), repositoryPath, aKext->bundlePathInRepository);
finish:
return absPath;
}
CFURLRef KXKextGetAbsoluteURL(KXKextRef aKext)
{
return aKext->bundleURL;
}
Boolean KXKextGetIsKernelResource(KXKextRef aKext)
{
return aKext->flags.isKernelResource ? true : false;
}
Boolean KXKextGetDeclaresExecutable(KXKextRef aKext)
{
return aKext->flags.declaresExecutable ? true : false;
}
Boolean KXKextIsAPlugin(KXKextRef aKext)
{
return (aKext->container != NULL);
}
KXKextRef KXKextGetContainerForPluginKext(KXKextRef aKext)
{
return aKext->container;
}
CFArrayRef KXKextGetPlugins(KXKextRef aKext)
{
return (CFArrayRef)aKext->plugins;
}
Boolean KXKextIsValid(KXKextRef aKext)
{
return aKext->flags.isValid ? true : false;
}
CFMutableDictionaryRef KXKextGetValidationFailures(KXKextRef aKext)
{
return aKext->validationFailures;
}
Boolean KXKextHasDebugProperties(KXKextRef aKext)
{
return (aKext->flags.hasIOKitDebugProperty || (aKext->logLevel > 0)) ?
true : false;
}
Boolean KXKextIsEligibleDuringSafeBoot(KXKextRef aKext)
{
return aKext->flags.isEligibleDuringSafeBoot ? true : false;
}
Boolean KXKextIsEnabled(KXKextRef aKext)
{
return aKext->flags.isEnabled ? true : false;
}
CFStringRef KXKextGetBundleIdentifier(KXKextRef aKext)
{
if (!aKext->infoDictionary) return NULL;
return (CFStringRef)CFDictionaryGetValue(aKext->infoDictionary,
CFSTR("CFBundleIdentifier"));
}
CFDictionaryRef KXKextGetBundleLibraryVersions(KXKextRef aKext)
{
if (!aKext->infoDictionary) {
return NULL;
}
return CFDictionaryGetValue(aKext->infoDictionary, CFSTR("OSBundleLibraries"));
}
Boolean KXKextIsCompatibleWithVersionNumber(
KXKextRef aKext,
UInt32 version)
{
if (!aKext->flags.isValid) {
return false;
}
if (aKext->compatibleVersion == 0) {
return false;
}
if (aKext->compatibleVersion <= version && version <= aKext->version) {
return true;
}
return false;
}
Boolean KXKextIsCompatibleWithVersionString(
KXKextRef aKext,
CFStringRef aVersionString)
{
char vers_buffer[32]; UInt32 version;
if (!aKext->flags.isValid) {
return false;
}
if (aKext->compatibleVersion == 0) {
return false;
}
if (!CFStringGetCString(aVersionString,
vers_buffer, sizeof(vers_buffer) - 1, kCFStringEncodingMacRoman)) {
return false;
} else {
vers_buffer[sizeof(vers_buffer) - 1] = '\0';
if (!VERS_parse_string(vers_buffer, &version)) {
return false;
}
}
if (aKext->compatibleVersion <= version && version <= aKext->version) {
return true;
}
return false;
}
Boolean KXKextHasPersonalities(KXKextRef aKext)
{
CFDictionaryRef pDict = NULL;
pDict = (CFDictionaryRef)CFDictionaryGetValue(aKext->infoDictionary,
CFSTR("IOKitPersonalities"));
if (!pDict) {
return false;
} else if (CFDictionaryGetCount(pDict) == 0) {
return false;
}
return true;
}
CFDictionaryRef KXKextCopyPersonalities(KXKextRef aKext)
{
Boolean error = false;
CFDictionaryRef pDict = NULL; CFMutableDictionaryRef newPDict = NULL; CFIndex count, i;
CFStringRef * keys = NULL; CFStringRef * values = NULL;
pDict = (CFDictionaryRef)CFDictionaryGetValue(aKext->infoDictionary,
CFSTR("IOKitPersonalities"));
if (!pDict) {
goto finish;
}
newPDict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!newPDict) {
error = true;
goto finish;
}
count = CFDictionaryGetCount(pDict);
keys = (CFStringRef *)malloc(count * sizeof(CFStringRef));
values = (CFStringRef *)malloc(count * sizeof(CFTypeRef));
CFDictionaryGetKeysAndValues(pDict, (const void **)keys,
(const void **)values);
for (i = 0; i < count; i++) {
CFDictionaryRef thisPersonality = (CFDictionaryRef)values[i];
if (CFDictionaryGetValue(thisPersonality, CFSTR("CFBundleIdentifier"))) {
CFDictionarySetValue(newPDict, keys[i], thisPersonality);
} else {
CFMutableDictionaryRef personalityCopy = NULL; personalityCopy = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
CFDictionaryGetCount(thisPersonality)+5, thisPersonality);
if (!personalityCopy) {
error = true;
goto finish;
}
CFDictionarySetValue(personalityCopy, CFSTR("CFBundleIdentifier"),
KXKextGetBundleIdentifier(aKext));
CFDictionarySetValue(newPDict, keys[i], personalityCopy);
CFRelease(personalityCopy);
}
}
finish:
if (error) {
if (newPDict) CFRelease(newPDict);
newPDict = NULL;
}
if (keys) free(keys);
if (values) free(values);
return newPDict;
}
CFArrayRef KXKextCopyPersonalitiesArray(KXKextRef aKext)
{
Boolean error = false;
CFDictionaryRef pDict = NULL; CFMutableArrayRef newPArray = NULL; CFIndex count, i;
CFStringRef * values = NULL;
pDict = (CFDictionaryRef)CFDictionaryGetValue(aKext->infoDictionary,
CFSTR("IOKitPersonalities"));
if (!pDict) {
goto finish;
}
newPArray = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!newPArray) {
error = true;
goto finish;
}
count = CFDictionaryGetCount(pDict);
values = (CFStringRef *)malloc(count * sizeof(CFTypeRef));
CFDictionaryGetKeysAndValues(pDict, NULL, (const void **)values);
for (i = 0; i < count; i++) {
CFDictionaryRef thisPersonality = (CFDictionaryRef)values[i];
if (CFDictionaryGetValue(thisPersonality, CFSTR("CFBundleIdentifier"))) {
CFArrayAppendValue(newPArray, thisPersonality);
} else {
CFMutableDictionaryRef personalityCopy = NULL; personalityCopy = CFDictionaryCreateMutableCopy(kCFAllocatorDefault,
CFDictionaryGetCount(thisPersonality)+5, thisPersonality);
if (!personalityCopy) {
error = true;
goto finish;
}
CFDictionarySetValue(personalityCopy, CFSTR("CFBundleIdentifier"),
KXKextGetBundleIdentifier(aKext));
CFArrayAppendValue(newPArray, personalityCopy);
CFRelease(personalityCopy);
}
}
finish:
if (error) {
if (newPArray) CFRelease(newPArray);
newPArray = NULL;
}
if (values) free(values);
return newPArray;
}
Boolean KXKextHasBeenAuthenticated(KXKextRef aKext)
{
return aKext->flags.hasBeenAuthenticated ? true : false;
}
KXKextManagerError KXKextAuthenticate(KXKextRef aKext)
{
KXKextManagerError result = kKXKextManagerErrorNone;
KXKextManagerError checkResult = kKXKextManagerErrorNone;
CFMutableDictionaryRef checkedURLs = NULL; CFStringRef bundlePath = NULL; CFURLRef infoDictURL = NULL; CFURLRef backscanURL = NULL; CFURLRef executableURL = NULL;
aKext->flags.isAuthentic = 0;
checkedURLs = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!checkedURLs) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
checkResult = __KXKextRealizeFromCache(aKext);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
goto finish;
}
if (!aKext->flags.canAuthenticate) {
result = kKXKextManagerErrorAuthentication;
goto finish;
}
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKexts,
kKXKextLogLevelBasic, false)) {
const char * kext_name = _KXKextCopyCanonicalPathnameAsCString(aKext);
if (kext_name) {
(_KMLog(aKext->manager))("authenticating extension %s",
kext_name);
free((char *)kext_name);
}
}
if (!__KXKextGetOrCreateAuthenticationFailures(aKext)) {
if (!aKext->authenticationFailures) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
}
CFDictionaryRemoveAllValues(aKext->authenticationFailures);
if (!aKext->bundleURL) {
result = kKXKextManagerErrorInvalidArgument;
goto finish;
}
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
const char * bundle_path =
PATH_CanonicalizedCStringForURL(aKext->bundleURL);
if (bundle_path) {
(_KMLog(aKext->manager))("authenticating bundle directory %s",
bundle_path);
free((char *)bundle_path);
}
}
checkResult = __KXKextAuthenticateURL(aKext, aKext->bundleURL);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
if (result == kKXKextManagerErrorNoMemory ||
!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
CFDictionarySetValue(checkedURLs, aKext->bundleURL, kCFBooleanTrue);
if (!KXKextManagerPerformsStrictAuthentication(aKext->manager)) {
aKext->flags.isAuthentic = 1;
goto finish;
}
infoDictURL = _CFBundleCopyInfoPlistURL(aKext->bundle);
if (!infoDictURL) {
result = kKXKextManagerErrorUnspecified;
goto finish;
}
checkResult = __KXKextAuthenticateURLAndParents(aKext, infoDictURL,
aKext->bundleURL, checkedURLs);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
if (result == kKXKextManagerErrorNoMemory ||
!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
if (aKext->flags.declaresExecutable) {
executableURL = CFBundleCopyExecutableURL(aKext->bundle);
if (!executableURL) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyMissingExecutable,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
} else {
checkResult = __KXKextAuthenticateURLAndParents(aKext, executableURL,
aKext->bundleURL, checkedURLs);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
if (result == kKXKextManagerErrorNoMemory ||
!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
}
}
if (result == kKXKextManagerErrorNone) {
aKext->flags.isAuthentic = 1;
}
finish:
aKext->flags.hasBeenAuthenticated = 1;
if (checkedURLs) CFRelease(checkedURLs);
if (bundlePath) CFRelease(bundlePath);
if (infoDictURL) CFRelease(infoDictURL);
if (backscanURL) CFRelease(backscanURL);
if (executableURL) CFRelease(executableURL);
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKexts,
kKXKextLogLevelBasic, false)) {
const char * kext_name = _KXKextCopyCanonicalPathnameAsCString(aKext);
if (kext_name) {
(_KMLog(aKext->manager))("extension %s is%s authentic",
kext_name, aKext->flags.isAuthentic ? "" : " not");
free((char *)kext_name);
}
}
return result;
}
KXKextManagerError KXKextMarkAuthentic(KXKextRef aKext)
{
KXKextManagerError result = kKXKextManagerErrorNone;
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKexts, kKXKextLogLevelBasic, false)) {
const char * kext_name = _KXKextCopyCanonicalPathnameAsCString(aKext);
if (kext_name) {
(_KMLog(aKext->manager))("marking extension %s authentic",
kext_name);
free((char *)kext_name);
}
}
aKext->flags.isAuthentic = 1;
aKext->flags.hasBeenAuthenticated = 1;
return result;
}
Boolean KXKextIsAuthentic(KXKextRef aKext)
{
return aKext->flags.isAuthentic ? true : false;
}
CFMutableDictionaryRef KXKextGetAuthenticationFailures(KXKextRef aKext)
{
return aKext->authenticationFailures;
}
KXKextManagerError KXKextResolveDependencies(KXKextRef aKext)
{
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKexts, kKXKextLogLevelBasic, false)) {
const char * kext_name = _KXKextCopyCanonicalPathnameAsCString(aKext);
if (kext_name) {
(_KMLog(aKext->manager))("resolving dependencies for extension %s",
kext_name);
free((char *)kext_name);
}
}
return __KXKextResolveDependencies(aKext, 0);
}
Boolean KXKextGetHasAllDependencies(KXKextRef aKext)
{
return aKext->flags.hasAllDependencies ? true : false;
}
CFArrayRef KXKextGetDirectDependencies(KXKextRef aKext)
{
return aKext->directDependencies;
}
CFMutableArrayRef KXKextCopyAllDependencies(KXKextRef aKext)
{
CFMutableArrayRef allDependencies = NULL;
if (!aKext->flags.hasAllDependencies || !aKext->directDependencies) {
goto finish;
}
allDependencies = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!allDependencies) {
goto finish;
}
__KXKextAddDependenciesToArray(aKext, allDependencies);
finish:
if (allDependencies && !CFArrayGetCount(allDependencies)) {
CFRelease(allDependencies);
allDependencies = NULL;
}
return allDependencies;
}
CFMutableArrayRef KXKextCopyIndirectDependencies(KXKextRef aKext)
{
CFMutableArrayRef indirectDependencies = NULL;
CFIndex count, i;
if (!aKext->flags.hasAllDependencies || !aKext->directDependencies) {
goto finish;
}
indirectDependencies = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!indirectDependencies) {
goto finish;
}
count = CFArrayGetCount(aKext->directDependencies);
for (i = 0; i < count; i++) {
KXKextRef thisDependency = (KXKextRef)CFArrayGetValueAtIndex(
aKext->directDependencies, i);
__KXKextAddDependenciesToArray(thisDependency, indirectDependencies);
}
finish:
if (indirectDependencies && !CFArrayGetCount(indirectDependencies)) {
CFRelease(indirectDependencies);
indirectDependencies = NULL;
}
return indirectDependencies;
}
CFMutableArrayRef KXKextCopyAllDependents(KXKextRef aKext)
{
CFMutableArrayRef allDependents = NULL; CFArrayRef allKexts = NULL; CFArrayRef kextDependencies = NULL; CFIndex count, i;
allDependents = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!allDependents) {
goto finish;
}
allKexts = KXKextManagerCopyAllKexts(KXKextGetManager(aKext));
if (!allKexts) {
goto finish;
}
count = CFArrayGetCount(allKexts);
for (i = 0; i < count; i++) {
KXKextRef thisKext = (KXKextRef)CFArrayGetValueAtIndex(allKexts, i);
if (kextDependencies) {
CFRelease(kextDependencies);
kextDependencies = NULL;
}
kextDependencies = KXKextCopyAllDependencies(thisKext);
if (!kextDependencies) {
continue;
}
if (kCFNotFound != CFArrayGetFirstIndexOfValue(kextDependencies,
CFRangeMake(0, CFArrayGetCount(kextDependencies)), aKext)) {
CFArrayAppendValue(allDependents, thisKext);
}
}
finish:
if (allKexts) CFRelease(allKexts);
if (kextDependencies) CFRelease(kextDependencies);
if (allDependents && !CFArrayGetCount(allDependents)) {
CFRelease(allDependents);
allDependents = NULL;
}
return allDependents;
}
CFDictionaryRef KXKextGetMissingDependencyErrors(KXKextRef aKext)
{
return aKext->missingDependencies;
}
Boolean KXKextIsLoadable(KXKextRef aKext, Boolean safeBoot)
{
Boolean result = (
(aKext->flags.isValid) &&
(aKext->flags.isEligibleDuringSafeBoot || !safeBoot) &&
(aKext->flags.hasBeenAuthenticated && aKext->flags.isAuthentic) &&
aKext->flags.isEnabled &&
aKext->flags.hasAllDependencies);
return result;
}
Boolean KXKextIsLoaded(KXKextRef aKext)
{
return aKext->flags.isLoaded ? true : false;
}
Boolean KXKextOtherVersionIsLoaded(KXKextRef aKext)
{
return aKext->flags.otherVersionIsLoaded ? true : false;
}
Boolean KXKextIsFromCache(KXKextRef aKext)
{
if (aKext->bundle) return false;
return true;
}
Boolean KXKextGetLoadFailed(KXKextRef aKext)
{
return aKext->flags.loadFailed ? true : false;
}
void KXKextSetLoadFailed(KXKextRef aKext, Boolean flag)
{
aKext->flags.loadFailed = (flag ? 1 : 0);
return;
}
void KXKextPrintDiagnostics(KXKextRef aKext,
FILE * stream)
{
CFDictionaryRef validationFailures = NULL; CFDictionaryRef authenticationFailures = NULL; CFDictionaryRef missingDependencies = NULL;
if (!stream) {
stream = stdin;
}
validationFailures = KXKextGetValidationFailures(aKext);
authenticationFailures = KXKextGetAuthenticationFailures(aKext);
missingDependencies = KXKextGetMissingDependencyErrors(aKext);
if (validationFailures && CFDictionaryGetCount(validationFailures)) {
fprintf(stream, "Validation failures\n");fflush(stdout);
printPList(stream, validationFailures);
}
if (authenticationFailures && CFDictionaryGetCount(authenticationFailures)) {
fprintf(stream, "Authentication failures\n");fflush(stdout);
printPList(stream, authenticationFailures);
}
if (missingDependencies && CFDictionaryGetCount(missingDependencies)) {
fprintf(stream, "Missing dependencies\n");fflush(stdout);
printPList(stream, missingDependencies);
}
fprintf(stream, "\n");
fflush(stream);
return;
}
KXKextRef _KXKextCreate(CFAllocatorRef alloc)
{
KXKextRef newKext = NULL;
newKext = __KXKextCreatePrivate(alloc, NULL);
if (!newKext) {
goto finish;
}
finish:
return (KXKextRef)newKext;
}
KXKextManagerError _KXKextInitWithBundlePathInManager(
KXKextRef aKext,
CFStringRef aBundlePath,
KXKextManagerRef aManager)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFURLRef bundleURL = NULL;
bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
aBundlePath, kCFURLPOSIXPathStyle, true);
if (!bundleURL) {
result = kKXKextManagerErrorUnspecified;
goto finish;
}
result = _KXKextInitWithURLInManager(aKext, bundleURL,
aManager);
finish:
if (bundleURL) CFRelease(bundleURL);
return result;
}
KXKextManagerError _KXKextInitWithURLInManager(
KXKextRef aKext,
CFURLRef anURL,
KXKextManagerRef aManager)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFURLRef scratchURL = NULL; KXKextRepositoryRef theRepository = NULL;
theRepository = KXKextManagerGetRepositoryForKextWithURL(aManager,
anURL);
if (!theRepository) {
scratchURL = CFURLCreateCopyDeletingLastPathComponent(
kCFAllocatorDefault, anURL);
if (!scratchURL) {
goto finish;
}
result = KXKextManagerAddRepositoryDirectory(aManager,
scratchURL, false, false, &theRepository);
if (result != kKXKextManagerErrorNone) {
goto finish;
}
}
result = _KXKextInitWithURLInRepository(aKext, anURL,
theRepository);
finish:
if (scratchURL) CFRelease(scratchURL);
return result;
}
KXKextManagerError _KXKextInitWithBundleInManager(
KXKextRef aKext,
CFBundleRef aBundle,
KXKextManagerRef aManager)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFURLRef bundleURL = NULL; CFURLRef scratchURL = NULL; KXKextRepositoryRef theRepository = NULL;
bundleURL = CFBundleCopyBundleURL(aBundle);
theRepository = KXKextManagerGetRepositoryForKextWithURL(aManager,
bundleURL);
if (!theRepository) {
scratchURL = CFURLCreateCopyDeletingLastPathComponent(
kCFAllocatorDefault, bundleURL);
if (!scratchURL) {
goto finish;
}
result = KXKextManagerAddRepositoryDirectory(aManager,
scratchURL, false, false, &theRepository);
if (result != kKXKextManagerErrorNone) {
goto finish;
}
}
result = _KXKextInitWithBundleInRepository(aKext, aBundle,
theRepository);
finish:
if (bundleURL) CFRelease(bundleURL);
if (scratchURL) CFRelease(scratchURL);
return result;
}
KXKextManagerError _KXKextInitWithBundlePathInRepository(
KXKextRef aKext,
CFStringRef aBundlePath,
KXKextRepositoryRef aRepository)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFURLRef bundleURL = NULL;
bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
aBundlePath, kCFURLPOSIXPathStyle, true);
if (!bundleURL) {
result = kKXKextManagerErrorUnspecified;
goto finish;
}
result = _KXKextInitWithURLInRepository(aKext, bundleURL,
aRepository);
finish:
CFRelease(bundleURL);
return result;
}
KXKextManagerError _KXKextInitWithURLInRepository(
KXKextRef aKext,
CFURLRef anURL,
KXKextRepositoryRef aRepository)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFBundleRef aBundle = NULL; const char * bundle_path = NULL;
aBundle = CFBundleCreate(kCFAllocatorDefault, anURL);
if (!aBundle) {
struct stat stat_buf;
bundle_path = PATH_CanonicalizedCStringForURL(anURL);
if (!bundle_path) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (stat(bundle_path, &stat_buf) != 0) {
if (errno == ENOENT || errno == ENOTDIR) {
_KMErrLog(KXKextRepositoryGetManager(aRepository))(
"%s: no such bundle file exists", bundle_path);
result = kKXKextManagerErrorFileAccess;
goto finish;
} else if (errno == EACCES) {
_KMErrLog(KXKextRepositoryGetManager(aRepository))(
"%s: permission denied", bundle_path);
result = kKXKextManagerErrorFileAccess;
goto finish;
} else {
_KMErrLog(KXKextRepositoryGetManager(aRepository))(
"%s: can't create bundle", bundle_path);
result = kKXKextManagerErrorUnspecified;
goto finish;
}
}
if ( !(stat_buf.st_mode & S_IFDIR) ) {
_KMErrLog(KXKextRepositoryGetManager(aRepository))(
"%s is not a directory", bundle_path);
result = kKXKextManagerErrorNotADirectory;
goto finish;
}
result = kKXKextManagerErrorUnspecified;
goto finish;
}
result = _KXKextInitWithBundleInRepository(aKext,
aBundle, aRepository);
finish:
if (aBundle) CFRelease(aBundle);
if (bundle_path) free((char *)bundle_path);
return result;
}
KXKextManagerError _KXKextInitWithBundleInRepository(
KXKextRef aKext,
CFBundleRef aBundle,
KXKextRepositoryRef aRepository)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFURLRef bundleRelativeURL = NULL; CFStringRef repositoryPath = NULL; CFStringRef bundlePath = NULL; CFStringRef bundleExtension = NULL;
CFStringRef bundleRepositoryPath = NULL;
if (!aKext || !aBundle || !aRepository) {
result = kKXKextManagerErrorInvalidArgument;
goto finish;
}
__KXKextInitBlank(aKext);
aKext->manager = KXKextRepositoryGetManager(aRepository);
aKext->repository = aRepository; aKext->bundle = (CFBundleRef)CFRetain(aBundle);
bundleRelativeURL = CFBundleCopyBundleURL(aKext->bundle);
if (!bundleRelativeURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
aKext->bundleURL = PATH_CopyCanonicalizedURL(bundleRelativeURL);
if (!aKext->bundleURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
aKext->bundleDirectoryName = CFURLCopyLastPathComponent(aKext->bundleURL);
if (!aKext->bundleDirectoryName) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
repositoryPath = KXKextRepositoryGetPath(aKext->repository);
if (!repositoryPath) {
result = kKXKextManagerErrorUnspecified;
goto finish;
}
bundlePath = CFURLCopyFileSystemPath(aKext->bundleURL, kCFURLPOSIXPathStyle);
if (!bundlePath) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
bundleRepositoryPath = CFStringCreateWithSubstring(kCFAllocatorDefault,
bundlePath, CFRangeMake(0, CFStringGetLength(repositoryPath)));
if (!bundleRepositoryPath) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
aKext->bundlePathInRepository =
CFStringCreateWithSubstring(kCFAllocatorDefault, bundlePath,
CFRangeMake(CFStringGetLength(repositoryPath) + 1,
CFStringGetLength(bundlePath) - CFStringGetLength(repositoryPath) - 1));
if (!aKext->bundlePathInRepository) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (CFStringCompare(repositoryPath, bundleRepositoryPath, 0) !=
kCFCompareEqualTo) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyBundleNotInRepository,
kCFBooleanTrue);
result = kKXKextManagerErrorURLNotInRepository;
goto finish;
}
if (!CFBundleGetIdentifier(aKext->bundle)) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyNotABundle,
kCFBooleanTrue);
result = kKXKextManagerErrorNotABundle;
goto finish;
}
aKext->infoDictionary = CFBundleGetInfoDictionary(aKext->bundle);
if (!aKext->infoDictionary) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyNotABundle,
kCFBooleanTrue);
result = kKXKextManagerErrorNotABundle;
goto finish;
} else {
CFRetain(aKext->infoDictionary);
}
bundleExtension = CFURLCopyPathExtension(aKext->bundleURL);
if (!bundleExtension ||
CFStringCompare(CFSTR("kext"), bundleExtension, NULL) !=
kCFCompareEqualTo) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyNotAKextBundle,
kCFBooleanTrue);
result = kKXKextManagerErrorNotAKext;
goto finish;
}
result = __KXKextValidate(aKext);
finish:
if (bundleRelativeURL) CFRelease(bundleRelativeURL);
if (bundlePath) CFRelease(bundlePath);
if (bundleRepositoryPath) CFRelease(bundleRepositoryPath);
if (bundleExtension) CFRelease(bundleExtension);
return result;
}
KXKextManagerError _KXKextInitWithCacheDictionaryInRepository(
KXKextRef aKext,
CFDictionaryRef aDictionary,
KXKextRepositoryRef aRepository)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFStringRef repositoryPath = NULL; CFStringRef bundlePath = NULL; CFStringRef bundleExtension = NULL;
CFDictionaryRef cacheInfoDictionary = NULL;
CFArrayRef plugins = NULL; CFIndex count, i;
if (!aKext || !aDictionary || !aRepository) {
result = kKXKextManagerErrorInvalidArgument;
goto finish;
}
__KXKextInitBlank(aKext);
aKext->manager = KXKextRepositoryGetManager(aRepository);
aKext->repository = aRepository; aKext->bundle = NULL;
repositoryPath = KXKextRepositoryGetPath(aKext->repository);
aKext->bundlePathInRepository = (CFStringRef)CFDictionaryGetValue(aDictionary,
CFSTR("bundlePathInRepository"));
if (!aKext->bundlePathInRepository ||
CFGetTypeID(aKext->bundlePathInRepository) != CFStringGetTypeID()) {
result = kKXKextManagerErrorInvalidArgument;
goto finish;
}
CFRetain(aKext->bundlePathInRepository);
cacheInfoDictionary = (CFDictionaryRef)CFDictionaryGetValue(aDictionary,
CFSTR("infoDictionary"));
if (!cacheInfoDictionary ||
CFGetTypeID(cacheInfoDictionary) != CFDictionaryGetTypeID()) {
result = kKXKextManagerErrorInvalidArgument;
goto finish;
}
aKext->infoDictionary = __KXKextCopyInfoDictionaryFromCache(
aKext, cacheInfoDictionary, false );
if (!aKext->infoDictionary) {
result = kKXKextManagerErrorCache;
goto finish;
}
bundlePath = CFStringCreateWithFormat(kCFAllocatorDefault, NULL ,
CFSTR("%@/%@"), repositoryPath, aKext->bundlePathInRepository);
aKext->bundleURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
bundlePath, kCFURLPOSIXPathStyle, true);
if (!aKext->bundleURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
aKext->bundleDirectoryName = CFURLCopyLastPathComponent(aKext->bundleURL);
if (!aKext->bundleDirectoryName) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
bundleExtension = CFURLCopyPathExtension(aKext->bundleURL);
if (!bundleExtension ||
CFStringCompare(CFSTR("kext"), bundleExtension, NULL) !=
kCFCompareEqualTo) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyNotAKextBundle,
kCFBooleanTrue);
result = kKXKextManagerErrorNotAKext;
goto finish;
}
result = __KXKextValidate(aKext);
if (result != kKXKextManagerErrorNone) {
goto finish;
}
if (aKext->container) goto finish;
plugins = (CFArrayRef)CFDictionaryGetValue(aDictionary,
CFSTR("plugins"));
if (!plugins) {
goto finish;
}
if (CFGetTypeID(plugins) != CFArrayGetTypeID()) {
result = kKXKextManagerErrorInvalidArgument;
goto finish;
}
count = CFArrayGetCount(plugins);
for (i = 0; i < count; i++) {
CFDictionaryRef pDict = (CFDictionaryRef)CFArrayGetValueAtIndex(
plugins, i);
KXKextRef newKext = NULL; KXKextManagerError kextResult = kKXKextManagerErrorNone;
CFURLRef kextURL = NULL; char * kext_path = NULL;
newKext = _KXKextCreate(kCFAllocatorDefault);
if (!newKext) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
kextResult = _KXKextInitWithCacheDictionaryInRepository(newKext, pDict,
aRepository);
kextURL = KXKextGetAbsoluteURL(newKext); kext_path = NULL; if (kextURL) {
kext_path = PATH_CanonicalizedCStringForURL(kextURL);
}
if (kextResult != kKXKextManagerErrorNone) {
_KXKextRepositoryAddBadKext(aRepository, newKext);
if (KXKextManagerGetLogLevel(KXKextGetManager(newKext)) >=
kKXKextManagerLogLevelDetails) {
_KMLog(KXKextGetManager(newKext))("added invalid cached kernel extension %s",
kext_path ? kext_path : "(unknown)");
}
} else {
if (KXKextManagerGetLogLevel(KXKextGetManager(newKext)) >=
kKXKextManagerLogLevelDetails) {
_KMLog(KXKextGetManager(newKext))("added cached kernel extension %s",
kext_path ? kext_path : "(unknown)");
}
_KXKextRepositoryAddKext(aRepository, newKext);
}
_KXKextAddPlugin(aKext, newKext);
CFRelease(newKext);
newKext = NULL;
if (kext_path) free(kext_path);
}
finish:
if (bundlePath) CFRelease(bundlePath);
if (bundleExtension) CFRelease(bundleExtension);
return result;
}
void _KXKextSetPriorVersionKext(KXKextRef aKext, KXKextRef thatKext)
{
KXKextRef oldPriorVersion = NULL;
oldPriorVersion = aKext->priorVersion;
aKext->priorVersion = thatKext;
if (aKext->priorVersion) CFRetain(aKext->priorVersion);
if (oldPriorVersion) CFRelease(oldPriorVersion);
return;
}
void _KXKextClearVersionRelationships(KXKextRef aKext)
{
if (aKext->priorVersion) {
CFRelease(aKext->priorVersion);
aKext->priorVersion = NULL;
}
if (aKext->nextDuplicate) {
CFRelease(aKext->nextDuplicate);
aKext->nextDuplicate = NULL;
}
return;
}
void _KXKextClearDependencies(KXKextRef aKext)
{
aKext->flags.hasAllDependencies = 0;
if (aKext->directDependencies) {
CFRelease(aKext->directDependencies);
aKext->directDependencies = NULL;
}
if (aKext->missingDependencies) {
CFRelease(aKext->missingDependencies);
aKext->missingDependencies = NULL;
}
return;
}
const char * _KXKextCopyCanonicalPathnameAsCString(KXKextRef aKext)
{
char * abs_path = NULL; CFStringRef absPath = NULL; CFIndex pathSize;
Boolean error = false;
absPath = KXKextCopyAbsolutePath(aKext);
if (!absPath) {
goto finish;
}
pathSize = 1 + CFStringGetLength(absPath);
abs_path = (char *)malloc(pathSize * sizeof(char));
if (!abs_path) {
goto finish;
}
if (!CFStringGetCString(absPath, abs_path,
pathSize, kCFStringEncodingMacRoman)) {
error = true;
}
finish:
if (absPath) CFRelease(absPath);
if (error && abs_path) {
free(abs_path);
abs_path = NULL;
}
return abs_path;
}
const char * _KXKextCopyBundlePathInRepositoryAsCString(KXKextRef aKext)
{
char * path = NULL; CFStringRef bundlePath = NULL; CFIndex pathSize;
Boolean error = false;
bundlePath = KXKextGetBundlePathInRepository(aKext);
if (!bundlePath) {
goto finish;
}
pathSize = 1 + CFStringGetLength(bundlePath);
path = (char *)malloc(pathSize * sizeof(char));
if (!path) {
goto finish;
}
if (!CFStringGetCString(bundlePath, path,
pathSize, kCFStringEncodingMacRoman)) {
error = true;
}
finish:
if (error && path) {
free(path);
path = NULL;
}
return path;
}
UInt32 _KXKextGetVersion(KXKextRef aKext)
{
return aKext->version;
}
UInt32 _KXKextGetCompatibleVersion(KXKextRef aKext)
{
return aKext->compatibleVersion;
}
Boolean _KXKextAddPriorOrDuplicateVersionKext(KXKextRef aKext,
KXKextRef priorKext)
{
KXKextRef peekingKext = NULL;
KXKextRef insertionKext = NULL;
if (KXKextGetPriorVersionKext(priorKext)) {
return false;
}
if (_KXKextGetVersion(priorKext) > _KXKextGetVersion(aKext)) {
return false;
} else if (_KXKextGetVersion(aKext) == _KXKextGetVersion(priorKext)) {
return _KXKextAddDuplicateVersionKext(aKext, priorKext);
}
peekingKext = insertionKext = aKext;
while (peekingKext) {
peekingKext = KXKextGetPriorVersionKext(insertionKext);
if (peekingKext) {
if (_KXKextGetVersion(peekingKext) == _KXKextGetVersion(priorKext)) {
return _KXKextAddDuplicateVersionKext(peekingKext, priorKext);
} else if (_KXKextGetVersion(peekingKext) <
_KXKextGetVersion(priorKext)) {
break;
}
insertionKext = peekingKext;
}
}
_KXKextSetPriorVersionKext(priorKext, peekingKext);
_KXKextSetPriorVersionKext(insertionKext, priorKext);
return true;
}
void _KXKextSetDuplicateVersionKext(KXKextRef aKext, KXKextRef thatKext)
{
KXKextRef oldNextDuplicate = NULL;
oldNextDuplicate = aKext->nextDuplicate;
aKext->nextDuplicate = thatKext;
if (aKext->nextDuplicate) CFRetain(aKext->nextDuplicate);
if (oldNextDuplicate) CFRelease(oldNextDuplicate);
return;
}
Boolean _KXKextAddDuplicateVersionKext(KXKextRef aKext, KXKextRef dupVersKext)
{
KXKextRef peekingKext = NULL;
KXKextRef insertionKext = NULL;
if (_KXKextGetVersion(aKext) != _KXKextGetVersion(dupVersKext)) {
return false;
}
if (KXKextGetDuplicateVersionKext(dupVersKext)) {
return false;
}
peekingKext = insertionKext = aKext;
while (peekingKext) {
peekingKext = KXKextGetDuplicateVersionKext(insertionKext);
if (peekingKext) insertionKext = peekingKext;
}
_KXKextSetDuplicateVersionKext(insertionKext, dupVersKext);
return true;
}
KXKextManagerError _KXKextScanPlugins(KXKextRef aKext,
CFArrayRef * goodPlugins,
CFArrayRef * badPlugins,
CFArrayRef * removedPlugins)
{
KXKextManagerError result = kKXKextManagerErrorNone;
KXKextManagerError checkResult = kKXKextManagerErrorNone;
CFStringRef bundlePath = NULL; CFURLRef pluginsRelURL = NULL; CFStringRef pluginsString = NULL; CFURLRef pluginsAbsURL = NULL; CFStringRef pluginsAbsString = NULL; CFArrayRef pluginArray = NULL;
CFIndex count, i;
KXKextRef thisPlugin = NULL;
checkResult = __KXKextRealizeFromCache(aKext);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
goto finish;
}
if (!aKext->infoDictionary) {
result = kKXKextManagerErrorNotABundle;
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyNotABundle,
kCFBooleanTrue);
aKext->flags.canAuthenticate = 0;
goto finish;
}
if (aKext->container) goto finish;
bundlePath = CFURLCopyFileSystemPath(aKext->bundleURL,
kCFURLPOSIXPathStyle);
if (!bundlePath) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
pluginsRelURL = CFBundleCopyBuiltInPlugInsURL(aKext->bundle);
if (!pluginsRelURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
pluginsString = CFURLCopyFileSystemPath(pluginsRelURL,
kCFURLPOSIXPathStyle);
if (!pluginsString) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
pluginsAbsString = CFStringCreateWithFormat(kCFAllocatorDefault,
NULL, CFSTR("%@/%@"), bundlePath, pluginsString);
if (!pluginsAbsString) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
pluginsAbsURL = CFURLCreateWithFileSystemPath(kCFAllocatorDefault,
pluginsAbsString, kCFURLPOSIXPathStyle, true);
if (!pluginsAbsURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
#if 0
pluginsAbsURL = CFURLCreateCopyAppendingPathComponent(kCFAllocatorDefault,
aKext->bundleURL, pluginsString, true);
if (!pluginsAbsURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
#endif 0
result = _KXKextRepositoryScanDirectoryForKexts(
aKext->repository,
pluginsAbsURL,
aKext->plugins,
goodPlugins,
badPlugins,
removedPlugins);
if (result == kKXKextManagerErrorNotADirectory) {
result = kKXKextManagerErrorNone;
}
if (result != kKXKextManagerErrorNone) {
goto finish;
}
if (goodPlugins && *goodPlugins) {
pluginArray = *goodPlugins;
count = CFArrayGetCount(pluginArray);
for (i = 0; i < count; i++) {
thisPlugin = (KXKextRef)CFArrayGetValueAtIndex(pluginArray, i);
_KXKextAddPlugin(aKext, thisPlugin);
}
}
if (removedPlugins && *removedPlugins) {
pluginArray = *removedPlugins;
count = CFArrayGetCount(pluginArray);
for (i = 0; i < count; i++) {
thisPlugin = (KXKextRef)CFArrayGetValueAtIndex(pluginArray, i);
_KXKextAddPlugin(aKext, thisPlugin);
}
}
finish:
if (bundlePath) CFRelease(bundlePath);
if (pluginsRelURL) CFRelease(pluginsRelURL);
if (pluginsString) CFRelease(pluginsString);
if (pluginsAbsString) CFRelease(pluginsAbsString);
if (pluginsAbsURL) CFRelease(pluginsAbsURL);
return result;
}
void _KXKextSetContainerForPluginKext(
KXKextRef aKext,
KXKextRef containerKext)
{
aKext->container = containerKext;
return;
}
void _KXKextAddPlugin(KXKextRef aKext, KXKextRef pluginKext)
{
CFIndex i;
if (!aKext->plugins) {
aKext->plugins = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!aKext->plugins) return;
}
i = CFArrayGetFirstIndexOfValue(aKext->plugins,
CFRangeMake(0, CFArrayGetCount(aKext->plugins)), pluginKext);
if (i == kCFNotFound) {
CFArrayAppendValue(aKext->plugins, pluginKext);
_KXKextSetContainerForPluginKext(pluginKext, aKext);
}
return;
}
void _KXKextRemovePlugin(KXKextRef aKext, KXKextRef pluginKext)
{
CFIndex i;
if (!aKext->plugins) {
goto finish;
}
_KXKextSetContainerForPluginKext(pluginKext, NULL);
i = CFArrayGetFirstIndexOfValue(aKext->plugins,
CFRangeMake(0, CFArrayGetCount(aKext->plugins)), pluginKext);
if (i != kCFNotFound) {
CFArrayRemoveValueAtIndex(aKext->plugins, i);
}
finish:
return;
}
void _KXKextRemoveAllPlugins(KXKextRef aKext)
{
CFIndex count, i;
if (!aKext->plugins) {
goto finish;
}
count = CFArrayGetCount(aKext->plugins);
for (i = 0; i < count; i++) {
KXKextRef thisKext = (KXKextRef)CFArrayGetValueAtIndex(aKext->plugins, i);
_KXKextSetContainerForPluginKext(thisKext, NULL);
}
CFArrayRemoveAllValues(aKext->plugins);
finish:
return;
}
void _KXKextSetIsLoaded(KXKextRef aKext, Boolean flag)
{
aKext->flags.isLoaded = (flag ? 1 : 0);
return;
}
void _KXKextSetHasBeenAuthenticated(KXKextRef aKext, Boolean flag)
{
aKext->flags.hasBeenAuthenticated = (flag ? 1 : 0);
return;
}
void _KXKextSetOtherVersionIsLoaded(KXKextRef aKext, Boolean flag)
{
aKext->flags.otherVersionIsLoaded = (flag ? 1 : 0);
return;
}
dgraph_t * _KXKextCreateDgraph(KXKextRef aKext)
{
int error = 0;
dgraph_t * dgraph = NULL; dgraph_error_t result = dgraph_valid;
if (!KXKextGetHasAllDependencies(aKext)) {
(_KMErrLog(aKext->manager))("kext doesn't have all dependencies");
goto finish;
}
dgraph = (dgraph_t *)malloc(sizeof(dgraph_t));
if (!dgraph) {
goto finish;
}
result = dgraph_init(dgraph);
if (result != dgraph_valid) {
(_KMErrLog(aKext->manager))("new dgraph is invalid");
error = 1;
goto finish;
}
if (!__KXKextAddDependenciesToDgraph(aKext,
KXKextGetDirectDependencies(aKext), dgraph)) {
(_KMErrLog(aKext->manager))("can't add dependencies to dgraph");
error = 1;
goto finish;
}
dgraph->root = dgraph_find_root(dgraph);
dgraph_establish_load_order(dgraph);
if (!dgraph->root) {
(_KMErrLog(aKext->manager))("dependency graph has no root");
error = 1;
goto finish;
}
if (dgraph->root->is_kernel_component) {
(_KMErrLog(aKext->manager))(
"dependency graph root is a kernel component");
error = 1;
goto finish;
}
finish:
if (error) {
dgraph_free(dgraph, 1);
dgraph = NULL;
}
return dgraph;
}
CFDictionaryRef _KXKextCopyCacheDictionary(KXKextRef aKext)
{
Boolean error = false;
CFMutableDictionaryRef theDictionary = NULL; CFDictionaryRef cacheInfoDictionary = NULL; CFMutableArrayRef plugins = NULL;
theDictionary = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!theDictionary) {
error = true;
goto finish;
}
CFDictionarySetValue(theDictionary, CFSTR("bundlePathInRepository"),
aKext->bundlePathInRepository);
cacheInfoDictionary = __KXKextCopyInfoDictionaryForCache(
aKext, aKext->infoDictionary, false );
if (!cacheInfoDictionary) {
goto finish;
}
CFDictionarySetValue(theDictionary, CFSTR("infoDictionary"),
cacheInfoDictionary);
if (aKext->plugins) {
CFIndex count, i;
plugins = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!plugins) {
error = true;
goto finish;
}
CFDictionarySetValue(theDictionary, CFSTR("plugins"),
plugins);
count = CFArrayGetCount(aKext->plugins);
for (i = 0; i < count; i++) {
KXKextRef plugin = (KXKextRef)CFArrayGetValueAtIndex(
aKext->plugins, i);
CFDictionaryRef pDict = _KXKextCopyCacheDictionary(plugin);
if (!pDict) {
error = true;
goto finish;
}
CFArrayAppendValue(plugins, pDict);
CFRelease(pDict); pDict = NULL;
}
}
finish:
if (cacheInfoDictionary) CFRelease(cacheInfoDictionary);
if (plugins) CFRelease(plugins);
if (error) {
if (theDictionary) CFRelease(theDictionary);
theDictionary = NULL;
}
return theDictionary;
}
KXKextManagerError _KXKextMakeSecure(KXKextRef aKext)
{
KXKextManagerError result = kKXKextManagerErrorNone;
KXKextManagerError checkResult = kKXKextManagerErrorNone;
CFURLRef absURL = NULL; CFStringRef urlPath = NULL; char path[MAXPATHLEN] = "";
char * const paths[2] = { path, NULL };
FTS * ftscursor = NULL; FTSENT * ftsentry = NULL;
checkResult = __KXKextRealizeFromCache(aKext);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
goto finish;
}
absURL = PATH_CopyCanonicalizedURL(aKext->bundleURL);
if (!absURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
urlPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
if (!urlPath) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (!CFStringGetCString(urlPath, path, sizeof(path),
kCFStringEncodingMacRoman)) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (!_KXKextRepositoryInvalidateCaches(aKext->repository)) {
(_KMErrLog(aKext->manager))("can't invalidate caches for %s",
path);
}
ftscursor = fts_open(paths, (FTS_NOCHDIR | FTS_PHYSICAL),
NULL);
if (!ftscursor) {
(_KMErrLog(aKext->manager))("can't scan contents of %s",
path);
result = kKXKextManagerErrorFileAccess;
goto finish;
}
while ( (ftsentry = fts_read(ftscursor))) {
if (! (ftsentry->fts_info & FTS_DP)) {
result = __KXKextMakeFTSEntrySecure(aKext, ftsentry);
if (result != kKXKextManagerErrorNone) {
goto finish;
}
}
}
aKext->flags.hasBeenAuthenticated = 0;
result = KXKextAuthenticate(aKext);
finish:
if (ftscursor) fts_close(ftscursor);
if (absURL) CFRelease(absURL);
if (urlPath) CFRelease(urlPath);
return result;
}
static const CFRuntimeClass __KXKextClass = {
0, "KXKext", NULL, NULL, __KXKextReleaseContents, NULL, NULL, NULL, __KXKextCopyDebugDescription };
static void __KXKextInitialize(void)
{
__kKXKextTypeID = _CFRuntimeRegisterClass(&__KXKextClass);
kKXKextErrorKeyFileAccess =
CFSTR("File access failure; no permission?");
kKXKextErrorKeyBundleNotInRepository =
CFSTR("Bundle was created with an URL not in the requested repository");
kKXKextErrorKeyNotABundle =
CFSTR("Not a bundle; file structure or property list error?");
kKXKextErrorKeyNotAKextBundle =
CFSTR("Bundle is not a kext bundle");
kKXKextErrorKeyBadPropertyList =
CFSTR("Info dictionary not valid for kext");
kKXKextErrorKeyMissingProperty =
CFSTR("Info dictionary missing required property/value");
kKXKextErrorKeyPropertyIsIllegalType =
CFSTR("Info dictionary property value is of illegal type");
kKXKextErrorKeyPropertyIsIllegalValue =
CFSTR("Info dictionary property value is illegal");
kKXKextErrorKeyIdentifierOrVersionTooLong =
CFSTR("CFBundleIdentifier or CFBundleVersion string is too long");
kKXKextErrorKeyPersonalitiesNotNested =
CFSTR("Structure of IOKitPersonalities is incorrect");
kKXKextErrorKeyMissingExecutable =
CFSTR("Kext claims an executable file but it doesn't exist");
kKXKextErrorKeyCompatibleVersionLaterThanVersion =
CFSTR("Compatible version is later than current version");
kKXKextErrorKeyExecutableBad =
CFSTR("Executable file doesn't contain kernel extension code");
kKXKextErrorKeyExecutableBadArch =
CFSTR("Executable does not contain code for this architecture");
kKXKextErrorKeyBundleIdentifierMismatch =
CFSTR("Kext has a kernel dependency prior to version 6.0 and "
"CFBundleIdentifier does not match executable's MODULE_NAME");
kKXKextErrorKeyBundleVersionMismatch =
CFSTR("Kext has a kernel dependency prior to version 6.0 and "
"CFBundleVersion does not match executable's MODULE_VERSION");
kKXKextErrorKeyStatFailure =
CFSTR("Failed to get authentication info");
kKXKextErrorKeyFileNotFound =
CFSTR("File not found");
kKXKextErrorKeyOwnerPermission =
CFSTR("File owner/permissions are incorrect");
kKXKextErrorKeyChecksum =
CFSTR("Checksum does not match");
kKXKextErrorKeySignature =
CFSTR("Signature cannot be authenticated");
kKXKextErrorKeyDependenciesUnresolvable =
CFSTR("Cannot resolve all dependencies");
kKXKextErrorKeyPossibleDependencyLoop =
CFSTR("Too many dependencies; possible loop?");
kKXKextDependencyUnavailable =
CFSTR("No valid version of this dependency can be found");
kKXKextDependencyNoCompatibleVersion =
CFSTR("A valid compatible version of this dependency cannot be found");
kKXKextDependencyCompatibleVersionUndeclared =
CFSTR("No dependency could be found that declares a compatible version");
kKXKextIndirectDependencyUnresolvable =
CFSTR("This dependency has dependencies that cannot be resolved");
kKXKextDependencyCircularReference =
CFSTR("This dependency may be causing a circular reference");
return;
}
static pthread_once_t initialized = PTHREAD_ONCE_INIT;
static KXKextRef __KXKextCreatePrivate(
CFAllocatorRef allocator,
CFAllocatorContext * context)
{
KXKextRef newKext = NULL;
void * offset = NULL;
UInt32 size;
pthread_once(&initialized, __KXKextInitialize);
size = sizeof(__KXKext) - sizeof(CFRuntimeBase);
newKext = (KXKextRef)_CFRuntimeCreateInstance(allocator,
__kKXKextTypeID, size, NULL);
if (!newKext) {
return NULL;
}
offset = newKext;
bzero(offset + sizeof(CFRuntimeBase), size);
return (KXKextRef)newKext;
}
static CFStringRef __KXKextCopyDebugDescription(CFTypeRef cf)
{
CFAllocatorRef allocator = CFGetAllocator(cf);
CFMutableStringRef result;
result = CFStringCreateMutable(allocator, 0);
CFStringAppendFormat(result, NULL, CFSTR("<KXKext %p [%p]> {\n"), cf, allocator);
CFStringAppendFormat(result, NULL, CFSTR("}"));
return result;
}
static void __KXKextResetTestFlags(KXKextRef aKext)
{
aKext->logLevel = 0;
aKext->flags.declaresExecutable = 0;
aKext->flags.isKernelResource = 0;
aKext->flags.isValid = 0;
aKext->flags.isEligibleDuringSafeBoot = 0;
aKext->flags.isEnabled = 1; aKext->flags.canAuthenticate = 1; aKext->flags.hasBeenAuthenticated = 0;
aKext->flags.isAuthentic = 0;
aKext->flags.canResolveDependencies = 1; aKext->flags.hasAllDependencies = 0;
aKext->flags.isLoaded = 0;
aKext->flags.otherVersionIsLoaded = 0;
aKext->flags.loadFailed = 0;
aKext->flags.hasIOKitDebugProperty = 0;
return;
}
static void __KXKextInitBlank(KXKextRef aKext)
{
aKext->manager = NULL;
aKext->repository = NULL;
aKext->bundle = NULL;
aKext->bundleURL = NULL;
aKext->infoDictionary = NULL;
aKext->bundleDirectoryName = NULL;
aKext->bundlePathInRepository = NULL;
aKext->plugins = NULL;
aKext->container = NULL;
__KXKextResetTestFlags(aKext);
aKext->version = 0;
aKext->compatibleVersion = 0;
aKext->priorVersion = NULL;
aKext->nextDuplicate = NULL;
aKext->directDependencies = NULL;
aKext->validationFailures = NULL;
aKext->authenticationFailures = NULL;
aKext->missingDependencies = NULL;
return;
}
static void __KXKextReleaseContents(CFTypeRef cf)
{
KXKextRef aKext = (KXKextRef)cf;
if (aKext->manager) {
aKext->manager = NULL;
}
if (aKext->repository) {
aKext->repository = NULL;
}
if (aKext->bundlePathInRepository) {
CFRelease(aKext->bundlePathInRepository);
aKext->bundlePathInRepository = NULL;
}
if (aKext->bundleDirectoryName) {
CFRelease(aKext->bundleDirectoryName);
aKext->bundleDirectoryName = NULL;
}
if (aKext->infoDictionary) {
CFRelease(aKext->infoDictionary);
aKext->infoDictionary = NULL;
}
if (aKext->container) {
CFRelease(aKext->container);
aKext->container = NULL;
}
_KXKextRemoveAllPlugins((KXKextRef)aKext);
if (aKext->plugins) {
CFRelease(aKext->plugins);
aKext->plugins = NULL;
}
if (aKext->bundleURL) {
CFRelease(aKext->bundleURL);
aKext->bundleURL = NULL;
}
if (aKext->bundle) {
CFRelease(aKext->bundle);
aKext->bundle = NULL;
}
if (aKext->priorVersion) {
CFRelease(aKext->priorVersion);
aKext->priorVersion = NULL;
}
if (aKext->nextDuplicate) {
CFRelease(aKext->nextDuplicate);
aKext->nextDuplicate = NULL;
}
if (aKext->directDependencies) {
CFRelease(aKext->directDependencies);
aKext->directDependencies = NULL;
}
if (aKext->validationFailures) {
CFRelease(aKext->validationFailures);
aKext->validationFailures = NULL;
}
if (aKext->authenticationFailures) {
CFRelease(aKext->authenticationFailures);
aKext->authenticationFailures = NULL;
}
if (aKext->missingDependencies) {
CFRelease(aKext->missingDependencies);
aKext->missingDependencies = NULL;
}
return;
}
static Boolean __KXKextCheckLogLevel(
KXKextRef aKext,
SInt32 managerLogLevel,
SInt32 kextLogLevel,
Boolean exact)
{
int kmLogLevel = KXKextManagerGetLogLevel(aKext->manager);
if (exact) {
if (kmLogLevel == managerLogLevel || aKext->logLevel == kextLogLevel) {
return true;
}
} else if (kmLogLevel >= managerLogLevel || aKext->logLevel >= kextLogLevel) {
return true;
}
return false;
}
static KXKextManagerError __KXKextValidate(KXKextRef aKext)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFStringRef propKey; CFStringRef stringValue;
CFTypeRef rawValue;
CFNumberRef numValue;
CFMutableArrayRef propPathArray = NULL; CFStringRef propPathString = NULL;
CFIndex numPersonalities = 0;
CFIndex numPersonalitiesWithIOKitDebug = 0;
CFTypeRef * personalityKeys = NULL; CFTypeRef * personalityValues = NULL;
CFStringRef * keys = NULL;
CFMutableArrayRef illegalValueProperties = NULL;
CFMutableArrayRef missingValueProperties = NULL;
KXKextManagerError checkResult = kKXKextManagerErrorNone;
volatile Boolean foundErrors = false;
UInt32 kernelLibVersion = 0;
Boolean requiresNewKextManager = false;
__KXKextResetTestFlags(aKext);
if (!__KXKextGetOrCreateValidationFailures(aKext)) {
if (!aKext->validationFailures) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
}
CFDictionaryRemoveAllValues(aKext->validationFailures);
propPathArray = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!propPathArray) {
result = kKXKextManagerErrorNoMemory;
goto finish; }
if (!aKext->infoDictionary ||
CFGetTypeID(aKext->infoDictionary) != CFDictionaryGetTypeID()) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyNotABundle,
kCFBooleanTrue);
result = kKXKextManagerErrorNotABundle;
aKext->flags.canAuthenticate = 0;
foundErrors = true;
goto finish;
}
if (!__KXKextCheckStringProperty(aKext, aKext->infoDictionary,
CFSTR("CFBundleIdentifier"), NULL, true, NULL, &stringValue)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
if (stringValue && CFStringGetLength(stringValue) > KMOD_MAX_NAME - 1) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyIdentifierOrVersionTooLong,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
if (!KXKextIsFromCache(aKext) &&
!__KXKextCheckStringProperty(aKext, aKext->infoDictionary,
CFSTR("CFBundlePackageType"), NULL, true, CFSTR("KEXT"), NULL)) {
result = kKXKextManagerErrorNotAKext;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
rawValue = CFDictionaryGetValue(aKext->infoDictionary,
CFSTR("OSBundleDebugLevel"));
if (rawValue) {
Boolean numError = false;
if (CFGetTypeID(rawValue) == CFNumberGetTypeID()) {
numValue = (CFNumberRef)rawValue;
if (!CFNumberGetValue(numValue, kCFNumberSInt32Type, &aKext->logLevel)) {
numError = true;
}
} else {
numError = true;
}
if (numError) {
CFMutableArrayRef illegalTypeProperties =
__KXKextGetIllegalTypeProperties(aKext);
if (!illegalTypeProperties) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
CFArrayAppendValue(illegalTypeProperties, CFSTR("OSBundleDebugLevel"));
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
}
#if 0
if (!__KXKextCheckStringProperty(aKext, aKext->infoDictionary,
CFSTR("CFBundleSignature"), NULL, true, NULL, NULL)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
#endif 0
propKey = CFSTR("CFBundleVersion");
if (!__KXKextCheckVersionProperty(aKext, aKext->infoDictionary,
propKey, NULL, true, &aKext->version)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
propKey = CFSTR("OSBundleCompatibleVersion");
if (!__KXKextCheckVersionProperty(aKext, aKext->infoDictionary,
propKey, NULL, false, &aKext->compatibleVersion)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
if (aKext->compatibleVersion > aKext->version) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyCompatibleVersionLaterThanVersion,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
propKey = CFSTR("CFBundleExecutable");
if (!__KXKextCheckStringProperty(aKext, aKext->infoDictionary,
propKey, NULL, false, NULL, &stringValue)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
if (!stringValue) {
aKext->flags.declaresExecutable = 0;
} else {
aKext->flags.declaresExecutable = 1;
}
propKey = CFSTR("OSKernelResource");
if (!__KXKextCheckPropertyType(aKext, aKext->infoDictionary, propKey,
NULL, false, CFBooleanGetTypeID(), &rawValue)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
if (rawValue) {
aKext->flags.isKernelResource =
CFBooleanGetValue((CFBooleanRef)rawValue) ? 1 : 0;
aKext->flags.hasAllDependencies = aKext->flags.isKernelResource;
}
propKey = CFSTR("IOKitPersonalities");
CFArrayAppendValue(propPathArray, propKey);
if (!__KXKextCheckPropertyType(aKext, aKext->infoDictionary, propKey,
NULL, false, CFDictionaryGetTypeID(), &rawValue)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
} else if (rawValue) {
CFDictionaryRef personalitiesDict = (CFDictionaryRef)rawValue;
CFIndex i;
numPersonalities = CFDictionaryGetCount(personalitiesDict);
personalityKeys =
(CFTypeRef *)malloc(numPersonalities * sizeof(CFTypeRef));
if (! personalityKeys) {
result = kKXKextManagerErrorNoMemory;
goto finish; }
personalityValues =
(CFTypeRef *)malloc(numPersonalities * sizeof(CFTypeRef));
if (!personalityValues) {
result = kKXKextManagerErrorNoMemory;
goto finish; }
CFDictionaryGetKeysAndValues(personalitiesDict,
(const void **)personalityKeys,
(const void **)personalityValues);
for (i = 0; i < numPersonalities; i++) {
CFStringRef thisPersonalityName = personalityKeys[i];
CFTypeRef thisPersonality = personalityValues[i];
CFDictionaryRef thisPersonalityDict;
if (CFGetTypeID(thisPersonality) != CFDictionaryGetTypeID()) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyPersonalitiesNotNested,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
} else {
CFArrayAppendValue(propPathArray, thisPersonalityName);
thisPersonalityDict = (CFDictionaryRef)thisPersonality;
propKey = CFSTR("IOClass");
CFArrayAppendValue(propPathArray, propKey);
if (!__KXKextCheckStringProperty(aKext, thisPersonality,
propKey, propPathArray, true, NULL, NULL)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
CFArrayRemoveValueAtIndex(propPathArray,
CFArrayGetCount(propPathArray) - 1);
propKey = CFSTR("IOProviderClass");
CFArrayAppendValue(propPathArray, propKey);
if (!__KXKextCheckStringProperty(aKext, thisPersonality,
propKey, propPathArray, true, NULL, NULL)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
CFArrayRemoveValueAtIndex(propPathArray,
CFArrayGetCount(propPathArray) - 1);
propKey = CFSTR("CFBundleIdentifier");
CFArrayAppendValue(propPathArray, propKey);
if (!__KXKextCheckStringProperty(aKext, thisPersonality,
propKey, propPathArray, false, NULL, NULL)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
CFArrayRemoveValueAtIndex(propPathArray,
CFArrayGetCount(propPathArray) - 1);
propKey = CFSTR("IOKitDebug");
CFArrayAppendValue(propPathArray, propKey);
if (!__KXKextCheckPropertyType(aKext, thisPersonality,
propKey, propPathArray, false, CFNumberGetTypeID(), &rawValue)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
} else if (rawValue) {
CFNumberRef number = (CFNumberRef)rawValue;
if (!CFNumberIsFloatType(rawValue)) {
long long int numValue = 0;
if (!CFNumberGetValue(number, kCFNumberLongLongType, &numValue)) {
(_KMErrLog(aKext->manager))(
"error reading IOKitDebug property");
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
if (numValue != 0) {
numPersonalitiesWithIOKitDebug++;
aKext->flags.hasIOKitDebugProperty = 1;
}
}
}
CFArrayRemoveValueAtIndex(propPathArray,
CFArrayGetCount(propPathArray) - 1);
if (!__KXKextCheckPersonalityTypes(aKext, thisPersonality,
propPathArray)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
CFArrayRemoveValueAtIndex(propPathArray,
CFArrayGetCount(propPathArray) - 1);
}
}
}
CFArrayRemoveAllValues(propPathArray);
propKey = CFSTR("OSBundleLibraries");
CFArrayAppendValue(propPathArray, propKey);
if (!__KXKextCheckPropertyType(aKext, aKext->infoDictionary,
propKey, NULL,
(!aKext->flags.isKernelResource && aKext->flags.declaresExecutable),
CFDictionaryGetTypeID(), &rawValue)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
aKext->flags.canResolveDependencies = 0;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
} else if (rawValue) {
CFDictionaryRef bundleLibraries = (CFDictionaryRef)rawValue;
CFIndex numLibraries, i;
numLibraries = CFDictionaryGetCount(bundleLibraries);
if (!numLibraries) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
aKext->flags.canResolveDependencies = 0;
missingValueProperties = __KXKextGetMissingProperties(aKext);
if (!missingValueProperties) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
CFArrayAppendValue(missingValueProperties, propKey);
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
keys = (CFStringRef *)malloc(numLibraries * sizeof(CFStringRef));
if (!keys) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
CFDictionaryGetKeysAndValues(bundleLibraries, (const void **)keys, NULL);
if (!VERS_parse_string("6.0", &kernelLibVersion)) {
result = kKXKextManagerErrorUnspecified;
goto finish;
}
for (i = 0; i < numLibraries; i++) {
CFStringRef dependencyID = keys[i];
UInt32 version;
CFArrayAppendValue(propPathArray, dependencyID);
if (!__KXKextCheckVersionProperty(aKext, bundleLibraries,
dependencyID, propPathArray, true, &version)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
aKext->flags.canResolveDependencies = 0;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
} else if (CFStringHasPrefix(dependencyID,
CFSTR("com.apple.kernel"))) {
if (version >= kernelLibVersion) {
requiresNewKextManager = true;
}
}
CFArrayRemoveValueAtIndex(propPathArray,
CFArrayGetCount(propPathArray) - 1);
}
}
CFArrayRemoveAllValues(propPathArray);
propKey = CFSTR("OSBundleRequired");
if (!__KXKextCheckStringProperty(aKext, aKext->infoDictionary,
propKey, NULL, false, NULL, &stringValue)) {
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
} else if (stringValue) {
CFStringRef str = stringValue;
if (kCFCompareEqualTo == CFStringCompare(str, CFSTR("Root"), 0) ||
kCFCompareEqualTo == CFStringCompare(str, CFSTR("Local-Root"), 0) ||
kCFCompareEqualTo == CFStringCompare(str, CFSTR("Network-Root"), 0) ||
kCFCompareEqualTo == CFStringCompare(str, CFSTR("Console"), 0) ||
kCFCompareEqualTo == CFStringCompare(str, CFSTR("Safe Boot"), 0) ) {
aKext->flags.isEligibleDuringSafeBoot = 1;
} else {
illegalValueProperties = __KXKextGetIllegalValueProperties(aKext);
if (!illegalValueProperties) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
CFArrayAppendValue(illegalValueProperties, propKey);
result = kKXKextManagerErrorValidation;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
}
if (numPersonalities > 0 &&
numPersonalities == numPersonalitiesWithIOKitDebug) {
aKext->flags.isEligibleDuringSafeBoot = 0;
}
if (KXKextManagerPerformsFullTests(aKext->manager)) {
checkResult = __KXKextRealizeFromCache(aKext);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
foundErrors = true;
goto finish; }
if (aKext->flags.declaresExecutable) {
checkResult = __KXKextValidateExecutable(aKext,
requiresNewKextManager);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
foundErrors = true;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
}
}
if (!foundErrors) {
aKext->flags.isValid = 1;
}
finish:
if (result != kKXKextManagerErrorNone) {
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelBasic,
kKXKextLogLevelBasic, false)) {
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext); (_KMErrLog(aKext->manager))(
"kext %s is not valid",
kext_name ? kext_name : "(unknown)");
if (kext_name) free((char *)kext_name);
}
}
if (propPathArray) CFRelease(propPathArray);
if (propPathString) CFRelease(propPathString);
if (personalityKeys) free(personalityKeys);
if (personalityValues) free(personalityValues);
if (keys) free(keys);
return result;
}
static KXKextManagerError __KXKextValidateExecutable(KXKextRef aKext,
Boolean requiresNewKextManager)
{
KXKextManagerError result = kKXKextManagerErrorNone;
KXKextManagerError checkResult = kKXKextManagerErrorNone;
CFURLRef executableURL = NULL;
checkResult = __KXKextRealizeFromCache(aKext);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
goto finish;
}
executableURL = CFBundleCopyExecutableURL(aKext->bundle);
if (!executableURL) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyMissingExecutable,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
} else {
checkResult = __KXKextCheckKmod(aKext, executableURL,
requiresNewKextManager);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
}
finish:
if (executableURL) CFRelease(executableURL);
return result;
}
static CFMutableDictionaryRef __KXKextGetOrCreateValidationFailures(KXKextRef aKext)
{
if (!aKext->validationFailures) {
aKext->validationFailures = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
return aKext->validationFailures;
}
static CFMutableDictionaryRef __KXKextGetOrCreateAuthenticationFailures(KXKextRef aKext)
{
if (!aKext->authenticationFailures) {
aKext->authenticationFailures = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
}
return aKext->authenticationFailures;
}
static CFMutableArrayRef __KXKextGetMissingProperties(KXKextRef aKext)
{
CFMutableDictionaryRef failures = NULL;
CFMutableArrayRef theMissingProperties = NULL;
failures = __KXKextGetOrCreateValidationFailures(aKext);
if (!failures) {
return NULL;
}
theMissingProperties = (CFMutableArrayRef)
CFDictionaryGetValue(failures, kKXKextErrorKeyMissingProperty);
if (!theMissingProperties) {
theMissingProperties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!theMissingProperties) {
return NULL;
}
CFDictionarySetValue(failures,
kKXKextErrorKeyMissingProperty,
theMissingProperties);
CFRelease(theMissingProperties);
}
return theMissingProperties;
}
static CFMutableArrayRef __KXKextGetIllegalTypeProperties(KXKextRef aKext)
{
CFMutableDictionaryRef failures = NULL;
CFMutableArrayRef theIllegalTypeProperties = NULL;
failures = __KXKextGetOrCreateValidationFailures(aKext);
if (!failures) {
return NULL;
}
theIllegalTypeProperties = (CFMutableArrayRef)
CFDictionaryGetValue(failures, kKXKextErrorKeyPropertyIsIllegalType);
if (!theIllegalTypeProperties) {
theIllegalTypeProperties = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!theIllegalTypeProperties) {
return NULL;
}
CFDictionarySetValue(failures,
kKXKextErrorKeyPropertyIsIllegalType,
theIllegalTypeProperties);
CFRelease(theIllegalTypeProperties);
}
return theIllegalTypeProperties;
}
static CFMutableArrayRef __KXKextGetIllegalValueProperties(KXKextRef aKext)
{
CFMutableDictionaryRef failures = NULL;
CFMutableArrayRef theIllegalValueProperties = NULL;
failures = __KXKextGetOrCreateValidationFailures(aKext);
if (!failures) {
return NULL;
}
theIllegalValueProperties = (CFMutableArrayRef)
CFDictionaryGetValue(failures, kKXKextErrorKeyPropertyIsIllegalValue);
if (!theIllegalValueProperties) {
theIllegalValueProperties = CFArrayCreateMutable(kCFAllocatorDefault,
0, &kCFTypeArrayCallBacks);
if (!theIllegalValueProperties) {
return NULL;
}
CFDictionarySetValue(failures,
kKXKextErrorKeyPropertyIsIllegalValue,
theIllegalValueProperties);
CFRelease(theIllegalValueProperties);
}
return theIllegalValueProperties;
}
static CFMutableArrayRef __KXKextGetMissingFiles(KXKextRef aKext)
{
CFMutableDictionaryRef failures = NULL;
CFMutableArrayRef theArray = NULL;
failures = __KXKextGetOrCreateAuthenticationFailures(aKext);
if (!failures) {
return NULL;
}
theArray = (CFMutableArrayRef)
CFDictionaryGetValue(failures, kKXKextErrorKeyFileNotFound);
if (!theArray) {
theArray = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!theArray) {
return NULL;
}
CFDictionarySetValue(failures,
kKXKextErrorKeyFileNotFound,
theArray);
CFRelease(theArray);
}
return theArray;
}
static CFMutableArrayRef __KXKextGetBadOwnerPermsFiles(KXKextRef aKext)
{
CFMutableDictionaryRef failures = NULL;
CFMutableArrayRef theArray = NULL;
failures = __KXKextGetOrCreateAuthenticationFailures(aKext);
if (!failures) {
return NULL;
}
theArray = (CFMutableArrayRef)
CFDictionaryGetValue(failures, kKXKextErrorKeyOwnerPermission);
if (!theArray) {
theArray = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!theArray) {
return NULL;
}
CFDictionarySetValue(failures,
kKXKextErrorKeyOwnerPermission,
theArray);
CFRelease(theArray);
}
return theArray;
}
static Boolean __KXKextCheckPropertyType(
KXKextRef aKext,
CFDictionaryRef aDictionary,
CFStringRef propKey,
CFArrayRef propPathArray,
Boolean isRequired,
CFTypeID expectedType,
CFTypeRef * rawValueOut)
{
CFTypeRef rawValue;
CFMutableArrayRef missingProperties;
CFMutableArrayRef illegalTypeProperties;
CFStringRef propPathString = NULL;
if (rawValueOut) * rawValueOut = NULL;
rawValue = CFDictionaryGetValue(aDictionary,
propKey);
if (!rawValue) {
if (!isRequired) {
return true;
} else {
missingProperties = __KXKextGetMissingProperties(aKext);
if (!missingProperties) {
return false;
}
if (!propPathArray) {
CFArrayAppendValue(missingProperties, propKey);
} else {
propPathString = CFStringCreateByCombiningStrings(
kCFAllocatorDefault, propPathArray, CFSTR(":"));
if (!propPathString) return NULL;
CFArrayAppendValue(missingProperties, propPathString);
CFRelease(propPathString);
}
return false;
}
}
if (rawValueOut) *rawValueOut = rawValue;
if (CFGetTypeID(rawValue) != expectedType) {
illegalTypeProperties = __KXKextGetIllegalTypeProperties(aKext);
if (! illegalTypeProperties) {
return false;
}
if (!propPathArray) {
CFArrayAppendValue(illegalTypeProperties, propKey);
} else {
propPathString = CFStringCreateByCombiningStrings(
kCFAllocatorDefault, propPathArray, CFSTR(":"));
if (!propPathString) return NULL;
CFArrayAppendValue(illegalTypeProperties, propPathString);
CFRelease(propPathString);
}
return false;
}
return true;
}
static Boolean __KXKextCheckStringProperty(
KXKextRef aKext,
CFDictionaryRef aDictionary,
CFStringRef propKey,
CFArrayRef propPathArray,
Boolean isRequired,
CFStringRef expectedValue,
CFStringRef *stringValueOut)
{
CFTypeRef rawValue = NULL;
CFStringRef stringValue = NULL;
CFMutableArrayRef missingProperties;
CFMutableArrayRef illegalTypeProperties;
CFMutableArrayRef illegalValueProperties;
CFStringRef propPathString = NULL;
if (stringValueOut) *stringValueOut = NULL;
rawValue = CFDictionaryGetValue(aDictionary,
propKey);
if (!rawValue) {
if (!isRequired) {
return true;
} else {
missingProperties = __KXKextGetMissingProperties(aKext);
if (!missingProperties) {
return false;
}
if (!propPathArray) {
CFArrayAppendValue(missingProperties, propKey);
} else {
propPathString = CFStringCreateByCombiningStrings(
kCFAllocatorDefault, propPathArray, CFSTR(":"));
if (!propPathString) return false;
CFArrayAppendValue(missingProperties, propPathString);
CFRelease(propPathString);
}
return false;
}
}
if (CFGetTypeID(rawValue) != CFStringGetTypeID()) {
illegalTypeProperties = __KXKextGetIllegalTypeProperties(aKext);
if (!illegalTypeProperties) {
return false;
}
if (!propPathArray) {
CFArrayAppendValue(illegalTypeProperties, propKey);
} else {
propPathString = CFStringCreateByCombiningStrings(
kCFAllocatorDefault, propPathArray, CFSTR(":"));
if (!propPathString) return NULL;
CFArrayAppendValue(illegalTypeProperties, propPathString);
CFRelease(propPathString);
}
return false;
}
stringValue = (CFStringRef)rawValue;
if (stringValueOut) *stringValueOut = stringValue;
if (expectedValue) {
if (CFStringCompare(expectedValue, stringValue, 0) !=
kCFCompareEqualTo) {
illegalValueProperties = __KXKextGetIllegalValueProperties(aKext);
if (!illegalValueProperties) {
return false;
}
if (!propPathArray) {
CFArrayAppendValue(illegalValueProperties, propKey);
} else {
propPathString = CFStringCreateByCombiningStrings(
kCFAllocatorDefault, propPathArray, CFSTR(":"));
if (!propPathString) return false;
CFArrayAppendValue(illegalValueProperties, propPathString);
CFRelease(propPathString);
}
return false;
}
}
return true;
}
static Boolean __KXKextCheckVersionProperty(
KXKextRef aKext,
CFDictionaryRef aDictionary,
CFStringRef propKey,
CFArrayRef propPathArray,
Boolean isRequired,
UInt32 *version)
{
char vers_buffer[32]; CFStringRef stringValue = NULL;
CFStringRef propPathString = NULL; CFMutableArrayRef illegalValueProperties = NULL;
if (!__KXKextCheckStringProperty(aKext, aDictionary,
propKey, propPathArray, isRequired, NULL, &stringValue)) {
if (isRequired) return false;
else return true;
}
if (!isRequired && !stringValue) {
return true;
}
if (!CFStringGetCString(stringValue,
vers_buffer, sizeof(vers_buffer) - 1, kCFStringEncodingMacRoman)) {
illegalValueProperties = __KXKextGetIllegalValueProperties(aKext);
if (!illegalValueProperties) return false;
if (!propPathArray) {
CFArrayAppendValue(illegalValueProperties, propKey);
} else {
propPathString = CFStringCreateByCombiningStrings(
kCFAllocatorDefault, propPathArray, CFSTR(":"));
if (!propPathString) return false;
CFArrayAppendValue(illegalValueProperties, propPathString);
CFRelease(propPathString);
}
return false;
} else {
vers_buffer[sizeof(vers_buffer) - 1] = '\0';
if (!VERS_parse_string(vers_buffer, version)) {
illegalValueProperties = __KXKextGetIllegalValueProperties(aKext);
if (! illegalValueProperties) return false;
if (!propPathArray) {
CFArrayAppendValue(illegalValueProperties, propKey);
} else {
propPathString = CFStringCreateByCombiningStrings(
kCFAllocatorDefault, propPathArray, CFSTR(":"));
if (!propPathString) return false;
CFArrayAppendValue(illegalValueProperties, propPathString);
CFRelease(propPathString);
}
return false;
}
}
if (CFEqual(propKey, CFSTR("CFBundleVersion"))) {
if (CFStringGetLength(stringValue) > KMOD_MAX_NAME - 1) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyIdentifierOrVersionTooLong,
kCFBooleanTrue);
return false;
}
}
return true;
}
static Boolean __KXKextCheckPersonalityTypes(KXKextRef aKext,
CFTypeRef cfObj, CFMutableArrayRef propPathArray)
{
Boolean result = true;
Boolean localResult = true;
Boolean foundInvalidType = false;
CFTypeID typeID;
CFStringRef arrayIndexString = NULL; CFStringRef propPathString = NULL; CFMutableArrayRef illegalTypeProperties = NULL; CFStringRef * keys = NULL; CFStringRef * values = NULL;
typeID = CFGetTypeID(cfObj);
if (typeID == CFDictionaryGetTypeID()) {
CFDictionaryRef dict = (CFDictionaryRef)cfObj;
CFIndex count, i;
count = CFDictionaryGetCount(dict);
keys = (CFStringRef *)malloc(count * sizeof(CFStringRef));
values = (CFStringRef *)malloc(count * sizeof(CFTypeRef));
CFDictionaryGetKeysAndValues(dict, (const void **)keys,
(const void **)values);
for (i = 0; i < count; i++) {
CFArrayAppendValue(propPathArray, keys[i]);
localResult = __KXKextCheckPersonalityTypes(aKext, values[i], propPathArray);
CFArrayRemoveValueAtIndex(propPathArray,
CFArrayGetCount(propPathArray) - 1);
if (!localResult) {
result = false;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
}
} else if (typeID == CFArrayGetTypeID()) {
CFArrayRef array = (CFArrayRef)cfObj;
CFIndex count, i;
count = CFArrayGetCount(array);
for (i = 0; i < count; i++) {
arrayIndexString = CFStringCreateWithFormat(kCFAllocatorDefault, NULL,
CFSTR("[%d]"), i);
if (!arrayIndexString) {
result = false;
goto finish;
}
CFArrayAppendValue(propPathArray, arrayIndexString);
CFRelease(arrayIndexString);
arrayIndexString = NULL;
localResult = __KXKextCheckPersonalityTypes(aKext,
CFArrayGetValueAtIndex(array, i),
propPathArray);
CFArrayRemoveValueAtIndex(propPathArray,
CFArrayGetCount(propPathArray) - 1);
if (!localResult) {
result = false;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
}
} else if (typeID == CFStringGetTypeID() || typeID == CFDataGetTypeID() ||
typeID == CFBooleanGetTypeID()) {
} else if (typeID == CFNumberGetTypeID()) {
CFNumberRef number = (CFNumberRef)cfObj;
if (CFNumberIsFloatType(number)) {
foundInvalidType = true;
}
} else {
foundInvalidType = true;
}
if (foundInvalidType) {
illegalTypeProperties = __KXKextGetIllegalTypeProperties(aKext);
if (!illegalTypeProperties) return false;
propPathString = CFStringCreateByCombiningStrings(
kCFAllocatorDefault, propPathArray, CFSTR(":"));
if (!propPathString) return false;
CFArrayAppendValue(illegalTypeProperties, propPathString);
CFRelease(propPathString);
propPathString = NULL;
result = false;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
finish:
if (keys) free(keys);
if (values) free(values);
if (arrayIndexString) CFRelease(arrayIndexString);
if (propPathString) CFRelease(propPathString);
return result;
}
static KXKextManagerError __KXKextAuthenticateURLAndParents(KXKextRef aKext,
CFURLRef anURL,
CFURLRef topURL ,
CFMutableDictionaryRef checkedURLs)
{
KXKextManagerError result = kKXKextManagerErrorNone;
KXKextManagerError checkResult = kKXKextManagerErrorNone;
CFURLRef backscanURL = NULL; char * anURL_path = NULL; char * topURL_path = NULL;
backscanURL = PATH_CopyCanonicalizedURL(anURL);
if (!backscanURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
anURL_path = PATH_CanonicalizedCStringForURL(backscanURL);
topURL_path = PATH_CanonicalizedCStringForURL(topURL);
if (strncmp(anURL_path, topURL_path, strlen(topURL_path))) {
(_KMErrLog(aKext->manager))("\"%s\" is not contained within \"%s\"",
anURL_path, topURL_path);
result = kKXKextManagerErrorUnspecified;
goto finish;
}
while (!CFEqual(backscanURL, topURL)) {
CFURLRef parentURL = NULL;
if (!CFDictionaryGetValue(checkedURLs, backscanURL)) {
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
const char * file_path =
PATH_CanonicalizedCStringForURL(backscanURL);
if (file_path) {
(_KMLog(aKext->manager))(
"authenticating file/directory \"%s\"",
file_path);
free((char *)file_path);
}
}
checkResult = __KXKextAuthenticateURL(aKext, backscanURL);
if (checkResult != kKXKextManagerErrorNone) {
result = checkResult;
if (result == kKXKextManagerErrorNoMemory ||
!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
}
CFDictionarySetValue(checkedURLs, backscanURL, kCFBooleanTrue);
parentURL = CFURLCreateCopyDeletingLastPathComponent(
kCFAllocatorDefault, backscanURL);
if (!parentURL) {
result = kKXKextManagerErrorUnspecified;
goto finish;
}
CFRelease(backscanURL);
backscanURL = parentURL;
parentURL = NULL;
}
finish:
if (backscanURL) CFRelease(backscanURL);
if (anURL_path) free(anURL_path);
if (topURL_path) free(topURL_path);
return result;
}
static KXKextManagerError __KXKextAuthenticateURL(KXKextRef aKext,
CFURLRef anURL)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFMutableArrayRef missingFiles = NULL;
CFMutableArrayRef badOwnerPermsFiles = NULL;
CFURLRef absURL = NULL; CFStringRef urlPath = NULL; char path[MAXPATHLEN];
struct stat stat_buf;
absURL = PATH_CopyCanonicalizedURL(anURL);
if (!absURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
urlPath = CFURLCopyFileSystemPath(absURL, kCFURLPOSIXPathStyle);
if (!urlPath) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (!CFStringGetCString(urlPath, path, sizeof(path),
kCFStringEncodingMacRoman)) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (stat(path, &stat_buf) != 0) {
if (errno == ENOENT) {
missingFiles = __KXKextGetMissingFiles(aKext);
if (missingFiles &&
kCFNotFound == CFArrayGetFirstIndexOfValue(missingFiles,
CFRangeMake(0, CFArrayGetCount(missingFiles)),
urlPath)) {
CFArrayAppendValue(missingFiles, urlPath);
}
result = kKXKextManagerErrorValidation;
goto finish;
} else {
perror(path);
result = kKXKextManagerErrorUnspecified;
goto finish;
}
}
if ( (stat_buf.st_uid != 0) || (stat_buf.st_gid != 0 ) ||
(stat_buf.st_mode & S_IWOTH) || (stat_buf.st_mode & S_IWGRP) ) {
badOwnerPermsFiles = __KXKextGetBadOwnerPermsFiles(aKext);
if (badOwnerPermsFiles &&
kCFNotFound == CFArrayGetFirstIndexOfValue(badOwnerPermsFiles,
CFRangeMake(0, CFArrayGetCount(badOwnerPermsFiles)),
urlPath)) {
CFArrayAppendValue(badOwnerPermsFiles, urlPath);
}
result = kKXKextManagerErrorAuthentication;
goto finish;
}
finish:
if (absURL) CFRelease(absURL);
if (urlPath) CFRelease(urlPath);
return result;
}
static KXKextManagerError __KXKextMakeFTSEntrySecure(
KXKextRef aKext,
FTSENT * ftsentry)
{
KXKextManagerError result = kKXKextManagerErrorNone;
int change_result = 0;
mode_t fixed_mode = 0;
change_result = chown(ftsentry->fts_path, 0, 0); if (change_result != 0) {
(_KMErrLog(aKext->manager))("can't change ownership/group of %s",
ftsentry->fts_path);
result = kKXKextManagerErrorFileAccess;
goto finish;
}
if (ftsentry->fts_statp->st_mode & S_IFDIR) {
fixed_mode = 0755; } else {
fixed_mode = 0644; }
change_result = chmod(ftsentry->fts_path, fixed_mode);
if (change_result != 0) {
(_KMErrLog(aKext->manager))("can't change permissions on %s",
ftsentry->fts_path);
result = kKXKextManagerErrorFileAccess;
goto finish;
}
finish:
return result;
}
static KXKextManagerError __KXKextCheckKmod(KXKextRef aKext,
CFURLRef kmodURL,
Boolean requiresNewKextManager)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFURLRef absoluteKmodURL = 0; int fd = -1;
mach_port_t host_port = PORT_NULL;
struct stat stat_buf;
long object_addr;
long object_size;
struct mach_header *mh;
kmod_info_t * kmod_info;
CFStringRef executablePath = 0; char module_path[MAXPATHLEN];
UInt32 version;
CFStringRef bundleIdentifier = 0; CFStringRef kmodName = 0;
struct nlist nl[] = {
{ "_kmod_info" },
{ "" },
};
absoluteKmodURL = PATH_CopyCanonicalizedURL(kmodURL);
if (!absoluteKmodURL) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
executablePath = CFURLCopyFileSystemPath(absoluteKmodURL,
kCFURLPOSIXPathStyle);
if (!executablePath) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (!CFStringGetCString(executablePath,
module_path, sizeof(module_path) - 1, kCFStringEncodingMacRoman)) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if ((fd = open(module_path, O_RDONLY)) == -1) {
(_KMErrLog(aKext->manager))("can't open %s", module_path);
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyFileAccess,
kCFBooleanTrue);
result = kKXKextManagerErrorFileAccess;
goto finish;
}
if (nlist(module_path, nl)) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyExecutableBad,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
goto finish;
}
if (requiresNewKextManager) {
goto finish;
}
if (fstat(fd, &stat_buf) == -1) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyFileAccess,
kCFBooleanTrue);
result = kKXKextManagerErrorFileAccess;
goto finish; }
object_size = stat_buf.st_size;
if (map_fd(fd, 0, (vm_offset_t *)&object_addr, TRUE, object_size) !=
KERN_SUCCESS) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyFileAccess,
kCFBooleanTrue);
result = kKXKextManagerErrorFileAccess;
goto finish; }
if (NXSwapBigLongToHost(*((long *)object_addr)) == FAT_MAGIC) {
struct host_basic_info hbi;
struct fat_header *fh;
struct fat_arch *fat_archs, *fap;
unsigned i, nfat_arch;
i = HOST_BASIC_INFO_COUNT;
host_port = mach_host_self();
if (host_info(host_port, HOST_BASIC_INFO,
(host_info_t)(&hbi), &i) != KERN_SUCCESS) {
result = kKXKextManagerErrorUnspecified;
goto finish; }
fh = (struct fat_header *)object_addr;
nfat_arch = NXSwapBigLongToHost(fh->nfat_arch);
fat_archs = (struct fat_arch *)((char *)fh + sizeof(struct fat_header));
for (i = 0; i < nfat_arch; i++) {
fat_archs[i].cputype =
NXSwapBigLongToHost(fat_archs[i].cputype);
fat_archs[i].cpusubtype =
NXSwapBigLongToHost(fat_archs[i].cpusubtype);
fat_archs[i].offset =
NXSwapBigLongToHost(fat_archs[i].offset);
fat_archs[i].size =
NXSwapBigLongToHost(fat_archs[i].size);
fat_archs[i].align =
NXSwapBigLongToHost(fat_archs[i].align);
}
#define CPUSUBTYPE_SUPPORT 0
#if CPUSUBTYPE_SUPPORT
fap = cpusubtype_getbestarch(hbi.cpu_type, hbi.cpu_subtype,
fat_archs, nfat_arch);
#else CPUSUBTYPE_SUPPORT
#warning Use the cpusubtype functions!!!
fap = NULL;
for (i = 0; i < nfat_arch; i++) {
if (fat_archs[i].cputype == hbi.cpu_type) {
fap = &fat_archs[i];
break;
}
}
#endif CPUSUBTYPE_SUPPORT
if (!fap) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyExecutableBadArch,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
goto finish; }
object_addr += fap->offset;
object_size = fap->size;
}
mh = (struct mach_header *)object_addr;
if (*((long *)mh) != MH_MAGIC) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyExecutableBad,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
goto finish; }
kmod_info = (kmod_info_t *)(object_addr + sizeof(struct mach_header) +
mh->sizeofcmds + nl->n_value);
bundleIdentifier = (CFStringRef)CFDictionaryGetValue(aKext->infoDictionary,
CFSTR("CFBundleIdentifier"));
kmodName = CFStringCreateWithCString(kCFAllocatorDefault,
kmod_info->name, kCFStringEncodingMacRoman);
if (!kmodName) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (CFStringCompare(bundleIdentifier , kmodName, NULL) !=
kCFCompareEqualTo) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyBundleIdentifierMismatch,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
if (VERS_parse_string(kmod_info->version, &version)) {
if (aKext->version != version) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyBundleVersionMismatch,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
if (!KXKextManagerPerformsFullTests(aKext->manager)) goto finish;
}
} else {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyBundleVersionMismatch,
kCFBooleanTrue);
result = kKXKextManagerErrorValidation;
goto finish;
}
finish:
if (PORT_NULL != host_port) {
mach_port_deallocate(mach_task_self(), host_port);
}
if (fd != -1) close(fd);
if (absoluteKmodURL) CFRelease(absoluteKmodURL);
if (executablePath) CFRelease(executablePath);
if (kmodName) CFRelease(kmodName);
return result;
}
static KXKextManagerError __KXKextResolveDependencies(KXKextRef aKext,
unsigned int recursionDepth)
{
KXKextManagerError result = kKXKextManagerErrorNone;
KXKextManagerRef manager = KXKextGetManager(aKext);
CFIndex count, i;
CFDictionaryRef libraries = NULL;
CFStringRef * libraryIDs = NULL; CFStringRef * libraryVersions = NULL;
KXKextManagerError localResult = kKXKextManagerErrorNone;
if (!aKext->flags.canResolveDependencies) {
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext); if (kext_name && __KXKextCheckLogLevel(aKext,
kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
(_KMErrLog(aKext->manager))(
"%s has validation failures that prevent resolution of dependencies",
kext_name);
}
result = kKXKextManagerErrorUnspecified;
goto finish;
}
if (aKext->flags.isKernelResource) {
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext); const char * message;
message = "%s is a kernel resource and thus has no dependencies";
if (kext_name) {
(_KMLog(aKext->manager))(message, kext_name);
}
if (kext_name) free((char *)kext_name);
}
aKext->flags.hasAllDependencies = 1;
result = kKXKextManagerErrorNone;
goto finish;
}
if (aKext->flags.hasAllDependencies) {
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext);
if (kext_name) {
(_KMLog(aKext->manager))(
"extension %s has already resolved its dependencies", kext_name);
}
if (kext_name) free((char *)kext_name);
}
result = kKXKextManagerErrorNone;
goto finish;
}
if (recursionDepth > 255) {
CFDictionarySetValue(__KXKextGetOrCreateValidationFailures(aKext),
kKXKextErrorKeyPossibleDependencyLoop,
kCFBooleanTrue);
result = kKXKextManagerErrorDependencyLoop;
goto finish;
}
if (aKext->directDependencies) {
CFArrayRemoveAllValues(aKext->directDependencies);
} else {
aKext->directDependencies = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!aKext->directDependencies) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
}
if (aKext->missingDependencies) {
CFDictionaryRemoveAllValues(aKext->missingDependencies);
} else {
aKext->missingDependencies = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!aKext->missingDependencies) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
}
libraries = CFDictionaryGetValue(aKext->infoDictionary,
CFSTR("OSBundleLibraries"));
if (!libraries) {
result = kKXKextManagerErrorValidation;
goto finish;
}
count = CFDictionaryGetCount(libraries);
if (!count) {
result = kKXKextManagerErrorValidation;
goto finish;
}
libraryIDs = (CFStringRef *)malloc(count * sizeof(CFStringRef));
libraryVersions = (CFStringRef *)malloc(count * sizeof(CFStringRef));
if (!libraryIDs || !libraryVersions) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
CFDictionaryGetKeysAndValues(libraries, (const void **)libraryIDs,
(const void **)libraryVersions);
for (i = 0; i < count; i++) {
KXKextRef thisDependency;
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails, kKXKextLogLevelDetails, false)) {
Boolean got_id, got_vers;
char dep_id[255];
char dep_vers[255];
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext);
got_id = CFStringGetCString(libraryIDs[i],
dep_id, sizeof(dep_id) - 1, kCFStringEncodingMacRoman);
got_vers = CFStringGetCString(libraryVersions[i],
dep_vers, sizeof(dep_vers) - 1, kCFStringEncodingMacRoman);
if (got_id && got_vers && kext_name) {
(_KMLog(aKext->manager))(
"looking for dependency of extension %s with ID %s, "
"compatible with version %s",
kext_name, dep_id, dep_vers);
}
if (kext_name) free((char *)kext_name);
}
thisDependency =
KXKextManagerGetKextWithIdentifierCompatibleWithVersionString(
manager, libraryIDs[i], libraryVersions[i]);
if (thisDependency) {
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext);
const char * dep_name =
_KXKextCopyCanonicalPathnameAsCString(thisDependency);
if (kext_name && dep_name) {
(_KMLog(aKext->manager))(
"found compatible dependency from extension %s to %s; "
"resolving its dependencies",
kext_name, dep_name);
}
if (kext_name) free((char *)kext_name);
if (dep_name) free((char *)dep_name);
}
localResult = __KXKextResolveDependencies(thisDependency,
recursionDepth + 1);
if (localResult == kKXKextManagerErrorNone) {
CFArrayAppendValue(aKext->directDependencies, thisDependency);
} else {
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext);
const char * dep_name =
_KXKextCopyCanonicalPathnameAsCString(thisDependency);
if (kext_name && dep_name) {
(_KMLog(aKext->manager))(
"failed to resolve dependencies for extension %s",
dep_name);
}
if (kext_name) free((char *)kext_name);
if (dep_name) free((char *)dep_name);
}
CFDictionarySetValue(aKext->missingDependencies, libraryIDs[i],
kKXKextIndirectDependencyUnresolvable);
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
} else {
KXKextRef incompatibleDependency =
KXKextManagerGetKextWithIdentifier(manager, libraryIDs[i]);
if (incompatibleDependency) {
if (!_KXKextGetCompatibleVersion(incompatibleDependency)) {
CFDictionarySetValue(aKext->missingDependencies,
libraryIDs[i],
kKXKextDependencyCompatibleVersionUndeclared);
} else {
CFDictionarySetValue(aKext->missingDependencies,
libraryIDs[i], kKXKextDependencyNoCompatibleVersion);
}
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext);
char dep_id[255];
if (kext_name && CFStringGetCString(libraryIDs[i],
dep_id, sizeof(dep_id) - 1, kCFStringEncodingMacRoman)) {
(_KMLog(aKext->manager))(
"can't resolve dependency from %s to ID %s; "
"no compatible version of ID %s is known",
kext_name, dep_id, dep_id);
}
if (kext_name) free((char *)kext_name);
}
} else { CFDictionarySetValue(aKext->missingDependencies, libraryIDs[i],
kKXKextDependencyUnavailable);
if (__KXKextCheckLogLevel(aKext, kKXKextManagerLogLevelKextDetails,
kKXKextLogLevelDetails, false)) {
const char * kext_name =
_KXKextCopyCanonicalPathnameAsCString(aKext);
char dep_id[255];
if (kext_name && CFStringGetCString(libraryIDs[i],
dep_id, sizeof(dep_id) - 1, kCFStringEncodingMacRoman)) {
(_KMErrLog(aKext->manager))(
"can't resolve dependency from extension %s to ID %s; "
"no extension with ID %s is known",
kext_name, dep_id, dep_id);
}
if (kext_name) free((char *)kext_name);
}
}
result = kKXKextManagerErrorDependency;
if (!KXKextManagerPerformsFullTests(aKext->manager)) {
goto finish;
}
}
}
if (result == kKXKextManagerErrorNone) {
aKext->flags.hasAllDependencies = 1;
}
finish:
if (libraryIDs) free(libraryIDs);
if (libraryVersions) free(libraryVersions);
return result;
}
static char * __KXKextCopyDgraphEntryName(KXKextRef aKext)
{
KXKextManagerError checkResult = kKXKextManagerErrorNone;
CFStringRef bundleID = NULL; CFURLRef executableURL = NULL; char * kmod_path = NULL; char * bundle_identifier = NULL; char * entry_name = NULL; size_t size;
int error = 0;
checkResult = __KXKextRealizeFromCache(aKext);
if (checkResult != kKXKextManagerErrorNone) {
error = 1;
goto finish;
}
if (KXKextGetIsKernelResource(aKext)) {
bundleID = KXKextGetBundleIdentifier(aKext);
size = (sizeof(char) * MAXPATHLEN);
bundle_identifier = (char *)malloc(size);
if (!bundle_identifier) {
error = 1;
goto finish;
}
if (!CFStringGetCString(bundleID,
bundle_identifier, size - 1, kCFStringEncodingMacRoman)) {
error = 1;
goto finish;
}
entry_name = bundle_identifier;
} else {
executableURL = CFBundleCopyExecutableURL(aKext->bundle);
if (!executableURL) {
error = 1;
goto finish;
}
kmod_path = PATH_CanonicalizedCStringForURL(executableURL);
if (!kmod_path) {
error = 1;
goto finish;
}
entry_name = kmod_path;
}
finish:
if (error && entry_name) {
free(entry_name);
entry_name = NULL;
}
if (executableURL) CFRelease(executableURL);
return entry_name;
}
static char * __KXKextCopyDgraphKmodName(KXKextRef aKext)
{
CFStringRef bundleID = NULL; char * bundle_identifier = NULL; CFIndex length;
int error = 0;
bundleID = KXKextGetBundleIdentifier(aKext);
length = 1 + CFStringGetLength(bundleID);
bundle_identifier = (char *)malloc(length);
if (!bundle_identifier) {
goto finish;
}
if (!CFStringGetCString(bundleID,
bundle_identifier, length, kCFStringEncodingMacRoman)) {
error = 1;
goto finish;
}
finish:
if (error && bundle_identifier) {
free(bundle_identifier);
bundle_identifier = NULL;
}
return bundle_identifier;
}
static Boolean __KXKextAddDependenciesToDgraph(KXKextRef aKext,
CFArrayRef dependencies,
dgraph_t * dgraph)
{
Boolean result = true;
char * entry_name = NULL; char * expected_kmod_name = NULL; dgraph_entry_t * aKext_entry = NULL; CFIndex count, i;
if (KXKextGetDeclaresExecutable(aKext)) {
entry_name = __KXKextCopyDgraphEntryName(aKext);
if (!entry_name) {
result = false;
goto finish;
}
expected_kmod_name = __KXKextCopyDgraphKmodName(aKext);
if (!expected_kmod_name) {
result = false;
goto finish;
}
aKext_entry = dgraph_add_dependent(dgraph, entry_name,
expected_kmod_name, aKext->version,
0, KXKextGetIsKernelResource(aKext));
if (!aKext_entry) {
result = false;
goto finish;
}
free(entry_name);
entry_name = NULL;
free(expected_kmod_name);
expected_kmod_name = NULL;
}
if (!dependencies) {
goto finish;
}
count = CFArrayGetCount(dependencies);
for (i = 0; i < count; i++) {
KXKextRef thisKext = (KXKextRef)CFArrayGetValueAtIndex(
dependencies, i);
if (KXKextGetDeclaresExecutable(thisKext)) {
entry_name = __KXKextCopyDgraphEntryName(thisKext);
if (!entry_name) {
result = false;
goto finish;
}
if (expected_kmod_name) {
free(expected_kmod_name);
expected_kmod_name = NULL;
}
expected_kmod_name = __KXKextCopyDgraphKmodName(thisKext);
if (!expected_kmod_name) {
result = false;
goto finish;
}
if (!dgraph_add_dependency(dgraph, aKext_entry, entry_name,
expected_kmod_name, thisKext->version,
0, KXKextGetIsKernelResource(thisKext))) {
result = false;
goto finish;
}
if (!__KXKextAddDependenciesToDgraph(thisKext,
KXKextGetDirectDependencies(thisKext), dgraph)) {
result = false;
goto finish;
}
free(entry_name);
entry_name = NULL;
} else {
if (!__KXKextAddDependenciesToDgraph(aKext,
KXKextGetDirectDependencies(thisKext), dgraph)) {
result = false;
goto finish;
}
}
}
finish:
if (expected_kmod_name) free(expected_kmod_name);
if (entry_name) free(entry_name);
return result;
}
static void __KXKextAddDependenciesToArray(KXKextRef aKext,
CFMutableArrayRef dependencyArray)
{
if (aKext->directDependencies) {
CFIndex dCount, dIndex;
CFIndex aCount, aIndex;
dCount = CFArrayGetCount(aKext->directDependencies);
for (dIndex = 0; dIndex < dCount; dIndex ++) {
KXKextRef thisDependency = (KXKextRef)CFArrayGetValueAtIndex(
aKext->directDependencies, dIndex);
__KXKextAddDependenciesToArray(thisDependency, dependencyArray);
}
aCount = CFArrayGetCount(dependencyArray);
for (dIndex = 0; dIndex < dCount; dIndex ++) {
Boolean gotItAlready = false;
KXKextRef thisDependency = (KXKextRef)CFArrayGetValueAtIndex(
aKext->directDependencies, dIndex);
for (aIndex = 0; aIndex < aCount; aIndex ++) {
KXKextRef checkDependency = (KXKextRef)CFArrayGetValueAtIndex(
dependencyArray, aIndex);
if (thisDependency == checkDependency) {
gotItAlready = true;
break;
}
}
if (!gotItAlready) {
CFArrayAppendValue(dependencyArray, thisDependency);
}
}
}
return;
}
KXKextManagerError __KXKextRealizeFromCache(KXKextRef aKext)
{
KXKextManagerError result = kKXKextManagerErrorNone;
CFStringRef absBundlePath = NULL; CFDictionaryRef bundleInfoDictionary = NULL; CFDictionaryRef comparisonInfoDictionary = NULL;
if (aKext->bundle) goto finish;
aKext->bundle = CFBundleCreate(kCFAllocatorDefault, aKext->bundleURL);
if (!aKext->bundle) {
result = kKXKextManagerErrorCache;
goto finish;
}
bundleInfoDictionary = CFBundleGetInfoDictionary(aKext->bundle);
comparisonInfoDictionary = __KXKextCopyInfoDictionaryForCache(
aKext, bundleInfoDictionary, false );
if (!comparisonInfoDictionary) {
result = kKXKextManagerErrorNoMemory;
goto finish;
}
if (!CFEqual(aKext->infoDictionary, comparisonInfoDictionary)) {
result = kKXKextManagerErrorCache;
goto finish;
}
CFRelease(aKext->infoDictionary); aKext->infoDictionary = bundleInfoDictionary; CFRetain(bundleInfoDictionary);
if (!KXKextIsFromCache(aKext) &&
!__KXKextCheckStringProperty(aKext, aKext->infoDictionary,
CFSTR("CFBundlePackageType"), NULL, true, CFSTR("KEXT"), NULL)) {
result = kKXKextManagerErrorCache;
goto finish;
}
finish:
if (absBundlePath) CFRelease(absBundlePath);
if (comparisonInfoDictionary) CFRelease(comparisonInfoDictionary);
return result;
}
typedef struct cacheKeySubs {
CFStringRef longKey;
CFStringRef shortKey;
Boolean required;
} __KXKextCacheKeySubs;
#define NUM_INFO_DICT_SUB_KEYS (14)
static __KXKextCacheKeySubs __gInfoDictSubKeys[NUM_INFO_DICT_SUB_KEYS];
#if 0
#define NUM_PERSONALITY_SUB_KEYS (4)
static __KXKextCacheKeySubs __gPersonalitySubKeys[NUM_PERSONALITY_SUB_KEYS];
#endif 0
static void __initSubKeys(void) {
static Boolean didIt = false;
if (didIt) return;
__gInfoDictSubKeys[0].longKey = CFSTR("CFBundleInfoDictionaryVersion");
__gInfoDictSubKeys[0].shortKey = CFSTR("d");
__gInfoDictSubKeys[0].required = true;
__gInfoDictSubKeys[1].longKey = CFSTR("CFBundleGetInfoString");
__gInfoDictSubKeys[1].shortKey = CFSTR("g");
__gInfoDictSubKeys[1].required = false;
__gInfoDictSubKeys[2].longKey = CFSTR("CFBundleIdentifier");
__gInfoDictSubKeys[2].shortKey = CFSTR("i");
__gInfoDictSubKeys[2].required = true;
__gInfoDictSubKeys[3].longKey = CFSTR("CFBundleExecutable");
__gInfoDictSubKeys[3].shortKey = CFSTR("x");
__gInfoDictSubKeys[3].required = false;
__gInfoDictSubKeys[4].longKey = CFSTR("CFBundleName");
__gInfoDictSubKeys[4].shortKey = CFSTR("n");
__gInfoDictSubKeys[4].required = false;
__gInfoDictSubKeys[5].longKey = CFSTR("CFBundleShortVersionString");
__gInfoDictSubKeys[5].shortKey = CFSTR("s");
__gInfoDictSubKeys[5].required = false;
__gInfoDictSubKeys[6].longKey = CFSTR("CFBundleVersion");
__gInfoDictSubKeys[6].shortKey = CFSTR("v");
__gInfoDictSubKeys[6].required = true;
__gInfoDictSubKeys[7].longKey = CFSTR("NSHumanReadableCopyright");
__gInfoDictSubKeys[7].shortKey = CFSTR("c");
__gInfoDictSubKeys[7].required = false;
__gInfoDictSubKeys[8].longKey = CFSTR("OSBundleCompatibleVersion");
__gInfoDictSubKeys[8].shortKey = CFSTR("cv");
__gInfoDictSubKeys[8].required = false;
__gInfoDictSubKeys[9].longKey = CFSTR("OSBundleRequired");
__gInfoDictSubKeys[9].shortKey = CFSTR("r");
__gInfoDictSubKeys[9].required = false;
__gInfoDictSubKeys[10].longKey = CFSTR("IOKitPersonalities");
__gInfoDictSubKeys[10].shortKey = CFSTR("p");
__gInfoDictSubKeys[10].required = false;
__gInfoDictSubKeys[11].longKey = CFSTR("OSBundleLibraries");
__gInfoDictSubKeys[11].shortKey = CFSTR("l");
__gInfoDictSubKeys[11].required = false;
__gInfoDictSubKeys[12].longKey = CFSTR("OSKernelResource");
__gInfoDictSubKeys[12].shortKey = CFSTR("k");
__gInfoDictSubKeys[12].required = false;
__gInfoDictSubKeys[13].longKey = CFSTR("OSBundleDebugLevel");
__gInfoDictSubKeys[13].shortKey = CFSTR("db");
__gInfoDictSubKeys[13].required = false;
#if 0
__gPersonalitySubKeys[0].longKey = CFSTR("CFBundleIdentifier");
__gPersonalitySubKeys[0].shortKey = CFSTR("i");
__gPersonalitySubKeys[0].required = false;
__gPersonalitySubKeys[1].longKey = CFSTR("IOClass");
__gPersonalitySubKeys[1].shortKey = CFSTR("ioc");
__gPersonalitySubKeys[1].required = false;
__gPersonalitySubKeys[2].longKey = CFSTR("IONameMatch");
__gPersonalitySubKeys[2].shortKey = CFSTR("ionm");
__gPersonalitySubKeys[2].required = false;
__gPersonalitySubKeys[3].longKey = CFSTR("IOProviderClass");
__gPersonalitySubKeys[3].shortKey = CFSTR("iopc");
__gPersonalitySubKeys[3].required = false;
#endif 0
didIt = true;
return;
}
static Boolean __KXKextCacheEntry(
KXKextRef aKext,
CFDictionaryRef infoDict,
CFMutableDictionaryRef cDict,
unsigned subKeyIndex,
Boolean makeSubstitutions)
{
Boolean result = true;
Boolean error = false;
CFTypeRef infoDictValue = NULL; CFTypeRef cDictEntry = NULL;
__initSubKeys();
infoDictValue = CFDictionaryGetValue(infoDict,
__gInfoDictSubKeys[subKeyIndex].longKey);
if (!infoDictValue) {
if (__gInfoDictSubKeys[subKeyIndex].required) {
result = false;
}
goto finish;
}
cDictEntry = __KXKextCopyPListForCache(aKext, infoDictValue, &error);
if (error) {
result = false;
goto finish;
}
if (cDictEntry) {
if (makeSubstitutions) {
CFDictionarySetValue(cDict,
__gInfoDictSubKeys[subKeyIndex].shortKey, cDictEntry);
} else {
CFDictionarySetValue(cDict,
__gInfoDictSubKeys[subKeyIndex].longKey, cDictEntry);
}
CFRelease(cDictEntry);
}
finish:
return result;
}
static Boolean __KXKextUncacheEntry(
KXKextRef aKext,
CFDictionaryRef cDict,
CFMutableDictionaryRef infoDict,
unsigned subKeyIndex,
Boolean makeSubstitutions)
{
Boolean result = true;
CFTypeRef infoDictValue = NULL;
__initSubKeys();
if (makeSubstitutions) {
infoDictValue = CFDictionaryGetValue(cDict,
__gInfoDictSubKeys[subKeyIndex].shortKey);
} else {
infoDictValue = CFDictionaryGetValue(cDict,
__gInfoDictSubKeys[subKeyIndex].longKey);
}
if (!infoDictValue) {
if (__gInfoDictSubKeys[subKeyIndex].required) {
result = false;
}
goto finish;
}
CFDictionarySetValue(infoDict,
__gInfoDictSubKeys[subKeyIndex].longKey, infoDictValue);
finish:
return result;
}
CFDictionaryRef __KXKextCopyInfoDictionaryFromCache(
KXKextRef aKext,
CFDictionaryRef cDict,
Boolean makeSubstitutions)
{
CFMutableDictionaryRef infoDict = NULL; Boolean error = false;
unsigned int keyIndex;
__initSubKeys();
if (!cDict) {
goto finish;
}
infoDict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!infoDict) {
goto finish;
}
for (keyIndex = 0; keyIndex < NUM_INFO_DICT_SUB_KEYS; keyIndex++) {
if (!__KXKextUncacheEntry(aKext, cDict, infoDict, keyIndex,
makeSubstitutions)) {
error = true;
goto finish;
}
}
finish:
if (error) {
if (infoDict) CFRelease(infoDict);
infoDict = NULL;
}
return infoDict;
}
CFDictionaryRef __KXKextCopyInfoDictionaryForCache(
KXKextRef aKext,
CFDictionaryRef infoDict,
Boolean makeSubstitutions)
{
CFMutableDictionaryRef cDict = NULL; Boolean error = false;
unsigned int keyIndex;
__initSubKeys();
if (!infoDict) {
goto finish;
}
cDict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!cDict) {
goto finish;
}
for (keyIndex = 0; keyIndex < NUM_INFO_DICT_SUB_KEYS; keyIndex++) {
if (!__KXKextCacheEntry(aKext, infoDict, cDict, keyIndex,
makeSubstitutions)) {
error = true;
goto finish;
}
}
finish:
if (error) {
if (cDict) CFRelease(cDict);
cDict = NULL;
}
return cDict;
}
CFTypeRef __KXKextCopyPListForCache(
KXKextRef aKext,
CFTypeRef pList,
Boolean * error)
{
CFTypeRef cList = NULL; CFTypeID typeID = NULL;
if (!pList) {
goto finish;
}
if (error) {
*error = false;
}
typeID = CFGetTypeID(pList);
if (typeID == CFDictionaryGetTypeID()) {
CFDictionaryRef dict = (CFDictionaryRef)pList;
CFMutableDictionaryRef newDict = NULL; CFIndex count, i;
CFStringRef * keys = NULL; CFStringRef * values = NULL; count = CFDictionaryGetCount(dict);
keys = (CFStringRef *)malloc(count * sizeof(CFStringRef));
values = (CFStringRef *)malloc(count * sizeof(CFTypeRef));
newDict = CFDictionaryCreateMutable(
kCFAllocatorDefault, 0,
&kCFTypeDictionaryKeyCallBacks,
&kCFTypeDictionaryValueCallBacks);
if (!newDict) {
if (error) {
*error = true;
}
goto finish;
}
cList = newDict;
CFDictionaryGetKeysAndValues(dict, (const void **)keys,
(const void **)values);
for (i = 0; i < count; i++) {
CFTypeRef entry = __KXKextCopyPListForCache(aKext, values[i], error);
if (error && *error) {
CFRelease(newDict);
cList = NULL;
goto finish;
}
if (entry) {
CFDictionarySetValue(newDict, keys[i], entry);
CFRelease(entry);
}
}
free(keys);
free(values);
goto finish;
} else if (typeID == CFArrayGetTypeID()) {
CFArrayRef array = (CFArrayRef)pList;
CFMutableArrayRef newArray = NULL; CFIndex count, i;
count = CFArrayGetCount(array);
newArray = CFArrayCreateMutable(kCFAllocatorDefault, 0,
&kCFTypeArrayCallBacks);
if (!newArray) {
if (error) {
*error = true;
}
goto finish;
}
cList = newArray;
for (i = 0; i < count; i++) {
CFTypeRef entry = __KXKextCopyPListForCache(aKext,
CFArrayGetValueAtIndex(array, i), error);
if (error && *error) {
CFRelease(newArray);
cList = NULL;
goto finish;
}
if (entry) {
CFArrayAppendValue(newArray, entry);
CFRelease(entry);
}
}
goto finish;
} else if (typeID == CFStringGetTypeID() ||
typeID == CFDataGetTypeID() ||
typeID == CFNumberGetTypeID() ||
typeID == CFBooleanGetTypeID() ||
typeID == CFDateGetTypeID()) {
cList = pList;
CFRetain(cList); goto finish;
} else {
cList = NULL;
goto finish;
}
finish:
return cList;
}