Loading...
--- dyld/dyld-1340/common/DyldSharedCache.cpp
+++ dyld/dyld-1284.13/common/DyldSharedCache.cpp
@@ -168,7 +168,6 @@
void DyldSharedCache::forEachRegion(void (^handler)(const void* content, uint64_t vmAddr, uint64_t size,
uint32_t initProt, uint32_t maxProt, uint64_t flags,
- uint64_t fileOffset,
bool& stopRegion)) const
{
// <rdar://problem/49875993> sanity check cache header
@@ -183,7 +182,7 @@
const dyld_cache_mapping_info* mappingsEnd = &mappings[header.mappingCount];
for (const dyld_cache_mapping_info* m=mappings; m < mappingsEnd; ++m) {
bool stop = false;
- handler((char*)this + m->fileOffset, m->address, m->size, m->initProt, m->maxProt, 0, m->fileOffset, stop);
+ handler((char*)this + m->fileOffset, m->address, m->size, m->initProt, m->maxProt, 0, stop);
if ( stop )
return;
}
@@ -196,7 +195,7 @@
// this is only called with a mapped dyld cache. That means to get content,
// we cannot use fileoffset, but intead us vmAddr + slide
const void* content = (void*)(m->address + slide);
- handler(content, m->address, m->size, m->initProt, m->maxProt, m->flags, m->fileOffset, stop);
+ handler(content, m->address, m->size, m->initProt, m->maxProt, m->flags, stop);
if ( stop )
return;
}
@@ -233,9 +232,9 @@
__block uint32_t cacheFileIndex = 0;
forEachCache(^(const DyldSharedCache *cache, bool& stopCache) {
cache->forEachRegion(^(const void *content, uint64_t unslidVMAddr, uint64_t size,
- uint32_t initProt, uint32_t maxProt, uint64_t flags,
- uint64_t fileOffset, bool& stopRegion) {
+ uint32_t initProt, uint32_t maxProt, uint64_t flags, bool& stopRegion) {
const char* mappingName = DyldSharedCache::mappingName(maxProt, flags);
+ uint64_t fileOffset = (uint8_t*)content - (uint8_t*)cache;
bool stop = false;
handler(mappingName, unslidVMAddr, size, cacheFileIndex, fileOffset, initProt, maxProt, stop);
if ( stop ) {
@@ -405,8 +404,7 @@
__block uint64_t startAddr = 0;
__block uint64_t endAddr = 0;
forEachRegion(^(const void* content, uint64_t vmAddr, uint64_t size,
- uint32_t initProt, uint32_t maxProt, uint64_t flags,
- uint64_t fileOffset, bool& stopRegion) {
+ uint32_t initProt, uint32_t maxProt, uint64_t flags, bool& stopRegion) {
if ( startAddr == 0 )
startAddr = vmAddr;
uint64_t end = vmAddr+size;
@@ -1120,8 +1118,7 @@
result.reserve(256*1024);
forEachRegion(^(const void* content, uint64_t vmAddr, uint64_t size,
- uint32_t initProt, uint32_t maxProt, uint64_t flags,
- uint64_t fileOffset, bool& stopRegion) {
+ uint32_t initProt, uint32_t maxProt, uint64_t flags, bool& stopRegion) {
regionStartAddresses.push_back(vmAddr);
regionSizes.push_back(size);
regionFileOffsets.push_back((uint8_t*)content - (uint8_t*)this);
@@ -1844,8 +1841,79 @@
return caches;
}
+void DyldSharedCache::applyCacheRebases() const {
+ auto rebaseChainV4 = ^(uint8_t* pageContent, uint16_t startOffset, const dyld_cache_slide_info4* slideInfo)
+ {
+ const uintptr_t deltaMask = (uintptr_t)(slideInfo->delta_mask);
+ const uintptr_t valueMask = ~deltaMask;
+ //const uintptr_t valueAdd = (uintptr_t)(slideInfo->value_add);
+ const unsigned deltaShift = __builtin_ctzll(deltaMask) - 2;
+
+ uint32_t pageOffset = startOffset;
+ uint32_t delta = 1;
+ while ( delta != 0 ) {
+ uint8_t* loc = pageContent + pageOffset;
+ uintptr_t rawValue = *((uintptr_t*)loc);
+ delta = (uint32_t)((rawValue & deltaMask) >> deltaShift);
+ pageOffset += delta;
+ uintptr_t value = (rawValue & valueMask);
+ if ( (value & 0xFFFF8000) == 0 ) {
+ // small positive non-pointer, use as-is
+ }
+ else if ( (value & 0x3FFF8000) == 0x3FFF8000 ) {
+ // small negative non-pointer
+ value |= 0xC0000000;
+ }
+ else {
+ // We don't want to fix up pointers, just the stolen integer slots above
+ // value += valueAdd;
+ // value += slideAmount;
+ continue;
+ }
+ *((uintptr_t*)loc) = value;
+ //dyld::log(" pageOffset=0x%03X, loc=%p, org value=0x%08llX, new value=0x%08llX, delta=0x%X\n", pageOffset, loc, (uint64_t)rawValue, (uint64_t)value, delta);
+ }
+ };
+
+ // On watchOS, the slide info v4 format steals high bits of integers. We need to undo these
+ this->forEachCache(^(const DyldSharedCache *subCache, bool& stopCache) {
+ subCache->forEachSlideInfo(^(uint64_t mappingStartAddress, uint64_t mappingSize, const uint8_t *dataPagesStart,
+ uint64_t slideInfoOffset, uint64_t slideInfoSize, const dyld_cache_slide_info *slideInfo) {
+ if ( slideInfo->version == 4) {
+ const dyld_cache_slide_info4* slideHeader = (dyld_cache_slide_info4*)slideInfo;
+ const uint32_t page_size = slideHeader->page_size;
+ const uint16_t* page_starts = (uint16_t*)((long)(slideInfo) + slideHeader->page_starts_offset);
+ const uint16_t* page_extras = (uint16_t*)((long)(slideInfo) + slideHeader->page_extras_offset);
+ for (int i=0; i < slideHeader->page_starts_count; ++i) {
+ uint8_t* page = (uint8_t*)(long)(dataPagesStart + (page_size*i));
+ uint16_t pageEntry = page_starts[i];
+ //dyld::log("page[%d]: page_starts[i]=0x%04X\n", i, pageEntry);
+ if ( pageEntry == DYLD_CACHE_SLIDE4_PAGE_NO_REBASE )
+ continue;
+ if ( pageEntry & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA ) {
+ uint16_t chainIndex = (pageEntry & DYLD_CACHE_SLIDE4_PAGE_INDEX);
+ bool done = false;
+ while ( !done ) {
+ uint16_t pInfo = page_extras[chainIndex];
+ uint16_t pageStartOffset = (pInfo & DYLD_CACHE_SLIDE4_PAGE_INDEX)*4;
+ //dyld::log(" chain[%d] pageOffset=0x%03X\n", chainIndex, pageStartOffset);
+ rebaseChainV4(page, pageStartOffset, slideHeader);
+ done = (pInfo & DYLD_CACHE_SLIDE4_PAGE_EXTRA_END);
+ ++chainIndex;
+ }
+ }
+ else {
+ uint32_t pageOffset = pageEntry * 4;
+ //dyld::log(" start pageOffset=0x%03X\n", pageOffset);
+ rebaseChainV4(page, pageOffset, slideHeader);
+ }
+ }
+ }
+ });
+ });
+}
+
#endif
-
const dyld_cache_slide_info* DyldSharedCache::legacyCacheSlideInfo() const
{
assert(header.mappingOffset <= offsetof(dyld_cache_header, mappingWithSlideOffset));
@@ -2542,290 +2610,3 @@
}
#endif // BUILDING_CACHE_BUILDER || BUILDING_CACHE_BUILDER_UNIT_TESTS
-
-static std::span<dyld_cache_mapping_and_slide_info const> slidMappings(const DyldSharedCache* cache)
-{
- const dyld_cache_mapping_and_slide_info* base = (dyld_cache_mapping_and_slide_info*)((uint8_t*)cache + cache->header.mappingWithSlideOffset);
- return { base, cache->header.mappingWithSlideCount };
-}
-
-#if __LP64__
-static void rebaseChainV2(uint8_t* pageContent, uint16_t startOffset, uintptr_t slideAmount, const dyld_cache_slide_info2* slideInfo)
-{
- const uintptr_t deltaMask = (uintptr_t)(slideInfo->delta_mask);
- const uintptr_t valueMask = ~deltaMask;
- const uintptr_t valueAdd = (uintptr_t)(slideInfo->value_add);
- const unsigned deltaShift = __builtin_ctzll(deltaMask) - 2;
-
- uint32_t pageOffset = startOffset;
- uint32_t delta = 1;
- while ( delta != 0 ) {
- uint8_t* loc = pageContent + pageOffset;
- uintptr_t rawValue = *((uintptr_t*)loc);
- delta = (uint32_t)((rawValue & deltaMask) >> deltaShift);
- uintptr_t value = (rawValue & valueMask);
- if ( value != 0 ) {
- value += valueAdd;
- value += slideAmount;
- }
- *((uintptr_t*)loc) = value;
- //dyld::log(" pageOffset=0x%03X, loc=%p, org value=0x%08llX, new value=0x%08llX, delta=0x%X\n", pageOffset, loc, (uint64_t)rawValue, (uint64_t)value, delta);
- pageOffset += delta;
- }
-}
-#endif
-
-
-#if !__LP64__ || BUILDING_CACHE_BUILDER_UNIT_TESTS
-static void rebaseChainV4(uint8_t* pageContent, uint16_t startOffset, uintptr_t slideAmount, const dyld_cache_slide_info4* slideInfo)
-{
- const uintptr_t deltaMask = (uintptr_t)(slideInfo->delta_mask);
- const uintptr_t valueMask = ~deltaMask;
- const uintptr_t valueAdd = (uintptr_t)(slideInfo->value_add);
- const unsigned deltaShift = __builtin_ctzll(deltaMask) - 2;
-
- uint32_t pageOffset = startOffset;
- uint32_t delta = 1;
- while ( delta != 0 ) {
- uint8_t* loc = pageContent + pageOffset;
- uintptr_t rawValue = *((uintptr_t*)loc);
- delta = (uint32_t)((rawValue & deltaMask) >> deltaShift);
- uintptr_t value = (rawValue & valueMask);
- if ( (value & 0xFFFF8000) == 0 ) {
- // small positive non-pointer, use as-is
- }
- else if ( (value & 0x3FFF8000) == 0x3FFF8000 ) {
- // small negative non-pointer
- value |= 0xC0000000;
- }
- else {
- value += valueAdd;
- value += slideAmount;
- }
- *((uintptr_t*)loc) = value;
- //dyld::log(" pageOffset=0x%03X, loc=%p, org value=0x%08llX, new value=0x%08llX, delta=0x%X\n", pageOffset, loc, (uint64_t)rawValue, (uint64_t)value, delta);
- pageOffset += delta;
- }
-}
-#endif
-
-// fixup (rebase and potentially authenticate) a specific DATA/AUTH mapping
-static mach_o::Error fixupDataPages(const dyld_cache_slide_info* slideInfo, uint8_t* dataPagesStart, intptr_t slide)
-{
- const dyld_cache_slide_info* slideInfoHeader = slideInfo;
- if ( slideInfoHeader == nullptr )
- return mach_o::Error::none();
-
-#if !__LP64__ || BUILDING_CACHE_BUILDER_UNIT_TESTS
- if ( slideInfoHeader->version == 1 ) {
- const dyld_cache_slide_info* slideHeader = (dyld_cache_slide_info*)slideInfo;
- const uint32_t page_size = 4096;
-
- const dyld_cache_slide_info_entry* entries = (dyld_cache_slide_info_entry*)((char*)slideHeader + slideHeader->entries_offset);
- const uint16_t* tocs = (uint16_t*)((char*)slideHeader + slideHeader->toc_offset);
- for(int i=0; i < slideHeader->toc_count; ++i) {
- const dyld_cache_slide_info_entry* entry = &entries[tocs[i]];
- uint8_t* page = (uint8_t*)(long)(dataPagesStart + (page_size * i));
- for(int j = 0; j < slideHeader->entries_size; ++j) {
- uint8_t bitmask = entry->bits[j];
- for (unsigned k = 0; k != 8; ++k) {
- if ( bitmask & (1 << k) ) {
- uint32_t pageOffset = ((j * 8) + k) * 4;
- uint32_t* loc = (uint32_t*)(page + pageOffset);
- *loc = *loc + (int32_t)slide;
- }
- }
- }
- }
- return mach_o::Error::none();
- }
-
- if ( slideInfoHeader->version == 4 ) {
- const dyld_cache_slide_info4* slideHeader = (dyld_cache_slide_info4*)slideInfo;
- const uint32_t page_size = slideHeader->page_size;
- const uint16_t* page_starts = (uint16_t*)((long)(slideInfo) + slideHeader->page_starts_offset);
- const uint16_t* page_extras = (uint16_t*)((long)(slideInfo) + slideHeader->page_extras_offset);
- for (int i=0; i < slideHeader->page_starts_count; ++i) {
- uint8_t* page = (uint8_t*)(long)(dataPagesStart + (page_size*i));
- uint16_t pageEntry = page_starts[i];
- //dyld::log("page[%d]: page_starts[i]=0x%04X\n", i, pageEntry);
- if ( pageEntry == DYLD_CACHE_SLIDE4_PAGE_NO_REBASE )
- continue;
- if ( pageEntry & DYLD_CACHE_SLIDE4_PAGE_USE_EXTRA ) {
- uint16_t chainIndex = (pageEntry & DYLD_CACHE_SLIDE4_PAGE_INDEX);
- bool done = false;
- while ( !done ) {
- uint16_t pInfo = page_extras[chainIndex];
- uint16_t pageStartOffset = (pInfo & DYLD_CACHE_SLIDE4_PAGE_INDEX)*4;
- //dyld::log(" chain[%d] pageOffset=0x%03X\n", chainIndex, pageStartOffset);
- rebaseChainV4(page, pageStartOffset, slide, slideHeader);
- done = (pInfo & DYLD_CACHE_SLIDE4_PAGE_EXTRA_END);
- ++chainIndex;
- }
- }
- else {
- uint32_t pageOffset = pageEntry * 4;
- //dyld::log(" start pageOffset=0x%03X\n", pageOffset);
- rebaseChainV4(page, pageOffset, slide, slideHeader);
- }
- }
- return mach_o::Error::none();
- }
-#endif
-
-#if __LP64__
- if ( slideInfoHeader->version == 2 ) {
- const dyld_cache_slide_info2* slideHeader = (dyld_cache_slide_info2*)slideInfo;
- const uint32_t page_size = slideHeader->page_size;
- const uint16_t* page_starts = (uint16_t*)((long)(slideInfo) + slideHeader->page_starts_offset);
- const uint16_t* page_extras = (uint16_t*)((long)(slideInfo) + slideHeader->page_extras_offset);
- for (int i=0; i < slideHeader->page_starts_count; ++i) {
- uint8_t* page = (uint8_t*)(long)(dataPagesStart + (page_size*i));
- uint16_t pageEntry = page_starts[i];
- //dyld4::log("page[%d]: page_starts[i]=0x%04X\n", i, pageEntry);
- if ( pageEntry == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE )
- continue;
- if ( pageEntry & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA ) {
- uint16_t chainIndex = (pageEntry & 0x3FFF);
- bool done = false;
- while ( !done ) {
- uint16_t pInfo = page_extras[chainIndex];
- uint16_t pageStartOffset = (pInfo & 0x3FFF)*4;
- //dyld4::log(" chain[%d] pageOffset=0x%03X\n", chainIndex, pageStartOffset);
- rebaseChainV2(page, pageStartOffset, slide, slideHeader);
- done = (pInfo & DYLD_CACHE_SLIDE_PAGE_ATTR_END);
- ++chainIndex;
- }
- }
- else {
- uint32_t pageOffset = pageEntry * 4;
- //dyld::log(" start pageOffset=0x%03X\n", pageOffset);
- rebaseChainV2(page, pageOffset, slide, slideHeader);
- }
- }
- return mach_o::Error::none();
- }
-
- if ( slideInfoHeader->version == 3 ) {
-#if __has_feature(ptrauth_calls) || BUILDING_CACHE_BUILDER_UNIT_TESTS
- const dyld_cache_slide_info3* slideHeader = (dyld_cache_slide_info3*)slideInfo;
- const uint32_t pageSize = slideHeader->page_size;
- for (int i=0; i < slideHeader->page_starts_count; ++i) {
- uint8_t* page = (uint8_t*)(dataPagesStart + (pageSize*i));
- uint64_t delta = slideHeader->page_starts[i];
- //dyld::log("page[%d]: page_starts[i]=0x%04X\n", i, delta);
- if ( delta == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE )
- continue;
- delta = delta/sizeof(uint64_t); // initial offset is byte based
- dyld_cache_slide_pointer3* loc = (dyld_cache_slide_pointer3*)page;
- do {
- loc += delta;
- delta = loc->plain.offsetToNextPointer;
- if ( loc->auth.authenticated ) {
- uint64_t target = slideHeader->auth_value_add + loc->auth.offsetFromSharedCacheBase + slide;
- MachOLoaded::ChainedFixupPointerOnDisk ptr;
- ptr.raw64 = *((uint64_t*)loc);
-#if BUILDING_DYLD
- // only sign pointers in dyld
- loc->raw = ptr.arm64e.signPointer(loc, target);
-#else
- loc->raw = target;
-#endif // BUILDING_DYLD
- }
- else {
- MachOLoaded::ChainedFixupPointerOnDisk ptr;
- ptr.raw64 = *((uint64_t*)loc);
- loc->raw = ptr.arm64e.unpackTarget() + slide;
- }
- } while (delta != 0);
- }
- return mach_o::Error::none();
-#else
- return mach_o::Error("invalid pointer kind in cache file");
-#endif // __has_feature(ptrauth_calls) || BUILDING_CACHE_BUILDER_UNIT_TESTS
- }
-
- if ( slideInfoHeader->version == 5 ) {
-#if __has_feature(ptrauth_calls) || BUILDING_CACHE_BUILDER_UNIT_TESTS
- const dyld_cache_slide_info5* slideHeader = (dyld_cache_slide_info5*)slideInfo;
- const uint32_t pageSize = slideHeader->page_size;
- for (int i=0; i < slideHeader->page_starts_count; ++i) {
- uint8_t* page = (uint8_t*)(dataPagesStart + (pageSize*i));
- uint64_t delta = slideHeader->page_starts[i];
- //dyld4::console("page[%d]: page_starts[i]=0x%04llX\n", i, delta);
- if ( delta == DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE )
- continue;
- delta = delta/sizeof(uint64_t); // initial offset is byte based
- dyld_cache_slide_pointer5* loc = (dyld_cache_slide_pointer5*)page;
- do {
- loc += delta;
- delta = loc->regular.next;
-
- MachOLoaded::ChainedFixupPointerOnDisk ptr;
- ptr.raw64 = *((uint64_t*)loc);
-
- uint64_t target = slideHeader->value_add + loc->regular.runtimeOffset + slide;
- if ( loc->auth.auth ) {
-#if BUILDING_DYLD
- // only sign pointers in dyld
- loc->raw = ptr.cache64e.signPointer(loc, target);
-#else
- loc->raw = target;
-#endif // BUILDING_DYLD
- } else {
- loc->raw = target | ptr.cache64e.high8();
- }
- } while (delta != 0);
- }
- return mach_o::Error::none();
-#else
- return mach_o::Error("invalid pointer kind in cache file");
-#endif // __has_feature(ptrauth_calls) || BUILDING_CACHE_BUILDER_UNIT_TESTS
- }
-#endif // LP64
-
- return mach_o::Error("invalid slide info in cache file");
-}
-
-mach_o::Error DyldSharedCache::fixupDataPages(intptr_t slideToApply) const
-{
- std::span<dyld_cache_mapping_and_slide_info const> mappings = slidMappings(this);
-
- // Nothing to do if we only have 1 mapping, as that means we are only TEXT or only LINKEDIT
- if ( mappings.size() == 1 )
- return mach_o::Error::none();
-
- // LINEKDIT must be last
- const dyld_cache_mapping_and_slide_info& linkeditMapping = mappings.back();
-
- for ( const dyld_cache_mapping_and_slide_info& mapping : mappings ) {
- if ( mapping.slideInfoFileSize == 0 )
- continue;
-
- // slide info is relative to where linkedit was mapped
- uint64_t slideInfoLinkeditOffset = mapping.slideInfoFileOffset - linkeditMapping.fileOffset;
- uint64_t slideInfoAddr = linkeditMapping.address + slideInfoLinkeditOffset;
- const dyld_cache_slide_info* slideInfo = (const dyld_cache_slide_info*)(slideInfoAddr + slide());
- uint8_t* dataPages = (uint8_t*)(mapping.address + slide());
-
- if ( mach_o::Error err = ::fixupDataPages(slideInfo, dataPages, slideToApply) )
- return err;
- }
-
- return mach_o::Error::none();
-}
-
-mach_o::Error DyldSharedCache::fixupAllDataPages(intptr_t slideToApply) const
-{
- // Fix up the pages in all subcaches
- __block mach_o::Error err = mach_o::Error::none();
- forEachCache(^(const DyldSharedCache* cache, bool& stopCache) {
- if ( mach_o::Error cacheErr = cache->fixupDataPages(slideToApply) ) {
- err = std::move(cacheErr);
- stopCache = true;
- return;
- }
- });
-
- return std::move(err);
-}