[lld] 68f5a8b - [DebugInfo] Do not hang when parsing a malformed .debug_pub* section.

Igor Kudrin via llvm-commits llvm-commits at lists.llvm.org
Thu Jul 9 05:16:45 PDT 2020


Author: Igor Kudrin
Date: 2020-07-09T19:15:11+07:00
New Revision: 68f5a8b2042b8c4dc83d1851b462a0570eb3410f

URL: https://github.com/llvm/llvm-project/commit/68f5a8b2042b8c4dc83d1851b462a0570eb3410f
DIFF: https://github.com/llvm/llvm-project/commit/68f5a8b2042b8c4dc83d1851b462a0570eb3410f.diff

LOG: [DebugInfo] Do not hang when parsing a malformed .debug_pub* section.

The parsing method did not check reading errors and might easily fall
into an infinite loop on an invalid input because of that.

Differential Revision: https://reviews.llvm.org/D83049

Added: 
    lld/test/ELF/gdb-index-invalid-pubnames.s
    llvm/test/tools/llvm-dwarfdump/X86/debug_pub_tables_invalid.s

Modified: 
    lld/ELF/DWARF.h
    lld/ELF/SyntheticSections.cpp
    llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h
    llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
    llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp

Removed: 
    


################################################################################
diff  --git a/lld/ELF/DWARF.h b/lld/ELF/DWARF.h
index 8609e35faf95..a12dae6e9960 100644
--- a/lld/ELF/DWARF.h
+++ b/lld/ELF/DWARF.h
@@ -56,11 +56,11 @@ template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
     return addrSection;
   }
 
