From: Kevin Enderby Date: Mon, 24 Oct 2016 21:15:11 +0000 (+0000) Subject: nother additional error check for an invalid Mach-O file X-Git-Url: https://granicus.if.org/sourcecode?a=commitdiff_plain;h=aa45092c24842bb2eb5cce3d5eab701a6e60df99;p=llvm nother additional error check for an invalid Mach-O file when contained in a Mach-O universal file and the cputypes in both headers don’t match. git-svn-id: https://llvm.org/svn/llvm-project/llvm/trunk@285026 91177308-0d34-0410-b5e6-96231b3b80d8 --- diff --git a/include/llvm/Object/MachO.h b/include/llvm/Object/MachO.h index 7906db1e8a7..a26a2ef7dfe 100644 --- a/include/llvm/Object/MachO.h +++ b/include/llvm/Object/MachO.h @@ -194,7 +194,8 @@ public: typedef LoadCommandList::const_iterator load_command_iterator; static Expected> - create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits); + create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, + uint32_t UniversalCputype = 0, uint32_t UniversalIndex = 0); void moveSymbolNext(DataRefImpl &Symb) const override; @@ -443,7 +444,8 @@ public: private: MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits, - Error &Err); + Error &Err, uint32_t UniversalCputype = 0, + uint32_t UniversalIndex = 0); uint64_t getSymbolValueImpl(DataRefImpl Symb) const override; diff --git a/include/llvm/Object/ObjectFile.h b/include/llvm/Object/ObjectFile.h index 6272a5f056e..07d6b134086 100644 --- a/include/llvm/Object/ObjectFile.h +++ b/include/llvm/Object/ObjectFile.h @@ -300,7 +300,9 @@ public: createELFObjectFile(MemoryBufferRef Object); static Expected> - createMachOObjectFile(MemoryBufferRef Object); + createMachOObjectFile(MemoryBufferRef Object, + uint32_t UniversalCputype = 0, + uint32_t UniversalIndex = 0); }; diff --git a/lib/Object/MachOObjectFile.cpp b/lib/Object/MachOObjectFile.cpp index 0edc6a71633..5bfc51ecf62 100644 --- a/lib/Object/MachOObjectFile.cpp +++ b/lib/Object/MachOObjectFile.cpp @@ -914,18 +914,22 @@ static Error checkTwoLevelHintsCommand(const MachOObjectFile *Obj, Expected> MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian, - bool Is64Bits) { + bool Is64Bits, uint32_t UniversalCputype, + uint32_t UniversalIndex) { Error Err; std::unique_ptr Obj( new MachOObjectFile(std::move(Object), IsLittleEndian, - Is64Bits, Err)); + Is64Bits, Err, UniversalCputype, + UniversalIndex)); if (Err) return std::move(Err); return std::move(Obj); } MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, - bool Is64bits, Error &Err) + bool Is64bits, Error &Err, + uint32_t UniversalCputype, + uint32_t UniversalIndex) : ObjectFile(getMachOType(IsLittleEndian, Is64bits), Object), SymtabLoadCmd(nullptr), DysymtabLoadCmd(nullptr), DataInCodeLoadCmd(nullptr), LinkOptHintsLoadCmd(nullptr), @@ -933,12 +937,15 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, HasPageZeroSegment(false) { ErrorAsOutParameter ErrAsOutParam(&Err); uint64_t SizeOfHeaders; + uint32_t cputype; if (is64Bit()) { parseHeader(this, Header64, Err); SizeOfHeaders = sizeof(MachO::mach_header_64); + cputype = Header64.cputype; } else { parseHeader(this, Header, Err); SizeOfHeaders = sizeof(MachO::mach_header); + cputype = Header.cputype; } if (Err) return; @@ -947,6 +954,12 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, Err = malformedError("load commands extend past the end of the file"); return; } + if (UniversalCputype != 0 && cputype != UniversalCputype) { + Err = malformedError("universal header architecture: " + + Twine(UniversalIndex) + "'s cputype does not match " + "object file's mach header"); + return; + } uint32_t LoadCommandCount = getHeader().ncmds; LoadCommandInfo Load; @@ -3281,16 +3294,22 @@ bool MachOObjectFile::isRelocatableObject() const { } Expected> -ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer) { +ObjectFile::createMachOObjectFile(MemoryBufferRef Buffer, + uint32_t UniversalCputype, + uint32_t UniversalIndex) { StringRef Magic = Buffer.getBuffer().slice(0, 4); if (Magic == "\xFE\xED\xFA\xCE") - return MachOObjectFile::create(Buffer, false, false); + return MachOObjectFile::create(Buffer, false, false, + UniversalCputype, UniversalIndex); if (Magic == "\xCE\xFA\xED\xFE") - return MachOObjectFile::create(Buffer, true, false); + return MachOObjectFile::create(Buffer, true, false, + UniversalCputype, UniversalIndex); if (Magic == "\xFE\xED\xFA\xCF") - return MachOObjectFile::create(Buffer, false, true); + return MachOObjectFile::create(Buffer, false, true, + UniversalCputype, UniversalIndex); if (Magic == "\xCF\xFA\xED\xFE") - return MachOObjectFile::create(Buffer, true, true); + return MachOObjectFile::create(Buffer, true, true, + UniversalCputype, UniversalIndex); return make_error("Unrecognized MachO magic number", object_error::invalid_file_type); } diff --git a/lib/Object/MachOUniversal.cpp b/lib/Object/MachOUniversal.cpp index f36e84d93b9..bac9d4dd3e3 100644 --- a/lib/Object/MachOUniversal.cpp +++ b/lib/Object/MachOUniversal.cpp @@ -73,13 +73,17 @@ MachOUniversalBinary::ObjectForArch::getAsObjectFile() const { StringRef ParentData = Parent->getData(); StringRef ObjectData; - if (Parent->getMagic() == MachO::FAT_MAGIC) + uint32_t cputype; + if (Parent->getMagic() == MachO::FAT_MAGIC) { ObjectData = ParentData.substr(Header.offset, Header.size); - else // Parent->getMagic() == MachO::FAT_MAGIC_64 + cputype = Header.cputype; + } else { // Parent->getMagic() == MachO::FAT_MAGIC_64 ObjectData = ParentData.substr(Header64.offset, Header64.size); + cputype = Header64.cputype; + } StringRef ObjectName = Parent->getFileName(); MemoryBufferRef ObjBuffer(ObjectData, ObjectName); - return ObjectFile::createMachOObjectFile(ObjBuffer); + return ObjectFile::createMachOObjectFile(ObjBuffer, cputype, Index); } Expected> diff --git a/test/Object/Inputs/macho-invalid-fat_cputype b/test/Object/Inputs/macho-invalid-fat_cputype new file mode 100644 index 00000000000..ce30be86932 Binary files /dev/null and b/test/Object/Inputs/macho-invalid-fat_cputype differ diff --git a/test/Object/macho-invalid.test b/test/Object/macho-invalid.test index 5a00d0def52..403b968fc05 100644 --- a/test/Object/macho-invalid.test +++ b/test/Object/macho-invalid.test @@ -406,3 +406,6 @@ INVALID-TWOLEVELHINTS-OFFSET: macho-invalid-twolevelhints-offset': truncated or RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-twolevelhints-offset-nhints 2>&1 | FileCheck -check-prefix INVALID-TWOLEVELHINTS-OFFSET-HNINTS %s INVALID-TWOLEVELHINTS-OFFSET-HNINTS: macho-invalid-twolevelhints-offset-nhints': truncated or malformed object (offset field plus nhints times sizeof(struct twolevel_hint) field of LC_TWOLEVEL_HINTS command 0 extends past the end of the file) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-fat_cputype 2>&1 | FileCheck -check-prefix INVALID-FAT-CPUTYPE %s +INVALID-FAT-CPUTYPE: macho-invalid-fat_cputype truncated or malformed object (universal header architecture: 0's cputype does not match object file's mach header)