From 1b18527bffc74c97965ccf42d5676f06c0691b82 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Christian=20G=C3=B6ttsche?= Date: Wed, 26 Oct 2022 16:53:44 +0200 Subject: [PATCH] Add feature to support compressed archives MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Add a new feature "archives" to support scanning (compresses) archives. Extracting archives is done via the create compress-tools, which uses the C library libarchive. Thus in order to build and run checksec installing libarchive is required. $ checksec -f /var/cache/apt/archives/xterm_376-1_amd64.deb ELF64: | Canary: true CFI: false SafeStack: false Fortify: Partial Fortified: 3 Fortifiable: 1 NX: true PIE: Full Relro: Full RPATH: None RUNPATH: None | File: /var/cache/apt/archives/xterm_376-1_amd64.deb➔data.tar.xz➔./usr/bin/resize ELF64: | Canary: true CFI: false SafeStack: false Fortify: Partial Fortified: 8 Fortifiable: 11 NX: true PIE: Full Relro: Full RPATH: None RUNPATH: None | File: /var/cache/apt/archives/xterm_376-1_amd64.deb➔data.tar.xz➔./usr/bin/xterm --- Cargo.lock | 36 +++++++++++++++++++++++++++++++++ Cargo.toml | 2 ++ src/main.rs | 57 +++++++++++++++++++++++++++++++++++++++++++++++++++++ 3 files changed, 95 insertions(+) diff --git a/Cargo.lock b/Cargo.lock index 0bcdd8c..7ed8744 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -56,6 +56,7 @@ dependencies = [ "clap", "colored", "colored_json", + "compress-tools", "either", "glob", "goblin", @@ -120,6 +121,18 @@ dependencies = [ "yansi", ] +[[package]] +name = "compress-tools" +version = "0.14.0" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "3a3b1511783270e75d95749c851008a01fba662a8136e488d29d2b3a51a56e08" +dependencies = [ + "derive_more", + "libc", + "pkg-config", + "vcpkg", +] + [[package]] name = "core-foundation-sys" version = "0.8.3" @@ -169,6 +182,17 @@ dependencies = [ "cfg-if", ] +[[package]] +name = "derive_more" +version = "0.99.17" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "4fb810d30a7c1953f91334de7244731fc3f3c10d7fe163338a35b9f640960321" +dependencies = [ + "proc-macro2", + "quote", + "syn", +] + [[package]] name = "either" version = "1.8.1" @@ -338,6 +362,12 @@ version = "6.3.0" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "9ff7415e9ae3fff1225851df9e0d9e4e5479f947619774677a63572e55e80eff" +[[package]] +name = "pkg-config" +version = "0.3.26" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "6ac9a59f73473f1b8d852421e59e64809f025994837ef743615c6d0c5b305160" + [[package]] name = "plain" version = "0.2.3" @@ -529,6 +559,12 @@ version = "1.0.5" source = "registry+https://github.com/rust-lang/crates.io-index" checksum = "6ceab39d59e4c9499d4e5a8ee0e2735b891bb7308ac83dfb4e80cad195c9f6f3" +[[package]] +name = "vcpkg" +version = "0.2.15" +source = "registry+https://github.com/rust-lang/crates.io-index" +checksum = "accd4ea62f7bb7a82fe23066fb0957d48ef677f6eeb8215f372f52e48bb32426" + [[package]] name = "walkdir" version = "2.3.2" diff --git a/Cargo.toml b/Cargo.toml index c569df9..761ef19 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -28,6 +28,7 @@ panic = 'abort' # Abort on panic clap = {version = "4.0.14", features = ["cargo"]} colored = {version = "2.0.0", optional = true} colored_json = {version = "3.0.1", optional = true} +compress-tools = {version = "0.14.0", optional = true} either = "1.8.1" glob = "0.3.0" goblin = "0.6.0" @@ -66,6 +67,7 @@ name = "checksec" path = "src/main.rs" [features] +archives = ["compress-tools"] color = ["colored", "colored_json", "xattr"] default = ["elf", "macho", "pe", "color", "maps", "disassembly"] disassembly = ["iced-x86"] diff --git a/src/main.rs b/src/main.rs index ca8660c..9401f5e 100644 --- a/src/main.rs +++ b/src/main.rs @@ -33,6 +33,8 @@ use std::collections::HashMap; #[cfg(all(target_os = "linux", feature = "elf"))] use std::collections::HashSet; use std::ffi::OsStr; +#[cfg(feature = "archives")] +use std::io::Cursor; use std::io::ErrorKind; #[cfg(all(feature = "color", not(target_os = "windows")))] use std::os::unix::fs::PermissionsExt; @@ -46,6 +48,8 @@ use colored::{ColoredString, Colorize}; #[cfg(feature = "color")] use colored_json::to_colored_json_auto; +#[cfg(feature = "archives")] +use compress_tools::{ArchiveContents, ArchiveIterator}; mod binary; mod proc; @@ -269,6 +273,8 @@ enum ParseError { IO(std::io::Error), #[cfg(all(target_os = "linux", feature = "elf"))] LdSo(LdSoError), + #[cfg(feature = "archives")] + Decompress(compress_tools::Error), #[allow(dead_code)] Unimplemented(&'static str), } @@ -282,6 +288,8 @@ impl fmt::Display for ParseError { Self::LdSo(e) => { write!(f, "Failed to initialize library lookup: {e}") } + #[cfg(feature = "archives")] + Self::Decompress(e) => e.fmt(f), Self::Unimplemented(str) => { write!(f, "Support for files of type {str} not implemented") } @@ -308,6 +316,13 @@ impl From for ParseError { } } +#[cfg(feature = "archives")] +impl From for ParseError { + fn from(err: compress_tools::Error) -> ParseError { + ParseError::Decompress(err) + } +} + type Cache = Arc>>>; fn parse( @@ -424,6 +439,48 @@ fn parse_bytes(bytes: &[u8], file: &Path) -> Result, ParseError> { #[cfg(not(feature = "macho"))] Object::Mach(_) => Err(ParseError::Unimplemented("MachO")), Object::Archive(archive) => Ok(parse_archive(&archive, file, bytes)), + #[cfg(feature = "archives")] + Object::Unknown(magic) => { + let mut results = Vec::new(); + let mut handled = false; + + let mut name = String::default(); + let mut buffer = Vec::new(); + + for content in ArchiveIterator::from_read(Cursor::new(bytes))? { + match content { + ArchiveContents::StartOfEntry(s, _) => { + name = s; + buffer.clear(); + } + ArchiveContents::DataChunk(v) => buffer.extend(v), + ArchiveContents::EndOfEntry => { + if buffer != bytes { + handled = true; + + if let Ok(mut res) = parse_bytes( + &buffer, + Path::new(&format!( + "{}\u{2794}{}", + file.display(), + name + )), + ) { + results.append(&mut res); + } + } + } + ArchiveContents::Err(e) => Err(e)?, + } + } + + if handled { + Ok(results) + } else { + Err(ParseError::Goblin(Error::BadMagic(magic))) + } + } + #[cfg(not(feature = "archives"))] Object::Unknown(magic) => { Err(ParseError::Goblin(Error::BadMagic(magic))) }