Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
3 changes: 3 additions & 0 deletions lib/macho/fat_file.rb
Original file line number Diff line number Diff line change
Expand Up @@ -396,11 +396,14 @@ def populate_fat_archs

# Obtain an array of Mach-O blobs from raw file data.
# @return [Array<MachOFile>] an array of Mach-Os
# @raise [TruncatedFileError] if the file is too small to contain all fat slices
# @api private
def populate_machos
machos = []

fat_archs.each do |arch|
raise TruncatedFileError if arch.offset + arch.size > @raw_data.bytesize

machos << MachOFile.new_from_bin(@raw_data[arch.offset, arch.size], **options)

# Make sure that each fat_arch and internal slice.
Expand Down
58 changes: 58 additions & 0 deletions test/test_fat.rb
Original file line number Diff line number Diff line change
Expand Up @@ -131,6 +131,64 @@ def test_truncated_fat_arch_64
end
end

def test_fat_slice_offset_past_eof
# FatArch: cputype(4) + cpusubtype(4) + offset(4) + size(4) + align(4).
# Push the first slice's offset past the end of the file.
machos = SINGLE_ARCHES.map { |a| MachO::MachOFile.new(fixture(a, "hello.bin")) }
fat_bin = MachO::FatFile.new_from_machos(*machos).serialize

offset_at = MachO::Headers::FatHeader.bytesize + 8
fat_bin[offset_at, 4] = [fat_bin.bytesize + 1024].pack("N")

assert_raises MachO::TruncatedFileError do
MachO::FatFile.new_from_bin(fat_bin)
end
end

def test_fat_slice_size_past_eof
# Inflate the first slice's size so offset + size exceeds the file size.
machos = SINGLE_ARCHES.map { |a| MachO::MachOFile.new(fixture(a, "hello.bin")) }
fat_bin = MachO::FatFile.new_from_machos(*machos).serialize

size_at = MachO::Headers::FatHeader.bytesize + 12
fat_bin[size_at, 4] = [fat_bin.bytesize * 4].pack("N")

assert_raises MachO::TruncatedFileError do
MachO::FatFile.new_from_bin(fat_bin)
end
end

def test_fat64_slice_offset_past_eof
# FatArch64: cputype(4) + cpusubtype(4) + offset(8) + size(8) + align(4) + reserved(4).
# Use a 64-bit offset that would wrap if arithmetic were not arbitrary precision.
machos = SINGLE_ARCHES.map { |a| MachO::MachOFile.new(fixture(a, "hello.bin")) }
fat_bin = MachO::FatFile.new_from_machos(*machos, :fat64 => true).serialize

offset_at = MachO::Headers::FatHeader.bytesize + 8
size_at = MachO::Headers::FatHeader.bytesize + 16
fat_bin[offset_at, 8] = [(2**64) - 8].pack("Q>")
fat_bin[size_at, 8] = [16].pack("Q>")

assert_raises MachO::TruncatedFileError do
MachO::FatFile.new_from_bin(fat_bin)
end
end

def test_fat_slice_offset_at_eof_is_rejected
# offset == filesize with size == 0 yields an empty slice, which is not a Mach-O.
machos = SINGLE_ARCHES.map { |a| MachO::MachOFile.new(fixture(a, "hello.bin")) }
fat_bin = MachO::FatFile.new_from_machos(*machos).serialize

offset_at = MachO::Headers::FatHeader.bytesize + 8
size_at = MachO::Headers::FatHeader.bytesize + 12
fat_bin[offset_at, 4] = [fat_bin.bytesize].pack("N")
fat_bin[size_at, 4] = [0].pack("N")

assert_raises MachO::TruncatedFileError do
MachO::FatFile.new_from_bin(fat_bin)
end
end

def test_mismatch_cpu_arch_file
assert_raises MachO::CPUTypeMismatchError do
MachO::FatFile.new("test/bin/llvm/macho-invalid-fat_cputype")
Expand Down
Loading