diff options
22 files changed, 351 insertions, 52 deletions
diff --git a/llvm/include/llvm/Object/MachO.h b/llvm/include/llvm/Object/MachO.h index 019f777ed65..1ee571cce73 100644 --- a/llvm/include/llvm/Object/MachO.h +++ b/llvm/include/llvm/Object/MachO.h @@ -146,7 +146,7 @@ public: MachORebaseEntry(Error *Err, const MachOObjectFile *O, ArrayRef<uint8_t> opcodes, bool is64Bit); - uint32_t segmentIndex() const; + int32_t segmentIndex() const; uint64_t segmentOffset() const; StringRef typeName() const; StringRef segmentName() const; @@ -161,19 +161,18 @@ private: friend class MachOObjectFile; void moveToFirst(); void moveToEnd(); - uint64_t readULEB128(); + uint64_t readULEB128(const char **error); Error *E; const MachOObjectFile *O; ArrayRef<uint8_t> Opcodes; const uint8_t *Ptr; uint64_t SegmentOffset; - uint32_t SegmentIndex; + int32_t SegmentIndex; uint64_t RemainingLoopCount; uint64_t AdvanceAmount; uint8_t RebaseType; uint8_t PointerSize; - bool Malformed; bool Done; }; typedef content_iterator<MachORebaseEntry> rebase_iterator; @@ -231,7 +230,6 @@ private: uint8_t BindType; uint8_t PointerSize; Kind TableKind; - bool Malformed; bool Done; }; typedef content_iterator<MachOBindEntry> bind_iterator; @@ -378,6 +376,22 @@ public: SegIndex, SegOffset); } + /// For use with a SegIndex,SegOffset pair in MachORebaseEntry::moveNext() to + /// validate a MachORebaseEntry. + const char *RebaseEntryCheckSegAndOffset(int32_t SegIndex, uint64_t SegOffset, + bool endInvalid) const { + return BindRebaseSectionTable->checkSegAndOffset(SegIndex, SegOffset, + endInvalid); + } + /// For use in MachORebaseEntry::moveNext() to validate a MachORebaseEntry for + /// the REBASE_OPCODE_DO_*_TIMES* opcodes. + const char *RebaseEntryCheckCountAndSkip(uint32_t Count, uint32_t Skip, + uint8_t PointerSize, int32_t SegIndex, + uint64_t SegOffset) const { + return BindRebaseSectionTable->checkCountAndSkip(Count, Skip, PointerSize, + SegIndex, SegOffset); + } + /// For use with the SegIndex of a checked Mach-O Bind or Rebase entry to /// get the segment name. StringRef BindRebaseSegmentName(int32_t SegIndex) const { diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 0ca1fea6179..8124c18f30e 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -2758,8 +2758,8 @@ iterator_range<export_iterator> MachOObjectFile::exports() const { MachORebaseEntry::MachORebaseEntry(Error *E, const MachOObjectFile *O, ArrayRef<uint8_t> Bytes, bool is64Bit) : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), - SegmentIndex(0), RemainingLoopCount(0), AdvanceAmount(0), RebaseType(0), - PointerSize(is64Bit ? 8 : 4), Malformed(false), Done(false) {} + SegmentIndex(-1), RemainingLoopCount(0), AdvanceAmount(0), RebaseType(0), + PointerSize(is64Bit ? 8 : 4), Done(false) {} void MachORebaseEntry::moveToFirst() { Ptr = Opcodes.begin(); @@ -2773,22 +2773,31 @@ void MachORebaseEntry::moveToEnd() { } void MachORebaseEntry::moveNext() { + ErrorAsOutParameter ErrAsOutParam(E); // If in the middle of some loop, move to next rebasing in loop. SegmentOffset += AdvanceAmount; if (RemainingLoopCount) { --RemainingLoopCount; return; } - if (Ptr == Opcodes.end()) { + if (Ptr >= Opcodes.end()) { + if (Opcodes.begin() != Opcodes.end() && Done != true) { + *E = malformedError("missing REBASE_OPCODE_DONE at end of opcodes"); + moveToEnd(); + return; + } Done = true; return; } bool More = true; - while (More && !Malformed) { + while (More) { // Parse next opcode and set up next loop. + const uint8_t *OpcodeStart = Ptr; uint8_t Byte = *Ptr++; uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK; uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK; + uint32_t Count, Skip; + const char *error = nullptr; switch (Opcode) { case MachO::REBASE_OPCODE_DONE: More = false; @@ -2798,6 +2807,13 @@ void MachORebaseEntry::moveNext() { break; case MachO::REBASE_OPCODE_SET_TYPE_IMM: RebaseType = ImmValue; + if (RebaseType > MachO::REBASE_TYPE_TEXT_PCREL32) { + *E = malformedError("for REBASE_OPCODE_SET_TYPE_IMM bad bind type: " + + Twine((int)RebaseType) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE( "mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_SET_TYPE_IMM: " @@ -2805,7 +2821,23 @@ void MachORebaseEntry::moveNext() { break; case MachO::REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: SegmentIndex = ImmValue; - SegmentOffset = readULEB128(); + SegmentOffset = readULEB128(&error); + if (error) { + *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } + error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, + true); + if (error) { + *E = malformedError("for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE( "mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB: " @@ -2814,22 +2846,80 @@ void MachORebaseEntry::moveNext() { << "\n"); break; case MachO::REBASE_OPCODE_ADD_ADDR_ULEB: - SegmentOffset += readULEB128(); + SegmentOffset += readULEB128(&error); + if (error) { + *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } + error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, + true); + if (error) { + *E = malformedError("for REBASE_OPCODE_ADD_ADDR_ULEB " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE("mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_ADD_ADDR_ULEB: " << format("SegmentOffset=0x%06X", SegmentOffset) << "\n"); break; case MachO::REBASE_OPCODE_ADD_ADDR_IMM_SCALED: + error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, + true); + if (error) { + *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } SegmentOffset += ImmValue * PointerSize; + error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, + false); + if (error) { + *E = malformedError("for REBASE_OPCODE_ADD_ADDR_IMM_SCALED " + " (after adding immediate times the pointer size) " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE("mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_ADD_ADDR_IMM_SCALED: " << format("SegmentOffset=0x%06X", SegmentOffset) << "\n"); break; case MachO::REBASE_OPCODE_DO_REBASE_IMM_TIMES: + error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, + true); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } AdvanceAmount = PointerSize; - RemainingLoopCount = ImmValue - 1; + Skip = 0; + Count = ImmValue; + if (ImmValue != 0) + RemainingLoopCount = ImmValue - 1; + else + RemainingLoopCount = 0; + error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, + SegmentIndex, SegmentOffset); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_IMM_TIMES " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE( "mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_IMM_TIMES: " @@ -2839,8 +2929,38 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES: + error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, + true); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } AdvanceAmount = PointerSize; - RemainingLoopCount = readULEB128() - 1; + Skip = 0; + Count = readULEB128(&error); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } + if (Count != 0) + RemainingLoopCount = Count - 1; + else + RemainingLoopCount = 0; + error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, + SegmentIndex, SegmentOffset); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE( "mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES: " @@ -2850,8 +2970,35 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: - AdvanceAmount = readULEB128() + PointerSize; + error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, + true); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } + Skip = readULEB128(&error); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } + AdvanceAmount = Skip + PointerSize; + Count = 1; RemainingLoopCount = 0; + error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, + SegmentIndex, SegmentOffset); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB " + + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE( "mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB: " @@ -2861,8 +3008,46 @@ void MachORebaseEntry::moveNext() { << "\n"); return; case MachO::REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: - RemainingLoopCount = readULEB128() - 1; - AdvanceAmount = readULEB128() + PointerSize; + error = O->RebaseEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, + true); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" + "ULEB " + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } + Count = readULEB128(&error); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" + "ULEB " + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } + if (Count != 0) + RemainingLoopCount = Count - 1; + else + RemainingLoopCount = 0; + Skip = readULEB128(&error); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" + "ULEB " + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } + AdvanceAmount = Skip + PointerSize; + + error = O->RebaseEntryCheckCountAndSkip(Count, Skip, PointerSize, + SegmentIndex, SegmentOffset); + if (error) { + *E = malformedError("for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_" + "ULEB " + Twine(error) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } DEBUG_WITH_TYPE( "mach-o-rebase", llvm::dbgs() << "REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB: " @@ -2872,23 +3057,25 @@ void MachORebaseEntry::moveNext() { << "\n"); return; default: - Malformed = true; + *E = malformedError("bad rebase info (bad opcode value 0x" + + utohexstr(Opcode) + " for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; } } } -uint64_t MachORebaseEntry::readULEB128() { +uint64_t MachORebaseEntry::readULEB128(const char **error) { unsigned Count; - uint64_t Result = decodeULEB128(Ptr, &Count); + uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error); Ptr += Count; - if (Ptr > Opcodes.end()) { + if (Ptr > Opcodes.end()) Ptr = Opcodes.end(); - Malformed = true; - } return Result; } -uint32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; } +int32_t MachORebaseEntry::segmentIndex() const { return SegmentIndex; } uint64_t MachORebaseEntry::segmentOffset() const { return SegmentOffset; } @@ -2956,8 +3143,7 @@ MachOBindEntry::MachOBindEntry(Error *E, const MachOObjectFile *O, : E(E), O(O), Opcodes(Bytes), Ptr(Bytes.begin()), SegmentOffset(0), SegmentIndex(-1), LibraryOrdinalSet(false), Ordinal(0), Flags(0), Addend(0), RemainingLoopCount(0), AdvanceAmount(0), BindType(0), - PointerSize(is64Bit ? 8 : 4), TableKind(BK), Malformed(false), - Done(false) {} + PointerSize(is64Bit ? 8 : 4), TableKind(BK), Done(false) {} void MachOBindEntry::moveToFirst() { Ptr = Opcodes.begin(); @@ -2978,12 +3164,17 @@ void MachOBindEntry::moveNext() { --RemainingLoopCount; return; } - if (Ptr == Opcodes.end()) { + if (Ptr >= Opcodes.end()) { + if (Opcodes.begin() != Opcodes.end() && Done != true) { + *E = malformedError("missing BIND_OPCODE_DONE at end of opcodes"); + moveToEnd(); + return; + } Done = true; return; } bool More = true; - while (More && !Malformed) { + while (More) { // Parse next opcode and set up next loop. const uint8_t *OpcodeStart = Ptr; uint8_t Byte = *Ptr++; @@ -3008,11 +3199,17 @@ void MachOBindEntry::moveNext() { break; } More = false; - Done = true; moveToEnd(); DEBUG_WITH_TYPE("mach-o-bind", llvm::dbgs() << "BIND_OPCODE_DONE\n"); break; case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_IMM: + if (TableKind == Kind::Weak) { + *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_IMM not allowed in " + "weak bind table for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } Ordinal = ImmValue; LibraryOrdinalSet = true; if (ImmValue > O->getLibraryCount()) { @@ -3029,6 +3226,13 @@ void MachOBindEntry::moveNext() { << "Ordinal=" << Ordinal << "\n"); break; case MachO::BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB: + if (TableKind == Kind::Weak) { + *E = malformedError("BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB not allowed in " + "weak bind table for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } Ordinal = readULEB128(&error); LibraryOrdinalSet = true; if (error) { @@ -3052,6 +3256,13 @@ void MachOBindEntry::moveNext() { << "Ordinal=" << Ordinal << "\n"); break; case MachO::BIND_OPCODE_SET_DYLIB_SPECIAL_IMM: + if (TableKind == Kind::Weak) { + *E = malformedError("BIND_OPCODE_SET_DYLIB_SPECIAL_IMM not allowed in " + "weak bind table for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } if (ImmValue) { SignExtended = MachO::BIND_OPCODE_MASK | ImmValue; Ordinal = SignExtended; @@ -3118,8 +3329,6 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - if (TableKind == Kind::Lazy) - Malformed = true; DEBUG_WITH_TYPE( "mach-o-bind", llvm::dbgs() << "BIND_OPCODE_SET_ADDEND_SLEB: " @@ -3202,6 +3411,13 @@ void MachOBindEntry::moveNext() { SegmentOffset) << "\n"); return; case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: + if (TableKind == Kind::Lazy) { + *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB not allowed in " + "lazy bind table for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB " + @@ -3245,8 +3461,6 @@ void MachOBindEntry::moveNext() { return; } RemainingLoopCount = 0; - if (TableKind == Kind::Lazy) - Malformed = true; DEBUG_WITH_TYPE( "mach-o-bind", llvm::dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB: " @@ -3256,6 +3470,13 @@ void MachOBindEntry::moveNext() { << "\n"); return; case MachO::BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: + if (TableKind == Kind::Lazy) { + *E = malformedError("BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED not " + "allowed in lazy bind table for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } error = O->BindEntryCheckSegAndOffset(SegmentIndex, SegmentOffset, true); if (error) { *E = malformedError("for BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED " + @@ -3290,8 +3511,6 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - if (TableKind == Kind::Lazy) - Malformed = true; DEBUG_WITH_TYPE("mach-o-bind", llvm::dbgs() << "BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED: " @@ -3299,6 +3518,13 @@ void MachOBindEntry::moveNext() { SegmentOffset) << "\n"); return; case MachO::BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: + if (TableKind == Kind::Lazy) { + *E = malformedError("BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB not " + "allowed in lazy bind table for opcode at: 0x" + + utohexstr(OpcodeStart - Opcodes.begin())); + moveToEnd(); + return; + } Count = readULEB128(&error); if (Count != 0) RemainingLoopCount = Count - 1; @@ -3351,8 +3577,6 @@ void MachOBindEntry::moveNext() { moveToEnd(); return; } - if (TableKind == Kind::Lazy) - Malformed = true; DEBUG_WITH_TYPE( "mach-o-bind", llvm::dbgs() << "BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB: " @@ -3362,7 +3586,6 @@ void MachOBindEntry::moveNext() { << "\n"); return; default: - Malformed = true; *E = malformedError("bad bind info (bad opcode value 0x" + utohexstr(Opcode) + " for opcode at: 0x" + utohexstr(OpcodeStart - Opcodes.begin())); @@ -3376,10 +3599,8 @@ uint64_t MachOBindEntry::readULEB128(const char **error) { unsigned Count; uint64_t Result = decodeULEB128(Ptr, &Count, Opcodes.end(), error); Ptr += Count; - if (Ptr > Opcodes.end()) { + if (Ptr > Opcodes.end()) Ptr = Opcodes.end(); - Malformed = true; - } return Result; } @@ -3387,10 +3608,8 @@ int64_t MachOBindEntry::readSLEB128(const char **error) { unsigned Count; int64_t Result = decodeSLEB128(Ptr, &Count, Opcodes.end(), error); Ptr += Count; - if (Ptr > Opcodes.end()) { + if (Ptr > Opcodes.end()) Ptr = Opcodes.end(); - Malformed = true; - } return Result; } @@ -3473,12 +3692,12 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) { } // For use with a SegIndex,SegOffset pair in MachOBindEntry::moveNext() to -// validate a MachOBindEntry. +// validate a MachOBindEntry or MachORebaseEntry. const char * BindRebaseSegInfo::checkSegAndOffset(int32_t SegIndex, uint64_t SegOffset, bool endInvalid) { if (SegIndex == -1) - return "missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"; + return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"; if (SegIndex >= MaxSegIndex) return "bad segIndex (too large)"; for (const SectionInfo &SI : Sections) { @@ -3496,12 +3715,14 @@ const char * BindRebaseSegInfo::checkSegAndOffset(int32_t SegIndex, } // For use in MachOBindEntry::moveNext() to validate a MachOBindEntry for -// the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode. The SegIndex -// and SegOffset must have been already checked. +// the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode and for use in +// MachORebaseEntry::moveNext() to validate a MachORebaseEntry for +// REBASE_OPCODE_DO_*_TIMES* opcodes. The SegIndex and SegOffset must have +// been already checked. const char * BindRebaseSegInfo::checkCountAndSkip(uint32_t Count, uint32_t Skip, uint8_t PointerSize, - int32_t SegIndex, - uint64_t SegOffset) { + int32_t SegIndex, + uint64_t SegOffset) { const SectionInfo &SI = findSection(SegIndex, SegOffset); uint64_t addr = SI.SegmentStartAddress + SegOffset; if (addr >= SI.Address + SI.Size) @@ -3509,8 +3730,15 @@ const char * BindRebaseSegInfo::checkCountAndSkip(uint32_t Count, uint32_t Skip, uint64_t i = 0; if (Count > 1) i = (Skip + PointerSize) * (Count - 1); - if (addr + i >= SI.Address + SI.Size) - return "bad count and skip, too large"; + else if (Count == 1) + i = Skip + PointerSize; + if (addr + i >= SI.Address + SI.Size) { + // For rebase opcodes they can step from one section to another. + uint64_t TrailingSegOffset = (addr + i) - SI.SegmentStartAddress; + const char *error = checkSegAndOffset(SegIndex, TrailingSegOffset, false); + if (error) + return "bad count and skip, too large"; + } return nullptr; } diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-bind-missing-done b/llvm/test/tools/llvm-objdump/Inputs/macho-bind-missing-done Binary files differnew file mode 100755 index 00000000000..ced8840ea83 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-bind-missing-done diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-add-addr-imm-scaled b/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-add-addr-imm-scaled Binary files differnew file mode 100755 index 00000000000..a7d5abeef74 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-add-addr-imm-scaled diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb b/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb Binary files differnew file mode 100755 index 00000000000..1f0288342c4 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do_bind_add_addr_uleb b/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do_bind_add_addr_uleb Binary files differnew file mode 100755 index 00000000000..63f034688ff --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-lazy-do_bind_add_addr_uleb diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-imm-scaled b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-imm-scaled Binary files differnew file mode 100755 index 00000000000..6b0c1bd4566 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-imm-scaled diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb Binary files differnew file mode 100755 index 00000000000..e409590dc2d --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb-too-big b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb-too-big Binary files differnew file mode 100755 index 00000000000..68b72ec6a3b --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-add-addr-uleb-too-big diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-bad-opcode-value b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-bad-opcode-value Binary files differnew file mode 100755 index 00000000000..59e0d4fe619 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-bad-opcode-value diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-imm-times b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-imm-times Binary files differnew file mode 100755 index 00000000000..be2286baf6b --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-imm-times diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-missing-done b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-missing-done Binary files differnew file mode 100755 index 00000000000..633a1175607 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-missing-done diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-seg-too-big b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-seg-too-big Binary files differnew file mode 100755 index 00000000000..12b52328a96 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-seg-too-big diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-segoff-too-big b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-segoff-too-big Binary files differnew file mode 100755 index 00000000000..4dfb19dea80 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-segoff-too-big diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-set-type-imm b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-set-type-imm Binary files differnew file mode 100755 index 00000000000..947db0ee915 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-set-type-imm diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-malformed-uleb128 b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-malformed-uleb128 Binary files differnew file mode 100755 index 00000000000..045f425b223 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-malformed-uleb128 diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times Binary files differnew file mode 100755 index 00000000000..c12f256f660 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times-skipping-uleb b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times-skipping-uleb Binary files differnew file mode 100755 index 00000000000..5bec8ca1157 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-rebase-uleb-times-skipping-uleb diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-imm b/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-imm Binary files differnew file mode 100755 index 00000000000..1d8785c55d0 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-imm diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-uleb b/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-uleb Binary files differnew file mode 100755 index 00000000000..bf7babc09e6 --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-ordinal-uleb diff --git a/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-special-imm b/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-special-imm Binary files differnew file mode 100755 index 00000000000..d13f6ec981e --- /dev/null +++ b/llvm/test/tools/llvm-objdump/Inputs/macho-weak-bind-set-dylib-special-imm diff --git a/llvm/test/tools/llvm-objdump/macho-bad-bind.test b/llvm/test/tools/llvm-objdump/macho-bad-bind.test index dea86bb6514..baf8dee3234 100644 --- a/llvm/test/tools/llvm-objdump/macho-bad-bind.test +++ b/llvm/test/tools/llvm-objdump/macho-bad-bind.test @@ -29,7 +29,7 @@ RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-add_addr_uleb 2>&1 | Fil ADD_ADDR_ULEB: macho-bind-add_addr_uleb': truncated or malformed object (for BIND_OPCODE_ADD_ADDR_ULEB bad segOffset, too large for opcode at: 0x17) RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-do-bind-no-segIndex 2>&1 | FileCheck -check-prefix BIND-NO-SEGINDEX %s -BIND-NO-SEGINDEX: macho-bind-do-bind-no-segIndex': truncated or malformed object (for BIND_OPCODE_DO_BIND missing preceding BIND_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB for opcode at: 0x15) +BIND-NO-SEGINDEX: macho-bind-do-bind-no-segIndex': truncated or malformed object (for BIND_OPCODE_DO_BIND missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB for opcode at: 0x15) RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-bind-add-addr-uleb 2>&1 | FileCheck -check-prefix ADD-ADDR-ULEB %s ADD-ADDR-ULEB: macho-bind-bind-add-addr-uleb': truncated or malformed object (for BIND_OPCODE_ADD_ADDR_ULEB (after adding ULEB) bad segOffset, too large for opcode at: 0x18) @@ -48,3 +48,60 @@ DO-BIND-NO-DYLIB-ORDINAL: macho-do-bind-no-dylib-ordinal': truncated or malforme RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-bad-opcode-value 2>&1 | FileCheck -check-prefix BAD-OPCODE-VALUE %s BAD-OPCODE-VALUE: macho-bind-bad-opcode-value': truncated or malformed object (bad bind info (bad opcode value 0xD0 for opcode at: 0x18) + +RUN: not llvm-objdump -macho -lazy-bind %p/Inputs/macho-lazy-do_bind_add_addr_uleb 2>&1 | FileCheck -check-prefix LAZY_DO_BIND_ADD_ADDR_ULEB %s +LAZY_DO_BIND_ADD_ADDR_ULEB: macho-lazy-do_bind_add_addr_uleb': truncated or malformed object (BIND_OPCODE_DO_BIND_ADD_ADDR_ULEB not allowed in lazy bind table for opcode at: 0xC) + +RUN: not llvm-objdump -macho -lazy-bind %p/Inputs/macho-lazy-do-bind-add-addr-imm-scaled 2>&1 | FileCheck -check-prefix LAZY-DO-BIND-ADD-ADDR-IMM-SCALED %s +LAZY-DO-BIND-ADD-ADDR-IMM-SCALED: macho-lazy-do-bind-add-addr-imm-scaled': truncated or malformed object (BIND_OPCODE_DO_BIND_ADD_ADDR_IMM_SCALED not allowed in lazy bind table for opcode at: 0xC) + +RUN: not llvm-objdump -macho -lazy-bind %p/Inputs/macho-lazy-do-bind-uleb-times-skipping-uleb 2>&1 | FileCheck -check-prefix LAZY-DO-BIND-ULEB-TIMES-SKIPPING-ULEB %s +LAZY-DO-BIND-ULEB-TIMES-SKIPPING-ULEB: macho-lazy-do-bind-uleb-times-skipping-uleb': truncated or malformed object (BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB not allowed in lazy bind table for opcode at: 0xC) + +RUN: not llvm-objdump -macho -weak-bind %p/Inputs/macho-weak-bind-set-dylib-ordinal-imm 2>&1 | FileCheck -check-prefix WEAK-BIND-SET-DYLIB-ORDINAL-IMM %s +WEAK-BIND-SET-DYLIB-ORDINAL-IMM: macho-weak-bind-set-dylib-ordinal-imm': truncated or malformed object (BIND_OPCODE_SET_DYLIB_ORDINAL_IMM not allowed in weak bind table for opcode at: 0x2) + +RUN: not llvm-objdump -macho -weak-bind %p/Inputs/macho-weak-bind-set-dylib-ordinal-uleb 2>&1 | FileCheck -check-prefix WEAK-BIND-SET-DYLIB-ORDINAL-ULEB %s +WEAK-BIND-SET-DYLIB-ORDINAL-ULEB: macho-weak-bind-set-dylib-ordinal-uleb': truncated or malformed object (BIND_OPCODE_SET_DYLIB_ORDINAL_ULEB not allowed in weak bind table for opcode at: 0x2) + +RUN: not llvm-objdump -macho -weak-bind %p/Inputs/macho-weak-bind-set-dylib-special-imm 2>&1 | FileCheck -check-prefix WEAK-BIND-SET-DYLIB-SPECIAL-IMM %s +WEAK-BIND-SET-DYLIB-SPECIAL-IMM: macho-weak-bind-set-dylib-special-imm': truncated or malformed object (BIND_OPCODE_SET_DYLIB_SPECIAL_IMM not allowed in weak bind table for opcode at: 0x2) + +RUN: not llvm-objdump -macho -bind %p/Inputs/macho-bind-missing-done 2>&1 | FileCheck -check-prefix BIND-MISSING-DONE %s +BIND-MISSING-DONE: macho-bind-missing-done': truncated or malformed object (missing BIND_OPCODE_DONE at end of opcodes) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-set-type-imm 2>&1 | FileCheck -check-prefix REBASE-SET-TYPE-IMM %s +REBASE-SET-TYPE-IMM: macho-rebase-set-type-imm': truncated or malformed object (for REBASE_OPCODE_SET_TYPE_IMM bad bind type: 5 for opcode at: 0x0) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-uleb-malformed-uleb128 2>&1 | FileCheck -check-prefix REBASE-ULEB-MALFORMED-ULEB128 %s +REBASE-ULEB-MALFORMED-ULEB128: macho-rebase-uleb-malformed-uleb128': truncated or malformed object (for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB malformed uleb128, extends past end for opcode at: 0x1) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-seg-too-big 2>&1 | FileCheck -check-prefix REBASE-SEG-TOO-BIG %s +REBASE-SEG-TOO-BIG: macho-rebase-seg-too-big': truncated or malformed object (for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB bad segIndex (too large) for opcode at: 0x1) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-segoff-too-big 2>&1 | FileCheck -check-prefix REBASE-SEGOFF-TOO-BIG %s +REBASE-SEGOFF-TOO-BIG: macho-rebase-segoff-too-big': truncated or malformed object (for REBASE_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB bad segOffset, too large for opcode at: 0x1) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-add-addr-uleb 2>&1 | FileCheck -check-prefix REBASE-ADD-ADDR-ULEB %s +REBASE-ADD-ADDR-ULEB: macho-rebase-add-addr-uleb': truncated or malformed object (for REBASE_OPCODE_ADD_ADDR_ULEB bad segOffset, too large for opcode at: 0x3) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-add-addr-imm-scaled 2>&1 | FileCheck -check-prefix REBASE-ADD-ADDR-IMM-SCALED %s +REBASE-ADD-ADDR-IMM-SCALED: macho-rebase-add-addr-imm-scaled': truncated or malformed object (for REBASE_OPCODE_ADD_ADDR_IMM_SCALED (after adding immediate times the pointer size) bad segOffset, too large for opcode at: 0x3) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-imm-times 2>&1 | FileCheck -check-prefix REBASE-IMM-TIMES %s +REBASE-IMM-TIMES: macho-rebase-imm-times': truncated or malformed object (for REBASE_OPCODE_DO_REBASE_IMM_TIMES bad count and skip, too large for opcode at: 0x3) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-uleb-times 2>&1 | FileCheck -check-prefix REBASE-ULEB-TIMES %s +REBASE-ULEB-TIMES: macho-rebase-uleb-times': truncated or malformed object (for REBASE_OPCODE_DO_REBASE_ULEB_TIMES bad count and skip, too large for opcode at: 0x3) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-add-addr-uleb-too-big 2>&1 | FileCheck -check-prefix REBASE-ADD-ADDR-ULEB-TOO-BIG %s +REBASE-ADD-ADDR-ULEB-TOO-BIG: macho-rebase-add-addr-uleb-too-big': truncated or malformed object (for REBASE_OPCODE_DO_REBASE_ADD_ADDR_ULEB bad count and skip, too large for opcode at: 0x3) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-uleb-times-skipping-uleb 2>&1 | FileCheck -check-prefix REBASE-ULEB-TIMES-SKIPPING-ULEB %s +REBASE-ULEB-TIMES-SKIPPING-ULEB: macho-rebase-uleb-times-skipping-uleb': truncated or malformed object (for REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB bad count and skip, too large for opcode at: 0x3) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-bad-opcode-value 2>&1 | FileCheck -check-prefix REBASE-BAD-OPCODE-VALUE %s +REBASE-BAD-OPCODE-VALUE: macho-rebase-bad-opcode-value': truncated or malformed object (bad rebase info (bad opcode value 0xD0 for opcode at: 0x4) + +RUN: not llvm-objdump -macho -rebase %p/Inputs/macho-rebase-missing-done 2>&1 | FileCheck -check-prefix REBASE-MISSING-DONE %s +REBASE-MISSING-DONE: macho-rebase-missing-done': truncated or malformed object (missing REBASE_OPCODE_DONE at end of opcodes) |