diff --git a/src/elf/section_header.rs b/src/elf/section_header.rs index 981706153..a81839eb0 100644 --- a/src/elf/section_header.rs +++ b/src/elf/section_header.rs @@ -442,18 +442,25 @@ if_alloc! { self.sh_addr as usize..(self.sh_addr as usize).saturating_add(self.sh_size as usize) } /// Parse `count` section headers from `bytes` at `offset`, using the given `ctx` + /// Assuming this is read from the whole file, it will check offset. #[cfg(feature = "endian_fd")] - pub fn parse(bytes: &[u8], mut offset: usize, mut count: usize, ctx: Ctx) -> error::Result> { - use scroll::Pread; + pub fn parse(bytes: &[u8], offset: usize, count: usize, ctx: Ctx) -> error::Result> { // Zero offset means no section headers, not even the null section header. if offset == 0 { return Ok(Vec::new()); } + Self::parse_from(bytes, offset, count, ctx) + } + /// Parse `count` section headers from `bytes` at `offset`, using the given `ctx` + /// without performing any offset checking to allow parsing relatively + #[cfg(feature = "endian_fd")] + pub fn parse_from(bytes: &[u8], mut offset: usize, mut count: usize, ctx: Ctx) -> error::Result> { + use scroll::Pread; let empty_sh = bytes.gread_with::(&mut offset, ctx)?; if count == 0 as usize { - // Zero count means either no section headers if offset is also zero (checked - // above), or the number of section headers overflows SHN_LORESERVE, in which - // case the count is stored in the sh_size field of the null section header. + // Zero count means either no section headers or the number of section headers + // overflows SHN_LORESERVE, in which case the count is stored in the sh_size field + // of the null section header. count = empty_sh.sh_size as usize; } diff --git a/tests/elf.rs b/tests/elf.rs index d12c4b4c3..046d07309 100644 --- a/tests/elf.rs +++ b/tests/elf.rs @@ -75,6 +75,36 @@ fn parse_text_section_size_lazy(base: &[u8]) -> Result { Err("Didn't find text section") } +fn parse_from_text_section_size_lazy(base: &[u8]) -> Result { + let header = Elf::parse_header(base).map_err(|_| "parse elf header error")?; + + use goblin::container::{Container, Ctx}; + use goblin::elf::SectionHeader; + + let ctx = Ctx { + le: scroll::Endian::Little, + container: Container::Big, + }; + + let sh_from_orig = + SectionHeader::parse(base, header.e_shoff as usize, header.e_shnum as usize, ctx) + .map_err(|_| "parse() section headers error")?; + + let sh_from_offset = SectionHeader::parse_from( + &base[header.e_shoff as usize..], + 0, + header.e_shnum as usize, + ctx, + ) + .map_err(|_| "parse_from() section headers error")?; + + if sh_from_orig == sh_from_offset { + return Ok(true); + } + + Err("Mismatching offset reading") +} + #[test] fn test_parse_gnu_hash_section_64bit() { static ALIGNED_DATA: &AlignedData<[u8]> = @@ -148,6 +178,13 @@ fn test_parse_text_section_size_lazy() { assert_eq!(parse_text_section_size_lazy(&ALIGNED_DATA.0), Ok(0x126)); } +#[test] +fn test_parse_from_text_section_size_lazy() { + static ALIGNED_DATA: &AlignedData<[u8]> = + &AlignedData(*include_bytes!("bins/elf/gnu_hash/hello.so")); + assert_eq!(parse_from_text_section_size_lazy(&ALIGNED_DATA.0), Ok(true)); +} + #[test] fn test_oom() { use goblin::container::{Container, Ctx};