[Object, MachO] Don't crash on invalid MachO segment load commands.
authorAlexey Samsonov <vonosmas@gmail.com>
Thu, 4 Jun 2015 20:08:52 +0000 (20:08 +0000)
committerAlexey Samsonov <vonosmas@gmail.com>
Thu, 4 Jun 2015 20:08:52 +0000 (20:08 +0000)
Summary:
Properly report the error in segment load commands from MachOObjectFile
constructor instead of crashing the program.

Adjust the test case accordingly.

Test Plan: regression test suite

Reviewers: rafael, filcab

Subscribers: llvm-commits

git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@239081 91177308-0d34-0410-b5e6-96231b3b80d8

include/llvm/Object/Error.h
lib/Object/Error.cpp
lib/Object/MachOObjectFile.cpp
test/Object/macho-invalid.test

index 13a14aa09c77604d1f921d5883913410173798c2..fe4372d4d96d1c1c9f2be02a5b418bb24d9627d5 100644 (file)
@@ -29,6 +29,8 @@ enum class object_error {
   unexpected_eof,
   bitcode_section_not_found,
   macho_small_load_command,
+  macho_load_segment_too_many_sections,
+  macho_load_segment_too_small,
 };
 
 inline std::error_code make_error_code(object_error e) {
index 1c8dad80b0a6db7c60cec7815238072099560e3f..5e4e237f4b0b13bad1395272e0b23cad3c0f4121 100644 (file)
@@ -46,6 +46,10 @@ std::string _object_error_category::message(int EV) const {
     return "Bitcode section not found in object file";
   case object_error::macho_small_load_command:
     return "Mach-O load command with size < 8 bytes";
+  case object_error::macho_load_segment_too_many_sections:
+    return "Mach-O segment load command contains too many sections";
+  case object_error::macho_load_segment_too_small:
+    return "Mach-O segment load command size is too small";
   }
   llvm_unreachable("An enumerator of object_error does not have a message "
                    "defined.");
index 3262c6c26ab9ac60251b473a95ce5a12c16ea1ad..62514d2ec9ace131c4aeb2729f785650d9ba3321 100644 (file)
@@ -66,17 +66,16 @@ static ErrorOr<T> getStructOrErr(const MachOObjectFile *O, const char *P) {
 }
 
 template <typename SegmentCmd>
-static uint32_t getSegmentLoadCommandNumSections(const SegmentCmd &S,
-                                                 uint32_t Cmdsize) {
+static ErrorOr<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 object_error::macho_load_segment_too_many_sections;
   return S.nsects;
 }
 
-static uint32_t
+static ErrorOr<uint32_t>
 getSegmentLoadCommandNumSections(const MachOObjectFile *O,
                                  const MachOObjectFile::LoadCommandInfo &L) {
   if (O->is64Bit())
@@ -306,14 +305,19 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian,
       }
       UuidLoadCmd = Load.Ptr;
     } else if (Load.C.cmd == SegmentLoadType) {
-      const unsigned SegmentLoadSize = this->is64Bit()
+      const unsigned SegmentLoadSize = 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) {
+      if (Load.C.cmdsize < SegmentLoadSize) {
+        EC = object_error::macho_load_segment_too_small;
+        return;
+      }
+      auto NumSectionsOrErr = getSegmentLoadCommandNumSections(this, Load);
+      if (!NumSectionsOrErr) {
+        EC = NumSectionsOrErr.getError();
+        return;
+      }
+      for (unsigned J = 0; J < NumSectionsOrErr.get(); ++J) {
         const char *Sec = getSectionPtr(this, Load, J);
         Sections.push_back(Sec);
       }
index 55b186dedd30a4a3ba4e6a59ea21c4d67abb064c..8bc11508dd59c2a91b03a66e98ebb6337c69b151 100644 (file)
@@ -15,13 +15,13 @@ RUN: not llvm-objdump -private-headers %p/Inputs/macho-invalid-too-small-segment
 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
-SMALL-SEGLOADC-SIZE: Segment load command size is too small
+SMALL-SEGLOADC-SIZE: Mach-O segment load command size is too small
 
 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
-TOO-MANY-SECTS: Number of sections too large for size of load command
+TOO-MANY-SECTS: Mach-O segment load command contains too many sections
 
 RUN: not llvm-objdump -t %p/Inputs/macho-invalid-bad-symbol-index 2>&1 \
 RUN:      | FileCheck -check-prefix BAD-SYMBOL %s