From 0ba2ca7982db018cd3c29cbee49f92b89bd6b457 Mon Sep 17 00:00:00 2001 From: roboterspinne <229981445+roboterspinne@users.noreply.github.com> Date: Sat, 24 Oct 2026 19:53:08 +0200 Subject: [PATCH] fix(relinker): reject executable DT_NEEDED names the guest reader rejects The pipeline read an executable's DT_NEEDED names with readCStr and checked only bounds and the NUL terminator, so without bundled modules an empty name, $LIB.prx, a:b.prx or a name with CR or LF relinked with exit 0 and reached the Linux DT_NEEDED unchanged, while the Windows and macOS outputs each rejected a different subset. The DT_NEEDED loop now applies the rule GuestImageReader applies to a module's DT_NEEDED: a name is not empty and contains no backslash, colon, dollar, CR or LF; a slash stays allowed. Such an executable now fails on every target with "Invalid dependency: " at the name's file offset, and outputs for valid names do not change. --- .../src/pipeline/RelinkerPipeline.cpp | 2 + .../relinker/tests/test_needed_libraries.py | 52 +++++++++++++++++-- 2 files changed, 51 insertions(+), 3 deletions(-) diff --git a/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp b/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp index 77044446d2..720c52fdee 100644 --- a/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp +++ b/core/relinker/relinker/src/pipeline/RelinkerPipeline.cpp @@ -277,6 +277,8 @@ RelinkResult RelinkerPipeline::Relink() { for (auto& [fst, snd] : neededLibraryNamesByStrOffset) { snd = readCStr(fst); + if (snd.empty() || snd.find_first_of("\\:$\r\n") != std::string::npos) + throw RelinkerException("Invalid dependency: " + snd, dynStrTabOffset + fst); neededLibraries.push_back(snd); } diff --git a/core/relinker/relinker/tests/test_needed_libraries.py b/core/relinker/relinker/tests/test_needed_libraries.py index 9bf39efb8f..06a4ddb1d5 100644 --- a/core/relinker/relinker/tests/test_needed_libraries.py +++ b/core/relinker/relinker/tests/test_needed_libraries.py @@ -6,15 +6,15 @@ import sys import tempfile from test_guest_intel_trampolines import PLAIN_SITE, guest_fixture -from test_guest_symbol_names import importing_executable +from test_guest_symbol_names import DYNAMIC, RELOCATIONS, STRINGS, SYMBOLS, importing_executable sys.path.insert(0, str(Path(__file__).resolve().parents[4] / "tools")) import import_audit -def named_module(tag): +def named_module(tag, name="Party.prx"): image = guest_fixture(PLAIN_SITE) - strings = b"\0Party.prx\0" + strings = b"\0" + name.encode() + b"\0" image[0x800:0x800 + len(strings)] = strings struct.pack_into("