From e80d47b7d0d6fe06eab39d2498beaf316f7e430c Mon Sep 17 00:00:00 2001 From: MrMha <114929652+MrMha@users.noreply.github.com> Date: Sat, 17 Oct 2026 18:40:43 +0400 Subject: [PATCH] fix: preserve SELF inputs when an output aliases them --- tools/tests/test_unwrap_self.py | 17 +++++++++++++++++ tools/unwrap_self.py | 5 ++++- 2 files changed, 21 insertions(+), 1 deletion(-) diff --git a/tools/tests/test_unwrap_self.py b/tools/tests/test_unwrap_self.py index 587c7e8b0c..8021984348 100644 --- a/tools/tests/test_unwrap_self.py +++ b/tools/tests/test_unwrap_self.py @@ -82,6 +82,23 @@ def read_program_headers(path): class UnwrapTest(unittest.TestCase): + def test_output_aliases_cannot_replace_the_input_container(self): + container = build_container(default_segments(), default_records(), default_payloads()) + source = Path(self.directory) / "input.self" + source.write_bytes(container) + alias = Path(self.directory) / "alias.elf" + import os + os.link(source, alias) + for output in (source, source.parent / "." / source.name, alias): + with self.subTest(output=output): + result = subprocess.run([sys.executable, str(Path(unwrap_self.__file__)), str(source), str(output)], + capture_output=True, text=True, timeout=30) + self.assertEqual(result.returncode, 2, result.stderr) + self.assertIn("output aliases the input", result.stderr) + self.assertNotIn("Traceback", result.stderr) + self.assertEqual(source.read_bytes(), container) + self.assertEqual(alias.read_bytes(), container) + def convert(self, container, name="input.self"): directory = Path(self.directory) source = directory / name diff --git a/tools/unwrap_self.py b/tools/unwrap_self.py index 4dd65de5ac..91fb662116 100644 --- a/tools/unwrap_self.py +++ b/tools/unwrap_self.py @@ -184,7 +184,10 @@ def check_decrypted(data, headers): def unwrap(path, output, verbose=False): - data = bytes(Path(path).read_bytes()) + source, destination = Path(path), Path(output) + if source.resolve() == destination.resolve() or (destination.exists() and source.samefile(destination)): + raise Refused("output aliases the input container") + data = bytes(source.read_bytes()) if len(data) < FIRST_REGION: raise Refused("file is smaller than the SELF header area") magic = struct.unpack_from("