[llvm] [llvm-objdump][ELF] Ensure offset to verdaux entry array does not go past size (PR #115284)

Antonio Frighetto via llvm-commits llvm-commits at lists.llvm.org
Fri Nov 8 03:34:43 PST 2024


https://github.com/antoniofrighetto updated https://github.com/llvm/llvm-project/pull/115284

>From f112c1e54b0b38401b535764055ab1867f937752 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 8 Nov 2024 12:25:02 +0100
Subject: [PATCH 1/3] [ObjectYAML][ELF] Fix misspelling in `Elf_Verdaux` var
 name (NFC)

---
 llvm/lib/ObjectYAML/ELFEmitter.cpp | 10 +++++-----
 1 file changed, 5 insertions(+), 5 deletions(-)

diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index fc234581a45a70..a449b18143f92b 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1665,13 +1665,13 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
     CBA.write((const char *)&VerDef, sizeof(Elf_Verdef));
 
     for (size_t J = 0; J < E.VerNames.size(); ++J, ++AuxCnt) {
-      Elf_Verdaux VernAux;
-      VernAux.vda_name = DotDynstr.getOffset(E.VerNames[J]);
+      Elf_Verdaux VerdAux;
+      VerdAux.vda_name = DotDynstr.getOffset(E.VerNames[J]);
       if (J == E.VerNames.size() - 1)
-        VernAux.vda_next = 0;
+        VerdAux.vda_next = 0;
       else
-        VernAux.vda_next = sizeof(Elf_Verdaux);
-      CBA.write((const char *)&VernAux, sizeof(Elf_Verdaux));
+        VerdAux.vda_next = sizeof(Elf_Verdaux);
+      CBA.write((const char *)&VerdAux, sizeof(Elf_Verdaux));
     }
   }
 

>From d4ae0505c7dcd8af687a54753162d6802f91eb93 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 8 Nov 2024 12:25:17 +0100
Subject: [PATCH 2/3] [ObjectYAML][ELF] Allow verdaux entry offset to be
 user-defined

---
 llvm/include/llvm/ObjectYAML/ELFYAML.h           | 1 +
 llvm/lib/ObjectYAML/ELFEmitter.cpp               | 2 +-
 llvm/lib/ObjectYAML/ELFYAML.cpp                  | 1 +
 llvm/test/tools/obj2yaml/ELF/verdef-section.yaml | 8 ++++++++
 llvm/tools/obj2yaml/elf2yaml.cpp                 | 8 ++++++++
 5 files changed, 19 insertions(+), 1 deletion(-)

diff --git a/llvm/include/llvm/ObjectYAML/ELFYAML.h b/llvm/include/llvm/ObjectYAML/ELFYAML.h
index 8f045d6383623b..dfdfa055d65fa6 100644
--- a/llvm/include/llvm/ObjectYAML/ELFYAML.h
+++ b/llvm/include/llvm/ObjectYAML/ELFYAML.h
@@ -582,6 +582,7 @@ struct VerdefEntry {
   std::optional<uint16_t> Flags;
   std::optional<uint16_t> VersionNdx;
   std::optional<uint32_t> Hash;
+  std::optional<uint16_t> VDAux;
   std::vector<StringRef> VerNames;
 };
 
