Skip to content

Commit 68f5a8b

Browse files
committed
[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
1 parent a86ce06 commit 68f5a8b

File tree

7 files changed

+108
-39
lines changed

7 files changed

+108
-39
lines changed

lld/ELF/DWARF.h

+2-2
Original file line numberDiff line numberDiff line change
@@ -56,11 +56,11 @@ template <class ELFT> class LLDDwarfObj final : public llvm::DWARFObject {
5656
return addrSection;
5757
}
5858

59-
const llvm::DWARFSection &getGnuPubnamesSection() const override {
59+
const LLDDWARFSection &getGnuPubnamesSection() const override {
6060
return gnuPubnamesSection;
6161
}
6262

63-
const llvm::DWARFSection &getGnuPubtypesSection() const override {
63+
const LLDDWARFSection &getGnuPubtypesSection() const override {
6464
return gnuPubtypesSection;
6565
}
6666

lld/ELF/SyntheticSections.cpp

+7-4
Original file line numberDiff line numberDiff line change
@@ -2705,12 +2705,15 @@ template <class ELFT>
27052705
static std::vector<GdbIndexSection::NameAttrEntry>
27062706
readPubNamesAndTypes(const LLDDwarfObj<ELFT> &obj,
27072707
const std::vector<GdbIndexSection::CuEntry> &cus) {
2708-
const DWARFSection &pubNames = obj.getGnuPubnamesSection();
2709-
const DWARFSection &pubTypes = obj.getGnuPubtypesSection();
2708+
const LLDDWARFSection &pubNames = obj.getGnuPubnamesSection();
2709+
const LLDDWARFSection &pubTypes = obj.getGnuPubtypesSection();
27102710

27112711
std::vector<GdbIndexSection::NameAttrEntry> ret;
2712-
for (const DWARFSection *pub : {&pubNames, &pubTypes}) {
2713-
DWARFDebugPubTable table(obj, *pub, config->isLE, true);
2712+
for (const LLDDWARFSection *pub : {&pubNames, &pubTypes}) {
2713+
DWARFDataExtractor data(obj, *pub, config->isLE, config->wordsize);
2714+
DWARFDebugPubTable table;
2715+
if (Error e = table.extract(data, /*GnuStyle=*/true))
2716+
warn(toString(pub->sec) + ": " + toString(std::move(e)));
27142717
for (const DWARFDebugPubTable::Set &set : table.getData()) {
27152718
// The value written into the constant pool is kind << 24 | cuIndex. As we
27162719
// don't know how many compilation units precede this object to compute
+26
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# REQUIRES: x86
2+
# RUN: llvm-mc -filetype=obj -triple=x86_64 %s -o %t
3+
# RUN: ld.lld --gdb-index %t -o /dev/null 2>&1 | FileCheck %s
4+
5+
# CHECK: warning: {{.*}}(.debug_gnu_pubnames): unexpected end of data at offset 0x1 while reading [0x0, 0x4)
6+
7+
.section .debug_abbrev,"",@progbits
8+
.byte 1 # Abbreviation Code
9+
.byte 17 # DW_TAG_compile_unit
10+
.byte 0 # DW_CHILDREN_no
11+
.byte 0 # EOM(1)
12+
.byte 0 # EOM(2)
13+
.byte 0 # EOM(3)
14+
15+
.section .debug_info,"",@progbits
16+
.LCUBegin:
17+
.long .LUnitEnd-.LUnitBegin # Length of Unit
18+
.LUnitBegin:
19+
.short 4 # DWARF version number
20+
.long .debug_abbrev # Offset Into Abbrev. Section
21+
.byte 8 # Address Size (in bytes)
22+
.byte 1 # Abbrev [1] DW_TAG_compile_unit
23+
.LUnitEnd:
24+
25+
.section .debug_gnu_pubnames,"",@progbits
26+
.byte 0

llvm/include/llvm/DebugInfo/DWARF/DWARFDebugPubTable.h

+5-3
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "llvm/ADT/ArrayRef.h"
1313
#include "llvm/ADT/StringRef.h"
1414
#include "llvm/BinaryFormat/Dwarf.h"
15+
#include "llvm/DebugInfo/DWARF/DWARFDataExtractor.h"
1516
#include "llvm/DebugInfo/DWARF/DWARFObject.h"
1617
#include <cstdint>
1718
#include <vector>
@@ -67,11 +68,12 @@ class DWARFDebugPubTable {
6768

6869
/// gnu styled tables contains additional information.
6970
/// This flag determines whether or not section we parse is debug_gnu* table.
70-
bool GnuStyle;
71+
bool GnuStyle = false;
7172

7273
public:
73-
DWARFDebugPubTable(const DWARFObject &Obj, const DWARFSection &Sec,
74-
bool LittleEndian, bool GnuStyle);
74+
DWARFDebugPubTable() = default;
75+
76+
Error extract(DWARFDataExtractor Data, bool GnuStyle);
7577

7678
void dump(raw_ostream &OS) const;
7779

llvm/lib/DebugInfo/DWARF/DWARFContext.cpp

+28-14
Original file line numberDiff line numberDiff line change
@@ -336,6 +336,14 @@ static void dumpLoclistsSection(raw_ostream &OS, DIDumpOptions DumpOpts,
336336
}
337337
}
338338

339+
static void dumpPubTableSection(raw_ostream &OS, DIDumpOptions DumpOpts,
340+
DWARFDataExtractor Data, bool GnuStyle) {
341+
DWARFDebugPubTable Table;
342+
if (Error E = Table.extract(Data, GnuStyle))
343+
DumpOpts.RecoverableErrorHandler(std::move(E));
344+
Table.dump(OS);
345+
}
346+
339347
void DWARFContext::dump(
340348
raw_ostream &OS, DIDumpOptions DumpOpts,
341349
std::array<Optional<uint64_t>, DIDT_ID_Count> DumpOffsets) {
@@ -626,26 +634,32 @@ void DWARFContext::dump(
626634
}
627635

628636
if (shouldDump(Explicit, ".debug_pubnames", DIDT_ID_DebugPubnames,
629-
DObj->getPubnamesSection().Data))
630-
DWARFDebugPubTable(*DObj, DObj->getPubnamesSection(), isLittleEndian(), false)
631-
.dump(OS);
637+
DObj->getPubnamesSection().Data)) {
638+
DWARFDataExtractor PubTableData(*DObj, DObj->getPubnamesSection(),
639+
isLittleEndian(), 0);
640+
dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false);
641+
}
632642

633643
if (shouldDump(Explicit, ".debug_pubtypes", DIDT_ID_DebugPubtypes,
634-
DObj->getPubtypesSection().Data))
635-
DWARFDebugPubTable(*DObj, DObj->getPubtypesSection(), isLittleEndian(), false)
636-
.dump(OS);
644+
DObj->getPubtypesSection().Data)) {
645+
DWARFDataExtractor PubTableData(*DObj, DObj->getPubtypesSection(),
646+
isLittleEndian(), 0);
647+
dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/false);
648+
}
637649

638650
if (shouldDump(Explicit, ".debug_gnu_pubnames", DIDT_ID_DebugGnuPubnames,
639-
DObj->getGnuPubnamesSection().Data))
640-
DWARFDebugPubTable(*DObj, DObj->getGnuPubnamesSection(), isLittleEndian(),
641-
true /* GnuStyle */)
642-
.dump(OS);
651+
DObj->getGnuPubnamesSection().Data)) {
652+
DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubnamesSection(),
653+
isLittleEndian(), 0);
654+
dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true);
655+
}
643656

