diff --git a/lib/spack/spack/test/util/elf.py b/lib/spack/spack/test/util/elf.py index 465985fb26d..f2fd00c44ad 100644 --- a/lib/spack/spack/test/util/elf.py +++ b/lib/spack/spack/test/util/elf.py @@ -201,3 +201,15 @@ def test_drop_redundant_rpath(tmpdir, binary_with_rpaths): new_rpaths = elf.get_rpaths(binary) assert set(existing_dirs).issubset(new_rpaths) assert set(non_existing_dirs).isdisjoint(new_rpaths) + + +def test_elf_invalid_e_shnum(tmp_path): + # from llvm/test/Object/Inputs/invalid-e_shnum.elf + path = tmp_path / "invalid-e_shnum.elf" + with open(path, "wb") as file: + file.write( + b"\x7fELF\x02\x010000000000\x03\x00>\x0000000000000000000000" + b"\x00\x00\x00\x00\x00\x00\x00\x000000000000@\x000000" + ) + with open(path, "rb") as file, pytest.raises(elf.ElfParsingError): + elf.parse_elf(file) diff --git a/lib/spack/spack/util/elf.py b/lib/spack/spack/util/elf.py index 44660307043..ceeb6ef4ab6 100644 --- a/lib/spack/spack/util/elf.py +++ b/lib/spack/spack/util/elf.py @@ -195,7 +195,10 @@ def parse_program_headers(f: BinaryIO, elf: ElfFile) -> None: elf: ELF file parser data """ # Forward to the program header - f.seek(elf.elf_hdr.e_phoff) + try: + f.seek(elf.elf_hdr.e_phoff) + except OSError: + raise ElfParsingError("Could not seek to program header") # Here we have to make a mapping from virtual address to offset in the file. ph_fmt = elf.byte_order + ("LLQQQQQQ" if elf.is_64_bit else "LLLLLLLL") @@ -245,7 +248,10 @@ def parse_pt_interp(f: BinaryIO, elf: ElfFile) -> None: f: file handle elf: ELF file parser data """ - f.seek(elf.pt_interp_p_offset) + try: + f.seek(elf.pt_interp_p_offset) + except OSError: + raise ElfParsingError("Could not seek to PT_INTERP entry") data = read_exactly(f, elf.pt_interp_p_filesz, "Malformed PT_INTERP entry") elf.pt_interp_str = parse_c_string(data) @@ -264,7 +270,10 @@ def find_strtab_size_at_offset(f: BinaryIO, elf: ElfFile, offset: int) -> int: """ section_hdr_fmt = elf.byte_order + ("LLQQQQLLQQ" if elf.is_64_bit else "LLLLLLLLLL") section_hdr_size = calcsize(section_hdr_fmt) - f.seek(elf.elf_hdr.e_shoff) + try: + f.seek(elf.elf_hdr.e_shoff) + except OSError: + raise ElfParsingError("Could not seek to section header table") for _ in range(elf.elf_hdr.e_shnum): data = read_exactly(f, section_hdr_size, "Malformed section header") sh = SectionHeader(*unpack(section_hdr_fmt, data)) @@ -286,7 +295,10 @@ def retrieve_strtab(f: BinaryIO, elf: ElfFile, offset: int) -> bytes: Returns: file offset """ size = find_strtab_size_at_offset(f, elf, offset) - f.seek(offset) + try: + f.seek(offset) + except OSError: + raise ElfParsingError("Could not seek to string table") return read_exactly(f, size, "Could not read string table") @@ -319,7 +331,10 @@ def parse_pt_dynamic(f: BinaryIO, elf: ElfFile) -> None: count_runpath = 0 count_strtab = 0 - f.seek(elf.pt_dynamic_p_offset) + try: + f.seek(elf.pt_dynamic_p_offset) + except OSError: + raise ElfParsingError("Could not seek to PT_DYNAMIC entry") # In case of broken ELF files, don't read beyond the advertized size. for _ in range(elf.pt_dynamic_p_filesz // dynamic_array_size): @@ -478,7 +493,10 @@ def get_interpreter(path: str) -> Optional[str]: def _delete_dynamic_array_entry( f: BinaryIO, elf: ElfFile, should_delete: Callable[[int, int], bool] ) -> None: - f.seek(elf.pt_dynamic_p_offset) + try: + f.seek(elf.pt_dynamic_p_offset) + except OSError: + raise ElfParsingError("Could not seek to PT_DYNAMIC entry") dynamic_array_fmt = elf.byte_order + ("qQ" if elf.is_64_bit else "lL") dynamic_array_size = calcsize(dynamic_array_fmt) new_offset = elf.pt_dynamic_p_offset # points to the new dynamic array