Skip to content

Commit

Permalink
elf: allow parsing SectionHeader from raw bytes
Browse files Browse the repository at this point in the history
* elf: Allow parsing SectionHeader from raw bytes
* elf: Add test coverage for SectionHeader::parse_impl
  • Loading branch information
lissyx committed Mar 10, 2024
1 parent 1335dad commit d73a80a
Show file tree
Hide file tree
Showing 2 changed files with 49 additions and 5 deletions.
17 changes: 12 additions & 5 deletions src/elf/section_header.rs
Expand Up @@ -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<Vec<SectionHeader>> {
use scroll::Pread;
pub fn parse(bytes: &[u8], offset: usize, count: usize, ctx: Ctx) -> error::Result<Vec<SectionHeader>> {
// 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<Vec<SectionHeader>> {
use scroll::Pread;
let empty_sh = bytes.gread_with::<SectionHeader>(&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;
}

Expand Down
37 changes: 37 additions & 0 deletions tests/elf.rs
Expand Up @@ -75,6 +75,36 @@ fn parse_text_section_size_lazy(base: &[u8]) -> Result<u64, &'static str> {
Err("Didn't find text section")
}

fn parse_from_text_section_size_lazy(base: &[u8]) -> Result<bool, &'static str> {
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]> =
Expand Down Expand Up @@ -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};
Expand Down

0 comments on commit d73a80a

Please sign in to comment.