Loading...
--- dyld/dyld-750.6/launch-cache/dsc_extractor.cpp
+++ dyld/dyld-635.2/launch-cache/dsc_extractor.cpp
@@ -33,6 +33,7 @@
#include <sys/mman.h>
#include <sys/syslimits.h>
#include <libkern/OSByteOrder.h>
+#include <mach-o/fat.h>
#include <mach-o/arch.h>
#include <mach-o/loader.h>
#include <Availability.h>
@@ -486,8 +487,52 @@
template <typename A>
-void dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, const std::vector<seg_info>& segments) {
+size_t dylib_maker(const void* mapped_cache, std::vector<uint8_t> &dylib_data, const std::vector<seg_info>& segments) {
typedef typename A::P P;
+
+ int32_t nfat_archs = 0;
+ uint32_t offsetInFatFile = 4096;
+ uint8_t *base_ptr = &dylib_data.front();
+
+#define FH reinterpret_cast<fat_header*>(base_ptr)
+#define FA reinterpret_cast<fat_arch*>(base_ptr + (8 + (nfat_archs - 1) * sizeof(fat_arch)))
+
+ if(dylib_data.size() >= 4096 && OSSwapBigToHostInt32(FH->magic) == FAT_MAGIC) {
+ // have fat header, append new arch to end
+ nfat_archs = OSSwapBigToHostInt32(FH->nfat_arch);
+ offsetInFatFile = OSSwapBigToHostInt32(FA->offset) + OSSwapBigToHostInt32(FA->size);
+ }
+
+ // First see if this slice already exists.
+ for(std::vector<seg_info>::const_iterator it=segments.begin(); it != segments.end(); ++it) {
+ if(strcmp(it->segName, "__TEXT") == 0 ) {
+ const macho_header<P> *textMH = reinterpret_cast<macho_header<P>*>((uint8_t*)mapped_cache+it->offset);
+
+ // if this cputype/subtype already exist in fat header, then return immediately
+ for(int32_t i=0; i < nfat_archs; ++i) {
+ fat_arch *afa = reinterpret_cast<fat_arch*>(base_ptr+8)+i;
+ if (afa->cputype == (cpu_type_t)OSSwapHostToBigInt32(textMH->cputype()) && afa->cpusubtype == (cpu_type_t)OSSwapHostToBigInt32(textMH->cpusubtype())) {
+ //fprintf(stderr, "arch already exists in fat dylib\n");
+ return offsetInFatFile;
+ }
+ }
+ }
+ }
+
+ if (dylib_data.empty()) {
+ // Reserve space for the fat header.
+ dylib_data.resize(4096);
+ base_ptr = &dylib_data.front();
+ FH->magic = OSSwapHostToBigInt32(FAT_MAGIC);
+ }
+
+ FH->nfat_arch = OSSwapHostToBigInt32(++nfat_archs);
+
+ FA->cputype = 0; // filled in later
+ FA->cpusubtype = 0; // filled in later
+ FA->offset = OSSwapHostToBigInt32(offsetInFatFile);
+ FA->size = 0; // filled in later
+ FA->align = OSSwapHostToBigInt32(12);
size_t additionalSize = 0;
for(std::vector<seg_info>::const_iterator it=segments.begin(); it != segments.end(); ++it) {
@@ -502,8 +547,12 @@
uint64_t textOffsetInCache = 0;
for( std::vector<seg_info>::const_iterator it=segments.begin(); it != segments.end(); ++it) {
- if(strcmp(it->segName, "__TEXT") == 0 )
- textOffsetInCache = it->offset;
+ if(strcmp(it->segName, "__TEXT") == 0 ) {
+ textOffsetInCache = it->offset;
+ const macho_header<P> *textMH = reinterpret_cast<macho_header<P>*>((uint8_t*)mapped_cache+textOffsetInCache);
+ FA->cputype = OSSwapHostToBigInt32(textMH->cputype());
+ FA->cpusubtype = OSSwapHostToBigInt32(textMH->cpusubtype());
+ }
//printf("segName=%s, offset=0x%llX, size=0x%0llX\n", it->segName, it->offset, it->sizem);
// Copy all but the __LINKEDIT. It will be copied later during the optimizer in to a temporary buffer but it would
@@ -528,7 +577,12 @@
while (new_dylib_data.size() % 4096)
new_dylib_data.push_back(0);
+ // update fat header with new file size
+ FA->size = OSSwapHostToBigInt32(new_dylib_data.size());
+#undef FH
+#undef FA
dylib_data.insert(dylib_data.end(), new_dylib_data.begin(), new_dylib_data.end());
+ return offsetInFatFile;
}
typedef __typeof(dylib_maker<x86>) dylib_maker_func;
@@ -557,7 +611,7 @@
progress(progress) {
extractors.reserve(map.size());
- for (auto it : map)
+ for (const std::pair<const char*, std::vector<seg_info>>& it : map)
extractors.emplace_back(it.first, it.second);
// Limit the number of open files. 16 seems to give better performance than higher numbers.
@@ -611,21 +665,39 @@
make_dirs(dylib_path);
// open file, create if does not already exist
- int fd = ::open(dylib_path, O_CREAT | O_TRUNC | O_EXLOCK | O_RDWR, 0644);
+ int fd = ::open(dylib_path, O_CREAT | O_EXLOCK | O_RDWR, 0644);
if ( fd == -1 ) {
fprintf(stderr, "can't open or create dylib file %s, errnor=%d\n", dylib_path, errno);
result = -1;
return;
}
- std::vector<uint8_t> vec;
- context.dylib_create_func(context.mapped_cache, vec, segInfo);
+ struct stat statbuf;
+ if (fstat(fd, &statbuf)) {
+ fprintf(stderr, "Error: stat failed for dyld file %s, errnor=%d\n", dylib_path, errno);
+ close(fd);
+ result = -1;
+ return;
+ }
+
+ std::vector<uint8_t> vec((size_t)statbuf.st_size);
+ if(pread(fd, &vec.front(), vec.size(), 0) != (long)vec.size()) {
+ fprintf(stderr, "can't read dylib file %s, errnor=%d\n", dylib_path, errno);
+ close(fd);
+ result = -1;
+ return;
+ }
+
+ const size_t offset = context.dylib_create_func(context.mapped_cache, vec, segInfo);
context.progress(context.count++, (unsigned)context.map.size());
- // Write file data
- if( write(fd, &vec.front(), vec.size()) == -1) {
- fprintf(stderr, "error writing, errnor=%d\n", errno);
- result = -1;
+ if(offset != vec.size()) {
+ //Write out the first page, and everything after offset
+ if( pwrite(fd, &vec.front(), 4096, 0) == -1
+ || pwrite(fd, &vec.front() + offset, vec.size() - offset, offset) == -1) {
+ fprintf(stderr, "error writing, errnor=%d\n", errno);
+ result = -1;
+ }
}
close(fd);
@@ -654,6 +726,7 @@
size_t inBbufferSize = 0;
for (auto& sharedCacheRegion : sharedCacheRegions)
inBbufferSize += (sharedCacheRegion.second - sharedCacheRegion.first);
+ uint32_t slotCountFromRegions = (uint32_t)((inBbufferSize + CS_PAGE_SIZE - 1) / CS_PAGE_SIZE);
// Now take the cd hash from the cache itself and validate the regions we found.
uint8_t* codeSignatureRegion = (uint8_t*)mapped_cache + dyldSharedCache->header.codeSignatureOffset;
@@ -694,8 +767,6 @@
return -1;
}
- uint32_t pageSize = 1 << cd->pageSize;
- uint32_t slotCountFromRegions = (uint32_t)((inBbufferSize + pageSize - 1) / pageSize);
if ( ntohl(cd->nCodeSlots) < slotCountFromRegions ) {
fprintf(stderr, "Error: dyld shared cache code signature directory num slots is incorrect.\n");
return -1;
@@ -704,10 +775,7 @@
uint32_t dscDigestFormat = kCCDigestNone;
switch (cd->hashType) {
case CS_HASHTYPE_SHA1:
-#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wdeprecated-declarations"
dscDigestFormat = kCCDigestSHA1;
-#pragma clang diagnostic pop
break;
case CS_HASHTYPE_SHA256:
dscDigestFormat = kCCDigestSHA256;
@@ -729,7 +797,7 @@
continue;
inBbufferSize += (sharedCacheRegion.second - sharedCacheRegion.first);
}
- uint32_t slotCountToProcess = (uint32_t)((inBbufferSize + pageSize - 1) / pageSize);
+ uint32_t slotCountToProcess = (uint32_t)((inBbufferSize + CS_PAGE_SIZE - 1) / CS_PAGE_SIZE);
for (unsigned i = 0; i != slotCountToProcess; ++i) {
// Skip data pages as those may have been slid by ASLR in the extracted file
@@ -737,7 +805,7 @@
if ( (fileOffset >= mappings[1].fileOffset) && (fileOffset < (mappings[1].fileOffset + mappings[1].size)) )
continue;
- CCDigest(dscDigestFormat, (uint8_t*)mapped_cache + fileOffset, (size_t)csPageSize, cdHashBuffer);
+ CCDigest(dscDigestFormat, (uint8_t*)mapped_cache + fileOffset, csPageSize, cdHashBuffer);
uint8_t* cacheCdHashBuffer = hashSlot + (i * cd->hashSize);
if (memcmp(cdHashBuffer, cacheCdHashBuffer, cd->hashSize) != 0) {
fprintf(stderr, "Error: dyld shared cache code signature for page %d is incorrect.\n", i);