Skip to content

Commit 719eb3b

Browse files
committed
Add YAML Mach-O parser fixtures
- Cover malformed command sizes, bounds and string offsets. - Exercise byte order, build metadata and runtime paths.
1 parent 1f005f1 commit 719eb3b

25 files changed

Lines changed: 256 additions & 0 deletions

‎lib/macho/exceptions.rb‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -126,6 +126,14 @@ def initialize(num)
126126
end
127127
end
128128

129+
# Raised when a load command has an invalid size.
130+
class LoadCommandSizeError < NotAMachOError
131+
# @param size [Integer] the invalid size
132+
def initialize(size)
133+
super("Invalid Mach-O load command size: #{size}")
134+
end
135+
end
136+
129137
# Raised when a load command can't be created manually.
130138
class LoadCommandNotCreatableError < MachOError
131139
# @param cmd_sym [Symbol] the uncreatable load command's symbol

‎lib/macho/load_commands.rb‎

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -332,6 +332,8 @@ def initialize(lc, lc_str)
332332
view = lc.view
333333

334334
if view
335+
raise LCStrMalformedError, lc if lc_str < lc.class.bytesize || lc_str >= lc.cmdsize
336+
335337
lc_str_abs = view.offset + lc_str
336338
lc_end = view.offset + lc.cmdsize - 1
337339
raw_string = view.raw_data.slice(lc_str_abs..lc_end)

‎lib/macho/macho_file.rb‎

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -579,17 +579,27 @@ def check_filetype(filetype)
579579

580580
# All load commands in the file.
581581
# @return [Array<LoadCommands::LoadCommand>] an array of load commands
582+
# @raise [TruncatedFileError] if the declared load command data is incomplete
582583
# @raise [LoadCommandError] if an unknown load command is encountered
584+
# @raise [LoadCommandSizeError] if a load command's size is invalid
583585
# @api private
584586
def populate_load_commands
585587
permissive = options.fetch(:permissive, false)
586588
offset = header.class.bytesize
589+
load_commands_end = offset + sizeofcmds
590+
raise TruncatedFileError if load_commands_end > @raw_data.bytesize
591+
587592
load_commands = []
588593
@load_commands_by_type = Hash.new { |h, k| h[k] = [] }
589594

590595
header.ncmds.times do
596+
raise TruncatedFileError if offset + LoadCommands::LoadCommand.bytesize > load_commands_end
597+
591598
fmt = Utils.specialize_format("L=", endianness)
592599
cmd = @raw_data.slice(offset, 4).unpack1(fmt)
600+
cmdsize = @raw_data.slice(offset + 4, 4).unpack1(fmt)
601+
raise LoadCommandSizeError, cmdsize if cmdsize % 4 != 0 || offset + cmdsize > load_commands_end
602+
593603
cmd_sym = LoadCommands::LOAD_COMMANDS[cmd]
594604

595605
raise LoadCommandError, cmd unless cmd_sym || permissive
@@ -602,6 +612,8 @@ def populate_load_commands
602612
LoadCommands::LoadCommand
603613
end
604614

615+
raise LoadCommandSizeError, cmdsize if cmdsize < klass.bytesize
616+
605617
view = MachOView.new(self, @raw_data, endianness, offset)
606618
command = klass.new_from_bin(view)
607619

‎test/bin/yaml2obj/Makefile‎

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,8 @@
1+
YAMLS := $(wildcard *.yaml)
2+
MACHOS := $(YAMLS:.yaml=.macho)
3+
4+
.PHONY: all
5+
all: $(MACHOS)
6+
7+
%.macho: %.yaml
8+
yaml2obj $< -o $@

‎test/bin/yaml2obj/big-endian.macho‎

28 Bytes
Binary file not shown.

‎test/bin/yaml2obj/big-endian.yaml‎

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,11 @@
1+
--- !mach-o
2+
IsLittleEndian: false
3+
FileHeader:
4+
magic: 0xFEEDFACE
5+
cputype: 0x00000007
6+
cpusubtype: 0x00000003
7+
filetype: 0x00000001
8+
ncmds: 0
9+
sizeofcmds: 0
10+
flags: 0x00000000
11+
...
64 Bytes
Binary file not shown.
Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
--- !mach-o
2+
IsLittleEndian: true
3+
FileHeader:
4+
magic: 0xFEEDFACF
5+
cputype: 0x01000007
6+
cpusubtype: 0x00000003
7+
filetype: 0x00000002
8+
ncmds: 1
9+
sizeofcmds: 32
10+
flags: 0x00000000
11+
reserved: 0x00000000
12+
LoadCommands:
13+
- cmd: LC_BUILD_VERSION
14+
cmdsize: 32
15+
platform: 2
16+
minos: 0x00080000
17+
sdk: 0x00090000
18+
ntools: 1
19+
Tools:
20+
- tool: 1
21+
version: 0
22+
...
56 Bytes
Binary file not shown.
Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,18 @@
1+
--- !mach-o
2+
IsLittleEndian: true
3+
FileHeader:
4+
magic: 0xFEEDFACF
5+
cputype: 0x01000007
6+
cpusubtype: 0x00000003
7+
filetype: 0x00000002
8+
ncmds: 1
9+
sizeofcmds: 24
10+
flags: 0x00000000
11+
reserved: 0x00000000
12+
LoadCommands:
13+
- cmd: LC_LOAD_DYLINKER
14+
cmdsize: 24
15+
name: 0
16+
Content: test
17+
ZeroPadBytes: 8
18+
...

0 commit comments

Comments
 (0)