Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

[SharedCache] Fix slide info parsing #6172

Open
wants to merge 4 commits into
base: dev
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
262 changes: 141 additions & 121 deletions view/sharedcache/core/SharedCache.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1139,33 +1139,98 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces
for (const auto& [off, mapping] : mappings)
{
m_logger->LogDebug("Slide Info Version: %d", mapping.slideInfoVersion);
uint64_t extrasOffset = off;
uint64_t pageStartsOffset = off;
uint64_t pageStartCount;
uint64_t pageSize;
std::vector<uint64_t> pageStartFileOffsets;

if (mapping.slideInfoVersion == 2)
{
pageStartsOffset += mapping.slideInfoV2.page_starts_offset;
pageStartCount = mapping.slideInfoV2.page_starts_count;
pageSize = mapping.slideInfoV2.page_size;

pageStartFileOffsets.reserve(pageStartCount);
size_t cursor = pageStartsOffset;
extrasOffset += mapping.slideInfoV2.page_extras_offset;
auto cursor = pageStartsOffset;

for (size_t i = 0; i < pageStartCount; i++)
{
try
{
uint64_t pageStart = mapping.file->ReadUShort(cursor) * 4;
cursor += 2;
if (pageStart & 0x4000)
uint16_t start = mapping.file->ReadUShort(cursor);
cursor += sizeof(uint16_t);
if (start == DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE)
continue;
pageStartFileOffsets.push_back(mapping.mappingInfo.fileOffset + (pageSize * i) + pageStart);

auto rebaseChain = [&](const dyld_cache_slide_info_v2& slideInfo, uint64_t pageContent, uint16_t startOffset)
{
uintptr_t slideAmount = 0;

auto deltaMask = slideInfo.delta_mask;
auto valueMask = ~deltaMask;
auto valueAdd = slideInfo.value_add;

auto deltaShift = count_trailing_zeros(deltaMask) - 2;

uint32_t pageOffset = startOffset;
uint32_t delta = 1;
while ( delta != 0 )
{
uint64_t loc = pageContent + pageOffset;
try
{
uintptr_t rawValue = file->ReadULong(loc);
delta = (uint32_t)((rawValue & deltaMask) >> deltaShift);
uintptr_t value = (rawValue & valueMask);
if (value != 0)
{
value += valueAdd;
value += slideAmount;
}
pageOffset += delta;
rewrites.emplace_back(loc, value);
}
catch (MappingReadException& ex)
{
m_logger->LogError("Failed to read v2 slide pointer at 0x%llx\n", loc);
break;
}
}
};

if (start & DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA)
{
int j=(start & 0x3FFF);
bool done = false;
do
{
uint64_t extraCursor = extrasOffset + (j * sizeof(uint16_t));
try
{
auto extra = mapping.file->ReadUShort(extraCursor);
uint16_t aStart = extra;
uint64_t page = mapping.mappingInfo.fileOffset + (pageSize * i);
uint16_t pageStartOffset = (aStart & 0x3FFF)*4;
rebaseChain(mapping.slideInfoV2, page, pageStartOffset);
done = (extra & DYLD_CACHE_SLIDE_PAGE_ATTR_END);
++j;
}
catch (MappingReadException& ex)
{
m_logger->LogError("Failed to read v2 slide extra at 0x%llx\n", cursor);
break;
}
} while (!done);
}
else
{
uint64_t page = mapping.mappingInfo.fileOffset + (pageSize * i);
uint16_t pageStartOffset = start*4;
rebaseChain(mapping.slideInfoV2, page, pageStartOffset);
}
}
catch (MappingReadException& ex)
{

m_logger->LogError("Failed to read v2 slide info at 0x%llx\n", cursor);
}
}
}
Expand All @@ -1174,148 +1239,103 @@ void SharedCache::ParseAndApplySlideInfoForFile(std::shared_ptr<MMappedFileAcces
pageStartsOffset += sizeof(dyld_cache_slide_info_v3);
pageStartCount = mapping.slideInfoV3.page_starts_count;
pageSize = mapping.slideInfoV3.page_size;

pageStartFileOffsets.reserve(pageStartCount);
size_t cursor = pageStartsOffset;
auto cursor = pageStartsOffset;

for (size_t i = 0; i < pageStartCount; i++)
{
try
{
uint64_t pageStart = mapping.file->ReadUShort(cursor);
cursor += 2;
if (pageStart & 0x4000)
uint16_t delta = mapping.file->ReadUShort(cursor);
cursor += sizeof(uint16_t);
if (delta == DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE)
continue;
pageStartFileOffsets.push_back(mapping.mappingInfo.fileOffset + (pageSize * i) + pageStart);

delta = delta/sizeof(uint64_t); // initial offset is byte based
uint64_t loc = mapping.mappingInfo.fileOffset + (pageSize * i);
do
{
loc += delta * sizeof(dyld_cache_slide_pointer3);
try
{
dyld_cache_slide_pointer3 slideInfo;
file->Read(&slideInfo, loc, sizeof(slideInfo));
delta = slideInfo.plain.offsetToNextPointer;

if (slideInfo.auth.authenticated)
{
uint64_t value = slideInfo.auth.offsetFromSharedCacheBase;
value += mapping.slideInfoV3.auth_value_add;
rewrites.emplace_back(loc, value);
}
else
{
uint64_t value51 = slideInfo.plain.pointerValue;
uint64_t top8Bits = value51 & 0x0007F80000000000;
uint64_t bottom43Bits = value51 & 0x000007FFFFFFFFFF;
uint64_t value = (uint64_t)top8Bits << 13 | bottom43Bits;
rewrites.emplace_back(loc, value);
}
}
catch (MappingReadException& ex)
{
m_logger->LogError("Failed to read v3 slide pointer at 0x%llx\n", loc);
break;
}
} while (delta != 0);
}
catch (MappingReadException& ex)
{
m_logger->LogError("Failed to read slide info at 0x%llx\n", cursor);
m_logger->LogError("Failed to read v3 slide info at 0x%llx\n", cursor);
}
}
}
else if (mapping.slideInfoVersion == 5)
{
pageStartsOffset += sizeof(dyld_cache_slide_info5);
pageStartCount = mapping.slideInfoV5.page_starts_count;
m_logger->LogDebug("Page Start Count: %d", pageStartCount);
pageSize = mapping.slideInfoV5.page_size;
auto cursor = pageStartsOffset;

for (size_t i = 0; i < pageStartCount; i++)
{
try
{
uint64_t pageStart = mapping.file->ReadUShort(cursor);
cursor += 2;
if (pageStart == DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE)
uint16_t delta = mapping.file->ReadUShort(cursor);
cursor += sizeof(uint16_t);
if (delta == DYLD_CACHE_SLIDE_V5_PAGE_ATTR_NO_REBASE)
continue;
pageStartFileOffsets.push_back(mapping.mappingInfo.fileOffset + (pageSize * i) + pageStart);
}
catch (MappingReadException& ex)
{
m_logger->LogError("Failed to read slide info at 0x%llx\n", cursor);
}
}
}
if (pageStartFileOffsets.empty())
{
m_logger->LogDebug("No page start file offsets found");
}
for (auto pageStart : pageStartFileOffsets)
{
if (mapping.slideInfoVersion == 2)
{
auto deltaMask = mapping.slideInfoV2.delta_mask;
auto valueMask = ~deltaMask;
auto valueAdd = mapping.slideInfoV2.value_add;

auto deltaShift = count_trailing_zeros(deltaMask) - 2;

uint64_t delta = 1;
uint64_t loc = pageStart;
while (delta != 0)
{
try {
uint64_t rawValue = file->ReadULong(loc);
delta = (rawValue & deltaMask) >> deltaShift;
uint64_t value = (rawValue & valueMask);
if (valueMask != 0)
{
value += valueAdd;
}
rewrites.emplace_back(loc, value);
}
catch (MappingReadException& ex)
{
m_logger->LogError("Failed to read slide info at 0x%llx\n", loc);
delta = 0;
}
loc += delta;
}
}
else if (mapping.slideInfoVersion == 3)
{
uint64_t loc = pageStart;
uint64_t delta = 1;
while (delta != 0)
{
dyld_cache_slide_pointer3 slideInfo;
try

delta = delta/sizeof(uint64_t); // initial offset is byte based
uint64_t loc = mapping.mappingInfo.fileOffset + (pageSize * i);
do
{
file->Read(&slideInfo, loc, 8);
delta = slideInfo.plain.offsetToNextPointer * 8;

if (slideInfo.auth.authenticated)
loc += delta * sizeof(dyld_cache_slide_pointer5);
try
{
uint64_t value = slideInfo.auth.offsetFromSharedCacheBase;
value += mapping.slideInfoV3.auth_value_add;
rewrites.emplace_back(loc, value);
dyld_cache_slide_pointer5 slideInfo;
file->Read(&slideInfo, loc, sizeof(slideInfo));
delta = slideInfo.regular.next;
if (slideInfo.auth.auth)
{
uint64_t value = mapping.slideInfoV5.value_add + slideInfo.auth.runtimeOffset;
rewrites.emplace_back(loc, value);
}
else
{
uint64_t value = mapping.slideInfoV5.value_add + slideInfo.regular.runtimeOffset;
rewrites.emplace_back(loc, value);
}
}
else
catch (MappingReadException& ex)
{
uint64_t value51 = slideInfo.plain.pointerValue;
uint64_t top8Bits = value51 & 0x0007F80000000000;
uint64_t bottom43Bits = value51 & 0x000007FFFFFFFFFF;
uint64_t value = (uint64_t)top8Bits << 13 | bottom43Bits;
rewrites.emplace_back(loc, value);
m_logger->LogError("Failed to read v5 slide pointer at 0x%llx\n", loc);
break;
}
loc += delta;
}
catch (MappingReadException& ex)
{
m_logger->LogError("Failed to read slide info at 0x%llx\n", loc);
delta = 0;
}
} while (delta != 0);
}
}
else if (mapping.slideInfoVersion == 5)
{
uint64_t loc = pageStart;
uint64_t delta = 1;
while (delta != 0)
catch (MappingReadException& ex)
{
dyld_cache_slide_pointer5 slideInfo;
try
{
file->Read(&slideInfo, loc, 8);
delta = slideInfo.regular.next * 8;
if (slideInfo.auth.auth)
{
uint64_t value = slideInfo.auth.runtimeOffset + mapping.slideInfoV5.value_add;
rewrites.emplace_back(loc, value);
}
else
{
uint64_t value = base + slideInfo.regular.runtimeOffset;
rewrites.emplace_back(loc, value);
}
loc += delta;
}
catch (MappingReadException& ex)
{
m_logger->LogError("Failed to read slide info at 0x%llx\n", loc);
delta = 0;
}
m_logger->LogError("Failed to read v5 slide info at 0x%llx\n", cursor);
}
}
}
Expand Down
6 changes: 6 additions & 0 deletions view/sharedcache/core/SharedCache.h
Original file line number Diff line number Diff line change
Expand Up @@ -161,6 +161,11 @@ namespace SharedCacheCore {
uint64_t delta_mask;
uint64_t value_add;
};
#define DYLD_CACHE_SLIDE_PAGE_ATTR_EXTRA 0x8000 // index is into extras array (not starts array)
#define DYLD_CACHE_SLIDE_PAGE_ATTR_NO_REBASE 0x4000 // page has no rebasing
#define DYLD_CACHE_SLIDE_PAGE_ATTR_END 0x8000 // last chain entry for page

#define DYLD_CACHE_SLIDE_V3_PAGE_ATTR_NO_REBASE 0xFFFF // page has no rebasing

struct PACKED_STRUCT dyld_cache_slide_info_v3
{
Expand Down Expand Up @@ -202,6 +207,7 @@ namespace SharedCacheCore {
uint32_t version; // currently 5
uint32_t page_size; // currently 4096 (may also be 16384)
uint32_t page_starts_count;
uint32_t pad; // padding to ensure the value below is on an 8-byte boundary
uint64_t value_add;
// uint16_t page_starts[/* page_starts_count */];
};
Expand Down