fix(relinker): preserve input binaries when writing registries
This commit is contained in:
parent
0f863c1022
commit
0cfdc79e59
|
|
@ -117,13 +117,23 @@ int Run(const int argc, char* argv[]) {
|
|||
|
||||
if (args.writeRegistry) {
|
||||
const std::filesystem::path outFsPath = Io::NativePath(absPath);
|
||||
const std::string registryPath = Io::Utf8Path(outFsPath.parent_path() / Io::NativePath(Io::Utf8Path(outFsPath.stem()) + ".registry.json"));
|
||||
const auto registryWriter = std::make_shared<Relinker::CallRegistryWriter>();
|
||||
fileWriter.Write(registryPath, registryWriter->WriteCallRegistry(result.RegistryEntries));
|
||||
for (const auto& artifact : guestArtifacts) {
|
||||
const auto modulePath = outFsPath.parent_path() / Io::NativePath(Io::Utf8Path(outFsPath.stem()) + "." + Io::Utf8Path(artifact.Path.filename()) + ".registry.json");
|
||||
fileWriter.Write(Io::Utf8Path(modulePath), registryWriter->WriteModuleImports(artifact.Imports));
|
||||
std::vector<std::filesystem::path> registryPaths{
|
||||
outFsPath.parent_path() / Io::NativePath(Io::Utf8Path(outFsPath.stem()) + ".registry.json")
|
||||
};
|
||||
for (const auto& artifact : guestArtifacts)
|
||||
registryPaths.push_back(outFsPath.parent_path() / Io::NativePath(Io::Utf8Path(outFsPath.stem()) + "." + Io::Utf8Path(artifact.Path.filename()) + ".registry.json"));
|
||||
for (const auto& path : registryPaths) {
|
||||
if (!std::filesystem::exists(path)) continue;
|
||||
if (std::filesystem::equivalent(Io::NativePath(args.inputPath), path))
|
||||
throw Domain::RelinkerException("Registry output would overwrite the input executable: " + Io::Utf8Path(path));
|
||||
for (const auto& artifact : guestArtifacts)
|
||||
if (std::filesystem::equivalent(artifact.SourcePath, path))
|
||||
throw Domain::RelinkerException("Registry output would overwrite an input module: " + Io::Utf8Path(path));
|
||||
}
|
||||
const auto registryWriter = std::make_shared<Relinker::CallRegistryWriter>();
|
||||
fileWriter.Write(Io::Utf8Path(registryPaths.front()), registryWriter->WriteCallRegistry(result.RegistryEntries));
|
||||
for (std::size_t index = 0; index < guestArtifacts.size(); ++index)
|
||||
fileWriter.Write(Io::Utf8Path(registryPaths[index + 1]), registryWriter->WriteModuleImports(guestArtifacts[index].Imports));
|
||||
}
|
||||
|
||||
auto byteWriter = std::make_shared<Io::ByteWriter>();
|
||||
|
|
|
|||
|
|
@ -56,6 +56,7 @@ struct GuestArtifact {
|
|||
std::filesystem::path Path;
|
||||
std::vector<std::uint8_t> Bytes;
|
||||
std::vector<Domain::CallRegistryEntry> Imports;
|
||||
std::filesystem::path SourcePath;
|
||||
};
|
||||
|
||||
class GuestModuleBuilder {
|
||||
|
|
|
|||
|
|
@ -386,7 +386,7 @@ std::vector<GuestArtifact> GuestModuleBuilder::Build(const std::filesystem::path
|
|||
}
|
||||
}
|
||||
dynamic.GuestModules.push_back(std::move(runtime));
|
||||
artifacts.push_back({target, std::move(output), std::move(imports)});
|
||||
artifacts.push_back({target, std::move(output), std::move(imports), image.SourcePath});
|
||||
std::cout << " [DONE]" << std::endl;
|
||||
}
|
||||
return artifacts;
|
||||
|
|
|
|||
|
|
@ -7,12 +7,58 @@ import tempfile
|
|||
from test_guest_intel_trampolines import PLAIN_SITE, guest_fixture, main_fixture
|
||||
|
||||
|
||||
def check_registry_inputs(relinker, work, windows):
|
||||
options = ["--windows"] if windows else []
|
||||
for module_registry in (False, True):
|
||||
for bundled in (False, True):
|
||||
for alias in ("direct", "hardlink", "symlink"):
|
||||
if bundled and alias == "direct":
|
||||
continue
|
||||
case = work / f"registry-{windows}-{module_registry}-{bundled}-{alias}"
|
||||
modules = case / "sce_module"
|
||||
modules.mkdir(parents=True)
|
||||
module = modules / "sample.prx"
|
||||
module_original = bytes(guest_fixture(PLAIN_SITE))
|
||||
module.write_bytes(module_original)
|
||||
output = case / ("output.exe" if windows else "output.elf")
|
||||
registries = [case / "output.registry.json", case / "output.sample.prx.guest.prx.registry.json"]
|
||||
registry = registries[int(module_registry)]
|
||||
source = registry if alias == "direct" else case / "input.elf"
|
||||
original = bytes(main_fixture())
|
||||
source.write_bytes(original)
|
||||
protected = module if bundled else source
|
||||
if alias == "hardlink":
|
||||
os.link(protected, registry)
|
||||
elif alias == "symlink":
|
||||
try:
|
||||
registry.symlink_to(protected)
|
||||
except OSError as error:
|
||||
if os.name != "nt" or error.winerror != 1314:
|
||||
raise
|
||||
print("Registry symbolic-link case skipped: Windows symlink privilege unavailable")
|
||||
continue
|
||||
previous_registry = b"previous registry"
|
||||
untouched = registries[int(not module_registry)]
|
||||
untouched.write_bytes(previous_registry)
|
||||
previous_output = b"previous executable"
|
||||
output.write_bytes(previous_output)
|
||||
result = subprocess.run([str(relinker), *options, "--registry", str(source), str(output)],
|
||||
capture_output=True, text=True, timeout=20)
|
||||
expected = "Registry output would overwrite an input module" if bundled else "Registry output would overwrite the input executable"
|
||||
assert result.returncode == 2 and expected in result.stderr, (result.returncode, result.stdout, result.stderr)
|
||||
assert source.read_bytes() == original and module.read_bytes() == module_original
|
||||
assert output.read_bytes() == previous_output and untouched.read_bytes() == previous_registry
|
||||
assert registry.read_bytes() == (module_original if bundled else original)
|
||||
assert not (case / "app0").exists()
|
||||
|
||||
|
||||
def main():
|
||||
relinker = Path(sys.argv[1]).resolve()
|
||||
with tempfile.TemporaryDirectory(prefix="anyps5-input-preservation-") as directory:
|
||||
work = Path(directory)
|
||||
for windows in (False, True):
|
||||
options = ["--windows"] if windows else []
|
||||
check_registry_inputs(relinker, work, windows)
|
||||
for bundled in (False, True):
|
||||
for alias in ("direct", "normalized", "hardlink", "symlink"):
|
||||
case = work / f"{windows}-{bundled}-{alias}"
|
||||
|
|
|
|||
Loading…
Reference in New Issue