Fix usage of TracingStage (#3062)

* real fix

* more

* debug

* fix

* fixer

* mmmm

* mm

* mm

* mm

* fix

* fix atheris

* ?
This commit is contained in:
Dongjia "toka" Zhang 2025-03-11 14:37:19 +01:00 committed by GitHub
parent f4cb9a827d
commit 226a20e6cf
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
21 changed files with 186 additions and 199 deletions

View File

@ -370,7 +370,7 @@ unsafe fn fuzz(
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(

View File

@ -218,7 +218,7 @@ fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s =

View File

@ -344,7 +344,7 @@ unsafe fn fuzz(options: &FuzzerOptions) -> Result<(), Error> {
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(

View File

@ -391,7 +391,7 @@ fn fuzz(
println!("We imported {} inputs from disk.", state.corpus().count());
}
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// The order of the stages matter!
let mut stages = tuple_list!(calibration, tracing, i2s, power);

View File

@ -403,7 +403,7 @@ fn fuzz(
println!("We imported {} input(s) from disk.", state.corpus().count());
}
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// The order of the stages matter!
let mut stages = tuple_list!(calibration, tracing, i2s, power);

View File

@ -316,7 +316,7 @@ impl<M: Monitor> Instance<'_, M> {
let mut shadow_executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
let tracing = ShadowTracingStage::new(&mut shadow_executor);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(

View File

@ -192,7 +192,7 @@ impl<M: Monitor> Instance<'_, M> {
I2SRandReplace::new()
)));
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// Setup a MOPT mutator
let mutator = StdMOptMutator::new(

View File

@ -232,7 +232,7 @@ pub fn fuzz() {
)));
// Setup an havoc mutator with a mutational stage
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(tracing, i2s, StdMutationalStage::new(mutator),);

View File

@ -240,7 +240,7 @@ pub fn fuzz() {
)));
// Setup an havoc mutator with a mutational stage
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
let mutator = StdScheduledMutator::new(havoc_mutations());
let mut stages = tuple_list!(tracing, i2s, StdMutationalStage::new(mutator),);

View File

@ -14,7 +14,7 @@ use clap::{Arg, ArgAction, Command};
use libafl::{
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
events::{launcher::Launcher, EventConfig},
executors::{inprocess::InProcessExecutor, ExitKind},
executors::{inprocess::InProcessExecutor, ExitKind, ShadowExecutor},
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -28,7 +28,7 @@ use libafl::{
},
observers::{CanTrack, HitcountsMapObserver, StdMapObserver, TimeObserver},
schedulers::{IndexesLenTimeMinimizerScheduler, QueueScheduler},
stages::{StdMutationalStage, TracingStage},
stages::{ShadowTracingStage, StdMutationalStage, TracingStage},
state::{HasCorpus, StdState},
Error, HasMetadata,
};
@ -216,14 +216,9 @@ pub extern "C" fn LLVMFuzzerRunDriver(
ExitKind::Ok
};
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
// Setup a tracing stage in which we log comparisons
let tracing = TracingStage::new(InProcessExecutor::new(
&mut harness,
tuple_list!(cmplog_observer),
&mut fuzzer,
&mut state,
&mut mgr,
)?);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s =

View File

