From e1358aa4ce91f21b82609dd1f0c85a7967903996 Mon Sep 17 00:00:00 2001 From: Rafael Espindola Date: Fri, 7 Aug 2015 15:25:20 +0000 Subject: [PATCH] Add dynamic_table iterators back to ELF.h. In tree they are only used by llvm-readobj, but it is also used by https://github.com/mono/CppSharp. While at it, add some missing error checking. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@244320 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/llvm/Object/ELF.h | 40 ++++++++++++++++++ include/llvm/Object/Error.h | 1 + lib/Object/Error.cpp | 2 + ...pt-invalid-dynamic-table-offset.elf.x86-64 | Bin 0 -> 1688 bytes test/Object/corrupt.test | 14 ++++++ tools/llvm-readobj/ELFDumper.cpp | 37 +++++++--------- 6 files changed, 72 insertions(+), 22 deletions(-) create mode 100755 test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index f477db64c82..bb949ec9708 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -141,6 +141,18 @@ public: Header->getDataEncoding() == ELF::ELFDATA2LSB; } + ErrorOr dynamic_table_begin(const Elf_Phdr *Phdr) const; + ErrorOr dynamic_table_end(const Elf_Phdr *Phdr) const; + ErrorOr dynamic_table(const Elf_Phdr *Phdr) const { + ErrorOr Begin = dynamic_table_begin(Phdr); + if (std::error_code EC = Begin.getError()) + return EC; + ErrorOr 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 { @@ -465,6 +477,34 @@ const typename ELFFile::Elf_Shdr *ELFFile::section_end() const { return section_begin() + getNumSections(); } +template +ErrorOr::Elf_Dyn *> +ELFFile::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(base() + Offset); +} + +template +ErrorOr::Elf_Dyn *> +ELFFile::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(base() + End); +} + template template const T *ELFFile::getEntry(uint32_t Section, uint32_t Entry) const { diff --git a/include/llvm/Object/Error.h b/include/llvm/Object/Error.h index aa320bb51a4..0f79a6ed0dd 100644 --- a/include/llvm/Object/Error.h +++ b/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/lib/Object/Error.cpp b/lib/Object/Error.cpp index 7ca2f12f092..7ecc3a19af9 100644 --- a/lib/Object/Error.cpp +++ b/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/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 b/test/Object/Inputs/corrupt-invalid-dynamic-table-offset.elf.x86-64 new file mode 100755 index 0000000000000000000000000000000000000000..d164d8243d5ce90ac25a48f9bfad4a6ad3518679 GIT binary patch literal 1688 zcmcIk%}OId5U#|ZRpTMb9u!s(@h004z34@<{<5H+b`OFuPBy^^W&)W}lGElfa?B%m z@DV)t7`}o}5bK+%PqVWV1jT}$uluY1x~jXY=kNZ}K|Yrg+L&z1>qw+*j@}q&fZLRD z{mx23CY2u7RyKDUAB`tY*%&b9s!O*a?};u#O7 zBi@>h$UKey50FPuo(Apte_haJ@n1*q;?=5t8xZ)&aZ zvKb`qPD5PX59{&BZ(RNn7uHo2`4#OEJB@f8*Mg?@VO!G`Py?(N)&=q0BEXL`Wxcar zW|bSRx31L%k#%Fs#A~n*+|Y)aWBk79iL02TX7o#Z)**N_*7eJKrvTz1qmI;;cA({N zi}mtgdcJe!$Nk%HM$S}=snqkGw<%EHu%+XFQ76`XuO9yktdTax|CVy3&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/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 916cb2acfb9..5887d2944d1 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/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 Ret = Obj->dynamic_table_begin(DynamicProgHeader); + error(Ret.getError()); + return *Ret; + } + const Elf_Dyn *dynamic_table_end() const { + ErrorOr 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 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::ELFDumper(const ELFFile *Obj, StreamWriter &Writer) SmallVector 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::Elf_Rela_Range ELFDumper::dyn_relas() const { return make_range(dyn_rela_begin(), dyn_rela_end()); } -template -const typename ELFDumper::Elf_Dyn * -ELFDumper::dynamic_table_begin() const { - return reinterpret_cast(DynamicRegion.Addr); -} - -template -const typename ELFDumper::Elf_Dyn * -ELFDumper::dynamic_table_end() const { - uint64_t Size = DynamicRegion.Size; - return dynamic_table_begin() + Size / sizeof(Elf_Dyn); -} - template void ELFDumper::printFileHeaders() { const Elf_Ehdr *Header = Obj->getHeader(); -- 2.34.1