auditable-extract-0.3.2/.cargo_vcs_info.json0000644000000001570000000000100144430ustar { "git": { "sha1": "f3caecf29b69da51effeb8acc03f90b396bfa92d" }, "path_in_vcs": "auditable-extract" }auditable-extract-0.3.2/.gitignore000064400000000000000000000000101046102023000152070ustar 00000000000000/target auditable-extract-0.3.2/Cargo.toml0000644000000015260000000000100124420ustar # THIS FILE IS AUTOMATICALLY GENERATED BY CARGO # # When uploading crates to the registry Cargo will automatically # "normalize" Cargo.toml files for maximal compatibility # with all versions of Cargo and also rewrite `path` dependencies # to registry (e.g., crates.io) dependencies. # # If you are reading this file be aware that the original Cargo.toml # will likely look very different (and much more reasonable). # See Cargo.toml.orig for the original contents. [package] edition = "2018" name = "auditable-extract" version = "0.3.2" authors = ["Sergey \"Shnatsel\" Davidoff "] description = "Extract the dependency trees embedded in binaries by `cargo auditable`" categories = ["encoding"] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-secure-code/cargo-auditable" [dependencies.binfarce] version = "0.2" auditable-extract-0.3.2/Cargo.toml.orig000064400000000000000000000007351046102023000161240ustar 00000000000000[package] name = "auditable-extract" version = "0.3.2" authors = ["Sergey \"Shnatsel\" Davidoff "] license = "MIT OR Apache-2.0" repository = "https://github.com/rust-secure-code/cargo-auditable" description = "Extract the dependency trees embedded in binaries by `cargo auditable`" categories = ["encoding"] edition = "2018" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] binfarce = "0.2" auditable-extract-0.3.2/src/lib.rs000064400000000000000000000121551046102023000151370ustar 00000000000000#![forbid(unsafe_code)] //! Extracts the dependency tree information embedded in executables by //! [`cargo auditable`](https://github.com/rust-secure-code/cargo-auditable). //! //! This crate parses platform-specific binary formats ([ELF](https://en.wikipedia.org/wiki/Executable_and_Linkable_Format), //! [PE](https://en.wikipedia.org/wiki/Portable_Executable), //! [Mach-O](https://en.wikipedia.org/wiki/Mach-O)) and obtains the compressed audit data. //! //! Unlike other binary parsing crates, it is specifically designed to be resilient to malicious input. //! It 100% safe Rust (including all dependencies) and performs no heap allocations. //! //! ## Usage //! //! **Note:** this is a low-level crate that only implements binary parsing. It rarely should be used directly. //! You probably want the higher-level [`auditable-info`](https://docs.rs/auditable-info) crate instead. //! //! The following snippet demonstrates full extraction pipeline, including decompression //! using the safe-Rust [`miniz_oxide`](http://docs.rs/miniz_oxide/) and optional JSON parsing //! via [`auditable-serde`](http://docs.rs/auditable-serde/): //! //! ```rust,ignore //! use std::io::{Read, BufReader}; //! use std::{error::Error, fs::File, str::FromStr}; //! //! fn main() -> Result<(), Box> { //! // Read the input //! let f = File::open("target/release/hello-world")?; //! let mut f = BufReader::new(f); //! let mut input_binary = Vec::new(); //! f.read_to_end(&mut input_binary)?; //! // Extract the compressed audit data //! let compressed_audit_data = auditable_extract::raw_auditable_data(&input_binary)?; //! // Decompress it with your Zlib implementation of choice. We recommend miniz_oxide //! use miniz_oxide::inflate::decompress_to_vec_zlib; //! let decompressed_data = decompress_to_vec_zlib(&compressed_audit_data) //! .map_err(|_| "Failed to decompress audit data")?; //! let decompressed_data = String::from_utf8(decompressed_data)?; //! println!("{}", decompressed_data); //! // Parse the audit data to Rust data structures //! let dependency_tree = auditable_serde::VersionInfo::from_str(&decompressed_data); //! Ok(()) //! } //! ``` use binfarce::Format; /// Extracts the Zlib-compressed dependency info from an executable. /// /// This function does not allocate any memory on the heap and can be safely given untrusted input. pub fn raw_auditable_data(data: &[u8]) -> Result<&[u8], Error> { match binfarce::detect_format(data) { Format::Elf32 { byte_order } => { let section = binfarce::elf32::parse(data, byte_order)? .section_with_name(".dep-v0")? .ok_or(Error::NoAuditData)?; Ok(data.get(section.range()?).ok_or(Error::UnexpectedEof)?) } Format::Elf64 { byte_order } => { let section = binfarce::elf64::parse(data, byte_order)? .section_with_name(".dep-v0")? .ok_or(Error::NoAuditData)?; Ok(data.get(section.range()?).ok_or(Error::UnexpectedEof)?) } Format::Macho => { let parsed = binfarce::macho::parse(data)?; let section = parsed.section_with_name("__DATA", ".dep-v0")?; let section = section.ok_or(Error::NoAuditData)?; Ok(data.get(section.range()?).ok_or(Error::UnexpectedEof)?) } Format::PE => { let parsed = binfarce::pe::parse(data)?; let section = parsed .section_with_name(".dep-v0")? .ok_or(Error::NoAuditData)?; Ok(data.get(section.range()?).ok_or(Error::UnexpectedEof)?) } _ => Err(Error::NotAnExecutable), } } #[derive(Debug, Copy, Clone)] pub enum Error { NoAuditData, NotAnExecutable, UnexpectedEof, MalformedFile, SymbolsSectionIsMissing, SectionIsMissing, UnexpectedSectionType, } impl std::error::Error for Error {} impl std::fmt::Display for Error { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { let message = match self { Error::NoAuditData => "No audit data found in the executable", Error::NotAnExecutable => "Not an executable file", Error::UnexpectedEof => "Unexpected end of file", Error::MalformedFile => "Malformed executable file", Error::SymbolsSectionIsMissing => "Symbols section missing from executable", Error::SectionIsMissing => "Section is missing from executable", Error::UnexpectedSectionType => "Unexpected executable section type", }; write!(f, "{}", message) } } impl From for Error { fn from(e: binfarce::ParseError) -> Self { match e { binfarce::ParseError::MalformedInput => Error::MalformedFile, binfarce::ParseError::UnexpectedEof => Error::UnexpectedEof, binfarce::ParseError::SymbolsSectionIsMissing => Error::SymbolsSectionIsMissing, binfarce::ParseError::SectionIsMissing(_) => Error::SectionIsMissing, binfarce::ParseError::UnexpectedSectionType { .. } => Error::UnexpectedSectionType, } } }