diff options
17 files changed, 97 insertions, 17 deletions
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 978988c2569..a367a49f6bc 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -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 *O, const char *P) {    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(MemoryBufferRef Object, bool IsLittleEndian,        }        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::getSymbolName(DataRefImpl Symb,    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::getSymbolByIndex(unsigned Index) const {      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::getSectionFinalSegmentName(DataRefImpl Sec) const {  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(DataRefImpl Sec) const {  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() const {                                      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(const LoadCommandInfo &L) const {    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]);  } diff --git a/llvm/test/Object/Inputs/macho-invalid-bad-symbol-index b/llvm/test/Object/Inputs/macho-invalid-bad-symbol-index Binary files differnew file mode 100644 index 00000000000..294bbde3ddf --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-bad-symbol-index diff --git a/llvm/test/Object/Inputs/macho-invalid-getsection-index b/llvm/test/Object/Inputs/macho-invalid-getsection-index Binary files differnew file mode 100644 index 00000000000..b7e4b95bc9b --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-getsection-index diff --git a/llvm/test/Object/Inputs/macho-invalid-no-size-for-sections b/llvm/test/Object/Inputs/macho-invalid-no-size-for-sections Binary files differnew file mode 100644 index 00000000000..89fa95acbcf --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-no-size-for-sections diff --git a/llvm/test/Object/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName b/llvm/test/Object/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName Binary files differnew file mode 100644 index 00000000000..e3f65865922 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-index-getSectionRawFinalSegmentName diff --git a/llvm/test/Object/Inputs/macho-invalid-section-index-getSectionRawName b/llvm/test/Object/Inputs/macho-invalid-section-index-getSectionRawName Binary files differnew file mode 100644 index 00000000000..9cd3e1cace8 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-index-getSectionRawName diff --git a/llvm/test/Object/Inputs/macho-invalid-symbol-name-past-eof b/llvm/test/Object/Inputs/macho-invalid-symbol-name-past-eof Binary files differnew file mode 100644 index 00000000000..87478840787 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-symbol-name-past-eof diff --git a/llvm/test/Object/Inputs/macho-invalid-too-small-load-command b/llvm/test/Object/Inputs/macho-invalid-too-small-load-command Binary files differnew file mode 100644 index 00000000000..36021692ee5 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-too-small-load-command diff --git a/llvm/test/Object/Inputs/macho-invalid-too-small-segment-load-command b/llvm/test/Object/Inputs/macho-invalid-too-small-segment-load-command Binary files differnew file mode 100644 index 00000000000..8cbfbf96578 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-too-small-segment-load-command diff --git a/llvm/test/Object/Inputs/macho-zero-ncmds b/llvm/test/Object/Inputs/macho-invalid-zero-ncmds Binary files differindex 0505419195e..0505419195e 100644 --- a/llvm/test/Object/Inputs/macho-zero-ncmds +++ b/llvm/test/Object/Inputs/macho-invalid-zero-ncmds diff --git a/llvm/test/Object/Inputs/macho64-invalid-getsection-index b/llvm/test/Object/Inputs/macho64-invalid-getsection-index Binary files differnew file mode 100644 index 00000000000..a2a7bc10c4f --- /dev/null +++ b/llvm/test/Object/Inputs/macho64-invalid-getsection-index diff --git a/llvm/test/Object/Inputs/macho64-invalid-incomplete-load-command b/llvm/test/Object/Inputs/macho64-invalid-incomplete-load-command Binary files differnew file mode 100644 index 00000000000..a569c9e14b3 --- /dev/null +++ b/llvm/test/Object/Inputs/macho64-invalid-incomplete-load-command diff --git a/llvm/test/Object/Inputs/macho64-invalid-no-size-for-sections b/llvm/test/Object/Inputs/macho64-invalid-no-size-for-sections Binary files differnew file mode 100644 index 00000000000..5aae5ffed3a --- /dev/null +++ b/llvm/test/Object/Inputs/macho64-invalid-no-size-for-sections diff --git a/llvm/test/Object/Inputs/macho64-invalid-too-small-load-command b/llvm/test/Object/Inputs/macho64-invalid-too-small-load-command Binary files differnew file mode 100644 index 00000000000..0028451d190 --- /dev/null +++ b/llvm/test/Object/Inputs/macho64-invalid-too-small-load-command diff --git a/llvm/test/Object/Inputs/macho64-invalid-too-small-segment-load-command b/llvm/test/Object/Inputs/macho64-invalid-too-small-segment-load-command Binary files differnew file mode 100644 index 00000000000..ce6a20134a9 --- /dev/null +++ b/llvm/test/Object/Inputs/macho64-invalid-too-small-segment-load-command diff --git a/llvm/test/Object/macho-invalid.test b/llvm/test/Object/macho-invalid.test new file mode 100644 index 00000000000..138d8eb1f3d --- /dev/null +++ b/llvm/test/Object/macho-invalid.test @@ -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 diff --git a/llvm/test/Object/objdump-macho-quirks.test b/llvm/test/Object/objdump-macho-quirks.test deleted file mode 100644 index eeee1537def..00000000000 --- a/llvm/test/Object/objdump-macho-quirks.test +++ /dev/null @@ -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 -  | 

