use log::{debug, warn};
use crate::errors::{Error, Result};
use crate::options::status::DisplayInColorTerm;
use crate::options::{BinarySecurityOption, ELFStackProtectionOption};
use crate::parser::BinaryParser;
pub(crate) fn analyze_binary(
parser: &BinaryParser,
options: &crate::cmdline::Options,
) -> Result<Vec<Box<dyn DisplayInColorTerm>>> {
let has_stack_protection = ELFStackProtectionOption.check(parser, options)?;
Ok(vec![has_stack_protection])
}
pub(crate) fn has_stack_protection(
parser: &BinaryParser,
archive: &goblin::archive::Archive,
) -> Result<bool> {
let bytes = parser.bytes();
for member_name in archive.members() {
let buffer =
archive
.extract(member_name, bytes)
.map_err(|source| Error::ExtractArchiveMember {
member: member_name.into(),
source,
})?;
let r = member_has_stack_protection(member_name, buffer)?;
if r {
return Ok(true);
}
}
Ok(false)
}
fn member_has_stack_protection(member_name: &str, bytes: &[u8]) -> Result<bool> {
use goblin::Object;
let obj = Object::parse(bytes).map_err(|source| Error::ParseFile { source })?;
if let Object::Elf(elf) = obj {
debug!("Format of archive member '{member_name}' is 'ELF'.");
let r = elf
.syms
.iter()
.filter_map(|symbol| crate::elf::symbol_is_named_function_or_unspecified(&elf, &symbol))
.any(|name| name == "__stack_chk_fail" || name == "__stack_chk_fail_local");
if r {
debug!(
"Found function symbol '__stack_chk_fail_local' or \
'__stack_chk_fail' inside symbols section of member '{member_name}'."
);
}
Ok(r)
} else {
warn!("Format of archive member '{member_name}' is not 'ELF'.");
Err(Error::UnexpectedBinaryFormat {
expected: "ELF",
name: member_name.into(),
})
}
}