[llvm] 82f2b66 - [llvm-objdump][ELF]Fix crash when reading strings from .dynstr (#125679)
via llvm-commits
llvm-commits at lists.llvm.org
Sun Mar 9 19:40:02 PDT 2025
Author: Ruoyu Qiu
Date: 2025-03-09T19:39:58-07:00
New Revision: 82f2b661101d1133b72872141009035f01a42595
URL: https://github.com/llvm/llvm-project/commit/82f2b661101d1133b72872141009035f01a42595
DIFF: https://github.com/llvm/llvm-project/commit/82f2b661101d1133b72872141009035f01a42595.diff
LOG: [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
https://github.com/llvm/llvm-project/issues/86612#issuecomment-2035694455.
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 <James.Henderson at sony.com>
Added:
Modified:
llvm/test/tools/llvm-objdump/ELF/dynamic-section.test
llvm/tools/llvm-objdump/ELFDump.cpp
Removed:
################################################################################
diff --git a/llvm/test/tools/llvm-objdump/ELF/dynamic-section.test b/llvm/test/tools/llvm-objdump/ELF/dynamic-section.test
index 5205c5a3876d5..b84a6e56881d4 100644
--- a/llvm/test/tools/llvm-objdump/ELF/dynamic-section.test
+++ b/llvm/test/tools/llvm-objdump/ELF/dynamic-section.test
@@ -470,3 +470,46 @@ Sections:
Value: 0x1
- Tag: DT_NULL
Value: 0x0
+
+# RUN: yaml2obj --docnum=5 %s -o %t5
+# RUN: llvm-objdump -p %t5 2>&1 | FileCheck %s --strict-whitespace -DFILE=%t5 --check-prefix=WARN
+
+# WARN: Dynamic Section:
+# WARN-NEXT: warning: '[[FILE]]': invalid string table offset
+# WARN-NEXT: NEEDED 0x0000000000000010
+# WARN-NEXT: NEEDED {{$}}
+# WARN-NEXT: STRTAB 0x0000000000001000
+# WARN-NEXT: STRSZ 0x0000000000000010
+
+--- !ELF
+FileHeader:
+ Class: ELFCLASS64
+ Data: ELFDATA2LSB
+ Type: ET_EXEC
+ Machine: EM_X86_64
+Sections:
+ - Name: .dynstr
+ Type: SHT_STRTAB
+ Address: 0x1000
+ Size: 0x10
+ - Name: .dynamic
+ Type: SHT_DYNAMIC
+ Entries:
+ - Tag: DT_NEEDED
+ Value: 0x10
+ - Tag: DT_NEEDED
+ Value: 0x0F
+ - Tag: DT_STRTAB
+ Value: 0x1000
+ - Tag: DT_STRSZ
+ Value: 0x10
+ - Tag: DT_NULL
+ Value: 0x0
+ProgramHeaders:
+ - Type: PT_LOAD
+ VAddr: 0x1000
+ FirstSec: .dynstr
+ LastSec: .dynamic
+ - Type: PT_DYNAMIC
+ FirstSec: .dynamic
+ LastSec: .dynamic
diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp
index b7899bc3bcbee..3b288ea73398b 100644
--- a/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -63,16 +63,24 @@ static Expected<StringRef> getDynamicStrTab(const ELFFile<ELFT> &Elf) {
if (!DynamicEntriesOrError)
return DynamicEntriesOrError.takeError();
+ typename ELFT::Xword StringTableSize{0};
+ const uint8_t *MappedAddr = nullptr;
for (const typename ELFT::Dyn &Dyn : *DynamicEntriesOrError) {
if (Dyn.d_tag == ELF::DT_STRTAB) {
auto MappedAddrOrError = Elf.toMappedAddr(Dyn.getPtr());
if (!MappedAddrOrError)
return MappedAddrOrError.takeError();
- return StringRef(reinterpret_cast<const char *>(*MappedAddrOrError));
+ MappedAddr = *MappedAddrOrError;
}
+ if (Dyn.d_tag == ELF::DT_STRSZ)
+ StringTableSize = Dyn.getVal();
}
+ if (MappedAddr && StringTableSize)
+ return StringRef(reinterpret_cast<const char *>(MappedAddr),
+ StringTableSize);
- // If the dynamic segment is not present, we fall back on the sections.
+ // If the dynamic segment is not present, or is missing the important tags, we
+ // fall back on the sections.
auto SectionsOrError = Elf.sections();
if (!SectionsOrError)
return SectionsOrError.takeError();
@@ -221,6 +229,7 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicSection() {
std::string TagFmt = " %-" + std::to_string(MaxLen) + "s ";
outs() << "\nDynamic Section:\n";
+
for (const typename ELFT::Dyn &Dyn : DynamicEntries) {
if (Dyn.d_tag == ELF::DT_NULL)
continue;
@@ -235,6 +244,14 @@ template <class ELFT> void ELFDumper<ELFT>::printDynamicSection() {
Expected<StringRef> StrTabOrErr = getDynamicStrTab(Elf);
if (StrTabOrErr) {
const char *Data = StrTabOrErr->data();
+ if (Dyn.getVal() >= StrTabOrErr->size()) {
+ reportWarning("invalid string table offset, string table size: 0x" +
+ Twine::utohexstr(StrTabOrErr->size()),
+ Obj.getFileName());
+ outs() << format(TagFmt.c_str(), Str.c_str())
+ << format(Fmt, (uint64_t)Dyn.getVal());
+ continue;
+ }
outs() << format(TagFmt.c_str(), Str.c_str()) << Data + Dyn.getVal()
<< "\n";
continue;
More information about the llvm-commits
mailing list