diff --git a/llvm/lib/ObjectYAML/ELFEmitter.cpp b/llvm/lib/ObjectYAML/ELFEmitter.cpp
index a449b18143f92b..bf19e81933cab7 100644
--- a/llvm/lib/ObjectYAML/ELFEmitter.cpp
+++ b/llvm/lib/ObjectYAML/ELFEmitter.cpp
@@ -1655,7 +1655,7 @@ void ELFState<ELFT>::writeSectionContent(Elf_Shdr &SHeader,
     VerDef.vd_flags = E.Flags.value_or(0);
     VerDef.vd_ndx = E.VersionNdx.value_or(0);
     VerDef.vd_hash = E.Hash.value_or(0);
-    VerDef.vd_aux = sizeof(Elf_Verdef);
+    VerDef.vd_aux = E.VDAux.value_or(sizeof(Elf_Verdef));
     VerDef.vd_cnt = E.VerNames.size();
     if (I == Section.Entries->size() - 1)
       VerDef.vd_next = 0;
diff --git a/llvm/lib/ObjectYAML/ELFYAML.cpp b/llvm/lib/ObjectYAML/ELFYAML.cpp
index e97248cbcf5682..bd816a6d704d44 100644
--- a/llvm/lib/ObjectYAML/ELFYAML.cpp
+++ b/llvm/lib/ObjectYAML/ELFYAML.cpp
@@ -1921,6 +1921,7 @@ void MappingTraits<ELFYAML::VerdefEntry>::mapping(IO &IO,
   IO.mapOptional("Flags", E.Flags);
   IO.mapOptional("VersionNdx", E.VersionNdx);
   IO.mapOptional("Hash", E.Hash);
+  IO.mapOptional("VDAux", E.VDAux);
   IO.mapRequired("Names", E.VerNames);
 }
 
diff --git a/llvm/test/tools/obj2yaml/ELF/verdef-section.yaml b/llvm/test/tools/obj2yaml/ELF/verdef-section.yaml
index fc3e0f7ae22d9c..f082e897a6636c 100644
--- a/llvm/test/tools/obj2yaml/ELF/verdef-section.yaml
+++ b/llvm/test/tools/obj2yaml/ELF/verdef-section.yaml
@@ -48,12 +48,14 @@ Sections:
         Flags:      0
         VersionNdx: 0
         Hash:       0
+        VDAux:      20
         Names:
           - VERSION_0
 ## An entry with arbitrary values.
       - Flags:      2
         VersionNdx: 2
         Hash:       108387921
+        VDAux:      [[VDAUX=20]]
         Names:
           - VERSION_1
 ## Another entry with arbitrary values and version predecessors.
@@ -81,3 +83,9 @@ DynamicSymbols: []
 # RUN:   FileCheck %s -DFILE=%t.version --check-prefix=VERSION-ERR
 
 # VERSION-ERR: Error reading file: [[FILE]]: invalid SHT_GNU_verdef section version: 2
+
+# RUN: yaml2obj %s -DVDAUX=100 -o %t.vdaux
+# RUN: not obj2yaml %t.vdaux 2>&1 | \
+# RUN:   FileCheck %s -DFILE=%t.vdaux --check-prefix=VDAUX-ERR
+
+# VDAUX-ERR: Error reading file: [[FILE]]: corrupted section: vd_aux value 100 in section verdef points past end of the section
diff --git a/llvm/tools/obj2yaml/elf2yaml.cpp b/llvm/tools/obj2yaml/elf2yaml.cpp
index 9b4644bde36c0b..b1c8032ea21929 100644
--- a/llvm/tools/obj2yaml/elf2yaml.cpp
+++ b/llvm/tools/obj2yaml/elf2yaml.cpp
@@ -1451,7 +1451,15 @@ ELFDumper<ELFT>::dumpVerdefSection(const Elf_Shdr *Shdr) {
     if (Verdef->vd_hash != 0)
       Entry.Hash = Verdef->vd_hash;
 
+    if (Verdef->vd_aux != sizeof(Elf_Verdef))
+      Entry.VDAux = Verdef->vd_aux;
+
     const uint8_t *BufAux = Buf + Verdef->vd_aux;
+    if (BufAux > Data.end())
+      return createStringError(
+          errc::invalid_argument,
+          "corrupted section: vd_aux value " + Twine(Verdef->vd_aux) +
+              " in section verdef points past end of the section");
     while (BufAux) {
       const Elf_Verdaux *Verdaux =
           reinterpret_cast<const Elf_Verdaux *>(BufAux);

>From ab4c234bd831e16e742b367137ffa1ca01417b28 Mon Sep 17 00:00:00 2001
From: Antonio Frighetto <me at antoniofrighetto.com>
Date: Fri, 8 Nov 2024 12:34:03 +0100
Subject: [PATCH 3/3] [llvm-objdump][ELF] Ensure offset to verdaux entry array
 does not go past size

Validate `vd_aux` while parsing `Elf_Verdef` structure.

Fixes: https://github.com/llvm/llvm-project/issues/86611.
---
 .../llvm-objdump/ELF/invalid-verdef.test      | 25 +++++++++++++++++++
 llvm/tools/llvm-objdump/ELFDump.cpp           | 17 ++++++++++---
 2 files changed, 38 insertions(+), 4 deletions(-)
 create mode 100644 llvm/test/tools/llvm-objdump/ELF/invalid-verdef.test

diff --git a/llvm/test/tools/llvm-objdump/ELF/invalid-verdef.test b/llvm/test/tools/llvm-objdump/ELF/invalid-verdef.test
new file mode 100644
index 00000000000000..9f6ea6d1c5193e
--- /dev/null
+++ b/llvm/test/tools/llvm-objdump/ELF/invalid-verdef.test
@@ -0,0 +1,25 @@
+# RUN: yaml2obj %s -o %t
+# RUN: llvm-objdump -p %t 2>&1 | FileCheck --check-prefix=BROKEN-VERDEF -DFILE=%t %s
+
+## Ensure we emit a warning when vd_aux offset field is invalid.
+
+# BROKEN-VERDEF: Version definitions:
+# BROKEN-VERDEF-NEXT: warning: '[[FILE]]': corrupted section: vd_aux value 69 in section verdef points past end of the section
+
+--- !ELF
+FileHeader:
+  Class:           ELFCLASS64
+  Data:            ELFDATA2LSB
+  Type:            ET_DYN
+Sections:
+  - Name:            .gnu.version_d
+    Type:            SHT_GNU_verdef
+    Entries:
+      - Version:         1
+        Flags:           0
+        VersionNdx:      0
+        VDAux:           69
+        Names:
+          - VERSION_1
+DynamicSymbols: []
+...
diff --git a/llvm/tools/llvm-objdump/ELFDump.cpp b/llvm/tools/llvm-objdump/ELFDump.cpp
index 5ac13495662faf..bfa5f57d2f0ec7 100644
--- a/llvm/tools/llvm-objdump/ELFDump.cpp
+++ b/llvm/tools/llvm-objdump/ELFDump.cpp
@@ -39,6 +39,9 @@ template <typename ELFT> class ELFDumper : public Dumper {
   void printProgramHeaders();
   void printSymbolVersion();
   void printSymbolVersionDependency(const typename ELFT::Shdr &Sec);
+  void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
+                                    ArrayRef<uint8_t> Contents,
+                                    StringRef StrTab);
 };
 } // namespace
 
@@ -380,9 +383,9 @@ void ELFDumper<ELFT>::printSymbolVersionDependency(
 }
 
 template <class ELFT>
-static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
-                                         ArrayRef<uint8_t> Contents,
-                                         StringRef StrTab) {
+void ELFDumper<ELFT>::printSymbolVersionDefinition(
+    const typename ELFT::Shdr &Shdr, ArrayRef<uint8_t> Contents,
+    StringRef StrTab) {
   outs() << "\nVersion definitions:\n";
 
   const uint8_t *Buf = Contents.data();
@@ -398,6 +401,12 @@ static void printSymbolVersionDefinition(const typename ELFT::Shdr &Shdr,
            << format("0x%08" PRIx32 " ", (uint32_t)Verdef->vd_hash);
 
     const uint8_t *BufAux = Buf + Verdef->vd_aux;
+    if (BufAux > Contents.end()) {
+      reportWarning("corrupted section: vd_aux value " + Twine(Verdef->vd_aux) +
+                        " in section verdef points past end of the section",
+                    Obj.getFileName());
+      break;
+    }
     uint16_t VerdauxIndex = 0;
     while (BufAux) {
       auto *Verdaux = reinterpret_cast<const typename ELFT::Verdaux *>(BufAux);
@@ -430,7 +439,7 @@ template <class ELFT> void ELFDumper<ELFT>::printSymbolVersion() {
     if (Shdr.sh_type == ELF::SHT_GNU_verneed)
       printSymbolVersionDependency(Shdr);
     else
-      printSymbolVersionDefinition<ELFT>(Shdr, Contents, StrTab);
+      printSymbolVersionDefinition(Shdr, Contents, StrTab);
   }
 }
 



More information about the llvm-commits mailing list