From 62f7e40c64a3fd6718eed3bfc1b12ee97b68ab8d Mon Sep 17 00:00:00 2001 From: Audrey Dutcher Date: Wed, 17 Apr 2024 09:43:56 -0700 Subject: [PATCH] File scoping and reporting works --- Cargo.toml | 2 +- src/filestore.rs | 6 +++--- src/main.rs | 48 +++++++++++++++++++++++++++++++++++++++++------- src/tracer.rs | 11 +++++++++-- 4 files changed, 54 insertions(+), 13 deletions(-) diff --git a/Cargo.toml b/Cargo.toml index 1d48293..b5b64e1 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -6,7 +6,7 @@ edition = "2021" # See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html [dependencies] -nix = { version = "0.28.0", features = ["ptrace", "process"] } +nix = { version = "0.28.0", features = ["ptrace", "process", "fs"] } linux-personality = "1.0.0" anyhow = { version = "1", features = ["backtrace"] } log = "0.4" diff --git a/src/filestore.rs b/src/filestore.rs index 3d0cb1a..0dfa97b 100644 --- a/src/filestore.rs +++ b/src/filestore.rs @@ -4,7 +4,7 @@ use std::{ path::PathBuf, borrow::Cow, }; -use gimli::{constants, AttributeValue, DW_TAG_compile_unit}; +use gimli::{constants, DW_TAG_compile_unit}; use serde::{Deserialize, Serialize}; use sha2::{digest::generic_array::{GenericArray, typenum::U32}, Digest, Sha256}; use object::{Object, ReadCache, ObjectSection}; @@ -110,7 +110,7 @@ impl FileStore { self.files .get_mut(*e.get()) .unwrap() - .output_names + .input_names .insert(filename.clone()); *e.get() } @@ -130,7 +130,7 @@ impl FileStore { } let fp = fs::File::open(&filename)?; - self.ingest_output(filename, fp); + self.ingest_output(filename, fp)?; Ok(()) } diff --git a/src/main.rs b/src/main.rs index 5060010..34be403 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,5 +1,6 @@ mod tracer; mod filestore; +mod reports; use std::path::PathBuf; @@ -13,18 +14,30 @@ struct Cli { #[derive(Subcommand, Debug, Clone)] enum Subcommands { + /// Run a command and record its execution Run { /// Any number of filepaths to treat as inputs. They will be hashed and accesses to /// equivalent files will be treated specially. #[arg(short, long)] - input: Vec, + file_scope: Vec, /// The filepath to dump the json report to. will dump to stdout if unspecified. #[arg(short, long)] output: Option, + #[arg(short, long)] + mute: bool, + /// The command to run. Have fun! cmd: Vec, + }, + /// Query from the report how in-scope items were used + QueryParameters { + /// The filepath of the report ot open. will read from stdin if unspecified. + input: Option, + + /// The filepath to dump the json report to. will dump to stdout if unspecified. + output: Option, } } @@ -32,20 +45,41 @@ fn main() { env_logger::init(); let cli = Cli::parse(); match cli.cmd { - Subcommands::Run { input, output, cmd } => { + Subcommands::Run { file_scope, output, cmd, mute } => { let fp: Box = if let Some(output) = &output { Box::new(std::fs::File::options().write(true).create(true).open(output).unwrap()) } else { Box::new(std::io::stdout()) }; - let mut t = tracer::Tracer::new(input).unwrap(); - t.start_root_process(cmd).unwrap(); + let mut t = tracer::Tracer::new(file_scope).unwrap(); + t.start_root_process(cmd, mute).unwrap(); if output.is_none() { - serde_json::to_writer_pretty(fp, &t.report).unwrap(); + serde_json::to_writer_pretty(fp, &t.report) } else { - serde_json::to_writer(fp, &t.report).unwrap(); - } + serde_json::to_writer(fp, &t.report) + }.expect("Could not serialize json trace report"); + } + Subcommands::QueryParameters { input, output } => { + let fp: Box = if let Some(output) = &output { + Box::new(std::fs::File::options().write(true).create(true).open(output).unwrap()) + } else { + Box::new(std::io::stdout()) + }; + + let in_report: tracer::TracerReport = if let Some(input) = &input { + serde_json::from_reader(std::fs::File::open(input).unwrap()) + } else { + serde_json::from_reader(std::io::stdin()) + }.expect("Could not deserialize json trace report"); + + let out_report = reports::parameters::run(&in_report).unwrap(); + + if output.is_none() { + serde_json::to_writer_pretty(fp, &out_report) + } else { + serde_json::to_writer(fp, &out_report) + }.expect("Could not serialize json parameter report"); } } } diff --git a/src/tracer.rs b/src/tracer.rs index a547a5c..c77813f 100644 --- a/src/tracer.rs +++ b/src/tracer.rs @@ -2,7 +2,7 @@ use std::{ collections::HashMap, ffi::CString, ffi::OsString, - os::unix::prelude::OsStringExt, + os::{fd::{AsRawFd}, unix::prelude::OsStringExt}, path::PathBuf, process::exit, time::{Duration, Instant}, @@ -465,7 +465,7 @@ impl Tracer { } } - pub fn start_root_process(&mut self, args: Vec) -> anyhow::Result<()> { + pub fn start_root_process(&mut self, args: Vec, mute: bool) -> anyhow::Result<()> { log::trace!("start_root_process: {:?}", args); if let ForkResult::Parent { child: root_child } = unsafe { nix::unistd::fork()? } { @@ -633,6 +633,13 @@ impl Tracer { exit(-1); } + if mute { + let null = std::fs::File::options().read(true).write(true).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 .into_iter() .map(CString::new)