Track parent testcase id, tuneable stage probabilistic settings (#1081)

* Added local event handlers

* clippy

* move tuned mutator to pow2

* Tunable updates

* parent ids

* no_std, etc

* windows

* remove local event manager handler

* maybe fix win

* win:

* win docs

* docs

* ASAN -> ASan
This commit is contained in:
Dominik Maier 2023-02-28 16:36:04 +01:00 committed by GitHub
parent 3e7322e395
commit 31357aa7e2
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
15 changed files with 276 additions and 103 deletions

View File

@ -113,47 +113,47 @@ fn parse_instrumentation_location(
)] )]
#[allow(clippy::struct_excessive_bools)] #[allow(clippy::struct_excessive_bools)]
pub struct FuzzerOptions { pub struct FuzzerOptions {
/// timeout for each target execution (milliseconds) /// Timeout for each target execution (milliseconds)
#[arg(short, long, default_value = "1000", value_parser = parse_timeout, help_heading = "Fuzz Options")] #[arg(short, long, default_value = "1000", value_parser = parse_timeout, help_heading = "Fuzz Options")]
pub timeout: Duration, pub timeout: Duration,
/// whether or not to print debug info /// Whether or not to print debug info
#[arg(short, long)] #[arg(short, long)]
pub verbose: bool, pub verbose: bool,
/// file to which all client output should be written /// File to which all client output should be written
#[arg(short, long, default_value = "/dev/null")] #[arg(short, long, default_value = "/dev/null")]
pub stdout: String, pub stdout: String,
/// the name of the configuration to use /// The name of the configuration to use
#[arg(long, default_value = "default configuration")] #[arg(long, default_value = "default configuration")]
pub configuration: String, pub configuration: String,
/// enable Address Sanitizer (ASAN) /// Enable Address Sanitizer (`ASan`)
#[arg(short = 'A', long, help_heading = "Fuzz Options")] #[arg(short = 'A', long, help_heading = "Fuzz Options")]
pub asan: bool, pub asan: bool,
/// Enable ASAN on each of the provided cores. Use 'all' to select all available /// Enable `ASan` on each of the provided cores. Use 'all' to select all available
/// cores. 'none' to run a client without binding to any core. /// cores. 'none' to run a client without binding to any core.
/// ex: '1,2-4,6' selects the cores 1, 2, 3, 4, and 6. /// ex: '1,2-4,6' selects the cores 1, 2, 3, 4, and 6.
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(long, default_value = "0", value_parser = Cores::from_cmdline, help_heading = "Cores that should use ASAN")] #[arg(long, default_value = "0", value_parser = Cores::from_cmdline, help_heading = "Cores that should use ASan")]
pub asan_cores: Cores, pub asan_cores: Cores,
/// number of fuzz iterations to perform /// Number of fuzz iterations to perform
#[arg(short = 'I', long, help_heading = "Fuzz Options", default_value = "0")] #[arg(short = 'I', long, help_heading = "Fuzz Options", default_value = "0")]
pub iterations: usize, pub iterations: usize,
/// path to the harness /// Path to the harness
#[arg(short = 'H', long, help_heading = "Fuzz Options")] #[arg(short = 'H', long, help_heading = "Fuzz Options")]
pub harness: Option<PathBuf>, pub harness: Option<PathBuf>,
/// trailing arguments (after "--"); can be passed directly to the harness /// Trailing arguments (after "`--`"); can be passed directly to the harness
#[cfg(not(feature = "qemu_cli"))] #[cfg(not(feature = "qemu_cli"))]
#[arg(last = true, value_name = "HARNESS_ARGS")] #[arg(last = true, value_name = "HARNESS_ARGS")]
pub harness_args: Vec<String>, pub harness_args: Vec<String>,
/// harness function to call /// Harness function to call
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg( #[arg(
short = 'F', short = 'F',
@ -163,12 +163,12 @@ pub struct FuzzerOptions {
)] )]
pub harness_function: String, pub harness_function: String,
/// additional libraries to instrument /// Additional libraries to instrument
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(short, long, help_heading = "Frida Options")] #[arg(short, long, help_heading = "Frida Options")]
pub libs_to_instrument: Vec<String>, pub libs_to_instrument: Vec<String>,
/// enable CmpLog instrumentation /// Enable `CmpLog` instrumentation
#[cfg_attr( #[cfg_attr(
feature = "frida_cli", feature = "frida_cli",
arg(short = 'C', long, help_heading = "Frida Options") arg(short = 'C', long, help_heading = "Frida Options")
@ -179,85 +179,85 @@ pub struct FuzzerOptions {
)] )]
pub cmplog: bool, pub cmplog: bool,
/// Enable CmpLog on each of the provided cores. Use 'all' to select all available /// Enable `CmpLog` on each of the provided cores. Use 'all' to select all available
/// cores. 'none' to run a client without binding to any core. /// cores. 'none' to run a client without binding to any core.
/// ex: '1,2-4,6' selects the cores 1, 2, 3, 4, and 6. /// ex: '1,2-4,6' selects the cores 1, 2, 3, 4, and 6.
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(long, default_value = "0", value_parser = Cores::from_cmdline, help_heading = "Frida Options")] #[arg(long, default_value = "0", value_parser = Cores::from_cmdline, help_heading = "Frida Options")]
pub cmplog_cores: Cores, pub cmplog_cores: Cores,
/// enable ASAN leak detection /// Enable `ASan` leak detection
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(short, long, help_heading = "ASAN Options")] #[arg(short, long, help_heading = "ASan Options")]
pub detect_leaks: bool, pub detect_leaks: bool,
/// instruct ASAN to continue after a memory error is detected /// Instruct `ASan` to continue after a memory error is detected
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(long, help_heading = "ASAN Options")] #[arg(long, help_heading = "ASan Options")]
pub continue_on_error: bool, pub continue_on_error: bool,
/// instruct ASAN to gather (and report) allocation-/free-site backtraces /// Instruct `ASan` to gather (and report) allocation-/free-site backtraces
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(long, help_heading = "ASAN Options")] #[arg(long, help_heading = "ASan Options")]
pub allocation_backtraces: bool, pub allocation_backtraces: bool,
/// the maximum size that the ASAN allocator should allocate /// The maximum size that the `ASan` allocator should allocate
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg( #[arg(
short, short,
long, long,
default_value = "1073741824", // 1_usize << 30 default_value = "1073741824", // 1_usize << 30
help_heading = "ASAN Options" help_heading = "ASan Options"
)] )]
pub max_allocation: usize, pub max_allocation: usize,
/// the maximum total allocation size that the ASAN allocator should allocate /// The maximum total allocation size that the `ASan` allocator should allocate
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg( #[arg(
short = 'M', short = 'M',
long, long,
default_value = "4294967296", // 1_usize << 32 default_value = "4294967296", // 1_usize << 32
help_heading = "ASAN Options" help_heading = "ASan Options"
)] )]
pub max_total_allocation: usize, pub max_total_allocation: usize,
/// instruct ASAN to panic if the max ASAN allocation size is exceeded /// Instruct `ASan` to panic if the max `ASan` allocation size is exceeded
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(long, help_heading = "ASAN Options")] #[arg(long, help_heading = "ASan Options")]
pub max_allocation_panics: bool, pub max_allocation_panics: bool,
/// disable coverage /// Disable coverage
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(long, help_heading = "Frida Options")] #[arg(long, help_heading = "Frida Options")]
pub disable_coverage: bool, pub disable_coverage: bool,
/// enable DrCov (aarch64 only) /// Enable `DrCov` (aarch64 only)
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(long, help_heading = "Frida Options")] #[arg(long, help_heading = "Frida Options")]
pub drcov: bool, pub drcov: bool,
/// disable stalker.exclude() if true /// Disable `stalker.exclude()` if `true`
/// It's better to disable this on windows or your harness uses c++ exception handling /// It's better to disable this on Windows or your harness uses c++ exception handling
/// See https://github.com/AFLplusplus/LibAFL/issues/830 /// See <https://github.com/AFLplusplus/LibAFL/issues/830>
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(long, help_heading = "Frida Options")] #[arg(long, help_heading = "Frida Options")]
pub disable_excludes: bool, pub disable_excludes: bool,
/// locations which will not be instrumented for ASAN or coverage purposes (ex: mod_name@0x12345) /// Locations which will not be instrumented for `ASan` or coverage purposes (ex: `mod_name@0x12345`)
#[cfg(feature = "frida_cli")] #[cfg(feature = "frida_cli")]
#[arg(short = 'D', long, help_heading = "Frida Options", value_parser = parse_instrumentation_location)] #[arg(short = 'D', long, help_heading = "Frida Options", value_parser = parse_instrumentation_location)]
pub dont_instrument: Vec<(String, usize)>, pub dont_instrument: Vec<(String, usize)>,
/// trailing arguments (after "--"); can be passed directly to QEMU /// Trailing arguments (after "`--`"); can be passed directly to QEMU
#[cfg(feature = "qemu_cli")] #[cfg(feature = "qemu_cli")]
#[arg(last = true)] #[arg(last = true)]
pub qemu_args: Vec<String>, pub qemu_args: Vec<String>,
/// paths to fuzzer token files (aka 'dictionaries') /// Paths to fuzzer token files (aka 'dictionaries')
#[arg(short = 'x', long, help_heading = "Fuzz Options")] #[arg(short = 'x', long, help_heading = "Fuzz Options")]
pub tokens: Vec<PathBuf>, pub tokens: Vec<PathBuf>,
/// input corpus directories /// Input corpus directories
#[arg( #[arg(
short, short,
long, long,
@ -266,7 +266,7 @@ pub struct FuzzerOptions {
)] )]
pub input: Vec<PathBuf>, pub input: Vec<PathBuf>,
/// output solutions directory /// Output solutions directory
#[arg( #[arg(
short, short,
long, long,
@ -281,15 +281,15 @@ pub struct FuzzerOptions {
#[arg(short = 'c', long, default_value = "0", value_parser = Cores::from_cmdline)] #[arg(short = 'c', long, default_value = "0", value_parser = Cores::from_cmdline)]
pub cores: Cores, pub cores: Cores,
/// port on which the broker should listen /// Port on which the broker should listen
#[arg(short = 'p', long, default_value = "1337", value_name = "PORT")] #[arg(short = 'p', long, default_value = "1337", value_name = "PORT")]
pub broker_port: u16, pub broker_port: u16,
/// ip:port where a remote broker is already listening /// `ip:port` where a remote broker is already listening
#[arg(short = 'a', long, value_name = "REMOTE")] #[arg(short = 'a', long, value_name = "REMOTE")]
pub remote_broker_addr: Option<SocketAddr>, pub remote_broker_addr: Option<SocketAddr>,
/// path to file that should be sent to the harness for crash reproduction /// Path to file that should be sent to the harness for crash reproduction
#[arg(short, long, help_heading = "Replay Options")] #[arg(short, long, help_heading = "Replay Options")]
pub replay: Option<PathBuf>, pub replay: Option<PathBuf>,
@ -305,7 +305,7 @@ pub struct FuzzerOptions {
} }
impl FuzzerOptions { impl FuzzerOptions {
/// given an `App`, add it to `FuzzerOptions` as a subcommand and return the resulting `App` /// Given an `App`, add it to `FuzzerOptions` as a subcommand and return the resulting `App`
/// ///
/// # Examples /// # Examples
/// ///
@ -354,7 +354,7 @@ impl FuzzerOptions {
/// Parse from `std::env::args_os()`, exit on error /// Parse from `std::env::args_os()`, exit on error
/// ///
/// for more information, see the [cli](super::cli) documentation /// For more information, see the [cli](super::cli) documentation
#[must_use] #[must_use]
pub fn parse_args() -> FuzzerOptions { pub fn parse_args() -> FuzzerOptions {
FuzzerOptions::parse() FuzzerOptions::parse()

View File

@ -30,7 +30,7 @@ pub mod staterestore;
pub mod tuples; pub mod tuples;
use alloc::{string::String, vec::Vec}; use alloc::{string::String, vec::Vec};
use core::{iter::Iterator, time}; use core::{iter::Iterator, ops::AddAssign, time};
#[cfg(feature = "std")] #[cfg(feature = "std")]
use std::time::{SystemTime, UNIX_EPOCH}; use std::time::{SystemTime, UNIX_EPOCH};
@ -216,6 +216,29 @@ pub fn format_duration_hms(duration: &time::Duration) -> String {
format!("{}h-{}m-{}s", (secs / 60) / 60, (secs / 60) % 60, secs % 60) format!("{}h-{}m-{}s", (secs / 60) / 60, (secs / 60) % 60, secs % 60)
} }
/// Calculates the cumulative sum for a slice, in-place.
/// The values are useful for example for cumulative probabilities.
///
/// So, to give an example:
/// ```rust
/// use libafl::bolts::calculate_cumulative_sum_in_place;
///
/// let mut value = [2, 4, 1, 3];
/// calculate_cumulative_sum_in_place(&mut value);
/// assert_eq!(&[2, 6, 7, 10], &value);
/// ```
pub fn calculate_cumulative_sum_in_place<T>(mut_slice: &mut [T])
where
T: Default + AddAssign<T> + Copy,
{
let mut acc = T::default();
for val in mut_slice {
acc += *val;
*val = acc;
}
}
/// A simple logger struct that logs to stderr when used with [`log::set_logger`]. /// A simple logger struct that logs to stderr when used with [`log::set_logger`].
#[derive(Debug)] #[derive(Debug)]
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -1213,7 +1213,7 @@ pub mod win32_shmem {
}, },
}; };
/// The default Sharedmap impl for windows using shmctl & shmget /// The default [`ShMem`] impl for Windows using `shmctl` & `shmget`
#[derive(Clone)] #[derive(Clone)]
pub struct Win32ShMem { pub struct Win32ShMem {
id: ShMemId, id: ShMemId,

View File

@ -8,6 +8,7 @@ use serde::{Deserialize, Serialize};
use crate::{ use crate::{
bolts::{serdeany::SerdeAnyMap, HasLen}, bolts::{serdeany::SerdeAnyMap, HasLen},
corpus::CorpusId,
inputs::Input, inputs::Input,
state::HasMetadata, state::HasMetadata,
Error, Error,
@ -36,6 +37,8 @@ where
fuzz_level: usize, fuzz_level: usize,
/// If it has been fuzzed /// If it has been fuzzed
fuzzed: bool, fuzzed: bool,
/// Parent [`CorpusId`], if known
parent_id: Option<CorpusId>,
} }
impl<I> HasMetadata for Testcase<I> impl<I> HasMetadata for Testcase<I>
@ -183,20 +186,30 @@ where
/// Create a new Testcase instance given an input /// Create a new Testcase instance given an input
#[inline] #[inline]
pub fn new(input: I) -> Self { pub fn new(mut input: I) -> Self {
let mut slf = Testcase { input.wrapped_as_testcase();
Self {
input: Some(input), input: Some(input),
..Testcase::default() ..Testcase::default()
}; }
slf.input.as_mut().unwrap().wrapped_as_testcase(); }
slf
/// Creates a testcase, attaching the id of the parent
/// that this [`Testcase`] was derived from on creation
pub fn with_parent_id(mut input: I, parent_id: CorpusId) -> Self {
input.wrapped_as_testcase();
Self {
input: Some(input),
parent_id: Some(parent_id),
..Testcase::default()
}
} }
/// Create a new Testcase instance given an [`Input`] and a `filename` /// Create a new Testcase instance given an [`Input`] and a `filename`
#[inline] #[inline]
pub fn with_filename(mut input: I, filename: String) -> Self { pub fn with_filename(mut input: I, filename: String) -> Self {
input.wrapped_as_testcase(); input.wrapped_as_testcase();
Testcase { Self {
input: Some(input), input: Some(input),
filename: Some(filename), filename: Some(filename),
..Testcase::default() ..Testcase::default()
@ -207,12 +220,28 @@ where
#[inline] #[inline]
pub fn with_executions(mut input: I, executions: usize) -> Self { pub fn with_executions(mut input: I, executions: usize) -> Self {
input.wrapped_as_testcase(); input.wrapped_as_testcase();
Testcase { Self {
input: Some(input), input: Some(input),
executions, executions,
..Testcase::default() ..Testcase::default()
} }
} }
/// Get the id of the parent, that this testcase was derived from
#[must_use]
pub fn parent_id(&self) -> Option<CorpusId> {
self.parent_id
}
/// Sets the id of the parent, that this testcase was derived from
pub fn set_parent_id(&mut self, parent_id: CorpusId) {
self.parent_id = Some(parent_id);
}
/// Sets the id of the parent, that this testcase was derived from
pub fn set_parent_id_optional(&mut self, parent_id: Option<CorpusId>) {
self.parent_id = parent_id;
}
} }
impl<I> Default for Testcase<I> impl<I> Default for Testcase<I>
@ -231,6 +260,7 @@ where
fuzz_level: 0, fuzz_level: 0,
executions: 0, executions: 0,
fuzzed: false, fuzzed: false,
parent_id: None,
} }
} }
} }
@ -450,6 +480,11 @@ pub mod pybind {
*self.inner.as_ref().executions() *self.inner.as_ref().executions()
} }
#[getter]
fn parent_id(&self) -> Option<usize> {
self.inner.as_ref().parent_id().map(|x| x.0)
}
#[getter] #[getter]
fn fuzz_level(&self) -> usize { fn fuzz_level(&self) -> usize {
self.inner.as_ref().fuzz_level() self.inner.as_ref().fuzz_level()

View File

@ -309,11 +309,15 @@ where
S: UsesInput, S: UsesInput,
SP: ShMemProvider + 'static, SP: ShMemProvider + 'static,
{ {
/// The llmp client for inter process communication
llmp: LlmpClient<SP>, llmp: LlmpClient<SP>,
/// The custom buf handler /// The custom buf handler
custom_buf_handlers: Vec<Box<CustomBufHandlerFn<S>>>, custom_buf_handlers: Vec<Box<CustomBufHandlerFn<S>>>,
#[cfg(feature = "llmp_compression")] #[cfg(feature = "llmp_compression")]
compressor: GzipCompressor, compressor: GzipCompressor,
/// The configuration defines this specific fuzzer.
/// A node will not re-use the observer values sent over `LLMP`
/// from nodes with other configurations.
configuration: EventConfig, configuration: EventConfig,
phantom: PhantomData<S>, phantom: PhantomData<S>,
} }
@ -1015,7 +1019,7 @@ where
} }
}; };
// On windows (or in any case without fork), we spawn ourself again // On Windows (or in any case without fork), we spawn ourself again
#[cfg(any(windows, not(feature = "fork")))] #[cfg(any(windows, not(feature = "fork")))]
let child_status = startable_self()?.status()?; let child_status = startable_self()?.status()?;
#[cfg(all(unix, not(feature = "fork")))] #[cfg(all(unix, not(feature = "fork")))]

