From c8bb42283ee6a118219593a2c98abc0974eb5dc4 Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Thu, 20 Oct 2016 20:10:30 +0000 Subject: [PATCH] Another additional error check for invalid Mach-O files for the load commands that use the MachO::twolevel_hints_command type which includes only the LC_TWOLEVEL_HINTS load command. This is not used in llvm libObject code or in llvm tool code. But does appear in one of the binary test files. While this load command is obsolete it is easier to add code for it in libObject than edit or change the binary test case. llvm-svn: 284769 --- llvm/lib/Object/MachOObjectFile.cpp | 34 +++++++++++++++++++++ .../Inputs/macho-invalid-twolevelhints-bad-size | Bin 0 -> 48 bytes .../macho-invalid-twolevelhints-more-than-one | Bin 0 -> 60 bytes .../Inputs/macho-invalid-twolevelhints-offset | Bin 0 -> 44 bytes .../macho-invalid-twolevelhints-offset-nhints | Bin 0 -> 44 bytes llvm/test/Object/macho-invalid.test | 12 ++++++++ 6 files changed, 46 insertions(+) create mode 100644 llvm/test/Object/Inputs/macho-invalid-twolevelhints-bad-size create mode 100644 llvm/test/Object/Inputs/macho-invalid-twolevelhints-more-than-one create mode 100644 llvm/test/Object/Inputs/macho-invalid-twolevelhints-offset create mode 100644 llvm/test/Object/Inputs/macho-invalid-twolevelhints-offset-nhints diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 87b19a1..0edc6a7 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -883,6 +883,35 @@ static Error checkThreadCommand(const MachOObjectFile *Obj, return Error::success(); } +static Error checkTwoLevelHintsCommand(const MachOObjectFile *Obj, + const MachOObjectFile::LoadCommandInfo + &Load, + uint32_t LoadCommandIndex, + const char **LoadCmd) { + if (Load.C.cmdsize != sizeof(MachO::twolevel_hints_command)) + return malformedError("load command " + Twine(LoadCommandIndex) + + " LC_TWOLEVEL_HINTS has incorrect cmdsize"); + if (*LoadCmd != nullptr) + return malformedError("more than one LC_TWOLEVEL_HINTS command"); + MachO::twolevel_hints_command Hints = + getStruct(Obj, Load.Ptr); + uint64_t FileSize = Obj->getData().size(); + if (Hints.offset > FileSize) + return malformedError("offset field of LC_TWOLEVEL_HINTS command " + + Twine(LoadCommandIndex) + " extends past the end of " + "the file"); + uint64_t BigSize = Hints.nhints; + BigSize *= Hints.nhints * sizeof(MachO::twolevel_hint); + BigSize += Hints.offset; + if (BigSize > FileSize) + return malformedError("offset field plus nhints times sizeof(struct " + "twolevel_hint) field of LC_TWOLEVEL_HINTS command " + + Twine(LoadCommandIndex) + " extends past the end of " + "the file"); + *LoadCmd = Load.Ptr; + return Error::success(); +} + Expected> MachOObjectFile::create(MemoryBufferRef Object, bool IsLittleEndian, bool Is64Bits) { @@ -941,6 +970,7 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, const char *EncryptLoadCmd = nullptr; const char *RoutinesLoadCmd = nullptr; const char *UnixThreadLoadCmd = nullptr; + const char *TwoLevelHintsLoadCmd = nullptr; for (unsigned I = 0; I < LoadCommandCount; ++I) { if (is64Bit()) { if (Load.C.cmdsize % 8 != 0) { @@ -1207,6 +1237,10 @@ MachOObjectFile::MachOObjectFile(MemoryBufferRef Object, bool IsLittleEndian, } else if (Load.C.cmd == MachO::LC_THREAD) { if ((Err = checkThreadCommand(this, Load, I, "LC_THREAD"))) return; + } else if (Load.C.cmd == MachO::LC_TWOLEVEL_HINTS) { + if ((Err = checkTwoLevelHintsCommand(this, Load, I, + &TwoLevelHintsLoadCmd))) + return; } if (I < LoadCommandCount - 1) { if (auto LoadOrErr = getNextLoadCommandInfo(this, I, Load)) diff --git a/llvm/test/Object/Inputs/macho-invalid-twolevelhints-bad-size b/llvm/test/Object/Inputs/macho-invalid-twolevelhints-bad-size new file mode 100644 index 0000000000000000000000000000000000000000..a13a00e6d20ca0c618c825b4ebaf1f3fb90b2879 GIT binary patch literal 48 gcmX^2>+L^w1_nlE1|R{&JU|)*#DEya1`7ZQ0I|~p?*IS* literal 0 HcmV?d00001 diff --git a/llvm/test/Object/Inputs/macho-invalid-twolevelhints-more-than-one b/llvm/test/Object/Inputs/macho-invalid-twolevelhints-more-than-one new file mode 100644 index 0000000000000000000000000000000000000000..27e3a17561e27580e2ae6ca76347809faa5cc1ce GIT binary patch literal 60 kcmX^2>+L^w1_nlE1|R{%OhBvv#2_FB!~$Rzgh1y50OsQaE&u=k literal 0 HcmV?d00001 diff --git a/llvm/test/Object/Inputs/macho-invalid-twolevelhints-offset b/llvm/test/Object/Inputs/macho-invalid-twolevelhints-offset new file mode 100644 index 0000000000000000000000000000000000000000..f280f14b9235845f62fdc8a77239842f20c55dec GIT binary patch literal 44 gcmX^2>+L^w1_nlE1|R{&0zeuB#DEygW&(2=0HU=6`2YX_ literal 0 HcmV?d00001 diff --git a/llvm/test/Object/Inputs/macho-invalid-twolevelhints-offset-nhints b/llvm/test/Object/Inputs/macho-invalid-twolevelhints-offset-nhints new file mode 100644 index 0000000000000000000000000000000000000000..81bf6a115944bbc0e0cd04634775f5692e933298 GIT binary patch literal 44 icmX^2>+L^w1_nlE1|R{&0zeuB#DEyY)&XJ;AO--WCj=`1 literal 0 HcmV?d00001 diff --git a/llvm/test/Object/macho-invalid.test b/llvm/test/Object/macho-invalid.test index 111ba66..5a00d0d 100644 --- a/llvm/test/Object/macho-invalid.test +++ b/llvm/test/Object/macho-invalid.test @@ -394,3 +394,15 @@ INVALID-THREAD-UNKNOWN-CPUTYPE: macho-invalid-thread-unknown-cputype': truncated 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) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-twolevelhints-bad-size 2>&1 | FileCheck -check-prefix INVALID-TWOLEVELHINTS-BAD-SIZE %s +INVALID-TWOLEVELHINTS-BAD-SIZE: macho-invalid-twolevelhints-bad-size': truncated or malformed object (load command 0 LC_TWOLEVEL_HINTS has incorrect cmdsize) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-twolevelhints-more-than-one 2>&1 | FileCheck -check-prefix INVALID-TWOLEVELHINTS-MORE-THAN-ONE %s +INVALID-TWOLEVELHINTS-MORE-THAN-ONE: macho-invalid-twolevelhints-more-than-one': truncated or malformed object (more than one LC_TWOLEVEL_HINTS command) + +RUN: not llvm-objdump -macho -private-headers %p/Inputs/macho-invalid-twolevelhints-offset 2>&1 | FileCheck -check-prefix INVALID-TWOLEVELHINTS-OFFSET %s +INVALID-TWOLEVELHINTS-OFFSET: macho-invalid-twolevelhints-offset': truncated or malformed object (offset 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-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) -- 2.7.4