Merge branch 'main' into fix-default-prng
This commit is contained in:
commit
00da3b975a
44
.github/workflows/build_and_test.yml
vendored
Normal file
44
.github/workflows/build_and_test.yml
vendored
Normal file
@ -0,0 +1,44 @@
|
||||
name: Build and Test
|
||||
|
||||
on: [push]
|
||||
|
||||
env:
|
||||
CARGO_TERM_COLOR: always
|
||||
|
||||
jobs:
|
||||
build:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: cd libafl && cargo build --verbose
|
||||
build-all:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: cd libafl &&cargo build --no-default-features --features runtime --features std --features anymapdbg --verbose
|
||||
test:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test
|
||||
run: cd libafl && cargo test --verbose
|
||||
build-no-std:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Build
|
||||
run: cd libafl && cargo build --no-default-features --verbose
|
||||
test-no-std:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test
|
||||
run: cd libafl && cargo test --no-default-features --verbose
|
||||
docs:
|
||||
runs-on: ubuntu-latest
|
||||
steps:
|
||||
- uses: actions/checkout@v2
|
||||
- name: Test
|
||||
run: cd libafl && cargo doc
|
@ -1,11 +1,13 @@
|
||||
# LibAFL, the fuzzer library.
|
||||
|
||||
Advanced Fuzzing Library - Slot your own Fuzzers together and extend their features, using Rust.
|
||||
Advanced Fuzzing Library - Slot your own fuzzers together and extend their features using Rust.
|
||||
|
||||
LibAFL is written and maintained by Andrea Fioraldi <andreafioraldi@gmail.com> and Dominik Maier <mail@dmnk.co>.
|
||||
|
||||
It is released as Free and Open Source Software under the GNU Lesser General Public License V3.
|
||||
|
||||
|
||||
|
||||
## Example usages
|
||||
|
||||
We collect example fuzzers in `./fuzzers`.
|
||||
@ -14,6 +16,10 @@ The best-tested fuzzer is `./fuzzers/libfuzzer_libpng`, a clone of libfuzzer usi
|
||||
If you want to get a quick overview, run `cargo doc`.
|
||||
Feel free to open issues or contact us directly. Thank you for your support. <3
|
||||
|
||||
## The Core Concepts
|
||||
|
||||
We're still working on the documentation. In the meantime, you can watch the Video from last year's Rc3, here:
|
||||
[](http://www.youtube.com/watch?v=3RWkT1Q5IV0 "Fuzzers Like LEGO")
|
||||
## Roadmap for release
|
||||
|
||||
+ Minset corpus scheduler
|
||||
|
@ -88,7 +88,7 @@ fn fuzz(corpus_dirs: Vec<PathBuf>, objective_dir: PathBuf, broker_port: u16) ->
|
||||
StdRand::new(current_nanos()),
|
||||
// Corpus that will be evolved, we keep it in memory for performance
|
||||
InMemoryCorpus::new(),
|
||||
// Feedbacks to rate the interestingness of an input
|
||||
// Feedbacks to rate the interestingness of an input
|
||||
tuple_list!(MaxMapFeedback::new_with_observer("edges", &edges_observer)),
|
||||
// Corpus in which we store solutions (crashes in this example),
|
||||
// on disk so the user can get them after stopping the fuzzer
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! Poor-rust-man's downcasts for stuff we send over the wire (or shared maps)
|
||||
use serde::{Deserialize, Deserializer, Serialize, Serializer};
|
||||
|
||||
use alloc::boxed::Box;
|
||||
|
@ -1,3 +1,5 @@
|
||||
//! Compiletime lists used throughout the libafl universe
|
||||
|
||||
pub use tuple_list::{tuple_list, tuple_list_type, TupleList};
|
||||
|
||||
use core::any::TypeId;
|
||||
|
@ -1,7 +1,7 @@
|
||||
//! Eventmanager manages all events that go to other instances of the fuzzer.
|
||||
|
||||
pub mod logger;
|
||||
pub use logger::*;
|
||||
pub mod simple;
|
||||
pub use simple::*;
|
||||
pub mod llmp;
|
||||
pub use llmp::*;
|
||||
|
||||
|
@ -1,3 +1,4 @@
|
||||
//! A very simple event manager, that just supports log outputs, but no multiprocessing
|
||||
use alloc::{string::ToString, vec::Vec};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
@ -12,7 +13,7 @@ use crate::{
|
||||
|
||||
/// A simple, single-threaded event manager that just logs
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct LoggerEventManager<I, S, ST>
|
||||
pub struct SimpleEventManager<I, S, ST>
|
||||
where
|
||||
I: Input,
|
||||
ST: Stats, //CE: CustomEvent<I, OT>,
|
||||
@ -24,7 +25,7 @@ where
|
||||
phantom: PhantomData<S>,
|
||||
}
|
||||
|
||||
impl<I, S, ST> EventManager<I, S> for LoggerEventManager<I, S, ST>
|
||||
impl<I, S, ST> EventManager<I, S> for SimpleEventManager<I, S, ST>
|
||||
where
|
||||
I: Input,
|
||||
ST: Stats, //CE: CustomEvent<I, OT>,
|
||||
@ -51,7 +52,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, S, ST> LoggerEventManager<I, S, ST>
|
||||
impl<I, S, ST> SimpleEventManager<I, S, ST>
|
||||
where
|
||||
I: Input,
|
||||
ST: Stats, //TODO CE: CustomEvent,
|
@ -38,7 +38,7 @@ pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard(guard: &u32) {
|
||||
//*trace_byte = (*trace_byte).wrapping_add(1);
|
||||
}
|
||||
|
||||
/// Called when the targetprogram starts
|
||||
/// Called when the target program starts
|
||||
#[no_mangle]
|
||||
#[inline]
|
||||
pub unsafe extern "C" fn __sanitizer_cov_trace_pc_guard_init(mut start: *mut u32, stop: *mut u32) {
|
||||
|
@ -117,7 +117,6 @@ impl From<ParseIntError> for Error {
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
// TODO: no_std test
|
||||
#[cfg(feature = "std")]
|
||||
#[cfg(test)]
|
||||
@ -125,7 +124,7 @@ mod tests {
|
||||
|
||||
use crate::{
|
||||
bolts::tuples::tuple_list,
|
||||
corpus::{Corpus, InMemoryCorpus, Testcase},
|
||||
corpus::{Corpus, InMemoryCorpus, RandCorpusScheduler, Testcase},
|
||||
executors::{Executor, ExitKind, InProcessExecutor},
|
||||
inputs::{BytesInput, Input},
|
||||
mutators::{mutation_bitflip, ComposedByMutations, StdScheduledMutator},
|
||||
@ -137,7 +136,7 @@ mod tests {
|
||||
};
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
use crate::events::LoggerEventManager;
|
||||
use crate::events::SimpleEventManager;
|
||||
|
||||
fn harness<E: Executor<I>, I: Input>(_executor: &E, _buf: &[u8]) -> ExitKind {
|
||||
ExitKind::Ok
|
||||
@ -145,23 +144,24 @@ mod tests {
|
||||
|
||||
#[test]
|
||||
fn test_fuzzer() {
|
||||
let mut rand = StdRand::new(0);
|
||||
let rand = StdRand::new(0);
|
||||
|
||||
let mut corpus = InMemoryCorpus::<BytesInput, StdRand>::new();
|
||||
let mut corpus = InMemoryCorpus::<BytesInput>::new();
|
||||
let testcase = Testcase::new(vec![0; 4]).into();
|
||||
corpus.add(testcase);
|
||||
corpus.add(testcase).unwrap();
|
||||
|
||||
let mut state = State::new(
|
||||
rand,
|
||||
corpus,
|
||||
tuple_list!(),
|
||||
InMemoryCorpus::<BytesInput, StdRand>::new(),
|
||||
InMemoryCorpus::<BytesInput>::new(),
|
||||
tuple_list!(),
|
||||
);
|
||||
|
||||
let stats = SimpleStats::new(|s| {
|
||||
println!("{}", s);
|
||||
});
|
||||
let mut event_manager = LoggerEventManager::new(stats);
|
||||
let mut event_manager = SimpleEventManager::new(stats);
|
||||
|
||||
let mut executor = InProcessExecutor::new(
|
||||
"main",
|
||||
@ -175,29 +175,28 @@ mod tests {
|
||||
let mut mutator = StdScheduledMutator::new();
|
||||
mutator.add_mutation(mutation_bitflip);
|
||||
let stage = StdMutationalStage::new(mutator);
|
||||
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
|
||||
let fuzzer = StdFuzzer::new(RandCorpusScheduler::new(), tuple_list!(stage));
|
||||
|
||||
for i in 0..1000 {
|
||||
fuzzer
|
||||
.fuzz_one(&mut rand, &mut executor, &mut state, &mut event_manager)
|
||||
.fuzz_one(&mut state, &mut executor, &mut event_manager)
|
||||
.expect(&format!("Error in iter {}", i));
|
||||
}
|
||||
|
||||
let state_serialized = postcard::to_allocvec(&state).unwrap();
|
||||
let state_deserialized: State<
|
||||
InMemoryCorpus<BytesInput, _>,
|
||||
InMemoryCorpus<BytesInput>,
|
||||
(),
|
||||
BytesInput,
|
||||
InMemoryCorpus<BytesInput, _>,
|
||||
(),
|
||||
StdRand,
|
||||
InMemoryCorpus<BytesInput>,
|
||||
> = postcard::from_bytes(state_serialized.as_slice()).unwrap();
|
||||
assert_eq!(state.executions(), state_deserialized.executions());
|
||||
assert_eq!(state.corpus().count(), state_deserialized.corpus().count());
|
||||
|
||||
let corpus_serialized = postcard::to_allocvec(state.corpus()).unwrap();
|
||||
let corpus_deserialized: InMemoryCorpus<BytesInput, StdRand> =
|
||||
let corpus_deserialized: InMemoryCorpus<BytesInput> =
|
||||
postcard::from_bytes(corpus_serialized.as_slice()).unwrap();
|
||||
assert_eq!(state.corpus().count(), corpus_deserialized.count());
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -31,14 +31,3 @@ where
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
/// The maximum size of a testcase
|
||||
pub const DEFAULT_MAX_SIZE: usize = 1048576;
|
||||
|
||||
/// Interact with the maximum size
|
||||
pub trait HasMaxSize {
|
||||
/// The maximum size of the contents returned
|
||||
fn max_size(&self) -> usize;
|
||||
/// Sets the maximum size of the contents returned
|
||||
fn set_max_size(&mut self, max_size: usize);
|
||||
}
|
||||
|
@ -1,8 +1,9 @@
|
||||
//! A wide variety of mutations used during fuzzing.
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
inputs::{HasBytesVec, Input},
|
||||
mutators::*,
|
||||
state::{HasCorpus, HasRand},
|
||||
state::{HasCorpus, HasMaxSize, HasRand},
|
||||
utils::Rand,
|
||||
Error,
|
||||
};
|
||||
@ -27,20 +28,20 @@ pub enum MutationResult {
|
||||
|
||||
// TODO maybe the mutator arg is not needed
|
||||
/// The generic function type that identifies mutations
|
||||
pub type MutationFunction<I, M, S> = fn(&M, &mut S, &mut I) -> Result<MutationResult, Error>;
|
||||
pub type MutationFunction<I, S> = fn(&mut S, &mut I) -> Result<MutationResult, Error>;
|
||||
|
||||
pub trait ComposedByMutations<I, S>
|
||||
where
|
||||
I: Input,
|
||||
{
|
||||
/// Get a mutation by index
|
||||
fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, Self, S>;
|
||||
fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, S>;
|
||||
|
||||
/// Get the number of mutations
|
||||
fn mutations_count(&self) -> usize;
|
||||
|
||||
/// Add a mutation
|
||||
fn add_mutation(&mut self, mutation: MutationFunction<I, Self, S>);
|
||||
fn add_mutation(&mut self, mutation: MutationFunction<I, S>);
|
||||
}
|
||||
|
||||
/// Mem move in the own vec
|
||||
@ -123,15 +124,10 @@ const INTERESTING_32: [i32; 27] = [
|
||||
];
|
||||
|
||||
/// Bitflip mutation for inputs with a bytes vector
|
||||
pub fn mutation_bitflip<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bitflip<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
S: HasRand<R> + HasMaxSize,
|
||||
R: Rand,
|
||||
{
|
||||
if input.bytes().len() == 0 {
|
||||
@ -146,12 +142,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_byteflip<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_byteflip<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -169,12 +160,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_byteinc<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_byteinc<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -193,12 +179,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_bytedec<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bytedec<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -217,12 +198,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_byteneg<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_byteneg<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -240,12 +216,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_byterand<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_byterand<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -263,12 +234,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_byteadd<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_byteadd<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -291,12 +257,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_wordadd<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_wordadd<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -321,12 +282,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_dwordadd<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_dwordadd<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -351,12 +307,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_qwordadd<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_qwordadd<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -381,9 +332,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_byteinteresting<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
pub fn mutation_byteinteresting<I, R, S>(
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
@ -405,9 +354,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_wordinteresting<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
pub fn mutation_wordinteresting<I, R, S>(
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
@ -435,9 +382,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_dwordinteresting<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
pub fn mutation_dwordinteresting<I, R, S>(
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
@ -465,12 +410,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
pub fn mutation_bytesdelete<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bytesdelete<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -488,25 +428,20 @@ where
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
|
||||
pub fn mutation_bytesexpand<I, M, R, S>(
|
||||
mutator: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bytesexpand<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
M: HasMaxSize,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
S: HasRand<R> + HasMaxSize,
|
||||
R: Rand,
|
||||
{
|
||||
let max_size = state.max_size();
|
||||
let size = input.bytes().len();
|
||||
let off = state.rand_mut().below((size + 1) as u64) as usize;
|
||||
let mut len = 1 + state.rand_mut().below(16) as usize;
|
||||
|
||||
if size + len > mutator.max_size() {
|
||||
if mutator.max_size() > size {
|
||||
len = mutator.max_size() - size;
|
||||
if size + len > max_size {
|
||||
if max_size > size {
|
||||
len = max_size - size;
|
||||
} else {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
@ -518,25 +453,23 @@ where
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
|
||||
pub fn mutation_bytesinsert<I, M, R, S>(
|
||||
mutator: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bytesinsert<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
M: HasMaxSize,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
S: HasRand<R> + HasMaxSize,
|
||||
R: Rand,
|
||||
{
|
||||
let max_size = state.max_size();
|
||||
let size = input.bytes().len();
|
||||
if size == 0 {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
let off = state.rand_mut().below((size + 1) as u64) as usize;
|
||||
let mut len = 1 + state.rand_mut().below(16) as usize;
|
||||
|
||||
if size + len > mutator.max_size() {
|
||||
if mutator.max_size() > size {
|
||||
len = mutator.max_size() - size;
|
||||
if size + len > max_size {
|
||||
if max_size > size {
|
||||
len = max_size - size;
|
||||
} else {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
@ -551,25 +484,23 @@ where
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
|
||||
pub fn mutation_bytesrandinsert<I, M, R, S>(
|
||||
mutator: &M,
|
||||
|
||||
pub fn mutation_bytesrandinsert<I, R, S>(
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
where
|
||||
M: HasMaxSize,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
S: HasRand<R> + HasMaxSize,
|
||||
R: Rand,
|
||||
{
|
||||
let max_size = state.max_size();
|
||||
let size = input.bytes().len();
|
||||
let off = state.rand_mut().below((size + 1) as u64) as usize;
|
||||
let mut len = 1 + state.rand_mut().below(16) as usize;
|
||||
|
||||
if size + len > mutator.max_size() {
|
||||
if mutator.max_size() > size {
|
||||
len = mutator.max_size() - size;
|
||||
if size + len > max_size {
|
||||
if max_size > size {
|
||||
len = max_size - size;
|
||||
} else {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
@ -584,12 +515,7 @@ where
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
|
||||
pub fn mutation_bytesset<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bytesset<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -609,12 +535,7 @@ where
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
|
||||
pub fn mutation_bytesrandset<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bytesrandset<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -634,12 +555,7 @@ where
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
|
||||
pub fn mutation_bytescopy<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bytescopy<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -659,12 +575,7 @@ where
|
||||
Ok(MutationResult::Mutated)
|
||||
}
|
||||
|
||||
pub fn mutation_bytesswap<I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_bytesswap<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R>,
|
||||
@ -687,18 +598,15 @@ where
|
||||
}
|
||||
|
||||
/// Crossover insert mutation
|
||||
pub fn mutation_crossover_insert<C, I, M, R, S>(
|
||||
mutator: &M,
|
||||
|
||||
pub fn mutation_crossover_insert<C, I, R, S>(
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
where
|
||||
M: HasMaxSize,
|
||||
C: Corpus<I>,
|
||||
I: Input + HasBytesVec,
|
||||
R: Rand,
|
||||
S: HasRand<R> + HasCorpus<C, I>,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMaxSize,
|
||||
{
|
||||
let size = input.bytes().len();
|
||||
|
||||
@ -722,6 +630,7 @@ where
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
|
||||
let max_size = state.max_size();
|
||||
let from = state.rand_mut().below(other_size as u64) as usize;
|
||||
let to = state.rand_mut().below(size as u64) as usize;
|
||||
let mut len = state.rand_mut().below((other_size - from) as u64) as usize;
|
||||
@ -729,9 +638,9 @@ where
|
||||
let mut other_testcase = state.corpus().get(idx)?.borrow_mut();
|
||||
let other = other_testcase.load_input()?;
|
||||
|
||||
if size + len > mutator.max_size() {
|
||||
if mutator.max_size() > size {
|
||||
len = mutator.max_size() - size;
|
||||
if size + len > max_size {
|
||||
if max_size > size {
|
||||
len = max_size - size;
|
||||
} else {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
@ -745,9 +654,7 @@ where
|
||||
}
|
||||
|
||||
/// Crossover replace mutation
|
||||
pub fn mutation_crossover_replace<C, I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
pub fn mutation_crossover_replace<C, I, R, S>(
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
@ -808,12 +715,7 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) {
|
||||
}
|
||||
|
||||
/// Splicing mutation from AFL
|
||||
pub fn mutation_splice<C, I, M, R, S>(
|
||||
_: &M,
|
||||
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_splice<C, I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
C: Corpus<I>,
|
||||
I: Input + HasBytesVec,
|
||||
@ -970,7 +872,6 @@ pub fn read_tokens_file(f: &str, tokens: &mut Vec<Vec<u8>>) -> Result<u32, Error
|
||||
Ok(entries)
|
||||
}
|
||||
|
||||
/*
|
||||
#[cfg(test)]
|
||||
mod tests {
|
||||
#[cfg(feature = "std")]
|
||||
@ -1007,17 +908,6 @@ token2="B"
|
||||
let _ = fs::remove_file("test.tkns");
|
||||
}
|
||||
|
||||
struct WithMaxSize {}
|
||||
impl HasMaxSize for WithMaxSize {
|
||||
fn max_size(&self) -> usize {
|
||||
16000 as usize
|
||||
}
|
||||
|
||||
fn set_max_size(&mut self, _max_size: usize) {
|
||||
todo!("Not needed");
|
||||
}
|
||||
}
|
||||
|
||||
#[test]
|
||||
fn test_mutators() {
|
||||
let mut inputs = vec![
|
||||
@ -1030,16 +920,16 @@ token2="B"
|
||||
BytesInput::new(vec![1; 4]),
|
||||
];
|
||||
|
||||
let mut mutator = WithMaxSize {};
|
||||
let rand = StdRand::new(1337);
|
||||
let mut corpus = InMemoryCorpus::new();
|
||||
|
||||
let mut rand = StdRand::new(1337);
|
||||
let mut corpus: InMemoryCorpus<_, StdRand> = InMemoryCorpus::new();
|
||||
corpus
|
||||
.add(BytesInput::new(vec![0x42; 0x1337]).into())
|
||||
.unwrap();
|
||||
|
||||
corpus.add(BytesInput::new(vec![0x42; 0x1337]).into());
|
||||
let mut state = State::new(rand, corpus, (), InMemoryCorpus::new(), ());
|
||||
|
||||
let mut state = State::new(corpus, (), InMemoryCorpus::new(), ());
|
||||
|
||||
let mut mutations: Vec<MutationFunction<BytesInput, WithMaxSize, StdRand, _>> = vec![];
|
||||
let mut mutations: Vec<MutationFunction<_, _>> = vec![];
|
||||
|
||||
mutations.push(mutation_bitflip);
|
||||
mutations.push(mutation_byteflip);
|
||||
@ -1072,7 +962,7 @@ token2="B"
|
||||
for mutation in &mutations {
|
||||
for input in inputs.iter() {
|
||||
let mut mutant = input.clone();
|
||||
match mutation(&mut mutator, &mut rand, &mut state, &mut mutant).unwrap() {
|
||||
match mutation(&mut state, &mut mutant).unwrap() {
|
||||
MutationResult::Mutated => new_testcases.push(mutant),
|
||||
MutationResult::Skipped => (),
|
||||
};
|
||||
@ -1087,4 +977,3 @@ token2="B"
|
||||
*/
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
@ -1,13 +1,15 @@
|
||||
use crate::inputs::HasBytesVec;
|
||||
use alloc::vec::Vec;
|
||||
use core::{default::Default, fmt, marker::PhantomData};
|
||||
use fmt::Debug;
|
||||
use core::{
|
||||
default::Default,
|
||||
fmt::{self, Debug},
|
||||
marker::PhantomData,
|
||||
};
|
||||
|
||||
use crate::{
|
||||
corpus::Corpus,
|
||||
inputs::Input,
|
||||
mutators::{HasMaxSize, Mutator, DEFAULT_MAX_SIZE},
|
||||
state::{HasCorpus, HasMetadata, HasRand},
|
||||
inputs::{HasBytesVec, Input},
|
||||
mutators::Mutator,
|
||||
state::{HasCorpus, HasMaxSize, HasMetadata, HasRand},
|
||||
utils::Rand,
|
||||
Error,
|
||||
};
|
||||
@ -31,7 +33,7 @@ where
|
||||
let num = self.iterations(state, input);
|
||||
for _ in 0..num {
|
||||
let idx = self.schedule(self.mutations_count(), state, input);
|
||||
self.mutation_by_idx(idx)(self, state, input)?;
|
||||
self.mutation_by_idx(idx)(state, input)?;
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
@ -43,8 +45,7 @@ where
|
||||
S: HasRand<R>,
|
||||
R: Rand,
|
||||
{
|
||||
mutations: Vec<MutationFunction<I, Self, S>>,
|
||||
max_size: usize,
|
||||
mutations: Vec<MutationFunction<I, S>>,
|
||||
phantom: PhantomData<R>,
|
||||
}
|
||||
|
||||
@ -57,9 +58,8 @@ where
|
||||
fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
|
||||
write!(
|
||||
f,
|
||||
"StdScheduledMutator with {} Mutations, max_size: {}, for Input type {}",
|
||||
"StdScheduledMutator with {} Mutations for Input type {}",
|
||||
self.mutations.len(),
|
||||
self.max_size,
|
||||
core::any::type_name::<I>()
|
||||
)
|
||||
}
|
||||
@ -83,7 +83,7 @@ where
|
||||
R: Rand,
|
||||
{
|
||||
#[inline]
|
||||
fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, Self, S> {
|
||||
fn mutation_by_idx(&self, index: usize) -> MutationFunction<I, S> {
|
||||
self.mutations[index]
|
||||
}
|
||||
|
||||
@ -93,7 +93,7 @@ where
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn add_mutation(&mut self, mutation: MutationFunction<I, Self, S>) {
|
||||
fn add_mutation(&mut self, mutation: MutationFunction<I, S>) {
|
||||
self.mutations.push(mutation)
|
||||
}
|
||||
}
|
||||
@ -116,23 +116,6 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, R, S> HasMaxSize for StdScheduledMutator<I, R, S>
|
||||
where
|
||||
I: Input,
|
||||
S: HasRand<R>,
|
||||
R: Rand,
|
||||
{
|
||||
#[inline]
|
||||
fn max_size(&self) -> usize {
|
||||
self.max_size
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_max_size(&mut self, max_size: usize) {
|
||||
self.max_size = max_size;
|
||||
}
|
||||
}
|
||||
|
||||
impl<I, R, S> StdScheduledMutator<I, R, S>
|
||||
where
|
||||
I: Input,
|
||||
@ -143,16 +126,14 @@ where
|
||||
pub fn new() -> Self {
|
||||
Self {
|
||||
mutations: vec![],
|
||||
max_size: DEFAULT_MAX_SIZE,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
||||
/// Create a new StdScheduledMutator instance specifying mutations
|
||||
pub fn with_mutations(mutations: Vec<MutationFunction<I, Self, S>>) -> Self {
|
||||
pub fn with_mutations(mutations: Vec<MutationFunction<I, S>>) -> Self {
|
||||
StdScheduledMutator {
|
||||
mutations: mutations,
|
||||
max_size: DEFAULT_MAX_SIZE,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
@ -162,9 +143,9 @@ where
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct HavocBytesMutator<C, I, R, S, SM>
|
||||
where
|
||||
SM: ScheduledMutator<I, S> + HasMaxSize,
|
||||
SM: ScheduledMutator<I, S>,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
|
||||
C: Corpus<I>,
|
||||
R: Rand,
|
||||
{
|
||||
@ -174,9 +155,9 @@ where
|
||||
|
||||
impl<C, I, R, S, SM> Mutator<I, S> for HavocBytesMutator<C, I, R, S, SM>
|
||||
where
|
||||
SM: ScheduledMutator<I, S> + HasMaxSize,
|
||||
SM: ScheduledMutator<I, S>,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
|
||||
C: Corpus<I>,
|
||||
R: Rand,
|
||||
{
|
||||
@ -208,30 +189,11 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, I, R, S, SM> HasMaxSize for HavocBytesMutator<C, I, R, S, SM>
|
||||
where
|
||||
SM: ScheduledMutator<I, S> + HasMaxSize,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
|
||||
C: Corpus<I>,
|
||||
R: Rand,
|
||||
{
|
||||
#[inline]
|
||||
fn max_size(&self) -> usize {
|
||||
self.scheduled.max_size()
|
||||
}
|
||||
|
||||
#[inline]
|
||||
fn set_max_size(&mut self, max_size: usize) {
|
||||
self.scheduled.set_max_size(max_size);
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, I, R, S, SM> HavocBytesMutator<C, I, R, S, SM>
|
||||
where
|
||||
SM: ScheduledMutator<I, S> + HasMaxSize,
|
||||
SM: ScheduledMutator<I, S>,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
|
||||
C: Corpus<I>,
|
||||
R: Rand,
|
||||
{
|
||||
@ -249,7 +211,7 @@ where
|
||||
impl<C, I, R, S> Default for HavocBytesMutator<C, I, R, S, StdScheduledMutator<I, R, S>>
|
||||
where
|
||||
I: Input + HasBytesVec,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata,
|
||||
S: HasRand<R> + HasCorpus<C, I> + HasMetadata + HasMaxSize,
|
||||
C: Corpus<I>,
|
||||
R: Rand,
|
||||
{
|
||||
|
@ -4,7 +4,7 @@
|
||||
use crate::{
|
||||
inputs::{HasBytesVec, Input},
|
||||
mutators::*,
|
||||
state::{HasMetadata, HasRand},
|
||||
state::{HasMaxSize, HasMetadata, HasRand},
|
||||
utils::Rand,
|
||||
Error,
|
||||
};
|
||||
@ -30,17 +30,13 @@ impl TokensMetadata {
|
||||
}
|
||||
|
||||
/// Insert a dictionary token
|
||||
pub fn mutation_tokeninsert<I, M, R, S>(
|
||||
mutator: &M,
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_tokeninsert<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
M: HasMaxSize,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasMetadata + HasRand<R>,
|
||||
S: HasMetadata + HasRand<R> + HasMaxSize,
|
||||
R: Rand,
|
||||
{
|
||||
let max_size = state.max_size();
|
||||
let tokens_len = {
|
||||
let meta = state.metadata().get::<TokensMetadata>();
|
||||
if meta.is_none() {
|
||||
@ -60,9 +56,9 @@ where
|
||||
let token = &meta.tokens[token_idx];
|
||||
let mut len = token.len();
|
||||
|
||||
if size + len > mutator.max_size() {
|
||||
if mutator.max_size() > size {
|
||||
len = mutator.max_size() - size;
|
||||
if size + len > max_size {
|
||||
if max_size > size {
|
||||
len = max_size - size;
|
||||
} else {
|
||||
return Ok(MutationResult::Skipped);
|
||||
}
|
||||
@ -76,13 +72,8 @@ where
|
||||
}
|
||||
|
||||
/// Overwrite with a dictionary token
|
||||
pub fn mutation_tokenreplace<I, M, R, S>(
|
||||
_: &M,
|
||||
state: &mut S,
|
||||
input: &mut I,
|
||||
) -> Result<MutationResult, Error>
|
||||
pub fn mutation_tokenreplace<I, R, S>(state: &mut S, input: &mut I) -> Result<MutationResult, Error>
|
||||
where
|
||||
M: HasMaxSize,
|
||||
I: Input + HasBytesVec,
|
||||
S: HasMetadata + HasRand<R>,
|
||||
R: Rand,
|
||||
|
@ -24,6 +24,9 @@ use crate::{
|
||||
#[cfg(feature = "std")]
|
||||
use crate::inputs::bytes::BytesInput;
|
||||
|
||||
/// The maximum size of a testcase
|
||||
pub const DEFAULT_MAX_SIZE: usize = 1048576;
|
||||
|
||||
/// Trait for elements offering a corpus
|
||||
pub trait HasCorpus<C, I>
|
||||
where
|
||||
@ -36,6 +39,14 @@ where
|
||||
fn corpus_mut(&mut self) -> &mut C;
|
||||
}
|
||||
|
||||
/// Interact with the maximum size
|
||||
pub trait HasMaxSize {
|
||||
/// The maximum size hint for items and mutations returned
|
||||
fn max_size(&self) -> usize;
|
||||
/// Sets the maximum size hint for the items and mutations
|
||||
fn set_max_size(&mut self, max_size: usize);
|
||||
}
|
||||
|
||||
/// Trait for elements offering a corpus of solutions
|
||||
pub trait HasSolutions<C, I>
|
||||
where
|
||||
@ -204,6 +215,8 @@ where
|
||||
objectives: OFT,
|
||||
/// Metadata stored for this state by one of the components
|
||||
metadata: SerdeAnyMap,
|
||||
/// MaxSize testcase size for mutators that appreciate it
|
||||
max_size: usize,
|
||||
|
||||
phantom: PhantomData<I>,
|
||||
}
|
||||
@ -362,6 +375,24 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, FT, I, OFT, R, SC> HasMaxSize for State<C, FT, I, OFT, R, SC>
|
||||
where
|
||||
C: Corpus<I>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
FT: FeedbacksTuple<I>,
|
||||
SC: Corpus<I>,
|
||||
OFT: FeedbacksTuple<I>,
|
||||
{
|
||||
fn max_size(&self) -> usize {
|
||||
self.max_size
|
||||
}
|
||||
|
||||
fn set_max_size(&mut self, max_size: usize) {
|
||||
self.max_size = max_size
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, FT, I, OFT, R, SC> HasStartTime for State<C, FT, I, OFT, R, SC>
|
||||
where
|
||||
C: Corpus<I>,
|
||||
@ -638,6 +669,7 @@ where
|
||||
feedbacks,
|
||||
solutions,
|
||||
objectives,
|
||||
max_size: DEFAULT_MAX_SIZE,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user