Loading...
--- dyld/dyld-1042.1/common/ProcessAtlas.cpp
+++ dyld/dyld-1235.2/common/ProcessAtlas.cpp
@@ -24,6 +24,8 @@
#include <TargetConditionals.h>
+#if !TARGET_OS_EXCLAVEKIT
+
#include <atomic>
#include <cstring>
#include <Block.h>
@@ -39,8 +41,8 @@
#include <sys/stat.h>
#include <sys/fsgetpath.h>
+#include <mach/mach_time.h> // mach_absolute_time()
#include <mach/mach_vm.h>
-#include <mach/mach_time.h> // mach_absolute_time()
#include <mach-o/dyld_priv.h> // FIXME: We can remove this once we fully integrate into dyld4
#include "dyld_cache_format.h"
//FIXME: We should remove this header
@@ -76,6 +78,8 @@
#else
#define _transactionalAllocator Allocator::defaultAllocator()
#endif
+
+#define BLEND_KERN_RETURN_LOCATION(kr, loc) (kr) = ((kr & 0x00ffffff) | loc<<24);
namespace {
static const size_t kCachePeekSize = 0x4000;
@@ -124,13 +128,28 @@
: _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);
+ uint64_t encodedSize = 0;
+ if (!readPVLEUInt64(data, encodedSize)) {
+ _size = 0;
+ _bitmap = nullptr;
+ return;
+ }
+ _size = (size_t)encodedSize;
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) {
@@ -410,7 +429,7 @@
}
// 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;
@@ -579,11 +598,14 @@
#if BUILDING_DYLD
Image::Image(RuntimeState* state, Allocator& ephemeralAllocator, SharedPtr<Mapper>& mapper, const Loader* ldr)
: _ephemeralAllocator(ephemeralAllocator), _mapper(mapper), _rebasedAddress((void*)ldr->loadAddress(*state)) {
- auto fileID = ldr->fileID(state->fileManager);
+ auto fileID = ldr->fileID(*state);
if (fileID.inode() && fileID.device()) {
- _file = state->fileManager.fileRecordForFileID(ldr->fileID(state->fileManager));
+ _file = state->fileManager.fileRecordForFileID(ldr->fileID(*state));
+ if ( _file.volume().empty() ) {
+ _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path(*state));
+ }
} else {
- _file = state->fileManager.fileRecordForPath(ldr->path());
+ _file = state->fileManager.fileRecordForPath(ephemeralAllocator, ldr->path(*state));
}
}
#endif
@@ -612,26 +634,38 @@
using std::swap;
if (this == &other) { return; }
- std::swap(_uuid, other._uuid);
- std::swap(_ml, other._ml);
- std::swap(_sharedCacheSlide, other._sharedCacheSlide);
- std::swap(_rebasedAddress, other._rebasedAddress);
- std::swap(_mapper, other._mapper);
- std::swap(_sharedCache, other._sharedCache);
- std::swap(_installname, other._installname);
- std::swap(_file, other._file);
- std::swap(_uuidLoaded, other._uuidLoaded);
- std::swap(_installnameLoaded, other._installnameLoaded);
+ swap(_uuid, other._uuid);
+ swap(_ml, other._ml);
+ swap(_sharedCacheSlide, other._sharedCacheSlide);
+ swap(_rebasedAddress, other._rebasedAddress);
+ swap(_mapper, other._mapper);
+ swap(_sharedCache, other._sharedCache);
+ swap(_installname, other._installname);
+ swap(_file, other._file);
+ swap(_uuidLoaded, other._uuidLoaded);
+ swap(_installnameLoaded, other._installnameLoaded);
+ swap(_mapperFailed, other._mapperFailed);
}
const MachOLoaded* Image::ml() const {
- void* slidML = (void*)rebasedAddress();
+ if (_mapperFailed) {
+ return nullptr;
+ }
if (!_ml) {
+ void* slidML = (void*)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);
+ }
if (!_mapper) {
- _mapper = Mapper::mapperForMachO(_transactionalAllocator, _file, _uuid, _rebasedAddress);
+ _mapperFailed = true;
+ 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);
@@ -640,6 +674,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
@@ -651,7 +689,7 @@
if (!_uuidLoaded) {
uuid_t fileUUID;
const MachOLoaded* mh = ml();
- if (mh->hasMachOMagic()) {
+ if (mh && mh->hasMachOMagic()) {
if (mh->getUuid(fileUUID))
_uuid = UUID(fileUUID);
}
@@ -667,7 +705,9 @@
const char* Image::installname() const {
if (!_installnameLoaded) {
- _installname = ml()->installName();
+ if (ml()) {
+ _installname = ml()->installName();
+ }
_installnameLoaded = true;
}
return _installname;
@@ -690,10 +730,12 @@
}
uint32_t Image::pointerSize() {
+ if (!ml()) { return 0; }
return ml()->pointerSize();
}
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) {
uint64_t vmAddr = 0x0;
@@ -712,6 +754,7 @@
}
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) {
uint64_t sectAddr = 0x0;
@@ -726,6 +769,7 @@
}
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) {
@@ -931,7 +975,7 @@
continue;
// FIXME: The memory managemnt here is awful, fix with allocators
- auto cacheFile = fileManager.fileRecordForPath(cachePath);
+ auto cacheFile = fileManager.fileRecordForPath(_ephemeralAllocator, cachePath);
auto cache = Atlas::SharedCache::createForFileRecord(_ephemeralAllocator, std::move(cacheFile));
if (cache) {
cache.withUnsafe([&](auto cachePtr){
@@ -1052,7 +1096,7 @@
return nullptr;
}
// TODO: Create Path extension helpers for FileRecord
- auto localSymbolsCacheFile = _file.fileManager().fileRecordForPath(localSymbolsCachePath);
+ auto localSymbolsCacheFile = _file.fileManager().fileRecordForPath(_ephemeralAllocator, localSymbolsCachePath);
auto [fileMapper, baseAddress] = Mapper::mapperForSharedCacheLocals(_ephemeralAllocator, localSymbolsCacheFile);
if (!fileMapper) { return nullptr; }
// Use placement new since operator new is not available
@@ -1201,6 +1245,8 @@
pid_t pid;
*kr = pid_for_task(_task, &pid);
if ( *kr != KERN_SUCCESS ) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xea);
+ *kr |= 0xeb000000UL;
return nullptr;
}
@@ -1208,6 +1254,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;
}
@@ -1231,6 +1278,7 @@
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);
@@ -1243,7 +1291,7 @@
executablePath[len] = '\0';
}
SharedPtr<Mapper> mapper = nullptr;
- auto file = _fileManager.fileRecordForPath(executablePath);
+ auto file = _fileManager.fileRecordForPath(_transactionalAllocator, executablePath);
uuid_t rawUUID;
mf->getUuid(rawUUID);
auto uuid = UUID(rawUUID);
@@ -1255,7 +1303,7 @@
executablePath[len] = '\0';
}
SharedPtr<Mapper> mapper = nullptr;
- auto file = _fileManager.fileRecordForPath(executablePath);
+ auto file = _fileManager.fileRecordForPath(_transactionalAllocator, executablePath);
uuid_t rawUUID;
mf->getUuid(rawUUID);
auto uuid = UUID(rawUUID);
@@ -1291,10 +1339,12 @@
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];
@@ -1305,6 +1355,7 @@
*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);
if (*kr != KERN_SUCCESS) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xed);
// If we cannot read the all image info this is game over
return nullptr;
}
@@ -1325,6 +1376,7 @@
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);
if (*kr != KERN_SUCCESS) {
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xec);
// The read failed, chances are the process mutated the compact info, retry
continue;
}
@@ -1333,6 +1385,7 @@
if (!result->valid()) {
// Something blew up we don't know what
*kr = KERN_FAILURE;
+ BLEND_KERN_RETURN_LOCATION(*kr, 0xeb);
return nullptr;
}
return result;
@@ -1577,7 +1630,7 @@
if (!serializer.deserialize(data)) {
// Deerialization failed, reset the snapshot and mark invalid
_images.clear();
- _bitmap = Bitmap();
+ _bitmap = nullptr;
_sharedCache = nullptr;
_platform = 0;
_initialImageCount = 0;
@@ -1600,7 +1653,7 @@
if (processedCacheImages) { return; }
processedCacheImages = true;
for (auto i = 0; i < _sharedCache->imageCount(); ++i) {
- if (!_bitmap.checkBit(i)) { continue; }
+ if (!_bitmap->checkBit(i)) { continue; }
_sharedCache->withImageForIndex(i, ^(Image *image) {
block(image);
});
@@ -1623,8 +1676,8 @@
if (processedCacheImages) { return; }
if (!_sharedCache) { return; }
for (auto i = 0; i < _sharedCache->imageCount(); ++i) {
- if (!_bitmap.checkBit(i)) { continue; }
- if (other._sharedCache && other._bitmap.checkBit(i)) { continue; }
+ if (!_bitmap->checkBit(i)) { continue; }
+ if (other._sharedCache && other._bitmap->checkBit(i)) { continue; }
_sharedCache->withImageForIndex(i, ^(Image *image) {
block(image);
});
@@ -1666,7 +1719,7 @@
void ProcessSnapshot::addImages(RuntimeState* state, const std::span<const Loader*>& loaders) {
for (auto& ldr : loaders) {
if (_sharedCache && ldr->dylibInDyldCache) {
- _bitmap.setBit(ldr->ref.index);
+ _bitmap->setBit(ldr->ref.index);
} else {
_images.insert(_transactionalAllocator.makeUnique<Image>(state, _ephemeralAllocator, identityMapper(), ldr));
}
@@ -1688,11 +1741,11 @@
#if BUILDING_DYLD || BUILDING_UNIT_TESTS
void ProcessSnapshot::addSharedCache(SharedCache&& sharedCache) {
_sharedCache = _transactionalAllocator.makeUnique<SharedCache>(std::move(sharedCache));
- _bitmap = Bitmap(_transactionalAllocator, _sharedCache->imageCount());
-}
-
+ _bitmap = _transactionalAllocator.makeUnique<Bitmap>(_transactionalAllocator, _sharedCache->imageCount());
+}
+
+/// Assumes the mach_header parameter is in the range of the shared cache. Otherwise asserts
void ProcessSnapshot::addSharedCacheImage(const struct mach_header* mh) {
- assert(mh->flags & MH_DYLIB_IN_CACHE);
auto header = (dyld_cache_header*)_sharedCache->rebasedAddress();
auto headerBytes = (uint8_t*)header;
auto slide = (uint64_t)header - header->sharedRegionStart;
@@ -1701,7 +1754,7 @@
return (other.loadAddress == ((uint64_t)mh-slide));
});
assert(i != images.end());
- _bitmap.setBit(i-images.begin());
+ _bitmap->setBit(i-images.begin());
}
@@ -1860,22 +1913,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);
- file = _fileManager.fileRecordForPath(&_stringTableBuffer[(size_t)pathOffset]);
- }
+ 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() {
@@ -1883,6 +1951,7 @@
_genCount++;
auto result = Vector<std::byte>(_ephemeralAllocator);
// We need unique all the strings and UUIDs and place them in sorted tables
+ // FIXME: We should use vectors and sort them since it faster in pathological cases, but we need a non-allocating sort
OrderedSet<const char*, lsl::ConstCharStarCompare> stringSet(_ephemeralAllocator);
OrderedSet<UUID> volumeUUIDSet(_ephemeralAllocator);
if (PAGE_SIZE == 16384) {
@@ -1905,7 +1974,7 @@
if (file.persistent()) {
volumeUUIDSet.insert(file.volume());
} else if (auto filePath = file.getPath()) {
- stringSet.insert(file.getPath());
+ stringSet.insert(filePath);
} else {
stringSet.insert("???");
}
@@ -1948,7 +2017,7 @@
if (_processFlags & kProcessFlagsHasSharedCache) {
uint64_t address = _sharedCache->rebasedAddress()/((_processFlags & kProcessFlagsHas16kPages) ? 16384 : 4096);
emitMappedFileInfo(address, _sharedCache->uuid(), _sharedCache->file(), result);
- _bitmap.emit(result);
+ _bitmap->emit(result);
}
emitPVLEUInt64(_images.size(), result);
@@ -1969,6 +2038,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);
@@ -1978,29 +2051,39 @@
_timestamp = read<uint64_t>(i);
_crc32c = read<uint32_t>(i);
if (_magic != kMagic) {
- assert(0);
+ return false;
}
if (_version != 0) {
- assert(0);
+ return false;
}
CRC32c checksumer;
checksumer(std::span(&data[0], 32));
checksumer((uint32_t)0); // Zero out the actual checksum
checksumer(std::span(&data[36], data.size() - 36));
if (_crc32c != checksumer) {
- assert(0);
- }
- _processFlags = readPVLEUInt64(i);
- _platform = readPVLEUInt64(i);
- _initialImageCount = readPVLEUInt64(i);
- _dyldState = readPVLEUInt64(i);
- auto volumeUUIDCount = readPVLEUInt64(i);
+ return false;
+ }
+ 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));
@@ -2009,7 +2092,8 @@
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);
SharedPtr<Mapper> mapper = nullptr;
if (_processSnapshot._useIdentityMapper) {
@@ -2027,30 +2111,33 @@
_sharedCache = _transactionalAllocator.makeUnique<SharedCache>(_ephemeralAllocator, std::move(file), mapper,
rebasedAddress, _processFlags & kProcessFlagsHasPrivateCache);
- _bitmap = Bitmap(_transactionalAllocator, i);
- }
- auto imageCount = readPVLEUInt64(i);
+ _bitmap = _transactionalAllocator.makeUnique<Bitmap>(_transactionalAllocator, 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;
if (_processSnapshot._useIdentityMapper) {
mapper = _processSnapshot.identityMapper();
- } else {
+ }
#if BUILDING_DYLD || BUILDING_UNIT_TESTS
+ else {
mapper = _transactionalAllocator.makeShared<Mapper>(_transactionalAllocator);
-#else
- mapper = Mapper::mapperForMachO(_transactionalAllocator, file, uuid, (const void*)rebasedAddress);
+ }
#endif
- }
- if (!mapper) {
- return false;
- }
auto image = Image(_ephemeralAllocator, std::move(file), mapper, (const struct mach_header*)rebasedAddress, uuid);
_images.insert(_transactionalAllocator.makeUnique<Image>(std::move(image)));
}
@@ -2059,3 +2146,4 @@
};
};
+#endif // !TARGET_OS_EXCLAVEKIT