Configurations (#162)

* print sender id

* storing sender id to env

* executor in llmp handle_in_client

* compile the lib

* compiling generic_inmemory

* fix forkserver

* adapt from fuzzers

* instrospection fix

* exitkind in NewTestcase

* fix libafl_frida

* fix firda_libpng

* send conf with Newtestcase event

* bump to 0.4.0

* no_std fix

* fmt

* fix libfuzzer_libmozjpeg

Co-authored-by: Dominik Maier <domenukk@gmail.com>
This commit is contained in:
Andrea Fioraldi 2021-06-22 15:04:14 +02:00 committed by GitHub
parent 5c5a1cf2e9
commit bdb5efbf5b
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
46 changed files with 668 additions and 864 deletions

View File

@ -1,6 +1,6 @@
[package] [package]
name = "baby_fuzzer" name = "baby_fuzzer"
version = "0.3.2" version = "0.4.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

@ -1,6 +1,6 @@
[package] [package]
name = "forkserver_simple" name = "forkserver_simple"
version = "0.1.0" version = "0.4.0"
authors = ["tokatoka <tokazerkje@outlook.com>"] authors = ["tokatoka <tokazerkje@outlook.com>"]
edition = "2018" edition = "2018"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "frida_libpng" name = "frida_libpng"
version = "0.3.2" version = "0.4.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"
@ -24,8 +24,8 @@ which = "4.1"
libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]} libafl = { path = "../../libafl/", features = [ "std", "llmp_compression", "llmp_bind_public" ] } #, "llmp_small_maps", "llmp_debug"]}
capstone = "0.8.0" capstone = "0.8.0"
frida-gum = { version = "0.5.2", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] } frida-gum = { version = "0.5.2", features = [ "auto-download", "backtrace", "event-sink", "invocation-listener"] }
libafl_frida = { path = "../../libafl_frida", version = "0.3.2", features = ["cmplog"] } libafl_frida = { path = "../../libafl_frida", version = "0.4.0", features = ["cmplog"] }
libafl_targets = { path = "../../libafl_targets", version = "0.3.2" , features = ["sancov_cmplog"] } libafl_targets = { path = "../../libafl_targets", version = "0.4.0" , features = ["sancov_cmplog"] }
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

@ -20,8 +20,8 @@ use libafl::{
QueueCorpusScheduler, QueueCorpusScheduler,
}, },
executors::{ executors::{
inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, inprocess::InProcessExecutor, timeout::TimeoutExecutor, Executor, ExitKind, HasObservers,
HasExecHooksTuple, HasObservers, HasObserversHooks, ShadowExecutor, ShadowExecutor,
}, },
feedback_or, feedback_or,
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
@ -65,7 +65,7 @@ where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&I) -> ExitKind, H: FnMut(&I) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
base: TimeoutExecutor<InProcessExecutor<'a, H, I, OT, S>>, base: TimeoutExecutor<InProcessExecutor<'a, H, I, OT, S>>,
/// Frida's dynamic rewriting engine /// Frida's dynamic rewriting engine
@ -82,7 +82,7 @@ where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&I) -> ExitKind, H: FnMut(&I) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
/// Instruct the target about the input and run /// Instruct the target about the input and run
#[inline] #[inline]
@ -120,13 +120,13 @@ where
} }
} }
impl<'a, 'b, 'c, FH, H, I, OT, S> HasObservers<OT> impl<'a, 'b, 'c, FH, H, I, OT, S> HasObservers<I, OT, S>
for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT, S> for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT, S>
where where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&I) -> ExitKind, H: FnMut(&I) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -139,22 +139,12 @@ where
} }
} }
impl<'a, 'b, 'c, EM, FH, H, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z>
for FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT, S>
where
FH: FridaHelper<'b>,
H: FnMut(&I) -> ExitKind,
I: Input + HasTargetBytes,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
}
impl<'a, 'b, 'c, FH, H, I, OT, S> FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT, S> impl<'a, 'b, 'c, FH, H, I, OT, S> FridaInProcessExecutor<'a, 'b, 'c, FH, H, I, OT, S>
where where
FH: FridaHelper<'b>, FH: FridaHelper<'b>,
H: FnMut(&I) -> ExitKind, H: FnMut(&I) -> ExitKind,
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
pub fn new( pub fn new(
gum: &'a Gum, gum: &'a Gum,
@ -205,6 +195,12 @@ pub fn main() {
.required(true) .required(true)
.index(3), .index(3),
) )
.arg(
Arg::with_name("configuration")
.required(false)
.value_name("CONF")
.takes_value(true),
)
.arg( .arg(
Arg::with_name("output") Arg::with_name("output")
.short("o") .short("o")
@ -252,6 +248,10 @@ pub fn main() {
&cores, &cores,
matches.value_of("output"), matches.value_of("output"),
broker_addr, broker_addr,
matches
.value_of("configuration")
.unwrap_or("default launcher")
.to_string(),
) )
.expect("An error occurred while fuzzing"); .expect("An error occurred while fuzzing");
} }
@ -269,6 +269,7 @@ fn fuzz(
_cores: &[usize], _cores: &[usize],
_stdout_file: Option<&str>, _stdout_file: Option<&str>,
_broker_addr: Option<SocketAddr>, _broker_addr: Option<SocketAddr>,
_configuration: String,
) -> Result<(), ()> { ) -> Result<(), ()> {
todo!("Example not supported on Windows"); todo!("Example not supported on Windows");
} }
@ -286,6 +287,7 @@ unsafe fn fuzz(
cores: &[usize], cores: &[usize],
stdout_file: Option<&str>, stdout_file: Option<&str>,
broker_addr: Option<SocketAddr>, broker_addr: Option<SocketAddr>,
configuration: String,
) -> Result<(), Error> { ) -> Result<(), Error> {
// 'While the stats are state, they are usually used in the broker - which is likely never restarted // 'While the stats are state, they are usually used in the broker - which is likely never restarted
let stats = MultiStats::new(|s| println!("{}", s)); let stats = MultiStats::new(|s| println!("{}", s));
@ -443,6 +445,7 @@ unsafe fn fuzz(
}; };
Launcher::builder() Launcher::builder()
.configuration(configuration)
.shmem_provider(shmem_provider) .shmem_provider(shmem_provider)
.stats(stats) .stats(stats)
.run_client(&mut run_client) .run_client(&mut run_client)

View File

@ -1,6 +1,6 @@
[package] [package]
name = "fuzzbench" name = "fuzzbench"
version = "0.3.2" version = "0.4.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

@ -1,6 +1,6 @@
[package] [package]
name = "generic_inmemory" name = "generic_inmemory"
version = "0.3.2" version = "0.4.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

