diff --git a/tools/tests/test_unwrap_self.py b/tools/tests/test_unwrap_self.py index a64f76f9abd2..2658c2e014fe 100644 --- a/tools/tests/test_unwrap_self.py +++ b/tools/tests/test_unwrap_self.py @@ -20,6 +20,7 @@ PT_DYNAMIC = 2 PT_TLS = 7 PT_NOTE = 4 +PT_PHDR = 6 SCE_COMMENT = 0x6FFFFF00 SCE_VERSION = 0x6FFFFF01 FIRST_REGION = 0x400 @@ -849,6 +850,147 @@ def test_program_headers_do_not_overwrite_the_first_load_payload(self): self.assertEqual(len(headers), count) self.assertTrue(all(header[0] == 0 for header in headers[1:])) + def test_phdr_names_the_rewritten_table_in_the_load_image(self): + table_size = 2 * 56 + for address in (0, 0x4000): + for delta in (0, 0x40): + for recorded in (False, True): + with self.subTest(address=address, delta=delta, recorded=recorded): + table_offset = PAGE + delta + segments = [(PT_PHDR, 4, table_offset, address + delta, table_size, 8), + (PT_LOAD, 4, PAGE, address, 0x400, PAGE)] + table = build_elf(segments, table_offset)[table_offset:table_offset + table_size] + payload = bytearray(b"load payload\0" * 80)[:0x400] + payload[delta:delta + table_size] = table + records = [(0x100800, 0x3000, len(payload))] + if recorded: + records.insert(0, (0x800, 0x3000 + delta, table_size)) + container = build_container(segments, records, {0x3000: payload}, + program_offset=table_offset) + result, output = self.convert(container) + self.assertEqual(result.returncode, 0, result.stderr) + data, headers = read_program_headers(output) + phdr, load = headers + rewritten = struct.unpack_from(" tail[0]): tail = (header["offset"], header["source"] - header["offset"]) continue - if header["vaddr"] != 0: + if header["vaddr"] != 0 or header["type"] == PT_PHDR: host = load_for(header["vaddr"], header["size"]) if host is None: if header["size"] == 0: @@ -266,7 +269,23 @@ def unwrap(path, output, verbose=False): records = read_records(data) inner, elf_header, headers = parse_elf(data) + phdrs = [header for header in headers if header["type"] == PT_PHDR] + if len(phdrs) > 1: + raise Refused("more than one PT_PHDR segment") + phdr = phdrs[0] if phdrs else None + if phdr is not None: + if phdr["size"] < len(headers) * 56 or phdr["memory"] < len(headers) * 56: + raise Refused("PT_PHDR does not cover the program header table") + if any(header["type"] == PT_LOAD and header["index"] < phdr["index"] for header in headers): + raise Refused("PT_PHDR must precede the load segments") place_segments(data, headers, records) + if phdr is not None: + if phdr["host"] is None: + raise Refused("PT_PHDR is not in a file-backed load segment") + table = inner + struct.unpack_from(" len(result): raise Refused("segment %d escaped the output" % header["index"]) + if phdr is not None: + program_offset = phdr["new"] + struct.pack_into("