@ -19,7 +19,7 @@ use libafl::{
Error, HasMetadata,
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
events::SimpleRestartingEventManager,
executors::{ExitKind, inprocess::InProcessExecutor},
executors::{ExitKind, ShadowExecutor, inprocess::InProcessExecutor},
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -34,7 +34,7 @@ use libafl::{
IndexesLenTimeMinimizerScheduler, StdWeightedScheduler, powersched::PowerSchedule,
},
stages::{
StdMutationalStage, TracingStage, calibrate::CalibrationStage,
ShadowTracingStage, StdMutationalStage, calibrate::CalibrationStage,
power::StdPowerMutationalStage,
},
state::{HasCorpus, StdState},
@ -331,8 +331,6 @@ fn fuzz(
ExitKind::Ok
};
let mut tracing_harness = harness;
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
@ -343,18 +341,10 @@ fn fuzz(
timeout,
)?;
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
// Setup a tracing stage in which we log comparisons
let tracing = TracingStage::new(
InProcessExecutor::with_timeout(
&mut tracing_harness,
tuple_list!(cmplog_observer),
&mut fuzzer,
&mut state,
&mut mgr,
timeout * 10,
)?,
// Give it more time!
);
let tracing = ShadowTracingStage::new();
// The order of the stages matter!
let mut stages = tuple_list!(calibration, tracing, i2s, power);

View File

@ -18,10 +18,7 @@ use clap::{Arg, Command};
use libafl::{
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
events::SimpleRestartingEventManager,
executors::{
inprocess::{HookableInProcessExecutor, InProcessExecutor},
ExitKind,
},
executors::{inprocess::HookableInProcessExecutor, ExitKind, ShadowExecutor},
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -36,8 +33,8 @@ use libafl::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
},
stages::{
calibrate::CalibrationStage, power::StdPowerMutationalStage, StdMutationalStage,
TracingStage,
calibrate::CalibrationStage, power::StdPowerMutationalStage, ShadowTracingStage,
StdMutationalStage,
},
state::{HasCorpus, StdState},
Error, HasMetadata,
@ -343,24 +340,10 @@ fn fuzz(
ExitKind::Ok
};
let mut tracing_harness = harness;
let ctx_hook = CtxHook::new();
// Setup a tracing stage in which we log comparisons
let tracing = TracingStage::new(
InProcessExecutor::with_timeout(
&mut tracing_harness,
tuple_list!(cmplog_observer),
&mut fuzzer,
&mut state,
&mut mgr,
timeout * 10,
)?,
// Give it more time!
);
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = HookableInProcessExecutor::with_timeout_generic(
let executor = HookableInProcessExecutor::with_timeout_generic(
tuple_list!(ctx_hook),
&mut harness,
tuple_list!(edges_observer, time_observer),
@ -370,6 +353,10 @@ fn fuzz(
timeout,
)?;
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
// Setup a tracing stage in which we log comparisons
let tracing = ShadowTracingStage::new();
// The order of the stages matter!
let mut stages = tuple_list!(calibration, tracing, i2s, power);

View File

@ -19,7 +19,7 @@ use content_inspector::inspect;
use libafl::{
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
events::SimpleRestartingEventManager,
executors::{inprocess::InProcessExecutor, ExitKind},
executors::{inprocess::InProcessExecutor, ExitKind, ShadowExecutor},
feedback_or,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback},
fuzzer::{Fuzzer, StdFuzzer},
@ -40,7 +40,7 @@ use libafl::{
},
stages::{
calibrate::CalibrationStage, power::StdPowerMutationalStage, GeneralizationStage,
StdMutationalStage, TracingStage,
ShadowTracingStage, StdMutationalStage,
},
state::{HasCorpus, StdState},
Error, HasMetadata,
@ -400,8 +400,6 @@ fn fuzz_binary(
ExitKind::Ok
};
let mut tracing_harness = harness;
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
@ -413,14 +411,9 @@ fn fuzz_binary(
)?;
// Setup a tracing stage in which we log comparisons
let tracing = TracingStage::new(InProcessExecutor::with_timeout(
&mut tracing_harness,
tuple_list!(cmplog_observer),
&mut fuzzer,
&mut state,
&mut mgr,
timeout * 10,
)?);
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
let tracing = ShadowTracingStage::new();
// The order of the stages matter!
let mut stages = tuple_list!(calibration, tracing, i2s, power);
@ -632,8 +625,6 @@ fn fuzz_text(
ExitKind::Ok
};
let mut tracing_harness = harness;
let generalization = GeneralizationStage::new(&edges_observer);
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
@ -646,15 +637,8 @@ fn fuzz_text(
timeout,
)?;
// Setup a tracing stage in which we log comparisons
let tracing = TracingStage::new(InProcessExecutor::with_timeout(
&mut tracing_harness,
tuple_list!(cmplog_observer),
&mut fuzzer,
&mut state,
&mut mgr,
// Give it more time!
timeout * 10,
)?);
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
let tracing = ShadowTracingStage::new();
// The order of the stages matter!
let mut stages = tuple_list!(generalization, calibration, tracing, i2s, power, grimoire);

View File

@ -152,7 +152,7 @@ fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Re
}
// Setup a tracing stage in which we log comparisons
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new())));

