diff --git a/include/llvm/Object/ELF.h b/include/llvm/Object/ELF.h index 662057a40b5..54ab3f922b8 100644 --- a/include/llvm/Object/ELF.h +++ b/include/llvm/Object/ELF.h @@ -172,8 +172,8 @@ private: const Elf_Ehdr *Header; const Elf_Shdr *SectionHeaderTable; - const Elf_Shdr *dot_shstrtab_sec; // Section header string table. - const Elf_Shdr *dot_strtab_sec; // Symbol header string table. + StringRef DotShstrtab; // Section header string table. + StringRef DotStrtab; // Symbol header string table. const Elf_Shdr *dot_symtab_sec; // Symbol table section. const Elf_Shdr *SymbolTableSectionHeaderIndex; @@ -235,7 +235,7 @@ public: const T *getEntry(uint32_t Section, uint32_t Entry) const; template const T *getEntry(const Elf_Shdr *Section, uint32_t Entry) const; - ErrorOr getString(const Elf_Shdr *Section, uint32_t Offset) const; + ErrorOr getStringTable(const Elf_Shdr *Section) const; const char *getDynamicString(uintX_t Offset) const; ErrorOr getSymbolVersion(const Elf_Shdr *section, const Elf_Sym *Symb, @@ -371,8 +371,7 @@ public: /// /// \p SymTab is used to lookup the string table to use to get the symbol's /// name. - ErrorOr getSymbolName(const Elf_Shdr *StrTab, - const Elf_Sym *Symb) const; + ErrorOr getSymbolName(StringRef StrTab, const Elf_Sym *Symb) const; ErrorOr getSectionName(const Elf_Shdr *Section) const; uint64_t getSymbolIndex(const Elf_Sym *sym) const; ErrorOr > getSectionContents(const Elf_Shdr *Sec) const; @@ -545,15 +544,6 @@ ELFFile::getRelocationSymbol(const Elf_Shdr *Sec, const RelT *Rel) const { SymTable, getEntry(SymTable, Rel->getSymbol(isMips64EL()))); } -// Verify that the last byte in the string table in a null. -template -void ELFFile::VerifyStrTab(const Elf_Shdr *sh) const { - const char *strtab = (const char *)base() + sh->sh_offset; - if (strtab[sh->sh_size - 1] != 0) - // FIXME: Proper error handling. - report_fatal_error("String table must end with a null terminator!"); -} - template uint64_t ELFFile::getNumSections() const { assert(Header && "Header not initialized!"); @@ -577,8 +567,7 @@ typename ELFFile::uintX_t ELFFile::getStringTableIndex() const { template ELFFile::ELFFile(StringRef Object, std::error_code &EC) - : Buf(Object), SectionHeaderTable(nullptr), dot_shstrtab_sec(nullptr), - dot_strtab_sec(nullptr), dot_symtab_sec(nullptr), + : Buf(Object), SectionHeaderTable(nullptr), dot_symtab_sec(nullptr), SymbolTableSectionHeaderIndex(nullptr), dot_gnu_version_sec(nullptr), dot_gnu_version_r_sec(nullptr), dot_gnu_version_d_sec(nullptr), dt_soname(nullptr) { @@ -626,15 +615,18 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) } SymbolTableSectionHeaderIndex = &Sec; break; - case ELF::SHT_SYMTAB: + case ELF::SHT_SYMTAB: { if (dot_symtab_sec) { // More than one .symtab! EC = object_error::parse_failed; return; } dot_symtab_sec = &Sec; - dot_strtab_sec = getSection(Sec.sh_link); - break; + ErrorOr SymtabOrErr = getStringTable(getSection(Sec.sh_link)); + if ((EC = SymtabOrErr.getError())) + return; + DotStrtab = *SymtabOrErr; + } break; case ELF::SHT_DYNSYM: { if (DynSymRegion.Addr) { // More than one .dynsym! @@ -688,11 +680,11 @@ ELFFile::ELFFile(StringRef Object, std::error_code &EC) } // Get string table sections. - dot_shstrtab_sec = getSection(getStringTableIndex()); - if (dot_shstrtab_sec) { - // Verify that the last byte in the string table in a null. - VerifyStrTab(dot_shstrtab_sec); - } + ErrorOr SymtabOrErr = + getStringTable(getSection(getStringTableIndex())); + if ((EC = SymtabOrErr.getError())) + return; + DotShstrtab = *SymtabOrErr; // Build symbol name side-mapping if there is one. if (SymbolTableSectionHeaderIndex) { @@ -865,13 +857,18 @@ ELFFile::getSection(uint32_t index) const { } template -ErrorOr ELFFile::getString(const Elf_Shdr *Section, - ELF::Elf32_Word Offset) const { +ErrorOr +ELFFile::getStringTable(const Elf_Shdr *Section) const { if (Section->sh_type != ELF::SHT_STRTAB) return object_error::parse_failed; - if (Offset >= Section->sh_size) + uint64_t Offset = Section->sh_offset; + uint64_t Size = Section->sh_size; + if (Offset + Size > Buf.size()) return object_error::parse_failed; - return StringRef((const char *)base() + Section->sh_offset + Offset); + StringRef Data((const char *)base() + Section->sh_offset, Size); + if (Data[Size - 1] != '\0') + return object_error::string_table_non_null_end; + return Data; } template @@ -884,7 +881,7 @@ const char *ELFFile::getDynamicString(uintX_t Offset) const { template ErrorOr ELFFile::getStaticSymbolName(const Elf_Sym *Symb) const { - return getSymbolName(dot_strtab_sec, Symb); + return getSymbolName(DotStrtab, Symb); } template @@ -902,27 +899,40 @@ ErrorOr ELFFile::getSymbolName(const Elf_Sym *Symb, } template -ErrorOr ELFFile::getSymbolName(const Elf_Shdr *StrTab, +ErrorOr ELFFile::getSymbolName(StringRef StrTab, const Elf_Sym *Sym) const { - return getString(StrTab, Sym->st_name); + uint32_t Offset = Sym->st_name; + if (Offset >= StrTab.size()) + return object_error::parse_failed; + return StringRef(StrTab.data() + Offset); } template ErrorOr ELFFile::getSectionName(const Elf_Shdr *Section) const { - return getString(dot_shstrtab_sec, Section->sh_name); + uint32_t Offset = Section->sh_name; + if (Offset >= DotShstrtab.size()) + return object_error::parse_failed; + return StringRef(DotShstrtab.data() + Offset); } template ErrorOr ELFFile::getSymbolVersion(const Elf_Shdr *section, const Elf_Sym *symb, bool &IsDefault) const { + StringRef StrTab; + if (section) { + ErrorOr StrTabOrErr = getStringTable(section); + if (std::error_code EC = StrTabOrErr.getError()) + return EC; + StrTab = *StrTabOrErr; + } // Handle non-dynamic symbols. if (section != DynSymRegion.Addr && section != nullptr) { // Non-dynamic symbols can have versions in their names // A name of the form 'foo@V1' indicates version 'V1', non-default. // A name of the form 'foo@@V2' indicates version 'V2', default version. - ErrorOr SymName = getSymbolName(section, symb); + ErrorOr SymName = getSymbolName(StrTab, symb); if (!SymName) return SymName; StringRef Name = *SymName; diff --git a/include/llvm/Object/Error.h b/include/llvm/Object/Error.h index c9db1b80b91..1b0b56787c5 100644 --- a/include/llvm/Object/Error.h +++ b/include/llvm/Object/Error.h @@ -27,6 +27,7 @@ enum class object_error { invalid_file_type, parse_failed, unexpected_eof, + string_table_non_null_end, bitcode_section_not_found, macho_small_load_command, macho_load_segment_too_many_sections, diff --git a/lib/Object/Error.cpp b/lib/Object/Error.cpp index 644a178c162..5d613d77609 100644 --- a/lib/Object/Error.cpp +++ b/lib/Object/Error.cpp @@ -41,6 +41,8 @@ std::string _object_error_category::message(int EV) const { return "Invalid data was encountered while parsing the file"; case object_error::unexpected_eof: return "The end of the file was unexpectedly encountered"; + case object_error::string_table_non_null_end: + return "String table must end with a null terminator"; case object_error::bitcode_section_not_found: return "Bitcode section not found in object file"; case object_error::macho_small_load_command: diff --git a/test/Object/Inputs/invalid-strtab-size.elf b/test/Object/Inputs/invalid-strtab-size.elf new file mode 100644 index 00000000000..fb1974613ab Binary files /dev/null and b/test/Object/Inputs/invalid-strtab-size.elf differ diff --git a/test/Object/invalid.test b/test/Object/invalid.test index 17cbb30c9c2..73a6ad8021a 100644 --- a/test/Object/invalid.test +++ b/test/Object/invalid.test @@ -1,5 +1,6 @@ RUN: not llvm-dwarfdump %p/Inputs/invalid-bad-rel-type.elf 2>&1 | FileCheck %s RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-type.elf 2>&1 | FileCheck %s +RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-size.elf 2>&1 | FileCheck %s CHECK: Invalid data was encountered while parsing the file RUN: not llvm-objdump -s %p/Inputs/invalid-strtab-non-null.elf 2>&1 | FileCheck --check-prefix=NON-NULL %s diff --git a/tools/llvm-objdump/llvm-objdump.cpp b/tools/llvm-objdump/llvm-objdump.cpp index 610d54877ea..33308234e7d 100644 --- a/tools/llvm-objdump/llvm-objdump.cpp +++ b/tools/llvm-objdump/llvm-objdump.cpp @@ -324,7 +324,11 @@ static std::error_code getRelocationValueString(const ELFObjectFile *Obj, const Elf_Shdr *SymTab = EF.getSection(sec->sh_link); assert(SymTab->sh_type == ELF::SHT_SYMTAB || SymTab->sh_type == ELF::SHT_DYNSYM); - const Elf_Shdr *StrTab = EF.getSection(SymTab->sh_link); + const Elf_Shdr *StrTabSec = EF.getSection(SymTab->sh_link); + ErrorOr StrTabOrErr = EF.getStringTable(StrTabSec); + if (std::error_code EC = StrTabOrErr.getError()) + return EC; + StringRef StrTab = *StrTabOrErr; uint8_t type; StringRef res; int64_t addend = 0; diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index 76b71c517fd..b1ba0906f69 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -757,8 +757,11 @@ void ELFDumper::printRelocation(const Elf_Shdr *Sec, TargetName = SecName.get(); } else if (Sym.first) { const Elf_Shdr *SymTable = Sym.first; - const Elf_Shdr *StrTable = Obj->getSection(SymTable->sh_link); - TargetName = errorOrDefault(Obj->getSymbolName(StrTable, Sym.second)); + const Elf_Shdr *StrTableSec = Obj->getSection(SymTable->sh_link); + ErrorOr StrTableOrErr = Obj->getStringTable(StrTableSec); + if (!error(StrTableOrErr.getError())) + TargetName = + errorOrDefault(Obj->getSymbolName(*StrTableOrErr, Sym.second)); } if (opts::ExpandRelocs) { diff --git a/tools/obj2yaml/elf2yaml.cpp b/tools/obj2yaml/elf2yaml.cpp index db29d2db390..73c83d897d9 100644 --- a/tools/obj2yaml/elf2yaml.cpp +++ b/tools/obj2yaml/elf2yaml.cpp @@ -183,7 +183,11 @@ std::error_code ELFDumper::dumpRelocation(const Elf_Shdr *Shdr, return obj2yaml_error::success; const Elf_Shdr *SymTab = NamePair.first; - const Elf_Shdr *StrTab = Obj.getSection(SymTab->sh_link); + const Elf_Shdr *StrTabSec = Obj.getSection(SymTab->sh_link); + ErrorOr StrTabOrErr = Obj.getStringTable(StrTabSec); + if (std::error_code EC = StrTabOrErr.getError()) + return EC; + StringRef StrTab = *StrTabOrErr; ErrorOr NameOrErr = Obj.getSymbolName(StrTab, NamePair.second); if (std::error_code EC = NameOrErr.getError()) @@ -302,7 +306,11 @@ ErrorOr ELFDumper::dumpGroup(const Elf_Shdr *Shdr) { // Get sh_info which is the signature. const Elf_Sym *symbol = Obj.getSymbol(Shdr->sh_info); const Elf_Shdr *symtab = Obj.getSection(Shdr->sh_link); - const Elf_Shdr *StrTab = Obj.getSection(symtab->sh_link); + const Elf_Shdr *StrTabSec = Obj.getSection(symtab->sh_link); + ErrorOr StrTabOrErr = Obj.getStringTable(StrTabSec); + if (std::error_code EC = StrTabOrErr.getError()) + return EC; + StringRef StrTab = *StrTabOrErr; auto sectionContents = Obj.getSectionContents(Shdr); if (std::error_code ec = sectionContents.getError()) return ec;