From b910bebc300dafb30569cecc3017b446ea8eafa0 Mon Sep 17 00:00:00 2001 From: Zixu Wang <9819235+zixu-w@users.noreply.github.com> Date: Wed, 8 May 2024 18:53:15 -0700 Subject: [llvm][MachO] Fix integer truncation in rebase/bind parsing (#89337) `Count` and `Skip` should use `uint64_t` as they are encoded/decoded using 64-bit ULEB128. In `*_OPCODE_DO_*_ULEB_TIMES_SKIPPING_ULEB`, `Skip` could be encoded as a two's complement for moving `SegmentOffset` backwards. Having a 32-bit `Skip` truncates the encoded value and leads to a malformed `AdvanceAmount` and invalid `SegmentOffset` that extends past valid sections. --- llvm/lib/Object/MachOObjectFile.cpp | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) (limited to 'llvm/lib/Object/MachOObjectFile.cpp') diff --git a/llvm/lib/Object/MachOObjectFile.cpp b/llvm/lib/Object/MachOObjectFile.cpp index 06186ad..ef390ce 100644 --- a/llvm/lib/Object/MachOObjectFile.cpp +++ b/llvm/lib/Object/MachOObjectFile.cpp @@ -3515,7 +3515,7 @@ void MachORebaseEntry::moveNext() { uint8_t Byte = *Ptr++; uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK; uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK; - uint32_t Count, Skip; + uint64_t Count, Skip; const char *error = nullptr; switch (Opcode) { case MachO::REBASE_OPCODE_DONE: @@ -3854,7 +3854,7 @@ void MachOBindEntry::moveNext() { uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK; int8_t SignExtended; const uint8_t *SymStart; - uint32_t Count, Skip; + uint64_t Count, Skip; const char *error = nullptr; switch (Opcode) { case MachO::BIND_OPCODE_DONE: @@ -4384,18 +4384,18 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) { // that fully contains a pointer at that location. Multiple fixups in a bind // (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can // be tested via the Count and Skip parameters. -const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex, - uint64_t SegOffset, - uint8_t PointerSize, - uint32_t Count, - uint32_t Skip) { +const char *BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex, + uint64_t SegOffset, + uint8_t PointerSize, + uint64_t Count, + uint64_t Skip) { if (SegIndex == -1) return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB"; if (SegIndex >= MaxSegIndex) return "bad segIndex (too large)"; - for (uint32_t i = 0; i < Count; ++i) { - uint32_t Start = SegOffset + i * (PointerSize + Skip); - uint32_t End = Start + PointerSize; + for (uint64_t i = 0; i < Count; ++i) { + uint64_t Start = SegOffset + i * (PointerSize + Skip); + uint64_t End = Start + PointerSize; bool Found = false; for (const SectionInfo &SI : Sections) { if (SI.SegmentIndex != SegIndex) -- cgit v1.1