Merge pull request #2605 from elsi06/fix/relinker-self-guest-modules

fix(relinker): reject guest modules in SELF containers
This commit is contained in:
Adrià 2026-10-10 10:52:52 +02:00 committed by GitHub
commit 69e9a2685a
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
3 changed files with 20 additions and 2 deletions

View File

@ -70,7 +70,11 @@ std::vector<GuestArtifact> GuestModuleBuilder::Build(const std::filesystem::path
char magic[4]{};
stream.read(magic, 4);
if (stream.bad()) throw Domain::RelinkerException("Cannot read guest candidate magic: " + path.string());
return stream.gcount() == 4 && static_cast<unsigned char>(magic[0]) == 0x7f && magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F';
if (stream.gcount() != 4) return false;
const auto byte = [&](const std::size_t index) { return static_cast<unsigned char>(magic[index]); };
const bool self = (byte(0) == 0x4f && byte(1) == 0x15 && byte(2) == 0x3d && byte(3) == 0x1d) || (byte(0) == 0x54 && byte(1) == 0x14 && byte(2) == 0xf5 && byte(3) == 0xee);
if (self) throw Domain::RelinkerException("Guest module is a SELF container, not an ELF: " + path.string());
return byte(0) == 0x7f && magic[1] == 'E' && magic[2] == 'L' && magic[3] == 'F';
};
for (const auto& directory : directories) {
if (!std::filesystem::is_directory(directory)) throw Domain::RelinkerException("Guest module path is not a directory: " + directory.string());

View File

@ -110,6 +110,20 @@ def main():
assert result.returncode == 2 and "not a directory" in result.stderr, result.stderr
assert not output.exists(), output
for magic in (b"\x4f\x15\x3d\x1d", b"\x54\x14\xf5\xee"):
case = work / f"{windows}-self-{magic.hex()}"
for name in ("sce_module", "prx"):
(case / name).mkdir(parents=True)
(case / "sce_module" / "libc.prx").write_bytes(magic + bytes(0x1000))
(case / "prx" / "provider.prx").write_bytes(module_with_symbol(True))
result, output = convert(case, windows)
assert result.returncode == 2 and "Guest module is a SELF container, not an ELF" in result.stderr, result.stderr
assert str(case / "sce_module" / "libc.prx") in result.stderr, result.stderr
assert not output.exists() and not (case / "app0").exists(), output
result, output = convert(case, windows, ["--exclude-sce-module", "libc.prx"])
assert result.returncode == 0 and output.exists(), result.stderr
assert {path.name for path in (case / "app0").rglob("*.guest.prx")} == {"provider.prx.guest.prx"}
case = work / f"{windows}-ambiguous"
for name in ("sce_module", "sce_modules", "prx"):
(case / name).mkdir(parents=True)

View File

@ -2,7 +2,7 @@
## Input and conversion
Use a clean ELF executable. Place its bundled ELF modules in `sce_module/`, `sce_modules/`, or `prx/` beside the input executable. `prx/` can coexist with either `sce_module/` or `sce_modules/`. Both `sce_module/` and `sce_modules/` present, or all three absent, is an error.
Use a clean ELF executable. Place its bundled ELF modules in `sce_module/`, `sce_modules/`, or `prx/` beside the input executable. A bundled module in a SELF container is an error, as the executable is. `prx/` can coexist with either `sce_module/` or `sce_modules/`. Both `sce_module/` and `sce_modules/` present, or all three absent, is an error.
```text
source/