diff --git a/Cargo.lock b/Cargo.lock index 8f032d79..9a8e6d34 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -497,6 +497,12 @@ dependencies = [ "libc", ] +[[package]] +name = "fallible-iterator" +version = "0.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4443176a9f2c162692bd3d352d745ef9413eec5782a80d8fd6f8a1ac692a07f7" + [[package]] name = "fastrand" version = "1.9.0" @@ -662,6 +668,11 @@ name = "gimli" version = "0.27.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "ad0a93d233ebf96623465aad4046a8d3aa4da22d4f4beba5388838c8a434bbb4" +dependencies = [ + "fallible-iterator", + "indexmap", + "stable_deref_trait", +] [[package]] name = "goblin" @@ -1306,6 +1317,7 @@ dependencies = [ "duct", "flate2", "futures", + "gimli", "goblin", "hex", "object 0.31.0", @@ -1759,6 +1771,12 @@ version = "0.5.2" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6e63cff320ae2c57904679ba7cb63280a3dc4613885beafb148ee7bf9aa9042d" +[[package]] +name = "stable_deref_trait" +version = "1.2.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "a8f112729512f8e442d81f95a8a7ddf2b7c6b8a1a6f509a95864142b30cab2d3" + [[package]] name = "static_assertions" version = "1.1.0" diff --git a/Cargo.toml b/Cargo.toml index 2f60dfbf..da89372c 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -12,6 +12,7 @@ clap = "4.2.5" duct = "0.13.6" flate2 = "1.0.26" futures = "0.3.28" +gimli = "0.27.2" goblin = "0.6.1" hex = "0.4.3" object = "0.31.0" diff --git a/src/validation.rs b/src/validation.rs index ba0f1ebe..9f77e5cd 100644 --- a/src/validation.rs +++ b/src/validation.rs @@ -17,10 +17,11 @@ use { macho::{LoadCommandVariant, MachHeader, Nlist}, pe::{ImageNtHeaders, PeFile, PeFile32, PeFile64}, }, - Endianness, FileKind, Object, SectionIndex, SymbolScope, + Endian, Endianness, FileKind, Object, SectionIndex, SymbolScope, }, once_cell::sync::Lazy, std::{ + borrow::Cow, collections::{BTreeSet, HashMap}, convert::TryInto, io::Read, @@ -990,6 +991,48 @@ fn validate_elf<'data, Elf: FileHeader>( } } + // Look at DWARF debug info. + + let load_section = |id: gimli::SectionId| -> Result, gimli::Error> { + match sections.section_by_name(endian, id.name().as_ref()) { + Some((_, section)) => { + // TODO handle compression. + Ok(section + .data(endian, data) + .map(Cow::Borrowed) + .unwrap_or(Cow::Borrowed(&[][..]))) + } + None => Ok(Cow::Borrowed(&[][..])), + } + }; + + let dwarf_cow = gimli::Dwarf::load(&load_section)?; + + let borrow_section: &dyn for<'a> Fn( + &'a Cow<[u8]>, + ) -> gimli::EndianSlice<'a, gimli::RunTimeEndian> = &|section| { + gimli::EndianSlice::new( + &*section, + if endian.is_big_endian() { + gimli::RunTimeEndian::Big + } else { + gimli::RunTimeEndian::Little + }, + ) + }; + + let dwarf = dwarf_cow.borrow(&borrow_section); + + let mut iter = dwarf.units(); + while let Some(header) = iter.next()? { + if header.version() > 4 { + context + .errors + .push(format!("{} has DWARF newer than version 4", path.display())); + break; + } + } + Ok(()) }