644657
if (shouldDump(Explicit, ".debug_gnu_pubtypes", DIDT_ID_DebugGnuPubtypes,
645-
DObj->getGnuPubtypesSection().Data))
646-
DWARFDebugPubTable(*DObj, DObj->getGnuPubtypesSection(), isLittleEndian(),
647-
true /* GnuStyle */)
648-
.dump(OS);
658+
DObj->getGnuPubtypesSection().Data)) {
659+
DWARFDataExtractor PubTableData(*DObj, DObj->getGnuPubtypesSection(),
660+
isLittleEndian(), 0);
661+
dumpPubTableSection(OS, DumpOpts, PubTableData, /*GnuStyle=*/true);
662+
}
649663

650664
if (shouldDump(Explicit, ".debug_str_offsets", DIDT_ID_DebugStrOffsets,
651665
DObj->getStrOffsetsSection().Data))

llvm/lib/DebugInfo/DWARF/DWARFDebugPubTable.cpp

+14-16
Original file line numberDiff line numberDiff line change
@@ -18,34 +18,32 @@
1818
using namespace llvm;
1919
using namespace dwarf;
2020

21-
DWARFDebugPubTable::DWARFDebugPubTable(const DWARFObject &Obj,
22-
const DWARFSection &Sec,
23-
bool LittleEndian, bool GnuStyle)
24-
: GnuStyle(GnuStyle) {
25-
DWARFDataExtractor PubNames(Obj, Sec, LittleEndian, 0);
26-
uint64_t Offset = 0;
27-
while (PubNames.isValidOffset(Offset)) {
21+
Error DWARFDebugPubTable::extract(DWARFDataExtractor Data, bool GnuStyle) {
22+
this->GnuStyle = GnuStyle;
23+
Sets.clear();
24+
DataExtractor::Cursor C(0);
25+
while (C && Data.isValidOffset(C.tell())) {
2826
Sets.push_back({});
2927
Set &SetData = Sets.back();
3028

31-
std::tie(SetData.Length, SetData.Format) =
32-
PubNames.getInitialLength(&Offset);
29+
std::tie(SetData.Length, SetData.Format) = Data.getInitialLength(C);
3330
const unsigned OffsetSize = dwarf::getDwarfOffsetByteSize(SetData.Format);
3431

35-
SetData.Version = PubNames.getU16(&Offset);
36-
SetData.Offset = PubNames.getRelocatedValue(OffsetSize, &Offset);
37-
SetData.Size = PubNames.getUnsigned(&Offset, OffsetSize);
32+
SetData.Version = Data.getU16(C);
33+
SetData.Offset = Data.getRelocatedValue(C, OffsetSize);
34+
SetData.Size = Data.getUnsigned(C, OffsetSize);
3835

39-
while (Offset < Sec.Data.size()) {
40-
uint64_t DieRef = PubNames.getUnsigned(&Offset, OffsetSize);
36+
while (C) {
37+
uint64_t DieRef = Data.getUnsigned(C, OffsetSize);
4138
if (DieRef == 0)
4239
break;
43-
uint8_t IndexEntryValue = GnuStyle ? PubNames.getU8(&Offset) : 0;
44-
StringRef Name = PubNames.getCStrRef(&Offset);
40+
uint8_t IndexEntryValue = GnuStyle ? Data.getU8(C) : 0;
41+
StringRef Name = Data.getCStrRef(C);
4542
SetData.Entries.push_back(
4643
{DieRef, PubIndexEntryDescriptor(IndexEntryValue), Name});
4744
}
4845
}
46+
return C.takeError();
4947
}
5048

5149
void DWARFDebugPubTable::dump(raw_ostream &OS) const {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,26 @@
1+
# RUN: llvm-mc -triple x86_64 %s -filetype=obj -o %t
2+
# RUN: not llvm-dwarfdump -v %t 2>&1 | FileCheck %s
3+
4+
# CHECK: .debug_pubnames contents:
5+
# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
6+
7+
# CHECK: .debug_pubtypes contents:
8+
# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
9+
10+
# CHECK: .debug_gnu_pubnames contents:
11+
# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
12+
13+
# CHECK: .debug_gnu_pubtypes contents:
14+
# CHECK-NEXT: error: unexpected end of data at offset 0x1 while reading [0x0, 0x4)
15+
16+
.section .debug_pubnames,"",@progbits
17+
.byte 0
18+
19+
.section .debug_pubtypes,"",@progbits
20+
.byte 0
21+
22+
.section .debug_gnu_pubnames,"",@progbits
23+
.byte 0
24+
25+
.section .debug_gnu_pubtypes,"",@progbits
26+
.byte 0

0 commit comments

Comments
 (0)