Skip to content

Commit b43c97b

Browse files
committed
[llvm][MachO] Fix integer truncation in rebase/bind parsing
`Skip` could use up the full 64 bits decoded by `readULEB128` for some rebase/bind opcodes. 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.
1 parent 39bfdb7 commit b43c97b

File tree

2 files changed

+18
-8
lines changed

2 files changed

+18
-8
lines changed

llvm/include/llvm/Object/MachO.h

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -136,7 +136,7 @@ class BindRebaseSegInfo {
136136
// Used to check a Mach-O Bind or Rebase entry for errors when iterating.
137137
const char* checkSegAndOffsets(int32_t SegIndex, uint64_t SegOffset,
138138
uint8_t PointerSize, uint32_t Count=1,
139-
uint32_t Skip=0);
139+
uint64_t Skip=0);
140140
// Used with valid SegIndex/SegOffset values from checked entries.
141141
StringRef segmentName(int32_t SegIndex);
142142
StringRef sectionName(int32_t SegIndex, uint64_t SegOffset);
@@ -577,7 +577,7 @@ class MachOObjectFile : public ObjectFile {
577577
// This is used by MachOBindEntry::moveNext() to validate a MachOBindEntry.
578578
const char *BindEntryCheckSegAndOffsets(int32_t SegIndex, uint64_t SegOffset,
579579
uint8_t PointerSize, uint32_t Count=1,
580-
uint32_t Skip=0) const {
580+
uint64_t Skip=0) const {
581581
return BindRebaseSectionTable->checkSegAndOffsets(SegIndex, SegOffset,
582582
PointerSize, Count, Skip);
583583
}
@@ -592,7 +592,7 @@ class MachOObjectFile : public ObjectFile {
592592
uint64_t SegOffset,
593593
uint8_t PointerSize,
594594
uint32_t Count=1,
595-
uint32_t Skip=0) const {
595+
uint64_t Skip=0) const {
596596
return BindRebaseSectionTable->checkSegAndOffsets(SegIndex, SegOffset,
597597
PointerSize, Count, Skip);
598598
}

llvm/lib/Object/MachOObjectFile.cpp

Lines changed: 15 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -3515,7 +3515,12 @@ void MachORebaseEntry::moveNext() {
35153515
uint8_t Byte = *Ptr++;
35163516
uint8_t ImmValue = Byte & MachO::REBASE_IMMEDIATE_MASK;
35173517
uint8_t Opcode = Byte & MachO::REBASE_OPCODE_MASK;
3518-
uint32_t Count, Skip;
3518+
uint32_t Count;
3519+
// For opcode REBASE_OPCODE_DO_REBASE_ULEB_TIMES_SKIPPING_ULEB, the ULEB128
3520+
// encoded Skip amount could be two's complements for moving SegmentOffset
3521+
// to a lower address. Skip should be the same integer width as
3522+
// SegmentOffset and AdvanceAmount to prevent truncating.
3523+
uint64_t Skip;
35193524
const char *error = nullptr;
35203525
switch (Opcode) {
35213526
case MachO::REBASE_OPCODE_DONE:
@@ -3854,7 +3859,12 @@ void MachOBindEntry::moveNext() {
38543859
uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK;
38553860
int8_t SignExtended;
38563861
const uint8_t *SymStart;
3857-
uint32_t Count, Skip;
3862+
uint32_t Count;
3863+
// For opcode BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB, the ULEB128
3864+
// encoded Skip amount could be two's complements for moving SegmentOffset
3865+
// to a lower address. Skip should be the same integer width as
3866+
// SegmentOffset and AdvanceAmount to prevent truncating.
3867+
uint64_t Skip;
38583868
const char *error = nullptr;
38593869
switch (Opcode) {
38603870
case MachO::BIND_OPCODE_DONE:
@@ -4388,14 +4398,14 @@ const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex,
43884398
uint64_t SegOffset,
43894399
uint8_t PointerSize,
43904400
uint32_t Count,
4391-
uint32_t Skip) {
4401+
uint64_t Skip) {
43924402
if (SegIndex == -1)
43934403
return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB";
43944404
if (SegIndex >= MaxSegIndex)
43954405
return "bad segIndex (too large)";
43964406
for (uint32_t i = 0; i < Count; ++i) {
4397-
uint32_t Start = SegOffset + i * (PointerSize + Skip);
4398-
uint32_t End = Start + PointerSize;
4407+
uint64_t Start = SegOffset + i * (PointerSize + Skip);
4408+
uint64_t End = Start + PointerSize;
43994409
bool Found = false;
44004410
for (const SectionInfo &SI : Sections) {
44014411
if (SI.SegmentIndex != SegIndex)

0 commit comments

Comments
 (0)