Skip to content

Commit

Permalink
feat: enable fuzzer PID tracking as a healthcheck (#17)
Browse files Browse the repository at this point in the history
  • Loading branch information
0xricksanchez committed Apr 29, 2024
1 parent 88a43b1 commit 6c9d509
Show file tree
Hide file tree
Showing 14 changed files with 348 additions and 196 deletions.
3 changes: 3 additions & 0 deletions AFLR_CFG_TEMPL.toml
Original file line number Diff line number Diff line change
Expand Up @@ -47,3 +47,6 @@ runner = "tmux"
[misc]
# Enable TUI mode
tui = false

# Start with no tui and detached from any session
detached = true
2 changes: 1 addition & 1 deletion Cargo.lock

Some generated files are not rendered by default. Learn more about how customized files appear on GitHub.

2 changes: 1 addition & 1 deletion Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@ name = "afl_runner"
authors = ["0x434b <admin@0x434b.dev"]
repository = "https://github.com/0xricksanchez/AFL_Runner"
description = "AFL Runner is a tool to run an efficient multi-core AFLPlusPlus campaign."
version = "0.3.4"
version = "0.3.5"
edition = "2021"
keywords = ["afl", "fuzzing", "fuzzer", "fuzz"]
license = "Apache-2.0"
Expand Down
16 changes: 15 additions & 1 deletion src/cli.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,7 @@ const AFL_OUTPUT: &str = "/tmp/afl_output";
#[derive(Parser, Debug, Clone)]
#[command(name = "Parallelized AFLPlusPlus Campaign Runner")]
#[command(author = "C.K. <admin@0x434b.dev>")]
#[command(version = "0.3.4")]
#[command(version = "0.3.5")]
pub struct Cli {
/// Subcommand to execute
#[command(subcommand)]
Expand Down Expand Up @@ -254,6 +254,13 @@ pub struct RunArgs {
/// Enable tui mode
#[arg(long, help = "Enable TUI mode", required = false)]
pub tui: bool,
/// Start detached from any session (not compatible with TUI)
#[arg(
long,
help = "Started detached from TMUX/screen session",
required = false
)]
pub detached: bool,
}

