Skip to content

Commit 82f2b66

Browse files
cabbakenjh7370
andauthored
[llvm-objdump][ELF]Fix crash when reading strings from .dynstr (#125679)
This change introduces a check for the strtab offset to prevent llvm-objdump from crashing when processing malformed ELF files. It provide a minimal reproduce test for #86612 (comment). Additionally, it modifies how llvm-objdump handles and outputs malformed ELF files with invalid string offsets.(More info: https://discourse.llvm.org/t/should-llvm-objdump-objdump-display-actual-corrupted-values-in-malformed-elf-files/84391) Fixes: #86612 Co-authored-by: James Henderson <[email protected]>
1 parent 42d49a7 commit 82f2b66

File tree

2 files changed

+62
-2
lines changed

2 files changed

+62
-2
lines changed

llvm/test/tools/llvm-objdump/ELF/dynamic-section.test

Lines changed: 43 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -470,3 +470,46 @@ Sections:
470470
Value: 0x1
471471
- Tag: DT_NULL
472472
Value: 0x0
473+
474+
# RUN: yaml2obj --docnum=5 %s -o %t5
475+
# RUN: llvm-objdump -p %t5 2>&1 | FileCheck %s --strict-whitespace -DFILE=%t5 --check-prefix=WARN
476+
477+
# WARN: Dynamic Section:
478+
# WARN-NEXT: warning: '[[FILE]]': invalid string table offset
479+
# WARN-NEXT: NEEDED 0x0000000000000010
480+
# WARN-NEXT: NEEDED {{$}}
481+
# WARN-NEXT: STRTAB 0x0000000000001000
482+
# WARN-NEXT: STRSZ 0x0000000000000010
483+
484+
--- !ELF
485+
FileHeader:
486+
Class: ELFCLASS64
487+
Data: ELFDATA2LSB
488+
Type: ET_EXEC
489+
Machine: EM_X86_64
490+
Sections:
491+
- Name: .dynstr
492+
Type: SHT_STRTAB
493+
Address: 0x1000
494+
Size: 0x10
495+
- Name: .dynamic
496+
Type: SHT_DYNAMIC
497+
Entries:
498+
- Tag: DT_NEEDED
499+
Value: 0x10
500+
- Tag: DT_NEEDED
501+
Value: 0x0F
502+
- Tag: DT_STRTAB
503+
Value: 0x1000
504+
- Tag: DT_STRSZ
505+
Value: 0x10
506+
- Tag: DT_NULL
507+
Value: 0x0
508+
ProgramHeaders:
509+
- Type: PT_LOAD
510+
VAddr: 0x1000
511+
FirstSec: .dynstr
512+
LastSec: .dynamic
513+
- Type: PT_DYNAMIC
514+
FirstSec: .dynamic
515+
LastSec: .dynamic

llvm/tools/llvm-objdump/ELFDump.cpp

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -63,16 +63,24 @@ static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> &Elf) {
6363
if (!DynamicEntriesOrError)
6464
return DynamicEntriesOrError.takeError();
6565

66+
typename ELFT::Xword StringTableSize{0};
67+
const uint8_t *MappedAddr = nullptr;
6668
for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
6769
if (Dyn.d_tag == ELF::DT_STRTAB) {
6870
auto MappedAddrOrError = Elf.toMappedAddr(Dyn.getPtr());
6971
if (!MappedAddrOrError)
7072
return MappedAddrOrError.takeError();
71-
return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError));
73+
MappedAddr = *MappedAddrOrError;
7274
}
75+
if (Dyn.d_tag == ELF::DT_STRSZ)
76+
StringTableSize = Dyn.getVal();
7377
}
78+
if (MappedAddr && StringTableSize)
79+
return StringRef(reinterpret_cast<const char *>(MappedAddr),
80+
StringTableSize);
7481

75-
// If the dynamic segment is not present, we fall back on the sections.
82+
// If the dynamic segment is not present, or is missing the important tags, we
83+
// fall back on the sections.
7684
auto SectionsOrError = Elf.sections();
7785
if (!SectionsOrError)
7886
return SectionsOrError.takeError();
@@ -221,6 +229,7 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicSection() {
221229
std::string TagFmt = " %-" + std::to_string(MaxLen) + "s ";
222230

223231
outs() << "\nDynamic Section:\n";
232+
224233
for (const typename ELFT::Dyn &Dyn : DynamicEntries) {
225234
if (Dyn.d_tag == ELF::DT_NULL)
226235
continue;
@@ -235,6 +244,14 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicSection() {
235244
Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf);
236245
if (StrTabOrErr) {
237246
const char *Data = StrTabOrErr->data();
247+
if (Dyn.getVal() >= StrTabOrErr->size()) {
248+
reportWarning("invalid string table offset, string table size: 0x" +
249+
Twine::utohexstr(StrTabOrErr->size()),
250+
Obj.getFileName());
251+
outs() << format(TagFmt.c_str(), Str.c_str())
252+
<< format(Fmt, (uint64_t)Dyn.getVal());
253+
continue;
254+
}
238255
outs() << format(TagFmt.c_str(), Str.c_str()) << Data + Dyn.getVal()
239256
<< "\n";
240257
continue;

0 commit comments

Comments
 (0)