Skip to content

Commit 803b401

Browse files
committed
Add test for sufficient headerpad
1 parent 4ec8e29 commit 803b401

File tree

1 file changed

+32
-2
lines changed

1 file changed

+32
-2
lines changed

src/validation.rs

Lines changed: 32 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -12,10 +12,10 @@ use {
1212
FileHeader32, FileHeader64, ET_DYN, ET_EXEC, SHN_UNDEF, STB_GLOBAL, STB_WEAK, STV_DEFAULT,
1313
STV_HIDDEN,
1414
},
15-
macho::{MachHeader32, MachHeader64, MH_OBJECT, MH_TWOLEVEL},
15+
macho::{LC_CODE_SIGNATURE, MH_OBJECT, MH_TWOLEVEL, MachHeader32, MachHeader64},
1616
read::{
1717
elf::{Dyn, FileHeader, SectionHeader, Sym},
18-
macho::{LoadCommandVariant, MachHeader, Nlist},
18+
macho::{LoadCommandVariant, MachHeader, Nlist, Section, Segment},
1919
pe::{ImageNtHeaders, PeFile, PeFile32, PeFile64},
2020
},
2121
Architecture, Endianness, FileKind, Object, SectionIndex, SymbolScope,
@@ -1264,6 +1264,8 @@ fn validate_macho<Mach: MachHeader<Endian = Endianness>>(
12641264
let mut undefined_symbols = vec![];
12651265
let mut target_version = None;
12661266
let mut sdk_version = None;
1267+
let mut has_code_signature = false;
1268+
let mut lowest_file_offset = u64::MAX;
12671269

12681270
while let Some(load_command) = load_commands.next()? {
12691271
match load_command.variant()? {
@@ -1386,10 +1388,38 @@ fn validate_macho<Mach: MachHeader<Endian = Endianness>>(
13861388
}
13871389
}
13881390
}
1391+
LoadCommandVariant::Segment32(segment, segment_data) => {
1392+
for section in segment.sections(endian, segment_data)? {
1393+
if let Some((offset, _)) = section.file_range(endian) {
1394+
lowest_file_offset = lowest_file_offset.min(offset);
1395+
}
1396+
}
1397+
}
1398+
LoadCommandVariant::Segment64(segment, segment_data) => {
1399+
for section in segment.sections(endian, segment_data)? {
1400+
if let Some((offset, _)) = section.file_range(endian) {
1401+
lowest_file_offset = lowest_file_offset.min(offset);
1402+
}
1403+
}
1404+
}
1405+
LoadCommandVariant::LinkeditData(c) if c.cmd.get(endian) == LC_CODE_SIGNATURE => {
1406+
has_code_signature = true;
1407+
}
13891408
_ => {}
13901409
}
13911410
}
13921411

1412+
let end_of_load_commands =
1413+
std::mem::size_of_val(header) as u64 + header.sizeofcmds(endian) as u64;
1414+
if header.filetype(endian) != MH_OBJECT
1415+
&& end_of_load_commands + if has_code_signature { 0 } else { 16 } > lowest_file_offset
1416+
{
1417+
context.errors.push(format!(
1418+
"{}: Insufficient headerpad between end of load commands {end_of_load_commands:#x} and beginning of code {lowest_file_offset:#x}",
1419+
path.display(),
1420+
));
1421+
}
1422+
13931423
if let Some(actual_target_version) = target_version {
13941424
if actual_target_version != advertised_target_version {
13951425
context.errors.push(format!(

0 commit comments

Comments
 (0)