From a5f280c4c67f53b4863d850bd3942be649bc9205 Mon Sep 17 00:00:00 2001 From: Joakim Hulthe Date: Wed, 10 Jul 2024 23:33:19 +0200 Subject: [PATCH] Take SHT_NOBITS into account --- src/main.rs | 8 +++++++- src/structs.rs | 24 ++++++++++++++++++++++++ 2 files changed, 31 insertions(+), 1 deletion(-) diff --git a/src/main.rs b/src/main.rs index 45cffb8..46330f4 100644 --- a/src/main.rs +++ b/src/main.rs @@ -95,8 +95,11 @@ macro_rules! parse_elf { let name = &names_section[name_start..name_end]; let name = from_utf8(name).wrap_err(eyre!(".names entry not valid utf-8"))?; let section_start = entry.start().wrap_err_with(|| name.to_string())?; + + // validate that section fits in file (or has SHT_NOBITS set) + let sht_nobits_set = (entry.sh_type.to_native() & 8) != 0; let section_end = entry.end().wrap_err_with(|| name.to_string())?; - if section_end > elf.len() { + if section_end > elf.len() && !sht_nobits_set { bail!("section {name:?} end is past eof"); } @@ -190,6 +193,7 @@ fn main() -> eyre::Result<()> { let elf = fs::read(opt.elf).wrap_err("failed to read elf file")?; + // extract first part of the header if elf.len() < HEADER1_LEN { bail!("not a valid elf file: file too small"); } @@ -199,6 +203,7 @@ fn main() -> eyre::Result<()> { let mut out = Output::default(); out.write("header", &header)?; + // validate header if &header.ei_magic != b"\x7FELF" { bail!("not a valid elf file: invalid magic"); } @@ -207,6 +212,7 @@ fn main() -> eyre::Result<()> { bail!("unknown elf version: 0x{:x}", header.ei_version); } + // determine endianness and size, then invoke the correct parse macro. match (header.ei_class, header.ei_data) { (1, 1) => parse_elf!(LittleEndian32, &mut out, header1, elf), (2, 1) => parse_elf!(LittleEndian64, &mut out, header1, elf), diff --git a/src/structs.rs b/src/structs.rs index af6bd5f..b6d760b 100644 --- a/src/structs.rs +++ b/src/structs.rs @@ -50,6 +50,7 @@ impl ElfConfig for BigEndian64 { type SymtabEntry = SymbolTableEntry64; } +/// First part of an ELF header. Use to determine endian and word size of elf file. #[derive(Pod, Zeroable, Clone, Copy, Debug, Serialize)] #[repr(C, packed)] pub struct ElfHeader1 { @@ -63,6 +64,7 @@ pub struct ElfHeader1 { _padding: [u8; 7], } +/// Second part of an elf header. Size and endianness depends on [ElfHeader1]. #[derive(Pod, Zeroable, Clone, Copy, Debug, Serialize)] #[repr(C, packed)] pub struct ElfHeader2 { @@ -84,15 +86,37 @@ pub struct ElfHeader2 { #[derive(Pod, Zeroable, Clone, Copy, Debug, Serialize)] #[repr(C, packed)] pub struct SectionHeaderEntry { + /// An index into the section header string table containing the name of this section. pub sh_name: C::Word, + + /// Specifies the section's semantics. pub sh_type: C::Word, + + /// Bitflags that describe the s.ections attributes. pub sh_flags: C::Addr, + + /// If the section will appear in the memory image of a process, this gives the address at + /// which the section should start. Otherwise, this is 0. pub sh_addr: C::Addr, + + /// This member's value gives the byte offset from the beginning of the ELF file to the start + /// of this section. If `SHT_NOBITS` is set in sh_flags, the section occupies no space in the + /// file. pub sh_offset: C::Addr, + + /// The size of the section in bytes. pub sh_size: C::Addr, + + /// Section header table link. Interpretation depends on section type. pub sh_link: C::Word, + + /// Extra section info. Interpretation depends on section type. pub sh_info: C::Word, + + /// Address alignment constraints. pub sh_addralign: C::Addr, + + /// Size in bytes of each entry in the section, or 0 if section does not contain entries. pub sh_entsize: C::Addr, }