auditable_extract/
lib.rs

1#![forbid(unsafe_code)]
2#![doc = include_str!("../README.md")]
3
4#[cfg(feature = "wasm")]
5mod wasm;
6
7use binfarce::Format;
8
9/// Extracts the Zlib-compressed dependency info from an executable.
10///
11/// This function does not allocate any memory on the heap and can be safely given untrusted input.
12pub fn raw_auditable_data(data: &[u8]) -> Result<&[u8], Error> {
13    match binfarce::detect_format(data) {
14        Format::Elf32 { byte_order } => {
15            let section = binfarce::elf32::parse(data, byte_order)?
16                .section_with_name(".dep-v0")?
17                .ok_or(Error::NoAuditData)?;
18            Ok(data.get(section.range()?).ok_or(Error::UnexpectedEof)?)
19        }
20        Format::Elf64 { byte_order } => {
21            let section = binfarce::elf64::parse(data, byte_order)?
22                .section_with_name(".dep-v0")?
23                .ok_or(Error::NoAuditData)?;
24            Ok(data.get(section.range()?).ok_or(Error::UnexpectedEof)?)
25        }
26        Format::Macho => {
27            let parsed = binfarce::macho::parse(data)?;
28            let section = parsed.section_with_name("__DATA", ".dep-v0")?;
29            let section = section.ok_or(Error::NoAuditData)?;
30            Ok(data.get(section.range()?).ok_or(Error::UnexpectedEof)?)
31        }
32        Format::PE => {
33            let parsed = binfarce::pe::parse(data)?;
34            let section = parsed
35                .section_with_name(".dep-v0")?
36                .ok_or(Error::NoAuditData)?;
37            Ok(data.get(section.range()?).ok_or(Error::UnexpectedEof)?)
38        }
39        Format::Unknown => {
40            #[cfg(feature = "wasm")]
41            if data.starts_with(b"\0asm") {
42                return wasm::raw_auditable_data_wasm(data);
43            }
44
45            Err(Error::NotAnExecutable)
46        }
47    }
48}
49
50#[cfg(all(fuzzing, feature = "wasm"))]
51pub fn raw_auditable_data_wasm_for_fuzz(input: &[u8]) -> Result<&[u8], Error> {
52    wasm::raw_auditable_data_wasm(input)
53}
54
55#[derive(Debug, Copy, Clone)]
56pub enum Error {
57    NoAuditData,
58    NotAnExecutable,
59    UnexpectedEof,
60    MalformedFile,
61    SymbolsSectionIsMissing,
62    SectionIsMissing,
63    UnexpectedSectionType,
64}
65
66impl std::error::Error for Error {}
67
68impl std::fmt::Display for Error {
69    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
70        let message = match self {
71            Error::NoAuditData => "No audit data found in the executable",
72            Error::NotAnExecutable => "Not an executable file",
73            Error::UnexpectedEof => "Unexpected end of file",
74            Error::MalformedFile => "Malformed executable file",
75            Error::SymbolsSectionIsMissing => "Symbols section missing from executable",
76            Error::SectionIsMissing => "Section is missing from executable",
77            Error::UnexpectedSectionType => "Unexpected executable section type",
78        };
79        write!(f, "{message}")
80    }
81}
82
83impl From<binfarce::ParseError> for Error {
84    fn from(e: binfarce::ParseError) -> Self {
85        match e {
86            binfarce::ParseError::MalformedInput => Error::MalformedFile,
87            binfarce::ParseError::UnexpectedEof => Error::UnexpectedEof,
88            binfarce::ParseError::SymbolsSectionIsMissing => Error::SymbolsSectionIsMissing,
89            binfarce::ParseError::SectionIsMissing(_) => Error::SectionIsMissing,
90            binfarce::ParseError::UnexpectedSectionType { .. } => Error::UnexpectedSectionType,
91        }
92    }
93}