diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/include/llvm/Object/ELF.h | 40 | ||||
-rw-r--r-- | llvm/include/llvm/Object/Error.h | 1 | ||||
-rw-r--r-- | llvm/lib/Object/Error.cpp | 2 | ||||
-rwxr-xr-x | llvm/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 | bin | 0 -> 1688 bytes | |||
-rw-r--r-- | llvm/test/Object/corrupt.test | 14 | ||||
-rw-r--r-- | llvm/tools/llvm-readobj/ELFDumper.cpp | 37 |
6 files changed, 72 insertions, 22 deletions
diff --git a/llvm/include/llvm/Object/ELF.h b/llvm/include/llvm/Object/ELF.h index f477db64c82..bb949ec9708 100644 --- a/llvm/include/llvm/Object/ELF.h +++ b/llvm/include/llvm/Object/ELF.h @@ -141,6 +141,18 @@ public: Header->getDataEncoding() == ELF::ELFDATA2LSB; } + ErrorOr<const Elf_Dyn *> dynamic_table_begin(const Elf_Phdr *Phdr) const; + ErrorOr<const Elf_Dyn *> dynamic_table_end(const Elf_Phdr *Phdr) const; + ErrorOr<Elf_Dyn_Range> dynamic_table(const Elf_Phdr *Phdr) const { + ErrorOr<const Elf_Dyn *> Begin = dynamic_table_begin(Phdr); + if (std::error_code EC = Begin.getError()) + return EC; + ErrorOr<const Elf_Dyn *> End = dynamic_table_end(Phdr); + if (std::error_code EC = End.getError()) + return EC; + return make_range(*Begin, *End); + } + const Elf_Shdr *section_begin() const; const Elf_Shdr *section_end() const; Elf_Shdr_Range sections() const { @@ -466,6 +478,34 @@ const typename ELFFile<ELFT>::Elf_Shdr *ELFFile<ELFT>::section_end() const { } template <class ELFT> +ErrorOr<const typename ELFFile<ELFT>::Elf_Dyn *> +ELFFile<ELFT>::dynamic_table_begin(const Elf_Phdr *Phdr) const { + if (!Phdr) + return nullptr; + assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header"); + uintX_t Offset = Phdr->p_offset; + if (Offset > Buf.size()) + return object_error::parse_failed; + return reinterpret_cast<const Elf_Dyn *>(base() + Offset); +} + +template <class ELFT> +ErrorOr<const typename ELFFile<ELFT>::Elf_Dyn *> +ELFFile<ELFT>::dynamic_table_end(const Elf_Phdr *Phdr) const { + if (!Phdr) + return nullptr; + assert(Phdr->p_type == ELF::PT_DYNAMIC && "Got the wrong program header"); + uintX_t Size = Phdr->p_filesz; + if (Size % sizeof(Elf_Dyn)) + return object_error::elf_invalid_dynamic_table_size; + // FIKME: Check for overflow? + uintX_t End = Phdr->p_offset + Size; + if (End > Buf.size()) + return object_error::parse_failed; + return reinterpret_cast<const Elf_Dyn *>(base() + End); +} + +template <class ELFT> template <typename T> const T *ELFFile<ELFT>::getEntry(uint32_t Section, uint32_t Entry) const { ErrorOr<const Elf_Shdr *> Sec = getSection(Section); diff --git a/llvm/include/llvm/Object/Error.h b/llvm/include/llvm/Object/Error.h index aa320bb51a4..0f79a6ed0dd 100644 --- a/llvm/include/llvm/Object/Error.h +++ b/llvm/include/llvm/Object/Error.h @@ -30,6 +30,7 @@ enum class object_error { string_table_non_null_end, invalid_section_index, bitcode_section_not_found, + elf_invalid_dynamic_table_size, macho_small_load_command, macho_load_segment_too_many_sections, macho_load_segment_too_small, diff --git a/llvm/lib/Object/Error.cpp b/llvm/lib/Object/Error.cpp index 7ca2f12f092..7ecc3a19af9 100644 --- a/llvm/lib/Object/Error.cpp +++ b/llvm/lib/Object/Error.cpp @@ -47,6 +47,8 @@ std::string _object_error_category::message(int EV) const { return "Invalid section index"; case object_error::bitcode_section_not_found: return "Bitcode section not found in object file"; + case object_error::elf_invalid_dynamic_table_size: + return "Invalid dynamic table size"; case object_error::macho_small_load_command: return "Mach-O load command with size < 8 bytes"; case object_error::macho_load_segment_too_many_sections: diff --git a/llvm/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 b/llvm/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 Binary files differnew file mode 100755 index 00000000000..d164d8243d5 --- /dev/null +++ b/llvm/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 diff --git a/llvm/test/Object/corrupt.test b/llvm/test/Object/corrupt.test index 360e7c8775e..0d9aad378f8 100644 --- a/llvm/test/Object/corrupt.test +++ b/llvm/test/Object/corrupt.test @@ -56,3 +56,17 @@ RUN: %p/Inputs/corrupt-invalid-dynamic-table-size.elf.x86-64 2>&1 | \ RUN: FileCheck --check-prefix=DYN-TABLE-SIZE %s DYN-TABLE-SIZE: Invalid dynamic table size + + +RUN: not llvm-readobj -dyn-relocations \ +RUN: %p/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 2>&1 | \ +RUN: FileCheck --check-prefix=DYN-TABLE-OFFSET %s + +DYN-TABLE-OFFSET: Invalid data was encountered while parsing the file. + + +RUN: not llvm-readobj -dyn-relocations \ +RUN: %p/Inputs/corrupt-invalid-dynamic-table-too-large.elf.x86-64 2>&1 | \ +RUN: FileCheck --check-prefix=DYN-TABLE-TOO-LARGE %s + +DYN-TABLE-TOO-LARGE: Invalid data was encountered while parsing the file. diff --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp index 916cb2acfb9..5887d2944d1 100644 --- a/llvm/tools/llvm-readobj/ELFDumper.cpp +++ b/llvm/tools/llvm-readobj/ELFDumper.cpp @@ -104,10 +104,20 @@ private: const Elf_Rela *dyn_rela_end() const; Elf_Rela_Range dyn_relas() const; StringRef getDynamicString(uint64_t Offset) const; - const Elf_Dyn *dynamic_table_begin() const; - const Elf_Dyn *dynamic_table_end() const; + const Elf_Dyn *dynamic_table_begin() const { + ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_begin(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + const Elf_Dyn *dynamic_table_end() const { + ErrorOr<const Elf_Dyn *> Ret = Obj->dynamic_table_end(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } Elf_Dyn_Range dynamic_table() const { - return make_range(dynamic_table_begin(), dynamic_table_end()); + ErrorOr<Elf_Dyn_Range> Ret = Obj->dynamic_table(DynamicProgHeader); + error(Ret.getError()); + return *Ret; } StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, @@ -118,7 +128,7 @@ private: const ELFO *Obj; DynRegionInfo DynRelaRegion; - DynRegionInfo DynamicRegion; + const Elf_Phdr *DynamicProgHeader = nullptr; StringRef DynamicStringTable; const Elf_Sym *DynSymStart = nullptr; StringRef SOName; @@ -798,11 +808,7 @@ ELFDumper<ELFT>::ELFDumper(const ELFFile<ELFT> *Obj, StreamWriter &Writer) SmallVector<const Elf_Phdr *, 4> LoadSegments; for (const Elf_Phdr &Phdr : Obj->program_headers()) { if (Phdr.p_type == ELF::PT_DYNAMIC) { - DynamicRegion.Addr = Obj->base() + Phdr.p_offset; - uint64_t Size = Phdr.p_filesz; - if (Size % sizeof(Elf_Dyn)) - report_fatal_error("Invalid dynamic table size"); - DynamicRegion.Size = Phdr.p_filesz; + DynamicProgHeader = &Phdr; continue; } if (Phdr.p_type != ELF::PT_LOAD || Phdr.p_filesz == 0) @@ -904,19 +910,6 @@ typename ELFDumper<ELFT>::Elf_Rela_Range ELFDumper<ELFT>::dyn_relas() const { return make_range(dyn_rela_begin(), dyn_rela_end()); } -template <typename ELFT> -const typename ELFDumper<ELFT>::Elf_Dyn * -ELFDumper<ELFT>::dynamic_table_begin() const { - return reinterpret_cast<const Elf_Dyn *>(DynamicRegion.Addr); -} - -template <typename ELFT> -const typename ELFDumper<ELFT>::Elf_Dyn * -ELFDumper<ELFT>::dynamic_table_end() const { - uint64_t Size = DynamicRegion.Size; - return dynamic_table_begin() + Size / sizeof(Elf_Dyn); -} - template<class ELFT> void ELFDumper<ELFT>::printFileHeaders() { const Elf_Ehdr *Header = Obj->getHeader(); |