[llvm] r226219 - Report fatal errors instead of segfaulting/asserting on a few invalid accesses while reading MachO files.

Filipe Cabecinhas me at filcab.net
Thu Jan 15 14:52:38 PST 2015


Author: filcab
Date: Thu Jan 15 16:52:38 2015
New Revision: 226219

URL: http://llvm.org/viewvc/llvm-project?rev=226219&view=rev
Log:
Report fatal errors instead of segfaulting/asserting on a few invalid accesses while reading MachO files.

Summary:
Shift an older “invalid file” test to get a consistent naming for these tests.

Bugs found by afl-fuzz

Reviewers: rafael

Subscribers: llvm-commits

Differential Revision: http://reviews.llvm.org/D6945

Added:
    llvm/trunk/test/Object/Inputs/macho-invalid-bad-symbol-index
    llvm/trunk/test/Object/Inputs/macho-invalid-getsection-index
    llvm/trunk/test/Object/Inputs/macho-invalid-no-size-for-sections
    llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName
    llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawName
    llvm/trunk/test/Object/Inputs/macho-invalid-symbol-name-past-eof
    llvm/trunk/test/Object/Inputs/macho-invalid-too-small-load-command
    llvm/trunk/test/Object/Inputs/macho-invalid-too-small-segment-load-command
    llvm/trunk/test/Object/Inputs/macho-invalid-zero-ncmds
      - copied, changed from r226217, llvm/trunk/test/Object/Inputs/macho-zero-ncmds
    llvm/trunk/test/Object/Inputs/macho64-invalid-getsection-index
    llvm/trunk/test/Object/Inputs/macho64-invalid-incomplete-load-command
    llvm/trunk/test/Object/Inputs/macho64-invalid-no-size-for-sections
    llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-load-command
    llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-segment-load-command
    llvm/trunk/test/Object/macho-invalid.test
Removed:
    llvm/trunk/test/Object/Inputs/macho-zero-ncmds
    llvm/trunk/test/Object/objdump-macho-quirks.test
Modified:
    llvm/trunk/lib/Object/MachOObjectFile.cpp

Modified: llvm/trunk/lib/Object/MachOObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/MachOObjectFile.cpp?rev=226219&r1=226218&r2=226219&view=diff
==============================================================================
--- llvm/trunk/lib/Object/MachOObjectFile.cpp (original)
+++ llvm/trunk/lib/Object/MachOObjectFile.cpp Thu Jan 15 16:52:38 2015
@@ -38,8 +38,12 @@ namespace {
   };
 }
 
