[llvm] r284668 - Next set of additional error checks for invalid Mach-O files for the

Kevin Enderby via llvm-commits llvm-commits at lists.llvm.org
Wed Oct 19 16:44:34 PDT 2016


Author: enderby
Date: Wed Oct 19 18:44:34 2016
New Revision: 284668

URL: http://llvm.org/viewvc/llvm-project?rev=284668&view=rev
Log:
Next set of additional error checks for invalid Mach-O files for the
load commands that use the MachO::thread_command type
but are not used in llvm libObject code but used in llvm tool code.

This includes the LC_UNIXTHREAD and LC_THREAD
load commands.

A quick note about the philosophy of the error checking in
libObject for Mach-O files, the idea behind the checking is
that we never will return a Mach-O file out of libObject that
contains unknown things in the load commands.

To do this the 32-bit ARM and PPC general tread states
needed to be defined as two test case binaries contained
them.  If other thread states for other CPUs need to be
added we will do that as needed.

Going forward the LC_MAIN load command is used to
set the entry point in Mach-O executables these days
instead of an LC_UNIXTHREAD as was done in the past.
So today only in core files are LC_THREAD load commands
and thread states usually found.

Other thread states have not yet been defined in
include/Support/MachO.h at this time.  But that can be
added as needed with their corresponding checking also
added.

Added:
    llvm/trunk/test/Object/Inputs/macho-invalid-thread-count-pastend   (with props)
    llvm/trunk/test/Object/Inputs/macho-invalid-thread-count-wrong   (with props)
    llvm/trunk/test/Object/Inputs/macho-invalid-thread-flavor-unknown   (with props)
    llvm/trunk/test/Object/Inputs/macho-invalid-thread-state-pastend   (with props)
    llvm/trunk/test/Object/Inputs/macho-invalid-thread-unknown-cputype   (with props)
    llvm/trunk/test/Object/Inputs/macho-invalid-unixthread-more-than-one   (with props)
Modified:
    llvm/trunk/include/llvm/Support/MachO.h
    llvm/trunk/lib/Object/MachOObjectFile.cpp
    llvm/trunk/test/Object/macho-invalid.test

