diff --git a/src/elf.rs b/src/elf.rs index 0987d9f99..cb2a4b2ee 100644 --- a/src/elf.rs +++ b/src/elf.rs @@ -1369,7 +1369,7 @@ mod test { elf_parser::{ // FIXME consts::{ELFCLASS32, ELFDATA2MSB, ET_REL}, consts::{ELFCLASS32, ELFDATA2MSB, ET_REL}, - types::{Elf64Ehdr, Elf64Shdr}, + types::{Elf64Ehdr, Elf64Shdr, Elf64Sym}, SECTION_NAME_LENGTH_MAXIMUM, }, error::ProgramResult, @@ -1398,6 +1398,99 @@ mod test { )) } + #[test] + fn test_strict_header() { + let elf_bytes = + std::fs::read("tests/elfs/strict_header.so").expect("failed to read elf file"); + let loader = loader(); + + // Check that the unmodified file can be parsed + ElfExecutable::load(&elf_bytes, loader.clone()).unwrap(); + + // Check that an empty file fails + let err = ElfExecutable::load_with_strict_parser(&[], loader.clone()).unwrap_err(); + assert_eq!(err, ElfParserError::OutOfBounds); + + // Break the file header one byte at a time + let expected_results = std::iter::repeat(&Err(ElfParserError::InvalidFileHeader)) + .take(40) + .chain(std::iter::repeat(&Ok(())).take(12)) + .chain(std::iter::repeat(&Err(ElfParserError::InvalidFileHeader)).take(4)) + .chain(std::iter::repeat(&Err(ElfParserError::InvalidProgramHeader)).take(1)) + .chain(std::iter::repeat(&Err(ElfParserError::InvalidFileHeader)).take(3)) + .chain(std::iter::repeat(&Ok(())).take(2)) + .chain(std::iter::repeat(&Err(ElfParserError::InvalidFileHeader)).take(2)); + for (offset, expected) in (0..std::mem::size_of::()).zip(expected_results) { + let mut elf_bytes = elf_bytes.clone(); + elf_bytes[offset] = 0xAF; + let result = + ElfExecutable::load_with_strict_parser(&elf_bytes, loader.clone()).map(|_| ()); + assert_eq!(&result, expected); + } + + // Break the program header table one byte at a time + let expected_results_readonly = + std::iter::repeat(&Err(ElfParserError::InvalidProgramHeader)) + .take(48) + .chain(std::iter::repeat(&Ok(())).take(8)) + .collect::>(); + let expected_results_writable = + std::iter::repeat(&Err(ElfParserError::InvalidProgramHeader)) + .take(40) + .chain(std::iter::repeat(&Ok(())).take(4)) + .chain(std::iter::repeat(&Err(ElfParserError::InvalidProgramHeader)).take(4)) + .chain(std::iter::repeat(&Ok(())).take(8)) + .collect::>(); + let expected_results = vec![ + expected_results_readonly.iter(), + expected_results_readonly.iter(), + expected_results_writable.iter(), + expected_results_writable.iter(), + expected_results_readonly.iter(), + ]; + for (header_index, expected_results) in expected_results.into_iter().enumerate() { + for (offset, expected) in (std::mem::size_of::() + + std::mem::size_of::() * header_index + ..std::mem::size_of::() + + std::mem::size_of::() * (header_index + 1)) + .zip(expected_results) + { + let mut elf_bytes = elf_bytes.clone(); + elf_bytes[offset] = 0xAF; + let result = + ElfExecutable::load_with_strict_parser(&elf_bytes, loader.clone()).map(|_| ()); + assert_eq!(&&result, expected); + } + } + + // Break the dynamic symbol table one byte at a time + for index in 1..3 { + let expected_results = std::iter::repeat(&Ok(())) + .take(8) + .chain(std::iter::repeat(&Err(ElfParserError::OutOfBounds)).take(8)) + .chain(std::iter::repeat(&Err(ElfParserError::InvalidSize)).take(1)) + .chain(std::iter::repeat(&Err(ElfParserError::OutOfBounds)).take(7)); + for (offset, expected) in (0x3000 + std::mem::size_of::() * index + ..0x3000 + std::mem::size_of::() * (index + 1)) + .zip(expected_results) + { + let mut elf_bytes = elf_bytes.clone(); + elf_bytes[offset] = 0xAF; + let result = + ElfExecutable::load_with_strict_parser(&elf_bytes, loader.clone()).map(|_| ()); + assert_eq!(&result, expected); + } + } + + // Check that an empty function symbol fails + let mut elf_bytes = elf_bytes.clone(); + elf_bytes[0x3040] = 0x00; + assert_eq!( + ElfExecutable::load_with_strict_parser(&elf_bytes, loader.clone()).unwrap_err(), + ElfParserError::InvalidSize + ); + } + #[test] fn test_validate() { let elf_bytes = std::fs::read("tests/elfs/relative_call_sbpfv1.so").unwrap(); diff --git a/tests/execution.rs b/tests/execution.rs index 54c1be01a..67d37e71c 100644 --- a/tests/execution.rs +++ b/tests/execution.rs @@ -3186,6 +3186,17 @@ fn test_struct_func_pointer() { ); } +#[test] +fn test_strict_header() { + test_interpreter_and_jit_elf!( + "tests/elfs/strict_header.so", + [], + (), + TestContextObject::new(6), + ProgramResult::Ok(42), + ); +} + // Programs #[test]