-template<typename T>
+template <typename T>
 static T getStruct(const MachOObjectFile *O, const char *P) {
+  // Don't read before the beginning or past the end of the file
+  if (P < O->getData().begin() || P + sizeof(T) > O->getData().end())
+    report_fatal_error("Malformed MachO file.");
+
   T Cmd;
   memcpy(&Cmd, P, sizeof(T));
   if (O->isLittleEndian() != sys::IsLittleEndianHost)
@@ -47,15 +51,26 @@ static T getStruct(const MachOObjectFile
   return Cmd;
 }
 
+template <typename SegmentCmd>
+static uint32_t getSegmentLoadCommandNumSections(const SegmentCmd &S,
+                                                 uint32_t Cmdsize) {
+  const unsigned SectionSize = sizeof(SegmentCmd);
+  if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize ||
+      S.nsects * SectionSize > Cmdsize - sizeof(S))
+    report_fatal_error(
+        "Number of sections too large for size of load command.");
+  return S.nsects;
+}
+
 static uint32_t
 getSegmentLoadCommandNumSections(const MachOObjectFile *O,
                                  const MachOObjectFile::LoadCommandInfo &L) {
-  if (O->is64Bit()) {
-    MachO::segment_command_64 S = O->getSegment64LoadCommand(L);
-    return S.nsects;
-  }
-  MachO::segment_command S = O->getSegmentLoadCommand(L);
-  return S.nsects;
+  if (O->is64Bit())
+    return getSegmentLoadCommandNumSections(O->getSegment64LoadCommand(L),
+                                            L.C.cmdsize);
+
+  return getSegmentLoadCommandNumSections(O->getSegmentLoadCommand(L),
+                                          L.C.cmdsize);
 }
 
 static bool isPageZeroSegment(const MachOObjectFile *O,
@@ -281,6 +296,12 @@ MachOObjectFile::MachOObjectFile(MemoryB
       }
       UuidLoadCmd = Load.Ptr;
     } else if (Load.C.cmd == SegmentLoadType) {
+      const unsigned SegmentLoadSize = this->is64Bit()
+                                           ? sizeof(MachO::segment_command_64)
+                                           : sizeof(MachO::segment_command);
+      if (Load.C.cmdsize < SegmentLoadSize)
+        report_fatal_error("Segment load command size is too small.");
+
       uint32_t NumSections = getSegmentLoadCommandNumSections(this, Load);
       for (unsigned J = 0; J < NumSections; ++J) {
         const char *Sec = getSectionPtr(this, Load, J);
@@ -315,6 +336,8 @@ std::error_code MachOObjectFile::getSymb
   StringRef StringTable = getStringTableData();
   MachO::nlist_base Entry = getSymbolTableEntryBase(this, Symb);
   const char *Start = &StringTable.data()[Entry.n_strx];
+  if (Start >= getData().end())
+    report_fatal_error("Symbol name entry points past end of file.");
   Res = StringRef(Start);
   return object_error::success;
 }
@@ -1204,7 +1227,8 @@ basic_symbol_iterator MachOObjectFile::g
     return basic_symbol_iterator(SymbolRef(DRI, this));
 
   MachO::symtab_command Symtab = getSymtabLoadCommand();
-  assert(Index < Symtab.nsyms && "Requested symbol index is out of range.");
+  if (Index >= Symtab.nsyms)
+    report_fatal_error("Requested symbol index is out of range.");
   unsigned SymbolTableEntrySize =
     is64Bit() ? sizeof(MachO::nlist_64) : sizeof(MachO::nlist);
   DRI.p = reinterpret_cast<uintptr_t>(getPtr(this, Symtab.symoff));
@@ -2108,6 +2132,8 @@ MachOObjectFile::getSectionFinalSegmentN
 
 ArrayRef<char>
 MachOObjectFile::getSectionRawName(DataRefImpl Sec) const {
+  if (Sec.d.a >= Sections.size())
+    report_fatal_error("getSectionRawName: Invalid section index");
   const section_base *Base =
     reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
   return makeArrayRef(Base->sectname);
@@ -2115,6 +2141,8 @@ MachOObjectFile::getSectionRawName(DataR
 
 ArrayRef<char>
 MachOObjectFile::getSectionRawFinalSegmentName(DataRefImpl Sec) const {
+  if (Sec.d.a >= Sections.size())
+    report_fatal_error("getSectionRawFinalSegmentName: Invalid section index");
   const section_base *Base =
     reinterpret_cast<const section_base *>(Sections[Sec.d.a]);
   return makeArrayRef(Base->segname);
@@ -2205,6 +2233,8 @@ MachOObjectFile::getFirstLoadCommandInfo
                                     sizeof(MachO::mach_header);
   Load.Ptr = getPtr(this, HeaderSize);
   Load.C = getStruct<MachO::load_command>(this, Load.Ptr);
+  if (Load.C.cmdsize < 8)
+    report_fatal_error("Load command with size < 8 bytes.");
   return Load;
 }
 
@@ -2213,14 +2243,22 @@ MachOObjectFile::getNextLoadCommandInfo(
   MachOObjectFile::LoadCommandInfo Next;
   Next.Ptr = L.Ptr + L.C.cmdsize;
   Next.C = getStruct<MachO::load_command>(this, Next.Ptr);
+  if (Next.C.cmdsize < 8)
+    report_fatal_error("Load command with size < 8 bytes.");
   return Next;
 }
 
 MachO::section MachOObjectFile::getSection(DataRefImpl DRI) const {
+  // TODO: What if Sections.size() == 0?
+  if (DRI.d.a >= Sections.size())
+    report_fatal_error("getSection: Invalid section index.");
   return getStruct<MachO::section>(this, Sections[DRI.d.a]);
 }
 
 MachO::section_64 MachOObjectFile::getSection64(DataRefImpl DRI) const {
+  // TODO: What if Sections.size() == 0?
+  if (DRI.d.a >= Sections.size())
+    report_fatal_error("getSection64: Invalid section index.");
   return getStruct<MachO::section_64>(this, Sections[DRI.d.a]);
 }
 

Added: llvm/trunk/test/Object/Inputs/macho-invalid-bad-symbol-index
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-bad-symbol-index?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-invalid-bad-symbol-index (added) and llvm/trunk/test/Object/Inputs/macho-invalid-bad-symbol-index Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho-invalid-getsection-index
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-getsection-index?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-invalid-getsection-index (added) and llvm/trunk/test/Object/Inputs/macho-invalid-getsection-index Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho-invalid-no-size-for-sections
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-no-size-for-sections?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-invalid-no-size-for-sections (added) and llvm/trunk/test/Object/Inputs/macho-invalid-no-size-for-sections Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName (added) and llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawName
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawName?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawName (added) and llvm/trunk/test/Object/Inputs/macho-invalid-section-index-getSectionRawName Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho-invalid-symbol-name-past-eof
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-symbol-name-past-eof?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-invalid-symbol-name-past-eof (added) and llvm/trunk/test/Object/Inputs/macho-invalid-symbol-name-past-eof Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho-invalid-too-small-load-command
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-too-small-load-command?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-invalid-too-small-load-command (added) and llvm/trunk/test/Object/Inputs/macho-invalid-too-small-load-command Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho-invalid-too-small-segment-load-command
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-too-small-segment-load-command?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-invalid-too-small-segment-load-command (added) and llvm/trunk/test/Object/Inputs/macho-invalid-too-small-segment-load-command Thu Jan 15 16:52:38 2015 differ

Copied: llvm/trunk/test/Object/Inputs/macho-invalid-zero-ncmds (from r226217, llvm/trunk/test/Object/Inputs/macho-zero-ncmds)
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-zero-ncmds?p2=llvm/trunk/test/Object/Inputs/macho-invalid-zero-ncmds&p1=llvm/trunk/test/Object/Inputs/macho-zero-ncmds&r1=226217&r2=226219&rev=226219&view=diff
==============================================================================
    (empty)

Removed: llvm/trunk/test/Object/Inputs/macho-zero-ncmds
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-zero-ncmds?rev=226218&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho-zero-ncmds (original) and llvm/trunk/test/Object/Inputs/macho-zero-ncmds (removed) differ

Added: llvm/trunk/test/Object/Inputs/macho64-invalid-getsection-index
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho64-invalid-getsection-index?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho64-invalid-getsection-index (added) and llvm/trunk/test/Object/Inputs/macho64-invalid-getsection-index Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho64-invalid-incomplete-load-command
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho64-invalid-incomplete-load-command?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho64-invalid-incomplete-load-command (added) and llvm/trunk/test/Object/Inputs/macho64-invalid-incomplete-load-command Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho64-invalid-no-size-for-sections
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho64-invalid-no-size-for-sections?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho64-invalid-no-size-for-sections (added) and llvm/trunk/test/Object/Inputs/macho64-invalid-no-size-for-sections Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-load-command
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-load-command?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-load-command (added) and llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-load-command Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-segment-load-command
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-segment-load-command?rev=226219&view=auto
==============================================================================
Binary files llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-segment-load-command (added) and llvm/trunk/test/Object/Inputs/macho64-invalid-too-small-segment-load-command Thu Jan 15 16:52:38 2015 differ

Added: llvm/trunk/test/Object/macho-invalid.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/macho-invalid.test?rev=226219&view=auto
==============================================================================
--- llvm/trunk/test/Object/macho-invalid.test (added)
+++ llvm/trunk/test/Object/macho-invalid.test Thu Jan 15 16:52:38 2015
@@ -0,0 +1,51 @@
+// No crash, might not be totally invalid
+RUN: llvm-objdump -private-headers %p/Inputs/macho-invalid-zero-ncmds
+
+RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-incomplete-load-command 2>&1 \
+RUN:      | FileCheck -check-prefix INCOMPLETE-LOADC %s
+
+RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-load-command 2>&1 \
+RUN:      | FileCheck -check-prefix SMALL-LOADC-SIZE %s
+RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-too-small-load-command 2>&1 \
+RUN:      | FileCheck -check-prefix SMALL-LOADC-SIZE %s
+
+RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-segment-load-command 2>&1 \
+RUN:      | FileCheck -check-prefix SMALL-SEGLOADC-SIZE %s
+RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-too-small-segment-load-command 2>&1 \
+RUN:      | FileCheck -check-prefix SMALL-SEGLOADC-SIZE %s
+
+RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-no-size-for-sections 2>&1 \
+RUN:      | FileCheck -check-prefix TOO-MANY-SECTS %s
+RUN: not llvm-objdump -private-headers %p/Inputs/macho64-invalid-no-size-for-sections 2>&1 \
+RUN:      | FileCheck -check-prefix TOO-MANY-SECTS %s
+
+RUN: not llvm-objdump -t %p/Inputs/macho-invalid-bad-symbol-index 2>&1 \
+RUN:      | FileCheck -check-prefix BAD-SYMBOL %s
+
+RUN: not llvm-objdump -t %p/Inputs/macho-invalid-symbol-name-past-eof 2>&1 \
+RUN:      | FileCheck -check-prefix NAME-PAST-EOF %s
+
+RUN: not llvm-objdump -t %p/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName 2>&1 \
+RUN:      | FileCheck -check-prefix INVALID-SECTION-IDX-SEG-NAME %s
+
+RUN: not llvm-nm %p/Inputs/macho-invalid-section-index-getSectionRawName 2>&1 \
+RUN:      | FileCheck -check-prefix INVALID-SECTION-IDX-SECT-NAME %s
+
+RUN: not llvm-objdump -t %p/Inputs/macho-invalid-getsection-index 2>&1 \
+RUN:      | FileCheck -check-prefix INVALID-SECTION-IDX-GETSECT %s
+
+RUN: not llvm-objdump -t %p/Inputs/macho64-invalid-getsection-index 2>&1 \
+RUN:      | FileCheck -check-prefix INVALID-SECTION-IDX-GETSECT64 %s
+
+
+SMALL-LOADC-SIZE: Load command with size < 8 bytes
+SMALL-SEGLOADC-SIZE: Segment load command size is too small
+INCOMPLETE-LOADC: Malformed MachO file
+TOO-MANY-SECTS: Number of sections too large for size of load command
+BAD-SYMBOL: Requested symbol index is out of range
+NAME-PAST-EOF: Symbol name entry points past end of file
+
+INVALID-SECTION-IDX-SEG-NAME: getSectionRawFinalSegmentName: Invalid section index
+INVALID-SECTION-IDX-SECT-NAME: getSectionRawName: Invalid section index
+INVALID-SECTION-IDX-GETSECT: getSection: Invalid section index
+INVALID-SECTION-IDX-GETSECT64: getSection64: Invalid section index

Removed: llvm/trunk/test/Object/objdump-macho-quirks.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/objdump-macho-quirks.test?rev=226218&view=auto
==============================================================================
--- llvm/trunk/test/Object/objdump-macho-quirks.test (original)
+++ llvm/trunk/test/Object/objdump-macho-quirks.test (removed)
@@ -1,9 +0,0 @@
-RUN: llvm-objdump -private-headers %p/Inputs/macho-zero-ncmds \
-RUN:         | FileCheck %s -check-prefix A
-
-// Check that we don't get an infinite loop if ncmds = 0
-A: file format Mach-O 64-bit unknown
-A: Mach header
-A:      magic cputype cpusubtype  caps    filetype ncmds sizeofcmds      flags
-A: MH_MAGIC_64  0x00      OBJECT     0          0 0x00000000
-






More information about the llvm-commits mailing list