mirror of
https://github.com/boykopovar/AnyPS5.git
synced 2026-10-18 23:07:07 -05:00
Merge pull request #6410 from DavidSamir/fix/relinker-macos-tls-overlapping-decode
fix(relinker): skip prefixed decodings inside an earlier instruction in the macOS TLS scan
This commit is contained in:
3 files changed
+57
-1
No files matched your search
@@ -523,6 +523,9 @@ if(BUILD_TESTING)
|
||||
set_tests_properties(needed_libraries PROPERTIES TIMEOUT 30)
|
||||
add_test(NAME macos_output COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_macos_output.py $<TARGET_FILE:relinker>)
|
||||
add_test(NAME macos_tls_overlap COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_macos_tls_overlap.py $<TARGET_FILE:relinker>)
|
||||
set_tests_properties(macos_tls_overlap PROPERTIES TIMEOUT 60)
|
||||
add_test(NAME guest_host_libc COMMAND ${Python3_EXECUTABLE}
|
||||
${CMAKE_CURRENT_SOURCE_DIR}/relinker/tests/test_guest_host_libc.py $<TARGET_FILE:relinker>)
|
||||
add_library(guest_module_args_host SHARED elfpatcher/tests/GuestModuleArgsHost.cpp)
|
||||
|
||||
@@ -218,16 +218,19 @@ TlsScan ScanTls(const std::vector<std::uint8_t>& source, const std::vector<Domai
|
||||
scan.Tls = &header;
|
||||
}
|
||||
if (header.Type != 1 || (header.Flags & 1) == 0) continue;
|
||||
std::uint64_t decodedEnd = 0;
|
||||
for (auto instruction = instructions.lower_bound(header.MappedAddress); instruction != instructions.end() && *instruction - header.MappedAddress < header.FileSize; ++instruction) {
|
||||
const auto offset = *instruction - header.MappedAddress;
|
||||
const auto* bytes = source.data() + header.Offset + offset;
|
||||
const auto info = decoder.DecodeInstruction(bytes, header.FileSize - offset);
|
||||
const auto rva = image.GetRva(header.MappedAddress + offset, info.Length);
|
||||
const bool insidePrevious = *instruction < decodedEnd;
|
||||
decodedEnd = std::max(decodedEnd, *instruction + info.Length);
|
||||
if (info.HasBranchTarget && !info.HasRipRelativeDisp) {
|
||||
const auto target = static_cast<std::int64_t>(rva) + static_cast<std::int64_t>(info.Length) + info.BranchDisp;
|
||||
if (target >= 0 && target <= std::numeric_limits<std::uint32_t>::max()) scan.BranchTargets.insert(static_cast<std::uint32_t>(target));
|
||||
}
|
||||
if (info.SegmentPrefix == 0) continue;
|
||||
if (info.SegmentPrefix == 0 || (insidePrevious && info.SegmentPrefix != 0x64)) continue;
|
||||
const auto position = info.OpcodeOffset;
|
||||
bool hasOperandSizePrefix = false;
|
||||
bool supportedPrefixes = info.SegmentPrefix == 0x64;
|
||||
|
||||
@@ -0,0 +1,50 @@
|
||||
"""Check the macOS TLS scan against decodings that start inside another instruction."""
|
||||
from pathlib import Path
|
||||
import subprocess
|
||||
import sys
|
||||
import tempfile
|
||||
|
||||
from test_macos_output import MachO
|
||||
from test_tls_function_coverage import TLS_LOAD, add_alias, make_image
|
||||
|
||||
|
||||
def convert(relinker, directory, name, image):
|
||||
source = Path(directory) / f"{name}.elf"
|
||||
output = Path(directory) / name
|
||||
source.write_bytes(bytes(image))
|
||||
result = subprocess.run([str(relinker), "--macos", "--skip-sce-module", str(source), str(output)],
|
||||
capture_output=True, text=True, timeout=60)
|
||||
return result, output
|
||||
|
||||
|
||||
def check_split_function(relinker, directory):
|
||||
immediate = bytes.fromhex("48 b9 00 00 00 65 2e 62 69 6e")
|
||||
body = TLS_LOAD + bytes.fromhex("eb 00 8b 40 f0") + immediate + b"\xc3" * 8
|
||||
image = add_alias(make_image("register", "symbol", 0x55, body), 0x0c, 0x1256)
|
||||
result, output = convert(relinker, directory, "function-begins-inside-instruction", image)
|
||||
if result.returncode != 0:
|
||||
raise SystemExit(f"function-begins-inside-instruction: relinker failed: {result.stdout}{result.stderr}")
|
||||
data = output.read_bytes()
|
||||
code = b"".join(data[lo:hi] for lo, hi in MachO(data).executable_ranges())
|
||||
if immediate not in code:
|
||||
raise SystemExit("function-begins-inside-instruction: the instruction around the GS-prefixed decoding changed")
|
||||
|
||||
|
||||
def check_gs_access_refused(relinker, directory):
|
||||
image = make_image("register", "unwind", body=bytes.fromhex("65 48 8b 04 25 28 00 00 00") + b"\xc3")
|
||||
result, output = convert(relinker, directory, "gs-access", image)
|
||||
message = result.stdout + result.stderr
|
||||
if result.returncode != 2 or "Unsupported macOS guest TLS instruction" not in message or output.exists():
|
||||
raise SystemExit(f"gs-access: a GS access at an instruction start was not refused: {message}")
|
||||
|
||||
|
||||
def main():
|
||||
relinker = Path(sys.argv[1]).resolve()
|
||||
with tempfile.TemporaryDirectory(prefix="anyps5-macos-tls-overlap-") as directory:
|
||||
check_split_function(relinker, directory)
|
||||
check_gs_access_refused(relinker, directory)
|
||||
print("macOS TLS overlap checks passed")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
Reference in new issue
Block a user