Composing feedback (#85)

* composing feedbacks as logic operations and bump to 0.2

* adapt fuzzers and libafl_frida

* fix windows build
This commit is contained in:
Andrea Fioraldi 2021-05-04 16:00:39 +02:00
parent 9e9d95f93d
commit 9f3b0984c3
19 changed files with 399 additions and 273 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "baby_fuzzer" name = "baby_fuzzer"
version = "0.1.0" version = "0.2.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
edition = "2018" edition = "2018"

View File

@ -56,13 +56,13 @@ pub fn main() {
StdRand::with_seed(current_nanos()), StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance // Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(), InMemoryCorpus::new(),
// Feedbacks to rate the interestingness of an input // Feedback to rate the interestingness of an input
tuple_list!(MaxMapFeedback::new_with_observer(&observer)), MaxMapFeedback::new_with_observer(&observer),
// Corpus in which we store solutions (crashes in this example), // Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer // on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
// Feedbacks to recognize an input as solution // Feedbacks to recognize an input as solution
tuple_list!(CrashFeedback::new()), CrashFeedback::new(),
); );
// Setup a basic mutator with a mutational stage // Setup a basic mutator with a mutational stage

View File

@ -1,6 +1,6 @@
[package] [package]
name = "frida_libpng" name = "frida_libpng"
version = "0.1.0" version = "0.2.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
edition = "2018" edition = "2018"
build = "build.rs" build = "build.rs"
@ -25,7 +25,7 @@ libafl = { path = "../../libafl/", features = [ "std", "llmp_compression" ] } #,
capstone = "0.8.0" capstone = "0.8.0"
frida-gum = { version = "0.4", git = "https://github.com/s1341/frida-rust", features = [ "auto-download", "event-sink", "invocation-listener"] } frida-gum = { version = "0.4", git = "https://github.com/s1341/frida-rust", features = [ "auto-download", "event-sink", "invocation-listener"] }
#frida-gum = { version = "0.4", path = "../../../frida-rust/frida-gum", features = [ "auto-download", "event-sink", "invocation-listener"] } #frida-gum = { version = "0.4", path = "../../../frida-rust/frida-gum", features = [ "auto-download", "event-sink", "invocation-listener"] }
libafl_frida = { path = "../../libafl_frida", version = "0.1.0" } libafl_frida = { path = "../../libafl_frida", version = "0.2.0" }
lazy_static = "1.4.0" lazy_static = "1.4.0"
libc = "0.2" libc = "0.2"
libloading = "0.7.0" libloading = "0.7.0"

View File

@ -12,6 +12,7 @@ use libafl::{
inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, HasExecHooks, inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, HasExecHooks,
HasExecHooksTuple, HasObservers, HasObserversHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
}, },
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
@ -276,17 +277,13 @@ unsafe fn fuzz(
// Corpus that will be evolved, we keep it in memory for performance // Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(), InMemoryCorpus::new(),
// Feedbacks to rate the interestingness of an input // Feedbacks to rate the interestingness of an input
tuple_list!(MaxMapFeedback::new_with_observer_track( MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
&edges_observer,
true,
false
)),
// Corpus in which we store solutions (crashes in this example), // Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer // on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new_save_meta(objective_dir, Some(OnDiskMetadataFormat::JsonPretty)) OnDiskCorpus::new_save_meta(objective_dir, Some(OnDiskMetadataFormat::JsonPretty))
.unwrap(), .unwrap(),
// Feedbacks to recognize an input as solution // Feedbacks to recognize an input as solution
tuple_list!( feedback_or!(
CrashFeedback::new(), CrashFeedback::new(),
TimeoutFeedback::new(), TimeoutFeedback::new(),
AsanErrorsFeedback::new() AsanErrorsFeedback::new()

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libfuzzer_libmozjpeg" name = "libfuzzer_libmozjpeg"
version = "0.1.0" version = "0.2.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
edition = "2018" edition = "2018"

View File

@ -8,6 +8,7 @@ use libafl::{
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler}, corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
events::setup_restarting_mgr_std, events::setup_restarting_mgr_std,
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::scheduled::{havoc_mutations, StdScheduledMutator},
@ -76,7 +77,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Corpus that will be evolved, we keep it in memory for performance // Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(), InMemoryCorpus::new(),
// Feedbacks to rate the interestingness of an input // Feedbacks to rate the interestingness of an input
tuple_list!( feedback_or!(
MaxMapFeedback::new_with_observer(&edges_observer), MaxMapFeedback::new_with_observer(&edges_observer),
MaxMapFeedback::new_with_observer(&cmps_observer), MaxMapFeedback::new_with_observer(&cmps_observer),
MaxMapFeedback::new_with_observer(&allocs_observer) MaxMapFeedback::new_with_observer(&allocs_observer)
@ -85,7 +86,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// on disk so the user can get them after stopping the fuzzer // on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(objective_dir).unwrap(), OnDiskCorpus::new(objective_dir).unwrap(),
// Feedbacks to recognize an input as solution // Feedbacks to recognize an input as solution
tuple_list!(CrashFeedback::new()), CrashFeedback::new(),
) )
}); });

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libfuzzer_libpng" name = "libfuzzer_libpng"
version = "0.1.0" version = "0.2.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
edition = "2018" edition = "2018"

View File

@ -12,6 +12,7 @@ use libafl::{
}, },
events::{setup_restarting_mgr_std, EventManager}, events::{setup_restarting_mgr_std, EventManager},
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor}, executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::scheduled::{havoc_mutations, StdScheduledMutator},
@ -76,7 +77,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Corpus that will be evolved, we keep it in memory for performance // Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(), InMemoryCorpus::new(),
// Feedbacks to rate the interestingness of an input // Feedbacks to rate the interestingness of an input
tuple_list!( feedback_or!(
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false), MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
TimeFeedback::new() TimeFeedback::new()
), ),
@ -84,7 +85,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// on disk so the user can get them after stopping the fuzzer // on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(objective_dir).unwrap(), OnDiskCorpus::new(objective_dir).unwrap(),
// Feedbacks to recognize an input as solution // Feedbacks to recognize an input as solution
tuple_list!(CrashFeedback::new(), TimeoutFeedback::new()), feedback_or!(CrashFeedback::new(), TimeoutFeedback::new()),
) )
}); });

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libfuzzer_stb_image" name = "libfuzzer_stb_image"
version = "0.1.0" version = "0.2.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
edition = "2018" edition = "2018"
build = "build.rs" build = "build.rs"

