[llvm] 3249bfd - [llvm-readobj] - Don't crash when a broken GNU hash table is dumped with --hash-symbols.

Georgii Rymar via llvm-commits llvm-commits at lists.llvm.org
Wed Jun 24 05:56:22 PDT 2020


Author: Georgii Rymar
Date: 2020-06-24T15:55:43+03:00
New Revision: 3249bfda9678724207803ce675505ffbfa65a372

URL: https://github.com/llvm/llvm-project/commit/3249bfda9678724207803ce675505ffbfa65a372
DIFF: https://github.com/llvm/llvm-project/commit/3249bfda9678724207803ce675505ffbfa65a372.diff

LOG: [llvm-readobj] - Don't crash when a broken GNU hash table is dumped with --hash-symbols.

Start using the `checkGNUHashTable` helper which was recently introduced to report
a proper warning when a GNU hash table goes past the end of the file.

Differential revision: https://reviews.llvm.org/D82449

Added: 
    

Modified: 
    llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
    llvm/tools/llvm-readobj/ELFDumper.cpp

Removed: 
    


################################################################################
diff  --git a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
index dd0d9e398174..edd3c1e9b84c 100644
--- a/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
+++ b/llvm/test/tools/llvm-readobj/ELF/hash-symbols.test
@@ -448,3 +448,64 @@ ProgramHeaders:
     Sections:
       - Section: .hash
       - Section: .dynamic
+
+## Check we report a proper warning when a GNU hash table goes past the end of the file.
+
+## Case A: the 'nbuckets' field is set so that the table goes past the end of the file.
+# RUN: yaml2obj --docnum=8 -D MASKWORDS=4294967295 -D NBUCKETS=3 %s -o %t.err.maskwords
+# RUN: llvm-readelf --hash-symbols %t.err.maskwords 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t.err.maskwords -DMASKWORDS=4294967295 -DNBUCKETS=3 --check-prefix=ERR4
+
+# ERR4:      Symbol table of .gnu.hash for image:
+# ERR4-NEXT:  Num Buc: Value Size Type Bind Vis Ndx Name
+# ERR4-NEXT: warning: '[[FILE]]': unable to dump the SHT_GNU_HASH section at 0x78: it goes past the end of the file
+
+## Case B: the 'maskwords' field is set so that the table goes past the end of the file.
+# RUN: yaml2obj --docnum=8 -D MASKWORDS=2 -D NBUCKETS=4294967295 %s -o %t.err.nbuckets
+# RUN: llvm-readelf --hash-symbols %t.err.nbuckets 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t.err.nbuckets -DMASKWORDS=2 -DNBUCKETS=4294967295 --check-prefix=ERR4
+
+--- !ELF
+FileHeader:
+  Class:   ELFCLASS64
+  Data:    ELFDATA2LSB
+  Type:    ET_DYN
+  Machine: EM_X86_64
+Sections:
+  - Name:  .gnu.hash
+    Type:  SHT_GNU_HASH
+    Flags: [ SHF_ALLOC ]
+    Header:
+      SymNdx: 0x1
+      Shift2: 0x2
+## The number of words in the Bloom filter. The value of 2 is no-op.
+      MaskWords: [[MASKWORDS]]
+## The number of hash buckets. The value of 3 is no-op.
+      NBuckets:  [[NBUCKETS]]
+    BloomFilter: [0x3, 0x4]
+    HashBuckets: [0x5, 0x6, 0x7]
+    HashValues:  [0x8, 0x9, 0xA, 0xB]
+  - Name:  .dynamic
+    Type:  SHT_DYNAMIC
+    Flags: [ SHF_ALLOC ]
+    Link:  .dynstr
+    Entries:
+      - Tag:   DT_GNU_HASH
+        Value: 0x0
+      - Tag:   DT_NULL
+        Value: 0x0
+DynamicSymbols:
+  - Name:    aaa
+    Binding: STB_GLOBAL
+  - Name:    bbb
+    Binding: STB_GLOBAL
+  - Name:    ccc
+    Binding: STB_GLOBAL
+  - Name:    ddd
+    Binding: STB_GLOBAL
+ProgramHeaders:
+  - Type:  PT_LOAD
+    Flags: [ PF_R, PF_X ]
+    Sections:
+      - Section: .gnu.hash
+      - Section: .dynamic

diff  --git a/llvm/tools/llvm-readobj/ELFDumper.cpp b/llvm/tools/llvm-readobj/ELFDumper.cpp
index e38ae9d56fb3..b424918a8d4b 100644
--- a/llvm/tools/llvm-readobj/ELFDumper.cpp
+++ b/llvm/tools/llvm-readobj/ELFDumper.cpp
@@ -4069,27 +4069,35 @@ template <class ELFT> void GNUStyle<ELFT>::printHashSymbols(const ELFO *Obj) {
       PrintHashTable(SysVHash);
   }
 
-  // Try printing .gnu.hash
-  if (auto GnuHash = this->dumper()->getGnuHashTable()) {
-    OS << "\n Symbol table of .gnu.hash for image:\n";
-    if (ELFT::Is64Bits)
-      OS << "  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name";
-    else
-      OS << "  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name";
-    OS << "\n";
-    auto Buckets = GnuHash->buckets();
-    for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) {
-      if (Buckets[Buc] == ELF::STN_UNDEF)
-        continue;
-      uint32_t Index = Buckets[Buc];
-      uint32_t GnuHashable = Index - GnuHash->symndx;
-      // Print whole chain
-      while (true) {
-        printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc);
-        // Chain ends at symbol with stopper bit
-        if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1)
-          break;
-      }
+  // Try printing the .gnu.hash table.
+  const Elf_GnuHash *GnuHash = this->dumper()->getGnuHashTable();
+  if (!GnuHash)
+    return;
+
+  OS << "\n Symbol table of .gnu.hash for image:\n";
+  if (ELFT::Is64Bits)
+    OS << "  Num Buc:    Value          Size   Type   Bind Vis      Ndx Name";
+  else
+    OS << "  Num Buc:    Value  Size   Type   Bind Vis      Ndx Name";
+  OS << "\n";
+
+  if (Error E = checkGNUHashTable<ELFT>(Obj, GnuHash)) {
+    this->reportUniqueWarning(std::move(E));
+    return;
+  }
+
+  auto Buckets = GnuHash->buckets();
+  for (uint32_t Buc = 0; Buc < GnuHash->nbuckets; Buc++) {
+    if (Buckets[Buc] == ELF::STN_UNDEF)
+      continue;
+    uint32_t Index = Buckets[Buc];
+    uint32_t GnuHashable = Index - GnuHash->symndx;
+    // Print whole chain
+    while (true) {
+      printHashedSymbol(Obj, &DynSyms[0], Index++, StringTable, Buc);
+      // Chain ends at symbol with stopper bit
+      if ((GnuHash->values(DynSyms.size())[GnuHashable++] & 1) == 1)
+        break;
     }
   }
 }


        


More information about the llvm-commits mailing list