@ -3,7 +3,8 @@
int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) { int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size) {
if (Size >= 8 && *(uint32_t*)Data == 0xaabbccdd) if (Size >= 8 && *(uint32_t*)Data == 0xaabbccdd)
abort(); return 1;
return 0;
} }
/* /*

View File

@ -233,6 +233,7 @@ pub fn main() {
Launcher::builder() Launcher::builder()
.shmem_provider(shmem_provider) .shmem_provider(shmem_provider)
.configuration("launcher default".into())
.stats(stats) .stats(stats)
.run_client(&mut run_client) .run_client(&mut run_client)
.cores(&cores) .cores(&cores)

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libfuzzer_libmozjpeg" name = "libfuzzer_libmozjpeg"
version = "0.3.2" version = "0.4.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

@ -60,7 +60,8 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
// The restarting state will spawn the same process again as child, then restarted it each time it crashes. // The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) = let (state, mut restarting_mgr) =
setup_restarting_mgr_std(stats, broker_port).expect("Failed to setup the restarter"); setup_restarting_mgr_std(stats, broker_port, "default".into())
.expect("Failed to setup the restarter");
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libfuzzer_libpng" name = "libfuzzer_libpng"
version = "0.3.2" version = "0.4.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

@ -54,17 +54,18 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let stats = MultiStats::new(|s| println!("{}", s)); let stats = MultiStats::new(|s| println!("{}", s));
// The restarting state will spawn the same process again as child, then restarted it each time it crashes. // The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) = match setup_restarting_mgr_std(stats, broker_port) { let (state, mut restarting_mgr) =
Ok(res) => res, match setup_restarting_mgr_std(stats, broker_port, "default".into()) {
Err(err) => match err { Ok(res) => res,
Error::ShuttingDown => { Err(err) => match err {
return Ok(()); Error::ShuttingDown => {
} return Ok(());
_ => { }
panic!("Failed to setup the restarter: {}", err); _ => {
} panic!("Failed to setup the restarter: {}", err);
}, }
}; },
};
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libfuzzer_libpng_launcher" name = "libfuzzer_libpng_launcher"
version = "0.3.2" version = "0.4.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

@ -167,6 +167,7 @@ pub fn main() {
Launcher::builder() Launcher::builder()
.shmem_provider(shmem_provider) .shmem_provider(shmem_provider)
.configuration("launcher default".into())
.stats(stats) .stats(stats)
.run_client(&mut run_client) .run_client(&mut run_client)
.cores(&cores) .cores(&cores)

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libfuzzer_reachability" name = "libfuzzer_reachability"
version = "0.3.2" version = "0.4.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

@ -51,17 +51,18 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let stats = SimpleStats::new(|s| println!("{}", s)); let stats = SimpleStats::new(|s| println!("{}", s));
// The restarting state will spawn the same process again as child, then restarted it each time it crashes. // The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) = match setup_restarting_mgr_std(stats, broker_port) { let (state, mut restarting_mgr) =
Ok(res) => res, match setup_restarting_mgr_std(stats, broker_port, "default".into()) {
Err(err) => match err { Ok(res) => res,
Error::ShuttingDown => { Err(err) => match err {
return Ok(()); Error::ShuttingDown => {
} return Ok(());
_ => { }
panic!("Failed to setup the restarter: {}", err); _ => {
} panic!("Failed to setup the restarter: {}", err);
}, }
}; },
};
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] };

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libfuzzer_stb_image" name = "libfuzzer_stb_image"
version = "0.3.2" version = "0.4.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

@ -52,17 +52,18 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
let stats = MultiStats::new(|s| println!("{}", s)); let stats = MultiStats::new(|s| println!("{}", s));
// The restarting state will spawn the same process again as child, then restarted it each time it crashes. // The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) = match setup_restarting_mgr_std(stats, broker_port) { let (state, mut restarting_mgr) =
Ok(res) => res, match setup_restarting_mgr_std(stats, broker_port, "default".into()) {
Err(err) => match err { Ok(res) => res,
Error::ShuttingDown => { Err(err) => match err {
return Ok(()); Error::ShuttingDown => {
} return Ok(());
_ => { }
panic!("Failed to setup the restarter: {}", err); _ => {
} panic!("Failed to setup the restarter: {}", err);
}, }
}; },
};
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
// We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges) // We don't use the hitcounts (see the Cargo.toml, we use pcguard_edges)

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libafl" name = "libafl"
version = "0.3.2" version = "0.4.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"
@ -53,7 +53,7 @@ path = "./examples/llmp_test/main.rs"
required-features = ["std"] required-features = ["std"]
[dependencies] [dependencies]
libafl_derive = { optional = true, path = "../libafl_derive", version = "0.3.2" } libafl_derive = { optional = true, path = "../libafl_derive", version = "0.4.0" }
tuple_list = "0.1.2" tuple_list = "0.1.2"
hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible hashbrown = { version = "0.9", features = ["serde", "ahash-compile-time-rng"] } # A faster hashmap, nostd compatible
num = "0.4.0" num = "0.4.0"

View File

@ -46,13 +46,15 @@ where
I: Input, I: Input,
ST: Stats, ST: Stats,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
S: DeserializeOwned, S: DeserializeOwned,
{ {
/// The ShmemProvider to use /// The ShmemProvider to use
shmem_provider: SP, shmem_provider: SP,
/// The stats instance to use /// The stats instance to use
stats: ST, stats: ST,
/// The configuration
configuration: String,
/// The 'main' function to run for each client forked. This probably shouldn't return /// The 'main' function to run for each client forked. This probably shouldn't return
run_client: LauncherClientFnRef<'a, I, OT, S, SP>, run_client: LauncherClientFnRef<'a, I, OT, S, SP>,
/// The broker port to use (or to attach to, in case [`Self::with_broker`] is `false`) /// The broker port to use (or to attach to, in case [`Self::with_broker`] is `false`)
@ -79,7 +81,7 @@ where
impl<'a, I, OT, S, SP, ST> Launcher<'a, I, OT, S, SP, ST> impl<'a, I, OT, S, SP, ST> Launcher<'a, I, OT, S, SP, ST>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
ST: Stats + Clone, ST: Stats + Clone,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
S: DeserializeOwned, S: DeserializeOwned,
@ -126,6 +128,7 @@ where
.kind(ManagerKind::Client { .kind(ManagerKind::Client {
cpu_core: Some(*bind_to), cpu_core: Some(*bind_to),
}) })
.configuration(self.configuration.clone())
.build() .build()
.launch()?; .launch()?;
@ -140,13 +143,14 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
println!("I am broker!!."); println!("I am broker!!.");
// TODO we don't want always a broker here, thing about using different laucher process to spawn different configurations // TODO we don't want always a broker here, think about using different laucher process to spawn different configurations
RestartingMgr::<I, OT, S, SP, ST>::builder() RestartingMgr::<I, OT, S, SP, ST>::builder()
.shmem_provider(self.shmem_provider.clone()) .shmem_provider(self.shmem_provider.clone())
.stats(Some(self.stats.clone())) .stats(Some(self.stats.clone()))
.broker_port(self.broker_port) .broker_port(self.broker_port)
.kind(ManagerKind::Broker) .kind(ManagerKind::Broker)
.remote_broker_addr(self.remote_broker_addr) .remote_broker_addr(self.remote_broker_addr)
.configuration(self.configuration.clone())
.build() .build()
.launch()?; .launch()?;
@ -191,6 +195,7 @@ where
id: core_conf.parse()?, id: core_conf.parse()?,
}), }),
}) })
.configuration(self.configuration.clone())
.build() .build()
.launch()?; .launch()?;
@ -246,6 +251,7 @@ where
.broker_port(self.broker_port) .broker_port(self.broker_port)
.kind(ManagerKind::Broker) .kind(ManagerKind::Broker)
.remote_broker_addr(self.remote_broker_addr) .remote_broker_addr(self.remote_broker_addr)
.configuration(self.configuration.clone())
.build() .build()
.launch()?; .launch()?;

View File

@ -475,7 +475,7 @@ unsafe fn _llmp_next_msg_ptr(last_msg: *const LlmpMsg) -> *mut LlmpMsg {
/// May be used to restore the map by id. /// May be used to restore the map by id.
#[derive(Copy, Clone, Debug, Serialize, Deserialize)] #[derive(Copy, Clone, Debug, Serialize, Deserialize)]
pub struct LlmpDescription { pub struct LlmpDescription {
/// Info about the SharedMap in use /// Info about the ShredMap in use
shmem: ShMemDescription, shmem: ShMemDescription,
/// The last message sent or received, depnding on page type /// The last message sent or received, depnding on page type
last_message_offset: Option<u64>, last_message_offset: Option<u64>,
@ -751,15 +751,36 @@ where
self.last_msg_sent = ptr::null_mut(); self.last_msg_sent = ptr::null_mut();
} }
/// Reads the stored sender / client id for the given `env_name` (by appending `_CLIENT_ID`).
/// If the content of the env is `_NULL`, returns [`Option::None`].
#[cfg(feature = "std")]
#[inline]
fn client_id_from_env(env_name: &str) -> Result<Option<ClientId>, Error> {
let client_id_str = env::var(&format!("{}_CLIENT_ID", env_name))?;
Ok(if client_id_str == _NULL_ENV_STR {
None
} else {
Some(client_id_str.parse()?)
})
}
/// Writes the `id` to an env var
#[cfg(feature = "std")]
fn client_id_to_env(env_name: &str, id: ClientId) {
env::set_var(&format!("{}_CLIENT_ID", env_name), &format!("{}", id));
}
/// Reattach to a vacant `out_map`, to with a previous sender stored the information in an env before. /// Reattach to a vacant `out_map`, to with a previous sender stored the information in an env before.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn on_existing_from_env(mut shmem_provider: SP, env_name: &str) -> Result<Self, Error> { pub fn on_existing_from_env(mut shmem_provider: SP, env_name: &str) -> Result<Self, Error> {
let msg_sent_offset = msg_offset_from_env(env_name)?; let msg_sent_offset = msg_offset_from_env(env_name)?;
Self::on_existing_map( let mut ret = Self::on_existing_map(
shmem_provider.clone(), shmem_provider.clone(),
shmem_provider.existing_from_env(env_name)?, shmem_provider.existing_from_env(env_name)?,
msg_sent_offset, msg_sent_offset,
) )?;
ret.id = Self::client_id_from_env(env_name)?.unwrap_or_default();
Ok(ret)
} }
/// Store the info to this sender to env. /// Store the info to this sender to env.
@ -768,6 +789,7 @@ where
pub fn to_env(&self, env_name: &str) -> Result<(), Error> { pub fn to_env(&self, env_name: &str) -> Result<(), Error> {
let current_out_map = self.out_maps.last().unwrap(); let current_out_map = self.out_maps.last().unwrap();
current_out_map.shmem.write_to_env(env_name)?; current_out_map.shmem.write_to_env(env_name)?;
Self::client_id_to_env(env_name, self.id);
unsafe { current_out_map.msg_to_env(self.last_msg_sent, env_name) } unsafe { current_out_map.msg_to_env(self.last_msg_sent, env_name) }
} }

View File

@ -1,6 +1,9 @@
//! LLMP-backed event manager for scalable multi-processed fuzzing //! LLMP-backed event manager for scalable multi-processed fuzzing
use alloc::{string::ToString, vec::Vec}; use alloc::{
string::{String, ToString},
vec::Vec,
};
use core::{marker::PhantomData, time::Duration}; use core::{marker::PhantomData, time::Duration};
use core_affinity::CoreId; use core_affinity::CoreId;
use serde::{de::DeserializeOwned, Serialize}; use serde::{de::DeserializeOwned, Serialize};
@ -23,9 +26,8 @@ use crate::{
shmem::ShMemProvider, shmem::ShMemProvider,
}, },
events::{BrokerEventResult, Event, EventFirer, EventManager, EventProcessor, EventRestarter}, events::{BrokerEventResult, Event, EventFirer, EventManager, EventProcessor, EventRestarter},
executors::Executor, executors::{Executor, HasObservers},
executors::ExitKind, fuzzer::{EvaluatorObservers, ExecutionProcessor},
fuzzer::{IfInteresting, IsInteresting},
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
stats::Stats, stats::Stats,
@ -162,6 +164,7 @@ where
Event::NewTestcase { Event::NewTestcase {
input: _, input: _,
client_config: _, client_config: _,
exit_kind: _,
corpus_size, corpus_size,
observers_buf: _, observers_buf: _,
time, time,
@ -245,20 +248,21 @@ where
pub struct LlmpEventManager<I, OT, S, SP> pub struct LlmpEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
llmp: llmp::LlmpClient<SP>, llmp: llmp::LlmpClient<SP>,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor, compressor: GzipCompressor,
configuration: String,
phantom: PhantomData<(I, OT, S)>, phantom: PhantomData<(I, OT, S)>,
} }
impl<I, OT, S, SP> Drop for LlmpEventManager<I, OT, S, SP> impl<I, OT, S, SP> Drop for LlmpEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
/// LLMP clients will have to wait until their pages are mapped by somebody. /// LLMP clients will have to wait until their pages are mapped by somebody.
@ -270,15 +274,16 @@ where
impl<I, OT, S, SP> LlmpEventManager<I, OT, S, SP> impl<I, OT, S, SP> LlmpEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
/// Create a manager from a raw llmp client /// Create a manager from a raw llmp client
pub fn new(llmp: llmp::LlmpClient<SP>) -> Result<Self, Error> { pub fn new(llmp: llmp::LlmpClient<SP>, configuration: String) -> Result<Self, Error> {
Ok(Self { Ok(Self {
llmp, llmp,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
phantom: PhantomData, phantom: PhantomData,
}) })
} }
@ -287,24 +292,32 @@ where
/// If the port is not yet bound, it will act as broker /// If the port is not yet bound, it will act as broker
/// Else, it will act as client. /// Else, it will act as client.
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn new_on_port(shmem_provider: SP, port: u16) -> Result<Self, Error> { pub fn new_on_port(
shmem_provider: SP,
port: u16,
configuration: String,
) -> Result<Self, Error> {
Ok(Self { Ok(Self {
llmp: llmp::LlmpClient::create_attach_to_tcp(shmem_provider, port)?, llmp: llmp::LlmpClient::create_attach_to_tcp(shmem_provider, port)?,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
configuration,
phantom: PhantomData, phantom: PhantomData,
}) })
} }
/// If a client respawns, it may reuse the existing connection, previously stored by [`LlmpClient::to_env()`]. /// If a client respawns, it may reuse the existing connection, previously stored by [`LlmpClient::to_env()`].
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn existing_client_from_env(shmem_provider: SP, env_name: &str) -> Result<Self, Error> { pub fn existing_client_from_env(
shmem_provider: SP,
env_name: &str,
configuration: String,
) -> Result<Self, Error> {
Ok(Self { Ok(Self {
llmp: LlmpClient::on_existing_from_env(shmem_provider, env_name)?, llmp: LlmpClient::on_existing_from_env(shmem_provider, env_name)?,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
// Inserting a nop-stats element here so rust won't complain. configuration,
// In any case, the client won't currently use it.
phantom: PhantomData, phantom: PhantomData,
}) })
} }
@ -318,13 +331,13 @@ where
pub fn existing_client_from_description( pub fn existing_client_from_description(
shmem_provider: SP, shmem_provider: SP,
description: &LlmpClientDescription, description: &LlmpClientDescription,
configuration: String,
) -> Result<Self, Error> { ) -> Result<Self, Error> {
Ok(Self { Ok(Self {
llmp: llmp::LlmpClient::existing_client_from_description(shmem_provider, description)?, llmp: llmp::LlmpClient::existing_client_from_description(shmem_provider, description)?,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor::new(COMPRESS_THRESHOLD), compressor: GzipCompressor::new(COMPRESS_THRESHOLD),
// Inserting a nop-stats element here so rust won't complain. configuration,
// In any case, the client won't currently use it.
phantom: PhantomData, phantom: PhantomData,
}) })
} }
@ -340,40 +353,41 @@ where
fn handle_in_client<E, Z>( fn handle_in_client<E, Z>(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
_executor: &mut E, executor: &mut E,
state: &mut S, state: &mut S,
_sender_id: u32, _sender_id: u32,
event: Event<I>, event: Event<I>,
) -> Result<(), Error> ) -> Result<(), Error>
where where
E: Executor<Self, I, S, Z>, OT: ObserversTuple<I, S>,
Z: IfInteresting<I, S> + IsInteresting<I, OT, S>, E: Executor<Self, I, S, Z> + HasObservers<I, OT, S>,
Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>,
{ {
match event { match event {
Event::NewTestcase { Event::NewTestcase {
input, input,
client_config: _, client_config,
exit_kind,
corpus_size: _, corpus_size: _,
observers_buf, observers_buf,
time: _, time: _,
executions: _, executions: _,
} => { } => {
// TODO: here u should match client_config, if equal to the current one do not re-execute
// we need to pass engine to process() too, TODO
#[cfg(feature = "std")] #[cfg(feature = "std")]
println!("Received new Testcase from {}", _sender_id); println!(
"Received new Testcase from {} ({}) {:?}",
_sender_id, client_config, input
);
let observers: OT = postcard::from_bytes(&observers_buf)?; let res = if client_config == self.configuration {
// TODO include ExitKind in NewTestcase let observers: OT = postcard::from_bytes(&observers_buf)?;
// TODO check for objective too fuzzer.process_execution(state, self, input, &observers, &exit_kind, false)?
let is_interesting = } else {
fuzzer.is_interesting(state, self, &input, &observers, &ExitKind::Ok)?; fuzzer.evaluate_input_with_observers(state, executor, self, input, false)?
if fuzzer };
.add_if_interesting(state, &input, is_interesting)? #[cfg(feature = "std")]
.is_some() if let Some(item) = res.1 {
{ println!("Added received Testcase as item #{}", item);
#[cfg(feature = "std")]
println!("Added received Testcase");
} }
Ok(()) Ok(())
} }
@ -388,7 +402,7 @@ where
impl<I, OT, S, SP> EventFirer<I, S> for LlmpEventManager<I, OT, S, SP> impl<I, OT, S, SP> EventFirer<I, S> for LlmpEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider, SP: ShMemProvider,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
@ -418,12 +432,16 @@ where
self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?;
Ok(()) Ok(())
} }
fn configuration(&self) -> &str {
&self.configuration
}
} }
impl<I, OT, S, SP> EventRestarter<S> for LlmpEventManager<I, OT, S, SP> impl<I, OT, S, SP> EventRestarter<S> for LlmpEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider, SP: ShMemProvider,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
@ -435,21 +453,25 @@ where
} }
} }
impl<E, I, OT, S, SP, Z> EventProcessor<E, S, Z> for LlmpEventManager<I, OT, S, SP> impl<E, I, OT, S, SP, Z> EventProcessor<E, I, S, Z> for LlmpEventManager<I, OT, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
E: Executor<Self, I, S, Z>, E: Executor<Self, I, S, Z> + HasObservers<I, OT, S>,
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
Z: IfInteresting<I, S> + IsInteresting<I, OT, S>, //CE: CustomEvent<I>, Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>, //CE: CustomEvent<I>,
{ {
fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> { fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error> {
// TODO: Get around local event copy by moving handle_in_client // TODO: Get around local event copy by moving handle_in_client
let mut events = vec![]; let mut events = vec![];
let self_id = self.llmp.sender.id;
while let Some((sender_id, tag, _flags, msg)) = self.llmp.recv_buf_with_flags()? { while let Some((sender_id, tag, _flags, msg)) = self.llmp.recv_buf_with_flags()? {
if tag == _LLMP_TAG_EVENT_TO_BROKER { if tag == _LLMP_TAG_EVENT_TO_BROKER {
panic!("EVENT_TO_BROKER parcel should not have arrived in the client!"); panic!("EVENT_TO_BROKER parcel should not have arrived in the client!");
} }
if sender_id == self_id {
continue;
}
#[cfg(not(feature = "llmp_compression"))] #[cfg(not(feature = "llmp_compression"))]
let event_bytes = msg; let event_bytes = msg;
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
@ -475,10 +497,10 @@ where
impl<E, I, OT, S, SP, Z> EventManager<E, I, S, Z> for LlmpEventManager<I, OT, S, SP> impl<E, I, OT, S, SP, Z> EventManager<E, I, S, Z> for LlmpEventManager<I, OT, S, SP>
where where
SP: ShMemProvider, SP: ShMemProvider,
E: Executor<Self, I, S, Z>, E: Executor<Self, I, S, Z> + HasObservers<I, OT, S>,
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
Z: IfInteresting<I, S> + IsInteresting<I, OT, S>, //CE: CustomEvent<I>, Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>, //CE: CustomEvent<I>,
{ {
} }
@ -491,7 +513,7 @@ pub fn serialize_state_mgr<I, OT, S, SP>(
) -> Result<Vec<u8>, Error> ) -> Result<Vec<u8>, Error>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
S: Serialize, S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
{ {
@ -503,17 +525,22 @@ where
pub fn deserialize_state_mgr<I, OT, S, SP>( pub fn deserialize_state_mgr<I, OT, S, SP>(
shmem_provider: SP, shmem_provider: SP,
state_corpus_serialized: &[u8], state_corpus_serialized: &[u8],
configuration: String,
) -> Result<(S, LlmpEventManager<I, OT, S, SP>), Error> ) -> Result<(S, LlmpEventManager<I, OT, S, SP>), Error>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
S: DeserializeOwned, S: DeserializeOwned,
SP: ShMemProvider, SP: ShMemProvider,
{ {
let tuple: (S, _) = postcard::from_bytes(state_corpus_serialized)?; let tuple: (S, _) = postcard::from_bytes(state_corpus_serialized)?;
Ok(( Ok((
tuple.0, tuple.0,
LlmpEventManager::existing_client_from_description(shmem_provider, &tuple.1)?, LlmpEventManager::existing_client_from_description(
shmem_provider,
&tuple.1,
configuration,
)?,
)) ))
} }
@ -522,7 +549,7 @@ where
pub struct LlmpRestartingEventManager<I, OT, S, SP> pub struct LlmpRestartingEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
@ -535,7 +562,7 @@ where
impl<I, OT, S, SP> EventFirer<I, S> for LlmpRestartingEventManager<I, OT, S, SP> impl<I, OT, S, SP> EventFirer<I, S> for LlmpRestartingEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
S: Serialize, S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
@ -544,12 +571,16 @@ where
// Check if we are going to crash in the event, in which case we store our current state for the next runner // Check if we are going to crash in the event, in which case we store our current state for the next runner
self.llmp_mgr.fire(state, event) self.llmp_mgr.fire(state, event)
} }
fn configuration(&self) -> &str {
self.llmp_mgr.configuration()
}
} }
impl<I, OT, S, SP> EventRestarter<S> for LlmpRestartingEventManager<I, OT, S, SP> impl<I, OT, S, SP> EventRestarter<S> for LlmpRestartingEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
S: Serialize, S: Serialize,
SP: ShMemProvider, SP: ShMemProvider,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
@ -573,12 +604,12 @@ where
} }
} }
impl<E, I, OT, S, SP, Z> EventProcessor<E, S, Z> for LlmpRestartingEventManager<I, OT, S, SP> impl<E, I, OT, S, SP, Z> EventProcessor<E, I, S, Z> for LlmpRestartingEventManager<I, OT, S, SP>
where where
E: Executor<LlmpEventManager<I, OT, S, SP>, I, S, Z>, E: Executor<LlmpEventManager<I, OT, S, SP>, I, S, Z> + HasObservers<I, OT, S>,
I: Input, I: Input,
Z: IfInteresting<I, S> + IsInteresting<I, OT, S>, Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
@ -589,11 +620,11 @@ where
impl<E, I, OT, S, SP, Z> EventManager<E, I, S, Z> for LlmpRestartingEventManager<I, OT, S, SP> impl<E, I, OT, S, SP, Z> EventManager<E, I, S, Z> for LlmpRestartingEventManager<I, OT, S, SP>
where where
E: Executor<LlmpEventManager<I, OT, S, SP>, I, S, Z>, E: Executor<LlmpEventManager<I, OT, S, SP>, I, S, Z> + HasObservers<I, OT, S>,
I: Input, I: Input,
S: Serialize, S: Serialize,
Z: IfInteresting<I, S> + IsInteresting<I, OT, S>, Z: ExecutionProcessor<I, OT, S> + EvaluatorObservers<I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
@ -608,7 +639,7 @@ const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT";
impl<I, OT, S, SP> LlmpRestartingEventManager<I, OT, S, SP> impl<I, OT, S, SP> LlmpRestartingEventManager<I, OT, S, SP>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
//CE: CustomEvent<I>, //CE: CustomEvent<I>,
{ {
@ -647,6 +678,7 @@ pub enum ManagerKind {
pub fn setup_restarting_mgr_std<I, OT, S, ST>( pub fn setup_restarting_mgr_std<I, OT, S, ST>(
stats: ST, stats: ST,
broker_port: u16, broker_port: u16,
configuration: String,
) -> Result< ) -> Result<
( (
Option<S>, Option<S>,
@ -658,7 +690,7 @@ where
I: Input, I: Input,
S: DeserializeOwned, S: DeserializeOwned,
ST: Stats + Clone, ST: Stats + Clone,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
S: DeserializeOwned, S: DeserializeOwned,
{ {
#[cfg(target_os = "android")] #[cfg(target_os = "android")]
@ -668,6 +700,7 @@ where
.shmem_provider(StdShMemProvider::new()?) .shmem_provider(StdShMemProvider::new()?)
.stats(Some(stats)) .stats(Some(stats))
.broker_port(broker_port) .broker_port(broker_port)
.configuration(configuration)
.build() .build()
.launch() .launch()
} }
@ -681,7 +714,7 @@ where
pub struct RestartingMgr<I, OT, S, SP, ST> pub struct RestartingMgr<I, OT, S, SP, ST>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
S: DeserializeOwned, S: DeserializeOwned,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
ST: Stats, ST: Stats,
@ -690,6 +723,8 @@ where
/// The shared memory provider to use for the broker or client spawned by the restarting /// The shared memory provider to use for the broker or client spawned by the restarting
/// manager. /// manager.
shmem_provider: SP, shmem_provider: SP,
/// The configuration
configuration: String,
/// The stats to use /// The stats to use
#[builder(default = None)] #[builder(default = None)]
stats: Option<ST>, stats: Option<ST>,
@ -711,7 +746,7 @@ where
impl<I, OT, S, SP, ST> RestartingMgr<I, OT, S, SP, ST> impl<I, OT, S, SP, ST> RestartingMgr<I, OT, S, SP, ST>
where where
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
S: DeserializeOwned, S: DeserializeOwned,
SP: ShMemProvider, SP: ShMemProvider,
ST: Stats + Clone, ST: Stats + Clone,
@ -757,7 +792,10 @@ where
return Err(Error::ShuttingDown); return Err(Error::ShuttingDown);
} }
LlmpConnection::IsClient { client } => { LlmpConnection::IsClient { client } => {
let mgr = LlmpEventManager::<I, OT, S, SP>::new(client)?; let mgr = LlmpEventManager::<I, OT, S, SP>::new(
client,
self.configuration.clone(),
)?;
(mgr, None) (mgr, None)
} }
} }
@ -778,6 +816,7 @@ where
let mgr = LlmpEventManager::<I, OT, S, SP>::new_on_port( let mgr = LlmpEventManager::<I, OT, S, SP>::new_on_port(
self.shmem_provider.clone(), self.shmem_provider.clone(),
self.broker_port, self.broker_port,
self.configuration.clone(),
)?; )?;
(mgr, cpu_core) (mgr, cpu_core)
@ -874,6 +913,7 @@ where
let mgr = LlmpEventManager::<I, OT, S, SP>::existing_client_from_env( let mgr = LlmpEventManager::<I, OT, S, SP>::existing_client_from_env(
new_shmem_provider, new_shmem_provider,
_ENV_FUZZER_BROKER_CLIENT_INITIAL, _ENV_FUZZER_BROKER_CLIENT_INITIAL,
self.configuration.clone(),
)?; )?;
(None, LlmpRestartingEventManager::new(mgr, sender)) (None, LlmpRestartingEventManager::new(mgr, sender))
@ -882,7 +922,7 @@ where
Some((_sender, _tag, msg)) => { Some((_sender, _tag, msg)) => {
println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len()); println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len());
let (state, mgr): (S, LlmpEventManager<I, OT, S, SP>) = let (state, mgr): (S, LlmpEventManager<I, OT, S, SP>) =
deserialize_state_mgr(new_shmem_provider, msg)?; deserialize_state_mgr(new_shmem_provider, msg, self.configuration.clone())?;
(Some(state), LlmpRestartingEventManager::new(mgr, sender)) (Some(state), LlmpRestartingEventManager::new(mgr, sender))
} }

View File

@ -9,7 +9,9 @@ use alloc::{string::String, vec::Vec};
use core::{fmt, marker::PhantomData, time::Duration}; use core::{fmt, marker::PhantomData, time::Duration};
use serde::{Deserialize, Serialize}; use serde::{Deserialize, Serialize};
use crate::{inputs::Input, observers::ObserversTuple, stats::UserStats, Error}; use crate::{
executors::ExitKind, inputs::Input, observers::ObserversTuple, stats::UserStats, Error,
};
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
use crate::stats::ClientPerfStats; use crate::stats::ClientPerfStats;
@ -79,6 +81,8 @@ where
input: I, input: I,
/// The state of the observers when this testcase was found /// The state of the observers when this testcase was found
observers_buf: Vec<u8>, observers_buf: Vec<u8>,
/// The exit kind
exit_kind: ExitKind,
/// The new corpus size of this client /// The new corpus size of this client
corpus_size: usize, corpus_size: usize,
/// The client config for this observers/testcase combination /// The client config for this observers/testcase combination
@ -151,6 +155,7 @@ where
input: _, input: _,
client_config: _, client_config: _,
corpus_size: _, corpus_size: _,
exit_kind: _,
observers_buf: _, observers_buf: _,
time: _, time: _,
executions: _, executions: _,
@ -192,6 +197,19 @@ where
{ {
/// Send off an event to the broker /// Send off an event to the broker
fn fire(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error>; fn fire(&mut self, state: &mut S, event: Event<I>) -> Result<(), Error>;
/// Serialize all observers for this type and manager
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error>
where
OT: ObserversTuple<I, S>,
{
Ok(postcard::to_allocvec(observers)?)
}
/// Get the configuration
fn configuration(&self) -> &str {
"<default>"
}
} }
pub trait EventRestarter<S> { pub trait EventRestarter<S> {
@ -207,23 +225,15 @@ pub trait EventRestarter<S> {
} }
/// [`EventProcessor`] process all the incoming messages /// [`EventProcessor`] process all the incoming messages
pub trait EventProcessor<E, S, Z> { pub trait EventProcessor<E, I, S, Z> {
/// Lookup for incoming events and process them. /// Lookup for incoming events and process them.
/// Return the number of processes events or an error /// Return the number of processes events or an error
fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error>; fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result<usize, Error>;
/// Serialize all observers for this type and manager
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Vec<u8>, Error>
where
OT: ObserversTuple,
{
Ok(postcard::to_allocvec(observers)?)
}
/// Deserialize all observers for this type and manager /// Deserialize all observers for this type and manager
fn deserialize_observers<OT>(&mut self, observers_buf: &[u8]) -> Result<OT, Error> fn deserialize_observers<OT>(&mut self, observers_buf: &[u8]) -> Result<OT, Error>
where where
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
Ok(postcard::from_bytes(observers_buf)?) Ok(postcard::from_bytes(observers_buf)?)
} }
@ -232,7 +242,7 @@ pub trait EventProcessor<E, S, Z> {
/// [`EventManager`] is the main communications hub. /// [`EventManager`] is the main communications hub.
/// For the "normal" multi-processed mode, you may want to look into `RestartingEventManager` /// For the "normal" multi-processed mode, you may want to look into `RestartingEventManager`
pub trait EventManager<E, I, S, Z>: pub trait EventManager<E, I, S, Z>:
EventFirer<I, S> + EventProcessor<E, S, Z> + EventRestarter<S> EventFirer<I, S> + EventProcessor<E, I, S, Z> + EventRestarter<S>
where where
I: Input, I: Input,
{ {
@ -253,7 +263,7 @@ where
impl<S> EventRestarter<S> for NopEventManager {} impl<S> EventRestarter<S> for NopEventManager {}
impl<E, S, Z> EventProcessor<E, S, Z> for NopEventManager { impl<E, I, S, Z> EventProcessor<E, I, S, Z> for NopEventManager {
fn process( fn process(
&mut self, &mut self,
_fuzzer: &mut Z, _fuzzer: &mut Z,
@ -277,6 +287,7 @@ mod tests {
tuples::{tuple_list, Named}, tuples::{tuple_list, Named},
}, },
events::Event, events::Event,
executors::ExitKind,
inputs::bytes::BytesInput, inputs::bytes::BytesInput,
observers::StdMapObserver, observers::StdMapObserver,
}; };
@ -293,6 +304,7 @@ mod tests {
let e = Event::NewTestcase { let e = Event::NewTestcase {
input: i, input: i,
observers_buf, observers_buf,
exit_kind: ExitKind::Ok,
corpus_size: 123, corpus_size: 123,
client_config: "conf".into(), client_config: "conf".into(),
time: current_time(), time: current_time(),
@ -307,6 +319,7 @@ mod tests {
input: _, input: _,
observers_buf, observers_buf,
corpus_size: _, corpus_size: _,
exit_kind: _,
client_config: _, client_config: _,
time: _, time: _,
executions: _, executions: _,

View File

@ -69,7 +69,7 @@ where
{ {
} }
impl<E, I, S, ST, Z> EventProcessor<E, S, Z> for SimpleEventManager<I, ST> impl<E, I, S, ST, Z> EventProcessor<E, I, S, Z> for SimpleEventManager<I, ST>
where where
I: Input, I: Input,
ST: Stats, //CE: CustomEvent<I, OT>, ST: Stats, //CE: CustomEvent<I, OT>,
@ -116,6 +116,7 @@ where
Event::NewTestcase { Event::NewTestcase {
input: _, input: _,
client_config: _, client_config: _,
exit_kind: _,
corpus_size, corpus_size,
observers_buf: _, observers_buf: _,
time, time,
@ -249,7 +250,7 @@ where
} }
#[cfg(feature = "std")] #[cfg(feature = "std")]
impl<E, I, S, SP, ST, Z> EventProcessor<E, S, Z> for SimpleRestartingEventManager<I, S, SP, ST> impl<E, I, S, SP, ST, Z> EventProcessor<E, I, S, Z> for SimpleRestartingEventManager<I, S, SP, ST>
where where
I: Input, I: Input,
S: Serialize, S: Serialize,

View File

@ -1,7 +1,7 @@
//! A `CombinedExecutor` wraps a primary executor and a secondary one //! A `CombinedExecutor` wraps a primary executor and a secondary one
use crate::{ use crate::{
executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, executors::{Executor, ExitKind, HasObservers},
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,
@ -52,10 +52,10 @@ where
} }
} }
impl<A, B, OT> HasObservers<OT> for CombinedExecutor<A, B> impl<A, B, I, OT, S> HasObservers<I, OT, S> for CombinedExecutor<A, B>
where where
A: HasObservers<OT>, A: HasObservers<I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -67,11 +67,3 @@ where
self.primary.observers_mut() self.primary.observers_mut()
} }
} }
impl<A, B, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for CombinedExecutor<A, B>
where
A: HasObservers<OT>,
I: Input,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
}

View File

@ -13,7 +13,7 @@ use std::{
use crate::{ use crate::{
bolts::os::{dup2, pipes::Pipe}, bolts::os::{dup2, pipes::Pipe},
executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, executors::{Executor, ExitKind, HasObservers},
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,
@ -411,23 +411,23 @@ where
} }
/// This [`Executor`] can run binaries compiled for AFL/AFL++ that make use of a forkserver. /// This [`Executor`] can run binaries compiled for AFL/AFL++ that make use of a forkserver.
pub struct ForkserverExecutor<I, OT> pub struct ForkserverExecutor<I, OT, S>
where where
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
target: String, target: String,
args: Vec<String>, args: Vec<String>,
out_file: OutFile, out_file: OutFile,
forkserver: Forkserver, forkserver: Forkserver,
observers: OT, observers: OT,
phantom: PhantomData<I>, phantom: PhantomData<(I, S)>,
} }
impl<I, OT> ForkserverExecutor<I, OT> impl<I, OT, S> ForkserverExecutor<I, OT, S>
where where
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
pub fn new(target: String, arguments: &[String], observers: OT) -> Result<Self, Error> { pub fn new(target: String, arguments: &[String], observers: OT) -> Result<Self, Error> {
let mut args = Vec::<String>::new(); let mut args = Vec::<String>::new();
@ -493,10 +493,10 @@ where
} }
} }
impl<EM, I, OT, S, Z> Executor<EM, I, S, Z> for ForkserverExecutor<I, OT> impl<EM, I, OT, S, Z> Executor<EM, I, S, Z> for ForkserverExecutor<I, OT, S>
where where
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn run_target( fn run_target(
@ -554,10 +554,10 @@ where
} }
} }
impl<I, OT> HasObservers<OT> for ForkserverExecutor<I, OT> impl<I, OT, S> HasObservers<I, OT, S> for ForkserverExecutor<I, OT, S>
where where
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -570,17 +570,10 @@ where
} }
} }
impl<EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for ForkserverExecutor<I, OT> impl<I, OT, S> HasForkserver for ForkserverExecutor<I, OT, S>
where where
I: Input + HasTargetBytes, I: Input + HasTargetBytes,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>, OT: ObserversTuple<I, S>,
{
}
impl<I, OT> HasForkserver for ForkserverExecutor<I, OT>
where
I: Input + HasTargetBytes,
OT: ObserversTuple,
{ {
#[inline] #[inline]
fn forkserver(&self) -> &Forkserver { fn forkserver(&self) -> &Forkserver {
@ -603,10 +596,10 @@ where
} }
} }
impl<E, OT> HasObservers<OT> for TimeoutForkserverExecutor<E> impl<E, I, OT, S> HasObservers<I, OT, S> for TimeoutForkserverExecutor<E>
where where
E: HasObservers<OT>, E: HasObservers<I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -619,14 +612,6 @@ where
} }
} }
impl<E, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for TimeoutForkserverExecutor<E>
where
E: HasObservers<OT>,
I: Input,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {
use crate::{ use crate::{
@ -657,7 +642,7 @@ mod tests {
&mut shmem_map, &mut shmem_map,
)); ));
let executor = ForkserverExecutor::<NopInput, _>::new( let executor = ForkserverExecutor::<NopInput, _, ()>::new(
bin.to_string(), bin.to_string(),
&args, &args,
tuple_list!(edges_observer), tuple_list!(edges_observer),

View File

@ -23,7 +23,7 @@ pub use windows_exception_handler::{nop_handler, HandlerFuncPtr};
use crate::{ use crate::{
corpus::Corpus, corpus::Corpus,
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, executors::{Executor, ExitKind, HasObservers},
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::Input, inputs::Input,
@ -37,7 +37,7 @@ pub struct InProcessExecutor<'a, H, I, OT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&I) -> ExitKind,
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
/// The harness function, being executed for each fuzzing loop execution /// The harness function, being executed for each fuzzing loop execution
harness_fn: &'a mut H, harness_fn: &'a mut H,
@ -56,7 +56,7 @@ impl<'a, EM, H, I, OT, S, Z> Executor<EM, I, S, Z> for InProcessExecutor<'a, H,
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&I) -> ExitKind,
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn run_target( fn run_target(
@ -130,11 +130,11 @@ where
} }
} }
impl<'a, H, I, OT, S> HasObservers<OT> for InProcessExecutor<'a, H, I, OT, S> impl<'a, H, I, OT, S> HasObservers<I, OT, S> for InProcessExecutor<'a, H, I, OT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&I) -> ExitKind,
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -147,20 +147,11 @@ where
} }
} }
impl<'a, EM, H, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z>
for InProcessExecutor<'a, H, I, OT, S>
where
H: FnMut(&I) -> ExitKind,
I: Input,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
}
impl<'a, H, I, OT, S> InProcessExecutor<'a, H, I, OT, S> impl<'a, H, I, OT, S> InProcessExecutor<'a, H, I, OT, S>
where where
H: FnMut(&I) -> ExitKind, H: FnMut(&I) -> ExitKind,
I: Input, I: Input,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
/// Create a new in mem executor. /// Create a new in mem executor.
/// Caution: crash and restart in one of them will lead to odd behavior if multiple are used, /// Caution: crash and restart in one of them will lead to odd behavior if multiple are used,
@ -349,7 +340,7 @@ mod unix_signal_handler {
data: &mut InProcessExecutorHandlerData, data: &mut InProcessExecutorHandlerData,
) where ) where
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
OC: Corpus<I>, OC: Corpus<I>,
OF: Feedback<I, S>, OF: Feedback<I, S>,
S: HasSolutions<OC, I>, S: HasSolutions<OC, I>,
@ -423,7 +414,7 @@ mod unix_signal_handler {
data: &mut InProcessExecutorHandlerData, data: &mut InProcessExecutorHandlerData,
) where ) where
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
OC: Corpus<I>, OC: Corpus<I>,
OF: Feedback<I, S>, OF: Feedback<I, S>,
S: HasSolutions<OC, I>, S: HasSolutions<OC, I>,
@ -634,7 +625,7 @@ mod windows_exception_handler {
data: &mut InProcessExecutorHandlerData, data: &mut InProcessExecutorHandlerData,
) where ) where
EM: EventFirer<I, S> + EventRestarter<S>, EM: EventFirer<I, S> + EventRestarter<S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
OC: Corpus<I>, OC: Corpus<I>,
OF: Feedback<I, S>, OF: Feedback<I, S>,
S: HasSolutions<OC, I>, S: HasSolutions<OC, I>,

View File

@ -17,19 +17,15 @@ pub mod shadow;
pub use shadow::{HasShadowObserverHooks, ShadowExecutor}; pub use shadow::{HasShadowObserverHooks, ShadowExecutor};
use crate::{ use crate::{
bolts::serdeany::SerdeAny,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,
}; };
use alloc::boxed::Box; use serde::{Deserialize, Serialize};
/// A `CustomExitKind` for exits that do not fit to one of the default `ExitKind`.
pub trait CustomExitKind: core::fmt::Debug + SerdeAny + 'static {}
/// How an execution finished. /// How an execution finished.
#[derive(Debug)] #[derive(Debug, Clone, Serialize, Deserialize)]
pub enum ExitKind { pub enum ExitKind {
/// The run exited normally. /// The run exited normally.
Ok, Ok,
@ -39,112 +35,14 @@ pub enum ExitKind {
Oom, Oom,
/// The run timed out /// The run timed out
Timeout, Timeout,
/// The run resulted in a custom `ExitKind`. // The run resulted in a custom `ExitKind`.
Custom(Box<dyn CustomExitKind>), // Custom(Box<dyn SerdeAny>),
}
/// Pre and post exec hooks
pub trait HasExecHooks<EM, I, S, Z> {
/// Called right before exexution starts
#[inline]
fn pre_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
Ok(())
}
/// Called right after execution finished.
#[inline]
fn post_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
Ok(())
}
}
/// A haskell-style tuple of objects that have pre and post exec hooks
pub trait HasExecHooksTuple<EM, I, S, Z> {
/// This is called right before the next execution.
fn pre_exec_all(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error>;
/// This is called right after the last execution
fn post_exec_all(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error>;
}
impl<EM, I, S, Z> HasExecHooksTuple<EM, I, S, Z> for () {
fn pre_exec_all(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
Ok(())
}
fn post_exec_all(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
Ok(())
}
}
impl<EM, I, S, Z, Head, Tail> HasExecHooksTuple<EM, I, S, Z> for (Head, Tail)
where
Head: HasExecHooks<EM, I, S, Z>,
Tail: HasExecHooksTuple<EM, I, S, Z>,
{
fn pre_exec_all(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.0.pre_exec(fuzzer, state, mgr, input)?;
self.1.pre_exec_all(fuzzer, state, mgr, input)
}
fn post_exec_all(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.0.post_exec(fuzzer, state, mgr, input)?;
self.1.post_exec_all(fuzzer, state, mgr, input)
}
} }
/// Holds a tuple of Observers /// Holds a tuple of Observers
pub trait HasObservers<OT> pub trait HasObservers<I, OT, S>
where where
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
/// Get the linked observers /// Get the linked observers
fn observers(&self) -> &OT; fn observers(&self) -> &OT;
@ -153,37 +51,6 @@ where
fn observers_mut(&mut self) -> &mut OT; fn observers_mut(&mut self) -> &mut OT;
} }
/// Execute the exec hooks of the observers if they all implement [`HasExecHooks`].
pub trait HasObserversHooks<EM, I, OT, S, Z>: HasObservers<OT>
where
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
/// Run the pre exec hook for all [`crate::observers::Observer`]`s` linked to this [`Executor`].
#[inline]
fn pre_exec_observers(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.observers_mut().pre_exec_all(fuzzer, state, mgr, input)
}
/// Run the post exec hook for all the [`crate::observers::Observer`]`s` linked to this [`Executor`].
#[inline]
fn post_exec_observers(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.observers_mut()
.post_exec_all(fuzzer, state, mgr, input)
}
}
/// An executor takes the given inputs, and runs the harness/target. /// An executor takes the given inputs, and runs the harness/target.
pub trait Executor<EM, I, S, Z> pub trait Executor<EM, I, S, Z>
where where

View File

@ -1,7 +1,9 @@
//! A `ShadowExecutor` wraps an executor to have shadow observer that will not be considered by the feedbacks and the manager //! A `ShadowExecutor` wraps an executor to have shadow observer that will not be considered by the feedbacks and the manager
use core::marker::PhantomData;
use crate::{ use crate::{
executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, executors::{Executor, ExitKind, HasObservers},
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,
@ -28,36 +30,22 @@ pub trait HasShadowObserverHooks<EM, I, S, SOT, Z> {
} }
/// A [`ShadowExecutor`] wraps an executor and a set of shadow observers /// A [`ShadowExecutor`] wraps an executor and a set of shadow observers
pub struct ShadowExecutor<E, SOT> { pub struct ShadowExecutor<E, I, S, SOT> {
executor: E, executor: E,
shadow_observers: SOT, shadow_observers: SOT,
// Enable the execution of the shadow observers hooks with the regular observers hooks phantom: PhantomData<(I, S)>,
shadow_hooks: bool,
} }
impl<E, SOT> ShadowExecutor<E, SOT> impl<E, I, S, SOT> ShadowExecutor<E, I, S, SOT>
where where
SOT: ObserversTuple, SOT: ObserversTuple<I, S>,
{ {
/// Create a new `ShadowExecutor`, wrapping the given `executor`. /// Create a new `ShadowExecutor`, wrapping the given `executor`.
pub fn new(executor: E, shadow_observers: SOT) -> Self { pub fn new(executor: E, shadow_observers: SOT) -> Self {
Self { Self {
executor, executor,
shadow_observers, shadow_observers,
shadow_hooks: false, phantom: PhantomData,
}
}
/// Create a new `ShadowExecutor`, wrapping the given `executor`.
pub fn with_shadow_hooks<EM, I, S, Z>(
executor: E,
shadow_observers: SOT,
shadow_hooks: bool,
) -> Self {
Self {
executor,
shadow_observers,
shadow_hooks,
} }
} }
@ -70,51 +58,13 @@ where
pub fn shadow_observers_mut(&mut self) -> &mut SOT { pub fn shadow_observers_mut(&mut self) -> &mut SOT {
&mut self.shadow_observers &mut self.shadow_observers
} }
pub fn shadow_hooks(&self) -> &bool {
&self.shadow_hooks
}
pub fn shadow_hooks_mut(&mut self) -> &mut bool {
&mut self.shadow_hooks
}
} }
impl<E, EM, I, S, SOT, Z> HasShadowObserverHooks<EM, I, S, SOT, Z> for ShadowExecutor<E, SOT> impl<E, EM, I, S, SOT, Z> Executor<EM, I, S, Z> for ShadowExecutor<E, I, S, SOT>
where
I: Input,
SOT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
#[inline]
fn pre_exec_shadow_observers(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.shadow_observers
.pre_exec_all(fuzzer, state, mgr, input)
}
#[inline]
fn post_exec_shadow_observers(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.shadow_observers
.post_exec_all(fuzzer, state, mgr, input)
}
}
impl<E, EM, I, S, SOT, Z> Executor<EM, I, S, Z> for ShadowExecutor<E, SOT>
where where
E: Executor<EM, I, S, Z>, E: Executor<EM, I, S, Z>,
I: Input, I: Input,
SOT: ObserversTuple, SOT: ObserversTuple<I, S>,
{ {
fn run_target( fn run_target(
&mut self, &mut self,
@ -127,11 +77,11 @@ where
} }
} }
impl<E, OT, SOT> HasObservers<OT> for ShadowExecutor<E, SOT> impl<E, I, OT, S, SOT> HasObservers<I, OT, S> for ShadowExecutor<E, I, S, SOT>
where where
E: HasObservers<OT>, E: HasObservers<I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
SOT: ObserversTuple, SOT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -143,44 +93,3 @@ where
self.executor.observers_mut() self.executor.observers_mut()
} }
} }
impl<E, EM, I, OT, S, SOT, Z> HasObserversHooks<EM, I, OT, S, Z> for ShadowExecutor<E, SOT>
where
E: HasObservers<OT>,
I: Input,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
SOT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
/// Run the pre exec hook for all [`crate::observers::Observer`]`s` linked to this [`Executor`].
#[inline]
fn pre_exec_observers(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
if self.shadow_hooks {
self.shadow_observers
.pre_exec_all(fuzzer, state, mgr, input)?;
}
self.observers_mut().pre_exec_all(fuzzer, state, mgr, input)
}
/// Run the post exec hook for all the [`crate::observers::Observer`]`s` linked to this [`Executor`].
#[inline]
fn post_exec_observers(
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
if self.shadow_hooks {
self.shadow_observers
.post_exec_all(fuzzer, state, mgr, input)?;
}
self.observers_mut()
.post_exec_all(fuzzer, state, mgr, input)
}
}

View File

@ -3,7 +3,7 @@
use core::time::Duration; use core::time::Duration;
use crate::{ use crate::{
executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, executors::{Executor, ExitKind, HasObservers},
inputs::Input, inputs::Input,
observers::ObserversTuple, observers::ObserversTuple,
Error, Error,
@ -129,10 +129,10 @@ where
} }
} }
impl<E, OT> HasObservers<OT> for TimeoutExecutor<E> impl<E, I, OT, S> HasObservers<I, OT, S> for TimeoutExecutor<E>
where where
E: HasObservers<OT>, E: HasObservers<I, OT, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
#[inline] #[inline]
fn observers(&self) -> &OT { fn observers(&self) -> &OT {
@ -144,11 +144,3 @@ where
self.executor.observers_mut() self.executor.observers_mut()
} }
} }
impl<E, EM, I, OT, S, Z> HasObserversHooks<EM, I, OT, S, Z> for TimeoutExecutor<E>
where
E: HasObservers<OT>,
I: Input,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
{
}

View File

@ -22,9 +22,9 @@ use crate::{
}; };
/// A [`MapFeedback`] that strives to maximize the map contents. /// A [`MapFeedback`] that strives to maximize the map contents.
pub type MaxMapFeedback<FT, O, S, T> = MapFeedback<FT, O, MaxReducer, S, T>; pub type MaxMapFeedback<FT, I, O, S, T> = MapFeedback<FT, I, O, MaxReducer, S, T>;
/// A [`MapFeedback`] that strives to minimize the map contents. /// A [`MapFeedback`] that strives to minimize the map contents.
pub type MinMapFeedback<FT, O, S, T> = MapFeedback<FT, O, MinReducer, S, T>; pub type MinMapFeedback<FT, I, O, S, T> = MapFeedback<FT, I, O, MinReducer, S, T>;
/// A Reducer function is used to aggregate values for the novelty search /// A Reducer function is used to aggregate values for the novelty search
pub trait Reducer<T>: Serialize + serde::de::DeserializeOwned + 'static pub trait Reducer<T>: Serialize + serde::de::DeserializeOwned + 'static
@ -185,7 +185,7 @@ where
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
#[derive(Serialize, Deserialize, Clone, Debug)] #[derive(Serialize, Deserialize, Clone, Debug)]
#[serde(bound = "T: serde::de::DeserializeOwned")] #[serde(bound = "T: serde::de::DeserializeOwned")]
pub struct MapFeedback<FT, O, R, S, T> pub struct MapFeedback<FT, I, O, R, S, T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
R: Reducer<T>, R: Reducer<T>,
@ -202,10 +202,10 @@ where
/// Name identifier of the observer /// Name identifier of the observer
observer_name: String, observer_name: String,
/// Phantom Data of Reducer /// Phantom Data of Reducer
phantom: PhantomData<(FT, S, R, O, T)>, phantom: PhantomData<(FT, I, S, R, O, T)>,
} }
impl<I, FT, O, R, S, T> Feedback<I, S> for MapFeedback<FT, O, R, S, T> impl<I, FT, O, R, S, T> Feedback<I, S> for MapFeedback<FT, I, O, R, S, T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
R: Reducer<T>, R: Reducer<T>,
@ -224,7 +224,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
let mut interesting = false; let mut interesting = false;
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
@ -312,7 +312,7 @@ where
} }
} }
impl<FT, O, R, S, T> Named for MapFeedback<FT, O, R, S, T> impl<FT, I, O, R, S, T> Named for MapFeedback<FT, I, O, R, S, T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
R: Reducer<T>, R: Reducer<T>,
@ -326,7 +326,7 @@ where
} }
} }
impl<FT, O, R, S, T> MapFeedback<FT, O, R, S, T> impl<FT, I, O, R, S, T> MapFeedback<FT, I, O, R, S, T>
where where
T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Integer + Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
R: Reducer<T>, R: Reducer<T>,
@ -441,7 +441,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers.match_name::<O>(&self.name).unwrap(); let observer = observers.match_name::<O>(&self.name).unwrap();

View File

@ -40,7 +40,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple; OT: ObserversTuple<I, S>;
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@ -56,7 +56,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
// Start a timer for this feedback // Start a timer for this feedback
let start_time = crate::bolts::cpu::read_time_counter(); let start_time = crate::bolts::cpu::read_time_counter();
@ -168,7 +168,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
FL::is_pair_interesting( FL::is_pair_interesting(
&mut self.first, &mut self.first,
@ -194,7 +194,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
FL::is_pair_interesting_with_perf( FL::is_pair_interesting_with_perf(
&mut self.first, &mut self.first,
@ -241,7 +241,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple; OT: ObserversTuple<I, S>;
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
#[allow(clippy::too_many_arguments)] #[allow(clippy::too_many_arguments)]
@ -258,7 +258,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple; OT: ObserversTuple<I, S>;
} }
pub struct LogicEagerOr {} pub struct LogicEagerOr {}
@ -287,7 +287,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
let b = second.is_interesting(state, manager, input, observers, exit_kind)?; let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
@ -308,7 +308,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
// Execute this feedback // Execute this feedback
let a = first.is_interesting_with_perf( let a = first.is_interesting_with_perf(
@ -355,7 +355,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
if a { if a {
@ -379,7 +379,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
// Execute this feedback // Execute this feedback
let a = first.is_interesting_with_perf( let a = first.is_interesting_with_perf(
@ -429,7 +429,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
let b = second.is_interesting(state, manager, input, observers, exit_kind)?; let b = second.is_interesting(state, manager, input, observers, exit_kind)?;
@ -450,7 +450,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
// Execute this feedback // Execute this feedback
let a = first.is_interesting_with_perf( let a = first.is_interesting_with_perf(
@ -497,7 +497,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let a = first.is_interesting(state, manager, input, observers, exit_kind)?;
if !a { if !a {
@ -521,7 +521,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
// Execute this feedback // Execute this feedback
let a = first.is_interesting_with_perf( let a = first.is_interesting_with_perf(
@ -596,7 +596,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
Ok(!self Ok(!self
.first .first
@ -707,7 +707,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
Ok(false) Ok(false)
} }
@ -738,7 +738,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
if let ExitKind::Crash = exit_kind { if let ExitKind::Crash = exit_kind {
Ok(true) Ok(true)
@ -787,7 +787,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
if let ExitKind::Timeout = exit_kind { if let ExitKind::Timeout = exit_kind {
Ok(true) Ok(true)
@ -841,7 +841,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
// TODO Replace with match_name_type when stable // TODO Replace with match_name_type when stable
let observer = observers.match_name::<TimeObserver>(self.name()).unwrap(); let observer = observers.match_name::<TimeObserver>(self.name()).unwrap();

View File

@ -4,7 +4,7 @@ use crate::{
bolts::current_time, bolts::current_time,
corpus::{Corpus, CorpusScheduler, Testcase}, corpus::{Corpus, CorpusScheduler, Testcase},
events::{Event, EventFirer, EventManager}, events::{Event, EventFirer, EventManager},
executors::{Executor, ExitKind, HasExecHooksTuple, HasObservers, HasObserversHooks}, executors::{Executor, ExitKind, HasObservers},
feedbacks::Feedback, feedbacks::Feedback,
inputs::Input, inputs::Input,
mark_feature_time, mark_feature_time,
@ -66,33 +66,44 @@ where
} }
/// Evaluate if an input is interesting using the feedback /// Evaluate if an input is interesting using the feedback
pub trait IsInteresting<I, OT, S> pub trait ExecutionProcessor<I, OT, S>
where where
OT: ObserversTuple, OT: ObserversTuple<I, S>,
I: Input, I: Input,
{ {
/// 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<EM>( fn process_execution<EM>(
&mut self, &mut self,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
input: &I, input: I,
observers: &OT, observers: &OT,
exit_kind: &ExitKind, exit_kind: &ExitKind,
) -> Result<bool, Error> send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error>
where where
EM: EventFirer<I, S>; EM: EventFirer<I, S>;
} }
/// Add to the state if interesting /// Evaluate an input modyfing the state of the fuzzer
pub trait IfInteresting<I, S> { pub trait EvaluatorObservers<I, OT, S>: Sized
/// Adds this input to the corpus, if it's intersting, and return the index where
fn add_if_interesting( I: Input,
OT: ObserversTuple<I, S>,
{
/// Runs the input and triggers observers and feedback,
/// returns if is interesting an (option) the index of the new testcase in the corpus
fn evaluate_input_with_observers<E, EM>(
&mut self, &mut self,
state: &mut S, state: &mut S,
input: &I, executor: &mut E,
is_interesting: bool, manager: &mut EM,
) -> Result<Option<usize>, Error>; input: I,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error>
where
E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>,
EM: EventManager<E, I, S, Self>;
} }
/// Evaluate an input modyfing the state of the fuzzer /// Evaluate an input modyfing the state of the fuzzer
@ -105,7 +116,21 @@ pub trait Evaluator<E, EM, I, S> {
executor: &mut E, executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: I,
) -> Result<(bool, Option<usize>), Error>; ) -> Result<(ExecuteInputResult, Option<usize>), Error> {
self.evaluate_input_events(state, executor, manager, input, true)
}
/// Runs the input and triggers observers and feedback,
/// returns if is interesting an (option) the index of the new testcase in the corpus
/// This version has a boolean to decide if send events to the manager.
fn evaluate_input_events(
&mut self,
state: &mut S,
executor: &mut E,
manager: &mut EM,
input: I,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error>;
/// Runs the input and triggers observers and feedback. /// Runs the input and triggers observers and feedback.
/// Adds an input, to the corpus even if it's not considered `interesting` by the `feedback`. /// Adds an input, to the corpus even if it's not considered `interesting` by the `feedback`.
@ -200,9 +225,10 @@ pub trait Fuzzer<E, EM, I, S, ST> {
) -> Result<Duration, Error>; ) -> Result<Duration, Error>;
} }
#[derive(Debug, PartialEq)]
pub enum ExecuteInputResult { pub enum ExecuteInputResult {
None, None,
Interesting, Corpus,
Solution, Solution,
} }
@ -270,97 +296,86 @@ where
} }
} }
impl<C, CS, F, I, OF, OT, S, SC> IsInteresting<I, OT, S> for StdFuzzer<C, CS, F, I, OF, OT, S, SC> impl<C, CS, F, I, OF, OT, S, SC> ExecutionProcessor<I, OT, S>
where
C: Corpus<I>,
CS: CorpusScheduler<I, S>,
F: Feedback<I, S>,
I: Input,
OF: Feedback<I, S>,
OT: ObserversTuple,
S: HasCorpus<C, I>,
{
/// Evaluate if a set of observation channels has an interesting state
fn is_interesting<EM>(
&mut self,
state: &mut S,
manager: &mut EM,
input: &I,
observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<I, S>,
{
self.feedback_mut()
.is_interesting(state, manager, input, observers, exit_kind)
}
}
impl<C, CS, F, I, OF, OT, S, SC> IfInteresting<I, S> for StdFuzzer<C, CS, F, I, OF, OT, S, SC>
where
C: Corpus<I>,
CS: CorpusScheduler<I, S>,
F: Feedback<I, S>,
I: Input,
OF: Feedback<I, S>,
OT: ObserversTuple,
S: HasCorpus<C, I>,
{
/// Adds this input to the corpus, if it's intersting, and return the index
#[inline]
fn add_if_interesting(
&mut self,
state: &mut S,
input: &I,
is_interesting: bool,
) -> Result<Option<usize>, Error> {
if is_interesting {
let mut testcase = Testcase::new(input.clone());
self.feedback_mut().append_metadata(state, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?;
self.scheduler_mut().on_add(state, idx)?;
Ok(Some(idx))
} else {
self.feedback_mut().discard_metadata(state, input)?;
Ok(None)
}
}
}
impl<C, CS, E, EM, F, I, OF, OT, S, SC> Evaluator<E, EM, I, S>
for StdFuzzer<C, CS, F, I, OF, OT, S, SC> for StdFuzzer<C, CS, F, I, OF, OT, S, SC>
where where
C: Corpus<I>, C: Corpus<I>,
SC: Corpus<I>,
CS: CorpusScheduler<I, S>, CS: CorpusScheduler<I, S>,
E: Executor<EM, I, S, Self> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Self>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Self>,
EM: EventManager<E, I, S, Self>,
F: Feedback<I, S>, F: Feedback<I, S>,
I: Input, I: Input,
OF: Feedback<I, S>, OF: Feedback<I, S>,
S: HasExecutions + HasCorpus<C, I> + HasSolutions<SC, I> + HasClientPerfStats, OT: ObserversTuple<I, S>,
SC: Corpus<I>, S: HasCorpus<C, I> + HasSolutions<SC, I> + HasClientPerfStats + HasExecutions,
{ {
/// Process one input, adding to the respective corpuses if needed and firing the right events /// Evaluate if a set of observation channels has an interesting state
#[inline] fn process_execution<EM>(
fn evaluate_input(
&mut self, &mut self,
state: &mut S, state: &mut S,
executor: &mut E,
manager: &mut EM, manager: &mut EM,
input: I, input: I,
) -> Result<(bool, Option<usize>), Error> { observers: &OT,
let result = self.execute_input(state, executor, manager, &input)?; exit_kind: &ExitKind,
let observers = executor.observers(); send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error>
where
EM: EventFirer<I, S>,
{
let mut res = ExecuteInputResult::None;
match result { start_timer!(state);
let is_solution = self
.objective_mut()
.is_interesting(state, manager, &input, observers, &exit_kind)?;
mark_feature_time!(state, PerfFeature::GetObjectivesInterestingAll);
if is_solution {
res = ExecuteInputResult::Solution;
} else {
#[cfg(not(feature = "introspection"))]
let is_corpus = self
.feedback_mut()
.is_interesting(state, manager, &input, observers, &exit_kind)?;
#[cfg(feature = "introspection")]
let is_corpus = {
// Init temporary feedback stats here. We can't use the typical pattern above
// since we need a `mut self` for `feedbacks_mut`, so we can't also hand a
// new `mut self` to `is_interesting_with_perf`. We use this stack
// variable to get the stats and then update the feedbacks directly
let mut feedback_stats = [0_u64; crate::stats::NUM_FEEDBACKS];
let feedback_index = 0;
let is_corpus = self.feedback_mut().is_interesting_with_perf(
state,
manager,
&input,
observers,
&exit_kind,
&mut feedback_stats,
feedback_index,
)?;
// Update the feedback stats
state
.introspection_stats_mut()
.update_feedbacks(feedback_stats);
// Return the total fitness
is_corpus
};
if is_corpus {
res = ExecuteInputResult::Corpus;
}
}
match res {
ExecuteInputResult::None => { ExecuteInputResult::None => {
self.feedback_mut().discard_metadata(state, &input)?; self.feedback_mut().discard_metadata(state, &input)?;
self.objective_mut().discard_metadata(state, &input)?; self.objective_mut().discard_metadata(state, &input)?;
Ok((false, None)) Ok((res, None))
} }
ExecuteInputResult::Interesting => { ExecuteInputResult::Corpus => {
// Not a solution // Not a solution
self.objective_mut().discard_metadata(state, &input)?; self.objective_mut().discard_metadata(state, &input)?;
@ -370,19 +385,22 @@ where
let idx = state.corpus_mut().add(testcase)?; let idx = state.corpus_mut().add(testcase)?;
self.scheduler_mut().on_add(state, idx)?; self.scheduler_mut().on_add(state, idx)?;
let observers_buf = manager.serialize_observers(observers)?; if send_events {
manager.fire( let observers_buf = manager.serialize_observers(observers)?;
state, manager.fire(
Event::NewTestcase { state,
input, Event::NewTestcase {
observers_buf, input,
corpus_size: state.corpus().count(), observers_buf,
client_config: "TODO".into(), exit_kind: exit_kind.clone(),
time: current_time(), corpus_size: state.corpus().count(),
executions: *state.executions(), client_config: manager.configuration().to_string(),
}, time: current_time(),
)?; executions: *state.executions(),
Ok((true, Some(idx))) },
)?;
}
Ok((res, Some(idx)))
} }
ExecuteInputResult::Solution => { ExecuteInputResult::Solution => {
// Not interesting // Not interesting
@ -392,17 +410,80 @@ where
let mut testcase = Testcase::new(input); let mut testcase = Testcase::new(input);
self.objective_mut().append_metadata(state, &mut testcase)?; self.objective_mut().append_metadata(state, &mut testcase)?;
state.solutions_mut().add(testcase)?; state.solutions_mut().add(testcase)?;
manager.fire(
state,
Event::Objective {
objective_size: state.solutions().count(),
},
)?;
Ok((false, None)) if send_events {
manager.fire(
state,
Event::Objective {
objective_size: state.solutions().count(),
},
)?;
}
Ok((res, None))
} }
} }
} }
}
impl<C, CS, F, I, OF, OT, S, SC> EvaluatorObservers<I, OT, S>
for StdFuzzer<C, CS, F, I, OF, OT, S, SC>
where
C: Corpus<I>,
CS: CorpusScheduler<I, S>,
OT: ObserversTuple<I, S>,
F: Feedback<I, S>,
I: Input,
OF: Feedback<I, S>,
S: HasExecutions + HasCorpus<C, I> + HasSolutions<SC, I> + HasClientPerfStats,
SC: Corpus<I>,
{
/// Process one input, adding to the respective corpuses if needed and firing the right events
#[inline]
fn evaluate_input_with_observers<E, EM>(
&mut self,
state: &mut S,
executor: &mut E,
manager: &mut EM,
input: I,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error>
where
E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>,
EM: EventManager<E, I, S, Self>,
{
let exit_kind = self.execute_input(state, executor, manager, &input)?;
let observers = executor.observers();
self.process_execution(state, manager, input, observers, &exit_kind, send_events)
}
}
impl<C, CS, E, EM, F, I, OF, OT, S, SC> Evaluator<E, EM, I, S>
for StdFuzzer<C, CS, F, I, OF, OT, S, SC>
where
C: Corpus<I>,
CS: CorpusScheduler<I, S>,
E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>,
OT: ObserversTuple<I, S>,
EM: EventManager<E, I, S, Self>,
F: Feedback<I, S>,
I: Input,
OF: Feedback<I, S>,
S: HasExecutions + HasCorpus<C, I> + HasSolutions<SC, I> + HasClientPerfStats,
SC: Corpus<I>,
{
/// Process one input, adding to the respective corpuses if needed and firing the right events
#[inline]
fn evaluate_input_events(
&mut self,
state: &mut S,
executor: &mut E,
manager: &mut EM,
input: I,
send_events: bool,
) -> Result<(ExecuteInputResult, Option<usize>), Error> {
self.evaluate_input_with_observers(state, executor, manager, input, send_events)
}
/// Adds an input, even if it's not conisered `interesting` by any of the executors /// Adds an input, even if it's not conisered `interesting` by any of the executors
fn add_input( fn add_input(
@ -412,7 +493,7 @@ where
manager: &mut EM, manager: &mut EM,
input: I, input: I,
) -> Result<usize, Error> { ) -> Result<usize, Error> {
let _ = self.execute_input(state, executor, manager, &input)?; let exit_kind = self.execute_input(state, executor, manager, &input)?;
let observers = executor.observers(); let observers = executor.observers();
// Always consider this to be "interesting" // Always consider this to be "interesting"
@ -431,8 +512,9 @@ where
Event::NewTestcase { Event::NewTestcase {
input, input,
observers_buf, observers_buf,
exit_kind,
corpus_size: state.corpus().count(), corpus_size: state.corpus().count(),
client_config: "TODO".into(), client_config: manager.configuration().to_string(),
time: current_time(), time: current_time(),
executions: *state.executions(), executions: *state.executions(),
}, },
@ -565,14 +647,13 @@ where
executor: &mut E, executor: &mut E,
event_mgr: &mut EM, event_mgr: &mut EM,
input: &I, input: &I,
) -> Result<ExecuteInputResult, Error> ) -> Result<ExitKind, Error>
where where
E: Executor<EM, I, S, Self> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Self>, E: Executor<EM, I, S, Self> + HasObservers<I, OT, S>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Self>, OT: ObserversTuple<I, S>,
EM: EventManager<E, I, S, Self>,
{ {
start_timer!(state); start_timer!(state);
executor.pre_exec_observers(self, state, event_mgr, input)?; executor.observers_mut().pre_exec_all(state, input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers); mark_feature_time!(state, PerfFeature::PreExecObservers);
start_timer!(state); start_timer!(state);
@ -582,57 +663,9 @@ where
*state.executions_mut() += 1; *state.executions_mut() += 1;
start_timer!(state); start_timer!(state);
executor.post_exec_observers(self, state, event_mgr, input)?; executor.observers_mut().post_exec_all(state, input)?;
mark_feature_time!(state, PerfFeature::PostExecObservers); mark_feature_time!(state, PerfFeature::PostExecObservers);
let observers = executor.observers(); Ok(exit_kind)
start_timer!(state);
let is_solution = self
.objective_mut()
.is_interesting(state, event_mgr, input, observers, &exit_kind)?;
mark_feature_time!(state, PerfFeature::GetObjectivesInterestingAll);
if is_solution {
return Ok(ExecuteInputResult::Solution);
}
#[cfg(not(feature = "introspection"))]
let is_interesting = self
.feedback_mut()
.is_interesting(state, event_mgr, &input, observers, &exit_kind)?;
#[cfg(feature = "introspection")]
let is_interesting = {
// Init temporary feedback stats here. We can't use the typical pattern above
// since we need a `mut self` for `feedbacks_mut`, so we can't also hand a
// new `mut self` to `is_interesting_with_perf`. We use this stack
// variable to get the stats and then update the feedbacks directly
let mut feedback_stats = [0_u64; crate::stats::NUM_FEEDBACKS];
let feedback_index = 0;
let is_interesting = self.feedback_mut().is_interesting_with_perf(
state,
event_mgr,
input,
observers,
&exit_kind,
&mut feedback_stats,
feedback_index,
)?;
// Update the feedback stats
state
.introspection_stats_mut()
.update_feedbacks(feedback_stats);
// Return the total fitness
is_interesting
};
if is_interesting {
Ok(ExecuteInputResult::Interesting)
} else {
Ok(ExecuteInputResult::None)
}
} }
} }

View File

@ -9,7 +9,6 @@ use serde::{de::DeserializeOwned, Deserialize, Serialize};
use crate::{ use crate::{
bolts::{ownedref::OwnedRefMut, tuples::Named, AsSlice}, bolts::{ownedref::OwnedRefMut, tuples::Named, AsSlice},
executors::HasExecHooks,
observers::Observer, observers::Observer,
state::HasMetadata, state::HasMetadata,
Error, Error,
@ -95,7 +94,7 @@ pub trait CmpMap: Serialize + DeserializeOwned {
} }
/// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`] /// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`]
pub trait CmpObserver<CM>: Observer pub trait CmpObserver<CM, I, S>: Observer<I, S>
where where
CM: CmpMap, CM: CmpMap,
{ {
@ -110,7 +109,7 @@ where
/// Add [`CmpValuesMetadata`] to the State including the logged values. /// Add [`CmpValuesMetadata`] to the State including the logged values.
/// This routine does a basic loop filtering because loop index cmps are not interesting. /// This routine does a basic loop filtering because loop index cmps are not interesting.
fn add_cmpvalues_meta<S>(&mut self, state: &mut S) fn add_cmpvalues_meta(&mut self, state: &mut S)
where where
S: HasMetadata, S: HasMetadata,
{ {
@ -181,14 +180,14 @@ where
name: String, name: String,
} }
impl<'a, CM> CmpObserver<CM> for StdCmpObserver<'a, CM> impl<'a, CM, I, S> CmpObserver<CM, I, S> for StdCmpObserver<'a, CM>
where where
CM: CmpMap, CM: CmpMap,
{ {
/// Get the number of usable cmps (all by default) /// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize { fn usable_count(&self) -> usize {
match &self.size { match &self.size {
None => self.map().len(), None => self.map.as_ref().len(),
Some(o) => *o.as_ref(), Some(o) => *o.as_ref(),
} }
} }
@ -202,19 +201,11 @@ where
} }
} }
impl<'a, CM> Observer for StdCmpObserver<'a, CM> where CM: CmpMap {} impl<'a, CM, I, S> Observer<I, S> for StdCmpObserver<'a, CM>
impl<'a, CM, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for StdCmpObserver<'a, CM>
where where
CM: CmpMap, CM: CmpMap,
{ {
fn pre_exec( fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
self.map.as_mut().reset()?; self.map.as_mut().reset()?;
Ok(()) Ok(())
} }

View File

@ -12,13 +12,12 @@ use crate::{
ownedref::{OwnedRefMut, OwnedSliceMut}, ownedref::{OwnedRefMut, OwnedSliceMut},
tuples::Named, tuples::Named,
}, },
executors::HasExecHooks,
observers::Observer, observers::Observer,
Error, Error,
}; };
/// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information /// A [`MapObserver`] observes the static map, as oftentimes used for afl-like coverage information
pub trait MapObserver<T>: Observer pub trait MapObserver<T>: Named + serde::Serialize + serde::de::DeserializeOwned
where where
T: Default + Copy, T: Default + Copy,
{ {
@ -70,24 +69,13 @@ where
name: String, name: String,
} }
impl<'a, T> Observer for StdMapObserver<'a, T> where impl<'a, I, S, T> Observer<I, S> for StdMapObserver<'a, T>
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
{
}
impl<'a, EM, I, S, T, Z> HasExecHooks<EM, I, S, Z> for StdMapObserver<'a, T>
where where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
Self: MapObserver<T>, Self: MapObserver<T>,
{ {
#[inline] #[inline]
fn pre_exec( fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -186,24 +174,13 @@ where
name: String, name: String,
} }
impl<'a, T, const N: usize> Observer for ConstMapObserver<'a, T, N> where impl<'a, I, S, T, const N: usize> Observer<I, S> for ConstMapObserver<'a, T, N>
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
{
}
impl<'a, EM, I, S, T, Z, const N: usize> HasExecHooks<EM, I, S, Z> for ConstMapObserver<'a, T, N>
where where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
Self: MapObserver<T>, Self: MapObserver<T>,
{ {
#[inline] #[inline]
fn pre_exec( fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -309,23 +286,13 @@ where
name: String, name: String,
} }
impl<'a, T> Observer for VariableMapObserver<'a, T> where impl<'a, I, S, T> Observer<I, S> for VariableMapObserver<'a, T>
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned
{
}
impl<'a, EM, I, S, T, Z> HasExecHooks<EM, I, S, Z> for VariableMapObserver<'a, T>
where where
T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned, T: Default + Copy + 'static + serde::Serialize + serde::de::DeserializeOwned,
Self: MapObserver<T>,
{ {
#[inline] #[inline]
fn pre_exec( fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
self.reset_map() self.reset_map()
} }
} }
@ -435,36 +402,22 @@ static COUNT_CLASS_LOOKUP: [u8; 256] = [
128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128, 128,
]; ];
impl<M> Observer for HitcountsMapObserver<M> where M: MapObserver<u8> {} impl<I, S, M> Observer<I, S> for HitcountsMapObserver<M>
impl<EM, I, S, M, Z> HasExecHooks<EM, I, S, Z> for HitcountsMapObserver<M>
where where
M: MapObserver<u8> + HasExecHooks<EM, I, S, Z>, M: MapObserver<u8> + Observer<I, S>,
{ {
#[inline] #[inline]
fn pre_exec( fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
&mut self, self.base.pre_exec(state, input)
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
self.base.pre_exec(fuzzer, state, mgr, input)
} }
#[inline] #[inline]
fn post_exec( fn post_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
&mut self,
fuzzer: &mut Z,
state: &mut S,
mgr: &mut EM,
input: &I,
) -> Result<(), Error> {
let cnt = self.usable_count(); let cnt = self.usable_count();
for x in self.map_mut()[0..cnt].iter_mut() { for x in self.map_mut()[0..cnt].iter_mut() {
*x = COUNT_CLASS_LOOKUP[*x as usize]; *x = COUNT_CLASS_LOOKUP[*x as usize];
} }
self.base.post_exec(fuzzer, state, mgr, input) self.base.post_exec(state, input)
} }
} }

View File

@ -15,31 +15,65 @@ use crate::{
current_time, current_time,
tuples::{MatchName, Named}, tuples::{MatchName, Named},
}, },
executors::HasExecHooks,
Error, Error,
}; };
/// Observers observe different information about the target. /// Observers observe different information about the target.
/// They can then be used by various sorts of feedback. /// They can then be used by various sorts of feedback.
pub trait Observer: Named + serde::Serialize + serde::de::DeserializeOwned { pub trait Observer<I, S>: Named + serde::Serialize + serde::de::DeserializeOwned {
/// The testcase finished execution, calculate any changes. /// The testcase finished execution, calculate any changes.
/// Reserved for future use. /// Reserved for future use.
#[inline] #[inline]
fn flush(&mut self) -> Result<(), Error> { fn flush(&mut self) -> Result<(), Error> {
Ok(()) Ok(())
} }
/// Called right before exexution starts
#[inline]
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
Ok(())
}
/// Called right after execution finished.
#[inline]
fn post_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
Ok(())
}
} }
/// A haskell-style tuple of observers /// A haskell-style tuple of observers
pub trait ObserversTuple: MatchName + serde::Serialize + serde::de::DeserializeOwned {} pub trait ObserversTuple<I, S>: MatchName + serde::Serialize + serde::de::DeserializeOwned {
/// This is called right before the next execution.
fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error>;
impl ObserversTuple for () {} /// This is called right after the last execution
fn post_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error>;
}
impl<Head, Tail> ObserversTuple for (Head, Tail) impl<I, S> ObserversTuple<I, S> for () {
fn pre_exec_all(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
Ok(())
}
fn post_exec_all(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
Ok(())
}
}
impl<Head, Tail, I, S> ObserversTuple<I, S> for (Head, Tail)
where where
Head: Observer, Head: Observer<I, S>,
Tail: ObserversTuple, Tail: ObserversTuple<I, S>,
{ {
fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
self.0.pre_exec(state, input)?;
self.1.pre_exec_all(state, input)
}
fn post_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> {
self.0.post_exec(state, input)?;
self.1.post_exec_all(state, input)
}
} }
/// A simple observer, just overlooking the runtime of the target. /// A simple observer, just overlooking the runtime of the target.
@ -68,28 +102,14 @@ impl TimeObserver {
} }
} }
impl Observer for TimeObserver {} impl<I, S> Observer<I, S> for TimeObserver {
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
impl<EM, I, S, Z> HasExecHooks<EM, I, S, Z> for TimeObserver {
fn pre_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
self.last_runtime = None; self.last_runtime = None;
self.start_time = current_time(); self.start_time = current_time();
Ok(()) Ok(())
} }
fn post_exec( fn post_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
self.last_runtime = current_time().checked_sub(self.start_time); self.last_runtime = current_time().checked_sub(self.start_time);
Ok(()) Ok(())
} }

View File

@ -2,7 +2,7 @@ use core::{marker::PhantomData, mem::drop};
use crate::{ use crate::{
corpus::Corpus, corpus::Corpus,
executors::{Executor, HasExecHooksTuple, HasObservers, HasObserversHooks, ShadowExecutor}, executors::{Executor, HasObservers, ShadowExecutor},
inputs::Input, inputs::Input,
mark_feature_time, mark_feature_time,
observers::ObserversTuple, observers::ObserversTuple,
@ -21,8 +21,8 @@ pub struct TracingStage<C, EM, I, OT, S, TE, Z>
where where
I: Input, I: Input,
C: Corpus<I>, C: Corpus<I>,
TE: Executor<EM, I, S, Z> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Z>, TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>, OT: ObserversTuple<I, S>,
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>, S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
{ {
tracer_executor: TE, tracer_executor: TE,
@ -34,8 +34,8 @@ impl<E, C, EM, I, OT, S, TE, Z> Stage<E, EM, S, Z> for TracingStage<C, EM, I, OT
where where
I: Input, I: Input,
C: Corpus<I>, C: Corpus<I>,
TE: Executor<EM, I, S, Z> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Z>, TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>, OT: ObserversTuple<I, S>,
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>, S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
{ {
#[inline] #[inline]
@ -58,7 +58,8 @@ where
start_timer!(state); start_timer!(state);
self.tracer_executor self.tracer_executor
.pre_exec_observers(fuzzer, state, manager, &input)?; .observers_mut()
.pre_exec_all(state, &input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers); mark_feature_time!(state, PerfFeature::PreExecObservers);
start_timer!(state); start_timer!(state);
@ -72,7 +73,8 @@ where
start_timer!(state); start_timer!(state);
self.tracer_executor self.tracer_executor
.post_exec_observers(fuzzer, state, manager, &input)?; .observers_mut()
.post_exec_all(state, &input)?;
mark_feature_time!(state, PerfFeature::PostExecObservers); mark_feature_time!(state, PerfFeature::PostExecObservers);
Ok(()) Ok(())
@ -83,8 +85,8 @@ impl<C, EM, I, OT, S, TE, Z> TracingStage<C, EM, I, OT, S, TE, Z>
where where
I: Input, I: Input,
C: Corpus<I>, C: Corpus<I>,
TE: Executor<EM, I, S, Z> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Z>, TE: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>, OT: ObserversTuple<I, S>,
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>, S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
{ {
/// Creates a new default stage /// Creates a new default stage
@ -103,21 +105,21 @@ pub struct ShadowTracingStage<C, E, EM, I, OT, S, SOT, Z> {
phantom: PhantomData<(C, E, EM, I, OT, S, SOT, Z)>, phantom: PhantomData<(C, E, EM, I, OT, S, SOT, Z)>,
} }
impl<C, E, EM, I, OT, S, SOT, Z> Stage<ShadowExecutor<E, SOT>, EM, S, Z> impl<C, E, EM, I, OT, S, SOT, Z> Stage<ShadowExecutor<E, I, S, SOT>, EM, S, Z>
for ShadowTracingStage<C, E, EM, I, OT, S, SOT, Z> for ShadowTracingStage<C, E, EM, I, OT, S, SOT, Z>
where where
I: Input, I: Input,
C: Corpus<I>, C: Corpus<I>,
E: Executor<EM, I, S, Z> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Z>, E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>, OT: ObserversTuple<I, S>,
SOT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>, SOT: ObserversTuple<I, S>,
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>, S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
{ {
#[inline] #[inline]
fn perform( fn perform(
&mut self, &mut self,
fuzzer: &mut Z, fuzzer: &mut Z,
executor: &mut ShadowExecutor<E, SOT>, executor: &mut ShadowExecutor<E, I, S, SOT>,
state: &mut S, state: &mut S,
manager: &mut EM, manager: &mut EM,
corpus_idx: usize, corpus_idx: usize,
@ -131,11 +133,11 @@ where
.clone(); .clone();
mark_feature_time!(state, PerfFeature::GetInputFromCorpus); mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
let prev_shadow_hooks = *executor.shadow_hooks();
*executor.shadow_hooks_mut() = true;
start_timer!(state); start_timer!(state);
executor.pre_exec_observers(fuzzer, state, manager, &input)?; executor
.shadow_observers_mut()
.pre_exec_all(state, &input)?;
executor.observers_mut().pre_exec_all(state, &input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers); mark_feature_time!(state, PerfFeature::PreExecObservers);
start_timer!(state); start_timer!(state);
@ -145,11 +147,12 @@ where
*state.executions_mut() += 1; *state.executions_mut() += 1;
start_timer!(state); start_timer!(state);
executor.post_exec_observers(fuzzer, state, manager, &input)?; executor
.shadow_observers_mut()
.post_exec_all(state, &input)?;
executor.observers_mut().post_exec_all(state, &input)?;
mark_feature_time!(state, PerfFeature::PostExecObservers); mark_feature_time!(state, PerfFeature::PostExecObservers);
*executor.shadow_hooks_mut() = prev_shadow_hooks;
Ok(()) Ok(())
} }
} }
@ -158,13 +161,13 @@ impl<C, E, EM, I, OT, S, SOT, Z> ShadowTracingStage<C, E, EM, I, OT, S, SOT, Z>
where where
I: Input, I: Input,
C: Corpus<I>, C: Corpus<I>,
E: Executor<EM, I, S, Z> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Z>, E: Executor<EM, I, S, Z> + HasObservers<I, OT, S>,
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>, OT: ObserversTuple<I, S>,
SOT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>, SOT: ObserversTuple<I, S>,
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>, S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
{ {
/// Creates a new default stage /// Creates a new default stage
pub fn new(_executor: &mut ShadowExecutor<E, SOT>) -> Self { pub fn new(_executor: &mut ShadowExecutor<E, I, S, SOT>) -> Self {
Self { Self {
phantom: PhantomData, phantom: PhantomData,
} }

View File

@ -14,9 +14,9 @@ use crate::{
serdeany::{SerdeAny, SerdeAnyMap}, serdeany::{SerdeAny, SerdeAnyMap},
}, },
corpus::Corpus, corpus::Corpus,
events::{Event, EventManager, LogSeverity}, events::{Event, EventFirer, LogSeverity},
feedbacks::FeedbackStatesTuple, feedbacks::FeedbackStatesTuple,
fuzzer::Evaluator, fuzzer::{Evaluator, ExecuteInputResult},
generators::Generator, generators::Generator,
inputs::Input, inputs::Input,
stats::ClientPerfStats, stats::ClientPerfStats,
@ -385,9 +385,8 @@ where
if forced { if forced {
let _ = fuzzer.add_input(self, executor, manager, input)?; let _ = fuzzer.add_input(self, executor, manager, input)?;
} else { } else {
let (is_interesting, _) = let (res, _) = fuzzer.evaluate_input(self, executor, manager, input)?;
fuzzer.evaluate_input(self, executor, manager, input)?; if res == ExecuteInputResult::None {
if !is_interesting {
println!("File {:?} was not interesting, skipped.", &path); println!("File {:?} was not interesting, skipped.", &path);
} }
} }
@ -411,7 +410,7 @@ where
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Evaluator<E, EM, I, Self>, Z: Evaluator<E, EM, I, Self>,
EM: EventManager<E, I, Self, Z>, EM: EventFirer<I, Self>,
{ {
for in_dir in in_dirs { for in_dir in in_dirs {
self.load_from_directory(fuzzer, executor, manager, in_dir, forced)?; self.load_from_directory(fuzzer, executor, manager, in_dir, forced)?;
@ -424,7 +423,6 @@ where
phantom: PhantomData, phantom: PhantomData,
}, },
)?; )?;
manager.process(fuzzer, self, executor)?;
Ok(()) Ok(())
} }
@ -440,7 +438,7 @@ where
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Evaluator<E, EM, I, Self>, Z: Evaluator<E, EM, I, Self>,
EM: EventManager<E, I, Self, Z>, EM: EventFirer<I, Self>,
{ {
self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, true) self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, true)
} }
@ -455,7 +453,7 @@ where
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Evaluator<E, EM, I, Self>, Z: Evaluator<E, EM, I, Self>,
EM: EventManager<E, I, Self, Z>, EM: EventFirer<I, Self>,
{ {
self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, false) self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, false)
} }
@ -481,13 +479,13 @@ where
where where
G: Generator<I, R>, G: Generator<I, R>,
Z: Evaluator<E, EM, I, Self>, Z: Evaluator<E, EM, I, Self>,
EM: EventManager<E, I, Self, Z>, EM: EventFirer<I, Self>,
{ {
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 (is_interesting, _) = fuzzer.evaluate_input(self, executor, manager, input)?; let (res, _) = fuzzer.evaluate_input(self, executor, manager, input)?;
if is_interesting { if res != ExecuteInputResult::None {
added += 1; added += 1;
} }
} }
@ -499,7 +497,6 @@ where
phantom: PhantomData, phantom: PhantomData,
}, },
)?; )?;
manager.process(fuzzer, self, executor)?;
Ok(()) Ok(())
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libafl_cc" name = "libafl_cc"
version = "0.3.2" version = "0.4.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
description = "Commodity library to wrap compilers and link LibAFL" description = "Commodity library to wrap compilers and link LibAFL"
documentation = "https://docs.rs/libafl_cc" documentation = "https://docs.rs/libafl_cc"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libafl_derive" name = "libafl_derive"
version = "0.3.2" version = "0.4.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
description = "Derive proc-macro crate for LibAFL" description = "Derive proc-macro crate for LibAFL"
documentation = "https://docs.rs/libafl_derive" documentation = "https://docs.rs/libafl_derive"

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libafl_frida" name = "libafl_frida"
version = "0.3.2" version = "0.4.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"
@ -19,8 +19,8 @@ cmplog = []
cc = { version = "1.0", features = ["parallel"] } cc = { version = "1.0", features = ["parallel"] }
[dependencies] [dependencies]
libafl = { path = "../libafl", version = "0.3.1", features = ["std", "libafl_derive"] } libafl = { path = "../libafl", version = "0.4.0", features = ["std", "libafl_derive"] }
libafl_targets = { path = "../libafl_targets", version = "0.3.2", features = ["sancov_cmplog"] } libafl_targets = { path = "../libafl_targets", version = "0.4.0", features = ["sancov_cmplog"] }
nix = "0.20.0" nix = "0.20.0"
libc = "0.2.92" libc = "0.2.92"
hashbrown = "0.11" hashbrown = "0.11"

View File

@ -9,7 +9,7 @@ use libafl::{
bolts::{ownedref::OwnedPtr, tuples::Named}, bolts::{ownedref::OwnedPtr, tuples::Named},
corpus::Testcase, corpus::Testcase,
events::EventFirer, events::EventFirer,
executors::{ExitKind, HasExecHooks}, executors::ExitKind,
feedbacks::Feedback, feedbacks::Feedback,
inputs::{HasTargetBytes, Input}, inputs::{HasTargetBytes, Input},
observers::{Observer, ObserversTuple}, observers::{Observer, ObserversTuple},
@ -447,16 +447,8 @@ pub struct AsanErrorsObserver {
errors: OwnedPtr<Option<AsanErrors>>, errors: OwnedPtr<Option<AsanErrors>>,
} }
impl Observer for AsanErrorsObserver {} impl<I, S> Observer<I, S> for AsanErrorsObserver {
fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
impl<EM, I, S, Z> HasExecHooks<EM, I, S, Z> for AsanErrorsObserver {
fn pre_exec(
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
unsafe { unsafe {
if ASAN_ERRORS.is_some() { if ASAN_ERRORS.is_some() {
ASAN_ERRORS.as_mut().unwrap().clear(); ASAN_ERRORS.as_mut().unwrap().clear();
@ -529,7 +521,7 @@ where
) -> Result<bool, Error> ) -> Result<bool, Error>
where where
EM: EventFirer<I, S>, EM: EventFirer<I, S>,
OT: ObserversTuple, OT: ObserversTuple<I, S>,
{ {
let observer = observers let observer = observers
.match_name::<AsanErrorsObserver>("AsanErrors") .match_name::<AsanErrorsObserver>("AsanErrors")

View File

@ -1946,6 +1946,7 @@ impl AsanRuntime {
let backtrace = Backtrace::new(); let backtrace = Backtrace::new();
let (stack_start, stack_end) = Self::current_stack(); let (stack_start, stack_end) = Self::current_stack();
#[allow(clippy::option_if_let_else)]
let error = if fault_address >= stack_start && fault_address < stack_end { let error = if fault_address >= stack_start && fault_address < stack_end {
if insn.mnemonic().unwrap().starts_with('l') { if insn.mnemonic().unwrap().starts_with('l') {
AsanError::StackOobRead(( AsanError::StackOobRead((
@ -1962,38 +1963,35 @@ impl AsanRuntime {
backtrace, backtrace,
)) ))
} }
} else { } else if let Some(metadata) = self
#[allow(clippy::option_if_let_else)] .allocator
if let Some(metadata) = self .find_metadata(fault_address, self.regs[base_reg as usize])
.allocator {
.find_metadata(fault_address, self.regs[base_reg as usize]) let asan_readwrite_error = AsanReadWriteError {
{ registers: self.regs,
let asan_readwrite_error = AsanReadWriteError { pc: actual_pc,
registers: self.regs, fault: (base_reg, index_reg, displacement as usize, fault_address),
pc: actual_pc, metadata: metadata.clone(),
fault: (base_reg, index_reg, displacement as usize, fault_address), backtrace,
metadata: metadata.clone(), };
backtrace, if insn.mnemonic().unwrap().starts_with('l') {
}; if metadata.freed {
if insn.mnemonic().unwrap().starts_with('l') { AsanError::ReadAfterFree(asan_readwrite_error)
if metadata.freed {
AsanError::ReadAfterFree(asan_readwrite_error)
} else {
AsanError::OobRead(asan_readwrite_error)
}
} else if metadata.freed {
AsanError::WriteAfterFree(asan_readwrite_error)
} else { } else {
AsanError::OobWrite(asan_readwrite_error) AsanError::OobRead(asan_readwrite_error)
} }
} else if metadata.freed {
AsanError::WriteAfterFree(asan_readwrite_error)
} else { } else {
AsanError::Unknown(( AsanError::OobWrite(asan_readwrite_error)
self.regs,
actual_pc,
(base_reg, index_reg, displacement as usize, fault_address),
backtrace,
))
} }
} else {
AsanError::Unknown((
self.regs,
actual_pc,
(base_reg, index_reg, displacement as usize, fault_address),
backtrace,
))
}; };
AsanErrors::get_mut().report_error(error); AsanErrors::get_mut().report_error(error);
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libafl_targets" name = "libafl_targets"
version = "0.3.2" version = "0.4.0"
authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"] authors = ["Andrea Fioraldi <andreafioraldi@gmail.com>"]
description = "Common code for target instrumentation that can be used combined with LibAFL" description = "Common code for target instrumentation that can be used combined with LibAFL"
documentation = "https://docs.rs/libafl_targets" documentation = "https://docs.rs/libafl_targets"
@ -25,6 +25,6 @@ cc = { version = "1.0", features = ["parallel"] }
[dependencies] [dependencies]
rangemap = "0.1.10" rangemap = "0.1.10"
libafl = { path = "../libafl", version = "0.3.2", features = [] } libafl = { path = "../libafl", version = "0.4.0", features = [] }
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
serde-big-array = "0.3.2" serde-big-array = "0.3.2"

View File

@ -3,7 +3,6 @@
use libafl::{ use libafl::{
bolts::{ownedref::OwnedRefMut, tuples::Named}, bolts::{ownedref::OwnedRefMut, tuples::Named},
executors::HasExecHooks,
observers::{CmpMap, CmpObserver, CmpValues, Observer}, observers::{CmpMap, CmpObserver, CmpValues, Observer},
state::HasMetadata, state::HasMetadata,
Error, Error,
@ -146,11 +145,14 @@ pub struct CmpLogObserver<'a> {
name: String, name: String,
} }
impl<'a> CmpObserver<CmpLogMap> for CmpLogObserver<'a> { impl<'a, I, S> CmpObserver<CmpLogMap, I, S> for CmpLogObserver<'a>
where
S: HasMetadata,
{
/// Get the number of usable cmps (all by default) /// Get the number of usable cmps (all by default)
fn usable_count(&self) -> usize { fn usable_count(&self) -> usize {
match &self.size { match &self.size {
None => self.map().len(), None => self.map.as_ref().len(),
Some(o) => *o.as_ref(), Some(o) => *o.as_ref(),
} }
} }
@ -164,19 +166,12 @@ impl<'a> CmpObserver<CmpLogMap> for CmpLogObserver<'a> {
} }
} }
impl<'a> Observer for CmpLogObserver<'a> {} impl<'a, I, S> Observer<I, S> for CmpLogObserver<'a>
impl<'a, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for CmpLogObserver<'a>
where where
S: HasMetadata, S: HasMetadata,
Self: CmpObserver<CmpLogMap, I, S>,
{ {
fn pre_exec( fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> {
&mut self,
_fuzzer: &mut Z,
_state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
self.map.as_mut().reset()?; self.map.as_mut().reset()?;
unsafe { unsafe {
CMPLOG_ENABLED = 1; CMPLOG_ENABLED = 1;
@ -184,13 +179,7 @@ where
Ok(()) Ok(())
} }
fn post_exec( fn post_exec(&mut self, state: &mut S, _input: &I) -> Result<(), Error> {
&mut self,
_fuzzer: &mut Z,
state: &mut S,
_mgr: &mut EM,
_input: &I,
) -> Result<(), Error> {
unsafe { unsafe {
CMPLOG_ENABLED = 0; CMPLOG_ENABLED = 0;
} }

View File

@ -1,6 +1,6 @@
[package] [package]
name = "libafl_tests" name = "libafl_tests"
version = "0.1.0" version = "0.4.0"
authors = ["tokatoka <tokazerkje@outlook.com>"] authors = ["tokatoka <tokazerkje@outlook.com>"]
edition = "2018" edition = "2018"