-  const llvm::DWARFSection &getGnuPubnamesSection() const override {
+  const LLDDWARFSection &getGnuPubnamesSection() const override {
     return gnuPubnamesSection;
   }
 
-  const llvm::DWARFSection &getGnuPubtypesSection() const override {
+  const LLDDWARFSection &getGnuPubtypesSection() const override {
     return gnuPubtypesSection;
   }
 

diff  --git a/lld/ELF/SyntheticSections.cpp b/lld/ELF/SyntheticSections.cpp
index f6d66fff6d4b..33748f881576 100644
--- a/lld/ELF/SyntheticSections.cpp
+++ b/lld/ELF/SyntheticSections.cpp
@@ -2705,12 +2705,15 @@ template <class ELFT>
 static std::vector<GdbIndexSection::NameAttrEntry>
 readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj,
                      const std::vector<GdbIndexSection::CuEntry> &cus) {
-  const DWARFSection &pubNames = obj.getGnuPubnamesSection();
-  const DWARFSection &pubTypes = obj.getGnuPubtypesSection();
+  const LLDDWARFSection &pubNames = obj.getGnuPubnamesSection();
+  const LLDDWARFSection &pubTypes = obj.getGnuPubtypesSection();
 
   std::vector<GdbIndexSection::NameAttrEntry> ret;
-  for (const DWARFSection *pub : {&pubNames, &pubTypes}) {
-    DWARFDebugPubTable table(obj, *pub, config->isLE, true);
+  for (const LLDDWARFSection *pub : {&pubNames, &pubTypes}) {
+    DWARFDataExtractor data(obj, *pub, config->isLE, config->wordsize);
+    DWARFDebugPubTable table;
+    if (Error e = table.extract(data, /*GnuStyle=*/true))
+      warn(toString(pub->sec) + ": " + toString(std::move(e)));
     for (const DWARFDebugPubTable::Set &set : table.getData()) {
       // The value written into the constant pool is kind << 24 | cuIndex. As we
       // don't know how many compilation units precede this object to compute

diff  --git a/lld/test/ELF/gdb-index-invalid-pubnames.s b/lld/test/ELF/gdb-index-invalid-pubnames.s
new file mode 100644
index 000000000000..15eb86ee7c1e
--- /dev/null
+++ b/lld/test/ELF/gdb-index-invalid-pubnames.s
@@ -0,0 +1,26 @@
+# REQUIRES: x86
+# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
+# RUN: ld.lld --gdb-index %t -o /dev/null 2>&1 | FileCheck %s
+
+# CHECK: warning: {{.*}}(.debug_gnu_pubnames): unexpected end of data at offset 0x1 while reading [0x0, 0x4)
+
+    .section .debug_abbrev,"", at progbits
+    .byte 1                         # Abbreviation Code
+    .byte 17                        # DW_TAG_compile_unit
+    .byte 0                         # DW_CHILDREN_no
+    .byte 0                         # EOM(1)
+    .byte 0                         # EOM(2)
+    .byte 0                         # EOM(3)
+
+    .section .debug_info,"", at progbits
+.LCUBegin:
+    .long .LUnitEnd-.LUnitBegin     # Length of Unit
+.LUnitBegin:
+    .short 4                        # DWARF version number
+    .long .debug_abbrev             # Offset Into Abbrev. Section
+    .byte 8                         # Address Size (in bytes)
+    .byte 1                         # Abbrev [1] DW_TAG_compile_unit
+.LUnitEnd:
+
+    .section .debug_gnu_pubnames,"", at progbits
+    .byte 0

diff  --git a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h
index 60f80bb12aa9..80c2d75bdc2a 100644
--- a/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h
+++ b/llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h
@@ -12,6 +12,7 @@
 #include "llvm/ADT/ArrayRef.h"
 #include "llvm/ADT/StringRef.h"
 #include "llvm/BinaryFormat/Dwarf.h"
+#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
 #include "llvm/DebugInfo/DWARF/DWARFObject.h"
 #include <cstdint>
 #include <vector>
@@ -67,11 +68,12 @@ class DWARFDebugPubTable {
 
   /// gnu styled tables contains additional information.
   /// This flag determines whether or not section we parse is debug_gnu* table.
-  bool GnuStyle;
+  bool GnuStyle = false;
 
 public:
-  DWARFDebugPubTable(const DWARFObject &Obj, const DWARFSection &Sec,
-                     bool LittleEndian, bool GnuStyle);
+  DWARFDebugPubTable() = default;
+
+  Error extract(DWARFDataExtractor Data, bool GnuStyle);
 
   void dump(raw_ostream &OS) const;
 

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
index ebe2600e0689..dba6b85e9104 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFContext.cpp
@@ -336,6 +336,14 @@ static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
   }
 }
 
+static void dumpPubTableSection(raw_ostream &OS, DIDumpOptions DumpOpts,
+                                DWARFDataExtractor Data, bool GnuStyle) {
+  DWARFDebugPubTable Table;
+  if (Error E = Table.extract(Data, GnuStyle))
+    DumpOpts.RecoverableErrorHandler(std::move(E));
+  Table.dump(OS);
+}
+
 void DWARFContext::dump(
     raw_ostream &OS, DIDumpOptions DumpOpts,
     std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
@@ -626,26 +634,32 @@ void DWARFContext::dump(
   }
 
   if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
-                 DObj->getPubnamesSection().Data))
-    DWARFDebugPubTable(*DObj, DObj->getPubnamesSection(), isLittleEndian(), false)
-        .dump(OS);
+                 DObj->getPubnamesSection().Data)) {
+    DWARFDataExtractor PubTableData(*DObj, DObj->getPubnamesSection(),
+                                    isLittleEndian(), 0);
+    dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false);
+  }
 
   if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes,
-                 DObj->getPubtypesSection().Data))
-    DWARFDebugPubTable(*DObj, DObj->getPubtypesSection(), isLittleEndian(), false)
-        .dump(OS);
+                 DObj->getPubtypesSection().Data)) {
+    DWARFDataExtractor PubTableData(*DObj, DObj->getPubtypesSection(),
+                                    isLittleEndian(), 0);
+    dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false);
+  }
 
   if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames,
-                 DObj->getGnuPubnamesSection().Data))
-    DWARFDebugPubTable(*DObj, DObj->getGnuPubnamesSection(), isLittleEndian(),
-                       true /* GnuStyle */)
-        .dump(OS);
+                 DObj->getGnuPubnamesSection().Data)) {
+    DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubnamesSection(),
+                                    isLittleEndian(), 0);
+    dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true);
+  }
 
   if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes,
