X-Git-Url: https://git.saurik.com/apple/xnu.git/blobdiff_plain/fe8ab488e9161c46dd9885d58fc52996dc0249ff..cc8bc92ae4a8e9f1a1ab61bf83d34ad8150b3405:/libsa/bootstrap.cpp?ds=inline diff --git a/libsa/bootstrap.cpp b/libsa/bootstrap.cpp index 02e5694d0..80a7508f3 100644 --- a/libsa/bootstrap.cpp +++ b/libsa/bootstrap.cpp @@ -29,6 +29,10 @@ extern "C" { #include #include #include + +#if CONFIG_EMBEDDED +extern uuid_t kernelcache_uuid; +#endif } #include @@ -111,6 +115,26 @@ static const char * sKernelComponentNames[] = { 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 @@ -206,6 +230,11 @@ KLDBootstrap::readStartupExtensions(void) return; } +typedef struct kaslrPackedOffsets { + uint32_t count; /* number of offsets */ + uint32_t offsetsArray[]; /* offsets to slide */ +} kaslrPackedOffsets; + /********************************************************************* *********************************************************************/ void @@ -217,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 @@ -239,6 +271,9 @@ KLDBootstrap::readPrelinkedExtensions( 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 | @@ -300,6 +335,14 @@ KLDBootstrap::readPrelinkedExtensions( prelinkData = (void *) prelinkTextSegment->vmaddr; prelinkLength = prelinkTextSegment->vmsize; + /* build arrays of plk info for later use */ + const char ** segNamePtr; + + 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]); + } + /* Unserialize the info dictionary from the prelink info section. */ @@ -331,6 +374,20 @@ KLDBootstrap::readPrelinkedExtensions( 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) { @@ -339,10 +396,15 @@ KLDBootstrap::readPrelinkedExtensions( goto finish; } + /* 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) { @@ -376,7 +438,7 @@ KLDBootstrap::readPrelinkedExtensions( if (ramDiskOnlyBool == kOSBooleanTrue) { dontLoad = true; } - } + } if (dontLoad == true) { OSString *bundleID = OSDynamicCast(OSString, @@ -391,7 +453,13 @@ KLDBootstrap::readPrelinkedExtensions( 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--); @@ -403,10 +471,47 @@ KLDBootstrap::readPrelinkedExtensions( * 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. */ @@ -420,7 +525,7 @@ KLDBootstrap::readPrelinkedExtensions( if (prelinkCountObj) { registryRoot->setProperty(kOSPrelinkKextCountKey, prelinkCountObj); } - + OSKextLog(/* kext */ NULL, kOSKextLogProgressLevel | kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag | @@ -445,13 +550,30 @@ 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-" @@ -510,7 +632,9 @@ KLDBootstrap::readBooterExtensions(void) /* Create dictionary of excluded kexts */ +#ifndef CONFIG_EMBEDDED OSKext::createExcludeListFromBooterData(propertyDict, keyIterator); +#endif keyIterator->reset(); while ( ( deviceTreeName = @@ -582,7 +706,7 @@ KLDBootstrap::readBooterExtensions(void) * Any creation/registration failures are already logged for us. */ OSKext * newKext = OSKext::withBooterData(deviceTreeName, booterData); - OSSafeRelease(newKext); + OSSafeReleaseNULL(newKext); booterMemoryMap->removeProperty(deviceTreeName); @@ -590,11 +714,11 @@ 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; } @@ -660,8 +784,8 @@ KLDBootstrap::loadSecurityExtensions(void) } finish: - OSSafeRelease(keyIterator); - OSSafeRelease(extensionsDict); + OSSafeReleaseNULL(keyIterator); + OSSafeReleaseNULL(extensionsDict); return; } @@ -703,7 +827,7 @@ KLDBootstrap::loadKernelComponentKexts(void) } } - OSSafeRelease(theKext); + OSSafeReleaseNULL(theKext); return result; } @@ -775,8 +899,8 @@ KLDBootstrap::loadKernelExternalComponents(void) } finish: - OSSafeRelease(keyIterator); - OSSafeRelease(extensionsDict); + OSSafeReleaseNULL(keyIterator); + OSSafeReleaseNULL(extensionsDict); return; } @@ -895,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; }