[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