Loading...
--- dyld/dyld-1122.1/common/ProcessAtlas.cpp
+++ dyld/dyld-1330/common/ProcessAtlas.cpp
@@ -26,6 +26,7 @@
#if !TARGET_OS_EXCLAVEKIT
+#include <span>
#include <atomic>
#include <cstring>
#include <Block.h>
@@ -49,24 +50,27 @@
#include "dyld_process_info_internal.h" // For dyld_all_image_infos_{32,64}
#include "Defines.h"
+#include "Header.h"
#include "DyldSharedCache.h"
-#include "MachOFile.h"
#include "PVLEInt64.h"
-#include "MachOFile.h"
#include "MachOLoaded.h"
#include "ProcessAtlas.h"
-#include "Utils.h"
+#include "Utilities.h"
+#include "SafeVMPrimitives.h"
#include "CRC32c.h"
#include "UUID.h"
+#include "Bitmap.h"
using lsl::CRC32c;
using lsl::Allocator;
using lsl::emitPVLEUInt64;
using lsl::readPVLEUInt64;
+using lsl::Bitmap;
using dyld3::FatFile;
-using dyld3::MachOFile;
+
+using mach_o::Header;
// TODO: forEach shared cache needs to filter out subcaches and skip them
// The allocations made by a snapshot need to last for the life of a spanshot. In libdyld that is under the caller control
@@ -76,8 +80,10 @@
#if BUILDING_DYLD
#define _transactionalAllocator _ephemeralAllocator
#else
-#define _transactionalAllocator Allocator::defaultAllocator()
+#define _transactionalAllocator MemoryManager::memoryManager().defaultAllocator()
#endif
+
+#define BLEND_KERN_RETURN_LOCATION(kr, loc) (kr) = ((kr & 0x00ffffff) | loc<<24);
namespace {
static const size_t kCachePeekSize = 0x4000;
@@ -96,7 +102,7 @@
static void getCacheInfo(const dyld_cache_header *cache, uint64_t &headerSize, bool& splitCache) {
// If we have sub caches, then the cache header itself tells us how much space we need to cover all caches
- if ( cache->mappingOffset >= __offsetof(dyld_cache_header, subCacheArrayCount) ) {
+ if ( cache->mappingOffset >= offsetof(dyld_cache_header, subCacheArrayCount) ) {
// New style cache
headerSize = cache->subCacheArrayOffset + (sizeof(dyld_subcache_entry)*cache->subCacheArrayCount);
splitCache = true;
@@ -121,56 +127,6 @@
namespace dyld4 {
namespace Atlas {
-
-Bitmap::Bitmap(Allocator& allocator, size_t size)
- : _size(size), _bitmap(UniquePtr<std::byte>((std::byte*)allocator.malloc((size+7)/8))) {}
-
-Bitmap::Bitmap(Allocator& allocator, std::span<std::byte>& data) {
- _size = (size_t)readPVLEUInt64(data);
- const size_t byteSize = (_size+7)/8;
- _bitmap = UniquePtr<std::byte>((std::byte*)allocator.malloc(byteSize));
- _bitmap.withUnsafe([&](std::byte* bitmap) {
- std::copy(&data[0], &data[byteSize], &bitmap[0]);
- });
- data = data.last(data.size()-byteSize);
-}
-
-Bitmap::Bitmap(Bitmap&& other) {
- swap(other);
-}
-
-Bitmap& Bitmap::operator=(Bitmap&& other) {
- swap(other);
- return *this;
-}
-
-void Bitmap::setBit(size_t bit) {
- contract(bit < _size);
- _bitmap.withUnsafe([&](std::byte* bitmap) {
- std::byte* byte = &bitmap[bit/8];
- (*byte) |= (std::byte)(1<<(bit%8));
- });
-}
-
-void Bitmap::emit(Vector<std::byte>& data) const {
- emitPVLEUInt64(_size, data);
- const size_t byteSize = (_size+7)/8;
- _bitmap.withUnsafe([&](std::byte* bitmap) {
- std::copy(&bitmap[0], &bitmap[byteSize], std::back_inserter(data));
- });
-}
-
-size_t Bitmap::size() const {
- return _size;
-}
-
-bool Bitmap::checkBit(size_t bit) const {
- contract(bit < _size);
- return ((std::byte)0 != _bitmap.withUnsafe([&](std::byte* bitmap) {
- std::byte* byte = &bitmap[bit/8];
- return ((*byte) & (std::byte)(1<<(bit%8)));
- }));
-}
#pragma mark -
#pragma mark Mappers
@@ -209,7 +165,7 @@
#endif
}
-SharedPtr<Mapper> Mapper::mapperForSharedCache(Allocator& _ephemeralAllocator, FileRecord& file, const void* baseAddress) {
+SharedPtr<Mapper> Mapper::mapperForSharedCache(Allocator& _ephemeralAllocator, FileRecord& file, SafePointer baseAddress) {
bool useLocalCache = false;
size_t length = 0;
uint64_t slide = 0;
@@ -247,7 +203,7 @@
}
if (!baseAddress) {
// No base address passed in, treat as unslid
- baseAddress = (void*)onDiskCacheHeader->sharedRegionStart;
+ baseAddress = onDiskCacheHeader->sharedRegionStart;
}
slide = (uint64_t)baseAddress-(uint64_t)onDiskCacheHeader->sharedRegionStart;
uint64_t headerSize = 0;
@@ -295,7 +251,7 @@
auto subCaches = (dyld_subcache_entry*)&onDiskHeaderBytes[onDiskCacheHeader->subCacheArrayOffset];
for (auto i = 0; i < onDiskCacheHeader->subCacheArrayCount; ++i) {
char subCachePath[PATH_MAX];
- if (onDiskCacheHeader->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType)) {
+ if (onDiskCacheHeader->mappingOffset <= offsetof(dyld_cache_header, cacheSubType)) {
snprintf(&subCachePath[0], sizeof(subCachePath), "%s.%u", file.getPath(), i+1);
} else {
char basePath[PATH_MAX];
@@ -321,7 +277,7 @@
auto onDiskSubcacheUUID = UUID(subCache->uuid);
uint8_t uuidBuf[16];
- if (onDiskCacheHeader->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType)) {
+ if (onDiskCacheHeader->mappingOffset <= offsetof(dyld_cache_header, cacheSubType)) {
auto subCacheArray = (dyld_subcache_entry_v1*)&onDiskHeaderBytes[onDiskCacheHeader->subCacheArrayOffset];
memcpy(uuidBuf, subCacheArray[i].uuid, 16);
} else {
@@ -405,7 +361,7 @@
return { _transactionalAllocator.makeShared<Mapper>(_transactionalAllocator, mappings), baseAddress };
}
-SharedPtr<Mapper> Mapper::mapperForMachO(Allocator& _ephemeralAllocator, FileRecord& file, const UUID& uuid, const void* baseAddress) {
+SharedPtr<Mapper> Mapper::mapperForMachO(Allocator& _ephemeralAllocator, FileRecord& file, const UUID& uuid, const SafePointer baseAddress) {
const char* filePath = file.getPath();
// open filePath
int fd = dyld3::open(filePath, O_RDONLY, 0);
@@ -421,21 +377,21 @@
}
// mmap whole file temporarily
- void* tempMapping = ::mmap(nullptr, (size_t)sb.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE, fd, 0);
+ void* tempMapping = ::mmap(nullptr, (size_t)sb.st_size, PROT_READ, MAP_FILE | MAP_PRIVATE | MAP_RESILIENT_CODESIGN, fd, 0);
if ( tempMapping == MAP_FAILED ) {
::close(fd);
return nullptr;
}
// if fat file, pick matching slice
- __block const MachOFile* mf = nullptr;
+ __block const Header* mf = nullptr;
const FatFile* ff = FatFile::isFatFile(tempMapping);
__block uint64_t fileOffset = 0;
if (ff) {
uint64_t fileLength = sb.st_size;
Diagnostics diag;
ff->forEachSlice(diag, fileLength, ^(uint32_t sliceCpuType, uint32_t sliceCpuSubType, const void *sliceStart, uint64_t sliceSize, bool &stop) {
- auto slice = (MachOFile*)sliceStart;
+ auto slice = (Header*)sliceStart;
uuid_t sliceUUIDRaw;
slice->getUuid(sliceUUIDRaw);
auto sliceUUID = UUID(sliceUUIDRaw);
@@ -449,7 +405,7 @@
diag.clearError();
}
if (!mf) {
- auto slice = MachOFile::isMachO(tempMapping);
+ auto slice = Header::isMachO({(uint8_t*)tempMapping, (size_t)sb.st_size});
if (slice) {
uuid_t sliceUUID;
slice->getUuid(sliceUUID);
@@ -465,16 +421,16 @@
}
__block Vector<Mapper::Mapping> mappings(_transactionalAllocator);
__block uint64_t slide = 0;
- mf->forEachSegment(^(const MachOFile::SegmentInfo &info, bool &stop) {
- if (strncmp(info.segName, "__TEXT", 16) == 0) {
- slide = (uint64_t)baseAddress - info.vmAddr;
+ mf->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
+ if ( info.segmentName == "__TEXT" ) {
+ slide = (uint64_t)baseAddress - info.vmaddr;
}
// fprintf(stderr, "Mapping\n");
// fprintf(stderr, "fd\tAddress\tFile Offset\tSize\n");
// fprintf(stderr, "%u\t0x%llx\t0x%llx\t%llu\n", fd, info.vmAddr + slide, info.fileOffset + fileOffset, info.vmSize);
mappings.emplace_back((Mapper::Mapping) {
- .address = info.vmAddr + slide,
- .size = info.vmSize,
+ .address = info.vmaddr + slide,
+ .size = info.vmsize,
.offset = info.fileOffset + fileOffset,
.fd = fd
});
@@ -502,46 +458,46 @@
}
}
-std::pair<void*,bool> Mapper::map(const void* addr, uint64_t size) const {
+std::pair<SafePointer,bool> Mapper::map(const SafePointer addr, uint64_t size) const {
if (_flatMapping) {
uint64_t offset = (uint64_t)addr-(uint64_t)baseAddress();
- return {(void*)((uintptr_t)_flatMapping+offset),false};
+ return {(uint64_t)((uintptr_t)_flatMapping+offset),false};
}
if (_mappings.size() == 0) {
// No mappings means we are an identity mapper
- return { (void*)addr, false };
+ return { addr, false };
}
for (const auto& mapping : _mappings) {
if (((uint64_t)addr >= mapping.address) && ((uint64_t)addr < (mapping.address + mapping.size))) {
if (mapping.fd == -1) {
- return {(void*)(((uint64_t)addr-mapping.address)+mapping.offset), false};
+ return {(((uint64_t)addr-mapping.address)+mapping.offset), false};
}
assert(((uint64_t)addr + size) <= mapping.address + mapping.size);
- off_t offset = (off_t)addr - mapping.address + mapping.offset;
+ uint64_t offset = (uint64_t)addr - mapping.address + mapping.offset;
// Handle unaligned mmap
void* newMapping = nullptr;
size_t extraBytes = 0;
- off_t roundedOffset = offset & (-1*PAGE_SIZE);
+ uint64_t roundedOffset = offset & (-1*PAGE_SIZE);
extraBytes = (size_t)offset - (size_t)roundedOffset;
newMapping = mmap(nullptr, (size_t)size+extraBytes, PROT_READ, MAP_FILE | MAP_PRIVATE, mapping.fd, roundedOffset);
- if (newMapping == (void*)-1) {
+ if (newMapping == MAP_FAILED) {
// fprintf(stderr, "mmap failed: %s (%d)\n", strerror(errno), errno);
- return {(void*)1, false};
- }
- return {(void*)((uintptr_t)newMapping+extraBytes),true};
- }
- }
- return {(void*)-1, false};
-}
-
-void Mapper::unmap(const void* addr, uint64_t size) const {
- void* roundedAddr = (void*)((intptr_t)addr & (-1*PAGE_SIZE));
- size_t extraBytes = (uintptr_t)addr - (uintptr_t)roundedAddr;
+ return { SafePointer(), false};
+ }
+ return {(uint64_t)((uintptr_t)newMapping+extraBytes),true};
+ }
+ }
+ return {SafePointer(), false};
+}
+
+void Mapper::unmap(const SafePointer addr, uint64_t size) const {
+ void* roundedAddr = (void*)((intptr_t)(uint64_t)addr & (-1*PAGE_SIZE));
+ size_t extraBytes = (uintptr_t)(uint64_t)addr - (uintptr_t)roundedAddr;
munmap(roundedAddr, (size_t)size+extraBytes);
}
-const void* Mapper::baseAddress() const {
- return (const void*)_mappings[0].address;
+const SafePointer Mapper::baseAddress() const {
+ return _mappings[0].address;
}
const uint64_t Mapper::size() const {
@@ -589,25 +545,25 @@
#if BUILDING_DYLD
Image::Image(RuntimeState* state, Allocator& ephemeralAllocator, SharedPtr<Mapper>& mapper, const Loader* ldr)
- : _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _rebasedAddress((void*)ldr->loadAddress(*state)) {
+ : _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _rebasedAddress((uint64_t)ldr->loadAddress(*state)) {
auto fileID = ldr->fileID(*state);
if (fileID.inode() && fileID.device()) {
_file = state->fileManager.fileRecordForFileID(ldr->fileID(*state));
if ( _file.volume().empty() ) {
- _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path());
+ _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path(*state));
}
} else {
- _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path());
+ _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path(*state));
}
}
#endif
-Image::Image(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, const struct mach_header* mh)
- : _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _rebasedAddress((void*)mh) {}
-Image::Image(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, const struct mach_header* mh, const UUID& uuid)
- : _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _uuid(uuid), _rebasedAddress((void*)mh) {}
-
-Image::Image(Allocator& ephemeralAllocator, SharedPtr<Mapper>& mapper, void* baseAddress, uint64_t cacheSlide, SharedCache* sharedCache)
- : _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _sharedCacheSlide(cacheSlide), _rebasedAddress((void*)((uint64_t)baseAddress+cacheSlide)), _sharedCache(sharedCache) {}
+Image::Image(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, const SafePointer mh)
+ : _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _rebasedAddress(mh) {}
+Image::Image(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, const SafePointer mh, const UUID& uuid)
+ : _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _uuid(uuid), _rebasedAddress(mh) {}
+
+Image::Image(Allocator& ephemeralAllocator, SharedPtr<Mapper>& mapper, SafePointer baseAddress, uint64_t cacheSlide, SharedCache* sharedCache)
+ : _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _sharedCacheSlide(cacheSlide), _rebasedAddress(((uint64_t)baseAddress+cacheSlide)), _sharedCache(sharedCache) {}
Image::Image(Image&& other) : _ephemeralAllocator(other._ephemeralAllocator) {
swap(other);
@@ -644,7 +600,7 @@
return nullptr;
}
if (!_ml) {
- void* slidML = (void*)rebasedAddress();
+ SafePointer slidML = rebasedAddress();
// Note, using 4k here as we might be an arm64e process inspecting an x86_64 image, which uses 4k pages
if (!_mapper && !_mapperFailed) {
_mapper = Mapper::mapperForMachO(_transactionalAllocator, _file, _uuid, _rebasedAddress);
@@ -654,6 +610,10 @@
return nullptr;
}
_ml = _mapper->map<MachOLoaded>(slidML, 4096);
+ if (!_ml) {
+ _mapperFailed = true;
+ return nullptr;
+ }
size_t size = _ml->sizeofcmds;
if ( _ml->magic == MH_MAGIC_64 ) {
size += sizeof(mach_header_64);
@@ -662,6 +622,10 @@
}
if (size > 4096) {
_ml = _mapper->map<MachOLoaded>(slidML, size);
+ if (!_ml) {
+ _mapperFailed = true;
+ return nullptr;
+ }
}
}
// This is a bit of a mess. With compact info this will be unified, but for now we use a lot of hacky abstactions here to deal with
@@ -672,7 +636,7 @@
const UUID& Image::uuid() const {
if (!_uuidLoaded) {
uuid_t fileUUID;
- const MachOLoaded* mh = ml();
+ const Header* mh = (Header*)ml();
if (mh && mh->hasMachOMagic()) {
if (mh->getUuid(fileUUID))
_uuid = UUID(fileUUID);
@@ -682,7 +646,7 @@
return _uuid;
}
-uint64_t Image::rebasedAddress() const {
+SafePointer Image::rebasedAddress() const {
return (uint64_t)_rebasedAddress;
}
@@ -690,7 +654,7 @@
const char* Image::installname() const {
if (!_installnameLoaded) {
if (ml()) {
- _installname = ml()->installName();
+ _installname = ((const Header*)ml())->installName();
}
_installnameLoaded = true;
}
@@ -710,7 +674,7 @@
}
uint64_t Image::sharedCacheVMOffset() const {
- return (uint64_t)_rebasedAddress - sharedCache()->rebasedAddress();
+ return (uint64_t)_rebasedAddress - (uint64_t)sharedCache()->rebasedAddress();
}
uint32_t Image::pointerSize() {
@@ -720,34 +684,34 @@
bool Image::forEachSegment(void (^block)(const char* segmentName, uint64_t vmAddr, uint64_t vmSize, int perm)) {
if (!ml()) { return false; }
- __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
- ml()->forEachSegment(^(const MachOLoaded::SegmentInfo &info, bool &stop) {
+ __block uint64_t slide = (uint64_t)_rebasedAddress - ((const Header*)ml())->preferredLoadAddress();
+ ((const Header*)ml())->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
uint64_t vmAddr = 0x0;
if ( _sharedCacheSlide.has_value() ) {
- vmAddr = info.vmAddr + _sharedCacheSlide.value();
+ vmAddr = info.vmaddr + _sharedCacheSlide.value();
} else {
if ( ml()->isMainExecutable() ) {
- if ( strncmp(info.segName, "__PAGEZERO", 10) == 0 )
+ if ( info.segmentName.starts_with("__PAGEZERO") )
return;
}
- vmAddr = info.vmAddr + slide;
- }
- block(info.segName, vmAddr, info.vmSize, info.protections);
+ vmAddr = info.vmaddr + slide;
+ }
+ block(info.segmentName.data(), vmAddr, info.vmsize, info.initProt);
});
return true;
}
bool Image::forEachSection(void (^block)(const char* segmentName, const char* sectionName, uint64_t vmAddr, uint64_t vmSize)) {
if (!ml()) { return false; }
- __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
- ml()->forEachSection(^(const MachOLoaded::SectionInfo &info, bool malformedSectionRange, bool &stop) {
+ __block uint64_t slide = (uint64_t)_rebasedAddress - ((const Header*)ml())->preferredLoadAddress();
+ ((const Header*)ml())->forEachSection(^(const Header::SectionInfo &info, bool &stop) {
uint64_t sectAddr = 0x0;
if ( _sharedCacheSlide.has_value() ) {
- sectAddr = info.sectAddr + _sharedCacheSlide.value();
+ sectAddr = info.address + _sharedCacheSlide.value();
} else {
- sectAddr = info.sectAddr + slide;
- }
- block(info.segInfo.segName, info.sectName, sectAddr, info.sectSize);
+ sectAddr = info.address + slide;
+ }
+ block(info.segmentName.data(), info.sectionName.data(), sectAddr, info.size);
});
return true;
}
@@ -755,23 +719,23 @@
bool Image::contentForSegment(const char* segmentName, void (^contentReader)(const void* content, uint64_t vmAddr, uint64_t vmSize)) {
if (!ml()) { return false; }
__block bool result = false;
- __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
- ml()->forEachSegment(^(const MachOLoaded::SegmentInfo &info, bool &stop) {
- if (strcmp(segmentName, info.segName) != 0) { return; }
+ __block uint64_t slide = (uint64_t)_rebasedAddress - ((const Header*)ml())->preferredLoadAddress();
+ ((const Header*)ml())->forEachSegment(^(const Header::SegmentInfo &info, bool &stop) {
+ if ( segmentName != info.segmentName ) { return; }
uint64_t vmAddr = 0;
if ( _sharedCacheSlide.has_value() ) {
- vmAddr = info.vmAddr + _sharedCacheSlide.value();
+ vmAddr = info.vmaddr + _sharedCacheSlide.value();
} else {
if ( ml()->isMainExecutable() ) {
- if ( strncmp(info.segName, "__PAGEZERO", 10) == 0 )
+ if ( info.segmentName.starts_with("__PAGEZERO") )
return;
}
- vmAddr = info.vmAddr + slide;
- }
-
- if (info.vmSize) {
- auto content = _mapper->map<uint8_t>((void*)(vmAddr), info.vmSize);
- contentReader((void*)&*content, vmAddr, info.vmSize);
+ vmAddr = info.vmaddr + slide;
+ }
+
+ if (info.vmsize) {
+ auto content = _mapper->map<uint8_t>(vmAddr, info.vmsize);
+ contentReader((void*)&*content, vmAddr, info.vmsize);
} else {
contentReader(nullptr, vmAddr, 0);
}
@@ -784,19 +748,19 @@
bool Image::contentForSection(const char* segmentName, const char* sectionName,
void (^contentReader)(const void* content, uint64_t vmAddr, uint64_t vmSize)) {
__block bool result = false;
- __block uint64_t slide = (uint64_t)_rebasedAddress - ml()->preferredLoadAddress();
- ml()->forEachSection(^(const MachOLoaded::SectionInfo &info, bool malformedRange, bool &stop) {
- if (strcmp(segmentName, info.segInfo.segName) != 0) { return; }
- if (strcmp(sectionName, info.sectName) != 0) { return; }
+ __block uint64_t slide = (uint64_t)_rebasedAddress - ((const Header*)ml())->preferredLoadAddress();
+ ((const Header*)ml())->forEachSection(^(const Header::SectionInfo &info, bool &stop) {
+ if ( segmentName != info.segmentName ) { return; }
+ if ( sectionName != info.sectionName ) { return; }
uint64_t sectAddr = 0;
if ( _sharedCacheSlide.has_value() ) {
- sectAddr = info.sectAddr + _sharedCacheSlide.value();
+ sectAddr = info.address + _sharedCacheSlide.value();
} else {
- sectAddr = info.sectAddr + slide;
- }
- if (info.sectSize) {
- auto content = _mapper->map<uint8_t>((void*)(sectAddr), info.sectSize);
- contentReader((void*)&*content, sectAddr, info.sectSize);
+ sectAddr = info.address + slide;
+ }
+ if (info.size) {
+ auto content = _mapper->map<uint8_t>(sectAddr, info.size);
+ contentReader((void*)&*content, sectAddr, info.size);
} else {
contentReader(nullptr, sectAddr, 0);
}
@@ -811,12 +775,12 @@
SharedCacheLocals::SharedCacheLocals(SharedPtr<Mapper>& M, bool use64BitDylibOffsets)
: _mapper(M), _use64BitDylibOffsets(use64BitDylibOffsets) {
- auto header = _mapper->map<dyld_cache_header>((void*)0, sizeof(dyld_cache_header));
+ auto header = _mapper->map<dyld_cache_header>(0ULL, sizeof(dyld_cache_header));
// Map in the whole locals buffer.
// TODO: Once we have the symbols in their own file, simplify this to just map the whole file
// and not do the header and locals separately
- _locals = _mapper->map<uint8_t>((void*)header->localSymbolsOffset, header->localSymbolsSize);
+ _locals = _mapper->map<uint8_t>(header->localSymbolsOffset, header->localSymbolsSize);
}
const dyld_cache_local_symbols_info* SharedCacheLocals::localInfo() const {
@@ -835,7 +799,7 @@
uint64_t rebasedAddress, bool splitCache)
{
// If we have sub caches, then the cache header itself tells us how much space we need to cover all caches
- if (header->mappingOffset >= __offsetof(dyld_cache_header, subCacheArrayCount) ) {
+ if (header->mappingOffset >= offsetof(dyld_cache_header, subCacheArrayCount) ) {
return header->sharedRegionSize;
} else {
auto headerBytes = (uint8_t*)&*header;
@@ -849,19 +813,19 @@
if (splitCache) {
for (auto i = 0; i < header->subCacheArrayCount; ++i) {
uint64_t subCacheOffset = 0;
- if (header->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType) ) {
+ if (header->mappingOffset <= offsetof(dyld_cache_header, cacheSubType) ) {
auto subCaches = (dyld_subcache_entry_v1*)&headerBytes[header->subCacheArrayOffset];
subCacheOffset = subCaches[i].cacheVMOffset;
} else {
auto subCaches = (dyld_subcache_entry*)&headerBytes[header->subCacheArrayOffset];
subCacheOffset = subCaches[i].cacheVMOffset;
}
- auto subCacheHeader = mapper->map<dyld_cache_header>((void*)(subCacheOffset + rebasedAddress), PAGE_SIZE);
+ auto subCacheHeader = mapper->map<dyld_cache_header>(subCacheOffset + rebasedAddress, PAGE_SIZE);
uint64_t subCacheHeaderSize = 0;
bool splitCacheUnused;
getCacheInfo(&*subCacheHeader, subCacheHeaderSize, splitCacheUnused);
if (subCacheHeaderSize > PAGE_SIZE) {
- subCacheHeader = mapper->map<dyld_cache_header>((void*)(subCacheOffset + rebasedAddress), subCacheHeaderSize);
+ subCacheHeader = mapper->map<dyld_cache_header>(subCacheOffset + rebasedAddress, subCacheHeaderSize);
}
auto subCacheHeaderBytes = (uint8_t*)&*subCacheHeader;
auto subCacheMappings = (dyld_cache_mapping_and_slide_info*)&subCacheHeaderBytes[subCacheHeader->mappingWithSlideOffset];
@@ -876,20 +840,20 @@
}
}
-SharedCache::SharedCache(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, uint64_t rebasedAddress, bool P)
+SharedCache::SharedCache(Allocator& ephemeralAllocator, FileRecord&& file, SharedPtr<Mapper>& mapper, SafePointer rebasedAddress, bool P)
: _ephemeralAllocator(ephemeralAllocator), _file(std::move(file)), _mapper(mapper), _rebasedAddress(rebasedAddress), _private(P)
{
assert(_mapper);
- _header = _mapper->map<dyld_cache_header>((void*)_rebasedAddress, PAGE_SIZE);
+ _header = _mapper->map<dyld_cache_header>(_rebasedAddress, PAGE_SIZE);
uint64_t headerSize = 0;
bool splitCache = false;
getCacheInfo(&*_header, headerSize, splitCache);
if (headerSize > PAGE_SIZE) {
- _header = _mapper->map<dyld_cache_header>((void*)_rebasedAddress, headerSize);
+ _header = _mapper->map<dyld_cache_header>(_rebasedAddress, headerSize);
}
_uuid = UUID(&_header->uuid[0]);
- _slide = _rebasedAddress - _header->sharedRegionStart;
- _size = cacheMappedSize(_header, _mapper, rebasedAddress, splitCache);
+ _slide = (uint64_t)_rebasedAddress - _header->sharedRegionStart;
+ _size = cacheMappedSize(_header, _mapper, (uint64_t)rebasedAddress, splitCache);
}
@@ -903,6 +867,7 @@
"/private/preboot/Cryptexes/OS/System/DriverKit/System/Library/dyld/",
"/System/Cryptexes/OS/System/Library/Caches/com.apple.dyld/",
"/System/Cryptexes/OS/System/Library/dyld/",
+ "/System/Cryptexes/ExclaveOS/System/ExclaveKit/System/Library/dyld/",
"/System/Volumes/Preboot/Cryptexes/Incoming/OS/System/Library/dyld/",
"/System/Volumes/Preboot/Cryptexes/Incoming/OS/System/DriverKit/System/Library/dyld/",
"/private/preboot/Cryptexes/Incoming/OS/System/Library/Caches/com.apple.dyld/",
@@ -911,6 +876,7 @@
"/System/Cryptexes/Incoming/OS/System/Library/dyld/",
"/System/Library/Caches/com.apple.dyld/",
"/System/DriverKit/System/Library/dyld/",
+ "/System/ExclaveKit/System/Library/dyld/",
"/System/Library/dyld/"
};
@@ -977,7 +943,7 @@
UniquePtr<SharedCache> SharedCache::createForFileRecord(Allocator& _ephemeralAllocator, FileRecord&& file) {
auto uuid = UUID();
- auto fileMapper = Mapper::mapperForSharedCache(_ephemeralAllocator, file, 0);
+ auto fileMapper = Mapper::mapperForSharedCache(_ephemeralAllocator, file, 0ULL);
if (!fileMapper) { return nullptr; }
return _transactionalAllocator.makeUnique<SharedCache>(_ephemeralAllocator, std::move(file), fileMapper, (uint64_t)fileMapper->baseAddress(), true);
}
@@ -987,7 +953,7 @@
return _uuid;
}
-uint64_t SharedCache::rebasedAddress() const {
+SafePointer SharedCache::rebasedAddress() const {
return _rebasedAddress;
}
@@ -1010,7 +976,7 @@
if (splitCache) {
auto headerBytes = (std::byte*)&*_header;
char subCachePath[PATH_MAX];
- if (_header->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType)) {
+ if (_header->mappingOffset <= offsetof(dyld_cache_header, cacheSubType)) {
for (auto i = 0; i < _header->subCacheArrayCount; ++i) {
snprintf(&subCachePath[0], sizeof(subCachePath), "%s.%u", _file.getPath(), i+1);
block(subCachePath);
@@ -1022,7 +988,7 @@
block(subCachePath);
}
}
- if ( (_header->mappingOffset >= __offsetof(dyld_cache_header, symbolFileUUID)) && !uuid_is_null(_header->symbolFileUUID) ) {
+ if ( (_header->mappingOffset >= offsetof(dyld_cache_header, symbolFileUUID)) && !uuid_is_null(_header->symbolFileUUID) ) {
strlcpy(&subCachePath[0], _file.getPath(), PATH_MAX);
// On new caches, the locals come from a new subCache file
if (strstr(subCachePath, ".development") != nullptr) {
@@ -1046,7 +1012,7 @@
auto headerBytes = (uint8_t*)&*_header;
auto images = std::span((const dyld_cache_image_text_info*)&headerBytes[_header->imagesTextOffset], (size_t)_header->imagesTextCount);
for (auto i : images) {
- auto image = Image(_ephemeralAllocator, _mapper, (void*)(i.loadAddress), _slide, this);
+ auto image = Image(_ephemeralAllocator, _mapper, i.loadAddress, _slide, this);
block(&image);
}
}
@@ -1054,7 +1020,7 @@
void SharedCache::withImageForIndex(uint32_t idx, void (^block)(Image* image)) {
auto headerBytes = (uint8_t*)&*_header;
auto images = std::span((const dyld_cache_image_text_info*)&headerBytes[_header->imagesTextOffset], (size_t)_header->imagesTextCount);
- auto image = Image(_ephemeralAllocator, _mapper, (void*)(images[idx].loadAddress), _slide, this);
+ auto image = Image(_ephemeralAllocator, _mapper, images[idx].loadAddress, _slide, this);
block(&image);
}
@@ -1065,7 +1031,7 @@
// Where it is depends on the cache header
char localSymbolsCachePath[PATH_MAX];
strlcpy(&localSymbolsCachePath[0], _file.getPath(), PATH_MAX);
- bool useSymbolsFile = (_header->mappingOffset >= __offsetof(dyld_cache_header, symbolFileUUID));
+ bool useSymbolsFile = (_header->mappingOffset >= offsetof(dyld_cache_header, symbolFileUUID));
if ( useSymbolsFile ) {
if ( uuid_is_null(_header->symbolFileUUID) )
return nullptr;
@@ -1116,7 +1082,7 @@
for(auto i = 0; i < _header->mappingCount; ++i) {
// _slide = _baseAddress - _header->sharedRegionStart;
auto mapping = (dyld_cache_mapping_info*)&subCacheHeaderBytes[subCacheHeader->mappingOffset+(i*sizeof(dyld_cache_mapping_info))];
- auto mappingBytes = _mapper->map<uint8_t>((void*)(mapping->address - _slide), mapping->size);
+ auto mappingBytes = _mapper->map<uint8_t>(mapping->address - _slide, mapping->size);
kern_return_t r = vm_copy(mach_task_self(), (vm_address_t)&*mappingBytes, (vm_size_t)mapping->size, (vm_address_t)(mappedSubCache+mapping->fileOffset));
if ( r != KERN_SUCCESS ) {
result = false;
@@ -1142,18 +1108,18 @@
if (splitCache) {
for (auto i = 0; i < _header->subCacheArrayCount; ++i) {
uint64_t subCacheOffset = 0;
- if (_header->mappingOffset <= __offsetof(dyld_cache_header, cacheSubType) ) {
+ if (_header->mappingOffset <= offsetof(dyld_cache_header, cacheSubType) ) {
auto subCaches = (dyld_subcache_entry_v1*)&headerBytes[_header->subCacheArrayOffset];
subCacheOffset = subCaches[i].cacheVMOffset;
} else {
auto subCaches = (dyld_subcache_entry*)&headerBytes[_header->subCacheArrayOffset];
subCacheOffset = subCaches[i].cacheVMOffset;
}
- auto subCacheHeader = _mapper->map<dyld_cache_header>((void*)(rebasedAddress() + subCacheOffset), PAGE_SIZE);
+ auto subCacheHeader = _mapper->map<dyld_cache_header>((uint64_t)rebasedAddress() + subCacheOffset, PAGE_SIZE);
uint64_t subCacheHeaderSize = subCacheHeader->mappingOffset+subCacheHeader->mappingCount*sizeof(dyld_cache_mapping_info);
getCacheInfo(&*_header, headerSize, splitCache);
if (subCacheHeaderSize > PAGE_SIZE) {
- subCacheHeader = _mapper->map<dyld_cache_header>((void*)(rebasedAddress() + subCacheOffset), subCacheHeaderSize);
+ subCacheHeader = _mapper->map<dyld_cache_header>((uint64_t)rebasedAddress() + subCacheOffset, subCacheHeaderSize);
}
// printf("Subcache Offset: %lx\n", (uintptr_t)&headerBytes[subCacheOffset]);
// printf("subCacheHeader: %lx\n", (uintptr_t)&*subCacheHeader);
@@ -1229,6 +1195,8 @@
pid_t pid;
*kr = pid_for_task(_task, &pid);
if ( *kr != KERN_SUCCESS ) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xea);
+ *kr |= 0xeb000000UL;
return nullptr;
}
@@ -1236,6 +1204,7 @@
mach_msg_type_number_t count = MACH_TASK_BASIC_INFO_COUNT;
*kr = task_info(_task, MACH_TASK_BASIC_INFO, (task_info_t)&ti, &count);
if ( *kr != KERN_SUCCESS ) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xe9);
return nullptr;
}
@@ -1259,13 +1228,14 @@
mach_vm_size_t readSize = 0;
*kr = mach_vm_read_overwrite(_task, address, size, (mach_vm_address_t)&unsafeBytes[0], &readSize);
if ( *kr != KERN_SUCCESS ) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xe8);
return;
}
- auto mf = MachOFile::isMachO((const void*)unsafeBytes);
- if (!mf) {
+ auto mh = Header::isMachO({(const uint8_t*)unsafeBytes, (size_t)readSize});
+ if (!mh) {
return;
}
- if ( mf->filetype == MH_EXECUTE ) {
+ if ( mh->isMainExecutable() ) {
int len = proc_regionfilename(pid, address, executablePath, PATH_MAX);
if ( len != 0 ) {
executablePath[len] = '\0';
@@ -1273,11 +1243,11 @@
SharedPtr<Mapper> mapper = nullptr;
auto file = _fileManager.fileRecordForPath(_transactionalAllocator, executablePath);
uuid_t rawUUID;
- mf->getUuid(rawUUID);
+ mh->getUuid(rawUUID);
auto uuid = UUID(rawUUID);
- result->addImage(Image(_transactionalAllocator, std::move(file), mapper, (const mach_header*)address, uuid));
+ result->addImage(Image(_transactionalAllocator, std::move(file), mapper, (uint64_t)address, uuid));
foundMainExecutable = true;
- } else if ( mf->filetype == MH_DYLINKER ) {
+ } else if ( mh->isDylinker() ) {
int len = proc_regionfilename(pid, address, executablePath, PATH_MAX);
if ( len != 0 ) {
executablePath[len] = '\0';
@@ -1285,9 +1255,9 @@
SharedPtr<Mapper> mapper = nullptr;
auto file = _fileManager.fileRecordForPath(_transactionalAllocator, executablePath);
uuid_t rawUUID;
- mf->getUuid(rawUUID);
+ mh->getUuid(rawUUID);
auto uuid = UUID(rawUUID);
- result->addImage(Image(_transactionalAllocator, std::move(file), mapper, (const mach_header*)address, uuid));
+ result->addImage(Image(_transactionalAllocator, std::move(file), mapper, (uint64_t)address, uuid));
foundDyld = true;
}
});
@@ -1319,48 +1289,55 @@
task_dyld_info_data_t task_dyld_info;
*kr = task_info(_task, TASK_DYLD_INFO, (task_info_t)&task_dyld_info, &count);
if ( *kr != KERN_SUCCESS ) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xef);
return nullptr;
}
//The kernel will return MACH_VM_MIN_ADDRESS for an executable that has not had dyld loaded
if (task_dyld_info.all_image_info_addr == MACH_VM_MIN_ADDRESS) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xee);
return nullptr;
}
- uint8_t remoteBuffer[16*1024];
- mach_vm_size_t readSize = 0;
+ uint64_t failedAddress = 0;
while (1) {
// Using mach_vm_read_overwrite because this is part of dyld. If the file is removed or the codesignature is invalid
// then the system is broken beyond recovery anyway
- *kr = mach_vm_read_overwrite(_task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size,
- (mach_vm_address_t)&remoteBuffer[0], &readSize);
+ auto taskInfoBuffer = SafeRemoteBuffer(_task, task_dyld_info.all_image_info_addr, task_dyld_info.all_image_info_size, kr);
if (*kr != KERN_SUCCESS) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xed);
// If we cannot read the all image info this is game over
return nullptr;
}
uint64_t compactInfoAddress;
uint64_t compactInfoSize;
if (task_dyld_info.all_image_info_format == TASK_DYLD_ALL_IMAGE_INFO_32 ) {
- const dyld_all_image_infos_32* info = (const dyld_all_image_infos_32*)&remoteBuffer[0];
+ const dyld_all_image_infos_32* info = (const dyld_all_image_infos_32*)&taskInfoBuffer.data()[0];
compactInfoAddress = info->compact_dyld_image_info_addr;
compactInfoSize = info->compact_dyld_image_info_size;
} else {
- const dyld_all_image_infos_64* info = (const dyld_all_image_infos_64*)&remoteBuffer[0];
+ const dyld_all_image_infos_64* info = (const dyld_all_image_infos_64*)&taskInfoBuffer.data()[0];
compactInfoAddress = info->compact_dyld_image_info_addr;
compactInfoSize = info->compact_dyld_image_info_size;
}
if (compactInfoSize == 0) {
return synthesizeSnapshot(kr);
}
- auto compactInfo = UniquePtr<std::byte>((std::byte*)_transactionalAllocator.malloc((size_t)compactInfoSize));
- *kr = mach_vm_read_overwrite(_task, compactInfoAddress, compactInfoSize, (mach_vm_address_t)&*compactInfo, &readSize);
+
+ auto compactInfoBuffer = SafeRemoteBuffer(_task, compactInfoAddress,compactInfoSize, kr);
if (*kr != KERN_SUCCESS) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xec);
+ if (compactInfoAddress == failedAddress) {
+ // We tried the same address twice and it failed both times, this is not a simple mutation issue, give up and reutrn an error
+ return nullptr;
+ }
+ failedAddress = compactInfoAddress;
// The read failed, chances are the process mutated the compact info, retry
continue;
}
- std::span<std::byte> data = std::span<std::byte>(&*compactInfo, (size_t)compactInfoSize);
- UniquePtr<ProcessSnapshot> result = _transactionalAllocator.makeUnique<ProcessSnapshot>(_ephemeralAllocator, _fileManager, false, data);
+ UniquePtr<ProcessSnapshot> result = _transactionalAllocator.makeUnique<ProcessSnapshot>(_ephemeralAllocator, _fileManager, false, compactInfoBuffer.data());
if (!result->valid()) {
// Something blew up we don't know what
*kr = KERN_FAILURE;
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xeb);
return nullptr;
}
return result;
@@ -1598,14 +1575,46 @@
: _ephemeralAllocator(ephemeralAllocator), _fileManager(fileManager), _images(_transactionalAllocator),
_identityMapper(_transactionalAllocator.makeShared<Mapper>(_transactionalAllocator)), _useIdentityMapper(useIdentityMapper) {}
+#if BUILDING_LIBDYLD && !TARGET_OS_DRIVERKIT && !TARGET_OS_EXCLAVEKIT
+// This function is a private interface between libdyld and Dyld.framework and implemented in Swift
+// there is no header
+extern "C" const bool unwrapCompactInfo(void* _Nonnull buffer, uint64_t* _Nonnull size);
+#endif /* BUILDING_LIBDYLD && !TARGET_OS_DRIVERKIT && !TARGET_OS_EXCLAVEKIT */
+
ProcessSnapshot::ProcessSnapshot(Allocator& ephemeralAllocator, FileManager& fileManager, bool useIdentityMapper, const std::span<std::byte> data)
: _ephemeralAllocator(ephemeralAllocator), _fileManager(fileManager), _images(_transactionalAllocator),
_identityMapper(_transactionalAllocator.makeShared<Mapper>(_transactionalAllocator)), _useIdentityMapper(useIdentityMapper) {
Serializer serializer(*this);
- if (!serializer.deserialize(data)) {
+ bool deserializedSucceeed = serializer.deserialize(data);
+#if BUILDING_LIBDYLD && !TARGET_OS_DRIVERKIT && !TARGET_OS_EXCLAVEKIT
+ static dispatch_once_t onceToken;
+ static __typeof__(unwrapCompactInfo) *unwrapCompactInfoPtr = nullptr;
+ if (!deserializedSucceeed) {
+ // If we failed we try to load the unwrap function
+ dispatch_once(&onceToken, ^{
+ // We attempt a dlopen() here since the unwrapCompactInfo is not in the build yet, and this is a temporary compatibility hack
+ void* dyldFrameworkHandle = dlopen("/System/Library/PrivateFrameworks/Dyld.framework/Dyld", RTLD_NOW);
+ unwrapCompactInfoPtr = (__typeof__(unwrapCompactInfo)*)dlsym(dyldFrameworkHandle, "unwrapCompactInfo");
+ });
+ }
+ // Only try the fallback if we managed to load the unwrap function
+ if (unwrapCompactInfoPtr && !deserializedSucceeed) {
+ std::byte* unwrappedData = (std::byte*)_transactionalAllocator.malloc(data.size());
+ std::copy(data.begin(), data.end(), unwrappedData);
+ uint64_t unwrappedSize = data.size();
+ if (unwrapCompactInfoPtr((void*)unwrappedData, &unwrappedSize)) {
+ std::span<std::byte> unwrappedSpan = std::span<std::byte>(unwrappedData, (size_t)unwrappedSize);
+ deserializedSucceeed = serializer.deserialize(unwrappedSpan);
+ }
+ free((void*)unwrappedData);
+ }
+#endif /* BUILDING_LIBDYLD && !TARGET_OS_DRIVERKIT && !TARGET_OS_EXCLAVEKIT */
+ if (!deserializedSucceeed) {
// Deerialization failed, reset the snapshot and mark invalid
_images.clear();
- _bitmap = nullptr;
+ if (_bitmap) {
+ _bitmap->clear();
+ }
_sharedCache = nullptr;
_platform = 0;
_initialImageCount = 0;
@@ -1662,7 +1671,7 @@
uint64_t address = ~0ULL;
auto i = other._images.begin();
if (i != other._images.end()) {
- address = (*i)->rebasedAddress();
+ address = (uint64_t)(*i)->rebasedAddress();
}
for (auto& image : _images) {
@@ -1674,7 +1683,7 @@
address = ~0ULL;
break;
}
- address = (*i)->rebasedAddress();
+ address = (uint64_t)(*i)->rebasedAddress();
}
if (image->rebasedAddress() != address) {
block(&*image);
@@ -1691,7 +1700,7 @@
}
#if BUILDING_DYLD
-void ProcessSnapshot::addImages(RuntimeState* state, const std::span<const Loader*>& loaders) {
+void ProcessSnapshot::addImages(RuntimeState* state, Vector<ConstAuthLoader>& loaders) {
for (auto& ldr : loaders) {
if (_sharedCache && ldr->dylibInDyldCache) {
_bitmap->setBit(ldr->ref.index);
@@ -1721,7 +1730,7 @@
void ProcessSnapshot::addSharedCacheImage(const struct mach_header* mh) {
assert(mh->flags & MH_DYLIB_IN_CACHE);
- auto header = (dyld_cache_header*)_sharedCache->rebasedAddress();
+ auto header = (dyld_cache_header*)(uint64_t)_sharedCache->rebasedAddress();
auto headerBytes = (uint8_t*)header;
auto slide = (uint64_t)header - header->sharedRegionStart;
auto images = std::span((const dyld_cache_image_text_info*)&headerBytes[header->imagesTextOffset], (size_t)header->imagesTextCount);
@@ -1775,7 +1784,7 @@
if (!name) {
name = "<unknown>";
}
- fprintf(stderr, "0x%llx %s %s\n", image->rebasedAddress(), uuidStr, name);
+ fprintf(stderr, "0x%llx %s %s\n", (uint64_t)image->rebasedAddress(), uuidStr, name);
});
}
@@ -1888,22 +1897,37 @@
}
}
-void ProcessSnapshot::Serializer::readMappedFileInfo(std::span<std::byte>& data, uint64_t& rebasedAddress, UUID& uuid, FileRecord& file) {
- uint64_t flags = readPVLEUInt64(data);
- rebasedAddress = readPVLEUInt64(data);
+bool ProcessSnapshot::Serializer::readMappedFileInfo(std::span<std::byte>& data, uint64_t& rebasedAddress, UUID& uuid, FileRecord& file) {
+ uint64_t flags = 0;
+ if (!readPVLEUInt64(data, flags)
+ || !readPVLEUInt64(data, rebasedAddress)) {
+ return false;
+ }
if (flags & kMappedFileFlagsHasUUID) {
+ if (data.size() < 16) {
+ return false;
+ }
uuid = UUID(&data[0]);
data = data.last(data.size()-16);
}
if (flags & kMappedFileFlagsHasFileID) {
- uint64_t volumeIndex = readPVLEUInt64(data);
- uint64_t objectID = readPVLEUInt64(data);
+ uint64_t volumeIndex = 0;
+ uint64_t objectID = 0;
+ if (!readPVLEUInt64(data, volumeIndex)
+ || !readPVLEUInt64(data, objectID)
+ || volumeIndex >= _volumeUUIDs.size()) {
+ return false;
+ }
file = _fileManager.fileRecordForVolumeUUIDAndObjID(_volumeUUIDs[(size_t)volumeIndex], objectID);
}
if (flags & kMappedFileFlagsHasFilePath) {
- uint64_t pathOffset = readPVLEUInt64(data);
+ uint64_t pathOffset = 0;
+ if (!readPVLEUInt64(data, pathOffset) || pathOffset >= _stringTableBuffer.size()) {
+ return false;
+ }
file = _fileManager.fileRecordForPath(_ephemeralAllocator, &_stringTableBuffer[(size_t)pathOffset]);
}
+ return true;
}
Vector<std::byte> ProcessSnapshot::Serializer::serialize() {
@@ -1975,16 +1999,18 @@
emitPVLEUInt64(_stringTableBuffer.size(), result);
std::copy((std::byte*)_stringTableBuffer.begin(), (std::byte*)_stringTableBuffer.end(), std::back_inserter(result));
if (_processFlags & kProcessFlagsHasSharedCache) {
- uint64_t address = _sharedCache->rebasedAddress()/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
+ uint64_t address = (uint64_t)_sharedCache->rebasedAddress()/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
emitMappedFileInfo(address, _sharedCache->uuid(), _sharedCache->file(), result);
- _bitmap->emit(result);
+ emitPVLEUInt64(_bitmap->size(), result);
+ if (_bitmap->size() > 0)
+ emit(_bitmap->bytes(), result);
}
emitPVLEUInt64(_images.size(), result);
uint64_t lastAddress = 0;
for (const auto& image : _images) {
- uint64_t address = (image->rebasedAddress()-lastAddress)/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
- lastAddress = image->rebasedAddress();
+ uint64_t address = ((uint64_t)image->rebasedAddress()-lastAddress)/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
+ lastAddress = (uint64_t)image->rebasedAddress();
emitMappedFileInfo(address, image->uuid(), image->file(), result);
}
while(result.size()%16 != 0) {
@@ -1998,6 +2024,10 @@
bool ProcessSnapshot::Serializer::deserialize(const std::span<std::byte> data) {
auto i = data;
+ if (i.size() < 36) {
+ // Ensure data is at least large enough to read the header
+ return false;
+ }
// Confirm magic
_magic = read<uint32_t>(i);
_version = read<uint32_t>(i);
@@ -2019,17 +2049,27 @@
if (_crc32c != checksumer) {
return false;
}
- _processFlags = readPVLEUInt64(i);
- _platform = readPVLEUInt64(i);
- _initialImageCount = readPVLEUInt64(i);
- _dyldState = readPVLEUInt64(i);
- auto volumeUUIDCount = readPVLEUInt64(i);
+ uint64_t volumeUUIDCount = 0;
+ if (!readPVLEUInt64(i, _processFlags)
+ || !readPVLEUInt64(i, _platform)
+ || !readPVLEUInt64(i, _initialImageCount)
+ || !readPVLEUInt64(i, _dyldState)
+ || !readPVLEUInt64(i, volumeUUIDCount)) {
+ return false;
+ }
+ if (i.size() < volumeUUIDCount*16) {
+ return false;
+ }
for (auto j = 0; j < volumeUUIDCount; ++j) {
UUID volumeUUID(&i[j*16]);
_volumeUUIDs.push_back(volumeUUID);
}
i = i.last((size_t)(i.size()-(16*volumeUUIDCount)));
- auto stringTableSize = readPVLEUInt64(i);
+ uint64_t stringTableSize = 0;
+ if (!readPVLEUInt64(i, stringTableSize)
+ || i.size() < stringTableSize) {
+ return false;
+ }
_stringTableBuffer.reserve((size_t)stringTableSize);
std::copy((uint8_t*)&i[0], (uint8_t*)&i[(size_t)stringTableSize], std::back_inserter(_stringTableBuffer));
i = i.last((size_t)(i.size()-stringTableSize));
@@ -2038,8 +2078,9 @@
uint64_t rebasedAddress;
UUID uuid;
FileRecord file;
- readMappedFileInfo(i, rebasedAddress, uuid, file);
- rebasedAddress = rebasedAddress * ((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
+ if ( !readMappedFileInfo(i, rebasedAddress, uuid, file) )
+ return false;
+ rebasedAddress = rebasedAddress * ((_processFlags & kProcessFlagsHas16kPages) ? kPageSize16K : kPageSize4K);
SharedPtr<Mapper> mapper = nullptr;
if (_processSnapshot._useIdentityMapper) {
mapper = _processSnapshot.identityMapper();
@@ -2047,24 +2088,34 @@
#if BUILDING_DYLD || BUILDING_UNIT_TESTS
mapper = _transactionalAllocator.makeShared<Mapper>(_transactionalAllocator);
#else
- mapper = Mapper::mapperForSharedCache(_transactionalAllocator, file, (void*)rebasedAddress);
+ mapper = Mapper::mapperForSharedCache(_transactionalAllocator, file, rebasedAddress);
#endif
}
if (!mapper) {
return false;
}
-
- _sharedCache = _transactionalAllocator.makeUnique<SharedCache>(_ephemeralAllocator, std::move(file), mapper,
+ _sharedCache = _transactionalAllocator.makeUnique<SharedCache>(_transactionalAllocator, std::move(file), mapper,
rebasedAddress, _processFlags & kProcessFlagsHasPrivateCache);
- _bitmap = _transactionalAllocator.makeUnique<Bitmap>(_transactionalAllocator, i);
- }
- auto imageCount = readPVLEUInt64(i);
+ uint64_t encodedSize = 0;
+ if (!readPVLEUInt64(i, encodedSize)) {
+ return false;
+ }
+ _bitmap = _transactionalAllocator.makeUnique<Bitmap>(_transactionalAllocator, (size_t)encodedSize, i);
+ if (_bitmap->size() == 0) {
+ return false;
+ }
+ }
+ uint64_t imageCount = 0;
+ if (!readPVLEUInt64(i, imageCount)) {
+ return false;
+ }
uint64_t lastAddress = 0;
for (auto j = 0; j < imageCount; ++j) {
uint64_t rebasedAddress;
UUID uuid;
FileRecord file;
- readMappedFileInfo(i, rebasedAddress, uuid, file);
+ if ( !readMappedFileInfo(i, rebasedAddress, uuid, file) )
+ return false;
rebasedAddress = (rebasedAddress * ((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096)) + lastAddress;
lastAddress = rebasedAddress;
SharedPtr<Mapper> mapper = nullptr;
@@ -2076,7 +2127,7 @@
mapper = _transactionalAllocator.makeShared<Mapper>(_transactionalAllocator);
}
#endif
- auto image = Image(_ephemeralAllocator, std::move(file), mapper, (const struct mach_header*)rebasedAddress, uuid);
+ auto image = Image(_transactionalAllocator, std::move(file), mapper, (uint64_t)rebasedAddress, uuid);
_images.insert(_transactionalAllocator.makeUnique<Image>(std::move(image)));
}
return true;
@@ -2085,3 +2136,4 @@
};
};
#endif // !TARGET_OS_EXCLAVEKIT
+