[llvm] bbaeb1e - Validate chained fixup image formats

Adrian Prantl via llvm-commits llvm-commits at lists.llvm.org
Fri Feb 25 13:04:25 PST 2022


Author: Adrian Prantl
Date: 2022-02-25T13:04:00-08:00
New Revision: bbaeb1ee0ee03ffd5161f1414c8b36d7d7fcdbb7

URL: https://github.com/llvm/llvm-project/commit/bbaeb1ee0ee03ffd5161f1414c8b36d7d7fcdbb7
DIFF: https://github.com/llvm/llvm-project/commit/bbaeb1ee0ee03ffd5161f1414c8b36d7d7fcdbb7.diff

LOG: Validate chained fixup image formats

This is part of a series of patches to upstream support for Mach-O
chained fixups.

Differential Revision: https://reviews.llvm.org/D113725

Added: 
    

Modified: 
    llvm/include/llvm/BinaryFormat/MachO.h
    llvm/include/llvm/Object/MachO.h
    llvm/lib/Object/MachOObjectFile.cpp
    llvm/test/Object/AArch64/chained-fixups-header.test

Removed: 
    


################################################################################
diff  --git a/llvm/include/llvm/BinaryFormat/MachO.h b/llvm/include/llvm/BinaryFormat/MachO.h
index 9850ba9c4d1cb..7e38c1342e321 100644
--- a/llvm/include/llvm/BinaryFormat/MachO.h
+++ b/llvm/include/llvm/BinaryFormat/MachO.h
@@ -1015,6 +1015,14 @@ struct dyld_chained_fixups_header {
   uint32_t symbols_format; ///< 0 => uncompressed, 1 => zlib compressed
 };
 
