merged
This commit is contained in:
commit
a77b1cb18e
@ -402,7 +402,7 @@ mod tests {
|
|||||||
use crate::executors::inmemory::InMemoryExecutor;
|
use crate::executors::inmemory::InMemoryExecutor;
|
||||||
use crate::executors::{Executor, ExitKind};
|
use crate::executors::{Executor, ExitKind};
|
||||||
use crate::inputs::bytes::BytesInput;
|
use crate::inputs::bytes::BytesInput;
|
||||||
use crate::mutators::scheduled::{mutation_bitflip, ComposedByMutations, StdScheduledMutator};
|
use crate::mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator};
|
||||||
use crate::stages::mutational::StdMutationalStage;
|
use crate::stages::mutational::StdMutationalStage;
|
||||||
use crate::utils::StdRand;
|
use crate::utils::StdRand;
|
||||||
|
|
||||||
|
@ -8,7 +8,7 @@ pub mod shmem_translated;
|
|||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub use crate::events::llmp::LLMP;
|
pub use crate::events::llmp::LLMP;
|
||||||
|
|
||||||
//use core::any::TypeId;
|
use core::fmt::Formatter;
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
use std::io::Write;
|
use std::io::Write;
|
||||||
|
|
||||||
@ -19,8 +19,43 @@ use crate::inputs::Input;
|
|||||||
use crate::utils::Rand;
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
|
pub enum EventDestination {
|
||||||
|
Main,
|
||||||
|
Broker,
|
||||||
|
Clients,
|
||||||
|
}
|
||||||
|
|
||||||
pub trait Event {
|
pub trait Event {
|
||||||
fn name(&self) -> &'static str;
|
fn name() -> &'static str;
|
||||||
|
|
||||||
|
fn destination() -> EventDestination;
|
||||||
|
|
||||||
|
fn log<S, C, E, I, R>(&self, formatter: &mut Formatter, _state: &S) -> Result<(), AflError>
|
||||||
|
where
|
||||||
|
S: State<C, E, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
E: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
match write!(formatter, "[{}]", Self::name()) {
|
||||||
|
Ok(_) => Ok(()),
|
||||||
|
Err(_) => Err(AflError::Unknown("write error".to_string())),
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn on_recv<S, C, E, I, R>(&self, _state: &mut S) -> Result<(), AflError>
|
||||||
|
where
|
||||||
|
S: State<C, E, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
E: Executor<I>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO serialize and deserialize, defaults to serde
|
||||||
}
|
}
|
||||||
|
|
||||||
pub trait EventManager<S, C, E, I, R>
|
pub trait EventManager<S, C, E, I, R>
|
||||||
@ -32,6 +67,7 @@ where
|
|||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
/// Check if this EventaManager support a given Event type
|
/// Check if this EventaManager support a given Event type
|
||||||
|
/// To compare events, use Event::name().as_ptr()
|
||||||
fn enabled<T>(&self) -> bool
|
fn enabled<T>(&self) -> bool
|
||||||
where
|
where
|
||||||
T: Event;
|
T: Event;
|
||||||
@ -71,9 +107,13 @@ macro_rules! fire_event {
|
|||||||
|
|
||||||
pub struct LoadInitialEvent {}
|
pub struct LoadInitialEvent {}
|
||||||
impl Event for LoadInitialEvent {
|
impl Event for LoadInitialEvent {
|
||||||
fn name(&self) -> &'static str {
|
fn name() -> &'static str {
|
||||||
"LOAD"
|
"LOAD"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn destination() -> EventDestination {
|
||||||
|
EventDestination::Broker
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl LoadInitialEvent {
|
impl LoadInitialEvent {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@ -92,9 +132,13 @@ impl<I> Event for NewTestcaseEvent<I>
|
|||||||
where
|
where
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
fn name(&self) -> &'static str {
|
fn name() -> &'static str {
|
||||||
"NEW"
|
"NEW"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn destination() -> EventDestination {
|
||||||
|
EventDestination::Clients
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<I> NewTestcaseEvent<I>
|
impl<I> NewTestcaseEvent<I>
|
||||||
@ -112,9 +156,13 @@ where
|
|||||||
|
|
||||||
pub struct UpdateStatsEvent {}
|
pub struct UpdateStatsEvent {}
|
||||||
impl Event for UpdateStatsEvent {
|
impl Event for UpdateStatsEvent {
|
||||||
fn name(&self) -> &'static str {
|
fn name() -> &'static str {
|
||||||
"STATS"
|
"STATS"
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn destination() -> EventDestination {
|
||||||
|
EventDestination::Broker
|
||||||
|
}
|
||||||
}
|
}
|
||||||
impl UpdateStatsEvent {
|
impl UpdateStatsEvent {
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
@ -122,6 +170,22 @@ impl UpdateStatsEvent {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub struct CrashEvent {}
|
||||||
|
impl Event for CrashEvent {
|
||||||
|
fn name() -> &'static str {
|
||||||
|
"CRASH"
|
||||||
|
}
|
||||||
|
|
||||||
|
fn destination() -> EventDestination {
|
||||||
|
EventDestination::Broker
|
||||||
|
}
|
||||||
|
}
|
||||||
|
impl CrashEvent {
|
||||||
|
pub fn new() -> Self {
|
||||||
|
CrashEvent {}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub struct LoggerEventManager<W>
|
pub struct LoggerEventManager<W>
|
||||||
where
|
where
|
||||||
@ -146,20 +210,13 @@ where
|
|||||||
T: Event,
|
T: Event,
|
||||||
{
|
{
|
||||||
true
|
true
|
||||||
/*let _load = TypeId::of::<LoadInitialEvent>();
|
|
||||||
let _new = TypeId::of::<NewTestcaseEvent>();
|
|
||||||
match TypeId::of::<T>() {
|
|
||||||
_load => true,
|
|
||||||
_new => true,
|
|
||||||
_ => false,
|
|
||||||
}*/
|
|
||||||
}
|
}
|
||||||
|
|
||||||
fn fire<T>(&mut self, event: T) -> Result<(), AflError>
|
fn fire<T>(&mut self, _event: T) -> Result<(), AflError>
|
||||||
where
|
where
|
||||||
T: Event,
|
T: Event,
|
||||||
{
|
{
|
||||||
self.events.push(event.name().to_string());
|
self.events.push(T::name().to_string());
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -1,8 +1,7 @@
|
|||||||
pub mod scheduled;
|
pub mod scheduled;
|
||||||
pub use scheduled::ComposedByMutations;
|
pub use scheduled::*;
|
||||||
pub use scheduled::HavocBytesMutator;
|
pub mod mutations;
|
||||||
pub use scheduled::ScheduledMutator;
|
pub use mutations::*;
|
||||||
pub use scheduled::StdScheduledMutator;
|
|
||||||
|
|
||||||
use crate::corpus::Corpus;
|
use crate::corpus::Corpus;
|
||||||
use crate::inputs::Input;
|
use crate::inputs::Input;
|
||||||
@ -34,3 +33,10 @@ where
|
|||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const DEFAULT_MAX_SIZE: usize = 1048576;
|
||||||
|
|
||||||
|
pub trait HasMaxSize {
|
||||||
|
fn max_size(&self) -> usize;
|
||||||
|
fn set_max_size(&mut self, max_size: usize);
|
||||||
|
}
|
||||||
|
260
afl/src/mutators/mutations.rs
Normal file
260
afl/src/mutators/mutations.rs
Normal file
@ -0,0 +1,260 @@
|
|||||||
|
use crate::inputs::{HasBytesVec, Input};
|
||||||
|
use crate::mutators::Corpus;
|
||||||
|
use crate::mutators::*;
|
||||||
|
use crate::utils::Rand;
|
||||||
|
use crate::AflError;
|
||||||
|
|
||||||
|
pub enum MutationResult {
|
||||||
|
Mutated,
|
||||||
|
Skipped,
|
||||||
|
}
|
||||||
|
|
||||||
|
// TODO maybe the mutator arg is not needed
|
||||||
|
/// The generic function type that identifies mutations
|
||||||
|
pub type MutationFunction<M, C, I, R> =
|
||||||
|
fn(&mut M, &mut R, &C, &mut I) -> Result<MutationResult, AflError>;
|
||||||
|
|
||||||
|
pub trait ComposedByMutations<C, I, R>
|
||||||
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
/// Get a mutation by index
|
||||||
|
fn mutation_by_idx(&self, index: usize) -> MutationFunction<Self, C, I, R>;
|
||||||
|
|
||||||
|
/// Get the number of mutations
|
||||||
|
fn mutations_count(&self) -> usize;
|
||||||
|
|
||||||
|
/// Add a mutation
|
||||||
|
fn add_mutation(&mut self, mutation: MutationFunction<Self, C, I, R>);
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Bitflip mutation for inputs with a bytes vector
|
||||||
|
pub fn mutation_bitflip<M, C, I, R>(
|
||||||
|
_mutator: &mut M,
|
||||||
|
rand: &mut R,
|
||||||
|
_corpus: &C,
|
||||||
|
input: &mut I,
|
||||||
|
) -> Result<MutationResult, AflError>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
if input.bytes().len() == 0 {
|
||||||
|
Ok(MutationResult::Skipped)
|
||||||
|
} else {
|
||||||
|
let bit = rand.below((input.bytes().len() << 3) as u64) as usize;
|
||||||
|
unsafe {
|
||||||
|
// moar speed, no bound check
|
||||||
|
*input.bytes_mut().get_unchecked_mut(bit >> 3) ^= (128 >> (bit & 7)) as u8;
|
||||||
|
}
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mutation_byteflip<M, C, I, R>(
|
||||||
|
_mutator: &mut M,
|
||||||
|
rand: &mut R,
|
||||||
|
_corpus: &C,
|
||||||
|
input: &mut I,
|
||||||
|
) -> Result<MutationResult, AflError>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
if input.bytes().len() == 0 {
|
||||||
|
Ok(MutationResult::Skipped)
|
||||||
|
} else {
|
||||||
|
let idx = rand.below(input.bytes().len() as u64) as usize;
|
||||||
|
unsafe {
|
||||||
|
// moar speed, no bound check
|
||||||
|
*input.bytes_mut().get_unchecked_mut(idx) ^= 0xff;
|
||||||
|
}
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mutation_byteinc<M, C, I, R>(
|
||||||
|
_mutator: &mut M,
|
||||||
|
rand: &mut R,
|
||||||
|
_corpus: &C,
|
||||||
|
input: &mut I,
|
||||||
|
) -> Result<MutationResult, AflError>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
if input.bytes().len() == 0 {
|
||||||
|
Ok(MutationResult::Skipped)
|
||||||
|
} else {
|
||||||
|
let idx = rand.below(input.bytes().len() as u64) as usize;
|
||||||
|
unsafe {
|
||||||
|
// moar speed, no bound check
|
||||||
|
*input.bytes_mut().get_unchecked_mut(idx) += 1;
|
||||||
|
}
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mutation_bytedec<M, C, I, R>(
|
||||||
|
_mutator: &mut M,
|
||||||
|
rand: &mut R,
|
||||||
|
_corpus: &C,
|
||||||
|
input: &mut I,
|
||||||
|
) -> Result<MutationResult, AflError>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
if input.bytes().len() == 0 {
|
||||||
|
Ok(MutationResult::Skipped)
|
||||||
|
} else {
|
||||||
|
let idx = rand.below(input.bytes().len() as u64) as usize;
|
||||||
|
unsafe {
|
||||||
|
// moar speed, no bound check
|
||||||
|
*input.bytes_mut().get_unchecked_mut(idx) -= 1;
|
||||||
|
}
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
pub fn mutation_byteneg<M, C, I, R>(
|
||||||
|
_mutator: &mut M,
|
||||||
|
rand: &mut R,
|
||||||
|
_corpus: &C,
|
||||||
|
input: &mut I,
|
||||||
|
) -> Result<MutationResult, AflError>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
if input.bytes().len() == 0 {
|
||||||
|
Ok(MutationResult::Skipped)
|
||||||
|
} else {
|
||||||
|
let idx = rand.below(input.bytes().len() as u64) as usize;
|
||||||
|
unsafe {
|
||||||
|
// moar speed, no bound check
|
||||||
|
*input.bytes_mut().get_unchecked_mut(idx) = !(*input.bytes().get_unchecked(idx));
|
||||||
|
}
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
pub fn mutation_bytesexpand<M, C, I, R>(
|
||||||
|
mutator: &mut M,
|
||||||
|
rand: &mut R,
|
||||||
|
_corpus: &C,
|
||||||
|
input: &mut I,
|
||||||
|
) -> Result<MutationResult, AflError>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R> + HasMaxSize,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
let len = rand.below(mutator.max_size() as u64) as usize;
|
||||||
|
|
||||||
|
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
|
pub fn mutation_bytesdelete<M, C, I, R>(
|
||||||
|
_mutator: &mut M,
|
||||||
|
rand: &mut R,
|
||||||
|
_corpus: & C,
|
||||||
|
input: &mut I,
|
||||||
|
) -> Result<MutationResult, AflError>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
let size = input.bytes().len();
|
||||||
|
if size <= 2 {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
|
|
||||||
|
let off = rand.below(size as u64) as usize;
|
||||||
|
let len = rand.below((size - off) as u64) as usize;
|
||||||
|
input.bytes_mut().drain(off..len);
|
||||||
|
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the first and last diff position between the given vectors, stopping at the min len
|
||||||
|
fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
||||||
|
let mut first_diff: i64 = -1;
|
||||||
|
let mut last_diff: i64 = -1;
|
||||||
|
for (i, (this_el, other_el)) in this.iter().zip(other.iter()).enumerate() {
|
||||||
|
if this_el != other_el {
|
||||||
|
if first_diff < 0 {
|
||||||
|
first_diff = i as i64;
|
||||||
|
}
|
||||||
|
last_diff = i as i64;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
(first_diff, last_diff)
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Splicing mutator
|
||||||
|
pub fn mutation_splice<M, C, I, R>(
|
||||||
|
_mutator: &mut M,
|
||||||
|
rand: &mut R,
|
||||||
|
corpus: & C,
|
||||||
|
input: &mut I,
|
||||||
|
) -> Result<MutationResult, AflError>
|
||||||
|
where
|
||||||
|
M: Mutator<C, I, R>,
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input + HasBytesVec,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
// We don't want to use the testcase we're already using for splicing
|
||||||
|
let (other_testcase, _) = corpus.random_entry(rand)?.clone();
|
||||||
|
// TODO: Load let other = Testcase::load_from_disk(other_test)?;
|
||||||
|
// println!("Input: {:?}, other input: {:?}", input.bytes(), other.bytes());
|
||||||
|
let other = match other_testcase.input() {
|
||||||
|
Some(i) => i,
|
||||||
|
None => return Ok(MutationResult::Skipped), //TODO
|
||||||
|
};
|
||||||
|
|
||||||
|
let mut counter = 0;
|
||||||
|
let (first_diff, last_diff) = loop {
|
||||||
|
let (f, l) = locate_diffs(input.bytes(), other.bytes());
|
||||||
|
// println!("Diffs were between {} and {}", f, l);
|
||||||
|
if f != l && f >= 0 && l >= 2 {
|
||||||
|
break (f, l);
|
||||||
|
}
|
||||||
|
if counter == 3 {
|
||||||
|
return Ok(MutationResult::Skipped);
|
||||||
|
}
|
||||||
|
counter += 1;
|
||||||
|
};
|
||||||
|
|
||||||
|
let split_at = rand.between(first_diff as u64, last_diff as u64) as usize;
|
||||||
|
|
||||||
|
// println!("Splicing at {}", split_at);
|
||||||
|
|
||||||
|
input
|
||||||
|
.bytes_mut()
|
||||||
|
.splice(split_at.., other.bytes()[split_at..].iter().cloned());
|
||||||
|
|
||||||
|
// println!("Splice result: {:?}, input is now: {:?}", split_result, input.bytes());
|
||||||
|
|
||||||
|
Ok(MutationResult::Mutated)
|
||||||
|
}
|
@ -3,36 +3,10 @@ use core::marker::PhantomData;
|
|||||||
|
|
||||||
use crate::inputs::{HasBytesVec, Input};
|
use crate::inputs::{HasBytesVec, Input};
|
||||||
use crate::mutators::Corpus;
|
use crate::mutators::Corpus;
|
||||||
use crate::mutators::Mutator;
|
use crate::mutators::*;
|
||||||
use crate::utils::Rand;
|
use crate::utils::Rand;
|
||||||
use crate::AflError;
|
use crate::AflError;
|
||||||
|
|
||||||
pub enum MutationResult {
|
|
||||||
Mutated,
|
|
||||||
Skipped,
|
|
||||||
}
|
|
||||||
|
|
||||||
// TODO maybe the mutator arg is not needed
|
|
||||||
/// The generic function type that identifies mutations
|
|
||||||
type MutationFunction<M, C, I, R> =
|
|
||||||
fn(&mut M, &mut R, &C, &mut I) -> Result<MutationResult, AflError>;
|
|
||||||
|
|
||||||
pub trait ComposedByMutations<C, I, R>
|
|
||||||
where
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
/// Get a mutation by index
|
|
||||||
fn mutation_by_idx(&self, index: usize) -> MutationFunction<Self, C, I, R>;
|
|
||||||
|
|
||||||
/// Get the number of mutations
|
|
||||||
fn mutations_count(&self) -> usize;
|
|
||||||
|
|
||||||
/// Add a mutation
|
|
||||||
fn add_mutation(&mut self, mutation: MutationFunction<Self, C, I, R>);
|
|
||||||
}
|
|
||||||
|
|
||||||
pub trait ScheduledMutator<C, I, R>: Mutator<C, I, R> + ComposedByMutations<C, I, R>
|
pub trait ScheduledMutator<C, I, R>: Mutator<C, I, R> + ComposedByMutations<C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
@ -85,6 +59,7 @@ where
|
|||||||
R: Rand,
|
R: Rand,
|
||||||
{
|
{
|
||||||
mutations: Vec<MutationFunction<Self, C, I, R>>,
|
mutations: Vec<MutationFunction<Self, C, I, R>>,
|
||||||
|
max_size: usize,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<C, I, R> Mutator<C, I, R> for StdScheduledMutator<C, I, R>
|
impl<C, I, R> Mutator<C, I, R> for StdScheduledMutator<C, I, R>
|
||||||
@ -132,6 +107,20 @@ where
|
|||||||
// Just use the default methods
|
// Just use the default methods
|
||||||
}
|
}
|
||||||
|
|
||||||
|
impl<C, I, R> HasMaxSize for StdScheduledMutator<C, I, R>
|
||||||
|
where
|
||||||
|
C: Corpus<I, R>,
|
||||||
|
I: Input,
|
||||||
|
R: Rand,
|
||||||
|
{
|
||||||
|
fn max_size(&self) -> usize {
|
||||||
|
self.max_size
|
||||||
|
}
|
||||||
|
fn set_max_size(&mut self, max_size: usize) {
|
||||||
|
self.max_size = max_size;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl<C, I, R> StdScheduledMutator<C, I, R>
|
impl<C, I, R> StdScheduledMutator<C, I, R>
|
||||||
where
|
where
|
||||||
C: Corpus<I, R>,
|
C: Corpus<I, R>,
|
||||||
@ -140,203 +129,21 @@ where
|
|||||||
{
|
{
|
||||||
/// Create a new StdScheduledMutator instance without mutations and corpus
|
/// Create a new StdScheduledMutator instance without mutations and corpus
|
||||||
pub fn new() -> Self {
|
pub fn new() -> Self {
|
||||||
StdScheduledMutator { mutations: vec![] }
|
StdScheduledMutator {
|
||||||
|
mutations: vec![],
|
||||||
|
max_size: DEFAULT_MAX_SIZE,
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new StdScheduledMutator instance specifying mutations
|
/// Create a new StdScheduledMutator instance specifying mutations
|
||||||
pub fn with_mutations(mutations: Vec<MutationFunction<Self, C, I, R>>) -> Self {
|
pub fn with_mutations(mutations: Vec<MutationFunction<Self, C, I, R>>) -> Self {
|
||||||
StdScheduledMutator {
|
StdScheduledMutator {
|
||||||
mutations: mutations,
|
mutations: mutations,
|
||||||
|
max_size: DEFAULT_MAX_SIZE,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Bitflip mutation for inputs with a bytes vector
|
|
||||||
pub fn mutation_bitflip<M, C, I, R>(
|
|
||||||
_mutator: &mut M,
|
|
||||||
rand: &mut R,
|
|
||||||
_corpus: &C,
|
|
||||||
input: &mut I,
|
|
||||||
) -> Result<MutationResult, AflError>
|
|
||||||
where
|
|
||||||
M: Mutator<C, I, R>,
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
if input.bytes().len() == 0 {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let bit = rand.below((input.bytes().len() << 3) as u64) as usize;
|
|
||||||
unsafe {
|
|
||||||
// moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(bit >> 3) ^= (128 >> (bit & 7)) as u8;
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mutation_byteflip<M, C, I, R>(
|
|
||||||
_mutator: &mut M,
|
|
||||||
rand: &mut R,
|
|
||||||
_corpus: &C,
|
|
||||||
input: &mut I,
|
|
||||||
) -> Result<MutationResult, AflError>
|
|
||||||
where
|
|
||||||
M: Mutator<C, I, R>,
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
if input.bytes().len() == 0 {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let idx = rand.below(input.bytes().len() as u64) as usize;
|
|
||||||
unsafe {
|
|
||||||
// moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(idx) ^= 0xff;
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mutation_byteinc<M, C, I, R>(
|
|
||||||
_mutator: &mut M,
|
|
||||||
rand: &mut R,
|
|
||||||
_corpus: &C,
|
|
||||||
input: &mut I,
|
|
||||||
) -> Result<MutationResult, AflError>
|
|
||||||
where
|
|
||||||
M: Mutator<C, I, R>,
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
if input.bytes().len() == 0 {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let idx = rand.below(input.bytes().len() as u64) as usize;
|
|
||||||
unsafe {
|
|
||||||
// moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(idx) += 1;
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mutation_bytedec<M, C, I, R>(
|
|
||||||
_mutator: &mut M,
|
|
||||||
rand: &mut R,
|
|
||||||
_corpus: &C,
|
|
||||||
input: &mut I,
|
|
||||||
) -> Result<MutationResult, AflError>
|
|
||||||
where
|
|
||||||
M: Mutator<C, I, R>,
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
if input.bytes().len() == 0 {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let idx = rand.below(input.bytes().len() as u64) as usize;
|
|
||||||
unsafe {
|
|
||||||
// moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(idx) -= 1;
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn mutation_byteneg<M, C, I, R>(
|
|
||||||
_mutator: &mut M,
|
|
||||||
rand: &mut R,
|
|
||||||
_corpus: &C,
|
|
||||||
input: &mut I,
|
|
||||||
) -> Result<MutationResult, AflError>
|
|
||||||
where
|
|
||||||
M: Mutator<C, I, R>,
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
if input.bytes().len() == 0 {
|
|
||||||
Ok(MutationResult::Skipped)
|
|
||||||
} else {
|
|
||||||
let idx = rand.below(input.bytes().len() as u64) as usize;
|
|
||||||
unsafe {
|
|
||||||
// moar speed, no bound check
|
|
||||||
*input.bytes_mut().get_unchecked_mut(idx) = !(*input.bytes().get_unchecked(idx));
|
|
||||||
}
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Returns the first and last diff position between the given vectors, stopping at the min len
|
|
||||||
fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
|
||||||
let mut first_diff: i64 = -1;
|
|
||||||
let mut last_diff: i64 = -1;
|
|
||||||
for (i, (this_el, other_el)) in this.iter().zip(other.iter()).enumerate() {
|
|
||||||
if this_el != other_el {
|
|
||||||
if first_diff < 0 {
|
|
||||||
first_diff = i as i64;
|
|
||||||
}
|
|
||||||
last_diff = i as i64;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
(first_diff, last_diff)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Splicing mutator
|
|
||||||
pub fn mutation_splice<M, C, I, R>(
|
|
||||||
_mutator: &mut M,
|
|
||||||
rand: &mut R,
|
|
||||||
corpus: &C,
|
|
||||||
input: &mut I,
|
|
||||||
) -> Result<MutationResult, AflError>
|
|
||||||
where
|
|
||||||
M: Mutator<C, I, R>,
|
|
||||||
C: Corpus<I, R>,
|
|
||||||
I: Input + HasBytesVec,
|
|
||||||
R: Rand,
|
|
||||||
{
|
|
||||||
// TODO: Don't reuse the current testcase!
|
|
||||||
// (We don't want to use the testcase we're already using for splicing)
|
|
||||||
let (other_testcase, _) = corpus.random_entry(rand)?;
|
|
||||||
// TODO: let other = other_testcase.load_input()?;
|
|
||||||
// println!("Input: {:?}, other input: {:?}", input.bytes(), other.bytes());
|
|
||||||
let other = match other_testcase.input() {
|
|
||||||
Some(i) => i,
|
|
||||||
None => return Ok(MutationResult::Skipped), // TODO!!
|
|
||||||
};
|
|
||||||
|
|
||||||
let mut counter = 0;
|
|
||||||
let (first_diff, last_diff) = loop {
|
|
||||||
let (f, l) = locate_diffs(input.bytes(), other.bytes());
|
|
||||||
// println!("Diffs were between {} and {}", f, l);
|
|
||||||
if f != l && f >= 0 && l >= 2 {
|
|
||||||
break (f, l);
|
|
||||||
}
|
|
||||||
if counter == 3 {
|
|
||||||
return Ok(MutationResult::Skipped);
|
|
||||||
}
|
|
||||||
counter += 1;
|
|
||||||
};
|
|
||||||
|
|
||||||
let split_at = rand.between(first_diff as u64, last_diff as u64) as usize;
|
|
||||||
|
|
||||||
// println!("Splicing at {}", split_at);
|
|
||||||
|
|
||||||
input
|
|
||||||
.bytes_mut()
|
|
||||||
.splice(split_at.., other.bytes()[split_at..].iter().cloned());
|
|
||||||
|
|
||||||
// println!("Splice result: {:?}, input is now: {:?}", split_result, input.bytes());
|
|
||||||
|
|
||||||
Ok(MutationResult::Mutated)
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Schedule some selected byte level mutations given a ScheduledMutator type
|
/// Schedule some selected byte level mutations given a ScheduledMutator type
|
||||||
pub struct HavocBytesMutator<SM, C, I, R>
|
pub struct HavocBytesMutator<SM, C, I, R>
|
||||||
where
|
where
|
||||||
@ -401,11 +208,12 @@ where
|
|||||||
scheduled.add_mutation(mutation_bytedec);
|
scheduled.add_mutation(mutation_bytedec);
|
||||||
scheduled.add_mutation(mutation_byteneg);
|
scheduled.add_mutation(mutation_byteneg);
|
||||||
|
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
//scheduled.add_mutation(mutation_bytesexpand);
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bytesdelete);
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bytesdelete);
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bytesdelete);
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bytesdelete);
|
||||||
|
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bitflip);
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bitflip);
|
||||||
scheduled.add_mutation(mutation_bitflip);
|
scheduled.add_mutation(mutation_bitflip);
|
||||||
|
Loading…
x
Reference in New Issue
Block a user