-                 DObj->getGnuPubtypesSection().Data))
-    DWARFDebugPubTable(*DObj, DObj->getGnuPubtypesSection(), isLittleEndian(),
-                       true /* GnuStyle */)
-        .dump(OS);
+                 DObj->getGnuPubtypesSection().Data)) {
+    DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubtypesSection(),
+                                    isLittleEndian(), 0);
+    dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true);
+  }
 
   if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets,
                  DObj->getStrOffsetsSection().Data))

diff  --git a/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp b/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
index eecca87d5270..45e16653420c 100644
--- a/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
+++ b/llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp
@@ -18,34 +18,32 @@
 using namespace llvm;
 using namespace dwarf;
 
-DWARFDebugPubTable::DWARFDebugPubTable(const DWARFObject &Obj,
-                                       const DWARFSection &Sec,
-                                       bool LittleEndian, bool GnuStyle)
-    : GnuStyle(GnuStyle) {
-  DWARFDataExtractor PubNames(Obj, Sec, LittleEndian, 0);
-  uint64_t Offset = 0;
-  while (PubNames.isValidOffset(Offset)) {
+Error DWARFDebugPubTable::extract(DWARFDataExtractor Data, bool GnuStyle) {
+  this->GnuStyle = GnuStyle;
+  Sets.clear();
+  DataExtractor::Cursor C(0);
+  while (C && Data.isValidOffset(C.tell())) {
     Sets.push_back({});
     Set &SetData = Sets.back();
 
-    std::tie(SetData.Length, SetData.Format) =
-        PubNames.getInitialLength(&Offset);
+    std::tie(SetData.Length, SetData.Format) = Data.getInitialLength(C);
     const unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(SetData.Format);
 
-    SetData.Version = PubNames.getU16(&Offset);
-    SetData.Offset = PubNames.getRelocatedValue(OffsetSize, &Offset);
-    SetData.Size = PubNames.getUnsigned(&Offset, OffsetSize);
+    SetData.Version = Data.getU16(C);
+    SetData.Offset = Data.getRelocatedValue(C, OffsetSize);
+    SetData.Size = Data.getUnsigned(C, OffsetSize);
 
-    while (Offset < Sec.Data.size()) {
-      uint64_t DieRef = PubNames.getUnsigned(&Offset, OffsetSize);
+    while (C) {
+      uint64_t DieRef = Data.getUnsigned(C, OffsetSize);
       if (DieRef == 0)
         break;
-      uint8_t IndexEntryValue = GnuStyle ? PubNames.getU8(&Offset) : 0;
-      StringRef Name = PubNames.getCStrRef(&Offset);
+      uint8_t IndexEntryValue = GnuStyle ? Data.getU8(C) : 0;
+      StringRef Name = Data.getCStrRef(C);
       SetData.Entries.push_back(
           {DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name});
     }
   }
+  return C.takeError();
 }
 
 void DWARFDebugPubTable::dump(raw_ostream &OS) const {

diff  --git a/llvm/test/tools/llvm-dwarfdump/X86/debug_pub_tables_invalid.s b/llvm/test/tools/llvm-dwarfdump/X86/debug_pub_tables_invalid.s
new file mode 100644
index 000000000000..cfd75c2a9aca
--- /dev/null
+++ b/llvm/test/tools/llvm-dwarfdump/X86/debug_pub_tables_invalid.s
@@ -0,0 +1,26 @@
+# RUN: llvm-mc -triple x86_64 %s -filetype=obj -o %t
+# RUN: not llvm-dwarfdump -v %t 2>&1 | FileCheck %s
+
+# CHECK:      .debug_pubnames contents:
+# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
+
+# CHECK:      .debug_pubtypes contents:
+# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
+
+# CHECK:      .debug_gnu_pubnames contents:
+# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
+
+# CHECK:      .debug_gnu_pubtypes contents:
+# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
+
+    .section .debug_pubnames,"", at progbits
+    .byte 0
+
+    .section .debug_pubtypes,"", at progbits
+    .byte 0
+
+    .section .debug_gnu_pubnames,"", at progbits
+    .byte 0
+
+    .section .debug_gnu_pubtypes,"", at progbits
+    .byte 0


        


More information about the llvm-commits mailing list