[llvm] r285632 - More additional error checks for invalid Mach-O files when

Kevin Enderby via llvm-commits llvm-commits at lists.llvm.org
Mon Oct 31 13:29:48 PDT 2016


Author: enderby
Date: Mon Oct 31 15:29:48 2016
New Revision: 285632

URL: http://llvm.org/viewvc/llvm-project?rev=285632&view=rev
Log:
More additional error checks for invalid Mach-O files when
the offsets and sizes of an element of the file overlaps with
another element in the Mach-O file.

This shows the approach to this testing for three elements
and contains for tests for their overlap.  Checking for all the
remain elements will be added next.

Added:
    llvm/trunk/test/Object/Inputs/macho-invalid-strtab-overlap   (with props)
    llvm/trunk/test/Object/Inputs/macho-invalid-symtab-overlap   (with props)
Modified:
    llvm/trunk/lib/Object/MachOObjectFile.cpp
    llvm/trunk/test/Object/macho-invalid.test

Modified: llvm/trunk/lib/Object/MachOObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/MachOObjectFile.cpp?rev=285632&r1=285631&r2=285632&view=diff
==============================================================================
--- llvm/trunk/lib/Object/MachOObjectFile.cpp (original)
+++ llvm/trunk/lib/Object/MachOObjectFile.cpp Mon Oct 31 15:29:48 2016
@@ -27,6 +27,7 @@
 #include <cctype>
 #include <cstring>
 #include <limits>
+#include <list>
 
 using namespace llvm;
 using namespace object;
@@ -216,6 +217,42 @@ static void parseHeader(const MachOObjec
     Err = HeaderOrErr.takeError();
 }
 
+// This is used to check for overlapping of Mach-O elements.
+struct MachOElement {
+  uint64_t Offset;
+  uint64_t Size;
+  const char *Name;
+};
+
+static Error checkOverlappingElement(std::list<MachOElement> &Elements,
+                                     uint64_t Offset, uint64_t Size,
+                                     const char *Name) {
+  if (Size == 0)
+    return Error::success();
+
+  for (auto it=Elements.begin() ; it != Elements.end(); ++it) {
+    auto E = *it;
+    if ((Offset >= E.Offset && Offset < E.Offset + E.Size) ||
+        (Offset + Size > E.Offset && Offset + Size < E.Offset + E.Size) ||
+        (Offset <= E.Offset && Offset + Size >= E.Offset + E.Size))
+      return malformedError(Twine(Name) + " at offset " + Twine(Offset) +
+                            " with a size of " + Twine(Size) + ", overlaps " +
+                            E.Name + " at offset " + Twine(E.Offset) + " with "
+                            "a size of " + Twine(E.Size));
+    auto nt = it;
+    nt++;
+    if (nt != Elements.end()) {
+      auto N = *nt;
+      if (Offset + Size <= N.Offset) {
+        Elements.insert(nt, {Offset, Size, Name});
+        return Error::success();
+      }
+    }
+  }
+  Elements.push_back({Offset, Size, Name});
+  return Error::success();
+}
+
 // Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all
 // sections to \param Sections, and optionally sets
 // \param IsPageZeroSegment to true.
