diff options
-rw-r--r-- | src/common/mac/macho_reader.cc | 40 | ||||
-rw-r--r-- | src/common/mac/macho_reader.h | 4 |
2 files changed, 34 insertions, 10 deletions
diff --git a/src/common/mac/macho_reader.cc b/src/common/mac/macho_reader.cc index 52f3c411..b4e3192a 100644 --- a/src/common/mac/macho_reader.cc +++ b/src/common/mac/macho_reader.cc @@ -38,6 +38,8 @@ #include <stdio.h> #include <stdlib.h> +#include <limits> + // Unfortunately, CPU_TYPE_ARM is not define for 10.4. #if !defined(CPU_TYPE_ARM) #define CPU_TYPE_ARM 12 @@ -344,8 +346,8 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const { cursor .Read(word_size, false, &segment.vmaddr) .Read(word_size, false, &segment.vmsize) - .Read(word_size, false, &file_offset) - .Read(word_size, false, &file_size); + .Read(word_size, false, &segment.fileoff) + .Read(word_size, false, &segment.filesize); cursor >> segment.maxprot >> segment.initprot >> segment.nsects @@ -354,8 +356,8 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const { reporter_->LoadCommandTooShort(index, type); return false; } - if (file_offset > buffer_.Size() || - file_size > buffer_.Size() - file_offset) { + if (segment.fileoff > buffer_.Size() || + segment.filesize > buffer_.Size() - segment.fileoff) { reporter_->MisplacedSegmentData(segment.name); return false; } @@ -363,11 +365,11 @@ bool Reader::WalkLoadCommands(Reader::LoadCommandHandler *handler) const { // segments removed, and their file offsets and file sizes zeroed // out. To help us handle this special case properly, give such // segments' contents NULL starting and ending pointers. - if (file_offset == 0 && file_size == 0) { + if (segment.fileoff == 0 && segment.filesize == 0) { segment.contents.start = segment.contents.end = NULL; } else { - segment.contents.start = buffer_.start + file_offset; - segment.contents.end = segment.contents.start + file_size; + segment.contents.start = buffer_.start + segment.fileoff; + segment.contents.end = segment.contents.start + segment.filesize; } // The section list occupies the remainder of this load command's space. segment.section_list.start = cursor.here(); @@ -461,14 +463,14 @@ bool Reader::WalkSegmentSections(const Segment &segment, for (size_t i = 0; i < segment.nsects; i++) { Section section; section.bits_64 = segment.bits_64; - uint64_t size; - uint32_t offset, dummy32; + uint64_t size, offset; + uint32_t dummy32; cursor .CString(§ion.section_name, 16) .CString(§ion.segment_name, 16) .Read(word_size, false, §ion.address) .Read(word_size, false, &size) - >> offset + .Read(sizeof(uint32_t), false, &offset) // clears high bits of |offset| >> section.align >> dummy32 >> dummy32 @@ -481,6 +483,24 @@ bool Reader::WalkSegmentSections(const Segment &segment, reporter_->SectionsMissing(segment.name); return false; } + + // Even 64-bit Mach-O isn’t a true 64-bit format in that it doesn’t handle + // 64-bit file offsets gracefully. Segment load commands do contain 64-bit + // file offsets, but sections within do not. Because segments load + // contiguously, recompute each section’s file offset on the basis of its + // containing segment’s file offset and the difference between the section’s + // and segment’s load addresses. If truncation is detected, honor the + // recomputed offset. + if (segment.bits_64 && + segment.fileoff + segment.filesize > + std::numeric_limits<uint32_t>::max()) { + const uint64_t section_offset_recomputed = + segment.fileoff + section.address - segment.vmaddr; + if (offset == static_cast<uint32_t>(section_offset_recomputed)) { + offset = section_offset_recomputed; + } + } + const uint32_t section_type = section.flags & SECTION_TYPE; if (section_type == S_ZEROFILL || section_type == S_THREAD_LOCAL_ZEROFILL || section_type == S_GB_ZEROFILL) { diff --git a/src/common/mac/macho_reader.h b/src/common/mac/macho_reader.h index 30db742d..145d17d1 100644 --- a/src/common/mac/macho_reader.h +++ b/src/common/mac/macho_reader.h @@ -175,6 +175,10 @@ struct Segment { // of this value are valid. uint64_t vmsize; + // The file offset and size of the segment in the Mach-O image. + uint64_t fileoff; + uint64_t filesize; + // The maximum and initial VM protection of this segment's contents. uint32_t maxprot; uint32_t initprot; |