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:
parent
9e9d95f93d
commit
9f3b0984c3
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "baby_fuzzer"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -56,13 +56,13 @@ pub fn main() {
|
||||
StdRand::with_seed(current_nanos()),
|
||||
// Corpus that will be evolved, we keep it in memory for performance
|
||||
InMemoryCorpus::new(),
|
||||
// Feedbacks to rate the interestingness of an input
|
||||
tuple_list!(MaxMapFeedback::new_with_observer(&observer)),
|
||||
// Feedback to rate the interestingness of an input
|
||||
MaxMapFeedback::new_with_observer(&observer),
|
||||
// Corpus in which we store solutions (crashes in this example),
|
||||
// on disk so the user can get them after stopping the fuzzer
|
||||
OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(),
|
||||
// Feedbacks to recognize an input as solution
|
||||
tuple_list!(CrashFeedback::new()),
|
||||
CrashFeedback::new(),
|
||||
);
|
||||
|
||||
// Setup a basic mutator with a mutational stage
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "frida_libpng"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
@ -25,7 +25,7 @@ libafl = { path = "../../libafl/", features = [ "std", "llmp_compression" ] } #,
|
||||
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", 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"
|
||||
libc = "0.2"
|
||||
libloading = "0.7.0"
|
||||
|
@ -12,6 +12,7 @@ use libafl::{
|
||||
inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, HasExecHooks,
|
||||
HasExecHooksTuple, HasObservers, HasObserversHooks,
|
||||
},
|
||||
feedback_or,
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeoutFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
inputs::{HasTargetBytes, Input},
|
||||
@ -276,17 +277,13 @@ unsafe fn fuzz(
|
||||
// Corpus that will be evolved, we keep it in memory for performance
|
||||
InMemoryCorpus::new(),
|
||||
// Feedbacks to rate the interestingness of an input
|
||||
tuple_list!(MaxMapFeedback::new_with_observer_track(
|
||||
&edges_observer,
|
||||
true,
|
||||
false
|
||||
)),
|
||||
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||
// Corpus in which we store solutions (crashes in this example),
|
||||
// on disk so the user can get them after stopping the fuzzer
|
||||
OnDiskCorpus::new_save_meta(objective_dir, Some(OnDiskMetadataFormat::JsonPretty))
|
||||
.unwrap(),
|
||||
// Feedbacks to recognize an input as solution
|
||||
tuple_list!(
|
||||
feedback_or!(
|
||||
CrashFeedback::new(),
|
||||
TimeoutFeedback::new(),
|
||||
AsanErrorsFeedback::new()
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libfuzzer_libmozjpeg"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -8,6 +8,7 @@ use libafl::{
|
||||
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus, RandCorpusScheduler},
|
||||
events::setup_restarting_mgr_std,
|
||||
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||
feedback_or,
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
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
|
||||
InMemoryCorpus::new(),
|
||||
// Feedbacks to rate the interestingness of an input
|
||||
tuple_list!(
|
||||
feedback_or!(
|
||||
MaxMapFeedback::new_with_observer(&edges_observer),
|
||||
MaxMapFeedback::new_with_observer(&cmps_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
|
||||
OnDiskCorpus::new(objective_dir).unwrap(),
|
||||
// Feedbacks to recognize an input as solution
|
||||
tuple_list!(CrashFeedback::new()),
|
||||
CrashFeedback::new(),
|
||||
)
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libfuzzer_libpng"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||
edition = "2018"
|
||||
|
||||
|
@ -12,6 +12,7 @@ use libafl::{
|
||||
},
|
||||
events::{setup_restarting_mgr_std, EventManager},
|
||||
executors::{inprocess::InProcessExecutor, ExitKind, TimeoutExecutor},
|
||||
feedback_or,
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
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
|
||||
InMemoryCorpus::new(),
|
||||
// Feedbacks to rate the interestingness of an input
|
||||
tuple_list!(
|
||||
feedback_or!(
|
||||
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||
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
|
||||
OnDiskCorpus::new(objective_dir).unwrap(),
|
||||
// Feedbacks to recognize an input as solution
|
||||
tuple_list!(CrashFeedback::new(), TimeoutFeedback::new()),
|
||||
feedback_or!(CrashFeedback::new(), TimeoutFeedback::new()),
|
||||
)
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libfuzzer_stb_image"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||
edition = "2018"
|
||||
build = "build.rs"
|
||||
|
@ -11,6 +11,7 @@ use libafl::{
|
||||
},
|
||||
events::setup_restarting_mgr_std,
|
||||
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||
feedback_or,
|
||||
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
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
|
||||
InMemoryCorpus::new(),
|
||||
// Feedbacks to rate the interestingness of an input
|
||||
tuple_list!(
|
||||
feedback_or!(
|
||||
MaxMapFeedback::new_with_observer_track(&edges_observer, true, false),
|
||||
TimeFeedback::new()
|
||||
),
|
||||
// Corpus in which we store solutions (crashes in this example),
|
||||
// on disk so the user can get them after stopping the fuzzer
|
||||
OnDiskCorpus::new(objective_dir).unwrap(),
|
||||
// Feedbacks to recognize an input as solution
|
||||
tuple_list!(CrashFeedback::new()),
|
||||
// Feedback to recognize an input as solution
|
||||
CrashFeedback::new(),
|
||||
)
|
||||
});
|
||||
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libafl"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>", "Dominik Maier <domenukk@gmail.com>"]
|
||||
description = "Slot your own fuzzers together and extend their features using Rust"
|
||||
documentation = "https://docs.rs/libafl"
|
||||
|
@ -23,8 +23,6 @@ where
|
||||
input: Option<I>,
|
||||
/// Filename, if this testcase is backed by a file in the filesystem
|
||||
filename: Option<String>,
|
||||
/// Accumulated fitness from all the feedbacks
|
||||
fitness: u32,
|
||||
/// Map of metadata associated with this testcase
|
||||
metadata: SerdeAnyMap,
|
||||
/// Time needed to execute the input
|
||||
@ -120,24 +118,6 @@ where
|
||||
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
|
||||
pub fn exec_time(&self) -> &Option<Duration> {
|
||||
&self.exec_time
|
||||
@ -157,7 +137,6 @@ where
|
||||
Testcase {
|
||||
input: Some(input.into()),
|
||||
filename: None,
|
||||
fitness: 0,
|
||||
metadata: SerdeAnyMap::new(),
|
||||
exec_time: None,
|
||||
cached_len: None,
|
||||
@ -170,20 +149,6 @@ where
|
||||
Testcase {
|
||||
input: Some(input),
|
||||
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(),
|
||||
exec_time: None,
|
||||
cached_len: None,
|
||||
@ -195,7 +160,6 @@ where
|
||||
Testcase {
|
||||
input: None,
|
||||
filename: None,
|
||||
fitness: 0,
|
||||
metadata: SerdeAnyMap::new(),
|
||||
exec_time: None,
|
||||
cached_len: None,
|
||||
|
@ -292,11 +292,10 @@ where
|
||||
|
||||
let observers: OT = postcard::from_bytes(&observers_buf)?;
|
||||
// TODO include ExitKind in NewTestcase
|
||||
let fitness = state.is_interesting(&input, &observers, &ExitKind::Ok)?;
|
||||
if fitness > 0
|
||||
&& state
|
||||
.add_if_interesting(&input, fitness, scheduler)?
|
||||
.is_some()
|
||||
let is_interesting = state.is_interesting(&input, &observers, &ExitKind::Ok)?;
|
||||
if state
|
||||
.add_if_interesting(&input, is_interesting, scheduler)?
|
||||
.is_some()
|
||||
{
|
||||
#[cfg(feature = "std")]
|
||||
println!("Added received Testcase");
|
||||
|
@ -19,10 +19,10 @@ use crate::{
|
||||
executors::{
|
||||
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
|
||||
},
|
||||
feedbacks::FeedbacksTuple,
|
||||
feedbacks::Feedback,
|
||||
inputs::{HasTargetBytes, Input},
|
||||
observers::ObserversTuple,
|
||||
state::{HasObjectives, HasSolutions},
|
||||
state::{HasObjective, HasSolutions},
|
||||
Error,
|
||||
};
|
||||
|
||||
@ -158,7 +158,7 @@ where
|
||||
/// * `harness_fn` - the harness, executiong the function
|
||||
/// * `observers` - the observers observing the target during execution
|
||||
/// 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,
|
||||
observers: OT,
|
||||
_state: &mut S,
|
||||
@ -167,19 +167,19 @@ where
|
||||
where
|
||||
EM: EventManager<I, S>,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
|
||||
OF: Feedback<I>,
|
||||
S: HasObjective<OF, I> + HasSolutions<OC, I>,
|
||||
{
|
||||
#[cfg(unix)]
|
||||
unsafe {
|
||||
let data = &mut unix_signal_handler::GLOBAL_STATE;
|
||||
write_volatile(
|
||||
&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(
|
||||
&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)?;
|
||||
@ -190,11 +190,11 @@ where
|
||||
let data = &mut windows_exception_handler::GLOBAL_STATE;
|
||||
write_volatile(
|
||||
&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(
|
||||
// &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)?;
|
||||
@ -234,10 +234,10 @@ mod unix_signal_handler {
|
||||
corpus::{Corpus, Testcase},
|
||||
events::{Event, EventManager},
|
||||
executors::ExitKind,
|
||||
feedbacks::FeedbacksTuple,
|
||||
feedbacks::Feedback,
|
||||
inputs::{HasTargetBytes, Input},
|
||||
observers::ObserversTuple,
|
||||
state::{HasObjectives, HasSolutions},
|
||||
state::{HasObjective, HasSolutions},
|
||||
};
|
||||
|
||||
// TODO merge GLOBAL_STATE with the Windows one
|
||||
@ -308,7 +308,7 @@ mod unix_signal_handler {
|
||||
}
|
||||
|
||||
#[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,
|
||||
_info: siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
@ -317,8 +317,8 @@ mod unix_signal_handler {
|
||||
EM: EventManager<I, S>,
|
||||
OT: ObserversTuple,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
|
||||
OF: Feedback<I>,
|
||||
S: HasObjective<OF, I> + HasSolutions<OC, I>,
|
||||
I: Input + HasTargetBytes,
|
||||
{
|
||||
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();
|
||||
data.current_input_ptr = ptr::null();
|
||||
|
||||
let obj_fitness = state
|
||||
.objectives_mut()
|
||||
.is_interesting_all(&input, observers, &ExitKind::Timeout)
|
||||
.expect("In timeout handler objectives failure.");
|
||||
if obj_fitness > 0 {
|
||||
let interesting = state
|
||||
.objective_mut()
|
||||
.is_interesting(&input, observers, &ExitKind::Timeout)
|
||||
.expect("In timeout handler objective failure.");
|
||||
if interesting {
|
||||
state
|
||||
.solutions_mut()
|
||||
.add(Testcase::new(input.clone()))
|
||||
@ -374,7 +374,7 @@ mod unix_signal_handler {
|
||||
/// Will be used for signal handling.
|
||||
/// It will store the current State to shmem, then exit.
|
||||
#[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,
|
||||
_info: siginfo_t,
|
||||
_context: &mut ucontext_t,
|
||||
@ -383,8 +383,8 @@ mod unix_signal_handler {
|
||||
EM: EventManager<I, S>,
|
||||
OT: ObserversTuple,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
|
||||
OF: Feedback<I>,
|
||||
S: HasObjective<OF, I> + HasSolutions<OC, I>,
|
||||
I: Input + HasTargetBytes,
|
||||
{
|
||||
#[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.
|
||||
data.current_input_ptr = ptr::null();
|
||||
|
||||
let obj_fitness = state
|
||||
.objectives_mut()
|
||||
.is_interesting_all(&input, observers, &ExitKind::Crash)
|
||||
.expect("In crash handler objectives failure.");
|
||||
if obj_fitness > 0 {
|
||||
let interesting = state
|
||||
.objective_mut()
|
||||
.is_interesting(&input, observers, &ExitKind::Crash)
|
||||
.expect("In crash handler objective failure.");
|
||||
if interesting {
|
||||
let new_input = input.clone();
|
||||
state
|
||||
.solutions_mut()
|
||||
@ -528,10 +528,10 @@ mod windows_exception_handler {
|
||||
corpus::{Corpus, Testcase},
|
||||
events::{Event, EventManager},
|
||||
executors::ExitKind,
|
||||
feedbacks::FeedbacksTuple,
|
||||
feedbacks::Feedback,
|
||||
inputs::{HasTargetBytes, Input},
|
||||
observers::ObserversTuple,
|
||||
state::{HasObjectives, HasSolutions},
|
||||
state::{HasObjective, HasSolutions},
|
||||
};
|
||||
|
||||
/// 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,
|
||||
exception_pointers: *mut EXCEPTION_POINTERS,
|
||||
data: &mut InProcessExecutorHandlerData,
|
||||
@ -590,8 +590,8 @@ mod windows_exception_handler {
|
||||
EM: EventManager<I, S>,
|
||||
OT: ObserversTuple,
|
||||
OC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
S: HasObjectives<OFT, I> + HasSolutions<OC, I>,
|
||||
OF: Feedback<I>,
|
||||
S: HasObjective<OF, I> + HasSolutions<OC, I>,
|
||||
I: Input + HasTargetBytes,
|
||||
{
|
||||
#[cfg(feature = "std")]
|
||||
@ -610,11 +610,11 @@ mod windows_exception_handler {
|
||||
// Make sure we don't crash in the crash handler forever.
|
||||
data.current_input_ptr = ptr::null();
|
||||
|
||||
let obj_fitness = state
|
||||
.objectives_mut()
|
||||
.is_interesting_all(&input, observers, &ExitKind::Crash)
|
||||
.expect("In crash handler objectives failure.");
|
||||
if obj_fitness > 0 {
|
||||
let interesting = state
|
||||
.objective_mut()
|
||||
.is_interesting(&input, observers, &ExitKind::Crash)
|
||||
.expect("In crash handler objective failure.");
|
||||
if interesting {
|
||||
let new_input = input.clone();
|
||||
state
|
||||
.solutions_mut()
|
||||
|
@ -139,11 +139,11 @@ where
|
||||
_input: &I,
|
||||
observers: &OT,
|
||||
_exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
let mut interesting = 0;
|
||||
let mut interesting = false;
|
||||
// TODO optimize
|
||||
let observer = observers.match_name_type::<O>(&self.name).unwrap();
|
||||
let size = observer.usable_count();
|
||||
@ -157,7 +157,7 @@ where
|
||||
let reduced = R::reduce(history, item);
|
||||
if history != reduced {
|
||||
self.history_map[i] = reduced;
|
||||
interesting += 1;
|
||||
interesting = true;
|
||||
}
|
||||
}
|
||||
} else if self.indexes.is_some() && self.novelties.is_none() {
|
||||
@ -171,7 +171,7 @@ where
|
||||
let reduced = R::reduce(history, item);
|
||||
if history != reduced {
|
||||
self.history_map[i] = reduced;
|
||||
interesting += 1;
|
||||
interesting = true;
|
||||
}
|
||||
}
|
||||
} else if self.indexes.is_none() && self.novelties.is_some() {
|
||||
@ -182,7 +182,7 @@ where
|
||||
let reduced = R::reduce(history, item);
|
||||
if history != reduced {
|
||||
self.history_map[i] = reduced;
|
||||
interesting += 1;
|
||||
interesting = true;
|
||||
self.novelties.as_mut().unwrap().push(i);
|
||||
}
|
||||
}
|
||||
@ -197,7 +197,7 @@ where
|
||||
let reduced = R::reduce(history, item);
|
||||
if history != reduced {
|
||||
self.history_map[i] = reduced;
|
||||
interesting += 1;
|
||||
interesting = true;
|
||||
self.novelties.as_mut().unwrap().push(i);
|
||||
}
|
||||
}
|
||||
|
@ -15,12 +15,12 @@ use crate::{
|
||||
Error,
|
||||
};
|
||||
|
||||
use core::time::Duration;
|
||||
use core::{marker::PhantomData, time::Duration};
|
||||
|
||||
/// Feedbacks evaluate the observers.
|
||||
/// Basically, they reduce the information provided by an observer to a value,
|
||||
/// 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
|
||||
I: Input,
|
||||
{
|
||||
@ -30,7 +30,7 @@ where
|
||||
input: &I,
|
||||
observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
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
|
||||
A: Feedback<I>,
|
||||
B: Feedback<I>,
|
||||
I: Input,
|
||||
{
|
||||
/// Get the total interestingness value from all feedbacks
|
||||
fn is_interesting_all<OT>(
|
||||
pub first: A,
|
||||
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,
|
||||
input: &I,
|
||||
observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<u32, 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>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
Ok(0)
|
||||
}
|
||||
|
||||
#[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(())
|
||||
let a = self.first.is_interesting(input, observers, exit_kind)?;
|
||||
let b = self.second.is_interesting(input, observers, exit_kind)?;
|
||||
Ok(a && b)
|
||||
}
|
||||
}
|
||||
|
||||
impl<Head, Tail, I> FeedbacksTuple<I> for (Head, Tail)
|
||||
impl<A, B, I> Named for AndFeedback<A, B, I>
|
||||
where
|
||||
Head: Feedback<I>,
|
||||
Tail: FeedbacksTuple<I>,
|
||||
A: Feedback<I>,
|
||||
B: Feedback<I>,
|
||||
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,
|
||||
input: &I,
|
||||
observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
Ok(self.0.is_interesting(input, observers, exit_kind)?
|
||||
+ self.1.is_interesting_all(input, observers, exit_kind)?)
|
||||
let a = self.first.is_interesting(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> {
|
||||
self.0.append_metadata(testcase)?;
|
||||
self.1.append_metadata_all(testcase)
|
||||
impl<A, B, I> Named for OrFeedback<A, B, I>
|
||||
where
|
||||
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> {
|
||||
self.0.discard_metadata(input)?;
|
||||
self.1.discard_metadata_all(input)
|
||||
impl<A, B, I> OrFeedback<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 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,
|
||||
_observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
if let ExitKind::Crash = exit_kind {
|
||||
Ok(1)
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(0)
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -177,14 +339,14 @@ where
|
||||
_input: &I,
|
||||
_observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
if let ExitKind::Timeout = exit_kind {
|
||||
Ok(1)
|
||||
Ok(true)
|
||||
} 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
|
||||
/// For this Feedback, the testcase is never interesting (use with an OR)
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
pub struct TimeFeedback {
|
||||
exec_time: Option<Duration>,
|
||||
@ -223,13 +386,13 @@ where
|
||||
_input: &I,
|
||||
observers: &OT,
|
||||
_exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
let observer = observers.match_first_type::<TimeObserver>().unwrap();
|
||||
self.exec_time = *observer.last_runtime();
|
||||
Ok(0)
|
||||
Ok(false)
|
||||
}
|
||||
|
||||
/// Append to the testcase the generated metadata in case of a new corpus item
|
||||
|
@ -15,7 +15,7 @@ use crate::{
|
||||
executors::{
|
||||
Executor, ExitKind, HasExecHooks, HasExecHooksTuple, HasObservers, HasObserversHooks,
|
||||
},
|
||||
feedbacks::FeedbacksTuple,
|
||||
feedbacks::Feedback,
|
||||
generators::Generator,
|
||||
inputs::Input,
|
||||
observers::ObserversTuple,
|
||||
@ -98,30 +98,30 @@ pub trait HasMetadata {
|
||||
}
|
||||
}
|
||||
|
||||
/// Trait for elements offering a feedbacks tuple
|
||||
pub trait HasFeedbacks<FT, I>: Sized
|
||||
/// Trait for elements offering a feedback
|
||||
pub trait HasFeedback<F, I>: Sized
|
||||
where
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
I: Input,
|
||||
{
|
||||
/// The feedbacks tuple
|
||||
fn feedbacks(&self) -> &FT;
|
||||
/// The feedback
|
||||
fn feedback(&self) -> &F;
|
||||
|
||||
/// The feedbacks tuple (mut)
|
||||
fn feedbacks_mut(&mut self) -> &mut FT;
|
||||
/// The feedback (mut)
|
||||
fn feedback_mut(&mut self) -> &mut F;
|
||||
}
|
||||
|
||||
/// Trait for elements offering an objective feedbacks tuple
|
||||
pub trait HasObjectives<FT, I>: Sized
|
||||
/// Trait for elements offering an objective feedback tuple
|
||||
pub trait HasObjective<OF, I>: Sized
|
||||
where
|
||||
FT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
I: Input,
|
||||
{
|
||||
/// The objective feedbacks tuple
|
||||
fn objectives(&self) -> &FT;
|
||||
/// The objective feedback
|
||||
fn objective(&self) -> &OF;
|
||||
|
||||
/// The objective feedbacks tuple (mut)
|
||||
fn objectives_mut(&mut self) -> &mut FT;
|
||||
/// The objective feedback (mut)
|
||||
fn objective_mut(&mut self) -> &mut OF;
|
||||
}
|
||||
|
||||
/// Trait for the execution counter
|
||||
@ -153,7 +153,7 @@ where
|
||||
input: &I,
|
||||
observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
OT: ObserversTuple;
|
||||
|
||||
@ -161,7 +161,7 @@ where
|
||||
fn add_if_interesting<CS>(
|
||||
&mut self,
|
||||
input: &I,
|
||||
fitness: u32,
|
||||
is_interesting: bool,
|
||||
scheduler: &CS,
|
||||
) -> Result<Option<usize>, Error>
|
||||
where
|
||||
@ -169,7 +169,7 @@ where
|
||||
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
|
||||
where
|
||||
I: Input,
|
||||
@ -181,7 +181,7 @@ where
|
||||
executor: &mut E,
|
||||
manager: &mut EM,
|
||||
scheduler: &CS,
|
||||
) -> Result<(u32, Option<usize>), Error>
|
||||
) -> Result<(bool, Option<usize>), Error>
|
||||
where
|
||||
E: Executor<I>
|
||||
+ HasObservers<OT>
|
||||
@ -194,15 +194,15 @@ where
|
||||
|
||||
/// The state a fuzz run.
|
||||
#[derive(Serialize, Deserialize, Clone, Debug)]
|
||||
#[serde(bound = "FT: serde::de::DeserializeOwned")]
|
||||
pub struct State<C, FT, I, OFT, R, SC>
|
||||
#[serde(bound = "F: serde::de::DeserializeOwned")]
|
||||
pub struct State<C, F, I, OF, R, SC>
|
||||
where
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// RNG instance
|
||||
rand: R,
|
||||
@ -213,11 +213,11 @@ where
|
||||
/// The corpus
|
||||
corpus: C,
|
||||
/// Feedbacks used to evaluate an input
|
||||
feedbacks: FT,
|
||||
feedback: F,
|
||||
// Solutions corpus
|
||||
solutions: SC,
|
||||
/// Objective Feedbacks
|
||||
objectives: OFT,
|
||||
objective: OF,
|
||||
/// Metadata stored for this state by one of the components
|
||||
metadata: SerdeAnyMap,
|
||||
/// MaxSize testcase size for mutators that appreciate it
|
||||
@ -226,14 +226,14 @@ where
|
||||
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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// The rand instance
|
||||
#[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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// Returns the corpus
|
||||
#[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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// Returns the solutions corpus
|
||||
#[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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// Get all the metadata into an HashMap
|
||||
#[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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// The feedbacks tuple
|
||||
/// The feedback
|
||||
#[inline]
|
||||
fn feedbacks(&self) -> &FT {
|
||||
&self.feedbacks
|
||||
fn feedback(&self) -> &F {
|
||||
&self.feedback
|
||||
}
|
||||
|
||||
/// The feedbacks tuple (mut)
|
||||
/// The feedback (mut)
|
||||
#[inline]
|
||||
fn feedbacks_mut(&mut self) -> &mut FT {
|
||||
&mut self.feedbacks
|
||||
fn feedback_mut(&mut self) -> &mut F {
|
||||
&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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// The objective feedbacks tuple
|
||||
/// The objective feedback
|
||||
#[inline]
|
||||
fn objectives(&self) -> &OFT {
|
||||
&self.objectives
|
||||
fn objective(&self) -> &OF {
|
||||
&self.objective
|
||||
}
|
||||
|
||||
/// The objective feedbacks tuple (mut)
|
||||
/// The objective feedback (mut)
|
||||
#[inline]
|
||||
fn objectives_mut(&mut self) -> &mut OFT {
|
||||
&mut self.objectives
|
||||
fn objective_mut(&mut self) -> &mut OF {
|
||||
&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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// The executions counter
|
||||
#[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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
fn max_size(&self) -> usize {
|
||||
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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// The starting time
|
||||
#[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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// Evaluate if a set of observation channels has an interesting state
|
||||
fn is_interesting<OT>(
|
||||
@ -435,12 +435,12 @@ where
|
||||
input: &I,
|
||||
observers: &OT,
|
||||
exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error>
|
||||
) -> Result<bool, Error>
|
||||
where
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
self.feedbacks_mut()
|
||||
.is_interesting_all(input, observers, exit_kind)
|
||||
self.feedback_mut()
|
||||
.is_interesting(input, observers, exit_kind)
|
||||
}
|
||||
|
||||
/// Adds this input to the corpus, if it's intersting, and return the index
|
||||
@ -448,33 +448,33 @@ where
|
||||
fn add_if_interesting<CS>(
|
||||
&mut self,
|
||||
input: &I,
|
||||
fitness: u32,
|
||||
is_interesting: bool,
|
||||
scheduler: &CS,
|
||||
) -> Result<Option<usize>, Error>
|
||||
where
|
||||
CS: CorpusScheduler<I, Self>,
|
||||
{
|
||||
if fitness > 0 {
|
||||
let mut testcase = Testcase::with_fitness(input.clone(), fitness);
|
||||
self.feedbacks_mut().append_metadata_all(&mut testcase)?;
|
||||
if is_interesting {
|
||||
let mut testcase = Testcase::new(input.clone());
|
||||
self.feedback_mut().append_metadata(&mut testcase)?;
|
||||
let idx = self.corpus.add(testcase)?;
|
||||
scheduler.on_add(self, idx)?;
|
||||
Ok(Some(idx))
|
||||
} else {
|
||||
self.feedbacks_mut().discard_metadata_all(&input)?;
|
||||
self.feedback_mut().discard_metadata(&input)?;
|
||||
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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<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
|
||||
#[inline]
|
||||
@ -485,7 +485,7 @@ where
|
||||
executor: &mut E,
|
||||
manager: &mut EM,
|
||||
scheduler: &CS,
|
||||
) -> Result<(u32, Option<usize>), Error>
|
||||
) -> Result<(bool, Option<usize>), Error>
|
||||
where
|
||||
E: Executor<I>
|
||||
+ HasObservers<OT>
|
||||
@ -496,19 +496,19 @@ where
|
||||
EM: EventManager<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();
|
||||
|
||||
if is_solution {
|
||||
// If the input is a solution, add it to the respective corpus
|
||||
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)?;
|
||||
} 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() {
|
||||
let observers_buf = manager.serialize_observers(observers)?;
|
||||
manager.fire(
|
||||
@ -524,18 +524,18 @@ where
|
||||
)?;
|
||||
}
|
||||
|
||||
Ok((fitness, corpus_idx))
|
||||
Ok((is_interesting, corpus_idx))
|
||||
}
|
||||
}
|
||||
|
||||
#[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
|
||||
C: Corpus<BytesInput>,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<BytesInput>,
|
||||
F: Feedback<BytesInput>,
|
||||
SC: Corpus<BytesInput>,
|
||||
OFT: FeedbacksTuple<BytesInput>,
|
||||
OF: Feedback<BytesInput>,
|
||||
{
|
||||
pub fn load_from_directory<CS, E, OT, EM>(
|
||||
&mut self,
|
||||
@ -568,9 +568,10 @@ where
|
||||
println!("Loading file {:?} ...", &path);
|
||||
let bytes = fs::read(&path)?;
|
||||
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
|
||||
.add_if_interesting(&input, fitness, scheduler)?
|
||||
.add_if_interesting(&input, is_interesting, scheduler)?
|
||||
.is_none()
|
||||
{
|
||||
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
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
F: Feedback<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
OF: Feedback<I>,
|
||||
{
|
||||
/// Runs the input and triggers observers and feedback
|
||||
pub fn execute_input<E, EM, OT>(
|
||||
@ -633,7 +634,7 @@ where
|
||||
input: &I,
|
||||
executor: &mut E,
|
||||
event_mgr: &mut EM,
|
||||
) -> Result<(u32, bool), Error>
|
||||
) -> Result<(bool, bool), Error>
|
||||
where
|
||||
E: Executor<I>
|
||||
+ HasObservers<OT>
|
||||
@ -653,15 +654,14 @@ where
|
||||
executor.post_exec_observers(self, event_mgr, input)?;
|
||||
|
||||
let observers = executor.observers();
|
||||
let fitness = self
|
||||
.feedbacks_mut()
|
||||
.is_interesting_all(&input, observers, &exit_kind)?;
|
||||
let is_interesting = self
|
||||
.feedback_mut()
|
||||
.is_interesting(&input, observers, &exit_kind)?;
|
||||
|
||||
let is_solution = self
|
||||
.objectives_mut()
|
||||
.is_interesting_all(&input, observers, &exit_kind)?
|
||||
> 0;
|
||||
Ok((fitness, is_solution))
|
||||
.objective_mut()
|
||||
.is_interesting(&input, observers, &exit_kind)?;
|
||||
Ok((is_interesting, is_solution))
|
||||
}
|
||||
|
||||
pub fn generate_initial_inputs<CS, G, E, OT, EM>(
|
||||
@ -686,8 +686,8 @@ where
|
||||
let mut added = 0;
|
||||
for _ in 0..num {
|
||||
let input = generator.generate(self.rand_mut())?;
|
||||
let (fitness, _) = self.evaluate_input(input, executor, manager, scheduler)?;
|
||||
if fitness > 0 {
|
||||
let (is_interesting, _) = self.evaluate_input(input, executor, manager, scheduler)?;
|
||||
if is_interesting {
|
||||
added += 1;
|
||||
}
|
||||
}
|
||||
@ -703,16 +703,16 @@ where
|
||||
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 {
|
||||
rand,
|
||||
executions: 0,
|
||||
start_time: Duration::from_millis(0),
|
||||
metadata: SerdeAnyMap::default(),
|
||||
corpus,
|
||||
feedbacks,
|
||||
feedback,
|
||||
solutions,
|
||||
objectives,
|
||||
objective,
|
||||
max_size: DEFAULT_MAX_SIZE,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
|
@ -1,6 +1,6 @@
|
||||
[package]
|
||||
name = "libafl_frida"
|
||||
version = "0.1.0"
|
||||
version = "0.2.0"
|
||||
authors = ["s1341 <github@shmarya.net>"]
|
||||
description = "Frida backend library for LibAFL"
|
||||
documentation = "https://docs.rs/libafl_frida"
|
||||
@ -13,7 +13,7 @@ edition = "2018"
|
||||
cc = { version = "1.0", features = ["parallel"] }
|
||||
|
||||
[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" }
|
||||
nix = "0.20.0"
|
||||
libc = "0.2.92"
|
||||
|
@ -1687,18 +1687,18 @@ where
|
||||
_input: &I,
|
||||
observers: &OT,
|
||||
_exit_kind: &ExitKind,
|
||||
) -> Result<u32, Error> {
|
||||
) -> Result<bool, Error> {
|
||||
let observer = observers
|
||||
.match_first_type::<AsanErrorsObserver>()
|
||||
.expect("An AsanErrorsFeedback needs an AsanErrorsObserver");
|
||||
match observer.errors() {
|
||||
None => Ok(0),
|
||||
None => Ok(false),
|
||||
Some(errors) => {
|
||||
if !errors.errors.is_empty() {
|
||||
self.errors = Some(errors.clone());
|
||||
Ok(1)
|
||||
Ok(true)
|
||||
} else {
|
||||
Ok(0)
|
||||
Ok(false)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user