From feb63b939132c645e1dc80311cd6560152c4be7f Mon Sep 17 00:00:00 2001 From: Kevin Enderby Date: Tue, 28 Feb 2017 21:47:07 +0000 Subject: Actually add error handling to unpacking the dyld compact bind and other tables. Providing a helpful error message to what the error is and where the error occurred based on which opcode it was associated with. MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit There have been handful of bug fixes dealing with bad bind info in object files, r294021 and r249845, which only put a band aid on the problem after a bad bind table was created after unpacking from its compact info. In these cases a bind table should have never been created and an error should have simply been generated. This change puts in place the plumbing to allow checking and returning of an error when the compact info is unpacked. This follows the model of iterators that can fail that Lang Hanes designed when fixing the problem for bad archives r275316 (or r275361). This change uses one of the existing test cases that now causes an error instead of printing <> after a bad bind table is created. The error uses the offset into the opcode table as shown with the macOS dyldinfo(1) tool to indicate where the error is and which opcode and which parameter is in error. For example the exiting test case has this lazy binding opcode table: % dyldinfo -opcodes test/tools/llvm-objdump/Inputs/bad-ordinal.macho-x86_64 … lazy binding opcodes: 0x0000 BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB(0x02, 0x00000010) 0x0002 BIND_OPCODE_SET_DYLIB_ORDINAL_IMM(2) In the test case the binary only has one library so setting the library ordinal to the value of 2 in the BIND_OPCODE_SET_DYLIB_ORDINAL_IMM opcode at 0x0002 above is an error. This now produces this error message: % llvm-objdump -lazy-bind bad-ordinal.macho-x86_64 … llvm-objdump: 'bad-ordinal.macho-x86_64': truncated or malformed object (for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad library ordinal: 2 (max 1) for opcode at: 0x2) This change provides the plumbing for the error handling and one example of an error message. Other error checks and test cases will be added in follow on commits. llvm-svn: 296527 --- llvm/lib/Object/MachOObjectFile.cpp | 38 ++++++++++++++++++++++++++----------- 1 file changed, 27 insertions(+), 11 deletions(-) (limited to 'llvm/lib/Object/MachOObjectFile.cpp') diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 928998330df..25f9a3d93dc 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -2272,6 +2272,10 @@ std::error_code MachOObjectFile::getLibraryShortNameByIndex(unsigned Index, return std::error_code(); } +uint32_t MachOObjectFile::getLibraryCount() const { + return Libraries.size(); +} + section_iterator MachOObjectFile::getRelocationRelocatedSection(relocation_iterator Rel) const { DataRefImpl Sec; @@ -2925,8 +2929,9 @@ iterator_range MachOObjectFile::rebaseTable() const { return rebaseTable(getDyldInfoRebaseOpcodes(), is64Bit()); } -MachOBindEntry::MachOBindEntry(ArrayRef Bytes, bool is64Bit, Kind BK) - : Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0), +MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O, + ArrayRef Bytes, bool is64Bit, Kind BK) + : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(0), Ordinal(0), Flags(0), Addend(0), RemainingLoopCount(0), AdvanceAmount(0), BindType(0), PointerSize(is64Bit ? 8 : 4), TableKind(BK), Malformed(false), Done(false) {} @@ -2943,6 +2948,7 @@ void MachOBindEntry::moveToEnd() { } void MachOBindEntry::moveNext() { + ErrorAsOutParameter ErrAsOutParam(E); // If in the middle of some loop, move to next binding in loop. SegmentOffset += AdvanceAmount; if (RemainingLoopCount) { @@ -2956,6 +2962,7 @@ void MachOBindEntry::moveNext() { bool More = true; while (More && !Malformed) { // Parse next opcode and set up next loop. + const uint8_t *OpcodeStart = Ptr; uint8_t Byte = *Ptr++; uint8_t ImmValue = Byte & MachO::BIND_IMMEDIATE_MASK; uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK; @@ -2982,6 +2989,14 @@ void MachOBindEntry::moveNext() { break; case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: Ordinal = ImmValue; + if (ImmValue > O->getLibraryCount()) { + *E = malformedError("for BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB bad " + "library ordinal: " + Twine((int)ImmValue) + " (max " + + Twine((int)O->getLibraryCount()) + ") for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE( "mach-o-bind", llvm::dbgs() << "BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: " @@ -3165,29 +3180,30 @@ bool MachOBindEntry::operator==(const MachOBindEntry &Other) const { } iterator_range -MachOObjectFile::bindTable(ArrayRef Opcodes, bool is64, +MachOObjectFile::bindTable(Error &Err, const MachOObjectFile *O, + ArrayRef Opcodes, bool is64, MachOBindEntry::Kind BKind) { - MachOBindEntry Start(Opcodes, is64, BKind); + MachOBindEntry Start(&Err, O, Opcodes, is64, BKind); Start.moveToFirst(); - MachOBindEntry Finish(Opcodes, is64, BKind); + MachOBindEntry Finish(&Err, O, Opcodes, is64, BKind); Finish.moveToEnd(); return make_range(bind_iterator(Start), bind_iterator(Finish)); } -iterator_range MachOObjectFile::bindTable() const { - return bindTable(getDyldInfoBindOpcodes(), is64Bit(), +iterator_range MachOObjectFile::bindTable(Error &Err) const { + return bindTable(Err, this, getDyldInfoBindOpcodes(), is64Bit(), MachOBindEntry::Kind::Regular); } -iterator_range MachOObjectFile::lazyBindTable() const { - return bindTable(getDyldInfoLazyBindOpcodes(), is64Bit(), +iterator_range MachOObjectFile::lazyBindTable(Error &Err) const { + return bindTable(Err, this, getDyldInfoLazyBindOpcodes(), is64Bit(), MachOBindEntry::Kind::Lazy); } -iterator_range MachOObjectFile::weakBindTable() const { - return bindTable(getDyldInfoWeakBindOpcodes(), is64Bit(), +iterator_range MachOObjectFile::weakBindTable(Error &Err) const { + return bindTable(Err, this, getDyldInfoWeakBindOpcodes(), is64Bit(), MachOBindEntry::Kind::Weak); } -- cgit v1.2.3