View File

@ -190,7 +190,7 @@ fn fuzz(
}
// Setup a tracing stage in which we log comparisons
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(I2SRandReplace::new())));

View File

@ -37,7 +37,7 @@ pub use sync::*;
#[cfg(feature = "std")]
pub use time_tracker::TimeTrackingStageWrapper;
pub use tmin::{ObserverEqualityFactory, ObserverEqualityFeedback, StdTMinMutationalStage};
pub use tracing::{ShadowTracingStage, TracingStage};
pub use tracing::TracingStage;
pub use tuneable::*;
use tuple_list::NonEmptyTuple;
#[cfg(feature = "unicode")]
@ -57,6 +57,9 @@ pub mod mutational;
pub mod push;
pub mod tmin;
pub mod shadow;
pub use shadow::*;
pub mod replay;
pub use replay::*;

139
libafl/src/stages/shadow.rs Normal file
View File

@ -0,0 +1,139 @@
//! A stage that runs the shadow executor using also the shadow observers. Unlike tracing stage, this
//! stage *CAN* be used with inprocess executor.
use alloc::{
borrow::{Cow, ToOwned},
string::ToString,
};
use core::{fmt::Debug, marker::PhantomData};
use libafl_bolts::Named;
#[cfg(feature = "introspection")]
use crate::monitors::stats::PerfFeature;
use crate::{
Error, HasNamedMetadata,
corpus::HasCurrentCorpusId,
executors::{Executor, HasObservers, ShadowExecutor},
mark_feature_time,
observers::ObserversTuple,
stages::{Restartable, RetryCountRestartHelper, Stage},
start_timer,
state::{HasCorpus, HasCurrentTestcase, HasExecutions, MaybeHasClientPerfMonitor},
};
/// A stage that runs the shadow executor using also the shadow observers
#[derive(Clone, Debug)]
pub struct ShadowTracingStage<E, EM, I, SOT, S, Z> {
name: Cow<'static, str>,
phantom: PhantomData<(E, EM, I, SOT, S, Z)>,
}
impl<E, EM, I, SOT, S, Z> Default for ShadowTracingStage<E, EM, I, SOT, S, Z>
where
E: Executor<EM, I, S, Z> + HasObservers,
S: HasExecutions + HasCorpus<I>,
SOT: ObserversTuple<I, S>,
{
fn default() -> Self {
Self::new()
}
}
/// The counter for giving this stage unique id
static mut SHADOW_TRACING_STAGE_ID: usize = 0;
/// Name for shadow tracing stage
pub static SHADOW_TRACING_STAGE_NAME: &str = "shadow";
impl<E, EM, I, SOT, S, Z> Named for ShadowTracingStage<E, EM, I, SOT, S, Z> {
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl<E, EM, I, SOT, S, Z> Stage<ShadowExecutor<E, I, S, SOT>, EM, S, Z>
for ShadowTracingStage<E, EM, I, SOT, S, Z>
where
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
SOT: ObserversTuple<I, S>,
S: HasExecutions
+ HasCorpus<I>
+ HasNamedMetadata
+ Debug
+ HasCurrentTestcase<I>
+ HasCurrentCorpusId
+ MaybeHasClientPerfMonitor,
{
#[inline]
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut ShadowExecutor<E, I, S, SOT>,
state: &mut S,
manager: &mut EM,
) -> Result<(), Error> {
start_timer!(state);
let input = state.current_input_cloned()?;
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
start_timer!(state);
executor
.shadow_observers_mut()
.pre_exec_all(state, &input)?;
executor.observers_mut().pre_exec_all(state, &input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers);
start_timer!(state);
let exit_kind = executor.run_target(fuzzer, state, manager, &input)?;
mark_feature_time!(state, PerfFeature::TargetExecution);
start_timer!(state);
executor
.shadow_observers_mut()
.post_exec_all(state, &input, &exit_kind)?;
executor
.observers_mut()
.post_exec_all(state, &input, &exit_kind)?;
mark_feature_time!(state, PerfFeature::PostExecObservers);
Ok(())
}
}
impl<E, EM, I, SOT, S, Z> Restartable<S> for ShadowTracingStage<E, EM, I, SOT, S, Z>
where
S: HasNamedMetadata + HasCurrentCorpusId,
{
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
RetryCountRestartHelper::no_retry(state, &self.name)
}
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
RetryCountRestartHelper::clear_progress(state, &self.name)
}
}
impl<E, EM, I, SOT, S, Z> ShadowTracingStage<E, EM, I, SOT, S, Z>
where
E: Executor<EM, I, S, Z> + HasObservers,
S: HasExecutions + HasCorpus<I>,
SOT: ObserversTuple<I, S>,
{
/// Creates a new default stage
pub fn new() -> Self {
// unsafe but impossible that you create two threads both instantiating this instance
let stage_id = unsafe {
let ret = SHADOW_TRACING_STAGE_ID;
SHADOW_TRACING_STAGE_ID += 1;
ret
};
Self {
name: Cow::Owned(
SHADOW_TRACING_STAGE_NAME.to_owned() + ":" + stage_id.to_string().as_str(),
),
phantom: PhantomData,
}
}
}

