From 52cc00fedc21b3c4796b3e5e316929909c9d1bd4 Mon Sep 17 00:00:00 2001 From: Alwin Berger Date: Mon, 8 May 2023 18:23:32 +0200 Subject: [PATCH] add run_until_saturation --- fuzzers/FRET/Cargo.toml | 2 + fuzzers/FRET/src/clock.rs | 16 ++-- fuzzers/FRET/src/fuzzer.rs | 124 ++++++++++++++++++++++++++-- fuzzers/FRET/src/mutational.rs | 6 +- fuzzers/FRET/src/systemstate/mod.rs | 1 + 5 files changed, 134 insertions(+), 15 deletions(-) diff --git a/fuzzers/FRET/Cargo.toml b/fuzzers/FRET/Cargo.toml index 8db691a4c8..c57ca43fa4 100644 --- a/fuzzers/FRET/Cargo.toml +++ b/fuzzers/FRET/Cargo.toml @@ -23,6 +23,8 @@ gensize_1 = [ ] gensize_10 = [ ] gensize_100 = [ ] observer_hitcounts = [] +no_hash_state = [] +run_until_saturation = [] [profile.release] lto = true diff --git a/fuzzers/FRET/src/clock.rs b/fuzzers/FRET/src/clock.rs index a63b9a36b5..28e10771e7 100644 --- a/fuzzers/FRET/src/clock.rs +++ b/fuzzers/FRET/src/clock.rs @@ -34,6 +34,7 @@ use core::{fmt::Debug, time::Duration}; // use libafl::feedbacks::FeedbackState; // use libafl::state::HasFeedbackStates; use libafl::bolts::tuples::MatchName; +use std::time::{SystemTime, UNIX_EPOCH}; //========== Metadata #[derive(Debug, SerdeAny, Serialize, Deserialize)] @@ -84,7 +85,7 @@ impl Default for MaxIcountMetadata { /// A piece of metadata tracking all icounts #[derive(Debug, SerdeAny, Serialize, Deserialize)] -pub struct IcHist (pub Vec, pub u64); +pub struct IcHist (pub Vec<(u64, u128)>, pub (u64,u128)); //========== Observer @@ -139,11 +140,14 @@ where let hist = metadata.get_mut::(); match hist { None => { - metadata.insert(IcHist(vec![self.end_tick - self.start_tick], self.end_tick-self.start_tick)); + metadata.insert(IcHist(vec![(self.end_tick - self.start_tick, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis())], + (self.end_tick - self.start_tick, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis()))); } Some(v) => { - v.0.push(self.end_tick - self.start_tick); - v.1 = max(v.1, self.end_tick - self.start_tick); + v.0.push((self.end_tick - self.start_tick, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis())); + if (v.1.0 < self.end_tick-self.start_tick) { + v.1 = (self.end_tick - self.start_tick, SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis()); + } if v.0.len() >= 100 { if let Ok(td) = env::var("TIME_DUMP") { let mut file = OpenOptions::new() @@ -152,9 +156,9 @@ where .create(true) .append(true) .open(td).expect("Could not open timedump"); - let newv : Vec = Vec::with_capacity(100); + let newv : Vec<(u64, u128)> = Vec::with_capacity(100); for i in std::mem::replace(&mut v.0, newv).into_iter() { - writeln!(file, "{}", i).expect("Write to dump failed"); + writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed"); } } else { // If we don't write out values we don't need to remember them at all diff --git a/fuzzers/FRET/src/fuzzer.rs b/fuzzers/FRET/src/fuzzer.rs index 37be0182e8..3b3b059896 100644 --- a/fuzzers/FRET/src/fuzzer.rs +++ b/fuzzers/FRET/src/fuzzer.rs @@ -42,6 +42,7 @@ use crate::{ // systemstate::mutation::scheduled::{havoc_mutations, StdScheduledMutator}, // mutational::StdMutationalStage }; +use std::time::{SystemTime, UNIX_EPOCH}; pub static mut RNG_SEED: u64 = 1; @@ -390,9 +391,9 @@ pub fn fuzz() { .create(true) .append(true) .open(td).expect("Could not open timedump"); - if let Some(ichist) = state.metadata().get::() { - for i in ichist.0.iter() { - writeln!(file, "{}", i).expect("Write to dump failed"); + if let Some(ichist) = state.metadata_mut().get_mut::() { + for i in ichist.0.drain(..) { + writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed"); } } } @@ -452,6 +453,117 @@ pub fn fuzz() { fuzzer .fuzz_loop_until(&mut stages, &mut executor, &mut state, &mut mgr, starttime.checked_add(Duration::from_secs(num)).unwrap()) .unwrap(); + #[cfg(feature = "run_until_saturation")] + { + { + let mut dumper = |marker : String| { + if let Ok(td) = env::var("TIME_DUMP") { + 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_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") { + println!("Dumping worst case to {:?}", td); + let corpus = state.corpus(); + let mut worst = Duration::new(0,0); + let mut worst_input = None; + for i in 0..corpus.count() { + let tc = corpus.get(i).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"); + } + } + match worst_input { + Some(wi) => { + // let cd = format!("{}.case",&td); + let mut cd = td.clone(); + cd.push_str(&marker); + fs::write(&cd,wi).expect("Failed to write worst corpus element"); + }, + None => (), + } + #[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_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"); + } + } + } + }; + dumper(format!(".iter_{}",t)); + } + println!("Start running until saturation"); + let mut last = state.metadata().get::().unwrap().1; + while SystemTime::now().duration_since(UNIX_EPOCH).unwrap().as_millis() < last.1 + Duration::from_secs(10800).as_millis() { + fuzzer + .fuzz_loop_until(&mut stages, &mut executor, &mut state, &mut mgr, starttime.checked_add(Duration::from_secs(5)).unwrap()) + .unwrap(); + let after = state.metadata().get::().unwrap().1; + if after.0 > last.0 { + last=after; + } + if let Ok(td) = env::var("CASE_DUMP") { + println!("Dumping worst case to {:?}", td); + let corpus = state.corpus(); + let mut worst = Duration::new(0,0); + let mut worst_input = None; + for i in 0..corpus.count() { + let tc = corpus.get(i).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"); + } + } + match worst_input { + Some(wi) => { + // let cd = format!("{}.case",&td); + let cd = td.clone(); + fs::write(&cd,wi).expect("Failed to write worst corpus element"); + }, + None => (), + } + #[cfg(feature = "feed_systemgraph")] + { + let mut gd = String::from(&td); + gd.push_str(".graph" ); + 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_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("TIME_DUMP") { let mut file = OpenOptions::new() @@ -460,9 +572,9 @@ pub fn fuzz() { .create(true) .append(true) .open(td).expect("Could not open timedump"); - if let Some(ichist) = state.metadata().get::() { - for i in ichist.0.iter() { - writeln!(file, "{}", i).expect("Write to dump failed"); + if let Some(ichist) = state.metadata_mut().get_mut::() { + for i in ichist.0.drain(..) { + writeln!(file, "{},{}", i.0, i.1).expect("Write to dump failed"); } } } diff --git a/fuzzers/FRET/src/mutational.rs b/fuzzers/FRET/src/mutational.rs index fe81a7e1bf..cf81fc2405 100644 --- a/fuzzers/FRET/src/mutational.rs +++ b/fuzzers/FRET/src/mutational.rs @@ -2,7 +2,7 @@ //! For the current input, it will perform a range of random mutations, and then run them in the executor. use core::marker::PhantomData; -use std::cmp::max; +use std::cmp::{max, min}; use libafl::{ bolts::rands::Rand, @@ -355,11 +355,11 @@ where { let metadata = state.metadata(); let hist = metadata.get::().unwrap(); - let maxtick : u64 = hist.1; + let maxtick : u64 = hist.1.0; // let maxtick : u64 = (_input.exec_time().expect("No duration found").as_nanos() >> 4).try_into().unwrap(); let mut numbers : Vec = vec![]; for i in 0..num_interrupts { - prefix.push(u32::to_le_bytes(myrand.between(0, maxtick).try_into().unwrap())); + prefix.push(u32::to_le_bytes(myrand.between(0, min(maxtick, u32::MAX as u64)).try_into().expect("ticks > u32"))); } } diff --git a/fuzzers/FRET/src/systemstate/mod.rs b/fuzzers/FRET/src/systemstate/mod.rs index c453b0237e..938e52b7ff 100644 --- a/fuzzers/FRET/src/systemstate/mod.rs +++ b/fuzzers/FRET/src/systemstate/mod.rs @@ -57,6 +57,7 @@ impl Hash for RefinedTCB { self.task_name.hash(state); self.priority.hash(state); self.mutexes_held.hash(state); + #[cfg(not(feature = "no_hash_state"))] self.notify_state.hash(state); // self.notify_value.hash(state); }