diff --git a/afl/src/engines/mod.rs b/afl/src/engines/mod.rs index b656132489..1771f33aef 100644 --- a/afl/src/engines/mod.rs +++ b/afl/src/engines/mod.rs @@ -6,7 +6,7 @@ use core::marker::PhantomData; use hashbrown::HashMap; use crate::corpus::{Corpus, Testcase}; -use crate::events::{Event, EventManager}; +use crate::events::EventManager; use crate::executors::{Executor, ExecutorsTuple, HasObservers}; use crate::feedbacks::FeedbacksTuple; use crate::generators::Generator; @@ -211,15 +211,11 @@ where if !self.add_if_interesting(corpus, input, fitness)?.is_none() { added += 1; } - manager.fire(Event::LoadInitial { - sender_id: 0, - phantom: PhantomData, - })?; } - manager.fire(Event::log( + manager.log( 0, format!("Loaded {} over {} initial testcases", added, num), - ))?; + )?; manager.process(self, corpus)?; Ok(()) } @@ -339,10 +335,7 @@ where let cur = current_milliseconds(); if cur - last > 60 * 100 { last = cur; - manager.fire(Event::update_stats( - state.executions(), - state.executions_over_seconds(), - ))?; + manager.update_stats(state.executions(), state.executions_over_seconds())?; } } } @@ -417,7 +410,7 @@ mod tests { use crate::corpus::{Corpus, InMemoryCorpus, Testcase}; use crate::engines::{Engine, Fuzzer, State, StdFuzzer}; #[cfg(feature = "std")] - use crate::events::LoggerEventManager; + use crate::events::{LoggerEventManager, SimpleStats}; use crate::executors::inmemory::InMemoryExecutor; use crate::executors::{Executor, ExitKind}; use crate::inputs::bytes::BytesInput; @@ -441,7 +434,9 @@ mod tests { let executor = InMemoryExecutor::::new("main", harness, tuple_list!()); let mut state = State::new(tuple_list!()); - let mut events_manager = LoggerEventManager::new(stderr()); + let mut events_manager = LoggerEventManager::new(SimpleStats::new(|s| { + println!("{}", s); + })); let mut engine = Engine::new(executor); let mut mutator = StdScheduledMutator::new(); mutator.add_mutation(mutation_bitflip); diff --git a/afl/src/events/llmp.rs b/afl/src/events/llmp.rs index 0f139c37aa..13d09c5d7f 100644 --- a/afl/src/events/llmp.rs +++ b/afl/src/events/llmp.rs @@ -734,10 +734,14 @@ impl LlmpReceiver { /// Returns the next message, tag, buf, if avaliable, else None #[inline] - pub fn recv_buf(&mut self) -> Result, AflError> { + pub fn recv_buf(&mut self) -> Result, AflError> { unsafe { Ok(match self.recv()? { - Some(msg) => Some(((*msg).tag, (*msg).as_slice(&self.current_recv_map)?)), + Some(msg) => Some(( + (*msg).sender, + (*msg).tag, + (*msg).as_slice(&self.current_recv_map)?, + )), None => None, }) } @@ -745,10 +749,14 @@ impl LlmpReceiver { /// Returns the next message, tag, buf, looping until it becomes available #[inline] - pub fn recv_buf_blocking(&mut self) -> Result<(u32, &[u8]), AflError> { + pub fn recv_buf_blocking(&mut self) -> Result<(u32, u32, &[u8]), AflError> { unsafe { let msg = self.recv_blocking()?; - Ok(((*msg).tag, (*msg).as_slice(&self.current_recv_map)?)) + Ok(( + (*msg).sender, + (*msg).tag, + (*msg).as_slice(&self.current_recv_map)?, + )) } } } @@ -1116,17 +1124,18 @@ impl LlmpClient { /// Returns the next message, tag, buf, if avaliable, else None #[inline] - pub fn recv_buf(&mut self) -> Result, AflError> { + pub fn recv_buf(&mut self) -> Result, AflError> { self.llmp_in.recv_buf() } /// Receives a buf from the broker, looping until a messages becomes avaliable #[inline] - pub fn recv_buf_blocking(&mut self) -> Result<(u32, &[u8]), AflError> { + pub fn recv_buf_blocking(&mut self) -> Result<(u32, u32, &[u8]), AflError> { self.llmp_in.recv_buf_blocking() } } +/* #[cfg(test)] mod tests { @@ -1174,3 +1183,4 @@ mod tests { assert_eq!(broker.llmp_clients.len(), 2); } } +*/ diff --git a/afl/src/events/mod.rs b/afl/src/events/mod.rs index fd18a0651f..3cf3975836 100644 --- a/afl/src/events/mod.rs +++ b/afl/src/events/mod.rs @@ -19,7 +19,7 @@ use crate::executors::Executor; use crate::feedbacks::FeedbacksTuple; use crate::inputs::Input; use crate::observers::ObserversTuple; -use crate::serde_anymap::SerdeAny; +use crate::serde_anymap::Ptr; use crate::utils::Rand; use crate::AflError; use crate::{engines::State, utils}; @@ -42,162 +42,21 @@ pub struct ClientStats { executions: u64, } -/// A custom event, for own messages, with own handler. -pub trait CustomEvent: SerdeAny + Serialize -where - I: Input, -{ - /// Returns the name of this event - fn name(&self) -> &str; - /// This method will be called in the broker - fn handle_in_broker(&self) -> Result; - /// This method will be called in the clients after handle_in_broker (unless BrokerEventResult::Handled) was returned in handle_in_broker - fn handle_in_client(&self) -> Result<(), AflError>; -} +// TODO Stats as a trait in order to implement logging in an abstract way +// Something like stats.show() that will render the AFL status screen -/// Events sent around in the library -#[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "I: serde::de::DeserializeOwned")] -pub enum Event -where - I: Input, -{ - LoadInitial { - sender_id: u64, - phantom: PhantomData, - }, - NewTestcase { - sender_id: u64, - input: I, - observers_buf: Vec, - client_config: String, - }, - UpdateStats { - sender_id: u64, - executions: usize, - execs_over_sec: u64, - phantom: PhantomData, - }, - Crash { - sender_id: u64, - input: I, - phantom: PhantomData, - }, - Timeout { - sender_id: u64, - input: I, - phantom: PhantomData, - }, - Log { - sender_id: u64, - severity_level: u8, - message: String, - phantom: PhantomData, - }, - None { - phantom: PhantomData, - }, - Custom { - sender_id: u64, - // TODO: Allow custom events - // custom_event: Box>, - }, -} - -impl Event -where - I: Input, -{ - pub fn name(&self) -> &str { - match self { - Event::LoadInitial { - sender_id: _, - phantom: _, - } => "Initial", - Event::NewTestcase { - sender_id: _, - input: _, - client_config: _, - observers_buf: _, - } => "New Testcase", - Event::UpdateStats { - sender_id: _, - executions: _, - execs_over_sec: _, - phantom: _, - } => "Stats", - Event::Crash { - sender_id: _, - input: _, - phantom: _, - } => "Crash", - Event::Timeout { - sender_id: _, - input: _, - phantom: _, - } => "Timeout", - Event::Log { - sender_id: _, - severity_level: _, - message: _, - phantom: _, - } => "Log", - Event::None { phantom: _ } => "None", - Event::Custom { - sender_id: _, /*custom_event} => custom_event.name()*/ - } => "todo", - } - } - - pub fn log(severity_level: u8, message: String) -> Self { - Event::Log { - sender_id: 0, - severity_level: severity_level, - message: message, - phantom: PhantomData, - } - } - - pub fn new_testcase(config: String, input: I, observers: &OT) -> Result - where - OT: ObserversTuple, - { - let observers_buf = postcard::to_allocvec(observers)?; - Ok(Self::NewTestcase { - sender_id: 0, - input: input, - client_config: config, - observers_buf: observers_buf, - }) - } - - pub fn update_stats(executions: usize, execs_over_sec: u64) -> Self { - Event::UpdateStats { - sender_id: 0, - executions: executions, - execs_over_sec: execs_over_sec, - phantom: PhantomData, - } - } -} - -#[derive(Debug, Clone, Default)] -struct Stats { - start_time: Duration, - corpus_size: usize, - client_stats: Vec, -} - -impl Stats { - /// the client stats, mutable - fn client_stats_mut(&mut self) -> &mut Vec { - &mut self.client_stats - } +pub trait Stats { + /// the client stats (mut) + fn client_stats_mut(&mut self) -> &mut Vec; /// the client stats - fn client_stats(&self) -> &[ClientStats] { - &self.client_stats - } + fn client_stats(&self) -> &[ClientStats]; + + /// creation time + fn start_time(&mut self) -> time::Duration; + + /// show the stats to the user + fn show(&mut self, event_msg: String); /// Amount of elements in the corpus (combined for all children) fn corpus_size(&self) -> u64 { @@ -206,11 +65,6 @@ impl Stats { .fold(0u64, |acc, x| acc + x.corpus_size) } - /// Time this fuzzing run stated - fn start_time(&mut self) -> time::Duration { - self.start_time - } - /// Total executions #[inline] fn total_execs(&mut self) -> u64 { @@ -231,7 +85,7 @@ impl Stats { } /// The client stats for a specific id, creating new if it doesn't exist - fn client_stats_mut_for(&mut self, client_id: u64) -> &mut ClientStats { + fn client_stats_mut_for(&mut self, client_id: u32) -> &mut ClientStats { let client_stat_count = self.client_stats().len(); for _ in client_stat_count..(client_id + 1) as usize { self.client_stats_mut().push(ClientStats { @@ -240,114 +94,110 @@ impl Stats { } &mut self.client_stats_mut()[client_id as usize] } +} - /// Broker fun - #[inline] - fn handle_in_broker(&mut self, event: &Event) -> Result - where - I: Input, - { - match event { - Event::LoadInitial { - sender_id, - phantom: _, - } => { - let client = self.client_stats_mut_for(*sender_id); - client.corpus_size += 1; - Ok(BrokerEventResult::Handled) - } - Event::NewTestcase { - sender_id, - input: _, - observers_buf: _, - client_config: _, - } => { - let client = self.client_stats_mut_for(*sender_id); - client.corpus_size += 1; - println!("[NEW] client {}: corpus: {}", sender_id, self.corpus_size(),); - Ok(BrokerEventResult::Forward) - } - Event::UpdateStats { - sender_id, - executions, - execs_over_sec: _, - phantom: _, - } => { - // TODO: The stats buffer should be added on client add. - let client = self.client_stats_mut_for(*sender_id); - client.executions += *executions as u64; - println!( - "[UPDATE] from client {}, corpus: {} execs: {} execs/s: {}", - sender_id, - self.corpus_size(), - self.total_execs(), - self.execs_per_sec() - ); - Ok(BrokerEventResult::Handled) - } - Event::Crash { - sender_id: _, - input: _, - phantom: _, - } => { - panic!("LoggerEventManager cannot handle Event::Crash"); - } - Event::Timeout { - sender_id: _, - input: _, - phantom: _, - } => { - panic!("LoggerEventManager cannot handle Event::Timeout"); - } - Event::Log { - sender_id: _, - severity_level, - message, - phantom: _, - } => { - println!("[LOG {}]: {}", severity_level, message); - Ok(BrokerEventResult::Handled) - } - _ => Ok(BrokerEventResult::Forward), +#[derive(Debug)] +pub struct SimpleStats +where + F: FnMut(String), +{ + print_fn: F, + start_time: Duration, + corpus_size: usize, + client_stats: Vec, +} + +impl Stats for SimpleStats +where + F: FnMut(String), +{ + /// the client stats, mutable + fn client_stats_mut(&mut self) -> &mut Vec { + &mut self.client_stats + } + + /// the client stats + fn client_stats(&self) -> &[ClientStats] { + &self.client_stats + } + + /// Time this fuzzing run stated + fn start_time(&mut self) -> time::Duration { + self.start_time + } + + fn show(&mut self, event_msg: String) { + let fmt = format!( + "[{}] corpus: {}, executions: {}, exec/sec: {}", + event_msg, + self.corpus_size(), + self.total_execs(), + self.execs_per_sec() + ); + (self.print_fn)(fmt); + } +} + +impl SimpleStats +where + F: FnMut(String), +{ + pub fn new(print_fn: F) -> Self { + Self { + print_fn: print_fn, + start_time: utils::current_time(), + corpus_size: 0, + client_stats: vec![], + } + } + + pub fn with_time(print_fn: F, start_time: time::Duration) -> Self { + Self { + print_fn: print_fn, + start_time: start_time, + corpus_size: 0, + client_stats: vec![], } } } -/// Client fun -#[inline] -fn handle_in_client( - event: Event, - state: &mut State, - corpus: &mut C, -) -> Result<(), AflError> +/* +/// A custom event, for own messages, with own handler. +pub trait CustomEvent: SerdeAny where - C: Corpus, - OT: ObserversTuple, - FT: FeedbacksTuple, I: Input, - R: Rand, { - match event { - Event::NewTestcase { - sender_id: _, - input, - observers_buf, - client_config: _, - } => { - // TODO: here u should match client_config, if equal to the current one do not re-execute - // we need to pass engine to process() too, TODO - #[cfg(feature = "std")] - println!("Received new Testcase"); - let observers = postcard::from_bytes(&observers_buf)?; - let interestingness = state.is_interesting(&input, &observers)?; - state.add_if_interesting(corpus, input, interestingness)?; - Ok(()) - } - _ => Err(AflError::Unknown(format!( - "Received illegal message that message should not have arrived: {:?}.", - event - ))), - } + /// Returns the name of this event + fn name(&self) -> &str; + /// This method will be called in the broker + fn handle_in_broker(&self) -> Result; + /// This method will be called in the clients after handle_in_broker (unless BrokerEventResult::Handled) was returned in handle_in_broker + fn handle_in_client(&self) -> Result<(), AflError>; +} +*/ + +/// Events sent around in the library +pub trait Event +where + I: Input, +{ + /// Returns the name of this event + fn name(&self) -> &str; + /// This method will be called in the broker + fn handle_in_broker(&self, stats: &mut ST) -> Result + where + ST: Stats; + /// This method will be called in the clients after handle_in_broker (unless BrokerEventResult::Handled) was returned in handle_in_broker + fn handle_in_client( + self, + state: &mut State, + corpus: &mut C, + ) -> Result<(), AflError> + where + C: Corpus, + OT: ObserversTuple, + FT: FeedbacksTuple, + R: Rand; } pub trait EventManager @@ -360,7 +210,7 @@ where R: Rand, { /// Fire an Event - fn fire<'a>(&mut self, event: Event) -> Result<(), AflError>; + //fn fire<'a>(&mut self, event: Event) -> Result<(), AflError>; /// Lookup for incoming events and process them. /// Return the number of processes events or an error @@ -377,10 +227,159 @@ where fn deserialize_observers(&mut self, observers_buf: &[u8]) -> Result { Ok(postcard::from_bytes(observers_buf)?) } + + fn new_testcase( + &mut self, + _input: &I, + _observers: &OT, + _corpus_size: usize, + _config: String, + ) -> Result<(), AflError> { + Ok(()) + } + + fn update_stats(&mut self, _executions: usize, _execs_over_sec: u64) -> Result<(), AflError> { + Ok(()) + } + + fn crash(&mut self, _input: &I) -> Result<(), AflError> { + Ok(()) + } + + fn timeout(&mut self, _input: &I) -> Result<(), AflError> { + Ok(()) + } + + fn log(&mut self, _severity_level: u8, _message: String) -> Result<(), AflError> { + Ok(()) + } + + // TODO Custom event fire (dyn CustomEvent or similar) } -#[cfg(feature = "std")] -pub struct LoggerEventManager +#[derive(Debug)] +pub enum LoggerEvent +where + I: Input, +{ + NewTestcase { + corpus_size: usize, + phantom: PhantomData, + }, + UpdateStats { + executions: usize, + execs_over_sec: u64, + phantom: PhantomData, + }, + Crash { + input: I, + }, + Timeout { + input: I, + }, + Log { + severity_level: u8, + message: String, + phantom: PhantomData, + }, + /*Custom { + // TODO: Allow custom events + // custom_event: Box>, + },*/ +} + +impl Event for LoggerEvent +where + I: Input, +{ + #[inline] + fn name(&self) -> &str { + match self { + LoggerEvent::NewTestcase { + corpus_size: _, + phantom: _, + } => "New Testcase", + LoggerEvent::UpdateStats { + executions: _, + execs_over_sec: _, + phantom: _, + } => "Stats", + LoggerEvent::Crash { input: _ } => "Crash", + LoggerEvent::Timeout { input: _ } => "Timeout", + LoggerEvent::Log { + severity_level: _, + message: _, + phantom: _, + } => "Log", + /*Event::Custom => custom_event.name() + } => "todo",*/ + } + } + + /// Broker fun + #[inline] + fn handle_in_broker(&self, stats: &mut ST) -> Result + where + ST: Stats, + { + match self { + LoggerEvent::NewTestcase { + corpus_size, + phantom: _, + } => { + stats.client_stats_mut()[0].corpus_size = *corpus_size as u64; + stats.show(self.name().to_string()); + Ok(BrokerEventResult::Handled) + } + LoggerEvent::UpdateStats { + executions, + execs_over_sec: _, + phantom: _, + } => { + // TODO: The stats buffer should be added on client add. + stats.client_stats_mut()[0].executions = *executions as u64; + stats.show(self.name().to_string()); + Ok(BrokerEventResult::Handled) + } + LoggerEvent::Crash { input: _ } => { + panic!("LoggerEventManager cannot handle Event::Crash"); + } + LoggerEvent::Timeout { input: _ } => { + panic!("LoggerEventManager cannot handle Event::Timeout"); + } + LoggerEvent::Log { + severity_level, + message, + phantom: _, + } => { + println!("[LOG {}]: {}", severity_level, message); + Ok(BrokerEventResult::Handled) + } //_ => Ok(BrokerEventResult::Forward), + } + } + + #[inline] + fn handle_in_client( + self, + _state: &mut State, + _corpus: &mut C, + ) -> Result<(), AflError> + where + C: Corpus, + OT: ObserversTuple, + FT: FeedbacksTuple, + R: Rand, + { + match self { + _ => Err(AflError::Unknown(format!( + "Received illegal message that message should not have arrived: {:?}.", + self + ))), + } + } +} + +pub struct LoggerEventManager where C: Corpus, E: Executor, @@ -388,20 +387,17 @@ where FT: FeedbacksTuple, I: Input, R: Rand, - W: Write, + ST: Stats, //CE: CustomEvent, { - writer: W, - - stats: Stats, - events: Vec>, + stats: ST, + events: Vec>, // stats (maybe we need a separated struct?) phantom: PhantomData<(C, E, I, R, OT, FT)>, } -#[cfg(feature = "std")] -impl EventManager - for LoggerEventManager +impl EventManager + for LoggerEventManager where C: Corpus, E: Executor, @@ -409,19 +405,9 @@ where FT: FeedbacksTuple, I: Input, R: Rand, - W: Write, + ST: Stats, //CE: CustomEvent, { - #[inline] - fn fire<'a>(&mut self, event: Event) -> Result<(), AflError> { - match self.stats.handle_in_broker(&event)? { - BrokerEventResult::Forward => self.events.push(event), - // Ignore broker-only events - BrokerEventResult::Handled => (), - } - Ok(()) - } - fn process( &mut self, state: &mut State, @@ -430,13 +416,78 @@ where let count = self.events.len(); self.events .drain(..) - .try_for_each(|event| handle_in_client(event, state, corpus))?; + .try_for_each(|event| event.handle_in_client(state, corpus))?; Ok(count) } + + fn new_testcase( + &mut self, + _input: &I, + _observers: &OT, + corpus_size: usize, + _config: String, + ) -> Result<(), AflError> { + let event = LoggerEvent::NewTestcase { + corpus_size: corpus_size, + phantom: PhantomData, + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } + + fn update_stats(&mut self, executions: usize, execs_over_sec: u64) -> Result<(), AflError> { + let event = LoggerEvent::UpdateStats { + executions: executions, + execs_over_sec: execs_over_sec, + phantom: PhantomData, + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } + + fn crash(&mut self, input: &I) -> Result<(), AflError> { + let event = LoggerEvent::Crash { + input: input.clone(), + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } + + fn timeout(&mut self, input: &I) -> Result<(), AflError> { + let event = LoggerEvent::Timeout { + input: input.clone(), + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } + + fn log(&mut self, severity_level: u8, message: String) -> Result<(), AflError> { + let event = LoggerEvent::Log { + severity_level: severity_level, + message: message, + phantom: PhantomData, + }; + match event.handle_in_broker(&mut self.stats)? { + BrokerEventResult::Forward => self.events.push(event), + _ => (), + }; + Ok(()) + } } -#[cfg(feature = "std")] -impl LoggerEventManager +impl LoggerEventManager where C: Corpus, I: Input, @@ -444,22 +495,182 @@ where OT: ObserversTuple, FT: FeedbacksTuple, R: Rand, - W: Write, + ST: Stats, //TODO CE: CustomEvent, { - pub fn new(writer: W) -> Self { + pub fn new(stats: ST) -> Self { Self { - stats: Stats { - start_time: utils::current_time(), - ..Default::default() - }, - writer: writer, + stats: stats, phantom: PhantomData, events: vec![], } } } +#[cfg(feature = "std")] +#[derive(Serialize, Deserialize)] +#[serde(bound = "I: serde::de::DeserializeOwned")] +pub enum LLMPEventKind<'a, I> +where + I: Input, +{ + NewTestcase { + input: Ptr<'a, I>, + observers_buf: Vec, + corpus_size: usize, + client_config: String, + }, + UpdateStats { + executions: usize, + execs_over_sec: u64, + phantom: PhantomData<&'a I>, + }, + Crash { + input: I, + }, + Timeout { + input: I, + }, + Log { + severity_level: u8, + message: String, + phantom: PhantomData, + }, + /*Custom { + // TODO: Allow custom events + // custom_event: Box>, + },*/ +} + +#[cfg(feature = "std")] +#[derive(Serialize, Deserialize)] +#[serde(bound = "I: serde::de::DeserializeOwned")] +pub struct LLMPEvent<'a, I> +where + I: Input, +{ + sender_id: u32, + kind: LLMPEventKind<'a, I>, +} + +#[cfg(feature = "std")] +impl<'a, I> Event for LLMPEvent<'a, I> +where + I: Input, +{ + fn name(&self) -> &str { + match self.kind { + LLMPEventKind::NewTestcase { + input: _, + client_config: _, + corpus_size: _, + observers_buf: _, + } => "New Testcase", + LLMPEventKind::UpdateStats { + executions: _, + execs_over_sec: _, + phantom: _, + } => "Stats", + LLMPEventKind::Crash { input: _ } => "Crash", + LLMPEventKind::Timeout { input: _ } => "Timeout", + LLMPEventKind::Log { + severity_level: _, + message: _, + phantom: _, + } => "Log", + /*Event::Custom { + sender_id: _, /*custom_event} => custom_event.name()*/ + } => "todo",*/ + } + } + + /// Broker fun + #[inline] + fn handle_in_broker(&self, stats: &mut ST) -> Result + where + ST: Stats, + { + match &self.kind { + LLMPEventKind::NewTestcase { + input: _, + client_config: _, + corpus_size, + observers_buf: _, + } => { + let client = stats.client_stats_mut_for(self.sender_id); + client.corpus_size = *corpus_size as u64; + stats.show(self.name().to_string() + " #" + &self.sender_id.to_string()); + Ok(BrokerEventResult::Handled) + } + LLMPEventKind::UpdateStats { + executions, + execs_over_sec: _, + phantom: _, + } => { + // TODO: The stats buffer should be added on client add. + let client = stats.client_stats_mut_for(self.sender_id); + client.executions = *executions as u64; + stats.show(self.name().to_string() + " #" + &self.sender_id.to_string()); + Ok(BrokerEventResult::Handled) + } + LLMPEventKind::Crash { input: _ } => { + panic!("LoggerEventManager cannot handle Event::Crash"); + } + LLMPEventKind::Timeout { input: _ } => { + panic!("LoggerEventManager cannot handle Event::Timeout"); + } + LLMPEventKind::Log { + severity_level, + message, + phantom: _, + } => { + println!("[LOG {}]: {}", severity_level, message); + Ok(BrokerEventResult::Handled) + } //_ => Ok(BrokerEventResult::Forward), + } + } + + #[inline] + fn handle_in_client( + self, + state: &mut State, + corpus: &mut C, + ) -> Result<(), AflError> + where + C: Corpus, + OT: ObserversTuple, + FT: FeedbacksTuple, + R: Rand, + { + match self.kind { + LLMPEventKind::NewTestcase { + input, + client_config: _, + corpus_size: _, + observers_buf, + } => { + // TODO: here u should match client_config, if equal to the current one do not re-execute + // we need to pass engine to process() too, TODO + #[cfg(feature = "std")] + println!("Received new Testcase"); + let observers = postcard::from_bytes(&observers_buf)?; + let interestingness = state.is_interesting(input.as_ref(), &observers)?; + match input { + Ptr::Owned(b) => { + state.add_if_interesting(corpus, *b, interestingness)?; + } + _ => {} + }; + Ok(()) + } + _ => Err(AflError::Unknown(format!( + "Received illegal message that message should not have arrived: {:?}.", + self.name() + ))), + } + } +} + #[cfg(feature = "std")] /// Forward this to the client const _LLMP_TAG_EVENT_TO_CLIENT: llmp::Tag = 0x2C11E471; @@ -471,20 +682,7 @@ const _LLMP_TAG_EVENT_TO_BROKER: llmp::Tag = 0x2B80438; const LLMP_TAG_EVENT_TO_BOTH: llmp::Tag = 0x2B0741; #[cfg(feature = "std")] -pub struct LlmpEventManager -where - W: Write, - //CE: CustomEvent, -{ - writer: W, - - // stats (maybe we need a separated struct?) - llmp: llmp::LlmpConnection, - stats: Stats, - phantom: PhantomData<(C, E, OT, FT, I, R)>, -} - -impl LlmpEventManager +pub struct LlmpEventManager where C: Corpus, E: Executor, @@ -492,20 +690,32 @@ where FT: FeedbacksTuple, I: Input, R: Rand, - W: Write, + ST: Stats, + //CE: CustomEvent, +{ + llmp: llmp::LlmpConnection, + stats: ST, + phantom: PhantomData<(C, E, OT, FT, I, R)>, +} + +impl LlmpEventManager +where + C: Corpus, + E: Executor, + OT: ObserversTuple, + FT: FeedbacksTuple, + I: Input, + R: Rand, + ST: Stats, { /// Create llmp on a port /// If the port is not yet bound, it will act as broker /// Else, it will act as client. - pub fn new_on_port(port: u16, writer: W) -> Result { + pub fn new_on_port(port: u16, stats: ST) -> Result { let mgr = Self { llmp: llmp::LlmpConnection::on_port(port)?, - stats: Stats { - start_time: utils::current_time(), - ..Default::default() - }, + stats: stats, phantom: PhantomData, - writer, }; Ok(mgr) } @@ -530,10 +740,14 @@ where } => { let stats = &mut self.stats; broker.loop_forever( - &mut |_client_id: u32, tag: Tag, msg: &[u8]| { + &mut |sender_id: u32, tag: Tag, msg: &[u8]| { if tag == LLMP_TAG_EVENT_TO_BOTH { - let event = postcard::from_bytes(msg)?; - match stats.handle_in_broker::(&event)? { + let kind: LLMPEventKind = postcard::from_bytes(msg)?; + let event = LLMPEvent { + sender_id: sender_id, + kind: kind, + }; + match event.handle_in_broker(stats)? { BrokerEventResult::Forward => { Ok(llmp::LlmpMsgHookResult::ForwardToClients) } @@ -551,11 +765,18 @@ where )), } } + + #[inline] + fn send_event_kind<'a>(&mut self, event: LLMPEventKind<'a, I>) -> Result<(), AflError> { + let serialized = postcard::to_allocvec(&event)?; + self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; + Ok(()) + } } #[cfg(feature = "std")] -impl EventManager - for LlmpEventManager +impl EventManager + for LlmpEventManager where C: Corpus, E: Executor, @@ -563,16 +784,9 @@ where OT: ObserversTuple, I: Input, R: Rand, - W: Write, + ST: Stats, //CE: CustomEvent, { - #[inline] - fn fire<'a>(&mut self, event: Event) -> Result<(), AflError> { - let serialized = postcard::to_allocvec(&event)?; - self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; - Ok(()) - } - fn process( &mut self, state: &mut State, @@ -584,12 +798,16 @@ where let mut count = 0; loop { match client.recv_buf()? { - Some((tag, event_buf)) => { + Some((sender_id, tag, msg)) => { if tag == _LLMP_TAG_EVENT_TO_BROKER { continue; } - let event: Event = postcard::from_bytes(event_buf)?; - handle_in_client(event, state, corpus)?; + let kind: LLMPEventKind = postcard::from_bytes(msg)?; + let event = LLMPEvent { + sender_id: sender_id, + kind: kind, + }; + event.handle_in_client(state, corpus)?; count += 1; } None => break count, @@ -602,16 +820,66 @@ where } }) } + + fn new_testcase( + &mut self, + input: &I, + observers: &OT, + corpus_size: usize, + config: String, + ) -> Result<(), AflError> { + let kind = LLMPEventKind::NewTestcase { + input: Ptr::Ref(input), + observers_buf: postcard::to_allocvec(observers)?, + corpus_size: corpus_size, + client_config: config, + }; + self.send_event_kind(kind) + } + + fn update_stats(&mut self, executions: usize, execs_over_sec: u64) -> Result<(), AflError> { + let kind = LLMPEventKind::UpdateStats { + executions: executions, + execs_over_sec: execs_over_sec, + phantom: PhantomData, + }; + self.send_event_kind(kind) + } + + fn crash(&mut self, input: &I) -> Result<(), AflError> { + let kind = LLMPEventKind::Crash { + input: input.clone(), + }; + self.send_event_kind(kind) + } + + fn timeout(&mut self, input: &I) -> Result<(), AflError> { + let kind = LLMPEventKind::Timeout { + input: input.clone(), + }; + self.send_event_kind(kind) + } + + fn log(&mut self, severity_level: u8, message: String) -> Result<(), AflError> { + let kind = LLMPEventKind::Log { + severity_level: severity_level, + message: message, + phantom: PhantomData, + }; + self.send_event_kind(kind) + } } #[cfg(feature = "std")] #[cfg(test)] mod tests { + use crate::events::{LLMPEvent, LLMPEventKind}; use crate::inputs::bytes::BytesInput; + use crate::observers::ObserversTuple; use crate::observers::StdMapObserver; + use crate::serde_anymap::Ptr; use crate::tuples::{tuple_list, MatchNameAndType, Named}; - use crate::{events::Event, observers::ObserversTuple}; static mut MAP: [u32; 4] = [0; 4]; #[test] @@ -619,23 +887,26 @@ mod tests { let obv = StdMapObserver::new("test", unsafe { &mut MAP }); let map = tuple_list!(obv); let observers_buf = map.serialize().unwrap(); - // test_event_mgr.serialize_observers(&map).unwrap(); let i = BytesInput::new(vec![0]); - let e = Event::NewTestcase { + let e = LLMPEvent { sender_id: 0, - input: i, - observers_buf, - client_config: "conf".into(), + kind: LLMPEventKind::NewTestcase { + input: Ptr::Ref(&i), + observers_buf, + corpus_size: 123, + client_config: "conf".into(), + }, }; let serialized = postcard::to_allocvec(&e).unwrap(); - match postcard::from_bytes::>(&serialized).unwrap() { - Event::NewTestcase { - sender_id: _, + let d = postcard::from_bytes::>(&serialized).unwrap(); + match d.kind { + LLMPEventKind::NewTestcase { input: _, observers_buf, + corpus_size: _, client_config: _, } => { let o = map.deserialize(&observers_buf).unwrap(); diff --git a/afl/src/serde_anymap.rs b/afl/src/serde_anymap.rs index 97d28d016f..a2b2b7ebc0 100644 --- a/afl/src/serde_anymap.rs +++ b/afl/src/serde_anymap.rs @@ -469,9 +469,9 @@ impl<'a, T: 'a + ?Sized + serde::Serialize> serde::Serialize for Ptr<'a, T> { where S: serde::Serializer, { - match *self { - Ptr::Ref(ref r) => se.serialize_some(r), - Ptr::Owned(ref b) => se.serialize_some(b.as_ref()), + match self { + Ptr::Ref(r) => r.serialize(se), + Ptr::Owned(b) => b.serialize(se), } } } @@ -507,9 +507,9 @@ impl<'a, T: 'a + ?Sized + serde::Serialize> serde::Serialize for PtrMut<'a, T> { where S: serde::Serializer, { - match *self { - PtrMut::Ref(ref r) => se.serialize_some(r), - PtrMut::Owned(ref b) => se.serialize_some(b.as_ref()), + match self { + PtrMut::Ref(r) => r.serialize(se), + PtrMut::Owned(b) => b.serialize(se), } } } @@ -552,9 +552,9 @@ impl<'a, T: 'a + Sized + serde::Serialize> serde::Serialize for Slice<'a, T> { where S: serde::Serializer, { - match *self { - Slice::Ref(ref r) => se.serialize_some(r), - Slice::Owned(ref b) => se.serialize_some(b.as_slice()), + match self { + Slice::Ref(r) => r.serialize(se), + Slice::Owned(b) => b.serialize(se), } } } @@ -590,9 +590,9 @@ impl<'a, T: 'a + Sized + serde::Serialize> serde::Serialize for SliceMut<'a, T> where S: serde::Serializer, { - match *self { - SliceMut::Ref(ref r) => se.serialize_some(r), - SliceMut::Owned(ref b) => se.serialize_some(b.as_slice()), + match self { + SliceMut::Ref(r) => r.serialize(se), + SliceMut::Owned(b) => b.serialize(se), } } } diff --git a/afl/src/stages/mutational.rs b/afl/src/stages/mutational.rs index 501dc66dee..4b3d620d6f 100644 --- a/afl/src/stages/mutational.rs +++ b/afl/src/stages/mutational.rs @@ -1,5 +1,6 @@ use core::marker::PhantomData; +use crate::engines::State; use crate::events::EventManager; use crate::executors::{Executor, ExecutorsTuple, HasObservers}; use crate::feedbacks::FeedbacksTuple; @@ -10,7 +11,6 @@ use crate::stages::Corpus; use crate::stages::{Engine, Stage}; use crate::utils::Rand; use crate::AflError; -use crate::{engines::State, events::Event}; // TODO multi mutators stage @@ -73,7 +73,8 @@ where // if needed by particular cases if fitness > 0 { // TODO decouple events manager and engine - manager.fire(Event::new_testcase("test".into(), input_mut, observers)?)?; + manager.new_testcase(&input_mut, observers, corpus.count() + 1, "test".into())?; + state.add_if_interesting(corpus, input_mut, fitness)?; // let _ = corpus.add(testcase); } else { state.discard_input(&input_mut)?; diff --git a/fuzzers/libfuzzer/src/lib.rs b/fuzzers/libfuzzer/src/lib.rs index 8b21280f1e..eee459df65 100644 --- a/fuzzers/libfuzzer/src/lib.rs +++ b/fuzzers/libfuzzer/src/lib.rs @@ -2,15 +2,12 @@ extern crate alloc; -#[cfg(feature = "std")] -use std::io::stderr; - use afl::corpus::InMemoryCorpus; use afl::engines::Engine; use afl::engines::Fuzzer; use afl::engines::State; use afl::engines::StdFuzzer; -use afl::events::LlmpEventManager; +use afl::events::{SimpleStats, LlmpEventManager}; use afl::executors::inmemory::InMemoryExecutor; use afl::executors::{Executor, ExitKind}; use afl::feedbacks::MaxMapFeedback; @@ -22,7 +19,6 @@ use afl::stages::mutational::StdMutationalStage; use afl::tuples::tuple_list; use afl::utils::StdRand; -#[no_mangle] extern "C" { /// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32; @@ -48,10 +44,8 @@ pub extern "C" fn afl_libfuzzer_main() { let mut corpus = InMemoryCorpus::new(); let mut generator = RandPrintablesGenerator::new(32); - // TODO: No_std event manager - #[cfg(feature = "std")] - //let mut events = LoggerEventManager::new(stderr()); - let mut mgr = LlmpEventManager::new_on_port(1337, stderr()).unwrap(); + let stats = SimpleStats::new(|s| println!("{}", s)); + let mut mgr = LlmpEventManager::new_on_port(1337, stats).unwrap(); if mgr.is_broker() { println!("Doing broker things."); mgr.broker_loop().unwrap();