This commit is contained in:
Audrey 2024-04-17 09:44:17 -07:00
parent 62f7e40c64
commit fbc5634ad9
3 changed files with 81 additions and 37 deletions

View File

@ -1,13 +1,17 @@
use std::{ use std::{
borrow::Cow,
collections::{BTreeMap, HashMap, HashSet}, collections::{BTreeMap, HashMap, HashSet},
fs, io, fs, io,
path::PathBuf, borrow::Cow, path::PathBuf,
}; };
use gimli::{constants, DW_TAG_compile_unit}; use gimli::{constants, DW_TAG_compile_unit};
use object::{Object, ObjectSection, ReadCache};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use sha2::{digest::generic_array::{GenericArray, typenum::U32}, Digest, Sha256}; use sha2::{
use object::{Object, ReadCache, ObjectSection}; digest::generic_array::{typenum::U32, GenericArray},
Digest, Sha256,
};
use typed_arena::Arena; use typed_arena::Arena;
#[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)] #[derive(Serialize, Deserialize, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Debug)]
@ -20,7 +24,7 @@ pub struct Sha256Hash {
impl From<GenericArray<u8, U32>> for Sha256Hash { impl From<GenericArray<u8, U32>> for Sha256Hash {
fn from(value: GenericArray<u8, U32>) -> Self { fn from(value: GenericArray<u8, U32>) -> Self {
Self { Self {
inner: value.into() inner: value.into(),
} }
} }
} }
@ -43,9 +47,7 @@ pub struct FileStoreEntry {
#[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)] #[derive(Clone, Debug, PartialEq, Eq, Serialize, Deserialize)]
pub enum FileFormat { pub enum FileFormat {
ELF { ELF { references: Vec<usize> },
references: Vec<usize>,
},
Other, Other,
} }
@ -116,8 +118,7 @@ impl FileStore {
} }
}; };
if index == self.files.len() { if index == self.files.len() {}
}
self.filenames.insert(filename, index); self.filenames.insert(filename, index);
Ok(()) Ok(())
@ -201,12 +202,16 @@ impl FileStore {
if entry.tag() == DW_TAG_compile_unit { if entry.tag() == DW_TAG_compile_unit {
let mut basename = None; let mut basename = None;
let mut dirname = None; let mut dirname = None;
if let Some(name) = entry.attr(constants::DW_AT_name)?.map(|a| a.value()) { if let Some(name) =
entry.attr(constants::DW_AT_name)?.map(|a| a.value())
{
if let Ok(name) = dwarf.attr_string(&dwarf.unit(unit)?, name) { if let Ok(name) = dwarf.attr_string(&dwarf.unit(unit)?, name) {
basename = Some(PathBuf::from(name.to_string()?)); basename = Some(PathBuf::from(name.to_string()?));
} }
} }
if let Some(name) = entry.attr(constants::DW_AT_comp_dir)?.map(|a| a.value()) { if let Some(name) =
entry.attr(constants::DW_AT_comp_dir)?.map(|a| a.value())
{
if let Ok(name) = dwarf.attr_string(&dwarf.unit(unit)?, name) { if let Ok(name) = dwarf.attr_string(&dwarf.unit(unit)?, name) {
dirname = Some(PathBuf::from(name.to_string()?)); dirname = Some(PathBuf::from(name.to_string()?));
} }
@ -218,11 +223,15 @@ impl FileStore {
} }
} }
let references = inputs.into_iter().map(|input| self.ingest_dependency_local(input)).collect::<Result<Vec<_>, _>>()?.into_iter().filter_map(|x| x).collect(); let references = inputs
FileFormat::ELF { .into_iter()
references, .map(|input| self.ingest_dependency_local(input))
} .collect::<Result<Vec<_>, _>>()?
}, .into_iter()
.filter_map(|x| x)
.collect();
FileFormat::ELF { references }
}
_ => FileFormat::Other, _ => FileFormat::Other,
}) })
} }

View File

@ -1,6 +1,6 @@
mod tracer;
mod filestore; mod filestore;
mod reports; mod reports;
mod tracer;
use std::path::PathBuf; use std::path::PathBuf;
@ -38,16 +38,27 @@ enum Subcommands {
/// The filepath to dump the json report to. will dump to stdout if unspecified. /// The filepath to dump the json report to. will dump to stdout if unspecified.
output: Option<PathBuf>, output: Option<PathBuf>,
} },
} }
fn main() { fn main() {
env_logger::init(); env_logger::init();
let cli = Cli::parse(); let cli = Cli::parse();
match cli.cmd { match cli.cmd {
Subcommands::Run { file_scope, output, cmd, mute } => { Subcommands::Run {
file_scope,
output,
cmd,
mute,
} => {
let fp: Box<dyn std::io::Write> = if let Some(output) = &output { let fp: Box<dyn std::io::Write> = if let Some(output) = &output {
Box::new(std::fs::File::options().write(true).create(true).open(output).unwrap()) Box::new(
std::fs::File::options()
.write(true)
.create(true)
.open(output)
.unwrap(),
)
} else { } else {
Box::new(std::io::stdout()) Box::new(std::io::stdout())
}; };
@ -58,11 +69,18 @@ fn main() {
serde_json::to_writer_pretty(fp, &t.report) serde_json::to_writer_pretty(fp, &t.report)
} else { } else {
serde_json::to_writer(fp, &t.report) serde_json::to_writer(fp, &t.report)
}.expect("Could not serialize json trace report"); }
.expect("Could not serialize json trace report");
} }
Subcommands::QueryParameters { input, output } => { Subcommands::QueryParameters { input, output } => {
let fp: Box<dyn std::io::Write> = if let Some(output) = &output { let fp: Box<dyn std::io::Write> = if let Some(output) = &output {
Box::new(std::fs::File::options().write(true).create(true).open(output).unwrap()) Box::new(
std::fs::File::options()
.write(true)
.create(true)
.open(output)
.unwrap(),
)
} else { } else {
Box::new(std::io::stdout()) Box::new(std::io::stdout())
}; };
@ -71,7 +89,8 @@ fn main() {
serde_json::from_reader(std::fs::File::open(input).unwrap()) serde_json::from_reader(std::fs::File::open(input).unwrap())
} else { } else {
serde_json::from_reader(std::io::stdin()) serde_json::from_reader(std::io::stdin())
}.expect("Could not deserialize json trace report"); }
.expect("Could not deserialize json trace report");
let out_report = reports::parameters::run(&in_report).unwrap(); let out_report = reports::parameters::run(&in_report).unwrap();
@ -79,7 +98,8 @@ fn main() {
serde_json::to_writer_pretty(fp, &out_report) serde_json::to_writer_pretty(fp, &out_report)
} else { } else {
serde_json::to_writer(fp, &out_report) serde_json::to_writer(fp, &out_report)
}.expect("Could not serialize json parameter report"); }
.expect("Could not serialize json parameter report");
} }
} }
} }

