From c38aa9286042b104000e075375a3ccc5c8e72e38 Mon Sep 17 00:00:00 2001 From: James Henderson Date: Fri, 14 Jun 2019 12:02:01 +0000 Subject: [PATCH] [llvm-readobj] Don't abort printing of dynamic table if string reference is invalid If dynamic table is missing, output "dynamic strtab not found'. If the index is out of range, output "Invalid Offset<..>". https://bugs.llvm.org/show_bug.cgi?id=40807 Reviewed by: jhenderson, grimar, MaskRay Differential Revision: https://reviews.llvm.org/D63084 Patch by Yuanfang Chen. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@363374 91177308-0d34-0410-b5e6-96231b3b80d8 --- .../Inputs/corrupt-invalid-strtab.elf.x86-64 | Bin 1712 -> 0 bytes test/Object/corrupt.test | 7 -- .../llvm-readobj/elf-dynamic-malformed.test | 53 ++++++++++++--- tools/llvm-readobj/ELFDumper.cpp | 62 +++++++++++------- 4 files changed, 81 insertions(+), 41 deletions(-) delete mode 100755 test/Object/Inputs/corrupt-invalid-strtab.elf.x86-64 diff --git a/test/Object/Inputs/corrupt-invalid-strtab.elf.x86-64 b/test/Object/Inputs/corrupt-invalid-strtab.elf.x86-64 deleted file mode 100755 index ab9a63ea7966324796a6dab59c9f3057065c4d5c..0000000000000000000000000000000000000000 GIT binary patch literal 0 HcmV?d00001 literal 1712 zcmcIk%}N_l6h6k-YHcAE7Ztk5qJkh^2;J08iPg3gqN{dM5T+9+HGyUVnNgBe^9WtK z%pSgv#_4oIsn7#6-?`uUyJzm1`~7X}U1ecGD2wu1?p7jA8gkf_ zS5i$ZtMWkksyeMKec$`3plA5oz=(rLcrtUyl3|S1K^Ys z#*x}p1+nM>!g=An!2h57WB+#j$g#$t6yy2-j~IZYIVskEs5a!hZ#?c1&1 | FileCheck --check-prefix=VER %s VER: error: Invalid version entry - -// The file is missing the dynamic string table but has references to it. -RUN: not llvm-readobj --dynamic-table %p/Inputs/corrupt-invalid-strtab.elf.x86-64 \ -RUN: 2>&1 | FileCheck --check-prefix=STRTAB %s - -STRTAB: Invalid dynamic string table reference - RUN: not llvm-readobj -l \ RUN: %p/Inputs/corrupt-invalid-phentsize.elf.x86-64 2>&1 | \ RUN: FileCheck --check-prefix=PHENTSIZE %s diff --git a/test/tools/llvm-readobj/elf-dynamic-malformed.test b/test/tools/llvm-readobj/elf-dynamic-malformed.test index abc0f89310c..337fedec5a5 100644 --- a/test/tools/llvm-readobj/elf-dynamic-malformed.test +++ b/test/tools/llvm-readobj/elf-dynamic-malformed.test @@ -68,13 +68,28 @@ ProgramHeaders: Sections: - Section: .dynamic -# Test handling of string references pointing past the end of the dynamic string table. In this case, -# we have a DT_NEEDED tag pointing at offset 1 in a 1-byte string table. +# Test handling of string references pointing past the end of the dynamic string table. # RUN: yaml2obj %s --docnum=3 -o %t.bad-string -# RUN: not llvm-readobj --dynamic-table %t.bad-string 2>&1 | FileCheck %s --check-prefix BAD-STRING -# RUN: not llvm-readelf --dynamic-table %t.bad-string 2>&1 | FileCheck %s --check-prefix BAD-STRING +# RUN: llvm-readobj --dynamic-table %t.bad-string | FileCheck %s --check-prefix BAD-STRING-LLVM +# RUN: llvm-readelf --dynamic-table %t.bad-string | FileCheck %s --check-prefix BAD-STRING-GNU -# BAD-STRING: Invalid dynamic string table reference +# BAD-STRING-LLVM: 0x000000000000000A STRSZ 1 (bytes) +# BAD-STRING-LLVM: 0x0000000000000001 NEEDED Shared library: +# BAD-STRING-LLVM: 0x000000007FFFFFFF FILTER Filter library: +# BAD-STRING-LLVM: 0x000000007FFFFFFD AUXILIARY Auxiliary library: +# BAD-STRING-LLVM: 0x000000007FFFFFFE USED Not needed object: +# BAD-STRING-LLVM: 0x000000000000000E SONAME Library soname: +# BAD-STRING-LLVM: 0x000000000000000F RPATH +# BAD-STRING-LLVM: 0x000000000000001D RUNPATH + +# BAD-STRING-GNU: 0x000000000000000a (STRSZ) 1 (bytes) +# BAD-STRING-GNU: 0x0000000000000001 (NEEDED) Shared library: +# BAD-STRING-GNU: 0x000000007fffffff (FILTER) Filter library: +# BAD-STRING-GNU: 0x000000007ffffffd (AUXILIARY) Auxiliary library: +# BAD-STRING-GNU: 0x000000007ffffffe (USED) Not needed object: +# BAD-STRING-GNU: 0x000000000000000e (SONAME) Library soname: +# BAD-STRING-GNU: 0x000000000000000f (RPATH) +# BAD-STRING-GNU: 0x000000000000001d (RUNPATH) --- !ELF FileHeader: @@ -96,6 +111,18 @@ Sections: Value: 1 - Tag: DT_NEEDED Value: 1 + - Tag: DT_FILTER + Value: 1 + - Tag: DT_AUXILIARY + Value: 1 + - Tag: DT_USED + Value: 1 + - Tag: DT_SONAME + Value: 1 + - Tag: DT_RPATH + Value: 1 + - Tag: DT_RUNPATH + Value: 1 - Tag: DT_NULL Value: 0 ProgramHeaders: @@ -111,11 +138,19 @@ ProgramHeaders: # Test handling of DT_STRTAB pointing outside the file's address space. # RUN: yaml2obj %s --docnum=4 -o %t.bad-strtab -# RUN: not llvm-readobj --dynamic-table %t.bad-strtab 2>&1 | FileCheck %s --check-prefix BAD-STRTAB -# RUN: not llvm-readelf --dynamic-table %t.bad-strtab 2>&1 | FileCheck %s --check-prefix BAD-STRTAB -# BAD-STRTAB: warning: Unable to parse DT_STRTAB: Virtual address is not in any segment -# BAD-STRTAB: error: Invalid dynamic string table reference +# RUN: llvm-readobj --dynamic-table %t.bad-strtab 2>&1 >/dev/null | FileCheck %s --check-prefix BAD-STRTAB-ERR +# RUN: llvm-readelf --dynamic-table %t.bad-strtab 2>&1 >/dev/null | FileCheck %s --check-prefix BAD-STRTAB-ERR +# BAD-STRTAB-ERR: warning: Unable to parse DT_STRTAB: Virtual address is not in any segment + +# RUN: llvm-readobj --dynamic-table --needed-libs %t.bad-strtab | FileCheck %s --check-prefixes=BAD-STRTAB,BAD-STRTAB-LLVM +# RUN: llvm-readelf --dynamic-table --needed-libs %t.bad-strtab | FileCheck %s --check-prefixes=BAD-STRTAB,BAD-STRTAB-GNU +# BAD-STRTAB-LLVM: LoadName: +# BAD-STRTAB-LLVM: 0x0000000000000001 NEEDED Shared library: +# BAD-STRTAB-GNU: 0x0000000000000001 (NEEDED) Shared library: +# BAD-STRTAB: NeededLibraries [ +# BAD-STRTAB: +# BAD-STRTAB: ] --- !ELF FileHeader: diff --git a/tools/llvm-readobj/ELFDumper.cpp b/tools/llvm-readobj/ELFDumper.cpp index e751e6db9eb..4a5be0ba84f 100644 --- a/tools/llvm-readobj/ELFDumper.cpp +++ b/tools/llvm-readobj/ELFDumper.cpp @@ -206,7 +206,8 @@ private: void loadDynamicTable(const ELFFile *Obj); void parseDynamicTable(); - StringRef getDynamicString(uint64_t Offset) const; + void printDynamicString(uint64_t Offset, raw_ostream &OS, + bool WithBracket = true) const; StringRef getSymbolVersion(StringRef StrTab, const Elf_Sym *symb, bool &IsDefault) const; void LoadVersionMap() const; @@ -221,7 +222,7 @@ private: DynRegionInfo DynSymRegion; DynRegionInfo DynamicTable; StringRef DynamicStringTable; - StringRef SOName; + StringRef SOName = ""; const Elf_Hash *HashTable = nullptr; const Elf_GnuHash *GnuHashTable = nullptr; const Elf_Shdr *DotSymtabSec = nullptr; @@ -1626,8 +1627,8 @@ template void ELFDumper::parseDynamicTable() { } if (StringTableBegin) DynamicStringTable = StringRef(StringTableBegin, StringTableSize); - if (SONameOffset) - SOName = getDynamicString(SONameOffset); + if (SONameOffset && SONameOffset < DynamicStringTable.size()) + SOName = DynamicStringTable.data() + SONameOffset; } template @@ -1790,14 +1791,19 @@ void printFlags(T Value, ArrayRef> Flags, raw_ostream &OS) { } template -StringRef ELFDumper::getDynamicString(uint64_t Value) const { - if (Value >= DynamicStringTable.size()) - reportError("Invalid dynamic string table reference"); - return StringRef(DynamicStringTable.data() + Value); -} - -static void printLibrary(raw_ostream &OS, const Twine &Tag, const Twine &Name) { - OS << Tag << ": [" << Name << "]"; +void ELFDumper::printDynamicString(uint64_t Value, + raw_ostream &OS, + bool WithBracket) const { + if (DynamicStringTable.empty()) + OS << " "; + else if (Value < DynamicStringTable.size()) { + if (WithBracket) + OS << "["; + OS << StringRef(DynamicStringTable.data() + Value); + if (WithBracket) + OS << "]"; + } else + OS << ""; } template @@ -1943,23 +1949,24 @@ void ELFDumper::printDynamicEntry(raw_ostream &OS, uint64_t Type, OS << Value << " (bytes)"; break; case DT_NEEDED: - printLibrary(OS, "Shared library", getDynamicString(Value)); - break; case DT_SONAME: - printLibrary(OS, "Library soname", getDynamicString(Value)); - break; case DT_AUXILIARY: - printLibrary(OS, "Auxiliary library", getDynamicString(Value)); - break; case DT_USED: - printLibrary(OS, "Not needed object", getDynamicString(Value)); - break; - case DT_FILTER: - printLibrary(OS, "Filter library", getDynamicString(Value)); + case DT_FILTER: { + const std::map TagNames = { + {DT_NEEDED, "Shared library"}, + {DT_SONAME, "Library soname"}, + {DT_AUXILIARY, "Auxiliary library"}, + {DT_USED, "Not needed object"}, + {DT_FILTER, "Filter library"}, + }; + OS << TagNames.at(Type) << ": "; + printDynamicString(Value, OS); break; + } case DT_RPATH: case DT_RUNPATH: - OS << getDynamicString(Value); + printDynamicString(Value, OS, false); break; case DT_FLAGS: printFlags(Value, makeArrayRef(ElfDynamicDTFlags), OS); @@ -2004,8 +2011,13 @@ template void ELFDumper::printNeededLibraries() { LibsTy Libs; for (const auto &Entry : dynamic_table()) - if (Entry.d_tag == ELF::DT_NEEDED) - Libs.push_back(getDynamicString(Entry.d_un.d_val)); + if (Entry.d_tag == ELF::DT_NEEDED) { + uint64_t Value = Entry.d_un.d_val; + if (Value < DynamicStringTable.size()) + Libs.push_back(StringRef(DynamicStringTable.data() + Value)); + else + Libs.push_back(""); + } llvm::stable_sort(Libs); -- 2.40.0