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:
parent
3e7322e395
commit
31357aa7e2
@ -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()
|
||||||
|
@ -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")]
|
||||||
|
@ -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,
|
||||||
|
@ -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()
|
||||||
|
@ -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")))]
|
||||||
|
@ -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")))]
|
||||||
|
@ -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()));
|
||||||
|
@ -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?
|
||||||
|
@ -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();
|
||||||
|
@ -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,12 +141,28 @@ 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();
|
||||||
|
|
||||||
|
if metadata.iter_probabilities_pow_cumulative.is_empty() {
|
||||||
|
if let Some(iters) = metadata.iters {
|
||||||
iters
|
iters
|
||||||
} else {
|
} else {
|
||||||
// fall back to random
|
// fall back to random
|
||||||
1 << (1 + state.rand_mut().below(self.max_stack_pow))
|
1 << (1 + state.rand_mut().below(self.max_stack_pow))
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
// We will sample using the mutation probabilities.
|
||||||
|
// 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())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the next mutation to apply
|
/// Get the next mutation to apply
|
||||||
@ -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;
|
||||||
}
|
}
|
||||||
|
@ -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>,
|
||||||
|
@ -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")]
|
||||||
|
@ -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
|
||||||
|
@ -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 {
|
||||||
|
@ -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>);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user