@@ -331,7 +368,8 @@ static Error parseSegmentLoadCommand(
 static Error checkSymtabCommand(const MachOObjectFile *Obj,
                                 const MachOObjectFile::LoadCommandInfo &Load,
                                 uint32_t LoadCommandIndex,
-                                const char **SymtabLoadCmd) {
+                                const char **SymtabLoadCmd,
+                                std::list<MachOElement> &Elements) {
   if (Load.C.cmdsize < sizeof(MachO::symtab_command))
     return malformedError("load command " + Twine(LoadCommandIndex) +
                           " LC_SYMTAB cmdsize too small");
@@ -347,21 +385,25 @@ static Error checkSymtabCommand(const Ma
     return malformedError("symoff field of LC_SYMTAB command " +
                           Twine(LoadCommandIndex) + " extends past the end "
                           "of the file");
-  uint64_t BigSize = Symtab.nsyms;
+  uint64_t SymtabSize = Symtab.nsyms;
   const char *struct_nlist_name;
   if (Obj->is64Bit()) {
-    BigSize *= sizeof(MachO::nlist_64);
+    SymtabSize *= sizeof(MachO::nlist_64);
     struct_nlist_name = "struct nlist_64";
   } else {
-    BigSize *= sizeof(MachO::nlist);
+    SymtabSize *= sizeof(MachO::nlist);
     struct_nlist_name = "struct nlist";
   }
+  uint64_t BigSize = SymtabSize;
   BigSize += Symtab.symoff;
   if (BigSize > FileSize)
     return malformedError("symoff field plus nsyms field times sizeof(" +
                           Twine(struct_nlist_name) + ") of LC_SYMTAB command " +
                           Twine(LoadCommandIndex) + " extends past the end "
                           "of the file");
+  if (Error Err = checkOverlappingElement(Elements, Symtab.symoff, SymtabSize,
+                                          "symbol table"))
+    return Err;
   if (Symtab.stroff > FileSize)
     return malformedError("stroff field of LC_SYMTAB command " +
                           Twine(LoadCommandIndex) + " extends past the end "
@@ -372,6 +414,9 @@ static Error checkSymtabCommand(const Ma
     return malformedError("stroff field plus strsize field of LC_SYMTAB "
                           "command " + Twine(LoadCommandIndex) + " extends "
                           "past the end of the file");
+  if (Error Err = checkOverlappingElement(Elements, Symtab.stroff,
+                                          Symtab.strsize, "string table"))
+    return Err;
   *SymtabLoadCmd = Load.Ptr;
   return Error::success();
 }
@@ -977,6 +1022,8 @@ MachOObjectFile::MachOObjectFile(MemoryB
                          "object file's mach header");
     return;
   }
+  std::list<MachOElement> Elements;
+  Elements.push_back({0, SizeOfHeaders, "Mach-O headers"});
 
   uint32_t LoadCommandCount = getHeader().ncmds;
   LoadCommandInfo Load;
@@ -1023,7 +1070,7 @@ MachOObjectFile::MachOObjectFile(MemoryB
     }
     LoadCommands.push_back(Load);
     if (Load.C.cmd == MachO::LC_SYMTAB) {
-      if ((Err = checkSymtabCommand(this, Load, I, &SymtabLoadCmd)))
+      if ((Err = checkSymtabCommand(this, Load, I, &SymtabLoadCmd, Elements)))
         return;
     } else if (Load.C.cmd == MachO::LC_DYSYMTAB) {
       if ((Err = checkDysymtabCommand(this, Load, I, &DysymtabLoadCmd)))

Added: llvm/trunk/test/Object/Inputs/macho-invalid-strtab-overlap
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-strtab-overlap?rev=285632&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/Object/Inputs/macho-invalid-strtab-overlap
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/Object/Inputs/macho-invalid-symtab-overlap
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-symtab-overlap?rev=285632&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/Object/Inputs/macho-invalid-symtab-overlap
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Modified: llvm/trunk/test/Object/macho-invalid.test
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/macho-invalid.test?rev=285632&r1=285631&r2=285632&view=diff
==============================================================================
--- llvm/trunk/test/Object/macho-invalid.test (original)
+++ llvm/trunk/test/Object/macho-invalid.test Mon Oct 31 15:29:48 2016
@@ -433,3 +433,9 @@ INVALID-FVMFILE-OBSOLETE: macho-invalid-
 
 RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-prepage-obsolete 2>&1 | FileCheck -check-prefix INVALID-PREPAGE-OBSOLETE %s
 INVALID-PREPAGE-OBSOLETE: macho-invalid-prepage-obsolete': truncated or malformed object (load command 0 for cmd value of: 10 is obsolete and not supported)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-symtab-overlap 2>&1 | FileCheck -check-prefix INVALID-SYMTAB-OVERLAP %s
+INVALID-SYMTAB-OVERLAP: macho-invalid-symtab-overlap': truncated or malformed object (symbol table at offset 8 with a size of 12, overlaps Mach-O headers at offset 0 with a size of 52)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-strtab-overlap 2>&1 | FileCheck -check-prefix INVALID-STRTAB-OVERLAP %s
+INVALID-STRTAB-OVERLAP: macho-invalid-strtab-overlap': truncated or malformed object (string table at offset 60 with a size of 16, overlaps symbol table at offset 52 with a size of 12)




More information about the llvm-commits mailing list