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
1 change: 0 additions & 1 deletion libwild/src/elf.rs
Original file line number Diff line number Diff line change
Expand Up @@ -417,7 +417,6 @@ impl platform::Platform for Elf {
output_section_id::PROGRAM_HEADERS,
output_section_id::SECTION_HEADERS,
output_section_id::SHSTRTAB,
output_section_id::RELRO_PADDING,
];

for section_id in FORCE_KEEP_SECTIONS {
Expand Down
74 changes: 74 additions & 0 deletions wild/tests/integration_tests.rs
Original file line number Diff line number Diff line change
Expand Up @@ -57,6 +57,12 @@
//! ExpectLoadAlignment:{alignment} Checks that the first PT_LOAD segment in the output binary has
//! the specified alignment.
//!
//! ExpectProgramHeader:{type} Checks that the output binary contains a program header of the
//! specified type.
//!
//! NoProgramHeader:{type} Checks that the output binary contains no program headers of the
//! specified type.
//!
//! DoesNotContain:{string} Checks that the output binary doesn't contain the specified string.
//!
//! Contains:{string} Checks that the output binary does contain the specified string.
Expand Down Expand Up @@ -814,6 +820,23 @@ enum DriverMode {
SaveDirResponse,
}

#[derive(Clone, Copy, Debug, Display, PartialEq, Eq, EnumString)]
#[strum(serialize_all = "SCREAMING_SNAKE_CASE")]
#[repr(u32)]
enum ProgramHeaderType {
Dynamic = object::elf::PT_DYNAMIC,
Interp = object::elf::PT_INTERP,
GnuEhFrame = object::elf::PT_GNU_EH_FRAME,
GnuProperty = object::elf::PT_GNU_PROPERTY,
GnuRelro = object::elf::PT_GNU_RELRO,
GnuStack = object::elf::PT_GNU_STACK,
Load = object::elf::PT_LOAD,
Note = object::elf::PT_NOTE,
Null = object::elf::PT_NULL,
Phdr = object::elf::PT_PHDR,
Tls = object::elf::PT_TLS,
}

#[derive(Debug, Clone)]
struct ErrorMatcher {
regex: regex::Regex,
Expand Down Expand Up @@ -1140,6 +1163,8 @@ struct Assertions {
expected_section_bytes: Vec<ExpectedSectionBytes>,
output_file_matches: Vec<OutputFileMatch>,
max_thunks: u64,
expected_program_headers: Vec<ProgramHeaderType>,
absent_program_headers: Vec<ProgramHeaderType>,
}

#[derive(Debug, Clone, PartialEq, Eq)]
Expand Down Expand Up @@ -1498,6 +1523,18 @@ fn process_directive(
};
config.assertions.expected_load_alignment = Some(alignment);
}
"ExpectProgramHeader" => {
let header_type: ProgramHeaderType = arg
.parse()
.with_context(|| format!("Invalid program header type `{arg}`"))?;
config.assertions.expected_program_headers.push(header_type);
}
"NoProgramHeader" => {
let header_type: ProgramHeaderType = arg
.parse()
.with_context(|| format!("Invalid program header type `{arg}`"))?;
config.assertions.absent_program_headers.push(header_type);
}
"Mode" => {
let mode: Mode = arg
.parse()
Expand Down Expand Up @@ -3430,6 +3467,7 @@ impl Assertions {
self.verify_dynamic_entries(&elf_obj)?;
self.verify_symbols_absent(&self.no_sym, elf_obj.dynamic_symbols(), "dynsym")?;
self.verify_symbols_absent(&self.no_dynsym, elf_obj.dynamic_symbols(), "dynsym")?;
self.verify_program_headers(&elf_obj)?;
}
object::File::MachO64(_) => {
if !self.expected_comments.is_empty() {
Expand All @@ -3447,6 +3485,12 @@ impl Assertions {
if !self.absent_dynamic_entries.is_empty() {
bail!("NoDynamic is not supported for MachO",);
}
if !self.expected_program_headers.is_empty() {
bail!("ExpectProgramHeader is not supported for MachO",);
}
if !self.absent_program_headers.is_empty() {
bail!("NoProgramHeader is not supported for MachO");
}
}
_ => bail!("Unsupported object file format"),
}
Expand Down Expand Up @@ -3676,6 +3720,36 @@ impl Assertions {
Ok(())
}

fn verify_program_headers<'data>(
&self,
obj: &object::read::elf::ElfFile64<'data, object::Endianness>,
) -> Result {
if self.expected_program_headers.is_empty() && self.absent_program_headers.is_empty() {
return Ok(());
}

let endian = obj.endian();
let mut header_types = HashSet::new();

for header in obj.elf_program_headers() {
header_types.insert(header.p_type(endian));
}

for header in &self.expected_program_headers {
if !header_types.contains(&(*header as u32)) {
bail!("Expected program header `{header}' not found.");
}
}

for header in &self.absent_program_headers {
if header_types.contains(&(*header as u32)) {
bail!("Program header `{header}' should be absent but was found.");
}
}

Ok(())
}

/// Returns whether we have assertions configured that require metrics to be enabled. Even if
/// this returns false, if diffing is enabled, we'll collect metrics and check them.
fn requires_metrics(&self) -> bool {
Expand Down
26 changes: 26 additions & 0 deletions wild/tests/sources/elf/relro/relro.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,26 @@
//#AbstractConfig:default
// Create a .got.plt section to force ld to include a PT_GNU_RELRO program
// header
//#Shared:runtime.c
//#Mode:dynamic
//#DiffIgnore:section.got
//#DiffIgnore:.dynamic.DT_NEEDED
//#DiffIgnore:.dynamic.DT_FLAGS_1.NOW
//#DiffIgnore:.dynamic.DT_RELA
//#DiffIgnore:.dynamic.DT_RELAENT

//#Config:enabled:default
//#LinkArgs:-z relro
//#ExpectProgramHeader:GNU_RELRO

//#Config:disabled:default
//#LinkArgs:-z norelro
//#NoProgramHeader:GNU_RELRO
//#DoesNotContain:relro_padding

#include "../common/runtime.h"

void _start() {
runtime_init();
exit_syscall(42);
}