View File

@ -11,6 +11,7 @@ use libafl::{
}, },
events::setup_restarting_mgr_std, events::setup_restarting_mgr_std,
executors::{inprocess::InProcessExecutor, ExitKind}, executors::{inprocess::InProcessExecutor, ExitKind},
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
mutators::scheduled::{havoc_mutations, StdScheduledMutator}, mutators::scheduled::{havoc_mutations, StdScheduledMutator},
@ -73,15 +74,15 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
// Corpus that will be evolved, we keep it in memory for performance // Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(), InMemoryCorpus::new(),
// Feedbacks to rate the interestingness of an input // Feedbacks to rate the interestingness of an input
tuple_list!( feedback_or!(
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false), MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
TimeFeedback::new() TimeFeedback::new()
), ),
// Corpus in which we store solutions (crashes in this example), // Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer // on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(objective_dir).unwrap(), OnDiskCorpus::new(objective_dir).unwrap(),
// Feedbacks to recognize an input as solution // Feedback to recognize an input as solution
tuple_list!(CrashFeedback::new()), CrashFeedback::new(),
) )
}); });

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libafl" name = "libafl"
version = "0.1.0" version = "0.2.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
description = "Slot your own fuzzers together and extend their features using Rust" description = "Slot your own fuzzers together and extend their features using Rust"
documentation = "https://docs.rs/libafl" documentation = "https://docs.rs/libafl"

View File

