diff options
Diffstat (limited to 'llvm')
-rw-r--r-- | llvm/lib/Object/MachOObjectFile.cpp | 113 | ||||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-section-addr | bin | 0 -> 162 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-section-addr-size | bin | 0 -> 163 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-section-offset | bin | 0 -> 152 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-section-offset-in-headers | bin | 0 -> 152 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-section-offset-size | bin | 0 -> 152 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-section-reloff | bin | 0 -> 152 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-section-reloff-nrelocs | bin | 0 -> 152 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-section-size-filesize | bin | 0 -> 163 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-segment-filesize | bin | 0 -> 84 bytes | |||
-rw-r--r-- | llvm/test/Object/Inputs/macho-invalid-segment-vmsize | bin | 0 -> 84 bytes | |||
-rw-r--r-- | llvm/test/Object/macho-invalid.test | 30 | ||||
-rw-r--r-- | llvm/test/tools/llvm-objdump/X86/malformed-machos.test | 18 |
13 files changed, 135 insertions, 26 deletions
diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 863081fbd4c..f34e68721c0 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -219,19 +219,19 @@ static void parseHeader(const MachOObjectFile *Obj, T &Header, // Parses LC_SEGMENT or LC_SEGMENT_64 load command, adds addresses of all // sections to \param Sections, and optionally sets // \param IsPageZeroSegment to true. -template <typename SegmentCmd> +template <typename Segment, typename Section> static Error parseSegmentLoadCommand( const MachOObjectFile *Obj, const MachOObjectFile::LoadCommandInfo &Load, SmallVectorImpl<const char *> &Sections, bool &IsPageZeroSegment, - uint32_t LoadCommandIndex, const char *CmdName) { - const unsigned SegmentLoadSize = sizeof(SegmentCmd); + uint32_t LoadCommandIndex, const char *CmdName, uint64_t SizeOfHeaders) { + const unsigned SegmentLoadSize = sizeof(Segment); if (Load.C.cmdsize < SegmentLoadSize) return malformedError("load command " + Twine(LoadCommandIndex) + " " + CmdName + " cmdsize too small"); - if (auto SegOrErr = getStructOrErr<SegmentCmd>(Obj, Load.Ptr)) { - SegmentCmd S = SegOrErr.get(); - const unsigned SectionSize = - Obj->is64Bit() ? sizeof(MachO::section_64) : sizeof(MachO::section); + if (auto SegOrErr = getStructOrErr<Segment>(Obj, Load.Ptr)) { + Segment S = SegOrErr.get(); + const unsigned SectionSize = sizeof(Section); + uint64_t FileSize = Obj->getData().size(); if (S.nsects > std::numeric_limits<uint32_t>::max() / SectionSize || S.nsects * SectionSize > Load.C.cmdsize - SegmentLoadSize) return malformedError("load command " + Twine(LoadCommandIndex) + @@ -240,12 +240,88 @@ static Error parseSegmentLoadCommand( for (unsigned J = 0; J < S.nsects; ++J) { const char *Sec = getSectionPtr(Obj, Load, J); Sections.push_back(Sec); + Section s = getStruct<Section>(Obj, Sec); + if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB && + Obj->getHeader().filetype != MachO::MH_DSYM && + s.flags != MachO::S_ZEROFILL && + s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && + s.offset > FileSize) + return malformedError("offset field of section " + Twine(J) + " in " + + CmdName + " command " + Twine(LoadCommandIndex) + + " extends past the end of the file"); + if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB && + Obj->getHeader().filetype != MachO::MH_DSYM && + s.flags != MachO::S_ZEROFILL && + s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && + S.fileoff == 0 && s.offset < SizeOfHeaders && s.size != 0) + return malformedError("offset field of section " + Twine(J) + " in " + + CmdName + " command " + Twine(LoadCommandIndex) + + " not past the headers of the file"); + uint64_t BigSize = s.offset; + BigSize += s.size; + if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB && + Obj->getHeader().filetype != MachO::MH_DSYM && + s.flags != MachO::S_ZEROFILL && + s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && + BigSize > FileSize) + return malformedError("offset field plus size field of section " + + Twine(J) + " in " + CmdName + " command " + + Twine(LoadCommandIndex) + + " extends past the end of the file"); + if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB && + Obj->getHeader().filetype != MachO::MH_DSYM && + s.flags != MachO::S_ZEROFILL && + s.flags != MachO::S_THREAD_LOCAL_ZEROFILL && + s.size > S.filesize) + return malformedError("size field of section " + + Twine(J) + " in " + CmdName + " command " + + Twine(LoadCommandIndex) + + " greater than the segment"); + if (Obj->getHeader().filetype != MachO::MH_DYLIB_STUB && + Obj->getHeader().filetype != MachO::MH_DSYM && + s.size != 0 && s.addr < S.vmaddr) + return malformedError("addr field of section " + + Twine(J) + " in " + CmdName + " command " + + Twine(LoadCommandIndex) + + " less than the segment's vmaddr"); + BigSize = s.addr; + BigSize += s.size; + uint64_t BigEnd = S.vmaddr; + BigEnd += S.vmsize; + if (S.vmsize != 0 && s.size != 0 && BigSize > BigEnd) + return malformedError("addr field plus size of section " + + Twine(J) + " in " + CmdName + " command " + + Twine(LoadCommandIndex) + " greater than than " + "the segment's vmaddr plus vmsize"); + if (s.reloff > FileSize) + return malformedError("reloff field of section " + + Twine(J) + " in " + CmdName + " command " + + Twine(LoadCommandIndex) + + " extends past the end of the file"); + BigSize = s.nreloc; + BigSize *= sizeof(struct MachO::relocation_info); + BigSize += s.reloff; + if (BigSize > FileSize) + return malformedError("reloff field plus nreloc field times sizeof(" + "struct relocation_info) of section " + + Twine(J) + " in " + CmdName + " command " + + Twine(LoadCommandIndex) + + " extends past the end of the file"); } - uint64_t FileSize = Obj->getData().size(); if (S.fileoff > FileSize) return malformedError("load command " + Twine(LoadCommandIndex) + " fileoff field in " + CmdName + " extends past the end of the file"); + uint64_t BigSize = S.fileoff; + BigSize += S.filesize; + if (BigSize > FileSize) + return malformedError("load command " + Twine(LoadCommandIndex) + + " fileoff field plus filesize field in " + + CmdName + " extends past the end of the file"); + if (S.vmsize != 0 && S.filesize > S.vmsize) + return malformedError("load command " + Twine(LoadCommandIndex) + + " fileoff field in " + CmdName + + " greater than vmsize field"); IsPageZeroSegment |= StringRef("__PAGEZERO").equals(S.segname); } else return SegOrErr.takeError(); @@ -273,18 +349,18 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, DyldInfoLoadCmd(nullptr), UuidLoadCmd(nullptr), HasPageZeroSegment(false) { ErrorAsOutParameter ErrAsOutParam(&Err); - uint64_t BigSize; + uint64_t SizeOfHeaders; if (is64Bit()) { parseHeader(this, Header64, Err); - BigSize = sizeof(MachO::mach_header_64); + SizeOfHeaders = sizeof(MachO::mach_header_64); } else { parseHeader(this, Header, Err); - BigSize = sizeof(MachO::mach_header); + SizeOfHeaders = sizeof(MachO::mach_header); } if (Err) return; - BigSize += getHeader().sizeofcmds; - if (getData().data() + BigSize > getData().end()) { + SizeOfHeaders += getHeader().sizeofcmds; + if (getData().data() + SizeOfHeaders > getData().end()) { Err = malformedError("load commands extend past the end of the file"); return; } @@ -366,13 +442,16 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, } UuidLoadCmd = Load.Ptr; } else if (Load.C.cmd == MachO::LC_SEGMENT_64) { - if ((Err = parseSegmentLoadCommand<MachO::segment_command_64>( + if ((Err = parseSegmentLoadCommand<MachO::segment_command_64, + MachO::section_64>( this, Load, Sections, HasPageZeroSegment, I, - "LC_SEGMENT_64"))) + "LC_SEGMENT_64", SizeOfHeaders))) return; } else if (Load.C.cmd == MachO::LC_SEGMENT) { - if ((Err = parseSegmentLoadCommand<MachO::segment_command>( - this, Load, Sections, HasPageZeroSegment, I, "LC_SEGMENT"))) + if ((Err = parseSegmentLoadCommand<MachO::segment_command, + MachO::section>( + this, Load, Sections, HasPageZeroSegment, I, + "LC_SEGMENT", SizeOfHeaders))) return; } else if (Load.C.cmd == MachO::LC_LOAD_DYLIB || Load.C.cmd == MachO::LC_LOAD_WEAK_DYLIB || diff --git a/llvm/test/Object/Inputs/macho-invalid-section-addr b/llvm/test/Object/Inputs/macho-invalid-section-addr Binary files differnew file mode 100644 index 00000000000..c9a384a56f0 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-addr diff --git a/llvm/test/Object/Inputs/macho-invalid-section-addr-size b/llvm/test/Object/Inputs/macho-invalid-section-addr-size Binary files differnew file mode 100644 index 00000000000..fdf8786ce94 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-addr-size diff --git a/llvm/test/Object/Inputs/macho-invalid-section-offset b/llvm/test/Object/Inputs/macho-invalid-section-offset Binary files differnew file mode 100644 index 00000000000..4d30bf96e85 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-offset diff --git a/llvm/test/Object/Inputs/macho-invalid-section-offset-in-headers b/llvm/test/Object/Inputs/macho-invalid-section-offset-in-headers Binary files differnew file mode 100644 index 00000000000..33161d3fc36 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-offset-in-headers diff --git a/llvm/test/Object/Inputs/macho-invalid-section-offset-size b/llvm/test/Object/Inputs/macho-invalid-section-offset-size Binary files differnew file mode 100644 index 00000000000..747b1861ea2 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-offset-size diff --git a/llvm/test/Object/Inputs/macho-invalid-section-reloff b/llvm/test/Object/Inputs/macho-invalid-section-reloff Binary files differnew file mode 100644 index 00000000000..2a46c51d975 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-reloff diff --git a/llvm/test/Object/Inputs/macho-invalid-section-reloff-nrelocs b/llvm/test/Object/Inputs/macho-invalid-section-reloff-nrelocs Binary files differnew file mode 100644 index 00000000000..5b3fc9efb2c --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-reloff-nrelocs diff --git a/llvm/test/Object/Inputs/macho-invalid-section-size-filesize b/llvm/test/Object/Inputs/macho-invalid-section-size-filesize Binary files differnew file mode 100644 index 00000000000..a5666d64e88 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-section-size-filesize diff --git a/llvm/test/Object/Inputs/macho-invalid-segment-filesize b/llvm/test/Object/Inputs/macho-invalid-segment-filesize Binary files differnew file mode 100644 index 00000000000..e92cc51098b --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-segment-filesize diff --git a/llvm/test/Object/Inputs/macho-invalid-segment-vmsize b/llvm/test/Object/Inputs/macho-invalid-segment-vmsize Binary files differnew file mode 100644 index 00000000000..a6715619234 --- /dev/null +++ b/llvm/test/Object/Inputs/macho-invalid-segment-vmsize diff --git a/llvm/test/Object/macho-invalid.test b/llvm/test/Object/macho-invalid.test index 2236b0b03c1..91e1ea7b1a0 100644 --- a/llvm/test/Object/macho-invalid.test +++ b/llvm/test/Object/macho-invalid.test @@ -112,3 +112,33 @@ INVALID-SEGMENT-FILEOFF-NM: macho-invalid-segment-fileoff truncated or malformed RUN: not llvm-size %p/Inputs/macho-invalid-segment-fileoff 2>&1 | FileCheck -check-prefix INVALID-SEGMENT-FILEOFF-SIZE %s INVALID-SEGMENT-FILEOFF-SIZE: macho-invalid-segment-fileoff truncated or malformed object (load command 0 fileoff field in LC_SEGMENT extends past the end of the file) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-segment-filesize 2>&1 | FileCheck -check-prefix INVALID-SEGMENT-FILESIZE %s +INVALID-SEGMENT-FILESIZE: macho-invalid-segment-filesize': truncated or malformed object (load command 0 fileoff field plus filesize field in LC_SEGMENT extends past the end of the file) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-segment-vmsize 2>&1 | FileCheck -check-prefix INVALID-SEGMENT-VMSIZE %s +INVALID-SEGMENT-VMSIZE: macho-invalid-segment-vmsize': truncated or malformed object (load command 0 fileoff field in LC_SEGMENT greater than vmsize field) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-offset 2>&1 | FileCheck -check-prefix INVALID-SECTION-FILEOFF %s +INVALID-SECTION-FILEOFF: macho-invalid-section-offset': truncated or malformed object (offset field of section 0 in LC_SEGMENT command 0 extends past the end of the file) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-offset-in-headers 2>&1 | FileCheck -check-prefix INVALID-SECTION-FILEOFF-IN-HEADERS %s +INVALID-SECTION-FILEOFF-IN-HEADERS: macho-invalid-section-offset-in-headers': truncated or malformed object (offset field of section 0 in LC_SEGMENT command 0 not past the headers of the file) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-offset-size 2>&1 | FileCheck -check-prefix INVALID-SECTION-FILEOFF-SIZE %s +INVALID-SECTION-FILEOFF-SIZE: macho-invalid-section-offset-size': truncated or malformed object (offset field plus size field of section 0 in LC_SEGMENT command 0 extends past the end of the file) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-size-filesize 2>&1 | FileCheck -check-prefix INVALID-SECTION-SIZE-FILESIZE %s +INVALID-SECTION-SIZE-FILESIZE: macho-invalid-section-size-filesize': truncated or malformed object (size field of section 0 in LC_SEGMENT command 0 greater than the segment) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-addr 2>&1 | FileCheck -check-prefix INVALID-SECTION-ADDR %s +INVALID-SECTION-ADDR: macho-invalid-section-addr': truncated or malformed object (addr field of section 0 in LC_SEGMENT command 0 less than the segment's vmaddr) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-addr-size 2>&1 | FileCheck -check-prefix INVALID-SECTION-ADDR-SIZE %s +INVALID-SECTION-ADDR-SIZE: macho-invalid-section-addr-size': truncated or malformed object (addr field plus size of section 0 in LC_SEGMENT command 0 greater than than the segment's vmaddr plus vmsize) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-reloff 2>&1 | FileCheck -check-prefix INVALID-SECTION-RELOFF %s +INVALID-SECTION-RELOFF: macho-invalid-section-reloff': truncated or malformed object (reloff field of section 0 in LC_SEGMENT command 0 extends past the end of the file) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-section-reloff-nrelocs 2>&1 | FileCheck -check-prefix INVALID-SECTION-RELOFF-NRELOCS %s +INVALID-SECTION-RELOFF-NRELOCS: macho-invalid-section-reloff-nrelocs': truncated or malformed object (reloff field plus nreloc field times sizeof(struct relocation_info) of section 0 in LC_SEGMENT command 0 extends past the end of the file) diff --git a/llvm/test/tools/llvm-objdump/X86/malformed-machos.test b/llvm/test/tools/llvm-objdump/X86/malformed-machos.test index a47e43443c5..9ada3ef0abe 100644 --- a/llvm/test/tools/llvm-objdump/X86/malformed-machos.test +++ b/llvm/test/tools/llvm-objdump/X86/malformed-machos.test @@ -1,11 +1,11 @@ // These test checks that llvm-objdump will not crash with malformed Mach-O // files. So the check line is not all that important but the bug fixes to // make sure llvm-objdump is robust is what matters. -# RUN: llvm-objdump -macho -objc-meta-data \ -# RUN: %p/Inputs/malformed-machos/mem-crup-0001.macho \ +# RUN: not llvm-objdump -macho -objc-meta-data \ +# RUN: %p/Inputs/malformed-machos/mem-crup-0001.macho 2>&1 \ # RUN: | FileCheck -check-prefix=m0001 %s -# m0001: (method_t extends past the end of the section) +# m0001: mem-crup-0001.macho': truncated or malformed object (addr field plus size of section 2 in LC_SEGMENT_64 command 0 greater than than the segment's vmaddr plus vmsize) # RUN: llvm-objdump -macho -objc-meta-data \ # RUN: %p/Inputs/malformed-machos/mem-crup-0006.macho \ @@ -19,17 +19,17 @@ # m0010: 00000000000010e0 0x10e8 _OBJC_CLASS_ -# RUN: llvm-objdump -macho -objc-meta-data \ -# RUN: %p/Inputs/malformed-machos/mem-crup-0040.macho \ +# RUN: not llvm-objdump -macho -objc-meta-data \ +# RUN: %p/Inputs/malformed-machos/mem-crup-0040.macho 2>&1 \ # RUN: | FileCheck -check-prefix=m0040 %s -# m0040: 00000000000010a0 0xf39 -[tiny_dylib init] +# m0040: mem-crup-0040.macho': truncated or malformed object (offset field plus size field of section 2 in LC_SEGMENT_64 command 1 extends past the end of the file) -# RUN: llvm-objdump -macho -objc-meta-data \ -# RUN: %p/Inputs/malformed-machos/mem-crup-0080.macho \ +# RUN: not llvm-objdump -macho -objc-meta-data \ +# RUN: %p/Inputs/malformed-machos/mem-crup-0080.macho 2>&1 \ # RUN: | FileCheck -check-prefix=m0080 %s -# m0080: data 0xf960000 (struct class_ro_t *) +# m0080: mem-crup-0080.macho': truncated or malformed object (addr field plus size of section 2 in LC_SEGMENT_64 command 1 greater than than the segment's vmaddr plus vmsize) # RUN: llvm-objdump -macho -objc-meta-data \ # RUN: %p/Inputs/malformed-machos/mem-crup-0261.macho |