View File

@ -13,7 +13,7 @@ use crate::monitors::stats::PerfFeature;
use crate::{
Error, HasNamedMetadata,
corpus::HasCurrentCorpusId,
executors::{Executor, HasObservers, ShadowExecutor},
executors::{Executor, HasObservers},
inputs::Input,
mark_feature_time,
observers::ObserversTuple,
@ -23,6 +23,7 @@ use crate::{
};
/// A stage that runs a tracer executor
/// This should *NOT* be used with inprocess executor
#[derive(Clone, Debug)]
pub struct TracingStage<EM, I, TE, S, Z> {
name: Cow<'static, str>,
@ -146,108 +147,3 @@ impl<EM, I, TE, S, Z> TracingStage<EM, I, TE, S, Z> {
&mut self.tracer_executor
}
}
/// A stage that runs the shadow executor using also the shadow observers
#[derive(Clone, Debug)]
pub struct ShadowTracingStage<E, EM, I, SOT, S, Z> {
name: Cow<'static, str>,
phantom: PhantomData<(E, EM, I, SOT, S, Z)>,
}
/// The counter for giving this stage unique id
static mut SHADOW_TRACING_STAGE_ID: usize = 0;
/// Name for shadow tracing stage
pub static SHADOW_TRACING_STAGE_NAME: &str = "shadow";
impl<E, EM, I, SOT, S, Z> Named for ShadowTracingStage<E, EM, I, SOT, S, Z> {
fn name(&self) -> &Cow<'static, str> {
&self.name
}
}
impl<E, EM, I, SOT, S, Z> Stage<ShadowExecutor<E, I, S, SOT>, EM, S, Z>
for ShadowTracingStage<E, EM, I, SOT, S, Z>
where
E: Executor<EM, I, S, Z> + HasObservers,
E::Observers: ObserversTuple<I, S>,
SOT: ObserversTuple<I, S>,
S: HasExecutions
+ HasCorpus<I>
+ HasNamedMetadata
+ Debug
+ HasCurrentTestcase<I>
+ HasCurrentCorpusId
+ MaybeHasClientPerfMonitor,
{
#[inline]
fn perform(
&mut self,
fuzzer: &mut Z,
executor: &mut ShadowExecutor<E, I, S, SOT>,
state: &mut S,
manager: &mut EM,
) -> Result<(), Error> {
start_timer!(state);
let input = state.current_input_cloned()?;
mark_feature_time!(state, PerfFeature::GetInputFromCorpus);
start_timer!(state);
executor
.shadow_observers_mut()
.pre_exec_all(state, &input)?;
executor.observers_mut().pre_exec_all(state, &input)?;
mark_feature_time!(state, PerfFeature::PreExecObservers);
start_timer!(state);
let exit_kind = executor.run_target(fuzzer, state, manager, &input)?;
mark_feature_time!(state, PerfFeature::TargetExecution);
start_timer!(state);
executor
.shadow_observers_mut()
.post_exec_all(state, &input, &exit_kind)?;
executor
.observers_mut()
.post_exec_all(state, &input, &exit_kind)?;
mark_feature_time!(state, PerfFeature::PostExecObservers);
Ok(())
}
}
impl<E, EM, I, SOT, S, Z> Restartable<S> for ShadowTracingStage<E, EM, I, SOT, S, Z>
where
S: HasNamedMetadata + HasCurrentCorpusId,
{
fn should_restart(&mut self, state: &mut S) -> Result<bool, Error> {
RetryCountRestartHelper::no_retry(state, &self.name)
}
fn clear_progress(&mut self, state: &mut S) -> Result<(), Error> {
RetryCountRestartHelper::clear_progress(state, &self.name)
}
}
impl<E, EM, I, SOT, S, Z> ShadowTracingStage<E, EM, I, SOT, S, Z>
where
E: Executor<EM, I, S, Z> + HasObservers,
S: HasExecutions + HasCorpus<I>,
SOT: ObserversTuple<I, S>,
{
/// Creates a new default stage
pub fn new(_executor: &mut ShadowExecutor<E, I, S, SOT>) -> Self {
// unsafe but impossible that you create two threads both instantiating this instance
let stage_id = unsafe {
let ret = SHADOW_TRACING_STAGE_ID;
SHADOW_TRACING_STAGE_ID += 1;
ret
};
Self {
name: Cow::Owned(
SHADOW_TRACING_STAGE_NAME.to_owned() + ":" + stage_id.to_string().as_str(),
),
phantom: PhantomData,
}
}
}

