Skip to content

Commit 1b18527

Browse files
committed
Add feature to support compressed archives
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
1 parent c4f56c4 commit 1b18527

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

Cargo.lock

Lines changed: 36 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ panic = 'abort' # Abort on panic
2828
clap = {version = "4.0.14", features = ["cargo"]}
2929
colored = {version = "2.0.0", optional = true}
3030
colored_json = {version = "3.0.1", optional = true}
31+
compress-tools = {version = "0.14.0", optional = true}
3132
either = "1.8.1"
3233
glob = "0.3.0"
3334
goblin = "0.6.0"
@@ -66,6 +67,7 @@ name = "checksec"
6667
path = "src/main.rs"
6768

6869
[features]
70+
archives = ["compress-tools"]
6971
color = ["colored", "colored_json", "xattr"]
7072
default = ["elf", "macho", "pe", "color", "maps", "disassembly"]
7173
disassembly = ["iced-x86"]

src/main.rs

Lines changed: 57 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,8 @@ use std::collections::HashMap;
3333
#[cfg(all(target_os = "linux", feature = "elf"))]
3434
use std::collections::HashSet;
3535
use std::ffi::OsStr;
36+
#[cfg(feature = "archives")]
37+
use std::io::Cursor;
3638
use std::io::ErrorKind;
3739
#[cfg(all(feature = "color", not(target_os = "windows")))]
3840
use std::os::unix::fs::PermissionsExt;
@@ -46,6 +48,8 @@ use colored::{ColoredString, Colorize};
4648

4749
#[cfg(feature = "color")]
4850
use colored_json::to_colored_json_auto;
51+
#[cfg(feature = "archives")]
52+
use compress_tools::{ArchiveContents, ArchiveIterator};
4953

5054
mod binary;
5155
mod proc;
@@ -269,6 +273,8 @@ enum ParseError {
269273
IO(std::io::Error),
270274
#[cfg(all(target_os = "linux", feature = "elf"))]
271275
LdSo(LdSoError),
276+
#[cfg(feature = "archives")]
277+
Decompress(compress_tools::Error),
272278
#[allow(dead_code)]
273279
Unimplemented(&'static str),
274280
}
@@ -282,6 +288,8 @@ impl fmt::Display for ParseError {
282288
Self::LdSo(e) => {
283289
write!(f, "Failed to initialize library lookup: {e}")
284290
}
291+
#[cfg(feature = "archives")]
292+
Self::Decompress(e) => e.fmt(f),
285293
Self::Unimplemented(str) => {
286294
write!(f, "Support for files of type {str} not implemented")
287295
}
@@ -308,6 +316,13 @@ impl From<LdSoError> for ParseError {
308316
}
309317
}
310318

319+
#[cfg(feature = "archives")]
320+
impl From<compress_tools::Error> for ParseError {
321+
fn from(err: compress_tools::Error) -> ParseError {
322+
ParseError::Decompress(err)
323+
}
324+
}
325+
311326
type Cache = Arc<Mutex<HashMap<PathBuf, Vec<Binary>>>>;
312327

313328
fn parse(
@@ -424,6 +439,48 @@ fn parse_bytes(bytes: &[u8], file: &Path) -> Result<Vec<Binary>, ParseError> {
424439
#[cfg(not(feature = "macho"))]
425440
Object::Mach(_) => Err(ParseError::Unimplemented("MachO")),
426441
Object::Archive(archive) => Ok(parse_archive(&archive, file, bytes)),
442+
#[cfg(feature = "archives")]
443+
Object::Unknown(magic) => {
444+
let mut results = Vec::new();
445+
let mut handled = false;
446+
447+
let mut name = String::default();
448+
let mut buffer = Vec::new();
449+
450+
for content in ArchiveIterator::from_read(Cursor::new(bytes))? {
451+
match content {
452+
ArchiveContents::StartOfEntry(s, _) => {
453+
name = s;
454+
buffer.clear();
455+
}
456+
ArchiveContents::DataChunk(v) => buffer.extend(v),
457+
ArchiveContents::EndOfEntry => {
458+
if buffer != bytes {
459+
handled = true;
460+
461+
if let Ok(mut res) = parse_bytes(
462+
&buffer,
463+
Path::new(&format!(
464+
"{}\u{2794}{}",
465+
file.display(),
466+
name
467+
)),
468+
) {
469+
results.append(&mut res);
470+
}
471+
}
472+
}
473+
ArchiveContents::Err(e) => Err(e)?,
474+
}
475+
}
476+
477+
if handled {
478+
Ok(results)
479+
} else {
480+
Err(ParseError::Goblin(Error::BadMagic(magic)))
481+
}
482+
}
483+
#[cfg(not(feature = "archives"))]
427484
Object::Unknown(magic) => {
428485
Err(ParseError::Goblin(Error::BadMagic(magic)))
429486
}

0 commit comments

Comments
 (0)