cmplog observer
This commit is contained in:
parent
ccfc95aa3a
commit
933b65dd86
@ -17,8 +17,7 @@ debug = true
|
||||
|
||||
[dependencies]
|
||||
libafl = { path = "../../libafl/" }
|
||||
|
||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_edges", "libfuzzer"] }
|
||||
libafl_targets = { path = "../../libafl_targets/", features = ["sancov_pcguard_edges", "sancov_cmplog", "libfuzzer"] }
|
||||
|
||||
[build-dependencies]
|
||||
cc = { version = "1.0", features = ["parallel"] }
|
||||
|
@ -12,11 +12,11 @@ use libafl::{
|
||||
events::setup_restarting_mgr_std,
|
||||
executors::{inprocess::InProcessExecutor, ExitKind},
|
||||
feedback_or,
|
||||
feedbacks::{CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback},
|
||||
feedbacks::{CmpFeedback, CrashFeedback, MapFeedbackState, MaxMapFeedback, TimeFeedback},
|
||||
fuzzer::{Fuzzer, StdFuzzer},
|
||||
inputs::{BytesInput, HasTargetBytes},
|
||||
mutators::scheduled::{havoc_mutations, StdScheduledMutator},
|
||||
mutators::token_mutations::I2SRandReplace,
|
||||
mutators::token_mutations::{I2SRandReplace, Tokens},
|
||||
observers::{StdMapObserver, TimeObserver},
|
||||
stages::{StdMutationalStage, TracingStage},
|
||||
state::{HasCorpus, StdState},
|
||||
@ -72,6 +72,9 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
|
||||
// Create an observation channel to keep track of the execution time
|
||||
let time_observer = TimeObserver::new("time");
|
||||
|
||||
let cmplog = unsafe { &mut CMPLOG_MAP };
|
||||
let cmplog_observer = CmpLogObserver::new("cmplog", cmplog);
|
||||
|
||||
let cmplog = unsafe { &mut CMPLOG_MAP };
|
||||
let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true);
|
||||
|
||||
|
@ -361,9 +361,12 @@ where
|
||||
}
|
||||
|
||||
/// Merge two `TupeList`
|
||||
pub trait Merge<T> {
|
||||
pub trait Merge<T>: TupleList
|
||||
where
|
||||
T: TupleList,
|
||||
{
|
||||
/// The Resulting [`TupleList`], of an [`Merge::merge()`] call
|
||||
type MergeResult;
|
||||
type MergeResult: TupleList;
|
||||
|
||||
/// Merge and return the merged tuple
|
||||
#[must_use]
|
||||
@ -371,7 +374,10 @@ pub trait Merge<T> {
|
||||
}
|
||||
|
||||
/// Implement merge for an empty tuple list.
|
||||
impl<T> Merge<T> for () {
|
||||
impl<T> Merge<T> for ()
|
||||
where
|
||||
T: TupleList,
|
||||
{
|
||||
type MergeResult = T;
|
||||
|
||||
fn merge(self, value: T) -> Self::MergeResult {
|
||||
@ -382,7 +388,10 @@ impl<T> Merge<T> for () {
|
||||
/// Implement merge for non-empty tuple list.
|
||||
impl<Head, Tail, T> Merge<T> for (Head, Tail)
|
||||
where
|
||||
T: TupleList,
|
||||
Self: TupleList,
|
||||
Tail: Merge<T>,
|
||||
(Head, Tail::MergeResult): TupleList,
|
||||
{
|
||||
type MergeResult = (Head, Tail::MergeResult);
|
||||
|
||||
|
@ -115,7 +115,7 @@ impl<'a, CM> StdCmpObserver<'a, CM>
|
||||
where
|
||||
CM: CmpMap,
|
||||
{
|
||||
/// Creates a new [`CmpObserver`] with the given name.
|
||||
/// Creates a new [`StdCmpObserver`] with the given name.
|
||||
#[must_use]
|
||||
pub fn new(name: &'static str, map: &'a mut CM) -> Self {
|
||||
Self {
|
||||
|
@ -1,96 +1,163 @@
|
||||
use core::{marker::PhantomData, mem::drop};
|
||||
use core::marker::PhantomData;
|
||||
|
||||
use crate::{
|
||||
bolts::rands::Rand,
|
||||
corpus::Corpus,
|
||||
executors::{Executor, HasExecHooksTuple, HasObservers, HasObserversHooks},
|
||||
fuzzer::Evaluator,
|
||||
inputs::Input,
|
||||
mark_feature_time,
|
||||
observers::ObserversTuple,
|
||||
mutators::Mutator,
|
||||
stages::Stage,
|
||||
start_timer,
|
||||
state::{HasClientPerfStats, HasCorpus, HasExecutions},
|
||||
state::{HasClientPerfStats, HasCorpus, HasRand},
|
||||
Error,
|
||||
};
|
||||
|
||||
#[cfg(feature = "introspection")]
|
||||
use crate::stats::PerfFeature;
|
||||
|
||||
/// The default mutational stage
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct TracingStage<C, EM, I, OT, S, TE, Z>
|
||||
// TODO multi mutators stage
|
||||
|
||||
/// A Mutational stage is the stage in a fuzzing run that mutates inputs.
|
||||
/// Mutational stages will usually have a range of mutations that are
|
||||
/// being applied to the input one by one, between executions.
|
||||
pub trait TracingStage<C, E, EM, I, M, S, Z>: Stage<E, EM, S, Z>
|
||||
where
|
||||
I: Input,
|
||||
C: Corpus<I>,
|
||||
TE: Executor<EM, I, S, Z> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Z>,
|
||||
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
|
||||
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
|
||||
M: Mutator<I, S>,
|
||||
I: Input,
|
||||
S: HasClientPerfStats + HasCorpus<C, I>,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
tracer_executor: TE,
|
||||
#[allow(clippy::type_complexity)]
|
||||
phantom: PhantomData<(C, EM, I, OT, S, TE, Z)>,
|
||||
/// The mutator registered for this stage
|
||||
fn mutator(&self) -> &M;
|
||||
|
||||
/// The mutator registered for this stage (mutable)
|
||||
fn mutator_mut(&mut self) -> &mut M;
|
||||
|
||||
/// Gets the number of iterations this mutator should run for.
|
||||
fn iterations(&self, state: &mut S) -> usize;
|
||||
|
||||
/// Runs this (mutational) stage for the given testcase
|
||||
#[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely...
|
||||
fn perform_mutational(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error> {
|
||||
let num = self.iterations(state);
|
||||
|
||||
for i in 0..num {
|
||||
start_timer!(state);
|
||||
let mut input = state
|
||||
.corpus()
|
||||
.get(corpus_idx)?
|
||||
.borrow_mut()
|
||||
.load_input()?
|
||||
.clone();
|
||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||
|
||||
start_timer!(state);
|
||||
self.mutator_mut().mutate(state, &mut input, i as i32)?;
|
||||
mark_feature_time!(state, PerfFeature::Mutate);
|
||||
|
||||
// Time is measured directly the `evaluate_input` function
|
||||
let (_, corpus_idx) = fuzzer.evaluate_input(state, executor, manager, input)?;
|
||||
|
||||
start_timer!(state);
|
||||
self.mutator_mut().post_exec(state, i as i32, corpus_idx)?;
|
||||
mark_feature_time!(state, PerfFeature::MutatePostExec);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
|
||||
impl<E, C, EM, I, OT, S, TE, Z> Stage<E, EM, S, Z> for TracingStage<C, EM, I, OT, S, TE, Z>
|
||||
/// Default value, how many iterations each stage gets, as an upper bound
|
||||
/// It may randomly continue earlier.
|
||||
pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128;
|
||||
|
||||
/// The default mutational stage
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct StdMutationalStage<C, E, EM, I, M, R, S, Z>
|
||||
where
|
||||
I: Input,
|
||||
C: Corpus<I>,
|
||||
TE: Executor<EM, I, S, Z> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Z>,
|
||||
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
|
||||
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
|
||||
M: Mutator<I, S>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
mutator: M,
|
||||
#[allow(clippy::type_complexity)]
|
||||
phantom: PhantomData<(C, E, EM, I, R, S, Z)>,
|
||||
}
|
||||
|
||||
impl<C, E, EM, I, M, R, S, Z> MutationalStage<C, E, EM, I, M, S, Z>
|
||||
for StdMutationalStage<C, E, EM, I, M, R, S, Z>
|
||||
where
|
||||
C: Corpus<I>,
|
||||
M: Mutator<I, S>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
/// The mutator, added to this stage
|
||||
#[inline]
|
||||
fn mutator(&self) -> &M {
|
||||
&self.mutator
|
||||
}
|
||||
|
||||
/// The list of mutators, added to this stage (as mutable ref)
|
||||
#[inline]
|
||||
fn mutator_mut(&mut self) -> &mut M {
|
||||
&mut self.mutator
|
||||
}
|
||||
|
||||
/// Gets the number of iterations as a random number
|
||||
fn iterations(&self, state: &mut S) -> usize {
|
||||
1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, E, EM, I, M, R, S, Z> Stage<E, EM, S, Z> for StdMutationalStage<C, E, EM, I, M, R, S, Z>
|
||||
where
|
||||
C: Corpus<I>,
|
||||
M: Mutator<I, S>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
#[inline]
|
||||
fn perform(
|
||||
&mut self,
|
||||
fuzzer: &mut Z,
|
||||
_executor: &mut E,
|
||||
executor: &mut E,
|
||||
state: &mut S,
|
||||
manager: &mut EM,
|
||||
corpus_idx: usize,
|
||||
) -> Result<(), Error> {
|
||||
start_timer!(state);
|
||||
let input = state
|
||||
.corpus()
|
||||
.get(corpus_idx)?
|
||||
.borrow_mut()
|
||||
.load_input()?
|
||||
.clone();
|
||||
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
|
||||
|
||||
start_timer!(state);
|
||||
self.tracer_executor
|
||||
.pre_exec_observers(fuzzer, state, manager, &input)?;
|
||||
mark_feature_time!(state, PerfFeature::PreExecObservers);
|
||||
|
||||
start_timer!(state);
|
||||
drop(
|
||||
self.tracer_executor
|
||||
.run_target(fuzzer, state, manager, &input)?,
|
||||
);
|
||||
mark_feature_time!(state, PerfFeature::TargetExecution);
|
||||
|
||||
*state.executions_mut() += 1;
|
||||
|
||||
start_timer!(state);
|
||||
self.tracer_executor
|
||||
.post_exec_observers(fuzzer, state, manager, &input)?;
|
||||
mark_feature_time!(state, PerfFeature::PostExecObservers);
|
||||
|
||||
Ok(())
|
||||
self.perform_mutational(fuzzer, executor, state, manager, corpus_idx)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, EM, I, OT, S, TE, Z> TracingStage<C, EM, I, OT, S, TE, Z>
|
||||
impl<C, E, EM, I, M, R, S, Z> StdMutationalStage<C, E, EM, I, M, R, S, Z>
|
||||
where
|
||||
I: Input,
|
||||
C: Corpus<I>,
|
||||
TE: Executor<EM, I, S, Z> + HasObservers<OT> + HasObserversHooks<EM, I, OT, S, Z>,
|
||||
OT: ObserversTuple + HasExecHooksTuple<EM, I, S, Z>,
|
||||
S: HasClientPerfStats + HasExecutions + HasCorpus<C, I>,
|
||||
M: Mutator<I, S>,
|
||||
I: Input,
|
||||
R: Rand,
|
||||
S: HasClientPerfStats + HasCorpus<C, I> + HasRand<R>,
|
||||
Z: Evaluator<E, EM, I, S>,
|
||||
{
|
||||
/// Creates a new default mutational stage
|
||||
pub fn new(tracer_executor: TE) -> Self {
|
||||
pub fn new(mutator: M) -> Self {
|
||||
Self {
|
||||
tracer_executor,
|
||||
mutator,
|
||||
phantom: PhantomData,
|
||||
}
|
||||
}
|
||||
|
@ -2,9 +2,12 @@
|
||||
//! The values will then be used in subsequent mutations.
|
||||
|
||||
use libafl::{
|
||||
observers::{CmpMap, CmpValues},
|
||||
bolts::{ownedref::OwnedRefMut, tuples::Named},
|
||||
executors::HasExecHooks,
|
||||
observers::{CmpMap, CmpObserver, CmpValues, Observer},
|
||||
Error,
|
||||
};
|
||||
|
||||
use serde::{Deserialize, Serialize};
|
||||
|
||||
// TODO compile time flag
|
||||
@ -140,12 +143,11 @@ pub static mut libafl_cmplog_enabled: u8 = 0;
|
||||
|
||||
pub use libafl_cmplog_enabled as CMPLOG_ENABLED;
|
||||
|
||||
/// A [`CmpObserver`] observer for `CmpLog`
|
||||
/// A [`CmpObserver`] observer for CmpLog
|
||||
#[derive(Serialize, Deserialize, Debug)]
|
||||
pub struct CmpLogObserver<'a> {
|
||||
map: OwnedRefMut<'a, CmpLogMap>,
|
||||
size: Option<OwnedRefMut<'a, usize>>,
|
||||
add_meta: bool,
|
||||
name: String,
|
||||
}
|
||||
|
||||
@ -169,10 +171,7 @@ impl<'a> CmpObserver<CmpLogMap> for CmpLogObserver<'a> {
|
||||
|
||||
impl<'a> Observer for CmpLogObserver<'a> {}
|
||||
|
||||
impl<'a, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for CmpLogObserver<'a>
|
||||
where
|
||||
S: HasMetadata,
|
||||
{
|
||||
impl<'a, EM, I, S, Z> HasExecHooks<EM, I, S, Z> for CmpLogObserver<'a> {
|
||||
fn pre_exec(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
@ -190,16 +189,13 @@ where
|
||||
fn post_exec(
|
||||
&mut self,
|
||||
_fuzzer: &mut Z,
|
||||
state: &mut S,
|
||||
_state: &mut S,
|
||||
_mgr: &mut EM,
|
||||
_input: &I,
|
||||
) -> Result<(), Error> {
|
||||
unsafe {
|
||||
CMPLOG_ENABLED = 0;
|
||||
}
|
||||
if self.add_meta {
|
||||
self.add_cmpvalues_meta(state);
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
}
|
||||
@ -213,11 +209,11 @@ impl<'a> Named for CmpLogObserver<'a> {
|
||||
impl<'a> CmpLogObserver<'a> {
|
||||
/// Creates a new [`CmpLogObserver`] with the given name.
|
||||
#[must_use]
|
||||
pub fn new(name: &'static str, map: &'a mut CmpLogMap, add_meta: bool) -> Self {
|
||||
pub fn new(name: &'static str, map: &'a mut CmpLogMap) -> Self {
|
||||
Self {
|
||||
name: name.to_string(),
|
||||
size: None,
|
||||
add_meta,
|
||||
|
||||
map: OwnedRefMut::Ref(map),
|
||||
}
|
||||
}
|
||||
|
@ -33,13 +33,13 @@ void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) {
|
||||
uintptr_t k = RETADDR;
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
k &= MAP_SIZE - 1;
|
||||
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
k &= MAP_SIZE - 1;
|
||||
__libafl_targets_value_profile1(k, arg1, arg2);
|
||||
#endif
|
||||
#ifdef SANCOV_CMPLOG
|
||||
k &= CMPLOG_MAP_W - 1;
|
||||
__libafl_targets_cmplog(k, 1, (uint64_t)arg1, (uint64_t)arg2);
|
||||
#endif
|
||||
|
||||
@ -50,13 +50,13 @@ void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) {
|
||||
uintptr_t k = RETADDR;
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
k &= MAP_SIZE - 1;
|
||||
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
k &= MAP_SIZE - 1;
|
||||
__libafl_targets_value_profile2(k, arg1, arg2);
|
||||
#endif
|
||||
#ifdef SANCOV_CMPLOG
|
||||
k &= CMPLOG_MAP_W - 1;
|
||||
__libafl_targets_cmplog(k, 2, (uint64_t)arg1, (uint64_t)arg2);
|
||||
#endif
|
||||
|
||||
@ -67,13 +67,13 @@ void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
|
||||
uintptr_t k = RETADDR;
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
k &= MAP_SIZE - 1;
|
||||
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
k &= MAP_SIZE - 1;
|
||||
__libafl_targets_value_profile4(k, arg1, arg2);
|
||||
#endif
|
||||
#ifdef SANCOV_CMPLOG
|
||||
k &= CMPLOG_MAP_W - 1;
|
||||
__libafl_targets_cmplog(k, 4, (uint64_t)arg1, (uint64_t)arg2);
|
||||
#endif
|
||||
|
||||
@ -84,6 +84,7 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
|
||||
uintptr_t k = RETADDR;
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
|
||||
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
k &= MAP_SIZE - 1;
|
||||
__libafl_targets_value_profile8(k, arg1, arg2);
|
||||
@ -93,13 +94,6 @@ void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
|
||||
__libafl_targets_cmplog(k, 8, (uint64_t)arg1, (uint64_t)arg2);
|
||||
#endif
|
||||
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
__libafl_targets_value_profile8(k, arg1, arg2);
|
||||
#endif
|
||||
#ifdef SANCOV_CMPLOG
|
||||
__libafl_targets_cmplog(k, 8, (uint64_t)arg1, (uint64_t)arg2);
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
@ -112,9 +106,9 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
|
||||
uintptr_t k = rt + i;
|
||||
k = (k >> 4) ^ (k << 8);
|
||||
k &= MAP_SIZE - 1;
|
||||
// val , cases[i + 2]
|
||||
#ifdef SANCOV_VALUE_PROFILE
|
||||
k &= MAP_SIZE - 1;
|
||||
switch (cases[1]) {
|
||||
case 8:
|
||||
__libafl_targets_value_profile1(k, (uint8_t)val, (uint8_t)cases[i + 2]);
|
||||
@ -131,6 +125,7 @@ void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
|
||||
}
|
||||
#endif
|
||||
#ifdef SANCOV_CMPLOG
|
||||
k &= CMPLOG_MAP_W - 1;
|
||||
__libafl_targets_cmplog(k, cases[1] / 8, val, cases[i + 2]);
|
||||
#endif
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user