Loading...
--- dyld/dyld-832.7.3/dyld3/SharedCacheRuntime.cpp
+++ dyld/dyld-640.2/dyld3/SharedCacheRuntime.cpp
@@ -26,7 +26,6 @@
#include <stdint.h>
#include <string.h>
#include <unistd.h>
-#include <errno.h>
#include <fcntl.h>
#include <sys/param.h>
#include <sys/types.h>
@@ -47,25 +46,18 @@
#include "dyld_cache_format.h"
#include "SharedCacheRuntime.h"
#include "Loading.h"
-#include "BootArgs.h"
#define ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE 1024
// should be in mach/shared_region.h
extern "C" int __shared_region_check_np(uint64_t* startaddress);
extern "C" int __shared_region_map_and_slide_np(int fd, uint32_t count, const shared_file_mapping_np mappings[], long slide, const dyld_cache_slide_info2* slideInfo, size_t slideInfoSize);
-extern "C" int __shared_region_map_and_slide_2_np(uint32_t files_count, const shared_file_np files[], uint32_t mappings_count, const shared_file_mapping_slide_np mappings[]);
-
-#ifndef VM_PROT_NOAUTH
-#define VM_PROT_NOAUTH 0x40 /* must not interfere with normal prot assignments */
-#endif
+
namespace dyld {
+ extern int my_stat(const char* path, struct stat* buf);
+ extern int my_open(const char* path, int flag, int other);
extern void log(const char*, ...);
- extern void logToConsole(const char* format, ...);
-#if defined(__x86_64__) && !TARGET_OS_SIMULATOR
- bool isTranslated();
-#endif
}
@@ -74,13 +66,14 @@
struct CacheInfo
{
- shared_file_mapping_slide_np mappings[DyldSharedCache::MaxMappings];
- uint32_t mappingsCount;
- // All mappings come from the same file
- int fd = 0;
- uint64_t sharedRegionStart;
- uint64_t sharedRegionSize;
- uint64_t maxSlide;
+ int fd;
+ shared_file_mapping_np mappings[3];
+ uint64_t slideInfoAddressUnslid;
+ size_t slideInfoSize;
+ uint64_t cachedDylibsGroupUnslid;
+ uint64_t sharedRegionStart;
+ uint64_t sharedRegionSize;
+ uint64_t maxSlide;
};
@@ -117,7 +110,7 @@
#endif
-#if !TARGET_OS_SIMULATOR
+
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);
@@ -141,9 +134,8 @@
pageOffset += delta;
}
}
-#endif
-
-#if !__LP64__ && !TARGET_OS_SIMULATOR
+
+#if !__LP64__
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);
@@ -176,123 +168,56 @@
}
#endif
-#if TARGET_OS_OSX
-bool getMacOSCachePath(char pathBuffer[], size_t pathBufferSize,
- const char* cacheDir, bool useHaswell) {
- // Clear old attempts at finding a cache, if any
- pathBuffer[0] = '\0';
-
+static void getCachePath(const SharedCacheOptions& options, size_t pathBufferSize, char pathBuffer[])
+{
// set cache dir
- strlcpy(pathBuffer, cacheDir, pathBufferSize);
+ if ( options.cacheDirOverride != nullptr ) {
+ strlcpy(pathBuffer, options.cacheDirOverride, pathBufferSize);
+ }
+ else {
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
+ strlcpy(pathBuffer, IPHONE_DYLD_SHARED_CACHE_DIR, sizeof(IPHONE_DYLD_SHARED_CACHE_DIR));
+#else
+ strlcpy(pathBuffer, MACOSX_DYLD_SHARED_CACHE_DIR, sizeof(MACOSX_DYLD_SHARED_CACHE_DIR));
+#endif
+ }
// append file component of cache file
if ( pathBuffer[strlen(pathBuffer)-1] != '/' )
strlcat(pathBuffer, "/", pathBufferSize);
-
-#if __x86_64__
- if ( useHaswell ) {
+#if __x86_64__ && !__IPHONE_OS_VERSION_MIN_REQUIRED
+ if ( options.useHaswell ) {
size_t len = strlen(pathBuffer);
struct stat haswellStatBuf;
strlcat(pathBuffer, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME_H, pathBufferSize);
- if ( dyld3::stat(pathBuffer, &haswellStatBuf) == 0 )
- return true;
+ if ( dyld::my_stat(pathBuffer, &haswellStatBuf) == 0 )
+ return;
// no haswell cache file, use regular x86_64 cache
pathBuffer[len] = '\0';
}
#endif
-
- struct stat statBuf;
strlcat(pathBuffer, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, pathBufferSize);
- if ( dyld3::stat(pathBuffer, &statBuf) == 0 )
- return true;
-
- return false;
-}
-#endif // TARGET_OS_OSX
-
-static void getCachePath(const SharedCacheOptions& options, size_t pathBufferSize, char pathBuffer[])
-{
-#if TARGET_OS_OSX
-
- if ( options.cacheDirOverride != nullptr ) {
- getMacOSCachePath(pathBuffer, pathBufferSize, options.cacheDirOverride, options.useHaswell);
- } else {
- getMacOSCachePath(pathBuffer, pathBufferSize, MACOSX_MRM_DYLD_SHARED_CACHE_DIR, options.useHaswell);
- }
-
-#else // TARGET_OS_OSX
-
- // Non-macOS path
- if ( options.cacheDirOverride != nullptr ) {
- strlcpy(pathBuffer, options.cacheDirOverride, pathBufferSize);
- } else {
- strlcpy(pathBuffer, IPHONE_DYLD_SHARED_CACHE_DIR, sizeof(IPHONE_DYLD_SHARED_CACHE_DIR));
- }
-
- // append file component of cache file
- if ( pathBuffer[strlen(pathBuffer)-1] != '/' )
- strlcat(pathBuffer, "/", pathBufferSize);
-
- strlcat(pathBuffer, DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, pathBufferSize);
-
-#if TARGET_OS_IPHONE && !TARGET_OS_SIMULATOR
+
+#if __IPHONE_OS_VERSION_MIN_REQUIRED && !TARGET_IPHONE_SIMULATOR
// use .development cache if it exists
- if ( BootArgs::forceCustomerCache() ) {
- // The boot-arg always wins. Use the customer cache if we are told to
- return;
- }
- if ( !dyld3::internalInstall() ) {
- // We can't use the development cache on customer installs
- return;
- }
- if ( BootArgs::forceDevelopmentCache() ) {
- // The boot-arg always wins. Use the development cache if we are told to
- strlcat(pathBuffer, DYLD_SHARED_CACHE_DEVELOPMENT_EXT, pathBufferSize);
- return;
- }
-
- // If only one or the other caches exists, then use the one we have
+ struct stat enableStatBuf;
struct stat devCacheStatBuf;
struct stat optCacheStatBuf;
- bool devCacheExists = (dyld3::stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME DYLD_SHARED_CACHE_DEVELOPMENT_EXT, &devCacheStatBuf) == 0);
- bool optCacheExists = (dyld3::stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &optCacheStatBuf) == 0);
- if ( !devCacheExists ) {
- // If the dev cache doesn't exist, then use the customer cache
- return;
- }
- if ( !optCacheExists ) {
- // If the customer cache doesn't exist, then use the development cache
+ bool developmentDevice = dyld3::internalInstall();
+ bool enableFileExists = (dyld::my_stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0);
+ bool devCacheExists = (dyld::my_stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME DYLD_SHARED_CACHE_DEVELOPMENT_EXT, &devCacheStatBuf) == 0);
+ bool optCacheExists = (dyld::my_stat(IPHONE_DYLD_SHARED_CACHE_DIR DYLD_SHARED_CACHE_BASE_NAME ARCH_NAME, &optCacheStatBuf) == 0);
+ if ( developmentDevice && ((enableFileExists && (enableStatBuf.st_size < ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE) && devCacheExists) || !optCacheExists) )
strlcat(pathBuffer, DYLD_SHARED_CACHE_DEVELOPMENT_EXT, pathBufferSize);
- return;
- }
-
- // Finally, check for the sentinels
- struct stat enableStatBuf;
- //struct stat sentinelStatBuf;
- bool enableFileExists = (dyld3::stat(IPHONE_DYLD_SHARED_CACHE_DIR "enable-dylibs-to-override-cache", &enableStatBuf) == 0);
- // FIXME: rdar://problem/59813537 Re-enable once automation is updated to use boot-arg
- bool sentinelFileExists = false;
- //bool sentinelFileExists = (dyld3::stat(MACOSX_MRM_DYLD_SHARED_CACHE_DIR "enable_development_mode", &sentinelStatBuf) == 0);
- if ( enableFileExists && (enableStatBuf.st_size < ENABLE_DYLIBS_TO_OVERRIDE_CACHE_SIZE) ) {
- // if the old enable file exists, use the development cache
- strlcat(pathBuffer, DYLD_SHARED_CACHE_DEVELOPMENT_EXT, pathBufferSize);
- return;
- }
- if ( sentinelFileExists ) {
- // If the new sentinel exists, then use the development cache
- strlcat(pathBuffer, DYLD_SHARED_CACHE_DEVELOPMENT_EXT, pathBufferSize);
- return;
- }
-#endif
-
-#endif //!TARGET_OS_OSX
+#endif
+
}
int openSharedCacheFile(const SharedCacheOptions& options, SharedCacheLoadInfo* results)
{
getCachePath(options, sizeof(results->path), results->path);
- return dyld3::open(results->path, O_RDONLY, 0);
+ return dyld::my_open(results->path, O_RDONLY, 0);
}
static bool validMagic(const SharedCacheOptions& options, const DyldSharedCache* cache)
@@ -319,7 +244,7 @@
if ( cache->header.platform != (uint32_t)MachOFile::currentPlatform() )
return false;
-#if TARGET_OS_SIMULATOR
+#if TARGET_IPHONE_SIMULATOR
if ( cache->header.simulator == 0 )
return false;
#else
@@ -330,47 +255,31 @@
return true;
}
-#if !TARGET_OS_SIMULATOR
-static void verboseSharedCacheMappings(const shared_file_mapping_slide_np mappings[DyldSharedCache::MaxMappings],
- uint32_t mappingsCount)
-{
- for (int i=0; i < mappingsCount; ++i) {
- const char* mappingName = "";
- if ( mappings[i].sms_init_prot & VM_PROT_WRITE ) {
- if ( mappings[i].sms_init_prot & VM_PROT_NOAUTH ) {
- // __DATA*
- mappingName = "data";
- } else {
- // __AUTH*
- mappingName = "auth";
- }
- }
- uint32_t init_prot = mappings[i].sms_init_prot & (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
- uint32_t max_prot = mappings[i].sms_max_prot & (VM_PROT_READ | VM_PROT_WRITE | VM_PROT_EXECUTE);
- dyld::log(" 0x%08llX->0x%08llX init=%x, max=%x %s%s%s%s\n",
- mappings[i].sms_address, mappings[i].sms_address+mappings[i].sms_size-1,
- init_prot, max_prot,
- ((mappings[i].sms_init_prot & VM_PROT_READ) ? "read " : ""),
- ((mappings[i].sms_init_prot & VM_PROT_WRITE) ? "write " : ""),
- ((mappings[i].sms_init_prot & VM_PROT_EXECUTE) ? "execute " : ""),
- mappingName);
- }
-}
-#endif
+
+static void verboseSharedCacheMappings(const shared_file_mapping_np mappings[3])
+{
+ for (int i=0; i < 3; ++i) {
+ dyld::log(" 0x%08llX->0x%08llX init=%x, max=%x %s%s%s\n",
+ mappings[i].sfm_address, mappings[i].sfm_address+mappings[i].sfm_size-1,
+ mappings[i].sfm_init_prot, mappings[i].sfm_init_prot,
+ ((mappings[i].sfm_init_prot & VM_PROT_READ) ? "read " : ""),
+ ((mappings[i].sfm_init_prot & VM_PROT_WRITE) ? "write " : ""),
+ ((mappings[i].sfm_init_prot & VM_PROT_EXECUTE) ? "execute " : ""));
+ }
+}
static bool preflightCacheFile(const SharedCacheOptions& options, SharedCacheLoadInfo* results, CacheInfo* info)
{
-
// find and open shared cache file
int fd = openSharedCacheFile(options, results);
if ( fd == -1 ) {
- results->errorMessage = "shared cache file open() failed";
+ results->errorMessage = "shared cache file cannot be opened";
return false;
}
struct stat cacheStatBuf;
- if ( dyld3::stat(results->path, &cacheStatBuf) != 0 ) {
- results->errorMessage = "shared cache file stat() failed";
+ if ( dyld::my_stat(results->path, &cacheStatBuf) != 0 ) {
+ results->errorMessage = "shared cache file cannot be stat()ed";
::close(fd);
return false;
}
@@ -379,7 +288,7 @@
// sanity check header and mappings
uint8_t firstPage[0x4000];
if ( ::pread(fd, firstPage, sizeof(firstPage), 0) != sizeof(firstPage) ) {
- results->errorMessage = "shared cache file pread() failed";
+ results->errorMessage = "shared cache header could not be read";
::close(fd);
return false;
}
@@ -394,41 +303,39 @@
::close(fd);
return false;
}
- if ( (cache->header.mappingCount < 3) || (cache->header.mappingCount > DyldSharedCache::MaxMappings) || (cache->header.mappingOffset > 0x168) ) {
+ if ( (cache->header.mappingCount != 3) || (cache->header.mappingOffset > 0x138) ) {
results->errorMessage = "shared cache file mappings are invalid";
::close(fd);
return false;
}
const dyld_cache_mapping_info* const fileMappings = (dyld_cache_mapping_info*)&firstPage[cache->header.mappingOffset];
- const dyld_cache_mapping_info* textMapping = &fileMappings[0];
- const dyld_cache_mapping_info* firstDataMapping = &fileMappings[1];
- const dyld_cache_mapping_info* linkeditMapping = &fileMappings[cache->header.mappingCount - 1];
- if ( (textMapping->fileOffset != 0)
- || ((fileMappings[0].address + fileMappings[0].size) > firstDataMapping->address)
- || ((fileMappings[0].fileOffset + fileMappings[0].size) != firstDataMapping->fileOffset)
+ if ( (fileMappings[0].fileOffset != 0)
+ || ((fileMappings[0].address + fileMappings[0].size) > fileMappings[1].address)
+ || ((fileMappings[1].address + fileMappings[1].size) > fileMappings[2].address)
+ || ((fileMappings[0].fileOffset + fileMappings[0].size) != fileMappings[1].fileOffset)
+ || ((fileMappings[1].fileOffset + fileMappings[1].size) != fileMappings[2].fileOffset)
|| ((cache->header.codeSignatureOffset + cache->header.codeSignatureSize) != cacheFileLength)
- || (textMapping->maxProt != (VM_PROT_READ|VM_PROT_EXECUTE))
- || (linkeditMapping->maxProt != VM_PROT_READ) ) {
- results->errorMessage = "shared cache text/linkedit mappings are invalid";
- ::close(fd);
- return false;
- }
-
- // Check the __DATA mappings
- for (unsigned i = 1; i != (cache->header.mappingCount - 1); ++i) {
- if ( ((fileMappings[i].address + fileMappings[i].size) > fileMappings[i + 1].address)
- || ((fileMappings[i].fileOffset + fileMappings[i].size) != fileMappings[i + 1].fileOffset)
- || (fileMappings[i].maxProt != (VM_PROT_READ|VM_PROT_WRITE)) ) {
- results->errorMessage = "shared cache data mappings are invalid";
+ || (fileMappings[0].maxProt != (VM_PROT_READ|VM_PROT_EXECUTE))
+ || (fileMappings[1].maxProt != (VM_PROT_READ|VM_PROT_WRITE))
+ || (fileMappings[2].maxProt != VM_PROT_READ) ) {
+ results->errorMessage = "shared cache file mappings are invalid";
+ ::close(fd);
+ return false;
+ }
+
+ if ( cache->header.mappingOffset >= 0xF8 ) {
+ if ( (fileMappings[0].address != cache->header.sharedRegionStart) || ((fileMappings[2].address + fileMappings[2].size) > (cache->header.sharedRegionStart+cache->header.sharedRegionSize)) ) {
+ results->errorMessage = "shared cache file mapping addressses invalid";
::close(fd);
return false;
}
}
-
- if ( (textMapping->address != cache->header.sharedRegionStart) || ((linkeditMapping->address + linkeditMapping->size) > (cache->header.sharedRegionStart+cache->header.sharedRegionSize)) ) {
- results->errorMessage = "shared cache file mapping addressses invalid";
- ::close(fd);
- return false;
+ else {
+ if ( (fileMappings[0].address != SHARED_REGION_BASE) || ((fileMappings[2].address + fileMappings[2].size) > (SHARED_REGION_BASE+SHARED_REGION_SIZE)) ) {
+ results->errorMessage = "shared cache file mapping addressses invalid";
+ ::close(fd);
+ return false;
+ }
}
// register code signature of cache file
@@ -464,63 +371,47 @@
::munmap(mappedData, sizeof(firstPage));
// fill out results
- info->mappingsCount = cache->header.mappingCount;
- // We have to emit the mapping for the __LINKEDIT before the slid mappings
- // This is so that the kernel has already mapped __LINKEDIT in to its address space
- // for when it copies the slid info for each __DATA mapping
- for (int i=0; i < cache->header.mappingCount; ++i) {
- uint64_t slideInfoFileOffset = 0;
- uint64_t slideInfoFileSize = 0;
- vm_prot_t authProt = 0;
- if ( cache->header.mappingOffset <= __offsetof(dyld_cache_header, mappingWithSlideOffset) ) {
- // Old cache without the new slid mappings
- if ( i == 1 ) {
- // Add slide info to the __DATA mapping
- slideInfoFileOffset = cache->header.slideInfoOffsetUnused;
- slideInfoFileSize = cache->header.slideInfoSizeUnused;
- // Don't set auth prot to anything interseting on the old mapppings
- authProt = 0;
- }
- } else {
- // New cache where each mapping has a corresponding slid mapping
- const dyld_cache_mapping_and_slide_info* slidableMappings = (const dyld_cache_mapping_and_slide_info*)&firstPage[cache->header.mappingWithSlideOffset];
- slideInfoFileOffset = slidableMappings[i].slideInfoFileOffset;
- slideInfoFileSize = slidableMappings[i].slideInfoFileSize;
- if ( (slidableMappings[i].flags & DYLD_CACHE_MAPPING_AUTH_DATA) == 0 )
- authProt = VM_PROT_NOAUTH;
- }
-
- // Add a file for each mapping
- info->fd = fd;
- info->mappings[i].sms_address = fileMappings[i].address;
- info->mappings[i].sms_size = fileMappings[i].size;
- info->mappings[i].sms_file_offset = fileMappings[i].fileOffset;
- info->mappings[i].sms_slide_size = 0;
- info->mappings[i].sms_slide_start = 0;
- info->mappings[i].sms_max_prot = fileMappings[i].maxProt;
- info->mappings[i].sms_init_prot = fileMappings[i].initProt;
- if ( slideInfoFileSize != 0 ) {
- uint64_t offsetInLinkEditRegion = (slideInfoFileOffset - linkeditMapping->fileOffset);
- info->mappings[i].sms_slide_start = (user_addr_t)(linkeditMapping->address + offsetInLinkEditRegion);
- info->mappings[i].sms_slide_size = (user_addr_t)slideInfoFileSize;
- info->mappings[i].sms_init_prot |= (VM_PROT_SLIDE | authProt);
- info->mappings[i].sms_max_prot |= (VM_PROT_SLIDE | authProt);
- }
- }
- info->sharedRegionStart = cache->header.sharedRegionStart;
- info->sharedRegionSize = cache->header.sharedRegionSize;
- info->maxSlide = cache->header.maxSlide;
+ info->fd = fd;
+ for (int i=0; i < 3; ++i) {
+ info->mappings[i].sfm_address = fileMappings[i].address;
+ info->mappings[i].sfm_size = fileMappings[i].size;
+ info->mappings[i].sfm_file_offset = fileMappings[i].fileOffset;
+ info->mappings[i].sfm_max_prot = fileMappings[i].maxProt;
+ info->mappings[i].sfm_init_prot = fileMappings[i].initProt;
+ }
+ info->mappings[1].sfm_max_prot |= VM_PROT_SLIDE;
+ info->mappings[1].sfm_init_prot |= VM_PROT_SLIDE;
+ info->slideInfoAddressUnslid = fileMappings[2].address + cache->header.slideInfoOffset - fileMappings[2].fileOffset;
+ info->slideInfoSize = (long)cache->header.slideInfoSize;
+ if ( cache->header.mappingOffset > 0xD0 )
+ info->cachedDylibsGroupUnslid = cache->header.dylibsImageGroupAddr;
+ else
+ info->cachedDylibsGroupUnslid = 0;
+ if ( cache->header.mappingOffset >= 0xf8 ) {
+ info->sharedRegionStart = cache->header.sharedRegionStart;
+ info->sharedRegionSize = cache->header.sharedRegionSize;
+ info->maxSlide = cache->header.maxSlide;
+ }
+ else {
+ info->sharedRegionStart = SHARED_REGION_BASE;
+ info->sharedRegionSize = SHARED_REGION_SIZE;
+ info->maxSlide = SHARED_REGION_SIZE - (fileMappings[2].address + fileMappings[2].size - fileMappings[0].address);
+ }
return true;
}
-#if !TARGET_OS_SIMULATOR
+#if !TARGET_IPHONE_SIMULATOR
// update all __DATA pages with slide info
-static bool rebaseDataPages(bool isVerbose, const dyld_cache_slide_info* slideInfo, const uint8_t *dataPagesStart,
- uint64_t sharedRegionStart, SharedCacheLoadInfo* results)
-{
- const dyld_cache_slide_info* slideInfoHeader = slideInfo;
+static bool rebaseDataPages(bool isVerbose, CacheInfo& info, SharedCacheLoadInfo* results)
+{
+ uint64_t dataPagesStart = info.mappings[1].sfm_address;
+ const dyld_cache_slide_info* slideInfo = nullptr;
+ if ( info.slideInfoSize != 0 ) {
+ slideInfo = (dyld_cache_slide_info*)(info.slideInfoAddressUnslid + results->slide);
+ }
+ const dyld_cache_slide_info* slideInfoHeader = (dyld_cache_slide_info*)slideInfo;
if ( slideInfoHeader != nullptr ) {
if ( slideInfoHeader->version == 2 ) {
const dyld_cache_slide_info2* slideHeader = (dyld_cache_slide_info2*)slideInfo;
@@ -559,7 +450,6 @@
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
@@ -569,19 +459,17 @@
delta = loc->plain.offsetToNextPointer;
if ( loc->auth.authenticated ) {
#if __has_feature(ptrauth_calls)
- uint64_t target = sharedRegionStart + loc->auth.offsetFromSharedCacheBase + results->slide;
+ uint64_t target = info.sharedRegionStart + loc->auth.offsetFromSharedCacheBase + results->slide;
MachOLoaded::ChainedFixupPointerOnDisk ptr;
- ptr.raw64 = *((uint64_t*)loc);
- loc->raw = ptr.arm64e.signPointer(loc, target);
+ ptr.raw = *((uint64_t*)loc);
+ loc->raw = ptr.signPointer(loc, target);
#else
results->errorMessage = "invalid pointer kind in cache file";
return false;
#endif
}
else {
- MachOLoaded::ChainedFixupPointerOnDisk ptr;
- ptr.raw64 = *((uint64_t*)loc);
- loc->raw = ptr.arm64e.unpackTarget() + results->slide;
+ loc->raw = MachOLoaded::ChainedFixupPointerOnDisk::signExtend51(loc->plain.pointerValue) + results->slide;
}
} while (delta != 0);
}
@@ -644,26 +532,12 @@
if ( options.verbose ) {
const shared_file_mapping_np* const mappings = (shared_file_mapping_np*)(cacheBaseAddress + existingCache->header.mappingOffset);
dyld::log("re-using existing shared cache (%s):\n", results->path);
- shared_file_mapping_slide_np slidMappings[DyldSharedCache::MaxMappings];
- for (int i=0; i < DyldSharedCache::MaxMappings; ++i) {
- slidMappings[i].sms_address = mappings[i].sfm_address;
- slidMappings[i].sms_size = mappings[i].sfm_size;
- slidMappings[i].sms_file_offset = mappings[i].sfm_file_offset;
- slidMappings[i].sms_max_prot = mappings[i].sfm_max_prot;
- slidMappings[i].sms_init_prot = mappings[i].sfm_init_prot;
-
- slidMappings[i].sms_address += results->slide;
- if ( existingCache->header.mappingOffset > __offsetof(dyld_cache_header, mappingWithSlideOffset) ) {
- // New caches have slide info on each new mapping
- const dyld_cache_mapping_and_slide_info* const slidableMappings = (dyld_cache_mapping_and_slide_info*)(cacheBaseAddress + existingCache->header.mappingWithSlideOffset);
- assert(existingCache->header.mappingWithSlideCount <= DyldSharedCache::MaxMappings);
- if ( !(slidableMappings[i].flags & DYLD_CACHE_MAPPING_AUTH_DATA) ) {
- slidMappings[i].sms_max_prot |= VM_PROT_NOAUTH;
- slidMappings[i].sms_init_prot |= VM_PROT_NOAUTH;
- }
- }
+ shared_file_mapping_np slidMappings[3];
+ for (int i=0; i < 3; ++i) {
+ slidMappings[i] = mappings[i];
+ slidMappings[i].sfm_address += results->slide;
}
- verboseSharedCacheMappings(slidMappings, existingCache->header.mappingCount);
+ verboseSharedCacheMappings(slidMappings);
}
}
else {
@@ -674,28 +548,24 @@
return false;
}
-static long pickCacheASLRSlide(CacheInfo& info)
+static long pickCacheASLR(CacheInfo& info)
{
// choose new random slide
-#if TARGET_OS_IPHONE || (TARGET_OS_OSX && TARGET_CPU_ARM64)
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
// <rdar://problem/20848977> change shared cache slide for 32-bit arm to always be 16k aligned
- long slide;
- if (info.maxSlide == 0)
+ long slide = ((arc4random() % info.maxSlide) & (-16384));
+#else
+ long slide = ((arc4random() % info.maxSlide) & (-4096));
+#endif
+
+ // <rdar://problem/32031197> respect -disable_aslr boot-arg
+ if ( dyld3::bootArgsContains("-disable_aslr") )
slide = 0;
- else
- slide = ((arc4random() % info.maxSlide) & (-16384));
-#else
- long slide;
- if (info.maxSlide == 0)
- slide = 0;
- else
- slide = ((arc4random() % info.maxSlide) & (-4096));
-#if defined(__x86_64__) && !TARGET_OS_SIMULATOR
- if (dyld::isTranslated()) {
- slide &= (-16384);
- }
-#endif
-#endif
+
+ // update mappings
+ for (uint32_t i=0; i < 3; ++i) {
+ info.mappings[i].sfm_address += slide;
+ }
return slide;
}
@@ -706,56 +576,16 @@
if ( !preflightCacheFile(options, results, &info) )
return false;
- int result = 0;
- if ( info.mappingsCount != 3 ) {
- uint32_t maxSlide = options.disableASLR ? 0 : (uint32_t)info.maxSlide;
-
- shared_file_np file;
- file.sf_fd = info.fd;
- file.sf_mappings_count = info.mappingsCount;
- // For the new syscall, this is actually the max slide. The kernel now owns the actual slide
- file.sf_slide = maxSlide;
- result = __shared_region_map_and_slide_2_np(1, &file, info.mappingsCount, info.mappings);
- } else {
- // With the old syscall, dyld has to choose the slide
- results->slide = options.disableASLR ? 0 : pickCacheASLRSlide(info);
-
- // update mappings based on the slide we choose
- for (uint32_t i=0; i < info.mappingsCount; ++i) {
- info.mappings[i].sms_address += results->slide;
- if ( info.mappings[i].sms_slide_size != 0 )
- info.mappings[i].sms_slide_start += (uint32_t)results->slide;
- }
-
- // If we get here then we don't have the new kernel function, so use the old one
- const dyld_cache_slide_info2* slideInfo = nullptr;
- size_t slideInfoSize = 0;
- shared_file_mapping_np mappings[3];
- for (unsigned i = 0; i != 3; ++i) {
- mappings[i].sfm_address = info.mappings[i].sms_address;
- mappings[i].sfm_size = info.mappings[i].sms_size;
- mappings[i].sfm_file_offset = info.mappings[i].sms_file_offset;
- mappings[i].sfm_max_prot = info.mappings[i].sms_max_prot;
- mappings[i].sfm_init_prot = info.mappings[i].sms_init_prot;
- if ( info.mappings[i].sms_slide_size != 0 ) {
- slideInfo = (dyld_cache_slide_info2*)info.mappings[i].sms_slide_start;
- slideInfoSize = (size_t)info.mappings[i].sms_slide_size;
- }
- }
- result = __shared_region_map_and_slide_np(info.fd, 3, mappings, results->slide, slideInfo, slideInfoSize);
- }
-
+ const dyld_cache_slide_info2* slideInfo = nullptr;
+ if ( info.slideInfoSize != 0 ) {
+ results->slide = pickCacheASLR(info);
+ slideInfo = (dyld_cache_slide_info2*)(info.slideInfoAddressUnslid + results->slide);
+ }
+
+ int result = __shared_region_map_and_slide_np(info.fd, 3, info.mappings, results->slide, slideInfo, info.slideInfoSize);
::close(info.fd);
if ( result == 0 ) {
- results->loadAddress = (const DyldSharedCache*)(info.mappings[0].sms_address);
- if ( info.mappingsCount != 3 ) {
- // We don't know our own slide any more as the kernel owns it, so ask for it again now
- if ( reuseExistingCache(options, results) )
- return true;
- // Uh oh, we mapped the kernel, but we didn't find the slide
- dyld::logToConsole("dyld: error finding shared cache slide for system wide mapping\n");
- return false;
- }
+ results->loadAddress = (const DyldSharedCache*)(info.mappings[0].sfm_address);
}
else {
// could be another process beat us to it
@@ -769,11 +599,11 @@
if ( options.verbose ) {
dyld::log("mapped dyld cache file system wide: %s\n", results->path);
- verboseSharedCacheMappings(info.mappings, info.mappingsCount);
+ verboseSharedCacheMappings(info.mappings);
}
return true;
}
-#endif // TARGET_OS_SIMULATOR
+#endif // TARGET_IPHONE_SIMULATOR
static bool mapCachePrivate(const SharedCacheOptions& options, SharedCacheLoadInfo* results)
{
@@ -784,70 +614,48 @@
// compute ALSR slide
results->slide = 0;
-#if !TARGET_OS_SIMULATOR
- results->slide = options.disableASLR ? 0 : pickCacheASLRSlide(info);
-#endif
-
- // update mappings
- for (uint32_t i=0; i < info.mappingsCount; ++i) {
- info.mappings[i].sms_address += (uint32_t)results->slide;
- if ( info.mappings[i].sms_slide_size != 0 )
- info.mappings[i].sms_slide_start += (uint32_t)results->slide;
- }
-
- results->loadAddress = (const DyldSharedCache*)(info.mappings[0].sms_address);
-
- // deallocate any existing system wide shared cache
- deallocateExistingSharedCache();
-
-#if TARGET_OS_SIMULATOR && TARGET_OS_WATCH
- // <rdar://problem/50887685> watchOS 32-bit cache does not overlap macOS dyld cache address range
- // mmap() of a file needs a vm_allocation behind it, so make one
- vm_address_t loadAddress = 0x40000000;
- ::vm_allocate(mach_task_self(), &loadAddress, 0x40000000, VM_FLAGS_FIXED);
-#endif
-
+#if !TARGET_IPHONE_SIMULATOR // simulator caches do not support sliding
+ if ( info.slideInfoSize != 0 ) {
+ results->slide = pickCacheASLR(info);
+ }
+#endif
+ results->loadAddress = (const DyldSharedCache*)(info.mappings[0].sfm_address);
+
+ // remove the shared region sub-map
+ vm_deallocate(mach_task_self(), (vm_address_t)info.sharedRegionStart, (vm_size_t)info.sharedRegionSize);
+
// map cache just for this process with mmap()
- for (int i=0; i < info.mappingsCount; ++i) {
- void* mmapAddress = (void*)(uintptr_t)(info.mappings[i].sms_address);
- size_t size = (size_t)(info.mappings[i].sms_size);
+ for (int i=0; i < 3; ++i) {
+ void* mmapAddress = (void*)(uintptr_t)(info.mappings[i].sfm_address);
+ size_t size = (size_t)(info.mappings[i].sfm_size);
//dyld::log("dyld: mapping address %p with size 0x%08lX\n", mmapAddress, size);
int protection = 0;
- if ( info.mappings[i].sms_init_prot & VM_PROT_EXECUTE )
+ if ( info.mappings[i].sfm_init_prot & VM_PROT_EXECUTE )
protection |= PROT_EXEC;
- if ( info.mappings[i].sms_init_prot & VM_PROT_READ )
+ if ( info.mappings[i].sfm_init_prot & VM_PROT_READ )
protection |= PROT_READ;
- if ( info.mappings[i].sms_init_prot & VM_PROT_WRITE )
+ if ( info.mappings[i].sfm_init_prot & VM_PROT_WRITE )
protection |= PROT_WRITE;
- off_t offset = info.mappings[i].sms_file_offset;
+ off_t offset = info.mappings[i].sfm_file_offset;
if ( ::mmap(mmapAddress, size, protection, MAP_FIXED | MAP_PRIVATE, info.fd, offset) != mmapAddress ) {
// failed to map some chunk of this shared cache file
// clear shared region
- ::mmap((void*)((long)SHARED_REGION_BASE), SHARED_REGION_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE| MAP_ANON, 0, 0);
+ vm_deallocate(mach_task_self(), (vm_address_t)info.sharedRegionStart, (vm_size_t)info.sharedRegionSize);
// return failure
results->loadAddress = nullptr;
results->errorMessage = "could not mmap() part of dyld cache";
- ::close(info.fd);
return false;
}
}
- ::close(info.fd);
-
-#if TARGET_OS_SIMULATOR // simulator caches do not support sliding
+
+#if TARGET_IPHONE_SIMULATOR // simulator caches do not support sliding
return true;
#else
- __block bool success = true;
- for (int i=0; i < info.mappingsCount; ++i) {
- if ( info.mappings[i].sms_slide_size == 0 )
- continue;
- const dyld_cache_slide_info* slideInfoHeader = (const dyld_cache_slide_info*)info.mappings[i].sms_slide_start;
- const uint8_t* mappingPagesStart = (const uint8_t*)info.mappings[i].sms_address;
- success &= rebaseDataPages(options.verbose, slideInfoHeader, mappingPagesStart, info.sharedRegionStart, results);
- }
+ bool success = rebaseDataPages(options.verbose, info, results);
if ( options.verbose ) {
dyld::log("mapped dyld cache file private to process (%s):\n", results->path);
- verboseSharedCacheMappings(info.mappings, info.mappingsCount);
+ verboseSharedCacheMappings(info.mappings);
}
return success;
#endif
@@ -861,7 +669,7 @@
results->slide = 0;
results->errorMessage = nullptr;
-#if TARGET_OS_SIMULATOR
+#if TARGET_IPHONE_SIMULATOR
// simulator only supports mmap()ing cache privately into process
return mapCachePrivate(options, results);
#else
@@ -891,7 +699,7 @@
if ( loadInfo.loadAddress->header.formatVersion != dyld3::closure::kFormatVersion ) {
// support for older cache with a different Image* format
-#if TARGET_OS_IPHONE
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
uint64_t hash = 0;
for (const char* s=dylibPathToFind; *s != '\0'; ++s)
hash += hash*4 + *s;
@@ -899,7 +707,7 @@
const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)loadInfo.loadAddress + loadInfo.loadAddress->header.imagesOffset);
const dyld_cache_image_info* const end = &start[loadInfo.loadAddress->header.imagesCount];
for (const dyld_cache_image_info* p = start; p != end; ++p) {
-#if TARGET_OS_IPHONE
+#if __IPHONE_OS_VERSION_MIN_REQUIRED
// on iOS, inode is used to hold hash of path
if ( (p->modTime == 0) && (p->inode != hash) )
continue;
@@ -922,7 +730,34 @@
if ( loadInfo.loadAddress->hasImagePath(dylibPathToFind, imageIndex) ) {
results->image = images->imageForNum(imageIndex+1);
}
-
+ #if __MAC_OS_X_VERSION_MIN_REQUIRED
+ else {
+ // <rdar://problem/32740215> handle symlink to cached dylib
+ if ( loadInfo.loadAddress->header.dylibsExpectedOnDisk ) {
+ struct stat statBuf;
+ if ( dyld::my_stat(dylibPathToFind, &statBuf) == 0 ) {
+ // on macOS we store the inode and mtime of each dylib in the cache in the dyld_cache_image_info array
+ const dyld_cache_image_info* const start = (dyld_cache_image_info*)((uint8_t*)loadInfo.loadAddress + loadInfo.loadAddress->header.imagesOffset);
+ const dyld_cache_image_info* const end = &start[loadInfo.loadAddress->header.imagesCount];
+ for (const dyld_cache_image_info* p = start; p != end; ++p) {
+ if ( (p->inode == statBuf.st_ino) && (p->modTime == statBuf.st_mtime) ) {
+ imageIndex = (uint32_t)(p - start);
+ results->image = images->imageForNum(imageIndex+1);
+ break;
+ }
+ }
+ }
+ }
+ else {
+ char resolvedPath[PATH_MAX];
+ if ( realpath(dylibPathToFind, resolvedPath) != nullptr ) {
+ if ( loadInfo.loadAddress->hasImagePath(resolvedPath, imageIndex) ) {
+ results->image = images->imageForNum(imageIndex+1);
+ }
+ }
+ }
+ }
+#endif
if ( results->image == nullptr )
return false;
@@ -935,26 +770,13 @@
bool pathIsInSharedCacheImage(const SharedCacheLoadInfo& loadInfo, const char* dylibPathToFind)
{
- if ( (loadInfo.loadAddress == nullptr) )
+ if ( (loadInfo.loadAddress == nullptr) || (loadInfo.loadAddress->header.formatVersion != closure::kFormatVersion) )
return false;
uint32_t imageIndex;
return loadInfo.loadAddress->hasImagePath(dylibPathToFind, imageIndex);
}
-void deallocateExistingSharedCache()
-{
-#if TARGET_OS_SIMULATOR
- // dyld deallocated macOS shared cache before jumping into dyld_sim
-#else
- // <rdar://problem/50773474> remove the shared region sub-map
- uint64_t existingCacheAddress = 0;
- if ( __shared_region_check_np(&existingCacheAddress) == 0 ) {
- ::mmap((void*)((long)SHARED_REGION_BASE), SHARED_REGION_SIZE, PROT_NONE, MAP_FIXED | MAP_PRIVATE| MAP_ANON, 0, 0);
- }
-#endif
-
-}
} // namespace dyld3