@ -23,8 +23,6 @@ where
input: Option<I>, input: Option<I>,
/// Filename, if this testcase is backed by a file in the filesystem /// Filename, if this testcase is backed by a file in the filesystem
filename: Option<String>, filename: Option<String>,
/// Accumulated fitness from all the feedbacks
fitness: u32,
/// Map of metadata associated with this testcase /// Map of metadata associated with this testcase
metadata: SerdeAnyMap, metadata: SerdeAnyMap,
/// Time needed to execute the input /// Time needed to execute the input
@ -120,24 +118,6 @@ where
self.filename = Some(filename); self.filename = Some(filename);
} }
/// Get the fitness
#[inline]
pub fn fitness(&self) -> u32 {
self.fitness
}
/// Get the fitness (mutable)
#[inline]
pub fn fitness_mut(&mut self) -> &mut u32 {
&mut self.fitness
}
/// Set the fitness
#[inline]
pub fn set_fitness(&mut self, fitness: u32) {
self.fitness = fitness;
}
/// Get the execution time of the testcase /// Get the execution time of the testcase
pub fn exec_time(&self) -> &Option<Duration> { pub fn exec_time(&self) -> &Option<Duration> {
&self.exec_time &self.exec_time
@ -157,7 +137,6 @@ where
Testcase { Testcase {
input: Some(input.into()), input: Some(input.into()),
filename: None, filename: None,
fitness: 0,
metadata: SerdeAnyMap::new(), metadata: SerdeAnyMap::new(),
exec_time: None, exec_time: None,
cached_len: None, cached_len: None,
@ -170,20 +149,6 @@ where
Testcase { Testcase {
input: Some(input), input: Some(input),
filename: Some(filename), filename: Some(filename),
fitness: 0,
metadata: SerdeAnyMap::new(),
exec_time: None,
cached_len: None,
}
}
/// Create a new Testcase instace given an input and a fitness
#[inline]
pub fn with_fitness(input: I, fitness: u32) -> Self {
Testcase {
input: Some(input),
filename: None,
fitness,
metadata: SerdeAnyMap::new(), metadata: SerdeAnyMap::new(),
exec_time: None, exec_time: None,
cached_len: None, cached_len: None,
@ -195,7 +160,6 @@ where
Testcase { Testcase {
input: None, input: None,
filename: None, filename: None,
fitness: 0,
metadata: SerdeAnyMap::new(), metadata: SerdeAnyMap::new(),
exec_time: None, exec_time: None,
cached_len: None, cached_len: None,

View File

@ -292,10 +292,9 @@ where
let observers: OT = postcard::from_bytes(&observers_buf)?; let observers: OT = postcard::from_bytes(&observers_buf)?;
// TODO include ExitKind in NewTestcase // TODO include ExitKind in NewTestcase
let fitness = state.is_interesting(&input, &observers, &ExitKind::Ok)?; let is_interesting = state.is_interesting(&input, &observers, &ExitKind::Ok)?;
if fitness > 0 if state
&& state .add_if_interesting(&input, is_interesting, scheduler)?
.add_if_interesting(&input, fitness, scheduler)?
.is_some() .is_some()
{ {
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -19,10 +19,10 @@ use crate::{
executors::{ executors::{
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks, Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
}, },
feedbacks::FeedbacksTuple, feedbacks::Feedback,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
state::{HasObjectives, HasSolutions}, state::{HasObjective, HasSolutions},
Error, Error,
}; };
@ -158,7 +158,7 @@ where
/// * `harness_fn` - the harness, executiong the function /// * `harness_fn` - the harness, executiong the function
/// * `observers` - the observers observing the target during execution /// * `observers` - the observers observing the target during execution
/// This may return an error on unix, if signal handler setup fails /// This may return an error on unix, if signal handler setup fails
pub fn new<OC, OFT>( pub fn new<OC, OF>(
harness_fn: &'a mut H, harness_fn: &'a mut H,
observers: OT, observers: OT,
_state: &mut S, _state: &mut S,
@ -167,19 +167,19 @@ where
where where
EM: EventManager<I, S>, EM: EventManager<I, S>,
OC: Corpus<I>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>, S: HasObjective<OF, I> + HasSolutions<OC, I>,
{ {
#[cfg(unix)] #[cfg(unix)]
unsafe { unsafe {
let data = &mut unix_signal_handler::GLOBAL_STATE; let data = &mut unix_signal_handler::GLOBAL_STATE;
write_volatile( write_volatile(
&mut data.crash_handler, &mut data.crash_handler,
unix_signal_handler::inproc_crash_handler::<EM, I, OC, OFT, OT, S>, unix_signal_handler::inproc_crash_handler::<EM, I, OC, OF, OT, S>,
); );
write_volatile( write_volatile(
&mut data.timeout_handler, &mut data.timeout_handler,
unix_signal_handler::inproc_timeout_handler::<EM, I, OC, OFT, OT, S>, unix_signal_handler::inproc_timeout_handler::<EM, I, OC, OF, OT, S>,
); );
setup_signal_handler(data)?; setup_signal_handler(data)?;
@ -190,11 +190,11 @@ where
let data = &mut windows_exception_handler::GLOBAL_STATE; let data = &mut windows_exception_handler::GLOBAL_STATE;
write_volatile( write_volatile(
&mut data.crash_handler, &mut data.crash_handler,
windows_exception_handler::inproc_crash_handler::<EM, I, OC, OFT, OT, S>, windows_exception_handler::inproc_crash_handler::<EM, I, OC, OF, OT, S>,
); );
//write_volatile( //write_volatile(
// &mut data.timeout_handler, // &mut data.timeout_handler,
// windows_exception_handler::inproc_timeout_handler::<EM, I, OC, OFT, OT, S>, // windows_exception_handler::inproc_timeout_handler::<EM, I, OC, OF, OT, S>,
//); //);
setup_exception_handler(data)?; setup_exception_handler(data)?;
@ -234,10 +234,10 @@ mod unix_signal_handler {
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
events::{Event, EventManager}, events::{Event, EventManager},
executors::ExitKind, executors::ExitKind,
feedbacks::FeedbacksTuple, feedbacks::Feedback,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
state::{HasObjectives, HasSolutions}, state::{HasObjective, HasSolutions},
}; };
// TODO merge GLOBAL_STATE with the Windows one // TODO merge GLOBAL_STATE with the Windows one
@ -308,7 +308,7 @@ mod unix_signal_handler {
} }
#[cfg(unix)] #[cfg(unix)]
pub unsafe fn inproc_timeout_handler<EM, I, OC, OFT, OT, S>( pub unsafe fn inproc_timeout_handler<EM, I, OC, OF, OT, S>(
_signal: Signal, _signal: Signal,
_info: siginfo_t, _info: siginfo_t,
_context: &mut ucontext_t, _context: &mut ucontext_t,
@ -317,8 +317,8 @@ mod unix_signal_handler {
EM: EventManager<I, S>, EM: EventManager<I, S>,
OT: ObserversTuple, OT: ObserversTuple,
OC: Corpus<I>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>, S: HasObjective<OF, I> + HasSolutions<OC, I>,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
{ {
let state = (data.state_ptr as *mut S).as_mut().unwrap(); let state = (data.state_ptr as *mut S).as_mut().unwrap();
@ -337,11 +337,11 @@ mod unix_signal_handler {
let input = (data.current_input_ptr as *const I).as_ref().unwrap(); let input = (data.current_input_ptr as *const I).as_ref().unwrap();
data.current_input_ptr = ptr::null(); data.current_input_ptr = ptr::null();
let obj_fitness = state let interesting = state
.objectives_mut() .objective_mut()
.is_interesting_all(&input, observers, &ExitKind::Timeout) .is_interesting(&input, observers, &ExitKind::Timeout)
.expect("In timeout handler objectives failure."); .expect("In timeout handler objective failure.");
if obj_fitness > 0 { if interesting {
state state
.solutions_mut() .solutions_mut()
.add(Testcase::new(input.clone())) .add(Testcase::new(input.clone()))
@ -374,7 +374,7 @@ mod unix_signal_handler {
/// Will be used for signal handling. /// Will be used for signal handling.
/// It will store the current State to shmem, then exit. /// It will store the current State to shmem, then exit.
#[allow(clippy::too_many_lines)] #[allow(clippy::too_many_lines)]
pub unsafe fn inproc_crash_handler<EM, I, OC, OFT, OT, S>( pub unsafe fn inproc_crash_handler<EM, I, OC, OF, OT, S>(
_signal: Signal, _signal: Signal,
_info: siginfo_t, _info: siginfo_t,
_context: &mut ucontext_t, _context: &mut ucontext_t,
@ -383,8 +383,8 @@ mod unix_signal_handler {
EM: EventManager<I, S>, EM: EventManager<I, S>,
OT: ObserversTuple, OT: ObserversTuple,
OC: Corpus<I>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>, S: HasObjective<OF, I> + HasSolutions<OC, I>,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
{ {
#[cfg(all(target_os = "android", target_arch = "aarch64"))] #[cfg(all(target_os = "android", target_arch = "aarch64"))]
@ -446,11 +446,11 @@ mod unix_signal_handler {
// Make sure we don't crash in the crash handler forever. // Make sure we don't crash in the crash handler forever.
data.current_input_ptr = ptr::null(); data.current_input_ptr = ptr::null();
let obj_fitness = state let interesting = state
.objectives_mut() .objective_mut()
.is_interesting_all(&input, observers, &ExitKind::Crash) .is_interesting(&input, observers, &ExitKind::Crash)
.expect("In crash handler objectives failure."); .expect("In crash handler objective failure.");
if obj_fitness > 0 { if interesting {
let new_input = input.clone(); let new_input = input.clone();
state state
.solutions_mut() .solutions_mut()
@ -528,10 +528,10 @@ mod windows_exception_handler {
corpus::{Corpus, Testcase}, corpus::{Corpus, Testcase},
events::{Event, EventManager}, events::{Event, EventManager},
executors::ExitKind, executors::ExitKind,
feedbacks::FeedbacksTuple, feedbacks::Feedback,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
state::{HasObjectives, HasSolutions}, state::{HasObjective, HasSolutions},
}; };
/// Signal handling on unix systems needs some nasty unsafe. /// Signal handling on unix systems needs some nasty unsafe.
@ -582,7 +582,7 @@ mod windows_exception_handler {
} }
} }
pub unsafe fn inproc_crash_handler<EM, I, OC, OFT, OT, S>( pub unsafe fn inproc_crash_handler<EM, I, OC, OF, OT, S>(
code: ExceptionCode, code: ExceptionCode,
exception_pointers: *mut EXCEPTION_POINTERS, exception_pointers: *mut EXCEPTION_POINTERS,
data: &mut InProcessExecutorHandlerData, data: &mut InProcessExecutorHandlerData,
@ -590,8 +590,8 @@ mod windows_exception_handler {
EM: EventManager<I, S>, EM: EventManager<I, S>,
OT: ObserversTuple, OT: ObserversTuple,
OC: Corpus<I>, OC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
S: HasObjectives<OFT, I> + HasSolutions<OC, I>, S: HasObjective<OF, I> + HasSolutions<OC, I>,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
{ {
#[cfg(feature = "std")] #[cfg(feature = "std")]
@ -610,11 +610,11 @@ mod windows_exception_handler {
// Make sure we don't crash in the crash handler forever. // Make sure we don't crash in the crash handler forever.
data.current_input_ptr = ptr::null(); data.current_input_ptr = ptr::null();
let obj_fitness = state let interesting = state
.objectives_mut() .objective_mut()
.is_interesting_all(&input, observers, &ExitKind::Crash) .is_interesting(&input, observers, &ExitKind::Crash)
.expect("In crash handler objectives failure."); .expect("In crash handler objective failure.");
if obj_fitness > 0 { if interesting {
let new_input = input.clone(); let new_input = input.clone();
state state
.solutions_mut() .solutions_mut()

View File

@ -139,11 +139,11 @@ where
_input: &I, _input: &I,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where where
OT: ObserversTuple, OT: ObserversTuple,
{ {
let mut interesting = 0; let mut interesting = false;
// TODO optimize // TODO optimize
let observer = observers.match_name_type::<O>(&self.name).unwrap(); let observer = observers.match_name_type::<O>(&self.name).unwrap();
let size = observer.usable_count(); let size = observer.usable_count();
@ -157,7 +157,7 @@ where
let reduced = R::reduce(history, item); let reduced = R::reduce(history, item);
if history != reduced { if history != reduced {
self.history_map[i] = reduced; self.history_map[i] = reduced;
interesting += 1; interesting = true;
} }
} }
} else if self.indexes.is_some() && self.novelties.is_none() { } else if self.indexes.is_some() && self.novelties.is_none() {
@ -171,7 +171,7 @@ where
let reduced = R::reduce(history, item); let reduced = R::reduce(history, item);
if history != reduced { if history != reduced {
self.history_map[i] = reduced; self.history_map[i] = reduced;
interesting += 1; interesting = true;
} }
} }
} else if self.indexes.is_none() && self.novelties.is_some() { } else if self.indexes.is_none() && self.novelties.is_some() {
@ -182,7 +182,7 @@ where
let reduced = R::reduce(history, item); let reduced = R::reduce(history, item);
if history != reduced { if history != reduced {
self.history_map[i] = reduced; self.history_map[i] = reduced;
interesting += 1; interesting = true;
self.novelties.as_mut().unwrap().push(i); self.novelties.as_mut().unwrap().push(i);
} }
} }
@ -197,7 +197,7 @@ where
let reduced = R::reduce(history, item); let reduced = R::reduce(history, item);
if history != reduced { if history != reduced {
self.history_map[i] = reduced; self.history_map[i] = reduced;
interesting += 1; interesting = true;
self.novelties.as_mut().unwrap().push(i); self.novelties.as_mut().unwrap().push(i);
} }
} }

View File

@ -15,12 +15,12 @@ use crate::{
Error, Error,
}; };
use core::time::Duration; use core::{marker::PhantomData, time::Duration};
/// Feedbacks evaluate the observers. /// Feedbacks evaluate the observers.
/// Basically, they reduce the information provided by an observer to a value, /// Basically, they reduce the information provided by an observer to a value,
/// indicating the "interestingness" of the last run. /// indicating the "interestingness" of the last run.
pub trait Feedback<I>: Named + serde::Serialize + serde::de::DeserializeOwned + 'static pub trait Feedback<I>: Named + serde::Serialize + serde::de::DeserializeOwned
where where
I: Input, I: Input,
{ {
@ -30,7 +30,7 @@ where
input: &I, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where where
OT: ObserversTuple; OT: ObserversTuple;
@ -47,77 +47,239 @@ where
} }
} }
pub trait FeedbacksTuple<I>: serde::Serialize + serde::de::DeserializeOwned /// Compose feedbacks with an AND operation
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct AndFeedback<A, B, I>
where where
A: Feedback<I>,
B: Feedback<I>,
I: Input, I: Input,
{ {
/// Get the total interestingness value from all feedbacks pub first: A,
fn is_interesting_all<OT>( pub second: B,
phantom: PhantomData<I>,
}
impl<A, B, I> Feedback<I> for AndFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
fn is_interesting<OT>(
&mut self, &mut self,
input: &I, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where
OT: ObserversTuple;
/// Write metadata for this testcase
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error>;
/// Discards metadata - the end of this input's execution
fn discard_metadata_all(&mut self, input: &I) -> Result<(), Error>;
}
impl<I> FeedbacksTuple<I> for ()
where
I: Input,
{
#[inline]
fn is_interesting_all<OT>(&mut self, _: &I, _: &OT, _: &ExitKind) -> Result<u32, Error>
where where
OT: ObserversTuple, OT: ObserversTuple,
{ {
Ok(0) let a = self.first.is_interesting(input, observers, exit_kind)?;
} let b = self.second.is_interesting(input, observers, exit_kind)?;
Ok(a && b)
#[inline]
fn append_metadata_all(&mut self, _testcase: &mut Testcase<I>) -> Result<(), Error> {
Ok(())
}
#[inline]
fn discard_metadata_all(&mut self, _input: &I) -> Result<(), Error> {
Ok(())
} }
} }
impl<Head, Tail, I> FeedbacksTuple<I> for (Head, Tail) impl<A, B, I> Named for AndFeedback<A, B, I>
where where
Head: Feedback<I>, A: Feedback<I>,
Tail: FeedbacksTuple<I>, B: Feedback<I>,
I: Input, I: Input,
{ {
fn is_interesting_all<OT>( #[inline]
fn name(&self) -> &str {
//format!("And({}, {})", self.first.name(), self.second.name())
"AndFeedback"
}
}
impl<A, B, I> AndFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
pub fn new(first: A, second: B) -> Self {
Self {
first,
second,
phantom: PhantomData,
}
}
}
/// Compose feedbacks with an OR operation
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct OrFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
pub first: A,
pub second: B,
phantom: PhantomData<I>,
}
impl<A, B, I> Feedback<I> for OrFeedback<A, B, I>
where
A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
fn is_interesting<OT>(
&mut self, &mut self,
input: &I, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where where
OT: ObserversTuple, OT: ObserversTuple,
{ {
Ok(self.0.is_interesting(input, observers, exit_kind)? let a = self.first.is_interesting(input, observers, exit_kind)?;
+ self.1.is_interesting_all(input, observers, exit_kind)?) let b = self.second.is_interesting(input, observers, exit_kind)?;
Ok(a || b)
} }
}
fn append_metadata_all(&mut self, testcase: &mut Testcase<I>) -> Result<(), Error> { impl<A, B, I> Named for OrFeedback<A, B, I>
self.0.append_metadata(testcase)?; where
self.1.append_metadata_all(testcase) A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
#[inline]
fn name(&self) -> &str {
//format!("Or({}, {})", self.first.name(), self.second.name())
"OrFeedback"
} }
}
fn discard_metadata_all(&mut self, input: &I) -> Result<(), Error> { impl<A, B, I> OrFeedback<A, B, I>
self.0.discard_metadata(input)?; where
self.1.discard_metadata_all(input) A: Feedback<I>,
B: Feedback<I>,
I: Input,
{
pub fn new(first: A, second: B) -> Self {
Self {
first,
second,
phantom: PhantomData,
}
}
}
/// Compose feedbacks with an OR operation
#[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "I: serde::de::DeserializeOwned")]
pub struct NotFeedback<A, I>
where
A: Feedback<I>,
I: Input,
{
pub first: A,
phantom: PhantomData<I>,
}
impl<A, I> Feedback<I> for NotFeedback<A, I>
where
A: Feedback<I>,
I: Input,
{
fn is_interesting<OT>(
&mut self,
input: &I,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
Ok(!self.first.is_interesting(input, observers, exit_kind)?)
}
}
impl<A, I> Named for NotFeedback<A, I>
where
A: Feedback<I>,
I: Input,
{
#[inline]
fn name(&self) -> &str {
//format!("Not({})", self.first.name())
"NotFeedback"
}
}
impl<A, I> NotFeedback<A, I>
where
A: Feedback<I>,
I: Input,
{
pub fn new(first: A) -> Self {
Self {
first,
phantom: PhantomData,
}
}
}
/// Variadic macro to create a chain of AndFeedback
#[macro_export]
macro_rules! feedback_and {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
// recursive call
$crate::feedbacks::AndFeedback::new($head , feedback_and!($($tail),+))
};
}
/// Variadic macro to create a chain of OrFeedback
#[macro_export]
macro_rules! feedback_or {
( $last:expr ) => { $last };
( $head:expr, $($tail:expr), +) => {
// recursive call
$crate::feedbacks::OrFeedback::new($head , feedback_or!($($tail),+))
};
}
/// Variadic macro to create a NotFeedback
#[macro_export]
macro_rules! feedback_not {
( $last:expr ) => {
$crate::feedbacks::NotFeedback::new($last)
};
}
/// Hack to use () as empty Feedback
impl<I> Feedback<I> for ()
where
I: Input,
{
fn is_interesting<OT>(
&mut self,
_input: &I,
_observers: &OT,
_exit_kind: &ExitKind,
) -> Result<bool, Error>
where
OT: ObserversTuple,
{
Ok(false)
}
}
impl Named for () {
#[inline]
fn name(&self) -> &str {
"Empty"
} }
} }
@ -134,14 +296,14 @@ where
_input: &I, _input: &I,
_observers: &OT, _observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where where
OT: ObserversTuple, OT: ObserversTuple,
{ {
if let ExitKind::Crash = exit_kind { if let ExitKind::Crash = exit_kind {
Ok(1) Ok(true)
} else { } else {
Ok(0) Ok(false)
} }
} }
} }
@ -177,14 +339,14 @@ where
_input: &I, _input: &I,
_observers: &OT, _observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where where
OT: ObserversTuple, OT: ObserversTuple,
{ {
if let ExitKind::Timeout = exit_kind { if let ExitKind::Timeout = exit_kind {
Ok(1) Ok(true)
} else { } else {
Ok(0) Ok(false)
} }
} }
} }
@ -209,6 +371,7 @@ impl Default for TimeoutFeedback {
} }
/// Nop feedback that annotates execution time in the new testcase, if any /// Nop feedback that annotates execution time in the new testcase, if any
/// For this Feedback, the testcase is never interesting (use with an OR)
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
pub struct TimeFeedback { pub struct TimeFeedback {
exec_time: Option<Duration>, exec_time: Option<Duration>,
@ -223,13 +386,13 @@ where
_input: &I, _input: &I,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where where
OT: ObserversTuple, OT: ObserversTuple,
{ {
let observer = observers.match_first_type::<TimeObserver>().unwrap(); let observer = observers.match_first_type::<TimeObserver>().unwrap();
self.exec_time = *observer.last_runtime(); self.exec_time = *observer.last_runtime();
Ok(0) Ok(false)
} }
/// Append to the testcase the generated metadata in case of a new corpus item /// Append to the testcase the generated metadata in case of a new corpus item

View File

@ -15,7 +15,7 @@ use crate::{
executors::{ executors::{
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks, Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
}, },
feedbacks::FeedbacksTuple, feedbacks::Feedback,
generators::Generator, generators::Generator,
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
@ -98,30 +98,30 @@ pub trait HasMetadata {
} }
} }
/// Trait for elements offering a feedbacks tuple /// Trait for elements offering a feedback
pub trait HasFeedbacks<FT, I>: Sized pub trait HasFeedback<F, I>: Sized
where where
FT: FeedbacksTuple<I>, F: Feedback<I>,
I: Input, I: Input,
{ {
/// The feedbacks tuple /// The feedback
fn feedbacks(&self) -> &FT; fn feedback(&self) -> &F;
/// The feedbacks tuple (mut) /// The feedback (mut)
fn feedbacks_mut(&mut self) -> &mut FT; fn feedback_mut(&mut self) -> &mut F;
} }
/// Trait for elements offering an objective feedbacks tuple /// Trait for elements offering an objective feedback tuple
pub trait HasObjectives<FT, I>: Sized pub trait HasObjective<OF, I>: Sized
where where
FT: FeedbacksTuple<I>, OF: Feedback<I>,
I: Input, I: Input,
{ {
/// The objective feedbacks tuple /// The objective feedback
fn objectives(&self) -> &FT; fn objective(&self) -> &OF;
/// The objective feedbacks tuple (mut) /// The objective feedback (mut)
fn objectives_mut(&mut self) -> &mut FT; fn objective_mut(&mut self) -> &mut OF;
} }
/// Trait for the execution counter /// Trait for the execution counter
@ -153,7 +153,7 @@ where
input: &I, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where where
OT: ObserversTuple; OT: ObserversTuple;
@ -161,7 +161,7 @@ where
fn add_if_interesting<CS>( fn add_if_interesting<CS>(
&mut self, &mut self,
input: &I, input: &I,
fitness: u32, is_interesting: bool,
scheduler: &CS, scheduler: &CS,
) -> Result<Option<usize>, Error> ) -> Result<Option<usize>, Error>
where where
@ -169,7 +169,7 @@ where
Self: Sized; Self: Sized;
} }
/// Evaluate an input modyfing the state of the fuzzer and returning a fitness /// Evaluate an input modyfing the state of the fuzzer
pub trait Evaluator<I>: Sized pub trait Evaluator<I>: Sized
where where
I: Input, I: Input,
@ -181,7 +181,7 @@ where
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
scheduler: &CS, scheduler: &CS,
) -> Result<(u32, Option<usize>), Error> ) -> Result<(bool, Option<usize>), Error>
where where
E: Executor<I> E: Executor<I>
+ HasObservers<OT> + HasObservers<OT>
@ -194,15 +194,15 @@ where
/// The state a fuzz run. /// The state a fuzz run.
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "FT: serde::de::DeserializeOwned")] #[serde(bound = "F: serde::de::DeserializeOwned")]
pub struct State<C, FT, I, OFT, R, SC> pub struct State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// RNG instance /// RNG instance
rand: R, rand: R,
@ -213,11 +213,11 @@ where
/// The corpus /// The corpus
corpus: C, corpus: C,
/// Feedbacks used to evaluate an input /// Feedbacks used to evaluate an input
feedbacks: FT, feedback: F,
// Solutions corpus // Solutions corpus
solutions: SC, solutions: SC,
/// Objective Feedbacks /// Objective Feedbacks
objectives: OFT, objective: OF,
/// Metadata stored for this state by one of the components /// Metadata stored for this state by one of the components
metadata: SerdeAnyMap, metadata: SerdeAnyMap,
/// MaxSize testcase size for mutators that appreciate it /// MaxSize testcase size for mutators that appreciate it
@ -226,14 +226,14 @@ where
phantom: PhantomData<I>, phantom: PhantomData<I>,
} }
impl<C, FT, I, OFT, R, SC> HasRand<R> for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasRand<R> for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// The rand instance /// The rand instance
#[inline] #[inline]
@ -248,14 +248,14 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> HasCorpus<C, I> for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasCorpus<C, I> for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// Returns the corpus /// Returns the corpus
#[inline] #[inline]
@ -270,14 +270,14 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> HasSolutions<SC, I> for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasSolutions<SC, I> for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// Returns the solutions corpus /// Returns the solutions corpus
#[inline] #[inline]
@ -292,14 +292,14 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> HasMetadata for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasMetadata for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// Get all the metadata into an HashMap /// Get all the metadata into an HashMap
#[inline] #[inline]
@ -314,58 +314,58 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> HasFeedbacks<FT, I> for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasFeedback<F, I> for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// The feedbacks tuple /// The feedback
#[inline] #[inline]
fn feedbacks(&self) -> &FT { fn feedback(&self) -> &F {
&self.feedbacks &self.feedback
} }
/// The feedbacks tuple (mut) /// The feedback (mut)
#[inline] #[inline]
fn feedbacks_mut(&mut self) -> &mut FT { fn feedback_mut(&mut self) -> &mut F {
&mut self.feedbacks &mut self.feedback
} }
} }
impl<C, FT, I, OFT, R, SC> HasObjectives<OFT, I> for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasObjective<OF, I> for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// The objective feedbacks tuple /// The objective feedback
#[inline] #[inline]
fn objectives(&self) -> &OFT { fn objective(&self) -> &OF {
&self.objectives &self.objective
} }
/// The objective feedbacks tuple (mut) /// The objective feedback (mut)
#[inline] #[inline]
fn objectives_mut(&mut self) -> &mut OFT { fn objective_mut(&mut self) -> &mut OF {
&mut self.objectives &mut self.objective
} }
} }
impl<C, FT, I, OFT, R, SC> HasExecutions for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasExecutions for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// The executions counter /// The executions counter
#[inline] #[inline]
@ -380,14 +380,14 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> HasMaxSize for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasMaxSize for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
fn max_size(&self) -> usize { fn max_size(&self) -> usize {
self.max_size self.max_size
@ -398,14 +398,14 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> HasStartTime for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> HasStartTime for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// The starting time /// The starting time
#[inline] #[inline]
@ -420,14 +420,14 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> IfInteresting<I> for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> IfInteresting<I> for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// Evaluate if a set of observation channels has an interesting state /// Evaluate if a set of observation channels has an interesting state
fn is_interesting<OT>( fn is_interesting<OT>(
@ -435,12 +435,12 @@ where
input: &I, input: &I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<u32, Error> ) -> Result<bool, Error>
where where
OT: ObserversTuple, OT: ObserversTuple,
{ {
self.feedbacks_mut() self.feedback_mut()
.is_interesting_all(input, observers, exit_kind) .is_interesting(input, observers, exit_kind)
} }
/// Adds this input to the corpus, if it's intersting, and return the index /// Adds this input to the corpus, if it's intersting, and return the index
@ -448,33 +448,33 @@ where
fn add_if_interesting<CS>( fn add_if_interesting<CS>(
&mut self, &mut self,
input: &I, input: &I,
fitness: u32, is_interesting: bool,
scheduler: &CS, scheduler: &CS,
) -> Result<Option<usize>, Error> ) -> Result<Option<usize>, Error>
where where
CS: CorpusScheduler<I, Self>, CS: CorpusScheduler<I, Self>,
{ {
if fitness > 0 { if is_interesting {
let mut testcase = Testcase::with_fitness(input.clone(), fitness); let mut testcase = Testcase::new(input.clone());
self.feedbacks_mut().append_metadata_all(&mut testcase)?; self.feedback_mut().append_metadata(&mut testcase)?;
let idx = self.corpus.add(testcase)?; let idx = self.corpus.add(testcase)?;
scheduler.on_add(self, idx)?; scheduler.on_add(self, idx)?;
Ok(Some(idx)) Ok(Some(idx))
} else { } else {
self.feedbacks_mut().discard_metadata_all(&input)?; self.feedback_mut().discard_metadata(&input)?;
Ok(None) Ok(None)
} }
} }
} }
impl<C, FT, I, OFT, R, SC> Evaluator<I> for State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> Evaluator<I> for State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// Process one input, adding to the respective corpuses if needed and firing the right events /// Process one input, adding to the respective corpuses if needed and firing the right events
#[inline] #[inline]
@ -485,7 +485,7 @@ where
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
scheduler: &CS, scheduler: &CS,
) -> Result<(u32, Option<usize>), Error> ) -> Result<(bool, Option<usize>), Error>
where where
E: Executor<I> E: Executor<I>
+ HasObservers<OT> + HasObservers<OT>
@ -496,19 +496,19 @@ where
EM: EventManager<I, Self>, EM: EventManager<I, Self>,
CS: CorpusScheduler<I, Self>, CS: CorpusScheduler<I, Self>,
{ {
let (fitness, is_solution) = self.execute_input(&input, executor, manager)?; let (is_interesting, is_solution) = self.execute_input(&input, executor, manager)?;
let observers = executor.observers(); let observers = executor.observers();
if is_solution { if is_solution {
// If the input is a solution, add it to the respective corpus // If the input is a solution, add it to the respective corpus
let mut testcase = Testcase::new(input.clone()); let mut testcase = Testcase::new(input.clone());
self.objectives_mut().append_metadata_all(&mut testcase)?; self.objective_mut().append_metadata(&mut testcase)?;
self.solutions_mut().add(testcase)?; self.solutions_mut().add(testcase)?;
} else { } else {
self.objectives_mut().discard_metadata_all(&input)?; self.objective_mut().discard_metadata(&input)?;
} }
let corpus_idx = self.add_if_interesting(&input, fitness, scheduler)?; let corpus_idx = self.add_if_interesting(&input, is_interesting, scheduler)?;
if corpus_idx.is_some() { if corpus_idx.is_some() {
let observers_buf = manager.serialize_observers(observers)?; let observers_buf = manager.serialize_observers(observers)?;
manager.fire( manager.fire(
@ -524,18 +524,18 @@ where
)?; )?;
} }
Ok((fitness, corpus_idx)) Ok((is_interesting, corpus_idx))
} }
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<C, FT, OFT, R, SC> State<C, FT, BytesInput, OFT, R, SC> impl<C, F, OF, R, SC> State<C, F, BytesInput, OF, R, SC>
where where
C: Corpus<BytesInput>, C: Corpus<BytesInput>,
R: Rand, R: Rand,
FT: FeedbacksTuple<BytesInput>, F: Feedback<BytesInput>,
SC: Corpus<BytesInput>, SC: Corpus<BytesInput>,
OFT: FeedbacksTuple<BytesInput>, OF: Feedback<BytesInput>,
{ {
pub fn load_from_directory<CS, E, OT, EM>( pub fn load_from_directory<CS, E, OT, EM>(
&mut self, &mut self,
@ -568,9 +568,10 @@ where
println!("Loading file {:?} ...", &path); println!("Loading file {:?} ...", &path);
let bytes = fs::read(&path)?; let bytes = fs::read(&path)?;
let input = BytesInput::new(bytes); let input = BytesInput::new(bytes);
let (fitness, is_solution) = self.execute_input(&input, executor, manager)?; let (is_interesting, is_solution) =
self.execute_input(&input, executor, manager)?;
if self if self
.add_if_interesting(&input, fitness, scheduler)? .add_if_interesting(&input, is_interesting, scheduler)?
.is_none() .is_none()
{ {
println!("File {:?} was not interesting, skipped.", &path); println!("File {:?} was not interesting, skipped.", &path);
@ -618,14 +619,14 @@ where
} }
} }
impl<C, FT, I, OFT, R, SC> State<C, FT, I, OFT, R, SC> impl<C, F, I, OF, R, SC> State<C, F, I, OF, R, SC>
where where
C: Corpus<I>, C: Corpus<I>,
I: Input, I: Input,
R: Rand, R: Rand,
FT: FeedbacksTuple<I>, F: Feedback<I>,
SC: Corpus<I>, SC: Corpus<I>,
OFT: FeedbacksTuple<I>, OF: Feedback<I>,
{ {
/// Runs the input and triggers observers and feedback /// Runs the input and triggers observers and feedback
pub fn execute_input<E, EM, OT>( pub fn execute_input<E, EM, OT>(
@ -633,7 +634,7 @@ where
input: &I, input: &I,
executor: &mut E, executor: &mut E,
event_mgr: &mut EM, event_mgr: &mut EM,
) -> Result<(u32, bool), Error> ) -> Result<(bool, bool), Error>
where where
E: Executor<I> E: Executor<I>
+ HasObservers<OT> + HasObservers<OT>
@ -653,15 +654,14 @@ where
executor.post_exec_observers(self, event_mgr, input)?; executor.post_exec_observers(self, event_mgr, input)?;
let observers = executor.observers(); let observers = executor.observers();
let fitness = self let is_interesting = self
.feedbacks_mut() .feedback_mut()
.is_interesting_all(&input, observers, &exit_kind)?; .is_interesting(&input, observers, &exit_kind)?;
let is_solution = self let is_solution = self
.objectives_mut() .objective_mut()
.is_interesting_all(&input, observers, &exit_kind)? .is_interesting(&input, observers, &exit_kind)?;
> 0; Ok((is_interesting, is_solution))
Ok((fitness, is_solution))
} }
pub fn generate_initial_inputs<CS, G, E, OT, EM>( pub fn generate_initial_inputs<CS, G, E, OT, EM>(
@ -686,8 +686,8 @@ where
let mut added = 0; let mut added = 0;
for _ in 0..num { for _ in 0..num {
let input = generator.generate(self.rand_mut())?; let input = generator.generate(self.rand_mut())?;
let (fitness, _) = self.evaluate_input(input, executor, manager, scheduler)?; let (is_interesting, _) = self.evaluate_input(input, executor, manager, scheduler)?;
if fitness > 0 { if is_interesting {
added += 1; added += 1;
} }
} }
@ -703,16 +703,16 @@ where
Ok(()) Ok(())
} }
pub fn new(rand: R, corpus: C, feedbacks: FT, solutions: SC, objectives: OFT) -> Self { pub fn new(rand: R, corpus: C, feedback: F, solutions: SC, objective: OF) -> Self {
Self { Self {
rand, rand,
executions: 0, executions: 0,
start_time: Duration::from_millis(0), start_time: Duration::from_millis(0),
metadata: SerdeAnyMap::default(), metadata: SerdeAnyMap::default(),
corpus, corpus,
feedbacks, feedback,
solutions, solutions,
objectives, objective,
max_size: DEFAULT_MAX_SIZE, max_size: DEFAULT_MAX_SIZE,
phantom: PhantomData, phantom: PhantomData,
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libafl_frida" name = "libafl_frida"
version = "0.1.0" version = "0.2.0"
authors = ["s1341 <github@shmarya.net>"] authors = ["s1341 <github@shmarya.net>"]
description = "Frida backend library for LibAFL" description = "Frida backend library for LibAFL"
documentation = "https://docs.rs/libafl_frida" documentation = "https://docs.rs/libafl_frida"
@ -13,7 +13,7 @@ edition = "2018"
cc = { version = "1.0", features = ["parallel"] } cc = { version = "1.0", features = ["parallel"] }
[dependencies] [dependencies]
libafl = { path = "../libafl", version = "0.1.0", features = ["std", "libafl_derive"] } libafl = { path = "../libafl", version = "0.2.0", features = ["std", "libafl_derive"] }
libafl_targets = { path = "../libafl_targets", version = "0.1.0" } libafl_targets = { path = "../libafl_targets", version = "0.1.0" }
nix = "0.20.0" nix = "0.20.0"
libc = "0.2.92" libc = "0.2.92"

View File

@ -1687,18 +1687,18 @@ where
_input: &I, _input: &I,
observers: &OT, observers: &OT,
_exit_kind: &ExitKind, _exit_kind: &ExitKind,
) -> Result<u32, Error> { ) -> Result<bool, Error> {
let observer = observers let observer = observers
.match_first_type::<AsanErrorsObserver>() .match_first_type::<AsanErrorsObserver>()
.expect("An AsanErrorsFeedback needs an AsanErrorsObserver"); .expect("An AsanErrorsFeedback needs an AsanErrorsObserver");
match observer.errors() { match observer.errors() {
None => Ok(0), None => Ok(false),
Some(errors) => { Some(errors) => {
if !errors.errors.is_empty() { if !errors.errors.is_empty() {
self.errors = Some(errors.clone()); self.errors = Some(errors.clone());
Ok(1) Ok(true)
} else { } else {
Ok(0) Ok(false)
} }
} }
} }