View File

@ -499,7 +499,7 @@ where
} }
}; };
// On windows (or in any case without forks), we spawn ourself again // On Windows (or in any case without forks), we spawn ourself again
#[cfg(any(windows, not(feature = "fork")))] #[cfg(any(windows, not(feature = "fork")))]
let child_status = startable_self()?.status()?; let child_status = startable_self()?.status()?;
#[cfg(all(unix, not(feature = "fork")))] #[cfg(all(unix, not(feature = "fork")))]

View File

@ -113,7 +113,7 @@ impl CommandConfigurator for StdCommandConfigurator {
debug_assert_eq!(arg, "DUMMY"); debug_assert_eq!(arg, "DUMMY");
#[cfg(unix)] #[cfg(unix)]
cmd.arg(OsStr::from_bytes(input.target_bytes().as_slice())); cmd.arg(OsStr::from_bytes(input.target_bytes().as_slice()));
// There is an issue here that the chars on windows are 16 bit wide. // There is an issue here that the chars on Windows are 16 bit wide.
// I can't really test it. Please open a PR if this goes wrong. // I can't really test it. Please open a PR if this goes wrong.
#[cfg(not(unix))] #[cfg(not(unix))]
cmd.arg(OsString::from_vec(input.target_bytes().as_vec())); cmd.arg(OsString::from_vec(input.target_bytes().as_vec()));

View File

@ -50,7 +50,7 @@ use crate::{
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
observers::{ObserversTuple, UsesObservers}, observers::{ObserversTuple, UsesObservers},
state::{HasClientPerfMonitor, HasSolutions, UsesState}, state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions, UsesState},
Error, Error,
}; };
@ -167,7 +167,7 @@ where
H: FnMut(&<S as UsesInput>::Input) -> ExitKind + ?Sized, H: FnMut(&<S as UsesInput>::Input) -> ExitKind + ?Sized,
HB: BorrowMut<H>, HB: BorrowMut<H>,
OT: ObserversTuple<S>, OT: ObserversTuple<S>,
S: HasSolutions + HasClientPerfMonitor, S: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
{ {
/// 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,
@ -344,7 +344,7 @@ impl InProcessHandlers {
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
#[cfg(unix)] #[cfg(unix)]
@ -543,7 +543,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let observers = executor.observers_mut(); let observers = executor.observers_mut();
@ -559,6 +559,7 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
if interesting { if interesting {
let mut new_testcase = Testcase::new(input.clone()); let mut new_testcase = Testcase::new(input.clone());
new_testcase.set_parent_id_optional(state.fuzzed_corpus_id());
new_testcase.add_metadata(exitkind); new_testcase.add_metadata(exitkind);
fuzzer fuzzer
.objective_mut() .objective_mut()
@ -578,6 +579,9 @@ pub fn run_observers_and_save_state<E, EM, OF, Z>(
.expect("Could not save state in run_observers_and_save_state"); .expect("Could not save state in run_observers_and_save_state");
} }
// We will start mutators from scratch after restart.
state.clear_fuzzed_corpus_id();
event_mgr.on_restart(state).unwrap(); event_mgr.on_restart(state).unwrap();
log::info!("Waiting for broker..."); log::info!("Waiting for broker...");
@ -608,7 +612,7 @@ mod unix_signal_handler {
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
state::{HasClientPerfMonitor, HasSolutions}, state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions},
}; };
pub(crate) type HandlerFuncPtr = pub(crate) type HandlerFuncPtr =
@ -667,7 +671,7 @@ mod unix_signal_handler {
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
@ -708,7 +712,7 @@ mod unix_signal_handler {
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
if !data.is_valid() { if !data.is_valid() {
@ -751,7 +755,7 @@ mod unix_signal_handler {
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
#[cfg(all(target_os = "android", target_arch = "aarch64"))] #[cfg(all(target_os = "android", target_arch = "aarch64"))]
@ -859,7 +863,7 @@ pub mod windows_asan_handler {
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
state::{HasClientPerfMonitor, HasSolutions}, state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions},
}; };
/// # Safety /// # Safety
@ -869,7 +873,7 @@ pub mod windows_asan_handler {
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let mut data = &mut GLOBAL_STATE; let mut data = &mut GLOBAL_STATE;
@ -968,7 +972,7 @@ mod windows_exception_handler {
feedbacks::Feedback, feedbacks::Feedback,
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
state::{HasClientPerfMonitor, HasSolutions}, state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions},
}; };
pub(crate) type HandlerFuncPtr = pub(crate) type HandlerFuncPtr =
@ -1007,7 +1011,7 @@ mod windows_exception_handler {
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let old_hook = panic::take_hook(); let old_hook = panic::take_hook();
@ -1066,7 +1070,7 @@ mod windows_exception_handler {
E: HasObservers, E: HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
let data: &mut InProcessExecutorHandlerData = let data: &mut InProcessExecutorHandlerData =
@ -1127,7 +1131,7 @@ mod windows_exception_handler {
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
// Have we set a timer_before? // Have we set a timer_before?

View File

@ -23,7 +23,10 @@ use crate::{
schedulers::Scheduler, schedulers::Scheduler,
stages::StagesTuple, stages::StagesTuple,
start_timer, start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasSolutions, UsesState}, state::{
HasClientPerfMonitor, HasCorpus, HasExecutions, HasFuzzedCorpusId, HasMetadata,
HasSolutions, UsesState,
},
Error, Error,
}; };
@ -327,7 +330,7 @@ where
F: Feedback<CS::State>, F: Feedback<CS::State>,
OF: Feedback<CS::State>, OF: Feedback<CS::State>,
OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions + HasFuzzedCorpusId,
{ {
/// Evaluate if a set of observation channels has an interesting state /// Evaluate if a set of observation channels has an interesting state
fn process_execution<EM>( fn process_execution<EM>(
@ -384,6 +387,7 @@ where
// Add the input to the main corpus // Add the input to the main corpus
let mut testcase = Testcase::with_executions(input.clone(), *state.executions()); let mut testcase = Testcase::with_executions(input.clone(), *state.executions());
testcase.set_parent_id_optional(state.fuzzed_corpus_id());
self.feedback_mut() self.feedback_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?; let idx = state.corpus_mut().add(testcase)?;
@ -417,6 +421,7 @@ where
// The input is a solution, add it to the respective corpus // The input is a solution, add it to the respective corpus
let mut testcase = Testcase::with_executions(input, *state.executions()); let mut testcase = Testcase::with_executions(input, *state.executions());
testcase.set_parent_id_optional(state.fuzzed_corpus_id());
self.objective_mut() self.objective_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, observers, &mut testcase)?;
state.solutions_mut().add(testcase)?; state.solutions_mut().add(testcase)?;
@ -442,7 +447,7 @@ where
OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
F: Feedback<CS::State>, F: Feedback<CS::State>,
OF: Feedback<CS::State>, OF: Feedback<CS::State>,
CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions + HasFuzzedCorpusId,
{ {
/// Process one input, adding to the respective corpora if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
@ -475,7 +480,7 @@ where
F: Feedback<CS::State>, F: Feedback<CS::State>,
OF: Feedback<CS::State>, OF: Feedback<CS::State>,
OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned, OT: ObserversTuple<CS::State> + Serialize + DeserializeOwned,
CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions + HasFuzzedCorpusId,
{ {
/// Process one input, adding to the respective corpora if needed and firing the right events /// Process one input, adding to the respective corpora if needed and firing the right events
#[inline] #[inline]
@ -513,6 +518,7 @@ where
// Add the input to the main corpus // Add the input to the main corpus
let mut testcase = Testcase::with_executions(input.clone(), *state.executions()); let mut testcase = Testcase::with_executions(input.clone(), *state.executions());
testcase.set_parent_id_optional(state.fuzzed_corpus_id());
self.feedback_mut() self.feedback_mut()
.append_metadata(state, observers, &mut testcase)?; .append_metadata(state, observers, &mut testcase)?;
let idx = state.corpus_mut().add(testcase)?; let idx = state.corpus_mut().add(testcase)?;
@ -546,7 +552,7 @@ where
EM: ProgressReporter + EventProcessor<E, Self, State = CS::State>, EM: ProgressReporter + EventProcessor<E, Self, State = CS::State>,
F: Feedback<CS::State>, F: Feedback<CS::State>,
OF: Feedback<CS::State>, OF: Feedback<CS::State>,
CS::State: HasClientPerfMonitor + HasExecutions + HasMetadata, CS::State: HasClientPerfMonitor + HasExecutions + HasMetadata + HasFuzzedCorpusId,
ST: StagesTuple<E, EM, CS::State, Self>, ST: StagesTuple<E, EM, CS::State, Self>,
{ {
fn fuzz_one( fn fuzz_one(
@ -571,9 +577,15 @@ where
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
state.introspection_monitor_mut().reset_stage_index(); state.introspection_monitor_mut().reset_stage_index();
// Set the parent id - all new testcases will have this id as parent in the following stages.
state.set_fuzzed_corpus_id(idx);
// Execute all stages // Execute all stages
stages.perform_all(self, executor, state, manager, idx)?; stages.perform_all(self, executor, state, manager, idx)?;
// Reset the parent id
state.clear_fuzzed_corpus_id();
// Init timer for manager // Init timer for manager
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
state.introspection_monitor_mut().start_timer(); state.introspection_monitor_mut().start_timer();

View File

@ -12,7 +12,7 @@ use serde::{Deserialize, Serialize};
pub use crate::mutators::{mutations::*, token_mutations::*}; pub use crate::mutators::{mutations::*, token_mutations::*};
use crate::{ use crate::{
bolts::rands::Rand, bolts::{calculate_cumulative_sum_in_place, rands::Rand},
impl_serdeany, impl_serdeany,
mutators::{ mutators::{
ComposedByMutations, MutationId, MutationResult, Mutator, MutatorsTuple, ScheduledMutator, ComposedByMutations, MutationId, MutationResult, Mutator, MutatorsTuple, ScheduledMutator,
@ -33,10 +33,12 @@ pub struct TuneableScheduledMutatorMetadata {
/// Will not be used when `mutation_ids` are set. /// Will not be used when `mutation_ids` are set.
/// Clear to fall back to random. /// Clear to fall back to random.
pub mutation_probabilities_cumulative: Vec<f32>, pub mutation_probabilities_cumulative: Vec<f32>,
/// The count of total mutations to perform. /// The count of mutations to stack.
/// If `mutation_ids` is of length `10`, and this number is `20`, /// If `mutation_ids` is of length `10`, and this number is `20`,
/// the mutations will be iterated through twice. /// the mutations will be iterated through twice.
pub iters: Option<u64>, pub iters: Option<u64>,
/// The probability of each number of mutations to stack.
pub iter_probabilities_pow_cumulative: Vec<f32>,
} }
impl Default for TuneableScheduledMutatorMetadata { impl Default for TuneableScheduledMutatorMetadata {
@ -46,6 +48,7 @@ impl Default for TuneableScheduledMutatorMetadata {
next_id: 0.into(), next_id: 0.into(),
mutation_probabilities_cumulative: Vec::default(), mutation_probabilities_cumulative: Vec::default(),
iters: None, iters: None,
iter_probabilities_pow_cumulative: Vec::default(),
} }
} }
} }
@ -138,11 +141,27 @@ where
{ {
/// Compute the number of iterations used to apply stacked mutations /// Compute the number of iterations used to apply stacked mutations
fn iterations(&self, state: &mut S, _: &I) -> u64 { fn iterations(&self, state: &mut S, _: &I) -> u64 {
if let Some(iters) = TuneableScheduledMutator::get_iters(state) { let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap();
iters
if metadata.iter_probabilities_pow_cumulative.is_empty() {
if let Some(iters) = metadata.iters {
iters
} else {
// fall back to random
1 << (1 + state.rand_mut().below(self.max_stack_pow))
}
} else { } else {
// fall back to random // We will sample using the mutation probabilities.
1 << (1 + state.rand_mut().below(self.max_stack_pow)) // Doing this outside of the original if branch to make the borrow checker happy.
#[allow(clippy::cast_precision_loss)]
let coin = state.rand_mut().next() as f32 / u64::MAX as f32;
let metadata = TuneableScheduledMutatorMetadata::get_mut(state).unwrap();
1 << (1 + metadata
.iter_probabilities_pow_cumulative
.iter()
.position(|i| *i >= coin)
.unwrap())
} }
} }
@ -229,6 +248,27 @@ where
pub fn set_iters(state: &mut S, iters: u64) { pub fn set_iters(state: &mut S, iters: u64) {
let metadata = Self::metadata_mut(state); let metadata = Self::metadata_mut(state);
metadata.iters = Some(iters); metadata.iters = Some(iters);
metadata.iter_probabilities_pow_cumulative.clear();
}
/// Sets the probability of next iteration counts,
/// i.e., how many times the mutation is likely to get mutated.
///
/// So, setting the `iter_probabilities` to `vec![0.1, 0.7, 0.2]`
/// would apply 2^one mutation with the likelihood of 10%, 2^2 mutations with the
/// a probability of 70% (0.7), and 2^3 mutations with the likelihood of 20%.
/// These will be applied for each call of this `mutate` function.
///
/// Setting this function will unset everything previously set in `set_iters`.
pub fn set_iter_probabilities_pow(state: &mut S, iter_probabilities_pow: Vec<f32>) {
let metadata = Self::metadata_mut(state);
metadata.iters = None;
// we precalculate the cumulative probability to be faster when sampling later.
let mut iter_probabilities_pow_cumulative = iter_probabilities_pow;
calculate_cumulative_sum_in_place(&mut iter_probabilities_pow_cumulative);
metadata.iter_probabilities_pow_cumulative = iter_probabilities_pow_cumulative;
} }
/// Gets the set amount of iterations /// Gets the set amount of iterations
@ -254,13 +294,7 @@ where
// we precalculate the cumulative probability to be faster when sampling later. // we precalculate the cumulative probability to be faster when sampling later.
let mut mutation_probabilities_cumulative = mutation_probabilities; let mut mutation_probabilities_cumulative = mutation_probabilities;
let mut acc = 0.0; calculate_cumulative_sum_in_place(&mut mutation_probabilities_cumulative);
for probability in &mut mutation_probabilities_cumulative {
let l = *probability;
*probability += acc;
acc += l;
}
metadata.mutation_probabilities_cumulative = mutation_probabilities_cumulative; metadata.mutation_probabilities_cumulative = mutation_probabilities_cumulative;
} }

View File

@ -21,7 +21,9 @@ use crate::{
observers::ObserversTuple, observers::ObserversTuple,
schedulers::Scheduler, schedulers::Scheduler,
start_timer, start_timer,
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasRand}, state::{
HasClientPerfMonitor, HasCorpus, HasExecutions, HasFuzzedCorpusId, HasMetadata, HasRand,
},
Error, EvaluatorObservers, ExecutionProcessor, HasScheduler, Error, EvaluatorObservers, ExecutionProcessor, HasScheduler,
}; };
@ -88,8 +90,14 @@ where
EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter, EM: EventFirer<State = CS::State> + EventRestarter + HasEventManagerId + ProgressReporter,
M: Mutator<CS::Input, CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: CS::State: HasFuzzedCorpusId
HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug, + HasClientPerfMonitor
+ HasCorpus
+ HasRand
+ HasExecutions
+ HasMetadata
+ Clone
+ Debug,
Z: ExecutionProcessor<OT, State = CS::State> Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT> + EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>, + HasScheduler<Scheduler = CS>,
@ -136,6 +144,8 @@ where
return None; return None;
} }
let idx = self.current_corpus_idx.unwrap();
state.set_fuzzed_corpus_id(idx);
start_timer!(state); start_timer!(state);
let mut input = state let mut input = state
.corpus() .corpus()
@ -169,7 +179,7 @@ where
last_input: <CS::State as UsesInput>::Input, last_input: <CS::State as UsesInput>::Input,
exit_kind: ExitKind, exit_kind: ExitKind,
) -> Result<(), Error> { ) -> Result<(), Error> {
// todo: isintersting, etc. // todo: is_interesting, etc.
fuzzer.process_execution(state, event_mgr, last_input, observers, &exit_kind, true)?; fuzzer.process_execution(state, event_mgr, last_input, observers, &exit_kind, true)?;
@ -178,6 +188,7 @@ where
.post_exec(state, self.stage_idx, self.current_corpus_idx)?; .post_exec(state, self.stage_idx, self.current_corpus_idx)?;
mark_feature_time!(state, PerfFeature::MutatePostExec); mark_feature_time!(state, PerfFeature::MutatePostExec);
self.testcases_done += 1; self.testcases_done += 1;
state.clear_fuzzed_corpus_id();
Ok(()) Ok(())
} }
@ -201,8 +212,14 @@ where
EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>, EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter<State = CS::State>,
M: Mutator<CS::Input, CS::State>, M: Mutator<CS::Input, CS::State>,
OT: ObserversTuple<CS::State>, OT: ObserversTuple<CS::State>,
CS::State: CS::State: HasClientPerfMonitor
HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug, + HasCorpus
+ HasRand
+ HasExecutions
+ HasMetadata
+ Clone
+ Debug
+ HasFuzzedCorpusId,
Z: ExecutionProcessor<OT, State = CS::State> Z: ExecutionProcessor<OT, State = CS::State>
+ EvaluatorObservers<OT> + EvaluatorObservers<OT>
+ HasScheduler<Scheduler = CS>, + HasScheduler<Scheduler = CS>,

View File

@ -60,6 +60,21 @@ pub trait HasCorpus: UsesInput {
fn corpus_mut(&mut self) -> &mut Self::Corpus; fn corpus_mut(&mut self) -> &mut Self::Corpus;
} }
/// Trait for a state that has information about which [`CorpusId`]
/// is currently being fuzzed.
/// When a new interesting input was found, this value becomes the `parent_id`.
pub trait HasFuzzedCorpusId {
/// The currently fuzzed [`CorpusId`], if known.
/// If a new interesting testcase was found, this should usually become the `parent_id`.
fn fuzzed_corpus_id(&self) -> Option<CorpusId>;
/// Sets the currently fuzzed [`CorpusId`].
fn set_fuzzed_corpus_id(&mut self, corpus_id: CorpusId);
/// Resets the currently fuzzed [`CorpusId`].
fn clear_fuzzed_corpus_id(&mut self);
}
/// Interact with the maximum size /// Interact with the maximum size
pub trait HasMaxSize { pub trait HasMaxSize {
/// The maximum size hint for items and mutations returned /// The maximum size hint for items and mutations returned
@ -192,6 +207,8 @@ pub struct StdState<I, C, R, SC> {
named_metadata: NamedSerdeAnyMap, named_metadata: NamedSerdeAnyMap,
/// MaxSize testcase size for mutators that appreciate it /// MaxSize testcase size for mutators that appreciate it
max_size: usize, max_size: usize,
/// The [`CorpusId`] of the testcase we're currently fuzzing.
fuzzed_corpus_id: Option<CorpusId>,
/// Performance statistics for this fuzzer /// Performance statistics for this fuzzer
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
introspection_monitor: ClientPerfMonitor, introspection_monitor: ClientPerfMonitor,
@ -257,6 +274,20 @@ where
} }
} }
impl<I, C, R, SC> HasFuzzedCorpusId for StdState<I, C, R, SC> {
fn fuzzed_corpus_id(&self) -> Option<CorpusId> {
self.fuzzed_corpus_id
}
fn set_fuzzed_corpus_id(&mut self, fuzzed_corpus_id: CorpusId) {
self.fuzzed_corpus_id = Some(fuzzed_corpus_id);
}
fn clear_fuzzed_corpus_id(&mut self) {
self.fuzzed_corpus_id = None;
}
}
impl<I, C, R, SC> HasSolutions for StdState<I, C, R, SC> impl<I, C, R, SC> HasSolutions for StdState<I, C, R, SC>
where where
I: Input, I: Input,
@ -694,6 +725,7 @@ where
corpus, corpus,
solutions, solutions,
max_size: DEFAULT_MAX_SIZE, max_size: DEFAULT_MAX_SIZE,
fuzzed_corpus_id: None,
#[cfg(feature = "introspection")] #[cfg(feature = "introspection")]
introspection_monitor: ClientPerfMonitor::new(), introspection_monitor: ClientPerfMonitor::new(),
#[cfg(feature = "std")] #[cfg(feature = "std")]

View File

@ -266,7 +266,7 @@ pub const LIBAFL_CC_LLVM_VERSION: Option<usize> = None;
if cfg!(windows) { if cfg!(windows) {
cxxflags.push(String::from("-fuse-ld=lld")); cxxflags.push(String::from("-fuse-ld=lld"));
cxxflags.push(String::from("/LD")); cxxflags.push(String::from("/LD"));
/* clang on windows links against the libcmt.lib runtime /* clang on Windows links against the libcmt.lib runtime
* however, the distributed binaries are compiled against msvcrt.lib * however, the distributed binaries are compiled against msvcrt.lib
* we need to also use msvcrt.lib instead of libcmt.lib when building the optimization passes * we need to also use msvcrt.lib instead of libcmt.lib when building the optimization passes
* first, we tell clang-cl (and indirectly link) to ignore libcmt.lib via -nodefaultlib:libcmt * first, we tell clang-cl (and indirectly link) to ignore libcmt.lib via -nodefaultlib:libcmt

View File

@ -13,7 +13,10 @@ use libafl::{
fuzzer::HasObjective, fuzzer::HasObjective,
inputs::UsesInput, inputs::UsesInput,
observers::{ObserversTuple, UsesObservers}, observers::{ObserversTuple, UsesObservers},
state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, State, UsesState}, state::{
HasClientPerfMonitor, HasCorpus, HasExecutions, HasFuzzedCorpusId, HasSolutions, State,
UsesState,
},
Error, Error,
}; };
@ -64,7 +67,12 @@ where
where where
EM: EventFirer<State = S> + EventRestarter<State = S>, EM: EventFirer<State = S> + EventRestarter<State = S>,
OF: Feedback<S>, OF: Feedback<S>,
S: State + HasExecutions + HasCorpus + HasSolutions + HasClientPerfMonitor, S: State
+ HasExecutions
+ HasCorpus
+ HasSolutions
+ HasClientPerfMonitor
+ HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = S>, Z: HasObjective<Objective = OF, State = S>,
{ {
Ok(Self { Ok(Self {

View File

@ -4,7 +4,7 @@ use libafl::{
events::{EventFirer, EventRestarter}, events::{EventFirer, EventRestarter},
executors::{inprocess::windows_asan_handler::asan_death_handler, Executor, HasObservers}, executors::{inprocess::windows_asan_handler::asan_death_handler, Executor, HasObservers},
feedbacks::Feedback, feedbacks::Feedback,
state::{HasClientPerfMonitor, HasSolutions}, state::{HasClientPerfMonitor, HasFuzzedCorpusId, HasSolutions},
HasObjective, HasObjective,
}; };
@ -15,20 +15,24 @@ extern "C" {
fn __sanitizer_set_death_callback(cb: CB); fn __sanitizer_set_death_callback(cb: CB);
} }
/// Setup `ASan` callback on windows
///
/// This is needed to intercept `ASan` error exit.
///
/// When we use `AddressSanitizer` on Windows, the crash handler is not called when `ASan` detects an error
/// This is because, on linux, `ASan` runtime raises `SIGABRT` so we can rely on the signal handler
/// but on Windows it simply calls `TerminateProcess`.
/// so we need to call the API by `ASan` to register the callback when `ASan` is about to finish the process.
/// See <https://github.com/AFLplusplus/LibAFL/issues/769>.
///
/// # Safety /// # Safety
/// Setup asan callback on windows /// Calls the unsafe `__sanitizer_set_death_callback` symbol, but should be safe to call otherwise.
// See https://github.com/AFLplusplus/LibAFL/issues/769
// This is needed to intercept asan error exit
// When we use AddressSanitizer on windows, the crash handler is not called when ASAN detects an error
// This is because, on linux, ASAN runtime raises SIGABRT so we can rely on the signal handler
// but on windows it simply calls TerminateProcess.
// so we need to call the api by asan to register the callback when asan is about to finish the process.
pub unsafe fn setup_asan_callback<E, EM, OF, Z>(_executor: &E, _event_mgr: &EM, _fuzzer: &Z) pub unsafe fn setup_asan_callback<E, EM, OF, Z>(_executor: &E, _event_mgr: &EM, _fuzzer: &Z)
where where
E: Executor<EM, Z> + HasObservers, E: Executor<EM, Z> + HasObservers,
EM: EventFirer<State = E::State> + EventRestarter<State = E::State>, EM: EventFirer<State = E::State> + EventRestarter<State = E::State>,
OF: Feedback<E::State>, OF: Feedback<E::State>,
E::State: HasSolutions + HasClientPerfMonitor, E::State: HasSolutions + HasClientPerfMonitor + HasFuzzedCorpusId,
Z: HasObjective<Objective = OF, State = E::State>, Z: HasObjective<Objective = OF, State = E::State>,
{ {
__sanitizer_set_death_callback(asan_death_handler::<E, EM, OF, Z>); __sanitizer_set_death_callback(asan_death_handler::<E, EM, OF, Z>);