View File

@ -2,18 +2,18 @@ use std::{
collections::HashMap, collections::HashMap,
ffi::CString, ffi::CString,
ffi::OsString, ffi::OsString,
os::{fd::{AsRawFd}, unix::prelude::OsStringExt}, fmt::{Display, Formatter},
os::{fd::AsRawFd, unix::prelude::OsStringExt},
path::PathBuf, path::PathBuf,
process::exit, process::exit,
time::{Duration, Instant}, time::{Duration, Instant},
fmt::{Display, Formatter},
}; };
use core::fmt; use core::fmt;
use nix::{ use nix::{
errno::Errno, errno::Errno,
libc::{pid_t, raise, tcsetpgrp, AT_EMPTY_PATH, SIGSTOP, STDIN_FILENO, AT_FDCWD}, libc::{pid_t, raise, tcsetpgrp, AT_EMPTY_PATH, AT_FDCWD, SIGSTOP, STDIN_FILENO},
sys::{ sys::{
ptrace::{self, traceme, AddressType}, ptrace::{self, traceme, AddressType},
signal::Signal, signal::Signal,
@ -446,10 +446,7 @@ impl Tracer {
Ok(Self { Ok(Self {
store: ProcessStateStore::default(), store: ProcessStateStore::default(),
start_time: Instant::now(), start_time: Instant::now(),
report: TracerReport { report: TracerReport { log: vec![], files },
log: vec![],
files,
},
}) })
} }
@ -585,7 +582,14 @@ impl Tracer {
// So we need to determine whether exec is successful here. // So we need to determine whether exec is successful here.
// PTRACE_EVENT_EXEC only happens for successful exec. // PTRACE_EVENT_EXEC only happens for successful exec.
p.is_exec_successful = true; p.is_exec_successful = true;
let path = p.pending_syscall_event.iter().find_map(|e| match e { Event::Exec { prog, .. } => Some(prog.clone()), _ => None }).unwrap(); let path = p
.pending_syscall_event
.iter()
.find_map(|e| match e {
Event::Exec { prog, .. } => Some(prog.clone()),
_ => None,
})
.unwrap();
self.report.files.ingest_output_local(path)?; self.report.files.ingest_output_local(path)?;
self.drain_syscall_events(pid.into(), Box::new(|_| {})); self.drain_syscall_events(pid.into(), Box::new(|_| {}));
// Don't use seccomp_aware_cont here because that will skip the next syscall exit stop // Don't use seccomp_aware_cont here because that will skip the next syscall exit stop
@ -634,10 +638,17 @@ impl Tracer {
} }
if mute { if mute {
let null = std::fs::File::options().read(true).write(true).open("/dev/null").expect("Could not open /dev/null"); let null = std::fs::File::options()
nix::unistd::dup2(null.as_raw_fd(), 0).expect("Could not dup /dev/null to /dev/stdin"); .read(true)
nix::unistd::dup2(null.as_raw_fd(), 1).expect("Could not dup /dev/null to /dev/stdout"); .write(true)
nix::unistd::dup2(null.as_raw_fd(), 2).expect("Could not dup /dev/null to /dev/stderr"); .open("/dev/null")
.expect("Could not open /dev/null");
nix::unistd::dup2(null.as_raw_fd(), 0)
.expect("Could not dup /dev/null to /dev/stdin");
nix::unistd::dup2(null.as_raw_fd(), 1)
.expect("Could not dup /dev/null to /dev/stdout");
nix::unistd::dup2(null.as_raw_fd(), 2)
.expect("Could not dup /dev/null to /dev/stderr");
} }
let args = args let args = args
@ -780,7 +791,11 @@ impl Tracer {
nix::libc::SYS_open | nix::libc::SYS_openat => { nix::libc::SYS_open | nix::libc::SYS_openat => {
if result >= 0 { if result >= 0 {
for pending in p.pending_syscall_event.iter_mut() { for pending in p.pending_syscall_event.iter_mut() {
if let Event::FdOpen { source: FdSource::File { path }, .. } = pending { if let Event::FdOpen {
source: FdSource::File { path },
..
} = pending
{
self.report.files.ingest_output_local(path.clone())?; self.report.files.ingest_output_local(path.clone())?;
} }
} }