impl RunArgs {
Expand Down Expand Up @@ -283,6 +290,11 @@ impl RunArgs {
} else {
self.tui || config.misc.tui.unwrap_or(false)
},
detached: if self.dry_run {
false
} else {
self.detached || config.misc.detached.unwrap_or(false)
},
}
}
}
Expand Down Expand Up @@ -348,4 +360,6 @@ pub struct SessionConfig {
pub struct MiscConfig {
/// Enable TUI mode
pub tui: Option<bool>,
/// Enabled detached mode
pub detached: Option<bool>,
}
287 changes: 163 additions & 124 deletions src/data_collection.rs

Large diffs are not rendered by default.

15 changes: 11 additions & 4 deletions src/main.rs
Original file line number Diff line number Diff line change
Expand Up @@ -45,6 +45,9 @@ fn handle_run_command(run_args: &cli::RunArgs) -> Result<()> {
let config_args = load_config(run_args.gen_args.config.as_ref())?;
let raw_afl_flags = config_args.afl_cfg.afl_flags.clone();
let merged_args = run_args.merge(&config_args);
if merged_args.tui && merged_args.detached {
bail!("TUI and detached mode cannot be used together");
}
let harness = create_harness(&merged_args.gen_args)?;
let afl_runner = create_afl_runner(&merged_args.gen_args, harness, raw_afl_flags);
let afl_cmds = afl_runner.generate_afl_commands()?;
Expand All @@ -56,16 +59,20 @@ fn handle_run_command(run_args: &cli::RunArgs) -> Result<()> {
.join(" ");

let sname = generate_session_name(&merged_args, &target_args);
let pid_fn = format!("/tmp/.{}_{}.pids", &sname, std::process::id());
let pid_fn_path = Path::new(&pid_fn);
let srunner: Box<dyn Runner> = match &merged_args.session_runner {
SessionRunner::Screen => Box::new(Screen::new(&sname, &afl_cmds)),
SessionRunner::Tmux => Box::new(Tmux::new(&sname, &afl_cmds)),
SessionRunner::Screen => Box::new(Screen::new(&sname, &afl_cmds, pid_fn_path)),
SessionRunner::Tmux => Box::new(Tmux::new(&sname, &afl_cmds, pid_fn_path)),
};

if merged_args.tui {
srunner.run_with_tui(&merged_args.gen_args.output_dir.unwrap())?;
} else {
srunner.run()?;
srunner.attach()?;
if !merged_args.detached {
srunner.attach()?;
}
}

Ok(())
Expand All @@ -76,7 +83,7 @@ fn handle_tui_command(tui_args: &cli::TuiArgs) -> Result<()> {
bail!("Output directory is required for TUI mode");
}
validate_tui_output_dir(&tui_args.afl_output)?;
Tui::run(&tui_args.afl_output);
Tui::run(&tui_args.afl_output, None)?;
Ok(())
}

Expand Down
22 changes: 14 additions & 8 deletions src/runners/runner.rs
Original file line number Diff line number Diff line change
Expand Up @@ -13,7 +13,7 @@ use crate::utils::{get_user_input, mkdir_helper};

#[allow(unused)]
pub trait Runner {
fn new(session_name: &str, commands: &[String]) -> Self
fn new(session_name: &str, commands: &[String], pid_file: &Path) -> Self
where
Self: Sized;
fn create_bash_script(&self) -> Result<String, anyhow::Error>;
Expand All @@ -28,10 +28,16 @@ pub struct Session {
pub commands: Vec<String>,
pub log_file: PathBuf,
pub runner_name: &'static str,
pub pid_file: PathBuf,
}

impl Session {
pub fn new(session_name: &str, commands: &[String], runner_name: &'static str) -> Self {
pub fn new(
session_name: &str,
commands: &[String],
runner_name: &'static str,
pid_file: &Path,
) -> Self {
let commands = commands
.iter()
.map(|c| c.replace('"', "\\\""))
Expand All @@ -45,6 +51,7 @@ impl Session {
commands,
log_file,
runner_name,
pid_file: pid_file.to_path_buf(),
}
}

Expand All @@ -57,6 +64,7 @@ impl Session {
session_name :self.name.clone(),
commands : self.commands.clone(),
log_file : self.log_file.to_str().unwrap().to_string(),
pid_file: self.pid_file.to_str().unwrap().to_string(),
})
.to_string()
.map_err(|e| anyhow::anyhow!("Error creating bash script: {}", e))
Expand Down Expand Up @@ -91,15 +99,13 @@ impl Session {
mkdir_helper(&outdir, true)?;

println!(
"Starting {} session '{}' for {} generated commands...",
"Starting {} session '{}' for {} generated commands. Continue [Y/n]?",
self.runner_name,
self.name,
self.commands.len()
);

print!("Continue [Y/n]? ");
std::io::stdout().flush()?;
if get_user_input() != "y" {
if get_user_input() != 'y' {
anyhow::bail!("Aborting");
}

Expand Down Expand Up @@ -135,12 +141,12 @@ impl Session {

pub fn run_with_tui(&self, out_dir: &Path) -> Result<()> {
if let Err(e) = self.run_detached() {
eprintln!("Error running TUI: {e}");
eprintln!("Error running TUI: '{e}'");
return Err(e);
}

thread::sleep(Duration::from_secs(1));
Tui::run(out_dir);
Tui::run(out_dir, Some(&self.pid_file))?;
Ok(())
}

Expand Down
4 changes: 2 additions & 2 deletions src/runners/screen.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ pub struct Screen {
}

impl Runner for Screen {
fn new(session_name: &str, commands: &[String]) -> Self {
fn new(session_name: &str, commands: &[String], pid_file: &Path) -> Self {
Self {
inner: Session::new(session_name, commands, "screen"),
inner: Session::new(session_name, commands, "screen", pid_file),
}
}

Expand Down
4 changes: 2 additions & 2 deletions src/runners/tmux.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,9 +12,9 @@ pub struct Tmux {
}

impl Runner for Tmux {
fn new(session_name: &str, commands: &[String]) -> Self {
fn new(session_name: &str, commands: &[String], pid_file: &Path) -> Self {
Self {
inner: Session::new(session_name, commands, "tmux"),
inner: Session::new(session_name, commands, "tmux", pid_file),
}
}

Expand Down
41 changes: 28 additions & 13 deletions src/session.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@ use std::path::PathBuf;
use std::time::Duration;

#[allow(dead_code)]
#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct CrashInfoDetails {
pub fuzzer_name: String,
pub file_path: PathBuf,
Expand All @@ -15,9 +15,11 @@ pub struct CrashInfoDetails {
pub rep: u64,
}

#[derive(Debug)]
#[derive(Debug, Clone)]
pub struct CampaignData {
pub fuzzers_alive: usize,
pub fuzzers_started: usize,
pub fuzzer_pids: Vec<u32>,
pub total_run_time: Duration,
pub executions: ExecutionsInfo,
pub pending: PendingInfo,
Expand All @@ -38,6 +40,8 @@ impl Default for CampaignData {
fn default() -> Self {
Self {
fuzzers_alive: 0,
fuzzers_started: 0,
fuzzer_pids: Vec::new(),
total_run_time: Duration::from_secs(0),
executions: ExecutionsInfo::default(),
pending: PendingInfo::default(),
Expand All @@ -57,34 +61,45 @@ impl Default for CampaignData {
}

impl CampaignData {
pub fn new() -> Self {
Self::default()
pub fn clear(&mut self) {
self.executions = ExecutionsInfo::default();
self.pending = PendingInfo::default();
self.corpus = CorpusInfo::default();
self.coverage = CoverageInfo::default();
self.cycles = Cycles::default();
self.stability = StabilityInfo::default();
self.crashes = Solutions::default();
self.hangs = Solutions::default();
self.levels = Levels::default();
self.time_without_finds = Duration::from_secs(0);
self.last_crashes.clear();
self.last_hangs.clear();
}
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct Levels {
pub avg: usize,
pub min: usize,
pub max: usize,
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct Solutions {
pub cum: usize,
pub avg: usize,
pub min: usize,
pub max: usize,
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct StabilityInfo {
pub avg: f64,
pub min: f64,
pub max: f64,
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct Cycles {
pub done_avg: usize,
pub done_min: usize,
Expand All @@ -94,7 +109,7 @@ pub struct Cycles {
pub wo_finds_max: usize,
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct ExecutionsInfo {
pub avg: usize,
pub min: usize,
Expand All @@ -106,14 +121,14 @@ pub struct ExecutionsInfo {
pub ps_cum: f64,
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct CoverageInfo {
pub avg: f64,
pub min: f64,
pub max: f64,
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct PendingInfo {
pub favorites_avg: usize,
pub favorites_cum: usize,
Expand All @@ -125,15 +140,15 @@ pub struct PendingInfo {
pub total_max: usize,
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct CorpusInfo {
pub avg: usize,
pub cum: usize,
pub min: usize,
pub max: usize,
}

#[derive(Default, Debug)]
#[derive(Default, Debug, Clone)]
pub struct Misc {
pub afl_version: String,
pub afl_banner: String,
Expand Down
Loading

0 comments on commit 6c9d509

Please sign in to comment.