Skip to content

Commit a148b33

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 3d5a0fe commit a148b33

File tree

3 files changed

+95
-0
lines changed

3 files changed

+95
-0
lines changed

Cargo.lock

+36
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

Cargo.toml

+2
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
goblin = "0.6.0"
3233
ignore = "0.4.18"
3334
memmap2 = "0.5.7"
@@ -61,6 +62,7 @@ name = "checksec"
6162
path = "src/main.rs"
6263

6364
[features]
65+
archives = ["compress-tools"]
6466
color = ["colored", "colored_json", "xattr"]
6567
default = ["elf", "macho", "pe", "color", "maps"]
6668
elf = ["shared"]

src/main.rs

+57
Original file line numberDiff line numberDiff line change
@@ -24,6 +24,8 @@ use sysinfo::{
2424
};
2525

2626
use std::ffi::OsStr;
27+
#[cfg(feature = "archives")]
28+
use std::io::Cursor;
2729
use std::path::Path;
2830
use std::{env, fmt, fs, process};
2931

@@ -32,6 +34,8 @@ use colored::Colorize;
3234

3335
#[cfg(feature = "color")]
3436
use colored_json::to_colored_json_auto;
37+
#[cfg(feature = "archives")]
38+
use compress_tools::{ArchiveContents, ArchiveIterator};
3539

3640
mod binary;
3741
mod proc;
@@ -132,6 +136,8 @@ fn print_process_results(processes: &Processes, settings: &output::Settings) {
132136
enum ParseError {
133137
Goblin(goblin::error::Error),
134138
IO(std::io::Error),
139+
#[cfg(feature = "archives")]
140+
Decompress(compress_tools::Error),
135141
#[allow(dead_code)]
136142
Unimplemented(&'static str),
137143
}
@@ -141,6 +147,8 @@ impl fmt::Display for ParseError {
141147
match self {
142148
Self::Goblin(e) => e.fmt(f),
143149
Self::IO(e) => e.fmt(f),
150+
#[cfg(feature = "archives")]
151+
Self::Decompress(e) => e.fmt(f),
144152
Self::Unimplemented(str) => {
145153
write!(f, "Support for files of type {str} not implemented")
146154
}
@@ -160,6 +168,13 @@ impl From<std::io::Error> for ParseError {
160168
}
161169
}
162170

171+
#[cfg(feature = "archives")]
172+
impl From<compress_tools::Error> for ParseError {
173+
fn from(err: compress_tools::Error) -> ParseError {
174+
ParseError::Decompress(err)
175+
}
176+
}
177+
163178
fn parse(file: &Path) -> Result<Vec<Binary>, ParseError> {
164179
let fp = fs::File::open(file)?;
165180
let buffer = unsafe { Mmap::map(&fp)? };
@@ -257,6 +272,48 @@ fn parse_bytes(bytes: &[u8], file: &Path) -> Result<Vec<Binary>, ParseError> {
257272
#[cfg(not(feature = "macho"))]
258273
Object::Mach(_) => Err(ParseError::Unimplemented("MachO")),
259274
Object::Archive(archive) => Ok(parse_archive(&archive, file, bytes)),
275+
#[cfg(feature = "archives")]
276+
Object::Unknown(magic) => {
277+
let mut results = Vec::new();
278+
let mut handled = false;
279+
280+
let mut name = String::default();
281+
let mut buffer = Vec::new();
282+
283+
for content in ArchiveIterator::from_read(Cursor::new(bytes))? {
284+
match content {
285+
ArchiveContents::StartOfEntry(s, _) => {
286+
name = s;
287+
buffer.clear();
288+
}
289+
ArchiveContents::DataChunk(v) => buffer.extend(v),
290+
ArchiveContents::EndOfEntry => {
291+
if buffer != bytes {
292+
handled = true;
293+
294+
if let Ok(mut res) = parse_bytes(
295+
&buffer,
296+
Path::new(&format!(
297+
"{}\u{2794}{}",
298+
file.display(),
299+
name
300+
)),
301+
) {
302+
results.append(&mut res);
303+
}
304+
}
305+
}
306+
ArchiveContents::Err(e) => Err(e)?,
307+
}
308+
}
309+
310+
if handled {
311+
Ok(results)
312+
} else {
313+
Err(ParseError::Goblin(Error::BadMagic(magic)))
314+
}
315+
}
316+
#[cfg(not(feature = "archives"))]
260317
Object::Unknown(magic) => {
261318
Err(ParseError::Goblin(Error::BadMagic(magic)))
262319
}

0 commit comments

Comments
 (0)