View File

@ -148,7 +148,7 @@ macro_rules! fuzz_with {
};
use libafl::{
corpus::Corpus,
executors::{ExitKind, InProcessExecutor},
executors::{ExitKind, InProcessExecutor, ShadowExecutor},
feedback_and_fast, feedback_not, feedback_or, feedback_or_fast,
feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, NewHashFeedback, TimeFeedback, TimeoutFeedback},
generators::RandBytesGenerator,
@ -166,7 +166,7 @@ macro_rules! fuzz_with {
},
stages::{
CalibrationStage, GeneralizationStage, IfStage, StdMutationalStage,
StdPowerMutationalStage, UnicodeIdentificationStage, TracingStage,
StdPowerMutationalStage, UnicodeIdentificationStage, ShadowTracingStage,
},
state::{HasCorpus, StdState},
StdFuzzer,
@ -438,8 +438,6 @@ macro_rules! fuzz_with {
}
};
let mut tracing_harness = harness;
let add_extra_observer = $extra_obsv;
let observers = add_extra_observer(
tuple_list!(edges_observer, size_edges_observer, time_observer, backtrace_observer, oom_observer),
@ -488,14 +486,9 @@ macro_rules! fuzz_with {
}
}
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
// Setup a tracing stage in which we log comparisons
let tracing = IfStage::new(|_, _, _, _| Ok(!$options.skip_tracing()), (TracingStage::new(InProcessExecutor::new(
&mut tracing_harness,
tuple_list!(cmplog_observer),
&mut fuzzer,
&mut state,
&mut mgr,
)?), ()));
let tracing = IfStage::new(|_, _, _, _| Ok(!$options.skip_tracing()), (ShadowTracingStage::new(), ()));
// The order of the stages matter!
let mut stages = tuple_list!(

View File

@ -261,7 +261,7 @@ where
}
// Setup a tracing stage in which we log comparisons
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(

View File

@ -299,7 +299,7 @@ where
}
// Setup a tracing stage in which we log comparisons
let tracing = ShadowTracingStage::new(&mut executor);
let tracing = ShadowTracingStage::new();
// Setup a randomic Input2State stage
let i2s = StdMutationalStage::new(StdScheduledMutator::new(tuple_list!(