Modified: llvm/trunk/include/llvm/Support/MachO.h
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/include/llvm/Support/MachO.h?rev=284668&r1=284667&r2=284668&view=diff
==============================================================================
--- llvm/trunk/include/llvm/Support/MachO.h (original)
+++ llvm/trunk/include/llvm/Support/MachO.h Wed Oct 19 18:44:34 2016
@@ -1710,6 +1710,181 @@ namespace llvm {
     const uint32_t x86_EXCEPTION_STATE_COUNT =
       sizeof(x86_exception_state_t) / sizeof(uint32_t);
 
+    struct arm_thread_state32_t {
+      uint32_t r[13];
+      uint32_t sp;
+      uint32_t lr;
+      uint32_t pc;
+      uint32_t cpsr;
+    };
+
+    inline void swapStruct(arm_thread_state32_t &x) {
+      for (int i = 0; i < 13; i++)
+        sys::swapByteOrder(x.r[i]);
+      sys::swapByteOrder(x.sp);
+      sys::swapByteOrder(x.lr);
+      sys::swapByteOrder(x.pc);
+      sys::swapByteOrder(x.cpsr);
+    }
+
+    struct arm_state_hdr_t {
+      uint32_t flavor;
+      uint32_t count;
+    };
+
+    struct arm_thread_state_t {
+      arm_state_hdr_t tsh;
+      union {
+        arm_thread_state32_t ts32;
+      } uts;
+    };
+
+    inline void swapStruct(arm_state_hdr_t &x) {
+      sys::swapByteOrder(x.flavor);
+      sys::swapByteOrder(x.count);
+    }
+
+    enum ARMThreadFlavors {
+      ARM_THREAD_STATE      = 1,
+      ARM_VFP_STATE         = 2,
+      ARM_EXCEPTION_STATE   = 3,
+      ARM_DEBUG_STATE       = 4,
+      ARN_THREAD_STATE_NONE = 5,
+      ARM_THREAD_STATE64    = 6,
+      ARM_EXCEPTION_STATE64 = 7
+    };
+
+    inline void swapStruct(arm_thread_state_t &x) {
+      swapStruct(x.tsh);
+      if (x.tsh.flavor == ARM_THREAD_STATE)
+        swapStruct(x.uts.ts32);
+    }
+
+    const uint32_t ARM_THREAD_STATE_COUNT =
+      sizeof(arm_thread_state32_t) / sizeof(uint32_t);
+
+    struct ppc_thread_state32_t {
+      uint32_t srr0;
+      uint32_t srr1;
+      uint32_t r0;
+      uint32_t r1;
+      uint32_t r2;
+      uint32_t r3;
+      uint32_t r4;
+      uint32_t r5;
+      uint32_t r6;
+      uint32_t r7;
+      uint32_t r8;
+      uint32_t r9;
+      uint32_t r10;
+      uint32_t r11;
+      uint32_t r12;
+      uint32_t r13;
+      uint32_t r14;
+      uint32_t r15;
+      uint32_t r16;
+      uint32_t r17;
+      uint32_t r18;
+      uint32_t r19;
+      uint32_t r20;
+      uint32_t r21;
+      uint32_t r22;
+      uint32_t r23;
+      uint32_t r24;
+      uint32_t r25;
+      uint32_t r26;
+      uint32_t r27;
+      uint32_t r28;
+      uint32_t r29;
+      uint32_t r30;
+      uint32_t r31;
+      uint32_t ct;
+      uint32_t xer;
+      uint32_t lr;
+      uint32_t ctr;
+      uint32_t mq;
+      uint32_t vrsave;
+    };
+
+    inline void swapStruct(ppc_thread_state32_t &x) {
+      sys::swapByteOrder(x.srr0);
+      sys::swapByteOrder(x.srr1);
+      sys::swapByteOrder(x.r0);
+      sys::swapByteOrder(x.r1);
+      sys::swapByteOrder(x.r2);
+      sys::swapByteOrder(x.r3);
+      sys::swapByteOrder(x.r4);
+      sys::swapByteOrder(x.r5);
+      sys::swapByteOrder(x.r6);
+      sys::swapByteOrder(x.r7);
+      sys::swapByteOrder(x.r8);
+      sys::swapByteOrder(x.r9);
+      sys::swapByteOrder(x.r10);
+      sys::swapByteOrder(x.r11);
+      sys::swapByteOrder(x.r12);
+      sys::swapByteOrder(x.r13);
+      sys::swapByteOrder(x.r14);
+      sys::swapByteOrder(x.r15);
+      sys::swapByteOrder(x.r16);
+      sys::swapByteOrder(x.r17);
+      sys::swapByteOrder(x.r18);
+      sys::swapByteOrder(x.r19);
+      sys::swapByteOrder(x.r20);
+      sys::swapByteOrder(x.r21);
+      sys::swapByteOrder(x.r22);
+      sys::swapByteOrder(x.r23);
+      sys::swapByteOrder(x.r24);
+      sys::swapByteOrder(x.r25);
+      sys::swapByteOrder(x.r26);
+      sys::swapByteOrder(x.r27);
+      sys::swapByteOrder(x.r28);
+      sys::swapByteOrder(x.r29);
+      sys::swapByteOrder(x.r30);
+      sys::swapByteOrder(x.r31);
+      sys::swapByteOrder(x.ct);
+      sys::swapByteOrder(x.xer);
+      sys::swapByteOrder(x.lr);
+      sys::swapByteOrder(x.ctr);
+      sys::swapByteOrder(x.mq);
+      sys::swapByteOrder(x.vrsave);
+    }
+
+    struct ppc_state_hdr_t {
+      uint32_t flavor;
+      uint32_t count;
+    };
+
+    struct ppc_thread_state_t {
+      ppc_state_hdr_t tsh;
+      union {
+        ppc_thread_state32_t ts32;
+      } uts;
+    };
+
+    inline void swapStruct(ppc_state_hdr_t &x) {
+      sys::swapByteOrder(x.flavor);
+      sys::swapByteOrder(x.count);
+    }
+
+    enum PPCThreadFlavors {
+      PPC_THREAD_STATE      = 1,
+      PPC_FLOAT_STATE       = 2,
+      PPC_EXCEPTION_STATE   = 3,
+      PPC_VECTOR_STATE      = 4,
+      PPC_THREAD_STATE64    = 5,
+      PPC_EXCEPTION_STATE64 = 6,
+      PPC_THREAD_STATE_NONE = 7
+    };
+
+    inline void swapStruct(ppc_thread_state_t &x) {
+      swapStruct(x.tsh);
+      if (x.tsh.flavor == PPC_THREAD_STATE)
+        swapStruct(x.uts.ts32);
+    }
+
+    const uint32_t PPC_THREAD_STATE_COUNT =
+      sizeof(ppc_thread_state32_t) / sizeof(uint32_t);
+
     // Define a union of all load command structs
     #define LOAD_COMMAND_STRUCT(LCStruct) LCStruct LCStruct##_data;
 

Modified: llvm/trunk/lib/Object/MachOObjectFile.cpp
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/lib/Object/MachOObjectFile.cpp?rev=284668&r1=284667&r2=284668&view=diff
==============================================================================
--- llvm/trunk/lib/Object/MachOObjectFile.cpp (original)
+++ llvm/trunk/lib/Object/MachOObjectFile.cpp Wed Oct 19 18:44:34 2016
@@ -782,6 +782,107 @@ static Error checkSubCommand(const MachO
   return Error::success();
 }
 
+static Error checkThreadCommand(const MachOObjectFile *Obj,
+                                const MachOObjectFile::LoadCommandInfo &Load,
+                                uint32_t LoadCommandIndex,
+                                const char *CmdName) {
+  if (Load.C.cmdsize < sizeof(MachO::thread_command))
+    return malformedError("load command " + Twine(LoadCommandIndex) +
+                          CmdName + " cmdsize too small");
+  MachO::thread_command T =
+    getStruct<MachO::thread_command>(Obj, Load.Ptr);
+  const char *state = Load.Ptr + sizeof(MachO::thread_command);
+  const char *end = Load.Ptr + T.cmdsize;
+  uint32_t nflavor = 0;
+  uint32_t cputype = getCPUType(Obj);
+  while (state < end) {
+    if(state + sizeof(uint32_t) > end)
+      return malformedError("load command " + Twine(LoadCommandIndex) +
+                            "flavor in " + CmdName + " extends past end of "
+                            "command");
+    uint32_t flavor;
+    memcpy(&flavor, state, sizeof(uint32_t));
+    if (Obj->isLittleEndian() != sys::IsLittleEndianHost)
+      sys::swapByteOrder(flavor);
+    state += sizeof(uint32_t);
+
+    if(state + sizeof(uint32_t) > end)
+      return malformedError("load command " + Twine(LoadCommandIndex) +
+                            " count in " + CmdName + " extends past end of "
+                            "command");
+    uint32_t count;
+    memcpy(&count, state, sizeof(uint32_t));
+    if (Obj->isLittleEndian() != sys::IsLittleEndianHost)
+      sys::swapByteOrder(count);
+    state += sizeof(uint32_t);
+
+    if (cputype == MachO::CPU_TYPE_X86_64) {
+      if (flavor == MachO::x86_THREAD_STATE64) {
+        if (count != MachO::x86_THREAD_STATE64_COUNT)
+          return malformedError("load command " + Twine(LoadCommandIndex) +
+                                " count not x86_THREAD_STATE64_COUNT for "
+                                "flavor number " + Twine(nflavor) + " which is "
+                                "a x86_THREAD_STATE64 flavor in " + CmdName +
+                                " command");
+        if (state + sizeof(MachO::x86_thread_state64_t) > end)
+          return malformedError("load command " + Twine(LoadCommandIndex) +
+                                " x86_THREAD_STATE64 extends past end of "
+                                "command in " + CmdName + " command");
+        state += sizeof(MachO::x86_thread_state64_t);
+      } else {
+        return malformedError("load command " + Twine(LoadCommandIndex) +
+                              " unknown flavor (" + Twine(flavor) + ") for "
+                              "flavor number " + Twine(nflavor) + " in " +
+                              CmdName + " command");
+      }
+    } else if (cputype == MachO::CPU_TYPE_ARM) {
+      if (flavor == MachO::ARM_THREAD_STATE) {
+        if (count != MachO::ARM_THREAD_STATE_COUNT)
+          return malformedError("load command " + Twine(LoadCommandIndex) +
+                                " count not ARM_THREAD_STATE_COUNT for "
+                                "flavor number " + Twine(nflavor) + " which is "
+                                "a ARM_THREAD_STATE flavor in " + CmdName +
+                                " command");
+        if (state + sizeof(MachO::arm_thread_state32_t) > end)
+          return malformedError("load command " + Twine(LoadCommandIndex) +
+                                " ARM_THREAD_STATE extends past end of "
+                                "command in " + CmdName + " command");
+        state += sizeof(MachO::arm_thread_state32_t);
+      } else {
+        return malformedError("load command " + Twine(LoadCommandIndex) +
+                              " unknown flavor (" + Twine(flavor) + ") for "
+                              "flavor number " + Twine(nflavor) + " in " +
+                              CmdName + " command");
+      }
+    } else if (cputype == MachO::CPU_TYPE_POWERPC) {
+      if (flavor == MachO::PPC_THREAD_STATE) {
+        if (count != MachO::PPC_THREAD_STATE_COUNT)
+          return malformedError("load command " + Twine(LoadCommandIndex) +
+                                " count not PPC_THREAD_STATE_COUNT for "
+                                "flavor number " + Twine(nflavor) + " which is "
+                                "a PPC_THREAD_STATE flavor in " + CmdName +
+                                " command");
+        if (state + sizeof(MachO::ppc_thread_state32_t) > end)
+          return malformedError("load command " + Twine(LoadCommandIndex) +
+                                " PPC_THREAD_STATE extends past end of "
+                                "command in " + CmdName + " command");
+        state += sizeof(MachO::ppc_thread_state32_t);
+      } else {
+        return malformedError("load command " + Twine(LoadCommandIndex) +
+                              " unknown flavor (" + Twine(flavor) + ") for "
+                              "flavor number " + Twine(nflavor) + " in " +
+                              CmdName + " command");
+      }
+    } else {
+      return malformedError("unknown cputype (" + Twine(cputype) + ") load "
+                            "command " + Twine(LoadCommandIndex) + " for " +
+                            CmdName + " command can't be checked");
+    }
+    nflavor++;
+  }
+  return Error::success();
+}
+
 Expected<std::unique_ptr<MachOObjectFile>>
 MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian,
                         bool Is64Bits) {
@@ -839,6 +940,7 @@ MachOObjectFile::MachOObjectFile(MemoryB
   const char *EntryPointLoadCmd = nullptr;
   const char *EncryptLoadCmd = nullptr;
   const char *RoutinesLoadCmd = nullptr;
+  const char *UnixThreadLoadCmd = nullptr;
   for (unsigned I = 0; I < LoadCommandCount; ++I) {
     if (is64Bit()) {
       if (Load.C.cmdsize % 8 != 0) {
@@ -1094,6 +1196,17 @@ MachOObjectFile::MachOObjectFile(MemoryB
         return;
       }
       RoutinesLoadCmd = Load.Ptr;
+    } else if (Load.C.cmd == MachO::LC_UNIXTHREAD) {
+      if ((Err = checkThreadCommand(this, Load, I, "LC_UNIXTHREAD")))
+        return;
+      if (UnixThreadLoadCmd) {
+        Err = malformedError("more than one LC_UNIXTHREAD command");
+        return;
+      }
+      UnixThreadLoadCmd = Load.Ptr;
+    } else if (Load.C.cmd == MachO::LC_THREAD) {
+      if ((Err = checkThreadCommand(this, Load, I, "LC_THREAD")))
+        return;
     }
     if (I < LoadCommandCount - 1) {
       if (auto LoadOrErr = getNextLoadCommandInfo(this, I, Load))

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

Propchange: llvm/trunk/test/Object/Inputs/macho-invalid-thread-count-pastend
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

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

Propchange: llvm/trunk/test/Object/Inputs/macho-invalid-thread-count-wrong
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

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

Propchange: llvm/trunk/test/Object/Inputs/macho-invalid-thread-flavor-unknown
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

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

Propchange: llvm/trunk/test/Object/Inputs/macho-invalid-thread-state-pastend
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

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

Propchange: llvm/trunk/test/Object/Inputs/macho-invalid-thread-unknown-cputype
------------------------------------------------------------------------------
    svn:mime-type = application/octet-stream

Added: llvm/trunk/test/Object/Inputs/macho-invalid-unixthread-more-than-one
URL: http://llvm.org/viewvc/llvm-project/llvm/trunk/test/Object/Inputs/macho-invalid-unixthread-more-than-one?rev=284668&view=auto
==============================================================================
Binary file - no diff available.

Propchange: llvm/trunk/test/Object/Inputs/macho-invalid-unixthread-more-than-one
------------------------------------------------------------------------------
    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=284668&r1=284667&r2=284668&view=diff
==============================================================================
--- llvm/trunk/test/Object/macho-invalid.test (original)
+++ llvm/trunk/test/Object/macho-invalid.test Wed Oct 19 18:44:34 2016
@@ -376,3 +376,21 @@ INVALID-ROUTINES64-MORE-THAN-ONE: macho-
 
 RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-codesign-bad-size 2>&1 | FileCheck -check-prefix INVALID-CODESIGN-BAD-SIZE %s
 INVALID-CODESIGN-BAD-SIZE: macho-invalid-codesign-bad-size': truncated or malformed object (LC_CODE_SIGNATURE command 0 has incorrect cmdsize)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-count-pastend 2>&1 | FileCheck -check-prefix INVALID-THREAD-COUNT-PASTEND %s
+INVALID-THREAD-COUNT-PASTEND: macho-invalid-thread-count-pastend': truncated or malformed object (load command 0 count in LC_UNIXTHREAD extends past end of command)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-count-wrong 2>&1 | FileCheck -check-prefix INVALID-THREAD-COUNT-WRONG %s
+INVALID-THREAD-COUNT-WRONG: macho-invalid-thread-count-wrong': truncated or malformed object (load command 0 count not x86_THREAD_STATE64_COUNT for flavor number 0 which is a x86_THREAD_STATE64 flavor in LC_THREAD command)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-flavor-unknown 2>&1 | FileCheck -check-prefix INVALID-THREAD-FLAVOR-UNKNOWN %s
+INVALID-THREAD-FLAVOR-UNKNOWN: macho-invalid-thread-flavor-unknown': truncated or malformed object (load command 0 unknown flavor (507) for flavor number 0 in LC_THREAD command)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-state-pastend 2>&1 | FileCheck -check-prefix INVALID-THREAD-PASTEND %s
+INVALID-THREAD-PASTEND: macho-invalid-thread-state-pastend': truncated or malformed object (load command 0 x86_THREAD_STATE64 extends past end of command in LC_THREAD command)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-thread-unknown-cputype 2>&1 | FileCheck -check-prefix INVALID-THREAD-UNKNOWN-CPUTYPE %s
+INVALID-THREAD-UNKNOWN-CPUTYPE: macho-invalid-thread-unknown-cputype': truncated or malformed object (unknown cputype (328) load command 0 for LC_THREAD command can't be checked)
+
+RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-unixthread-more-than-one 2>&1 | FileCheck -check-prefix INVALID-UNIXTHREAD-MORE-THAN-ONE %s
+INVALID-UNIXTHREAD-MORE-THAN-ONE: macho-invalid-unixthread-more-than-one': truncated or malformed object (more than one LC_UNIXTHREAD command)




More information about the llvm-commits mailing list