+/// dyld_chained_starts_in_image is embedded in LC_DYLD_CHAINED_FIXUPS payload.
+/// Each each seg_info_offset entry is the offset into this struct for that
+/// segment followed by pool of dyld_chain_starts_in_segment data.
+struct dyld_chained_starts_in_image {
+  uint32_t    seg_count;
+  uint32_t    seg_info_offset[1];
+};
+  
 // Byte order swapping functions for MachO structs
 
 inline void swapStruct(fat_header &mh) {

diff  --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h
index de911c005b53d..c248c9d0dc032 100644
--- a/llvm/include/llvm/Object/MachO.h
+++ b/llvm/include/llvm/Object/MachO.h
@@ -683,6 +683,9 @@ class MachOObjectFile : public ObjectFile {
   ArrayRef<uint8_t> getDyldInfoBindOpcodes() const;
   ArrayRef<uint8_t> getDyldInfoWeakBindOpcodes() const;
   ArrayRef<uint8_t> getDyldInfoLazyBindOpcodes() const;
+  /// If the optional is None, no header was found, but the object was well-formed.
+  Expected<Optional<MachO::dyld_chained_fixups_header>>
+  getChainedFixupsHeader() const;
   Expected<std::vector<ChainedFixupTarget>> getDyldChainedFixupTargets() const;
   ArrayRef<uint8_t> getDyldInfoExportsTrie() const;
   SmallVector<uint64_t> getFunctionStarts() const;

diff  --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp
index 5d6e237c8a99a..a3e051664223b 100644
--- a/llvm/lib/Object/MachOObjectFile.cpp
+++ b/llvm/lib/Object/MachOObjectFile.cpp
@@ -3259,13 +3259,13 @@ MachOChainedFixupEntry::MachOChainedFixupEntry(Error *E,
                                                bool Parse)
     : MachOAbstractFixupEntry(E, O) {
   ErrorAsOutParameter e(E);
-  if (Parse) {
-    if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets())
-      FixupTargets = *FixupTargetsOrErr;
-    else {
-      *E = FixupTargetsOrErr.takeError();
-      return;
-    }
+  if (!Parse)
+    return;
+  if (auto FixupTargetsOrErr = O->getDyldChainedFixupTargets())
+    FixupTargets = *FixupTargetsOrErr;
+  else {
+    *E = FixupTargetsOrErr.takeError();
+    return;
   }
 }
 
@@ -4763,11 +4763,11 @@ ArrayRef<uint8_t> MachOObjectFile::getDyldInfoLazyBindOpcodes() const {
   return makeArrayRef(Ptr, DyldInfo.lazy_bind_size);
 }
 
-Expected<std::vector<ChainedFixupTarget>>
-MachOObjectFile::getDyldChainedFixupTargets() const {
+Expected<Optional<MachO::dyld_chained_fixups_header>>
+MachOObjectFile::getChainedFixupsHeader() const {
   // Load the dyld chained fixups load command.
   if (!DyldChainedFixupsLoadCmd)
-    return std::vector<ChainedFixupTarget>();
+    return llvm::None;
   auto DyldChainedFixupsOrErr = getStructOrErr<MachO::linkedit_data_command>(
       *this, DyldChainedFixupsLoadCmd);
   if (!DyldChainedFixupsOrErr)
@@ -4775,11 +4775,10 @@ MachOObjectFile::getDyldChainedFixupTargets() const {
   MachO::linkedit_data_command DyldChainedFixups = DyldChainedFixupsOrErr.get();
 
   // If the load command is present but the data offset has been zeroed out,
-  // as is the case for dylib stubs, return an empty list of targets.
+  // as is the case for dylib stubs, return None (no error).
   uint64_t CFHeaderOffset = DyldChainedFixups.dataoff;
-  std::vector<ChainedFixupTarget> Targets;
   if (CFHeaderOffset == 0)
-    return Targets;
+    return DyldChainedFixupsOrErr.takeError();
 
   // Load the dyld chained fixups header.
   const char *CFHeaderPtr = getPtr(*this, CFHeaderOffset);
@@ -4798,6 +4797,35 @@ MachOObjectFile::getDyldChainedFixupTargets() const {
         Twine("bad chained fixups: unknown imports format: ") +
         Twine(CFHeader.imports_format));
 
+  // Validate the image format.
+  //
+  // Load the image starts.
+  uint64_t CFImageStartsOffset = (CFHeaderOffset + CFHeader.starts_offset);
+  if (CFHeader.starts_offset < sizeof(MachO::dyld_chained_fixups_header)) {
+    return malformedError(Twine("bad chained fixups: image starts offset ") +
+                          Twine(CFHeader.starts_offset) +
+                          " overlaps with chained fixups header");
+  }
+  uint32_t EndOffset = DyldChainedFixups.dataoff + DyldChainedFixups.datasize;
+  if (CFImageStartsOffset + sizeof(MachO::dyld_chained_starts_in_image) >
+      EndOffset) {
+    return malformedError(Twine("bad chained fixups: image starts end ") +
+                          Twine(CFImageStartsOffset +
+                                sizeof(MachO::dyld_chained_starts_in_image)) +
+                          " extends past end " + Twine(EndOffset));
+  }
+
+  return CFHeader;
+}
+
+Expected<std::vector<ChainedFixupTarget>>
+MachOObjectFile::getDyldChainedFixupTargets() const {
+  auto CFHeaderOrErr = getChainedFixupsHeader();
+  if (!CFHeaderOrErr)
+    return CFHeaderOrErr.takeError();
+  std::vector<ChainedFixupTarget> Targets;
+  if (!(*CFHeaderOrErr))
+    return Targets;
   return Targets;
 }
 

diff  --git a/llvm/test/Object/AArch64/chained-fixups-header.test b/llvm/test/Object/AArch64/chained-fixups-header.test
index 9a97a719aa8f8..9eebd15384d21 100644
--- a/llvm/test/Object/AArch64/chained-fixups-header.test
+++ b/llvm/test/Object/AArch64/chained-fixups-header.test
@@ -10,3 +10,15 @@ RUN:   | sed 's/1000000010000000/1000000AB0000000/' \
 RUN:   | yaml2obj | not llvm-objdump --macho --dyld_info - 2>&1 \
 RUN:   | FileCheck %s --check-prefix=HEADER2
 HEADER2: truncated or malformed object (bad chained fixups: unknown imports format: 171)
+
+RUN: cat %p/../Inputs/MachO/chained-fixups.yaml \
+RUN:   | sed 's/20000000/01000000/' \
+RUN:   | yaml2obj | not llvm-objdump --macho --dyld_info - 2>&1 \
+RUN:   | FileCheck %s --check-prefix=HEADER3
+HEADER3: truncated or malformed object (bad chained fixups: image starts offset 1 overlaps with chained fixups header)
+
+RUN: cat %p/../Inputs/MachO/chained-fixups.yaml \
+RUN:   | sed 's/20000000/FF000000/' \
+RUN:   | yaml2obj | not llvm-objdump --macho --dyld_info - 2>&1 \
+RUN:   | FileCheck %s --check-prefix=HEADER4
+HEADER4: truncated or malformed object (bad chained fixups: image starts end 33031 extends past end 32856)


        


More information about the llvm-commits mailing list