Skip to content

Commit b910beb

Browse files
authored
[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.
1 parent ea126ae commit b910beb

File tree

4 files changed

+534
-17
lines changed

4 files changed

+534
-17
lines changed

llvm/include/llvm/Object/MachO.h

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -134,9 +134,9 @@ class BindRebaseSegInfo {
134134
BindRebaseSegInfo(const MachOObjectFile *Obj);
135135

136136
// Used to check a Mach-O Bind or Rebase entry for errors when iterating.
137-
const char* checkSegAndOffsets(int32_t SegIndex, uint64_t SegOffset,
138-
uint8_t PointerSize, uint32_t Count=1,
139-
uint32_t Skip=0);
137+
const char *checkSegAndOffsets(int32_t SegIndex, uint64_t SegOffset,
138+
uint8_t PointerSize, uint64_t Count = 1,
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);
@@ -576,8 +576,9 @@ class MachOObjectFile : public ObjectFile {
576576
//
577577
// This is used by MachOBindEntry::moveNext() to validate a MachOBindEntry.
578578
const char *BindEntryCheckSegAndOffsets(int32_t SegIndex, uint64_t SegOffset,
579-
uint8_t PointerSize, uint32_t Count=1,
580-
uint32_t Skip=0) const {
579+
uint8_t PointerSize,
580+
uint64_t Count = 1,
581+
uint64_t Skip = 0) const {
581582
return BindRebaseSectionTable->checkSegAndOffsets(SegIndex, SegOffset,
582583
PointerSize, Count, Skip);
583584
}
@@ -591,8 +592,8 @@ class MachOObjectFile : public ObjectFile {
591592
const char *RebaseEntryCheckSegAndOffsets(int32_t SegIndex,
592593
uint64_t SegOffset,
593594
uint8_t PointerSize,
594-
uint32_t Count=1,
595-
uint32_t Skip=0) const {
595+
uint64_t Count = 1,
596+
uint64_t Skip = 0) const {
596597
return BindRebaseSectionTable->checkSegAndOffsets(SegIndex, SegOffset,
597598
PointerSize, Count, Skip);
598599
}

llvm/lib/Object/MachOObjectFile.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -3515,7 +3515,7 @@ 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+
uint64_t Count, Skip;
35193519
const char *error = nullptr;
35203520
switch (Opcode) {
35213521
case MachO::REBASE_OPCODE_DONE:
@@ -3854,7 +3854,7 @@ void MachOBindEntry::moveNext() {
38543854
uint8_t Opcode = Byte & MachO::BIND_OPCODE_MASK;
38553855
int8_t SignExtended;
38563856
const uint8_t *SymStart;
3857-
uint32_t Count, Skip;
3857+
uint64_t Count, Skip;
38583858
const char *error = nullptr;
38593859
switch (Opcode) {
38603860
case MachO::BIND_OPCODE_DONE:
@@ -4384,18 +4384,18 @@ BindRebaseSegInfo::BindRebaseSegInfo(const object::MachOObjectFile *Obj) {
43844384
// that fully contains a pointer at that location. Multiple fixups in a bind
43854385
// (such as with the BIND_OPCODE_DO_BIND_ULEB_TIMES_SKIPPING_ULEB opcode) can
43864386
// be tested via the Count and Skip parameters.
4387-
const char * BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex,
4388-
uint64_t SegOffset,
4389-
uint8_t PointerSize,
4390-
uint32_t Count,
4391-
uint32_t Skip) {
4387+
const char *BindRebaseSegInfo::checkSegAndOffsets(int32_t SegIndex,
4388+
uint64_t SegOffset,
4389+
uint8_t PointerSize,
4390+
uint64_t Count,
4391+
uint64_t Skip) {
43924392
if (SegIndex == -1)
43934393
return "missing preceding *_OPCODE_SET_SEGMENT_AND_OFFSET_ULEB";
43944394
if (SegIndex >= MaxSegIndex)
43954395
return "bad segIndex (too large)";
4396-
for (uint32_t i = 0; i < Count; ++i) {
4397-
uint32_t Start = SegOffset + i * (PointerSize + Skip);
4398-
uint32_t End = Start + PointerSize;
4396+
for (uint64_t i = 0; i < Count; ++i) {
4397+
uint64_t Start = SegOffset + i * (PointerSize + Skip);
4398+
uint64_t End = Start + PointerSize;
43994399
bool Found = false;
44004400
for (const SectionInfo &SI : Sections) {
44014401
if (SI.SegmentIndex != SegIndex)

0 commit comments

Comments
 (0)