fix(relinker): restrict lea roots to unwind reachability (#7547)

This commit is contained in:
PROGABBOMALA committed 2026-10-31 22:35:11 +01:00
1 parent b8fc47fd47
commit 6a82825008
3 files changed
+20 -26

No files matched your search

@@ -375,27 +375,7 @@ static std::vector<CodeRange> DiscoverRoutines(const std::vector<std::uint8_t>&
pos += info.Length;
}
}
for (std::size_t pos = 0; pos < limit;) {
if (ContainsOffset(unwind, pos)) {
const auto after = std::upper_bound(unwind.begin(), unwind.end(), pos, [](const std::size_t value, const CodeRange& range) { return value < range.Begin; });
if (after != unwind.begin())
pos = static_cast<std::size_t>(std::prev(after)->End);
continue;
}
Codegen::DecodedInstructionInfo info;
try {
info = decoder.DecodeInstruction(code.data() + pos, limit - pos);
} catch (const Codegen::CodegenException&) {
++pos;
continue;
}
if (info.Length == 0 || info.Length > limit - pos) {
++pos;
continue;
}
QueueInstructionTargets(pending, visited, unwind, info, code, pos, limit);
pos += info.Length;
}
std::set<std::size_t> explored;
while (!pending.empty()) {
const auto root = pending.back();
@@ -98,16 +98,29 @@ void CheckNoUnwindIndirectJumpSyscall(Domain::FileByteOffset origin) {
void CheckIndirectOnlyDynamicSyscall(Domain::FileByteOffset origin) {
const Bytes code = {
0xC3,
0x0F, 0x78,
0x90, 0x90,
0xEB, 0x03,
0x0F, 0x78, 0x00,
0x48, 0x8D, 0x05, 0x02, 0x00, 0x00, 0x00,
0xFF, 0xE0,
0x8B, 0x07,
0x0F, 0x05,
0xC3,
};
CheckForbiddenInstruction(code, origin, 16, {}, {{0, 1}});
CheckForbiddenInstruction(code, origin, 16, {}, {{0, 2}});
}
void CheckGapBranchToSyscall(Domain::FileByteOffset origin) {
const Bytes code = {
0xC3,
0xEB, 0x03,
0x00, 0x00, 0x00,
0x8B, 0x07,
0x0F, 0x05,
0xC3,
};
TestProgress progress;
const auto scanner = Relinker::MakeSyscallScanner(progress);
Require(scanner->ScanCodeSectionForSyscalls(code, origin, code.size(), {}, {{0, 1}}).empty(), "Data gap branch falsely created a routine and rejected 0F 05");
}
void CheckDirectCallAfterIndirectJump(Domain::FileByteOffset origin) {
@@ -175,6 +188,7 @@ int main() {
CheckDirectCallAfterIndirectJump(origin);
CheckConditionalBranchAcrossGap(origin);
CheckUnwindGapAndBoundedCallee(origin);
CheckGapBranchToSyscall(origin);
}
std::cout << "Embedded-code-data known-gap and reachable-code controls passed\n";
} catch (const std::exception& error) {
+1 -1
View File
@@ -6,7 +6,7 @@
- [Packed relative relocations](../../../core/relinker/relinker/src/parsing/RelrRelocations.cpp) require the table to fit in one file-backed PT_LOAD segment and each 8-byte storage unit to fit in one load segment. Units spanning load segments, overlapping RELR units and overlaps with RELA relocations are rejected; relocation composition is not implemented.
- The [syscall scanner](../../../core/relinker/relinker/src/analysis/SyscallScanner.cpp) discovers routine bounds from unwind ranges, direct branch targets, and address-taken `lea` targets ([#7547](https://github.com/boykopovar/AnyPS5/issues/7547)) so undecodable bytes in an inter-routine gap are not reported as an illegal instruction. Each unwind range is decoded from its start through its end, and direct branch and `lea` targets from it and from inter-routine gaps are followed until the next return, unconditional jump, indirect jump, or trap. Inside discovered routines, all syscalls are rejected, including dynamic RAX loads. In inter-routine gaps outside all discovered routines, embedded data does not trigger decode failures, and raw syscall bytes without a constant number are skipped and counted; stubs with constant syscall numbers in gaps remain detected. With no unwind ranges, discovery is not performed and every syscall byte pattern is rejected.
- The [syscall scanner](../../../core/relinker/relinker/src/analysis/SyscallScanner.cpp) discovers routine bounds from unwind ranges, direct branch targets, and address-taken `lea` targets ([#7547](https://github.com/boykopovar/AnyPS5/issues/7547)) so undecodable bytes in an inter-routine gap are not reported as an illegal instruction. Each unwind range is decoded from its start through its end, and direct branch and `lea` targets reached from it are followed until the next return, unconditional jump, indirect jump, or trap. Inside discovered routines, all syscalls are rejected, including dynamic RAX loads. In inter-routine gaps outside all discovered routines, embedded data does not trigger decode failures, and raw syscall bytes without a constant number are skipped and counted; stubs with constant syscall numbers in gaps remain detected. With no unwind ranges, discovery is not performed and every syscall byte pattern is rejected.
- [Executable guest imports](../../../core/relinker/relinker/src/guest/GuestModuleBuilder.cpp) - on Linux and macOS, a relocated executable import resolved to one guest provider requires that module and its dependencies at startup, even when it was discovered through `--module-dir` without a DT_NEEDED entry. Unreferenced symbols and no-op relocations do not require an otherwise deferred module. Console module-start ordering is unmeasured.