LIBAFL_DEBUG_OUTPUT in Launcher and OnDiskTOMLMonitor to create fuzzer_stats (#666)
* LIBAFL_DEBUG_OUTPUT in launcher on unix * OnDiskTOMLMonitor * fix * clp * clippy * fix * fix * allow all Co-authored-by: tokatoka <tokazerkje@outlook.com>
This commit is contained in:
parent
2e746bf439
commit
323b8e23ee
3
fuzzers/libfuzzer_libpng_launcher/.gitignore
vendored
3
fuzzers/libfuzzer_libpng_launcher/.gitignore
vendored
@ -1 +1,2 @@
|
|||||||
libpng-*
|
fuzzer_stats.toml
|
||||||
|
libpng-*
|
||||||
|
@ -27,7 +27,7 @@ use libafl::{
|
|||||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||||
fuzzer::{Fuzzer, StdFuzzer},
|
fuzzer::{Fuzzer, StdFuzzer},
|
||||||
inputs::{BytesInput, HasTargetBytes},
|
inputs::{BytesInput, HasTargetBytes},
|
||||||
monitors::tui::TuiMonitor,
|
monitors::{MultiMonitor, OnDiskTOMLMonitor},
|
||||||
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
|
||||||
mutators::token_mutations::Tokens,
|
mutators::token_mutations::Tokens,
|
||||||
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
observers::{HitcountsMapObserver, StdMapObserver, TimeObserver},
|
||||||
@ -139,7 +139,10 @@ pub fn libafl_main() {
|
|||||||
|
|
||||||
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
|
let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
|
||||||
|
|
||||||
let monitor = TuiMonitor::new("Test fuzzer on libpng".into(), true);
|
let monitor = OnDiskTOMLMonitor::new(
|
||||||
|
"./fuzzer_stats.toml",
|
||||||
|
MultiMonitor::new(|s| println!("{}", s)),
|
||||||
|
);
|
||||||
|
|
||||||
let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| {
|
let mut run_client = |state: Option<_>, mut restarting_mgr, _core_id| {
|
||||||
// Create an observation channel using the coverage map
|
// Create an observation channel using the coverage map
|
||||||
|
@ -142,6 +142,9 @@ where
|
|||||||
.stdout_file
|
.stdout_file
|
||||||
.map(|filename| File::create(filename).unwrap());
|
.map(|filename| File::create(filename).unwrap());
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
let debug_output = std::env::var("LIBAFL_DEBUG_OUTPUT").is_ok();
|
||||||
|
|
||||||
// Spawn clients
|
// Spawn clients
|
||||||
let mut index = 0_u64;
|
let mut index = 0_u64;
|
||||||
for (id, bind_to) in core_ids.iter().enumerate().take(num_cores) {
|
for (id, bind_to) in core_ids.iter().enumerate().take(num_cores) {
|
||||||
@ -163,10 +166,13 @@ where
|
|||||||
std::thread::sleep(std::time::Duration::from_millis(index * 100));
|
std::thread::sleep(std::time::Duration::from_millis(index * 100));
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
if let Some(file) = stdout_file {
|
if !debug_output {
|
||||||
dup2(file.as_raw_fd(), libc::STDOUT_FILENO)?;
|
if let Some(file) = stdout_file {
|
||||||
dup2(file.as_raw_fd(), libc::STDERR_FILENO)?;
|
dup2(file.as_raw_fd(), libc::STDOUT_FILENO)?;
|
||||||
|
dup2(file.as_raw_fd(), libc::STDERR_FILENO)?;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Fuzzer client. keeps retrying the connection to broker till the broker starts
|
// Fuzzer client. keeps retrying the connection to broker till the broker starts
|
||||||
let (state, mgr) = RestartingMgr::<I, MT, OT, S, SP>::builder()
|
let (state, mgr) = RestartingMgr::<I, MT, OT, S, SP>::builder()
|
||||||
.shmem_provider(self.shmem_provider.clone())
|
.shmem_provider(self.shmem_provider.clone())
|
||||||
|
@ -205,7 +205,7 @@ where
|
|||||||
|
|
||||||
fn shmem_from_id_and_size(&mut self, id: ShMemId, size: usize) -> Result<Self::ShMem, Error> {
|
fn shmem_from_id_and_size(&mut self, id: ShMemId, size: usize) -> Result<Self::ShMem, Error> {
|
||||||
let parts = id.as_str().split(':').collect::<Vec<&str>>();
|
let parts = id.as_str().split(':').collect::<Vec<&str>>();
|
||||||
let server_id_str = parts.get(0).unwrap();
|
let server_id_str = parts.first().unwrap();
|
||||||
let (server_fd, client_fd) = self.send_receive(ServedShMemRequest::ExistingMap(
|
let (server_fd, client_fd) = self.send_receive(ServedShMemRequest::ExistingMap(
|
||||||
ShMemDescription::from_string_and_size(server_id_str, size),
|
ShMemDescription::from_string_and_size(server_id_str, size),
|
||||||
))?;
|
))?;
|
||||||
@ -431,7 +431,8 @@ where
|
|||||||
// It's either running at this point, or we won't be able to spawn it anyway.
|
// It's either running at this point, or we won't be able to spawn it anyway.
|
||||||
env::set_var(AFL_SHMEM_SERVICE_STARTED, "true");
|
env::set_var(AFL_SHMEM_SERVICE_STARTED, "true");
|
||||||
|
|
||||||
match *success {
|
let status = *success;
|
||||||
|
match status {
|
||||||
ShMemServiceStatus::Starting => panic!("Unreachable"),
|
ShMemServiceStatus::Starting => panic!("Unreachable"),
|
||||||
ShMemServiceStatus::Started => {
|
ShMemServiceStatus::Started => {
|
||||||
println!("Started ShMem Service");
|
println!("Started ShMem Service");
|
||||||
|
@ -332,6 +332,8 @@ where
|
|||||||
name: String,
|
name: String,
|
||||||
/// Name identifier of the observer
|
/// Name identifier of the observer
|
||||||
observer_name: String,
|
observer_name: String,
|
||||||
|
/// Name of the feedback as shown in the `UserStats`
|
||||||
|
stats_name: String,
|
||||||
/// Phantom Data of Reducer
|
/// Phantom Data of Reducer
|
||||||
phantom: PhantomData<(I, N, S, R, O, T)>,
|
phantom: PhantomData<(I, N, S, R, O, T)>,
|
||||||
}
|
}
|
||||||
@ -416,7 +418,7 @@ where
|
|||||||
manager.fire(
|
manager.fire(
|
||||||
state,
|
state,
|
||||||
Event::UpdateUserStats {
|
Event::UpdateUserStats {
|
||||||
name: self.name.to_string(),
|
name: self.stats_name.to_string(),
|
||||||
value: UserStats::Ratio(filled, size as u64),
|
value: UserStats::Ratio(filled, size as u64),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
},
|
},
|
||||||
@ -480,6 +482,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn create_stats_name(name: &str) -> String {
|
||||||
|
name.to_lowercase()
|
||||||
|
}
|
||||||
|
|
||||||
impl<I, N, O, R, S, T> MapFeedback<I, N, O, R, S, T>
|
impl<I, N, O, R, S, T> MapFeedback<I, N, O, R, S, T>
|
||||||
where
|
where
|
||||||
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug,
|
||||||
@ -497,6 +503,7 @@ where
|
|||||||
novelties: None,
|
novelties: None,
|
||||||
name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(),
|
name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(),
|
||||||
observer_name: map_observer.name().to_string(),
|
observer_name: map_observer.name().to_string(),
|
||||||
|
stats_name: create_stats_name(map_observer.name()),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -509,6 +516,7 @@ where
|
|||||||
novelties: if track_novelties { Some(vec![]) } else { None },
|
novelties: if track_novelties { Some(vec![]) } else { None },
|
||||||
name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(),
|
name: MAPFEEDBACK_PREFIX.to_string() + map_observer.name(),
|
||||||
observer_name: map_observer.name().to_string(),
|
observer_name: map_observer.name().to_string(),
|
||||||
|
stats_name: create_stats_name(map_observer.name()),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -521,6 +529,7 @@ where
|
|||||||
novelties: None,
|
novelties: None,
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
observer_name: observer_name.to_string(),
|
observer_name: observer_name.to_string(),
|
||||||
|
stats_name: create_stats_name(name),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -537,6 +546,7 @@ where
|
|||||||
indexes: if track_indexes { Some(vec![]) } else { None },
|
indexes: if track_indexes { Some(vec![]) } else { None },
|
||||||
novelties: if track_novelties { Some(vec![]) } else { None },
|
novelties: if track_novelties { Some(vec![]) } else { None },
|
||||||
observer_name: observer_name.to_string(),
|
observer_name: observer_name.to_string(),
|
||||||
|
stats_name: create_stats_name(name),
|
||||||
name: name.to_string(),
|
name: name.to_string(),
|
||||||
phantom: PhantomData,
|
phantom: PhantomData,
|
||||||
}
|
}
|
||||||
|
136
libafl/src/monitors/disk.rs
Normal file
136
libafl/src/monitors/disk.rs
Normal file
@ -0,0 +1,136 @@
|
|||||||
|
//! Monitors that wrap a base one and log on disk
|
||||||
|
|
||||||
|
use alloc::{string::String, vec::Vec};
|
||||||
|
use core::time::Duration;
|
||||||
|
|
||||||
|
use crate::{
|
||||||
|
bolts::{current_time, format_duration_hms},
|
||||||
|
monitors::{ClientStats, Monitor, NopMonitor},
|
||||||
|
};
|
||||||
|
|
||||||
|
use std::{fs::File, io::Write, path::PathBuf};
|
||||||
|
|
||||||
|
/// Wrap a monitor and log the current state of the monitor into a TOML file.
|
||||||
|
#[derive(Debug, Clone)]
|
||||||
|
pub struct OnDiskTOMLMonitor<M>
|
||||||
|
where
|
||||||
|
M: Monitor,
|
||||||
|
{
|
||||||
|
base: M,
|
||||||
|
filename: PathBuf,
|
||||||
|
last_update: Duration,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> Monitor for OnDiskTOMLMonitor<M>
|
||||||
|
where
|
||||||
|
M: Monitor,
|
||||||
|
{
|
||||||
|
/// The client monitor, mutable
|
||||||
|
fn client_stats_mut(&mut self) -> &mut Vec<ClientStats> {
|
||||||
|
self.base.client_stats_mut()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// The client monitor
|
||||||
|
fn client_stats(&self) -> &[ClientStats] {
|
||||||
|
self.base.client_stats()
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Time this fuzzing run stated
|
||||||
|
fn start_time(&mut self) -> Duration {
|
||||||
|
self.base.start_time()
|
||||||
|
}
|
||||||
|
|
||||||
|
fn display(&mut self, event_msg: String, sender_id: u32) {
|
||||||
|
let cur_time = current_time();
|
||||||
|
|
||||||
|
if (cur_time - self.last_update).as_secs() >= 60 {
|
||||||
|
self.last_update = cur_time;
|
||||||
|
|
||||||
|
let mut file = File::create(&self.filename).expect("Failed to open the TOML file");
|
||||||
|
write!(
|
||||||
|
&mut file,
|
||||||
|
"# This TOML is generated using the OnDiskMonitor component of LibAFL
|
||||||
|
|
||||||
|
[global]
|
||||||
|
run_time = \"{}\"
|
||||||
|
clients = {}
|
||||||
|
corpus = {}
|
||||||
|
objectives = {}
|
||||||
|
executions = {}
|
||||||
|
exec_sec = {}
|
||||||
|
",
|
||||||
|
format_duration_hms(&(cur_time - self.start_time())),
|
||||||
|
self.client_stats().len(),
|
||||||
|
self.corpus_size(),
|
||||||
|
self.objective_size(),
|
||||||
|
self.total_execs(),
|
||||||
|
self.execs_per_sec()
|
||||||
|
)
|
||||||
|
.expect("Failed to write to the TOML file");
|
||||||
|
|
||||||
|
for (i, client) in self.client_stats_mut().iter_mut().skip(1).enumerate() {
|
||||||
|
let exec_sec = client.execs_per_sec(cur_time);
|
||||||
|
|
||||||
|
write!(
|
||||||
|
&mut file,
|
||||||
|
"
|
||||||
|
[client_{}]
|
||||||
|
corpus = {}
|
||||||
|
objectives = {}
|
||||||
|
executions = {}
|
||||||
|
exec_sec = {}
|
||||||
|
",
|
||||||
|
i + 1,
|
||||||
|
client.corpus_size,
|
||||||
|
client.objective_size,
|
||||||
|
client.executions,
|
||||||
|
exec_sec
|
||||||
|
)
|
||||||
|
.expect("Failed to write to the TOML file");
|
||||||
|
|
||||||
|
for (key, val) in &client.user_monitor {
|
||||||
|
let k: String = key
|
||||||
|
.chars()
|
||||||
|
.map(|c| if c.is_whitespace() { '_' } else { c })
|
||||||
|
.filter(|c| c.is_alphanumeric() || *c == '_')
|
||||||
|
.collect();
|
||||||
|
writeln!(&mut file, "{} = \"{}\"", k, val)
|
||||||
|
.expect("Failed to write to the TOML file");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
drop(file);
|
||||||
|
}
|
||||||
|
|
||||||
|
self.base.display(event_msg, sender_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl<M> OnDiskTOMLMonitor<M>
|
||||||
|
where
|
||||||
|
M: Monitor,
|
||||||
|
{
|
||||||
|
/// Create new [`OnDiskTOMLMonitor`]
|
||||||
|
#[must_use]
|
||||||
|
pub fn new<P>(filename: P, base: M) -> Self
|
||||||
|
where
|
||||||
|
P: Into<PathBuf>,
|
||||||
|
{
|
||||||
|
Self {
|
||||||
|
base,
|
||||||
|
filename: filename.into(),
|
||||||
|
last_update: current_time(),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
impl OnDiskTOMLMonitor<NopMonitor> {
|
||||||
|
/// Create new [`OnDiskTOMLMonitor`] without a base
|
||||||
|
#[must_use]
|
||||||
|
pub fn nop<P>(filename: P) -> Self
|
||||||
|
where
|
||||||
|
P: Into<PathBuf>,
|
||||||
|
{
|
||||||
|
Self::new(filename, NopMonitor::new())
|
||||||
|
}
|
||||||
|
}
|
@ -7,6 +7,11 @@ pub use multi::MultiMonitor;
|
|||||||
#[allow(missing_docs)]
|
#[allow(missing_docs)]
|
||||||
pub mod tui;
|
pub mod tui;
|
||||||
|
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub mod disk;
|
||||||
|
#[cfg(feature = "std")]
|
||||||
|
pub use disk::OnDiskTOMLMonitor;
|
||||||
|
|
||||||
use alloc::{string::String, vec::Vec};
|
use alloc::{string::String, vec::Vec};
|
||||||
|
|
||||||
#[cfg(feature = "introspection")]
|
#[cfg(feature = "introspection")]
|
||||||
|
@ -813,9 +813,10 @@ pub mod pybind {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[pyo3(name = "match_name")]
|
#[pyo3(name = "match_name")]
|
||||||
|
#[allow(clippy::all)]
|
||||||
fn pymatch_name(&self, name: &str) -> Option<PythonObserver> {
|
fn pymatch_name(&self, name: &str) -> Option<PythonObserver> {
|
||||||
for ob in &self.list {
|
for ob in &self.list {
|
||||||
if ob.name() == name {
|
if *ob.name() == *name {
|
||||||
return Some(ob.clone());
|
return Some(ob.clone());
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -155,8 +155,10 @@ where
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<E, EM, I, S, Z>
|
/// Function type when the callback in `SyncFromDiskStage` is not a lambda
|
||||||
SyncFromDiskStage<fn(&mut Z, &mut S, &Path) -> Result<I, Error>, E, EM, I, S, Z>
|
pub type SyncFromDiskFunction<I, S, Z> = fn(&mut Z, &mut S, &Path) -> Result<I, Error>;
|
||||||
|
|
||||||
|
impl<E, EM, I, S, Z> SyncFromDiskStage<SyncFromDiskFunction<I, S, Z>, E, EM, I, S, Z>
|
||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasMetadata,
|
S: HasClientPerfMonitor + HasCorpus<I> + HasRand + HasMetadata,
|
||||||
|
@ -381,7 +381,7 @@ mod tests {
|
|||||||
edge = cfg.get_edge((41864 >> 1) ^ 26911).unwrap();
|
edge = cfg.get_edge((41864 >> 1) ^ 26911).unwrap();
|
||||||
assert_eq!(edge.calling_func, "main");
|
assert_eq!(edge.calling_func, "main");
|
||||||
assert_eq!(edge.successor_edges.len(), 2);
|
assert_eq!(edge.successor_edges.len(), 2);
|
||||||
assert_eq!(*edge.successor_edges.get(0).unwrap(), (26911 >> 1) ^ 52706);
|
assert_eq!(*edge.successor_edges.first().unwrap(), (26911 >> 1) ^ 52706);
|
||||||
|
|
||||||
assert!(cfg.get_edge(26911).is_none());
|
assert!(cfg.get_edge(26911).is_none());
|
||||||
assert!(cfg.get_edge(41864).is_some());
|
assert!(cfg.get_edge(41864).is_some());
|
||||||
|
Loading…
x
Reference in New Issue
Block a user