X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/6d2010ae8f7a6078e10b361c6962983bab233e0f..cc8bc92ae4a8e9f1a1ab61bf83d34ad8150b3405:/libsa/bootstrap.cpp?ds=inline diff --git a/libsa/bootstrap.cpp b/libsa/bootstrap.cpp index 9ad023c1a..80a7508f3 100644 --- a/libsa/bootstrap.cpp +++ b/libsa/bootstrap.cpp @@ -1,5 +1,5 @@ /* - * Copyright (c) 2000 Apple Inc. All rights reserved. + * Copyright (c) 2000-2012 Apple Inc. All rights reserved. * * @APPLE_OSREFERENCE_LICENSE_HEADER_START@ * @@ -29,6 +29,10 @@ extern "C" { #include #include #include + +#if CONFIG_EMBEDDED +extern uuid_t kernelcache_uuid; +#endif } #include @@ -40,6 +44,10 @@ extern "C" { #include #include +#if __x86_64__ +#define KASLR_KEXT_DEBUG 0 +#endif + #if PRAGMA_MARK #pragma mark Bootstrap Declarations #endif @@ -67,6 +75,10 @@ static void bootstrapRecordStartupExtensions(void); static void bootstrapLoadSecurityExtensions(void); +#if NO_KEXTD +extern "C" bool IORamDiskBSDRoot(void); +#endif + #if PRAGMA_MARK #pragma mark Macros #endif @@ -100,23 +112,29 @@ static const char * sKernelComponentNames[] = { "com.apple.driver.AppleNMI", "com.apple.iokit.IOSystemManagementFamily", "com.apple.iokit.ApplePlatformFamily", - -#if defined(__i386__) || defined(__arm__) - /* These ones are not supported on x86_64 or any newer platforms. - * They must be version 7.9.9; check by "com.apple.kernel.", with - * the trailing period; "com.apple.kernel" always represents the - * current kernel version. - */ - "com.apple.kernel.6.0", - "com.apple.kernel.bsd", - "com.apple.kernel.iokit", - "com.apple.kernel.libkern", - "com.apple.kernel.mach", -#endif - NULL }; +static int __whereIsAddr(vm_offset_t theAddr, unsigned long * segSizes, vm_offset_t *segAddrs, int segCount ); + +#define PLK_SEGMENTS 12 + +static const char * plk_segNames[] = { + "__TEXT", + "__TEXT_EXEC", + "__DATA", + "__DATA_CONST", + "__LINKEDIT", + "__PRELINK_TEXT", + "__PLK_TEXT_EXEC", + "__PRELINK_DATA", + "__PLK_DATA_CONST", + "__PLK_LLVM_COV", + "__PLK_LINKEDIT", + "__PRELINK_INFO", + NULL +}; + #if PRAGMA_MARK #pragma mark KLDBootstrap Class #endif @@ -137,11 +155,9 @@ private: void readPrelinkedExtensions( kernel_section_t * prelinkInfoSect); void readBooterExtensions(void); - OSReturn readMkextExtensions( - OSString * deviceTreeName, - OSData * deviceTreeData); OSReturn loadKernelComponentKexts(void); + void loadKernelExternalComponents(void); void readBuiltinPersonalities(void); void loadSecurityExtensions(void); @@ -207,12 +223,18 @@ KLDBootstrap::readStartupExtensions(void) } loadKernelComponentKexts(); + loadKernelExternalComponents(); readBuiltinPersonalities(); OSKext::sendAllKextPersonalitiesToCatalog(); return; } +typedef struct kaslrPackedOffsets { + uint32_t count; /* number of offsets */ + uint32_t offsetsArray[]; /* offsets to slide */ +} kaslrPackedOffsets; + /********************************************************************* *********************************************************************/ void @@ -224,6 +246,9 @@ KLDBootstrap::readPrelinkedExtensions( OSDictionary * prelinkInfoDict = NULL; // do not release OSString * errorString = NULL; // must release OSKext * theKernel = NULL; // must release +#if CONFIG_EMBEDDED + OSData * kernelcacheUUID = NULL; // do not release +#endif kernel_segment_command_t * prelinkTextSegment = NULL; // see code kernel_segment_command_t * prelinkInfoSegment = NULL; // see code @@ -234,11 +259,6 @@ KLDBootstrap::readPrelinkedExtensions( void * prelinkData = NULL; // see code vm_size_t prelinkLength = 0; -#if !__LP64__ && !defined(__arm__) - vm_map_offset_t prelinkDataMapOffset = 0; - void * prelinkCopy = NULL; // see code - kern_return_t mem_result = KERN_SUCCESS; -#endif OSDictionary * infoDict = NULL; // do not release @@ -246,6 +266,14 @@ KLDBootstrap::readPrelinkedExtensions( OSNumber * prelinkCountObj = NULL; // must release u_int i = 0; +#if NO_KEXTD + bool ramDiskBoot; + bool developerDevice; + bool dontLoad; +#endif + OSData * kaslrOffsets = NULL; + unsigned long plk_segSizes[PLK_SEGMENTS]; + vm_offset_t plk_segAddrs[PLK_SEGMENTS]; OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | @@ -261,69 +289,60 @@ KLDBootstrap::readPrelinkedExtensions( goto finish; } +#if KASLR_KEXT_DEBUG + unsigned long scratchSize; + vm_offset_t scratchAddr; + + IOLog("kaslr: prelinked kernel address info: \n"); + + scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__TEXT", &scratchSize); + IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __TEXT \n", + (unsigned long)scratchAddr, + (unsigned long)(scratchAddr + scratchSize), + scratchSize); + + scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__DATA", &scratchSize); + IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __DATA \n", + (unsigned long)scratchAddr, + (unsigned long)(scratchAddr + scratchSize), + scratchSize); + + scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__LINKEDIT", &scratchSize); + IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __LINKEDIT \n", + (unsigned long)scratchAddr, + (unsigned long)(scratchAddr + scratchSize), + scratchSize); + + scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__KLD", &scratchSize); + IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __KLD \n", + (unsigned long)scratchAddr, + (unsigned long)(scratchAddr + scratchSize), + scratchSize); + + scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_TEXT", &scratchSize); + IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_TEXT \n", + (unsigned long)scratchAddr, + (unsigned long)(scratchAddr + scratchSize), + scratchSize); + + scratchAddr = (vm_offset_t) getsegdatafromheader(&_mh_execute_header, "__PRELINK_INFO", &scratchSize); + IOLog("kaslr: start 0x%lx end 0x%lx length %lu for __PRELINK_INFO \n", + (unsigned long)scratchAddr, + (unsigned long)(scratchAddr + scratchSize), + scratchSize); +#endif + prelinkData = (void *) prelinkTextSegment->vmaddr; prelinkLength = prelinkTextSegment->vmsize; -#if !__LP64__ && !__arm__ - /* XXX: arm's pmap implementation doesn't seem to let us do this */ + /* build arrays of plk info for later use */ + const char ** segNamePtr; - /* To enable paging and write/execute protections on the kext - * executables, we need to copy them out of the booter-created - * memory, reallocate that space with VM, then prelinkCopy them back in. - * This isn't necessary on LP64 because kexts have their own VM - * region on that architecture model. - */ - - mem_result = kmem_alloc(kernel_map, (vm_offset_t *)&prelinkCopy, - prelinkLength); - if (mem_result != KERN_SUCCESS) { - OSKextLog(/* kext */ NULL, - kOSKextLogErrorLevel | - kOSKextLogGeneralFlag | kOSKextLogArchiveFlag, - "Can't copy prelinked kexts' text for VM reassign."); - goto finish; + for (segNamePtr = &plk_segNames[0], i = 0; *segNamePtr && i < PLK_SEGMENTS; segNamePtr++, i++) { + plk_segSizes[i] = 0; + plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(&_mh_execute_header, *segNamePtr, &plk_segSizes[i]); } - /* Copy it out. - */ - memcpy(prelinkCopy, prelinkData, prelinkLength); - - /* Dump the booter memory. - */ - ml_static_mfree((vm_offset_t)prelinkData, prelinkLength); - - /* Set up the VM region. - */ - prelinkDataMapOffset = (vm_map_offset_t)(uintptr_t)prelinkData; - mem_result = vm_map_enter_mem_object( - kernel_map, - &prelinkDataMapOffset, - prelinkLength, /* mask */ 0, - VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE, - (ipc_port_t)NULL, - (vm_object_offset_t) 0, - /* copy */ FALSE, - /* cur_protection */ VM_PROT_ALL, - /* max_protection */ VM_PROT_ALL, - /* inheritance */ VM_INHERIT_DEFAULT); - if ((mem_result != KERN_SUCCESS) || - (prelinkTextSegment->vmaddr != prelinkDataMapOffset)) - { - OSKextLog(/* kext */ NULL, - kOSKextLogErrorLevel | - kOSKextLogGeneralFlag | kOSKextLogArchiveFlag, - "Can't create kexts' text VM entry at 0x%llx, length 0x%x (error 0x%x).", - (unsigned long long) prelinkDataMapOffset, prelinkLength, mem_result); - goto finish; - } - prelinkData = (void *)(uintptr_t)prelinkDataMapOffset; - - /* And copy it back. - */ - memcpy(prelinkData, prelinkCopy, prelinkLength); - - kmem_free(kernel_map, (vm_offset_t)prelinkCopy, prelinkLength); -#endif /* !__LP64__ && !__arm__*/ /* Unserialize the info dictionary from the prelink info section. */ @@ -345,6 +364,30 @@ KLDBootstrap::readPrelinkedExtensions( goto finish; } +#if NO_KEXTD + /* Check if we should keep developer kexts around. + * TODO: Check DeviceTree instead of a boot-arg + */ + developerDevice = true; + PE_parse_boot_argn("developer", &developerDevice, sizeof(developerDevice)); + + ramDiskBoot = IORamDiskBSDRoot(); +#endif /* NO_KEXTD */ + +#if CONFIG_EMBEDDED + /* Copy in the kernelcache UUID */ + kernelcacheUUID = OSDynamicCast(OSData, + prelinkInfoDict->getObject(kPrelinkInfoKCIDKey)); + if (!kernelcacheUUID) { + bzero(&kernelcache_uuid, sizeof(kernelcache_uuid)); + } else if (kernelcacheUUID->getLength() != sizeof(kernelcache_uuid)) { + panic("kernelcacheUUID length is %d, expected %lu", kernelcacheUUID->getLength(), + sizeof(kernelcache_uuid)); + } else { + memcpy((void *)&kernelcache_uuid, (void *)kernelcacheUUID->getBytesNoCopy(), kernelcacheUUID->getLength()); + } +#endif /* CONFIG_EMBEDDED */ + infoDictArray = OSDynamicCast(OSArray, prelinkInfoDict->getObject(kPrelinkInfoDictionaryKey)); if (!infoDictArray) { @@ -352,9 +395,18 @@ KLDBootstrap::readPrelinkedExtensions( "The prelinked kernel has no kext info dictionaries"); goto finish; } - - /* Create OSKext objects for each info dictionary. - */ + + /* kaslrOffsets are available use them to slide local relocations */ + kaslrOffsets = OSDynamicCast(OSData, + prelinkInfoDict->getObject(kPrelinkLinkKASLROffsetsKey)); + + /* Create dictionary of excluded kexts + */ +#ifndef CONFIG_EMBEDDED + OSKext::createExcludeListFromPrelinkInfo(infoDictArray); +#endif + /* Create OSKext objects for each info dictionary. + */ for (i = 0; i < infoDictArray->getCount(); ++i) { infoDict = OSDynamicCast(OSDictionary, infoDictArray->getObject(i)); if (!infoDict) { @@ -365,14 +417,101 @@ KLDBootstrap::readPrelinkedExtensions( continue; } +#if NO_KEXTD + dontLoad = false; + + /* If we're not on a developer device, skip and free developer kexts. + */ + if (developerDevice == false) { + OSBoolean *devOnlyBool = OSDynamicCast(OSBoolean, + infoDict->getObject(kOSBundleDeveloperOnlyKey)); + if (devOnlyBool == kOSBooleanTrue) { + dontLoad = true; + } + } + + /* Skip and free kexts that are only needed when booted from a ram disk. + */ + if (ramDiskBoot == false) { + OSBoolean *ramDiskOnlyBool = OSDynamicCast(OSBoolean, + infoDict->getObject(kOSBundleRamDiskOnlyKey)); + if (ramDiskOnlyBool == kOSBooleanTrue) { + dontLoad = true; + } + } + + if (dontLoad == true) { + OSString *bundleID = OSDynamicCast(OSString, + infoDict->getObject(kCFBundleIdentifierKey)); + if (bundleID) { + OSKextLog(NULL, kOSKextLogWarningLevel | kOSKextLogGeneralFlag, + "Kext %s not loading.", bundleID->getCStringNoCopy()); + } + + OSNumber *addressNum = OSDynamicCast(OSNumber, + infoDict->getObject(kPrelinkExecutableLoadKey)); + OSNumber *lengthNum = OSDynamicCast(OSNumber, + infoDict->getObject(kPrelinkExecutableSizeKey)); + if (addressNum && lengthNum) { +#if __arm__ || __arm64__ + vm_offset_t data = (vm_offset_t) ((addressNum->unsigned64BitValue()) + vm_kernel_slide); + vm_size_t length = (vm_size_t) (lengthNum->unsigned32BitValue()); + ml_static_mfree(data, length); +#else +#error Pick the right way to free prelinked data on this arch +#endif + } + + infoDictArray->removeObject(i--); + continue; + } +#endif /* NO_KEXTD */ + /* Create the kext for the entry, then release it, because the * kext system keeps them around until explicitly removed. * Any creation/registration failures are already logged for us. */ - OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict); + OSKext * newKext = OSKext::withPrelinkedInfoDict(infoDict, (kaslrOffsets ? TRUE : FALSE)); OSSafeReleaseNULL(newKext); } - + + /* slide kxld relocations */ + if (kaslrOffsets && vm_kernel_slide > 0) { + int slidKextAddrCount = 0; + int badSlideAddr = 0; + int badSlideTarget = 0; + + kaslrPackedOffsets * myOffsets = NULL; + myOffsets = (kaslrPackedOffsets *) kaslrOffsets->getBytesNoCopy(); + + for (uint32_t j = 0; j < myOffsets->count; j++) { + + uint64_t slideOffset = (uint64_t) myOffsets->offsetsArray[j]; + uintptr_t * slideAddr = (uintptr_t *) ((uint64_t)prelinkData + slideOffset); + int slideAddrSegIndex = -1; + int addrToSlideSegIndex = -1; + + slideAddrSegIndex = __whereIsAddr( (vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], PLK_SEGMENTS ); + if (slideAddrSegIndex >= 0) { + addrToSlideSegIndex = __whereIsAddr( (vm_offset_t)(*slideAddr + vm_kernel_slide), &plk_segSizes[0], &plk_segAddrs[0], PLK_SEGMENTS ); + if (addrToSlideSegIndex < 0) { + badSlideTarget++; + continue; + } + } + else { + badSlideAddr++; + continue; + } + + slidKextAddrCount++; + *(slideAddr) += vm_kernel_slide; + } // for ... + + /* All kexts are now slid, set VM protections for them */ + OSKext::setAllVMAttributes(); + } + /* Store the number of prelinked kexts in the registry so we can tell * when the system has been started from a prelinked kernel. */ @@ -386,7 +525,7 @@ KLDBootstrap::readPrelinkedExtensions( if (prelinkCountObj) { registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj); } - + OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag | @@ -394,12 +533,13 @@ KLDBootstrap::readPrelinkedExtensions( "%u prelinked kexts", infoDictArray->getCount()); -#if __LP64__ - /* On LP64 systems, kexts are copied to their own special VM region - * during OSKext init time, so we can free the whole segment now. +#if CONFIG_KEXT_BASEMENT + /* On CONFIG_KEXT_BASEMENT systems, kexts are copied to their own + * special VM region during OSKext init time, so we can free the whole + * segment now. */ ml_static_mfree((vm_offset_t) prelinkData, prelinkLength); -#endif /* __LP64__ */ +#endif /* __x86_64__ */ /* Free the prelink info segment, we're done with it. */ @@ -410,17 +550,33 @@ KLDBootstrap::readPrelinkedExtensions( } finish: - OSSafeRelease(errorString); - OSSafeRelease(parsedXML); - OSSafeRelease(theKernel); - OSSafeRelease(prelinkCountObj); + OSSafeReleaseNULL(errorString); + OSSafeReleaseNULL(parsedXML); + OSSafeReleaseNULL(theKernel); + OSSafeReleaseNULL(prelinkCountObj); return; } +static int __whereIsAddr(vm_offset_t theAddr, unsigned long * segSizes, vm_offset_t *segAddrs, int segCount) +{ + int i; + + for (i = 0; i < segCount; i++) { + vm_offset_t myAddr = *(segAddrs + i); + unsigned long mySize = *(segSizes + i); + + if (theAddr >= myAddr && theAddr < (myAddr + mySize)) { + return i; + } + } + + return -1; +} + + /********************************************************************* *********************************************************************/ #define BOOTER_KEXT_PREFIX "Driver-" -#define BOOTER_MKEXT_PREFIX "DriversPackage-" typedef struct _DeviceTreeBuffer { uint32_t paddr; @@ -444,7 +600,7 @@ KLDBootstrap::readBooterExtensions(void) OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | kOSKextLogDirectoryScanFlag | kOSKextLogKextBookkeepingFlag, - "Reading startup extensions/mkexts from booter memory."); + "Reading startup extensions from booter memory."); booterMemoryMap = IORegistryEntry::fromPath( "/chosen/memory-map", gIODTPlane); @@ -474,10 +630,16 @@ KLDBootstrap::readBooterExtensions(void) goto finish; } + /* Create dictionary of excluded kexts + */ +#ifndef CONFIG_EMBEDDED + OSKext::createExcludeListFromBooterData(propertyDict, keyIterator); +#endif + keyIterator->reset(); + while ( ( deviceTreeName = OSDynamicCast(OSString, keyIterator->getNextObject() ))) { - boolean_t isMkext = FALSE; const char * devTreeNameCString = deviceTreeName->getCStringNoCopy(); OSData * deviceTreeEntry = OSDynamicCast(OSData, propertyDict->getObject(deviceTreeName)); @@ -491,18 +653,10 @@ KLDBootstrap::readBooterExtensions(void) continue; } - /* Make sure it is either a kext or an mkext */ - if (!strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX, - CONST_STRLEN(BOOTER_KEXT_PREFIX))) { - - isMkext = FALSE; - - } else if (!strncmp(devTreeNameCString, BOOTER_MKEXT_PREFIX, - CONST_STRLEN(BOOTER_MKEXT_PREFIX))) { - - isMkext = TRUE; - - } else { + /* Make sure it is a kext */ + if (strncmp(devTreeNameCString, + BOOTER_KEXT_PREFIX, + CONST_STRLEN(BOOTER_KEXT_PREFIX))) { continue; } @@ -525,7 +679,7 @@ KLDBootstrap::readBooterExtensions(void) OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogDirectoryScanFlag, - "Can't get virtual address for device tree mkext entry %s.", + "Can't get virtual address for device tree entry %s.", devTreeNameCString); goto finish; } @@ -547,16 +701,12 @@ KLDBootstrap::readBooterExtensions(void) } booterData->setDeallocFunction(osdata_phys_free); - if (isMkext) { - readMkextExtensions(deviceTreeName, booterData); - } else { - /* Create the kext for the entry, then release it, because the - * kext system keeps them around until explicitly removed. - * Any creation/registration failures are already logged for us. - */ - OSKext * newKext = OSKext::withBooterData(deviceTreeName, booterData); - OSSafeRelease(newKext); - } + /* Create the kext for the entry, then release it, because the + * kext system keeps them around until explicitly removed. + * Any creation/registration failures are already logged for us. + */ + OSKext * newKext = OSKext::withBooterData(deviceTreeName, booterData); + OSSafeReleaseNULL(newKext); booterMemoryMap->removeProperty(deviceTreeName); @@ -564,57 +714,14 @@ KLDBootstrap::readBooterExtensions(void) finish: - OSSafeRelease(booterMemoryMap); - OSSafeRelease(propertyDict); - OSSafeRelease(keyIterator); - OSSafeRelease(booterData); - OSSafeRelease(aKext); + OSSafeReleaseNULL(booterMemoryMap); + OSSafeReleaseNULL(propertyDict); + OSSafeReleaseNULL(keyIterator); + OSSafeReleaseNULL(booterData); + OSSafeReleaseNULL(aKext); return; } -/********************************************************************* -*********************************************************************/ -OSReturn -KLDBootstrap::readMkextExtensions( - OSString * deviceTreeName, - OSData * booterData) -{ - OSReturn result = kOSReturnError; - - uint32_t checksum; - IORegistryEntry * registryRoot = NULL; // do not release - OSData * checksumObj = NULL; // must release - - OSKextLog(/* kext */ NULL, - kOSKextLogStepLevel | - kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag, - "Reading startup mkext archive from device tree entry %s.", - deviceTreeName->getCStringNoCopy()); - - /* If we successfully read the archive, - * then save the mkext's checksum in the IORegistry. - * assumes we'll only ever have one mkext to boot - */ - result = OSKext::readMkextArchive(booterData, &checksum); - if (result == kOSReturnSuccess) { - - OSKextLog(/* kext */ NULL, - kOSKextLogProgressLevel | - kOSKextLogArchiveFlag, - "Startup mkext archive has checksum 0x%x.", (int)checksum); - - registryRoot = IORegistryEntry::getRegistryRoot(); - assert(registryRoot); - checksumObj = OSData::withBytes((void *)&checksum, sizeof(checksum)); - assert(checksumObj); - if (checksumObj) { - registryRoot->setProperty(kOSStartupMkextCRC, checksumObj); - } - } - - return result; -} - /********************************************************************* *********************************************************************/ #define COM_APPLE "com.apple." @@ -665,7 +772,7 @@ KLDBootstrap::loadSecurityExtensions(void) } isSecurityKext = OSDynamicCast(OSBoolean, - theKext->getPropertyForHostArch("AppleSecurityExtension")); + theKext->getPropertyForHostArch(kAppleSecurityExtensionKey)); if (isSecurityKext && isSecurityKext->isTrue()) { OSKextLog(/* kext */ NULL, kOSKextLogStepLevel | @@ -677,8 +784,8 @@ KLDBootstrap::loadSecurityExtensions(void) } finish: - OSSafeRelease(keyIterator); - OSSafeRelease(extensionsDict); + OSSafeReleaseNULL(keyIterator); + OSSafeReleaseNULL(extensionsDict); return; } @@ -720,10 +827,84 @@ KLDBootstrap::loadKernelComponentKexts(void) } } - OSSafeRelease(theKext); + OSSafeReleaseNULL(theKext); return result; } +/********************************************************************* +* Ensure that Kernel External Components are loaded early in boot, +* before other kext personalities get sent to the IOCatalogue. These +* kexts are treated specially because they may provide the implementation +* for kernel-vended KPI, so they must register themselves before +* general purpose IOKit probing begins. +*********************************************************************/ + +#define COM_APPLE_KEC "com.apple.kec." + +void +KLDBootstrap::loadKernelExternalComponents(void) +{ + OSDictionary * extensionsDict = NULL; // must release + OSCollectionIterator * keyIterator = NULL; // must release + OSString * bundleID = NULL; // don't release + OSKext * theKext = NULL; // don't release + OSBoolean * isKernelExternalComponent = NULL; // don't release + + OSKextLog(/* kext */ NULL, + kOSKextLogStepLevel | + kOSKextLogLoadFlag, + "Loading Kernel External Components."); + + extensionsDict = OSKext::copyKexts(); + if (!extensionsDict) { + return; + } + + keyIterator = OSCollectionIterator::withCollection(extensionsDict); + if (!keyIterator) { + OSKextLog(/* kext */ NULL, + kOSKextLogErrorLevel | + kOSKextLogGeneralFlag, + "Failed to allocate iterator for Kernel External Components."); + goto finish; + } + + while ((bundleID = OSDynamicCast(OSString, keyIterator->getNextObject()))) { + + const char * bundle_id = bundleID->getCStringNoCopy(); + + /* Skip extensions whose bundle IDs don't start with "com.apple.kec.". + */ + if (!bundle_id || + (strncmp(bundle_id, COM_APPLE_KEC, CONST_STRLEN(COM_APPLE_KEC)) != 0)) { + + continue; + } + + theKext = OSDynamicCast(OSKext, extensionsDict->getObject(bundleID)); + if (!theKext) { + continue; + } + + isKernelExternalComponent = OSDynamicCast(OSBoolean, + theKext->getPropertyForHostArch(kAppleKernelExternalComponentKey)); + if (isKernelExternalComponent && isKernelExternalComponent->isTrue()) { + OSKextLog(/* kext */ NULL, + kOSKextLogStepLevel | + kOSKextLogLoadFlag, + "Loading kernel external component %s.", bundleID->getCStringNoCopy()); + OSKext::loadKextWithIdentifier(bundleID->getCStringNoCopy(), + /* allowDefer */ false); + } + } + +finish: + OSSafeReleaseNULL(keyIterator); + OSSafeReleaseNULL(extensionsDict); + + return; +} + /********************************************************************* *********************************************************************/ void @@ -838,10 +1019,10 @@ KLDBootstrap::readBuiltinPersonalities(void) gIOCatalogue->addDrivers(allPersonalities, false); finish: - OSSafeRelease(parsedXML); - OSSafeRelease(allPersonalities); - OSSafeRelease(errorString); - OSSafeRelease(personalitiesIterator); + OSSafeReleaseNULL(parsedXML); + OSSafeReleaseNULL(allPersonalities); + OSSafeReleaseNULL(errorString); + OSSafeReleaseNULL(personalitiesIterator); return; }