diff --git a/fuzzers/FRET/src/fuzzer.rs b/fuzzers/FRET/src/fuzzer.rs index 5a83eff762..98352edaf7 100644 --- a/fuzzers/FRET/src/fuzzer.rs +++ b/fuzzers/FRET/src/fuzzer.rs @@ -46,6 +46,8 @@ use std::time::{SystemTime, UNIX_EPOCH}; use clap::{Parser, Subcommand}; use csv::Reader; +// Constants ================================================================================ + pub static mut RNG_SEED: u64 = 1; pub static mut LIMIT : u32 = u32::MAX; @@ -83,6 +85,7 @@ extern "C" { static mut libafl_num_interrupts : usize; } +// Argument parsing ================================================================================ #[derive(Parser)] #[command(author, version, about, long_about = None)] @@ -111,6 +114,10 @@ struct Cli { #[arg(short='r', long)] dump_traces: bool, + /// do graph dumps (if supported) + #[arg(short='g', long)] + dump_graph: bool, + #[command(subcommand)] command: Commands, } @@ -136,25 +143,82 @@ enum Commands { } } +/// Takes a state, cli and a suffix, writes out the current worst case macro_rules! do_dump_case { - ( $s:expr,$c:expr) => { - println!("Dumping worst case to {:?}", $c); - let corpus = $s.corpus(); - let mut worst = Duration::new(0,0); - let mut worst_input = None; - for i in 0..corpus.count() { - let tc = corpus.get(i.into()).expect("Could not get element from corpus").borrow(); - if worst < tc.exec_time().expect("Testcase missing duration") { - worst_input = Some(tc.input().as_ref().unwrap().bytes().to_owned()); - worst = tc.exec_time().expect("Testcase missing duration"); + ( $s:expr,$cli:expr, $c:expr) => { + if ($cli.dump_cases) { + let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"case"} else {$c}); + println!("Dumping worst case to {:?}", &dump_path); + let corpus = $s.corpus(); + let mut worst = Duration::new(0,0); + let mut worst_input = None; + for i in 0..corpus.count() { + let tc = corpus.get(i.into()).expect("Could not get element from corpus").borrow(); + if worst < tc.exec_time().expect("Testcase missing duration") { + worst_input = Some(tc.input().as_ref().unwrap().bytes().to_owned()); + worst = tc.exec_time().expect("Testcase missing duration"); + } + } + if let Some(wi) = worst_input { + fs::write(dump_path,wi).expect("Failed to write worst corpus element"); } } - if let Some(wi) = worst_input { - fs::write(&$c,wi).expect("Failed to write worst corpus element"); - } } } +/// Takes a state, cli and a suffix, appends icount history +macro_rules! do_dump_times { + ($state:expr, $cli:expr, $c:expr) => { + if $cli.dump_times { + let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"times"} else {$c}); + let mut file = std::fs::OpenOptions::new() + .read(true) + .write(true) + .create(true) + .append(true) + .open(dump_path).expect("Could not open timedump"); + if let Ok(ichist) = $state.metadata_mut::() { + for i in ichist.0.drain(..) { + writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed"); + } + } + } + }; +} + +/// Takes a state and a bool, writes out the current graph +macro_rules! do_dump_graph { + ($state:expr, $cli:expr, $c:expr) => { + #[cfg(feature = "feed_systemgraph")] + if $cli.dump_graph { + let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"graph"} else {$c}); + println!("Dumping graph to {:?}", &dump_path); + if let Some(md) = $state.named_metadata_map_mut().get_mut::("SysMap") { + let out = md.graph.map(|i,x| x.pretty_print(), |_,_| ()); + fs::write(dump_path,ron::to_string(&out).expect("Failed to serialize graph")).expect("Failed to write graph"); + } + } + }; +} + +/// Takes a state and a bool, writes out top rated inputs +macro_rules! do_dump_toprated { + ($state:expr, $cli:expr, $c:expr) => { + if $cli.dump_cases { + { + let dump_path = $cli.dump_name.clone().unwrap().with_extension(if $c=="" {"toprated"} else {$c}); + println!("Dumping toprated to {:?}", &dump_path); + if let Some(md) = $state.metadata_map_mut().get_mut::() { + let mut uniq: Vec = md.map.values().map(|x| x.clone()).collect(); + uniq.sort(); + uniq.dedup(); + fs::write(dump_path,ron::to_string(&md.map).expect("Failed to serialize metadata")).expect("Failed to write graph"); + } + } + } + }; +} + fn env_from_config(kernel : &PathBuf, path : &PathBuf) { let is_csv = path.as_path().extension().map_or(false, |x| x=="csv"); if !is_csv { @@ -183,15 +247,18 @@ fn env_from_config(kernel : &PathBuf, path : &PathBuf) { } } +// Fuzzer setup ================================================================================ + pub fn fuzz() { let cli = Cli::parse(); env_from_config(&cli.kernel, &cli.config); unsafe {FUZZ_START_TIMESTAMP = SystemTime::now();} if let Some(n) = &cli.dump_name { - env::set_var("DUMP_NAME", n); if cli.dump_times { env::set_var("DUMP_TIMES", n.with_extension("time")); } + } else if cli.dump_times || cli.dump_cases || cli.dump_traces || cli.dump_graph { + cli.dump_name.clone().expect("Dump name not give but dump is requested"); } let mut starttime = std::time::Instant::now(); if let Ok(s) = env::var("FUZZ_SIZE") { @@ -565,14 +632,7 @@ pub fn fuzz() { Some(t) => { println!("Iterations {}",t); let num = t; - if let Ok(s) = env::var("FUZZ_RANDOM") { unsafe { - if s.contains("watersv2_int") { - println!("V2"); - LIMIT=7000000; - } else { - println!("V1"); - LIMIT=5000000; - } + if random { unsafe { println!("Random Fuzzing, ignore corpus"); // let mut generator = RandBytesGenerator::new(MAX_INPUT_SIZE); let target_duration = Duration::from_secs(num); @@ -593,46 +653,18 @@ pub fn fuzz() { .unwrap(); #[cfg(feature = "run_until_saturation")] { - { let mut dumper = |marker : String| { - if let Ok(td) = env::var("DUMP_TIMES") { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .append(true) - .open(td).expect("Could not open timedump"); - if let Some(ichist) = state.metadata_map_mut().get_mut::() { - for i in ichist.0.drain(..) { - writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed"); - } - } - } - if let Ok(td) = env::var("CASE_DUMP") { - let cd = cli.dump_name.clone().expect("Dump name not give").with_extension("time"); - do_dump_case!(state,cd); - #[cfg(feature = "feed_systemgraph")] - { - let mut gd = String::from(&td); - gd.push_str(&format!(".graph{}", marker)); - if let Some(md) = state.named_metadata_mut().get_mut::("SysMap") { - fs::write(&gd,ron::to_string(&md).expect("Failed to serialize graph")).expect("Failed to write graph"); - } - } - { - let mut gd = String::from(&td); - if let Some(md) = state.metadata_map_mut().get_mut::() { - let mut uniq: Vec = md.map.values().map(|x| x.clone()).collect(); - uniq.sort(); - uniq.dedup(); - gd.push_str(&format!(".{}.toprated{}", uniq.len(), marker)); - fs::write(&gd,ron::to_string(&md.map).expect("Failed to serialize metadata")).expect("Failed to write graph"); - } - } - } + let d = format!("{}.case",marker); + do_dump_case!(state, &cli, &d); + let _d = format!("{}.graph",marker); + do_dump_graph!(state, &cli, &_d); + let d = format!("{}.toprated",marker); + do_dump_toprated!(state, &cli, &d); }; + dumper(format!(".iter_{}",t)); - } + do_dump_times!(state, &cli, ""); + println!("Start running until saturation"); let mut last = state.metadata_map().get::().unwrap().1; while SystemTime::now().duration_since(unsafe {FUZZ_START_TIMESTAMP}).unwrap().as_millis() < last.1 + Duration::from_secs(10800).as_millis() { @@ -644,64 +676,16 @@ pub fn fuzz() { if after.0 > last.0 { last=after; } - if let Ok(td) = env::var("CASE_DUMP") { - let cd = cli.dump_name.clone().expect("Dump name not give").with_extension("time"); - do_dump_case!(state,cd); - #[cfg(feature = "feed_systemgraph")] - { - let mut gd = String::from(&td); - gd.push_str(".graph" ); - if let Some(md) = state.named_metadata_map_mut().get_mut::("SysMap") { - fs::write(&gd,ron::to_string(&md).expect("Failed to serialize graph")).expect("Failed to write graph"); - } - } - { - let mut gd = String::from(&td); - if let Some(md) = state.metadata_map_mut().get_mut::() { - let mut uniq: Vec = md.map.values().map(|x| x.clone()).collect(); - uniq.sort(); - uniq.dedup(); - gd.push_str(&format!(".{}.toprated", uniq.len())); - fs::write(&gd,ron::to_string(&md.map).expect("Failed to serialize metadata")).expect("Failed to write graph"); - } - } - } - } - } - } - if let Ok(td) = env::var("DUMP_TIMES") { - let mut file = OpenOptions::new() - .read(true) - .write(true) - .create(true) - .append(true) - .open(td).expect("Could not open timedump"); - if let Ok(ichist) = state.metadata_mut::() { - for i in ichist.0.drain(..) { - writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed"); - } - } - } - if cli.dump_cases { - let cd = cli.dump_name.clone().expect("Dump name not give").with_extension("case"); - do_dump_case!(state,cd); - #[cfg(feature = "feed_systemgraph")] - { - let mut gd = cli.dump_name.clone().expect("Dump name not give").with_extension("graph"); - if let Some(md) = state.named_metadata_map_mut().get_mut::("SysMap") { - fs::write(&gd,ron::to_string(&md).expect("Failed to serialize graph")).expect("Failed to write graph"); - } - } - { - let gd = cli.dump_name.clone().expect("Dump name not give").with_extension("toprated"); - if let Ok(md) = state.metadata_mut::() { - let mut uniq: Vec = md.map.values().map(|x| x.clone()).collect(); - uniq.sort(); - uniq.dedup(); - fs::write(&gd,ron::to_string(&(uniq.len(),&md.map)).expect("Failed to serialize metadata")).expect("Failed to write graph"); + do_dump_case!(state, &cli, ""); + do_dump_graph!(state, &cli, ""); + do_dump_toprated!(state, &cli, ""); } } } + do_dump_times!(state, &cli, ""); + do_dump_case!(state, &cli, ""); + do_dump_graph!(state, &cli, ""); + do_dump_toprated!(state, &cli, ""); }, } }