diff --git a/bindings/pylibafl/src/lib.rs b/bindings/pylibafl/src/lib.rs index 809ffdbfa6..8674537de4 100644 --- a/bindings/pylibafl/src/lib.rs +++ b/bindings/pylibafl/src/lib.rs @@ -2,8 +2,7 @@ use libafl; #[cfg(target_os = "linux")] use libafl_qemu; use libafl_sugar; -use pyo3::prelude::*; -use pyo3::types::PyDict; +use pyo3::{prelude::*, types::PyDict}; const LIBAFL_CODE: &str = r#" class BaseObserver: diff --git a/bindings/pylibafl/test.py b/bindings/pylibafl/test.py index de84135200..01e72f7489 100644 --- a/bindings/pylibafl/test.py +++ b/bindings/pylibafl/test.py @@ -1,30 +1,38 @@ from pylibafl.libafl import * import ctypes + class FooObserver(BaseObserver): def __init__(self): self.n = 0 + def name(self): return "Foo" + def pre_exec(self, state, input): if self.n % 10000 == 0: print("FOO!", self.n, input) self.n += 1 + class FooFeedback(BaseFeedback): def is_interesting(self, state, mgr, input, observers, exit_kind): ob = observers.match_name("Foo").unwrap_py() return ob.n % 10000 == 0 + class FooExecutor(BaseExecutor): def __init__(self, harness, observers: ObserversTuple): self.h = harness self.o = observers + def observers(self): return self.o + def run_target(self, fuzzer, state, mgr, input) -> ExitKind: return (self.h)(input) + libc = ctypes.cdll.LoadLibrary("libc.so.6") area_ptr = libc.calloc(1, 4096) @@ -33,34 +41,46 @@ observer = StdMapObserverI8("mymap", area_ptr, 4096) m = observer.as_map_observer() -observers = ObserversTuple([observer.as_map_observer().as_observer(), FooObserver().as_observer()]) +observers = ObserversTuple( + [observer.as_map_observer().as_observer(), FooObserver().as_observer()] +) feedback = feedback_or(MaxMapFeedbackI8(m).as_feedback(), FooFeedback().as_feedback()) -objective = feedback_and_fast(CrashFeedback().as_feedback(), MaxMapFeedbackI8(m).as_feedback()) +objective = feedback_and_fast( + CrashFeedback().as_feedback(), MaxMapFeedbackI8(m).as_feedback() +) fuzzer = StdFuzzer(feedback, objective) rand = StdRand.with_current_nanos() -state = StdState(rand.as_rand(), InMemoryCorpus().as_corpus(), InMemoryCorpus().as_corpus(), feedback, objective) +state = StdState( + rand.as_rand(), + InMemoryCorpus().as_corpus(), + InMemoryCorpus().as_corpus(), + feedback, + objective, +) monitor = SimpleMonitor(lambda s: print(s)) mgr = SimpleEventManager(monitor.as_monitor()) + def harness(buf) -> ExitKind: - #print(buf) + # print(buf) m[0] = 1 - if len(buf) > 0 and buf[0] == ord('a'): + if len(buf) > 0 and buf[0] == ord("a"): m[1] = 1 - if len(buf) > 1 and buf[1] == ord('b'): + if len(buf) > 1 and buf[1] == ord("b"): m[2] = 1 - if len(buf) > 2 and buf[2] == ord('c'): + if len(buf) > 2 and buf[2] == ord("c"): m[3] = 1 return ExitKind.crash() return ExitKind.ok() + # executor = InProcessExecutor(harness, observers, fuzzer, state, mgr.as_manager()) executor = FooExecutor(harness, observers) @@ -69,6 +89,6 @@ stage = StdMutationalStage(StdHavocMutator().as_mutator()) stage_tuple_list = StagesTuple([stage.as_stage()]) -fuzzer.add_input(state, executor.as_executor(), mgr.as_manager(), b'\0\0') +fuzzer.add_input(state, executor.as_executor(), mgr.as_manager(), b"\0\0") fuzzer.fuzz_loop(executor.as_executor(), state, mgr.as_manager(), stage_tuple_list) diff --git a/docs/src/design/migration-0.9.md b/docs/src/design/migration-0.9.md new file mode 100644 index 0000000000..1922e02cf1 --- /dev/null +++ b/docs/src/design/migration-0.9.md @@ -0,0 +1,161 @@ +# Migrating from libafl <0.9 to 0.9 + +Internal APIs of libafl have changed in version 0.9 to prefer associated types in cases where components were "fixed" to +particular versions of other components. As a result, many existing custom components will not be compatible between +versions prior to 0.9 and version 0.9. + +## Reasons for this change + +When implementing a trait with a generic, it is possible to have more than one instantiation of that generic trait. As a +result, everywhere where consistency across generic types was required to implement a trait, it needed to be properly +and explicitly constrained at every point. This led to `impl`s which were at best difficult to debug and, at worst, +incorrect and caused confusing bugs for users. + +For example, consider the MapCorpusMinimizer implementation (from <0.9) below: + +```rust +impl CorpusMinimizer for MapCorpusMinimizer +where + E: Copy + Hash + Eq, + I: Input, + for<'a> O: MapObserver + AsIter<'a, Item = E>, + S: HasMetadata + HasCorpus, + TS: TestcaseScore, +{ + fn minimize( + &self, + fuzzer: &mut Z, + executor: &mut EX, + manager: &mut EM, + state: &mut S, + ) -> Result<(), Error> + where + CS: Scheduler, + EX: Executor + HasObservers, + EM: EventManager, + OT: ObserversTuple, + Z: Evaluator + HasScheduler, + { + // --- SNIP --- + } +} +``` + +It was previously necessary to constrain every generic using a slew of other generics; above, it is necessary to +constrain the input type (`I`) for every generic, despite the fact that this was already made clear by the state (`S`) +and that the input will necessarily be the same over every implementation for that type. + +Below is the same code, but with the associated types changes (note that some generic names have changed): + +```rust +impl CorpusMinimizer for MapCorpusMinimizer +where + E: UsesState, + for<'a> O: MapObserver + AsIter<'a, Item = T>, + E::State: HasMetadata + HasCorpus, + T: Copy + Hash + Eq, + TS: TestcaseScore, +{ + fn minimize( + &self, + fuzzer: &mut Z, + executor: &mut E, + manager: &mut EM, + state: &mut E::State, + ) -> Result<(), Error> + where + E: Executor + HasObservers, + CS: Scheduler, + EM: UsesState, + Z: HasScheduler, + { + // --- SNIP --- + } +} +``` + +The executor is constrained to `EM` and `Z`, with each of their respective states being constrained to `E`'s state. It +is no longer necessary to explicitly defined a generic for the input type, the state type, or the generic type, as these +are all present as associated types for `E`. Additionally, we don't even need to specify any details about the observers +(`OT` in the previous version) as the type does not need to be constrained and is not shared by other types. + +## Scope + +You are affected by this change if: + - You specified explicit generics for a type (e.g., `MaxMapFeedback::<_, (), _>::new(...)`) + - You implemented a custom component (e.g., `Mutator`, `Executor`, `State`, `Fuzzer`, `Feedback`, `Observer`, etc.) + +If you did neither of these, congrats! You are likely unaffected by these changes. + +### Migrating explicit generics + +Migrating specific generics should be a quite simple process; you should review the API documentation for details on the +order of generics and replace them accordingly. Generally speaking, it should no longer be necessary to specify these +generics. + +See `fuzzers/` for examples of these changes. + +### Migrating component types + +If you implemented a Mutator, Executor, State, or another kind of component, you must update your implementation. The +main changes to the API are in the use of "Uses*" for associated types. + +In many scenarios, Input, Observers, and State generics have been moved into traits with associated types (namely, +"UsesInput", "UsesObservers", and "UsesState". These traits are required for many existing traits now and are very +straightforward to implement. In a majority of cases, you will have generics on your custom implementation or a fixed +type to implement this with. Thankfully, Rust will let you know when you need to implement this type. + +As an example, InMemoryCorpus before 0.9 looked like this: + +```rust +#[derive(Default, Serialize, Deserialize, Clone, Debug)] +#[serde(bound = "I: serde::de::DeserializeOwned")] +pub struct InMemoryCorpus +where + I: Input, +{ + entries: Vec>>, + current: Option, +} + +impl Corpus for InMemoryCorpus +where + I: Input, +{ + // --- SNIP --- +} +``` + +After 0.9, all `Corpus` implementations are required to implement `UsesInput` and `Corpus` no longer has a generic for +the input type (as it is now provided by the UsesInput impl). The migrated implementation is shown below: + +```rust +#[derive(Default, Serialize, Deserialize, Clone, Debug)] +#[serde(bound = "I: serde::de::DeserializeOwned")] +pub struct InMemoryCorpus +where + I: Input, +{ + entries: Vec>>, + current: Option, +} + +impl UsesInput for InMemoryCorpus +where + I: Input, +{ + type Input = I; +} + +impl Corpus for InMemoryCorpus +where + I: Input, +{ + // --- SNIP --- +} +``` + +Now, `Corpus` cannot be accidentally implemented for another type other than that specified by `InMemoryCorpus`, as it +is fixed to the associated type for `UsesInput`. + +A more complex example of migration can be found in the "Reasons for this change" section of this document. \ No newline at end of file diff --git a/fuzzers/backtrace_baby_fuzzers/README.md b/fuzzers/backtrace_baby_fuzzers/README.md index bc6da522eb..336873adfe 100644 --- a/fuzzers/backtrace_baby_fuzzers/README.md +++ b/fuzzers/backtrace_baby_fuzzers/README.md @@ -1,6 +1,6 @@ # Backtrace baby fuzzers -The projects contained in this directory are simple fuzzers derived from the original baby_fuzzer examples, whose perpose is to show how to use a `BacktraceObserver` or an `ASANObserver` to dedupe crashes and other necessary component for this feature. +The projects contained in this directory are simple fuzzers derived from the original baby_fuzzer examples, whose purpose is to show how to use a `BacktraceObserver` or an `ASANObserver` to dedupe crashes and other necessary components for this feature. The examples cover: diff --git a/fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs index a6b370f231..2b05f58019 100644 --- a/fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/c_code_with_fork_executor/src/main.rs @@ -58,10 +58,7 @@ pub fn main() { let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let mut objective = feedback_and!( - CrashFeedback::new(), - NewHashFeedback::::new(&bt_observer) - ); + let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer)); // create a State from scratch let mut state = StdState::new( diff --git a/fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs index 9886af04f2..97b5eca4cb 100644 --- a/fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/c_code_with_inprocess_executor/src/main.rs @@ -48,10 +48,7 @@ pub fn main() { let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let mut objective = feedback_and!( - CrashFeedback::new(), - NewHashFeedback::::new(&bt_observer) - ); + let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer)); // create a State from scratch let mut state = StdState::new( diff --git a/fuzzers/backtrace_baby_fuzzers/command_executor/build.rs b/fuzzers/backtrace_baby_fuzzers/command_executor/build.rs index aae5e26982..6fc42bbab3 100644 --- a/fuzzers/backtrace_baby_fuzzers/command_executor/build.rs +++ b/fuzzers/backtrace_baby_fuzzers/command_executor/build.rs @@ -3,7 +3,7 @@ use std::env; fn main() { let cwd = env::current_dir().unwrap().to_string_lossy().to_string(); let mut cmd = cc::Build::new().get_compiler().to_command(); - cmd.args(&["src/test_command.c", "-o"]) + cmd.args(["src/test_command.c", "-o"]) .arg(&format!("{}/test_command", &cwd)) .arg("-fsanitize=address") .status() diff --git a/fuzzers/backtrace_baby_fuzzers/command_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/command_executor/src/main.rs index c5fd3dc4d7..a741e53b4a 100644 --- a/fuzzers/backtrace_baby_fuzzers/command_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/command_executor/src/main.rs @@ -46,10 +46,7 @@ pub fn main() { let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let mut objective = feedback_and!( - CrashFeedback::new(), - NewHashFeedback::::new(&bt_observer) - ); + let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer)); // let mut objective = CrashFeedback::new(); // create a State from scratch @@ -93,7 +90,7 @@ pub fn main() { let mut command = Command::new("./test_command"); let command = command - .args(&[self.shmem_id.as_str()]) + .args([self.shmem_id.as_str()]) .env("ASAN_OPTIONS", get_asan_runtime_flags()); command diff --git a/fuzzers/backtrace_baby_fuzzers/forkserver_executor/build.rs b/fuzzers/backtrace_baby_fuzzers/forkserver_executor/build.rs index 6212fe81ca..862a09ccf0 100644 --- a/fuzzers/backtrace_baby_fuzzers/forkserver_executor/build.rs +++ b/fuzzers/backtrace_baby_fuzzers/forkserver_executor/build.rs @@ -32,13 +32,13 @@ fn main() { if !afl_gcc_path.is_file() { Command::new("make") .arg("all") - .current_dir(&afl_path) + .current_dir(afl_path) .status() .unwrap(); } Command::new(afl_gcc_path) - .args(&["src/program.c", "-o"]) + .args(["src/program.c", "-o"]) .arg(&format!("{}/target/release/program", &cwd)) .arg("-fsanitize=address") .status() diff --git a/fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs index 1fa7f1dc82..1391aa84ed 100644 --- a/fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/rust_code_with_fork_executor/src/main.rs @@ -77,10 +77,7 @@ pub fn main() { let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let mut objective = feedback_and!( - CrashFeedback::new(), - NewHashFeedback::::new(&bt_observer) - ); + let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer)); // create a State from scratch let mut state = StdState::new( diff --git a/fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs b/fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs index f8cb55913e..c9982b497f 100644 --- a/fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs +++ b/fuzzers/backtrace_baby_fuzzers/rust_code_with_inprocess_executor/src/main.rs @@ -71,10 +71,7 @@ pub fn main() { let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not - let mut objective = feedback_and!( - CrashFeedback::new(), - NewHashFeedback::::new(&bt_observer) - ); + let mut objective = feedback_and!(CrashFeedback::new(), NewHashFeedback::new(&bt_observer)); // create a State from scratch let mut state = StdState::new( diff --git a/fuzzers/forkserver_simple/src/main.rs b/fuzzers/forkserver_simple/src/main.rs index ce0d89d3c5..461cafaa05 100644 --- a/fuzzers/forkserver_simple/src/main.rs +++ b/fuzzers/forkserver_simple/src/main.rs @@ -117,7 +117,7 @@ pub fn main() { // Must be a crash CrashFeedback::new(), // Take it onlt if trigger new coverage over crashes - MaxMapFeedback::<_, _, _, u8>::new(&edges_observer) + MaxMapFeedback::new(&edges_observer) ); // create a State from scratch diff --git a/fuzzers/frida_gdiplus/src/fuzzer.rs b/fuzzers/frida_gdiplus/src/fuzzer.rs index 130e8c9954..d9625006cc 100644 --- a/fuzzers/frida_gdiplus/src/fuzzer.rs +++ b/fuzzers/frida_gdiplus/src/fuzzer.rs @@ -75,9 +75,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { let shmem_provider = StdShMemProvider::new()?; - let mut run_client = |state: Option<_>, - mgr: LlmpRestartingEventManager<_, _, _, _>, - core_id| { + let mut run_client = |state: Option<_>, mgr: LlmpRestartingEventManager<_, _>, core_id| { // The restarting state will spawn the same process again as child, then restarted it each time it crashes. // println!("{:?}", mgr.mgr_id()); @@ -95,7 +93,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { }; if options.asan && options.asan_cores.contains(core_id) { - (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); @@ -220,7 +218,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Ok(()) })(state, mgr, core_id) } else if options.cmplog && options.cmplog_cores.contains(core_id) { - (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); @@ -354,7 +352,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Ok(()) })(state, mgr, core_id) } else { - (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); diff --git a/fuzzers/frida_libpng/src/fuzzer.rs b/fuzzers/frida_libpng/src/fuzzer.rs index 11c092edc7..f4ca848435 100644 --- a/fuzzers/frida_libpng/src/fuzzer.rs +++ b/fuzzers/frida_libpng/src/fuzzer.rs @@ -69,9 +69,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { let shmem_provider = StdShMemProvider::new()?; - let mut run_client = |state: Option<_>, - mgr: LlmpRestartingEventManager<_, _, _, _>, - core_id| { + let mut run_client = |state: Option<_>, mgr: LlmpRestartingEventManager<_, _>, core_id| { // The restarting state will spawn the same process again as child, then restarted it each time it crashes. // println!("{:?}", mgr.mgr_id()); @@ -89,7 +87,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { }; if options.asan && options.asan_cores.contains(core_id) { - (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); @@ -214,7 +212,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Ok(()) })(state, mgr, core_id) } else if options.cmplog && options.cmplog_cores.contains(core_id) { - (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); @@ -348,7 +346,7 @@ unsafe fn fuzz(options: FuzzerOptions) -> Result<(), Error> { Ok(()) })(state, mgr, core_id) } else { - (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _, _, _>, _core_id| { + (|state: Option<_>, mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { let gum = Gum::obtain(); let coverage = CoverageRuntime::new(); diff --git a/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs b/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs index 8455d45243..3c52e51314 100644 --- a/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs +++ b/fuzzers/libfuzzer_stb_image_concolic/fuzzer/src/main.rs @@ -4,13 +4,13 @@ use mimalloc::MiMalloc; #[global_allocator] static GLOBAL: MiMalloc = MiMalloc; -use clap::{self, Parser}; use std::{ env, path::PathBuf, process::{Child, Command, Stdio}, }; +use clap::{self, Parser}; use libafl::{ bolts::{ current_nanos, @@ -48,7 +48,6 @@ use libafl::{ state::{HasCorpus, StdState}, Error, }; - use libafl_targets::{ libfuzzer_initialize, libfuzzer_test_one_input, CmpLogObserver, CMPLOG_MAP, EDGES_MAP, MAX_EDGES_NUM, @@ -116,7 +115,6 @@ fn fuzz( let cmplog = unsafe { &mut CMPLOG_MAP }; let cmplog_observer = CmpLogObserver::new("cmplog", cmplog, true); - // Feedback to rate the interestingness of an input // This one is composed by two Feedbacks in OR let mut feedback = feedback_or!( @@ -139,12 +137,13 @@ fn fuzz( // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(objective_dir).unwrap(), - // States of the feedbacks. - // The feedbacks can report the data that should persist in the State. - &mut feedback, - // Same for objective feedbacks - &mut objective, - ).unwrap() + // States of the feedbacks. + // The feedbacks can report the data that should persist in the State. + &mut feedback, + // Same for objective feedbacks + &mut objective, + ) + .unwrap() }); println!("We're a client, let's fuzz :)"); diff --git a/fuzzers/nyx_libxml2_parallel/src/main.rs b/fuzzers/nyx_libxml2_parallel/src/main.rs index b2f7732167..fddd15bedf 100644 --- a/fuzzers/nyx_libxml2_parallel/src/main.rs +++ b/fuzzers/nyx_libxml2_parallel/src/main.rs @@ -60,7 +60,7 @@ fn main() { corpus .add(Testcase::new(input)) .expect("error in adding corpus"); - let solutions = OnDiskCorpus::::new(PathBuf::from("./crashes")).unwrap(); + let solutions = OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(); // libafl stuff let mut feedback = MaxMapFeedback::new(&observer); diff --git a/fuzzers/nyx_libxml2_standalone/src/main.rs b/fuzzers/nyx_libxml2_standalone/src/main.rs index 21022096bf..db08592046 100644 --- a/fuzzers/nyx_libxml2_standalone/src/main.rs +++ b/fuzzers/nyx_libxml2_standalone/src/main.rs @@ -48,7 +48,7 @@ fn main() { // let monitor = SimpleMonitor::new(|x|-> () {println!("{}",x)}); let monitor = TuiMonitor::new("test_fuzz".to_string(), true); - let mut mgr: SimpleEventManager = SimpleEventManager::new(monitor); + let mut mgr = SimpleEventManager::new(monitor); let mut executor = NyxExecutor::new(&mut helper, tuple_list!(observer)).unwrap(); let mutator = StdScheduledMutator::new(havoc_mutations()); let mut stages = tuple_list!(StdMutationalStage::new(mutator)); diff --git a/fuzzers/push_stage_harness/src/main.rs b/fuzzers/push_stage_harness/src/main.rs index 135be0df59..41a4c3f32b 100644 --- a/fuzzers/push_stage_harness/src/main.rs +++ b/fuzzers/push_stage_harness/src/main.rs @@ -37,7 +37,7 @@ pub fn main() { let observer = StdMapObserver::new("signals", unsafe { &mut SIGNALS }); // Feedback to rate the interestingness of an input - let mut feedback = MaxMapFeedback::::new(&observer); + let mut feedback = MaxMapFeedback::new(&observer); // A feedback to choose if an input is a solution or not let mut objective = CrashFeedback::new(); @@ -47,7 +47,7 @@ pub fn main() { // RNG StdRand::with_seed(current_nanos()), // Corpus that will be evolved, we keep it in memory for performance - InMemoryCorpus::new(), + InMemoryCorpus::::new(), // Corpus in which we store solutions (crashes in this example), // on disk so the user can get them after stopping the fuzzer OnDiskCorpus::new(PathBuf::from("./crashes")).unwrap(), diff --git a/fuzzers/tutorial/src/metadata.rs b/fuzzers/tutorial/src/metadata.rs index 03fb8c58c6..9f18862b36 100644 --- a/fuzzers/tutorial/src/metadata.rs +++ b/fuzzers/tutorial/src/metadata.rs @@ -4,6 +4,7 @@ use libafl::{ events::EventFirer, executors::ExitKind, feedbacks::{Feedback, MapIndexesMetadata}, + inputs::UsesInput, observers::ObserversTuple, schedulers::{MinimizerScheduler, TestcaseScore}, state::{HasClientPerfMonitor, HasCorpus, HasMetadata}, @@ -20,9 +21,9 @@ pub struct PacketLenMetadata { pub struct PacketLenTestcaseScore {} -impl TestcaseScore for PacketLenTestcaseScore +impl TestcaseScore for PacketLenTestcaseScore where - S: HasCorpus + HasMetadata, + S: HasCorpus + HasMetadata, { fn compute(entry: &mut Testcase, _state: &S) -> Result { Ok(entry @@ -32,17 +33,17 @@ where } } -pub type PacketLenMinimizerScheduler = - MinimizerScheduler; +pub type PacketLenMinimizerScheduler = + MinimizerScheduler; #[derive(Serialize, Deserialize, Default, Clone, Debug)] pub struct PacketLenFeedback { len: u64, } -impl Feedback for PacketLenFeedback +impl Feedback for PacketLenFeedback where - S: HasClientPerfMonitor, + S: UsesInput + HasClientPerfMonitor, { #[inline] fn is_interesting( @@ -54,8 +55,8 @@ where _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { self.len = input.length; Ok(false) diff --git a/fuzzers/tutorial/src/mutator.rs b/fuzzers/tutorial/src/mutator.rs index 8d5e0a0c53..19647003ee 100644 --- a/fuzzers/tutorial/src/mutator.rs +++ b/fuzzers/tutorial/src/mutator.rs @@ -4,6 +4,7 @@ use libafl::{ rands::{Rand, StdRand}, tuples::Named, }, + inputs::UsesInput, mutators::{MutationResult, Mutator}, state::HasRand, Error, @@ -15,7 +16,10 @@ pub struct LainMutator { inner: lain::mutator::Mutator, } -impl Mutator for LainMutator { +impl Mutator for LainMutator +where + S: UsesInput + HasRand, +{ fn mutate( &mut self, state: &mut S, diff --git a/libafl/src/bolts/launcher.rs b/libafl/src/bolts/launcher.rs index f15a1de40d..8ccd93fb36 100644 --- a/libafl/src/bolts/launcher.rs +++ b/libafl/src/bolts/launcher.rs @@ -33,13 +33,13 @@ use crate::bolts::core_affinity::CoreId; use crate::bolts::os::startable_self; #[cfg(all(unix, feature = "std", feature = "fork"))] use crate::bolts::os::{dup2, fork, ForkResult}; +use crate::inputs::UsesInput; #[cfg(feature = "std")] use crate::{ bolts::{core_affinity::Cores, shmem::ShMemProvider}, events::{EventConfig, LlmpRestartingEventManager, ManagerKind, RestartingMgr}, - inputs::Input, monitors::Monitor, - observers::ObserversTuple, + state::{HasClientPerfMonitor, HasExecutions}, Error, }; @@ -49,14 +49,13 @@ const _AFL_LAUNCHER_CLIENT: &str = "AFL_LAUNCHER_CLIENT"; #[cfg(feature = "std")] #[derive(TypedBuilder)] #[allow(clippy::type_complexity, missing_debug_implementations)] -pub struct Launcher<'a, CF, I, MT, OT, S, SP> +pub struct Launcher<'a, CF, MT, S, SP> where - CF: FnOnce(Option, LlmpRestartingEventManager, usize) -> Result<(), Error>, - I: Input + 'a, + CF: FnOnce(Option, LlmpRestartingEventManager, usize) -> Result<(), Error>, + S::Input: 'a, MT: Monitor, SP: ShMemProvider + 'static, - OT: ObserversTuple + 'a, - S: DeserializeOwned + 'a, + S: DeserializeOwned + UsesInput + 'a, { /// The ShmemProvider to use shmem_provider: SP, @@ -86,17 +85,15 @@ where #[builder(default = true)] spawn_broker: bool, #[builder(setter(skip), default = PhantomData)] - phantom_data: PhantomData<(&'a I, &'a OT, &'a S, &'a SP)>, + phantom_data: PhantomData<(&'a S, &'a SP)>, } -impl Debug for Launcher<'_, CF, I, MT, OT, S, SP> +impl Debug for Launcher<'_, CF, MT, S, SP> where - CF: FnOnce(Option, LlmpRestartingEventManager, usize) -> Result<(), Error>, - I: Input, - OT: ObserversTuple + DeserializeOwned, + CF: FnOnce(Option, LlmpRestartingEventManager, usize) -> Result<(), Error>, MT: Monitor + Clone, SP: ShMemProvider + 'static, - S: DeserializeOwned, + S: DeserializeOwned + UsesInput, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("Launcher") @@ -111,14 +108,12 @@ where } #[cfg(feature = "std")] -impl<'a, CF, I, MT, OT, S, SP> Launcher<'a, CF, I, MT, OT, S, SP> +impl<'a, CF, MT, S, SP> Launcher<'a, CF, MT, S, SP> where - CF: FnOnce(Option, LlmpRestartingEventManager, usize) -> Result<(), Error>, - I: Input, - OT: ObserversTuple + DeserializeOwned, + CF: FnOnce(Option, LlmpRestartingEventManager, usize) -> Result<(), Error>, MT: Monitor + Clone, + S: DeserializeOwned + UsesInput + HasExecutions + HasClientPerfMonitor, SP: ShMemProvider + 'static, - S: DeserializeOwned, { /// Launch the broker and the clients and fuzz #[cfg(all(unix, feature = "std", feature = "fork"))] @@ -175,7 +170,7 @@ where } // Fuzzer client. keeps retrying the connection to broker till the broker starts - let (state, mgr) = RestartingMgr::::builder() + let (state, mgr) = RestartingMgr::::builder() .shmem_provider(self.shmem_provider.clone()) .broker_port(self.broker_port) .kind(ManagerKind::Client { @@ -198,7 +193,7 @@ where println!("I am broker!!."); // TODO we don't want always a broker here, think about using different laucher process to spawn different configurations - RestartingMgr::::builder() + RestartingMgr::::builder() .shmem_provider(self.shmem_provider.clone()) .monitor(Some(self.monitor.clone())) .broker_port(self.broker_port) @@ -245,7 +240,7 @@ where //todo: silence stdout and stderr for clients // the actual client. do the fuzzing - let (state, mgr) = RestartingMgr::::builder() + let (state, mgr) = RestartingMgr::::builder() .shmem_provider(self.shmem_provider.clone()) .broker_port(self.broker_port) .kind(ManagerKind::Client { @@ -299,7 +294,7 @@ where #[cfg(feature = "std")] println!("I am broker!!."); - RestartingMgr::::builder() + RestartingMgr::::builder() .shmem_provider(self.shmem_provider.clone()) .monitor(Some(self.monitor.clone())) .broker_port(self.broker_port) diff --git a/libafl/src/bolts/mod.rs b/libafl/src/bolts/mod.rs index aa8fbd4b4d..026f2b07ec 100644 --- a/libafl/src/bolts/mod.rs +++ b/libafl/src/bolts/mod.rs @@ -153,6 +153,7 @@ pub fn format_duration_hms(duration: &time::Duration) -> String { } /// The purpose of this module is to alleviate imports of the bolts by adding a glob import. +#[cfg(feature = "prelude")] pub mod bolts_prelude { #[cfg(feature = "std")] pub use super::build_id::*; diff --git a/libafl/src/corpus/cached.rs b/libafl/src/corpus/cached.rs index 0ce2680e47..51be87c462 100644 --- a/libafl/src/corpus/cached.rs +++ b/libafl/src/corpus/cached.rs @@ -11,7 +11,7 @@ use crate::{ ondisk::{OnDiskCorpus, OnDiskMetadataFormat}, Corpus, Testcase, }, - inputs::Input, + inputs::{Input, UsesInput}, Error, }; @@ -28,7 +28,14 @@ where cache_max_len: usize, } -impl Corpus for CachedOnDiskCorpus +impl UsesInput for CachedOnDiskCorpus +where + I: Input, +{ + type Input = I; +} + +impl Corpus for CachedOnDiskCorpus where I: Input, { diff --git a/libafl/src/corpus/inmemory.rs b/libafl/src/corpus/inmemory.rs index c442c9d424..0640274d9c 100644 --- a/libafl/src/corpus/inmemory.rs +++ b/libafl/src/corpus/inmemory.rs @@ -7,7 +7,7 @@ use serde::{Deserialize, Serialize}; use crate::{ corpus::{Corpus, Testcase}, - inputs::Input, + inputs::{Input, UsesInput}, Error, }; @@ -22,7 +22,14 @@ where current: Option, } -impl Corpus for InMemoryCorpus +impl UsesInput for InMemoryCorpus +where + I: Input, +{ + type Input = I; +} + +impl Corpus for InMemoryCorpus where I: Input, { diff --git a/libafl/src/corpus/minimizer.rs b/libafl/src/corpus/minimizer.rs index eefe19b7c3..a8d54c2eef 100644 --- a/libafl/src/corpus/minimizer.rs +++ b/libafl/src/corpus/minimizer.rs @@ -12,71 +12,70 @@ use num_traits::ToPrimitive; use z3::{ast::Bool, Config, Context, Optimize}; use crate::{ - bolts::AsIter, + bolts::{ + tuples::{MatchName, Named}, + AsIter, + }, corpus::Corpus, - events::EventManager, executors::{Executor, HasObservers}, - inputs::Input, observers::{MapObserver, ObserversTuple}, schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore}, - state::{HasCorpus, HasMetadata}, - Error, Evaluator, HasScheduler, + state::{HasCorpus, HasMetadata, UsesState}, + Error, HasScheduler, }; /// `CorpusMinimizers` minimize corpora according to internal logic. See various implementations for /// details. -pub trait CorpusMinimizer +pub trait CorpusMinimizer where - I: Input, - S: HasCorpus, + E: UsesState, + E::State: HasCorpus, { /// Minimize the corpus of the provided state. - fn minimize( + fn minimize( &self, fuzzer: &mut Z, - executor: &mut EX, + executor: &mut E, manager: &mut EM, - state: &mut S, + state: &mut E::State, ) -> Result<(), Error> where - CS: Scheduler, - EX: Executor + HasObservers, - EM: EventManager, - OT: ObserversTuple, - Z: Evaluator + HasScheduler; + E: Executor + HasObservers, + CS: Scheduler, + EM: UsesState, + Z: HasScheduler; } /// Minimizes a corpus according to coverage maps, weighting by the specified `TestcaseScore`. /// /// Algorithm based on WMOPT: #[derive(Debug)] -pub struct MapCorpusMinimizer +pub struct MapCorpusMinimizer where - E: Copy + Hash + Eq, - I: Input, - for<'a> O: MapObserver + AsIter<'a, Item = E>, - S: HasMetadata + HasCorpus, - TS: TestcaseScore, + E: UsesState, + E::State: HasCorpus + HasMetadata, + TS: TestcaseScore, { obs_name: String, - phantom: PhantomData<(E, I, O, S, TS)>, + phantom: PhantomData<(E, O, T, TS)>, } /// Standard corpus minimizer, which weights inputs by length and time. -pub type StdCorpusMinimizer = - MapCorpusMinimizer>; +pub type StdCorpusMinimizer = + MapCorpusMinimizer::State>>; -impl MapCorpusMinimizer +impl MapCorpusMinimizer where - E: Copy + Hash + Eq, - I: Input, - for<'a> O: MapObserver + AsIter<'a, Item = E>, - S: HasMetadata + HasCorpus, - TS: TestcaseScore, + E: UsesState, + E::State: HasCorpus + HasMetadata, + TS: TestcaseScore, { /// Constructs a new `MapCorpusMinimizer` from a provided observer. This observer will be used /// in the future to get observed maps from an executed input. - pub fn new(obs: &O) -> Self { + pub fn new(obs: &O) -> Self + where + O: Named, + { Self { obs_name: obs.name().to_string(), phantom: PhantomData, @@ -84,27 +83,26 @@ where } } -impl CorpusMinimizer for MapCorpusMinimizer +impl CorpusMinimizer for MapCorpusMinimizer where - E: Copy + Hash + Eq, - I: Input, - for<'a> O: MapObserver + AsIter<'a, Item = E>, - S: HasMetadata + HasCorpus, - TS: TestcaseScore, + E: UsesState, + for<'a> O: MapObserver + AsIter<'a, Item = T>, + E::State: HasMetadata + HasCorpus, + T: Copy + Hash + Eq, + TS: TestcaseScore, { - fn minimize( + fn minimize( &self, fuzzer: &mut Z, - executor: &mut EX, + executor: &mut E, manager: &mut EM, - state: &mut S, + state: &mut E::State, ) -> Result<(), Error> where - CS: Scheduler, - EX: Executor + HasObservers, - EM: EventManager, - OT: ObserversTuple, - Z: Evaluator + HasScheduler, + E: Executor + HasObservers, + CS: Scheduler, + EM: UsesState, + Z: HasScheduler, { let cfg = Config::default(); let ctx = Context::new(&cfg); diff --git a/libafl/src/corpus/mod.rs b/libafl/src/corpus/mod.rs index c79e71477d..dadbec6953 100644 --- a/libafl/src/corpus/mod.rs +++ b/libafl/src/corpus/mod.rs @@ -23,13 +23,10 @@ use core::cell::RefCell; #[cfg(feature = "cmin")] pub use minimizer::*; -use crate::{inputs::Input, Error}; +use crate::{inputs::UsesInput, Error}; /// Corpus with all current testcases -pub trait Corpus: serde::Serialize + for<'de> serde::Deserialize<'de> -where - I: Input, -{ +pub trait Corpus: UsesInput + serde::Serialize + for<'de> serde::Deserialize<'de> { /// Returns the number of elements fn count(&self) -> usize; @@ -39,16 +36,20 @@ where } /// Add an entry to the corpus and return its index - fn add(&mut self, testcase: Testcase) -> Result; + fn add(&mut self, testcase: Testcase) -> Result; /// Replaces the testcase at the given idx, returning the existing. - fn replace(&mut self, idx: usize, testcase: Testcase) -> Result, Error>; + fn replace( + &mut self, + idx: usize, + testcase: Testcase, + ) -> Result, Error>; /// Removes an entry from the corpus, returning it if it was present. - fn remove(&mut self, idx: usize) -> Result>, Error>; + fn remove(&mut self, idx: usize) -> Result>, Error>; /// Get by id - fn get(&self, idx: usize) -> Result<&RefCell>, Error>; + fn get(&self, idx: usize) -> Result<&RefCell>, Error>; /// Current testcase scheduled fn current(&self) -> &Option; @@ -72,7 +73,7 @@ pub mod pybind { ondisk::pybind::PythonOnDiskCorpus, testcase::pybind::PythonTestcaseWrapper, Corpus, Testcase, }, - inputs::BytesInput, + inputs::{BytesInput, UsesInput}, Error, }; @@ -170,7 +171,11 @@ pub mod pybind { } } - impl Corpus for PythonCorpus { + impl UsesInput for PythonCorpus { + type Input = BytesInput; + } + + impl Corpus for PythonCorpus { #[inline] fn count(&self) -> usize { unwrap_me!(self.wrapper, c, { c.count() }) diff --git a/libafl/src/corpus/ondisk.rs b/libafl/src/corpus/ondisk.rs index 63edb3c13e..bc031e1aaa 100644 --- a/libafl/src/corpus/ondisk.rs +++ b/libafl/src/corpus/ondisk.rs @@ -14,7 +14,7 @@ use serde::{Deserialize, Serialize}; use crate::{ bolts::serdeany::SerdeAnyMap, corpus::{Corpus, Testcase}, - inputs::Input, + inputs::{Input, UsesInput}, state::HasMetadata, Error, }; @@ -54,7 +54,14 @@ where meta_format: Option, } -impl Corpus for OnDiskCorpus +impl UsesInput for OnDiskCorpus +where + I: Input, +{ + type Input = I; +} + +impl Corpus for OnDiskCorpus where I: Input, { diff --git a/libafl/src/corpus/testcase.rs b/libafl/src/corpus/testcase.rs index c9ae06883f..f5524be871 100644 --- a/libafl/src/corpus/testcase.rs +++ b/libafl/src/corpus/testcase.rs @@ -2,7 +2,7 @@ //! It will contain a respective input, and metadata. use alloc::string::String; -use core::{convert::Into, default::Default, option::Option, time::Duration}; +use core::{default::Default, option::Option, time::Duration}; use serde::{Deserialize, Serialize}; @@ -181,14 +181,11 @@ where self.fuzzed = fuzzed; } - /// Create a new Testcase instace given an input + /// Create a new Testcase instance given an input #[inline] - pub fn new(input: T) -> Self - where - T: Into, - { + pub fn new(input: I) -> Self { let mut slf = Testcase { - input: Some(input.into()), + input: Some(input), ..Testcase::default() }; slf.input.as_mut().unwrap().wrapped_as_testcase(); diff --git a/libafl/src/events/llmp.rs b/libafl/src/events/llmp.rs index f64b8371bb..59f3e559e0 100644 --- a/libafl/src/events/llmp.rs +++ b/libafl/src/events/llmp.rs @@ -11,9 +11,9 @@ use core::{marker::PhantomData, time::Duration}; #[cfg(feature = "std")] use std::net::{SocketAddr, ToSocketAddrs}; -use serde::de::DeserializeOwned; +use serde::Deserialize; #[cfg(feature = "std")] -use serde::Serialize; +use serde::{de::DeserializeOwned, Serialize}; #[cfg(feature = "std")] use typed_builder::TypedBuilder; @@ -42,9 +42,9 @@ use crate::{ }, executors::{Executor, HasObservers}, fuzzer::{EvaluatorObservers, ExecutionProcessor}, - inputs::Input, + inputs::{Input, UsesInput}, monitors::Monitor, - observers::ObserversTuple, + state::{HasClientPerfMonitor, HasExecutions, HasMetadata, UsesState}, Error, }; @@ -244,12 +244,10 @@ where /// An [`EventManager`] that forwards all events to other attached fuzzers on shared maps or via tcp, /// using low-level message passing, [`crate::bolts::llmp`]. -pub struct LlmpEventManager +pub struct LlmpEventManager where - I: Input, - OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider + 'static, - //CE: CustomEvent, { llmp: LlmpClient, /// The custom buf handler @@ -257,14 +255,13 @@ where #[cfg(feature = "llmp_compression")] compressor: GzipCompressor, configuration: EventConfig, - phantom: PhantomData<(I, OT, S)>, + phantom: PhantomData, } -impl core::fmt::Debug for LlmpEventManager +impl core::fmt::Debug for LlmpEventManager where - I: Input, - OT: ObserversTuple, SP: ShMemProvider + 'static, + S: UsesInput, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { let mut debug_struct = f.debug_struct("LlmpEventManager"); @@ -279,11 +276,10 @@ where } } -impl Drop for LlmpEventManager +impl Drop for LlmpEventManager where - I: Input, - OT: ObserversTuple, SP: ShMemProvider + 'static, + S: UsesInput, { /// LLMP clients will have to wait until their pages are mapped by somebody. fn drop(&mut self) { @@ -291,10 +287,9 @@ where } } -impl LlmpEventManager +impl LlmpEventManager where - I: Input, - OT: ObserversTuple, + S: UsesInput + HasExecutions + HasClientPerfMonitor, SP: ShMemProvider + 'static, { /// Create a manager from a raw llmp client @@ -319,7 +314,7 @@ where configuration: EventConfig, ) -> Result { Ok(Self { - llmp: llmp::LlmpClient::create_attach_to_tcp(shmem_provider, port)?, + llmp: LlmpClient::create_attach_to_tcp(shmem_provider, port)?, #[cfg(feature = "llmp_compression")] compressor: GzipCompressor::new(COMPRESS_THRESHOLD), configuration, @@ -357,7 +352,7 @@ where configuration: EventConfig, ) -> Result { Ok(Self { - llmp: llmp::LlmpClient::existing_client_from_description(shmem_provider, description)?, + llmp: LlmpClient::existing_client_from_description(shmem_provider, description)?, #[cfg(feature = "llmp_compression")] compressor: GzipCompressor::new(COMPRESS_THRESHOLD), configuration, @@ -380,12 +375,12 @@ where executor: &mut E, state: &mut S, _client_id: u32, - event: Event, + event: Event, ) -> Result<(), Error> where - OT: ObserversTuple + DeserializeOwned, - E: Executor + HasObservers, - Z: ExecutionProcessor + EvaluatorObservers, + E: Executor + HasObservers, + for<'a> E::Observers: Deserialize<'a>, + Z: ExecutionProcessor + EvaluatorObservers, { match event { Event::NewTestcase { @@ -406,10 +401,13 @@ where let _res = if client_config.match_with(&self.configuration) && observers_buf.is_some() { - let observers: OT = postcard::from_bytes(observers_buf.as_ref().unwrap())?; + let observers: E::Observers = + postcard::from_bytes(observers_buf.as_ref().unwrap())?; fuzzer.process_execution(state, self, input, &observers, &exit_kind, false)? } else { - fuzzer.evaluate_input_with_observers(state, executor, self, input, false)? + fuzzer.evaluate_input_with_observers::( + state, executor, self, input, false, + )? }; #[cfg(feature = "std")] if let Some(item) = _res.1 { @@ -433,15 +431,25 @@ where } } -impl EventFirer for LlmpEventManager +impl UsesState for LlmpEventManager where - I: Input, - OT: ObserversTuple, + S: UsesInput, + SP: ShMemProvider, +{ + type State = S; +} + +impl EventFirer for LlmpEventManager +where + S: UsesInput, SP: ShMemProvider, - //CE: CustomEvent, { #[cfg(feature = "llmp_compression")] - fn fire(&mut self, _state: &mut S2, event: Event) -> Result<(), Error> { + fn fire( + &mut self, + _state: &mut Self::State, + event: Event<::Input>, + ) -> Result<(), Error> { let serialized = postcard::to_allocvec(&event)?; let flags: Flags = LLMP_FLAG_INITIALIZED; @@ -461,7 +469,11 @@ where } #[cfg(not(feature = "llmp_compression"))] - fn fire(&mut self, _state: &mut S2, event: Event) -> Result<(), Error> { + fn fire( + &mut self, + _state: &mut Self::State, + event: Event<::Input>, + ) -> Result<(), Error> { let serialized = postcard::to_allocvec(&event)?; self.llmp.send_buf(LLMP_TAG_EVENT_TO_BOTH, &serialized)?; Ok(()) @@ -472,12 +484,10 @@ where } } -impl EventRestarter for LlmpEventManager +impl EventRestarter for LlmpEventManager where - I: Input, - OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, - //CE: CustomEvent, { /// The llmp client needs to wait until a broker mapped all pages, before shutting down. /// Otherwise, the OS may already have removed the shared maps, @@ -487,15 +497,20 @@ where } } -impl EventProcessor for LlmpEventManager +impl EventProcessor for LlmpEventManager where + S: UsesInput + HasClientPerfMonitor + HasExecutions, SP: ShMemProvider, - E: Executor + HasObservers, - I: Input, - OT: ObserversTuple + DeserializeOwned, - Z: ExecutionProcessor + EvaluatorObservers, //CE: CustomEvent, + E: HasObservers + Executor, + for<'a> E::Observers: Deserialize<'a>, + Z: EvaluatorObservers + ExecutionProcessor, { - fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result { + fn process( + &mut self, + fuzzer: &mut Z, + state: &mut Self::State, + executor: &mut E, + ) -> Result { // TODO: Get around local event copy by moving handle_in_client let self_id = self.llmp.sender.id; let mut count = 0; @@ -519,7 +534,7 @@ where } else { msg }; - let event: Event = postcard::from_bytes(event_bytes)?; + let event: Event = postcard::from_bytes(event_bytes)?; self.handle_in_client(fuzzer, executor, state, client_id, event)?; count += 1; } @@ -527,20 +542,19 @@ where } } -impl EventManager for LlmpEventManager +impl EventManager for LlmpEventManager where - E: Executor + HasObservers, - I: Input, - OT: ObserversTuple + DeserializeOwned, + E: HasObservers + Executor, + for<'a> E::Observers: Deserialize<'a>, + S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata, SP: ShMemProvider, - Z: ExecutionProcessor + EvaluatorObservers, //CE: CustomEvent, + Z: EvaluatorObservers + ExecutionProcessor, { } -impl HasCustomBufHandlers for LlmpEventManager +impl HasCustomBufHandlers for LlmpEventManager where - I: Input, - OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, { fn add_custom_buf_handler( @@ -551,18 +565,16 @@ where } } -impl ProgressReporter for LlmpEventManager +impl ProgressReporter for LlmpEventManager where - I: Input, - OT: ObserversTuple + DeserializeOwned, + S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata, SP: ShMemProvider, { } -impl HasEventManagerId for LlmpEventManager +impl HasEventManagerId for LlmpEventManager where - I: Input, - OT: ObserversTuple + DeserializeOwned, + S: UsesInput, SP: ShMemProvider, { /// Gets the id assigned to this staterestorer. @@ -576,38 +588,47 @@ where /// A manager that can restart on the fly, storing states in-between (in `on_restart`) #[cfg(feature = "std")] #[derive(Debug)] -pub struct LlmpRestartingEventManager +pub struct LlmpRestartingEventManager where - I: Input, - OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider + 'static, //CE: CustomEvent, { /// The embedded llmp event manager - llmp_mgr: LlmpEventManager, + llmp_mgr: LlmpEventManager, /// The staterestorer to serialize the state for the next runner staterestorer: StateRestorer, } #[cfg(feature = "std")] -impl ProgressReporter for LlmpRestartingEventManager +impl UsesState for LlmpRestartingEventManager where - I: Input, - OT: ObserversTuple, - S: Serialize, + S: UsesInput, + SP: ShMemProvider + 'static, +{ + type State = S; +} + +#[cfg(feature = "std")] +impl ProgressReporter for LlmpRestartingEventManager +where + S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata + Serialize, SP: ShMemProvider, { } #[cfg(feature = "std")] -impl EventFirer for LlmpRestartingEventManager +impl EventFirer for LlmpRestartingEventManager where - I: Input, - OT: ObserversTuple, SP: ShMemProvider, + S: UsesInput, //CE: CustomEvent, { - fn fire(&mut self, state: &mut S2, event: Event) -> Result<(), Error> { + fn fire( + &mut self, + state: &mut Self::State, + event: Event<::Input>, + ) -> Result<(), Error> { // Check if we are going to crash in the event, in which case we store our current state for the next runner self.llmp_mgr.fire(state, event) } @@ -618,11 +639,9 @@ where } #[cfg(feature = "std")] -impl EventRestarter for LlmpRestartingEventManager +impl EventRestarter for LlmpRestartingEventManager where - I: Input, - OT: ObserversTuple, - S: Serialize, + S: UsesInput + HasExecutions + HasClientPerfMonitor + Serialize, SP: ShMemProvider, //CE: CustomEvent, { @@ -643,14 +662,13 @@ where } #[cfg(feature = "std")] -impl EventProcessor for LlmpRestartingEventManager +impl EventProcessor for LlmpRestartingEventManager where - E: Executor, I, S, Z> + HasObservers, - I: Input, - Z: ExecutionProcessor + EvaluatorObservers, - OT: ObserversTuple + DeserializeOwned, + E: HasObservers + Executor, Z>, + for<'a> E::Observers: Deserialize<'a>, + S: UsesInput + HasExecutions + HasClientPerfMonitor, SP: ShMemProvider + 'static, - //CE: CustomEvent, + Z: EvaluatorObservers + ExecutionProcessor, //CE: CustomEvent, { fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result { self.llmp_mgr.process(fuzzer, state, executor) @@ -658,24 +676,20 @@ where } #[cfg(feature = "std")] -impl EventManager for LlmpRestartingEventManager +impl EventManager for LlmpRestartingEventManager where - E: Executor, I, S, Z> + HasObservers, - I: Input, - S: Serialize, - Z: ExecutionProcessor + EvaluatorObservers, - OT: ObserversTuple + DeserializeOwned, + E: HasObservers + Executor, Z>, + for<'a> E::Observers: Deserialize<'a>, + S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata + Serialize, SP: ShMemProvider + 'static, - //CE: CustomEvent, + Z: EvaluatorObservers + ExecutionProcessor, //CE: CustomEvent, { } #[cfg(feature = "std")] -impl HasEventManagerId for LlmpRestartingEventManager +impl HasEventManagerId for LlmpRestartingEventManager where - I: Input, - OT: ObserversTuple + DeserializeOwned, - S: Serialize, + S: UsesInput + Serialize, SP: ShMemProvider + 'static, { fn mgr_id(&self) -> EventManagerId { @@ -690,15 +704,14 @@ const _ENV_FUZZER_RECEIVER: &str = "_AFL_ENV_FUZZER_RECEIVER"; const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT"; #[cfg(feature = "std")] -impl LlmpRestartingEventManager +impl LlmpRestartingEventManager where - I: Input, - OT: ObserversTuple + DeserializeOwned, + S: UsesInput, SP: ShMemProvider + 'static, //CE: CustomEvent, { /// Create a new runner, the executed child doing the actual fuzzing. - pub fn new(llmp_mgr: LlmpEventManager, staterestorer: StateRestorer) -> Self { + pub fn new(llmp_mgr: LlmpEventManager, staterestorer: StateRestorer) -> Self { Self { llmp_mgr, staterestorer, @@ -736,22 +749,14 @@ pub enum ManagerKind { /// The restarter will spawn a new process each time the child crashes or timeouts. #[cfg(feature = "std")] #[allow(clippy::type_complexity)] -pub fn setup_restarting_mgr_std( +pub fn setup_restarting_mgr_std( monitor: MT, broker_port: u16, configuration: EventConfig, -) -> Result< - ( - Option, - LlmpRestartingEventManager, - ), - Error, -> +) -> Result<(Option, LlmpRestartingEventManager), Error> where - I: Input, MT: Monitor + Clone, - OT: ObserversTuple + DeserializeOwned, - S: DeserializeOwned, + S: DeserializeOwned + UsesInput + HasClientPerfMonitor + HasExecutions, { RestartingMgr::builder() .shmem_provider(StdShMemProvider::new()?) @@ -768,11 +773,9 @@ where #[cfg(feature = "std")] #[allow(clippy::default_trait_access)] #[derive(TypedBuilder, Debug)] -pub struct RestartingMgr +pub struct RestartingMgr where - I: Input, - OT: ObserversTuple + DeserializeOwned, - S: DeserializeOwned, + S: UsesInput + DeserializeOwned, SP: ShMemProvider + 'static, MT: Monitor, //CE: CustomEvent, @@ -795,28 +798,25 @@ where #[builder(default = ManagerKind::Any)] kind: ManagerKind, #[builder(setter(skip), default = PhantomData)] - phantom_data: PhantomData<(I, OT, S)>, + phantom_data: PhantomData, } #[cfg(feature = "std")] #[allow(clippy::type_complexity, clippy::too_many_lines)] -impl RestartingMgr +impl RestartingMgr where - I: Input, - OT: ObserversTuple + DeserializeOwned, - S: DeserializeOwned, SP: ShMemProvider, + S: UsesInput + HasExecutions + HasClientPerfMonitor + DeserializeOwned, MT: Monitor + Clone, { /// Launch the restarting manager - pub fn launch( - &mut self, - ) -> Result<(Option, LlmpRestartingEventManager), Error> { + pub fn launch(&mut self) -> Result<(Option, LlmpRestartingEventManager), Error> { // We start ourself as child process to actually fuzz let (staterestorer, new_shmem_provider, core_id) = if std::env::var(_ENV_FUZZER_SENDER) .is_err() { - let broker_things = |mut broker: LlmpEventBroker, remote_broker_addr| { + let broker_things = |mut broker: LlmpEventBroker, + remote_broker_addr| { if let Some(remote_broker_addr) = remote_broker_addr { println!("B2b: Connecting to {:?}", &remote_broker_addr); broker.connect_b2b(remote_broker_addr)?; @@ -832,7 +832,7 @@ where LlmpConnection::on_port(self.shmem_provider.clone(), self.broker_port)?; match connection { LlmpConnection::IsBroker { broker } => { - let event_broker = LlmpEventBroker::::new( + let event_broker = LlmpEventBroker::::new( broker, self.monitor.take().unwrap(), )?; @@ -847,14 +847,13 @@ where return Err(Error::shutting_down()); } LlmpConnection::IsClient { client } => { - let mgr = - LlmpEventManager::::new(client, self.configuration)?; + let mgr = LlmpEventManager::::new(client, self.configuration)?; (mgr, None) } } } ManagerKind::Broker => { - let event_broker = LlmpEventBroker::::new_on_port( + let event_broker = LlmpEventBroker::::new_on_port( self.shmem_provider.clone(), self.monitor.take().unwrap(), self.broker_port, @@ -866,7 +865,7 @@ where } ManagerKind::Client { cpu_core } => { // We are a client - let mgr = LlmpEventManager::::new_on_port( + let mgr = LlmpEventManager::::new_on_port( self.shmem_provider.clone(), self.broker_port, self.configuration, @@ -967,7 +966,7 @@ where } else { println!("First run. Let's set it all up"); // Mgr to send and receive msgs from/to all other fuzzer instances - let mgr = LlmpEventManager::::existing_client_from_env( + let mgr = LlmpEventManager::::existing_client_from_env( new_shmem_provider, _ENV_FUZZER_BROKER_CLIENT_INITIAL, self.configuration, @@ -1006,12 +1005,14 @@ mod tests { corpus::{Corpus, InMemoryCorpus, Testcase}, events::{llmp::_ENV_FUZZER_SENDER, LlmpEventManager}, executors::{ExitKind, InProcessExecutor}, + feedbacks::ConstFeedback, + fuzzer::Fuzzer, inputs::BytesInput, mutators::BitFlipMutator, schedulers::RandScheduler, stages::StdMutationalStage, state::StdState, - Fuzzer, StdFuzzer, + StdFuzzer, }; #[test] @@ -1020,12 +1021,16 @@ mod tests { let rand = StdRand::with_seed(0); let mut corpus = InMemoryCorpus::::new(); - let testcase = Testcase::new(vec![0; 4]); + let testcase = Testcase::new(vec![0; 4].into()); corpus.add(testcase).unwrap(); let solutions = InMemoryCorpus::::new(); - let mut state = StdState::new(rand, corpus, solutions, &mut (), &mut ()).unwrap(); + let mut feedback = ConstFeedback::new(false); + let mut objective = ConstFeedback::new(false); + + let mut state = + StdState::new(rand, corpus, solutions, &mut feedback, &mut objective).unwrap(); let mut shmem_provider = StdShMemProvider::new().unwrap(); @@ -1041,12 +1046,14 @@ mod tests { llmp_client.mark_safe_to_unmap(); } - let mut llmp_mgr = - LlmpEventManager::::new(llmp_client, "fuzzer".into()).unwrap(); + let mut llmp_mgr = LlmpEventManager::new(llmp_client, "fuzzer".into()).unwrap(); let scheduler = RandScheduler::new(); - let mut fuzzer = StdFuzzer::new(scheduler, (), ()); + let feedback = ConstFeedback::new(true); + let objective = ConstFeedback::new(false); + + let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut harness = |_buf: &BytesInput| ExitKind::Ok; let mut executor = InProcessExecutor::new( diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 9f41eea4a5..90c770ee2c 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -37,6 +37,7 @@ pub struct EventManagerId { #[cfg(feature = "introspection")] use crate::monitors::ClientPerfMonitor; +use crate::{inputs::UsesInput, state::UsesState}; /// The log event severity #[derive(Serialize, Deserialize, Debug, Clone, Copy)] @@ -300,10 +301,7 @@ where } /// [`EventFirer`] fire an event. -pub trait EventFirer -where - I: Input, -{ +pub trait EventFirer: UsesState { /// Send off an [`Event`] to the broker /// /// For multi-processed managers, such as [`llmp::LlmpEventManager`], @@ -312,13 +310,17 @@ where /// (for example for each [`Input`], on multiple cores) /// the [`llmp`] shared map may fill up and the client will eventually OOM or [`panic`]. /// This should not happen for a normal use-case. - fn fire(&mut self, state: &mut S, event: Event) -> Result<(), Error>; + fn fire( + &mut self, + state: &mut Self::State, + event: Event<::Input>, + ) -> Result<(), Error>; /// Send off an [`Event::Log`] event to the broker. /// This is a shortcut for [`EventFirer::fire`] with [`Event::Log`] as argument. - fn log( + fn log( &mut self, - state: &mut S, + state: &mut Self::State, severity_level: LogSeverity, message: String, ) -> Result<(), Error> { @@ -333,9 +335,9 @@ where } /// Serialize all observers for this type and manager - fn serialize_observers(&mut self, observers: &OT) -> Result, Error> + fn serialize_observers(&mut self, observers: &OT) -> Result, Error> where - OT: ObserversTuple + Serialize, + OT: ObserversTuple + Serialize, { Ok(postcard::to_allocvec(observers)?) } @@ -347,22 +349,19 @@ where } /// [`ProgressReporter`] report progress to the broker. -pub trait ProgressReporter: EventFirer +pub trait ProgressReporter: EventFirer where - I: Input, + Self::State: HasClientPerfMonitor + HasMetadata + HasExecutions, { /// Given the last time, if `monitor_timeout` seconds passed, send off an info/monitor/heartbeat message to the broker. /// Returns the new `last` time (so the old one, unless `monitor_timeout` time has passed and monitor have been sent) /// Will return an [`crate::Error`], if the stats could not be sent. - fn maybe_report_progress( + fn maybe_report_progress( &mut self, - state: &mut S, + state: &mut Self::State, last_report_time: Duration, monitor_timeout: Duration, - ) -> Result - where - S: HasExecutions + HasClientPerfMonitor + HasMetadata, - { + ) -> Result { let executions = *state.executions(); let cur = current_time(); // default to 0 here to avoid crashes on clock skew @@ -421,10 +420,10 @@ where } /// Restartable trait -pub trait EventRestarter { +pub trait EventRestarter: UsesState { /// For restarting event managers, implement a way to forward state to their next peers. #[inline] - fn on_restart(&mut self, _state: &mut S) -> Result<(), Error> { + fn on_restart(&mut self, _state: &mut Self::State) -> Result<(), Error> { Ok(()) } @@ -434,18 +433,15 @@ pub trait EventRestarter { } /// [`EventProcessor`] process all the incoming messages -pub trait EventProcessor { +pub trait EventProcessor: UsesState { /// Lookup for incoming events and process them. /// Return the number of processes events or an error - fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result; - - /// Deserialize all observers for this type and manager - fn deserialize_observers(&mut self, observers_buf: &[u8]) -> Result - where - OT: ObserversTuple + serde::de::DeserializeOwned, - { - Ok(postcard::from_bytes(observers_buf)?) - } + fn process( + &mut self, + fuzzer: &mut Z, + state: &mut Self::State, + executor: &mut E, + ) -> Result; } /// The id of this [`EventManager`]. /// For multi processed [`EventManager`]s, @@ -458,14 +454,10 @@ pub trait HasEventManagerId { /// [`EventManager`] is the main communications hub. /// For the "normal" multi-processed mode, you may want to look into [`LlmpRestartingEventManager`] -pub trait EventManager: - EventFirer - + EventProcessor - + EventRestarter - + HasEventManagerId - + ProgressReporter +pub trait EventManager: + EventFirer + EventProcessor + EventRestarter + HasEventManagerId + ProgressReporter where - I: Input, + Self::State: HasClientPerfMonitor + HasMetadata + HasExecutions, { } @@ -480,34 +472,63 @@ pub trait HasCustomBufHandlers { } /// An eventmgr for tests, and as placeholder if you really don't need an event manager. -#[derive(Copy, Clone, Debug)] -pub struct NopEventManager {} +#[derive(Copy, Clone, Debug, Default)] +pub struct NopEventManager { + phantom: PhantomData, +} -impl EventFirer for NopEventManager +impl NopEventManager { + /// Creates a new [`NopEventManager`] + #[must_use] + pub fn new() -> Self { + NopEventManager { + phantom: PhantomData, + } + } +} + +impl UsesState for NopEventManager where - I: Input, + S: UsesInput, { - fn fire(&mut self, _state: &mut S, _event: Event) -> Result<(), Error> { + type State = S; +} + +impl EventFirer for NopEventManager +where + S: UsesInput, +{ + fn fire( + &mut self, + _state: &mut Self::State, + _event: Event<::Input>, + ) -> Result<(), Error> { Ok(()) } } -impl EventRestarter for NopEventManager {} +impl EventRestarter for NopEventManager where S: UsesInput {} -impl EventProcessor for NopEventManager { +impl EventProcessor for NopEventManager +where + S: UsesInput + HasClientPerfMonitor + HasExecutions, +{ fn process( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut Self::State, _executor: &mut E, ) -> Result { Ok(0) } } -impl EventManager for NopEventManager where I: Input {} +impl EventManager for NopEventManager where + S: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata +{ +} -impl HasCustomBufHandlers for NopEventManager { +impl HasCustomBufHandlers for NopEventManager { fn add_custom_buf_handler( &mut self, _handler: Box Result>, @@ -515,9 +536,12 @@ impl HasCustomBufHandlers for NopEventManager { } } -impl ProgressReporter for NopEventManager where I: Input {} +impl ProgressReporter for NopEventManager where + S: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata +{ +} -impl HasEventManagerId for NopEventManager { +impl HasEventManagerId for NopEventManager { fn mgr_id(&self) -> EventManagerId { EventManagerId { id: 0 } } @@ -594,7 +618,7 @@ pub mod pybind { executors::pybind::PythonExecutor, fuzzer::pybind::PythonStdFuzzer, inputs::BytesInput, - state::pybind::PythonStdState, + state::{pybind::PythonStdState, UsesState}, Error, }; @@ -637,17 +661,19 @@ pub mod pybind { } } - impl EventFirer for PythonEventManager { - fn fire(&mut self, state: &mut S, event: Event) -> Result<(), Error> { + impl UsesState for PythonEventManager { + type State = PythonStdState; + } + + impl EventFirer for PythonEventManager { + fn fire(&mut self, state: &mut Self::State, event: Event) -> Result<(), Error> { unwrap_me_mut!(self.wrapper, e, { e.fire(state, event) }) } } - impl EventRestarter for PythonEventManager {} + impl EventRestarter for PythonEventManager {} - impl EventProcessor - for PythonEventManager - { + impl EventProcessor for PythonEventManager { fn process( &mut self, fuzzer: &mut PythonStdFuzzer, @@ -658,7 +684,7 @@ pub mod pybind { } } - impl ProgressReporter for PythonEventManager {} + impl ProgressReporter for PythonEventManager {} impl HasEventManagerId for PythonEventManager { fn mgr_id(&self) -> EventManagerId { @@ -666,10 +692,7 @@ pub mod pybind { } } - impl EventManager - for PythonEventManager - { - } + impl EventManager for PythonEventManager {} /// Register the classes to the python module pub fn register(_py: Python, m: &PyModule) -> PyResult<()> { diff --git a/libafl/src/events/simple.rs b/libafl/src/events/simple.rs index 4764d0d6f1..402d535aa9 100644 --- a/libafl/src/events/simple.rs +++ b/libafl/src/events/simple.rs @@ -21,7 +21,7 @@ use crate::bolts::os::{fork, ForkResult}; use crate::{ bolts::{shmem::ShMemProvider, staterestore::StateRestorer}, corpus::Corpus, - executors::Executor, + monitors::SimplePrintingMonitor, state::{HasCorpus, HasSolutions}, }; use crate::{ @@ -29,8 +29,9 @@ use crate::{ BrokerEventResult, Event, EventFirer, EventManager, EventManagerId, EventProcessor, EventRestarter, HasEventManagerId, }, - inputs::Input, + inputs::UsesInput, monitors::Monitor, + state::{HasClientPerfMonitor, HasExecutions, HasMetadata, UsesState}, Error, }; @@ -41,24 +42,23 @@ const _ENV_FUZZER_RECEIVER: &str = "_AFL_ENV_FUZZER_RECEIVER"; const _ENV_FUZZER_BROKER_CLIENT_INITIAL: &str = "_AFL_ENV_FUZZER_BROKER_CLIENT"; /// A simple, single-threaded event manager that just logs -pub struct SimpleEventManager +pub struct SimpleEventManager where - I: Input, - MT: Monitor + Debug, //CE: CustomEvent, + S: UsesInput, { /// The monitor monitor: MT, /// The events that happened since the last handle_in_broker - events: Vec>, + events: Vec>, /// The custom buf handler custom_buf_handlers: Vec>>, phantom: PhantomData, } -impl Debug for SimpleEventManager +impl Debug for SimpleEventManager where - I: Input, - MT: Monitor + Debug, + MT: Debug, + S: UsesInput, { fn fmt(&self, f: &mut core::fmt::Formatter<'_>) -> core::fmt::Result { f.debug_struct("SimpleEventManager") @@ -69,12 +69,23 @@ where } } -impl EventFirer for SimpleEventManager +impl UsesState for SimpleEventManager where - I: Input, - MT: Monitor + Debug, //CE: CustomEvent, + S: UsesInput, { - fn fire(&mut self, _state: &mut S2, event: Event) -> Result<(), Error> { + type State = S; +} + +impl EventFirer for SimpleEventManager +where + MT: Monitor, + S: UsesInput, +{ + fn fire( + &mut self, + _state: &mut Self::State, + event: Event<::Input>, + ) -> Result<(), Error> { match Self::handle_in_broker(&mut self.monitor, &event)? { BrokerEventResult::Forward => self.events.push(event), BrokerEventResult::Handled => (), @@ -83,17 +94,17 @@ where } } -impl EventRestarter for SimpleEventManager +impl EventRestarter for SimpleEventManager where - I: Input, - MT: Monitor + Debug, //CE: CustomEvent, + MT: Monitor, + S: UsesInput, { } -impl EventProcessor for SimpleEventManager +impl EventProcessor for SimpleEventManager where - I: Input, - MT: Monitor + Debug, //CE: CustomEvent, + MT: Monitor, + S: UsesInput, { fn process( &mut self, @@ -110,17 +121,17 @@ where } } -impl EventManager for SimpleEventManager +impl EventManager for SimpleEventManager where - I: Input, - MT: Monitor + Debug, //CE: CustomEvent, + MT: Monitor, + S: UsesInput + HasClientPerfMonitor + HasExecutions + HasMetadata, { } -impl HasCustomBufHandlers for SimpleEventManager +impl HasCustomBufHandlers for SimpleEventManager where - I: Input, - MT: Monitor + Debug, //CE: CustomEvent, + MT: Monitor, //CE: CustomEvent, + S: UsesInput, { /// Adds a custom buffer handler that will run for each incoming `CustomBuf` event. fn add_custom_buf_handler( @@ -131,27 +142,39 @@ where } } -impl ProgressReporter for SimpleEventManager +impl ProgressReporter for SimpleEventManager where - I: Input, - MT: Monitor + Debug, //CE: CustomEvent, + MT: Monitor, + S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata, { } -impl HasEventManagerId for SimpleEventManager +impl HasEventManagerId for SimpleEventManager where - I: Input, - MT: Monitor + Debug, + MT: Monitor, + S: UsesInput, { fn mgr_id(&self) -> EventManagerId { EventManagerId { id: 0 } } } -impl SimpleEventManager +#[cfg(feature = "std")] +impl SimpleEventManager where - I: Input, - MT: Monitor + Debug, //TODO CE: CustomEvent, + S: UsesInput, +{ + /// Creates a [`SimpleEventManager`] that just prints to `stdout`. + #[must_use] + pub fn printing() -> Self { + Self::new(SimplePrintingMonitor::new()) + } +} + +impl SimpleEventManager +where + MT: Monitor, //TODO CE: CustomEvent, + S: UsesInput, { /// Creates a new [`SimpleEventManager`]. pub fn new(monitor: MT) -> Self { @@ -165,7 +188,10 @@ where /// Handle arriving events in the broker #[allow(clippy::unnecessary_wraps)] - fn handle_in_broker(monitor: &mut MT, event: &Event) -> Result { + fn handle_in_broker( + monitor: &mut MT, + event: &Event, + ) -> Result { match event { Event::NewTestcase { input: _, @@ -247,7 +273,7 @@ where // Handle arriving events in the client #[allow(clippy::needless_pass_by_value, clippy::unused_self)] - fn handle_in_client(&mut self, state: &mut S, event: Event) -> Result<(), Error> { + fn handle_in_client(&mut self, state: &mut S, event: Event) -> Result<(), Error> { if let Event::CustomBuf { tag, buf } = &event { for handler in &mut self.custom_buf_handlers { handler(state, tag, buf)?; @@ -268,37 +294,47 @@ where #[cfg(feature = "std")] #[allow(clippy::default_trait_access)] #[derive(Debug)] -pub struct SimpleRestartingEventManager +pub struct SimpleRestartingEventManager where - I: Input, - SP: ShMemProvider, - MT: Monitor + Debug, //CE: CustomEvent, + S: UsesInput, + SP: ShMemProvider, //CE: CustomEvent, { /// The actual simple event mgr - simple_event_mgr: SimpleEventManager, + simple_event_mgr: SimpleEventManager, /// [`StateRestorer`] for restarts staterestorer: StateRestorer, } #[cfg(feature = "std")] -impl EventFirer for SimpleRestartingEventManager +impl UsesState for SimpleRestartingEventManager where - I: Input, + S: UsesInput, SP: ShMemProvider, - MT: Monitor + Debug, //CE: CustomEvent, { - fn fire(&mut self, _state: &mut S2, event: Event) -> Result<(), Error> { + type State = S; +} + +#[cfg(feature = "std")] +impl EventFirer for SimpleRestartingEventManager +where + MT: Monitor, + S: UsesInput, + SP: ShMemProvider, +{ + fn fire( + &mut self, + _state: &mut Self::State, + event: Event<::Input>, + ) -> Result<(), Error> { self.simple_event_mgr.fire(_state, event) } } #[cfg(feature = "std")] -impl EventRestarter for SimpleRestartingEventManager +impl EventRestarter for SimpleRestartingEventManager where - I: Input, - S: Serialize, + S: UsesInput + Serialize, SP: ShMemProvider, - MT: Monitor + Debug, //CE: CustomEvent, { /// Reset the single page (we reuse it over and over from pos 0), then send the current state to the next runner. fn on_restart(&mut self, state: &mut S) -> Result<(), Error> { @@ -309,35 +345,37 @@ where } #[cfg(feature = "std")] -impl EventProcessor for SimpleRestartingEventManager +impl EventProcessor for SimpleRestartingEventManager where - I: Input, - S: Serialize, + MT: Monitor, + S: UsesInput + HasClientPerfMonitor + HasExecutions + Serialize, SP: ShMemProvider, - MT: Monitor + Debug, //CE: CustomEvent, { - fn process(&mut self, fuzzer: &mut Z, state: &mut S, executor: &mut E) -> Result { + fn process( + &mut self, + fuzzer: &mut Z, + state: &mut Self::State, + executor: &mut E, + ) -> Result { self.simple_event_mgr.process(fuzzer, state, executor) } } #[cfg(feature = "std")] -impl EventManager for SimpleRestartingEventManager +impl EventManager for SimpleRestartingEventManager where - E: Executor, - I: Input, - S: Serialize, + MT: Monitor, + S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata + Serialize, SP: ShMemProvider, - MT: Monitor + Debug, //CE: CustomEvent, { } #[cfg(feature = "std")] -impl HasCustomBufHandlers for SimpleRestartingEventManager +impl HasCustomBufHandlers for SimpleRestartingEventManager where - I: Input, + MT: Monitor, + S: UsesInput, SP: ShMemProvider, - MT: Monitor + Debug, //CE: CustomEvent, { fn add_custom_buf_handler( &mut self, @@ -348,20 +386,20 @@ where } #[cfg(feature = "std")] -impl ProgressReporter for SimpleRestartingEventManager +impl ProgressReporter for SimpleRestartingEventManager where - I: Input, + MT: Monitor, + S: UsesInput + HasExecutions + HasClientPerfMonitor + HasMetadata, SP: ShMemProvider, - MT: Monitor + Debug, //CE: CustomEvent, { } #[cfg(feature = "std")] -impl HasEventManagerId for SimpleRestartingEventManager +impl HasEventManagerId for SimpleRestartingEventManager where - I: Input, + MT: Monitor, + S: UsesInput, SP: ShMemProvider, - MT: Monitor + Debug, { fn mgr_id(&self) -> EventManagerId { self.simple_event_mgr.mgr_id() @@ -370,11 +408,11 @@ where #[cfg(feature = "std")] #[allow(clippy::type_complexity, clippy::too_many_lines)] -impl SimpleRestartingEventManager +impl SimpleRestartingEventManager where - I: Input, + S: UsesInput, SP: ShMemProvider, - MT: Monitor + Debug, //TODO CE: CustomEvent, + MT: Monitor, //TODO CE: CustomEvent, { /// Creates a new [`SimpleEventManager`]. fn new_launched(monitor: MT, staterestorer: StateRestorer) -> Self { @@ -390,7 +428,7 @@ where #[allow(clippy::similar_names)] pub fn launch(mut monitor: MT, shmem_provider: &mut SP) -> Result<(Option, Self), Error> where - S: DeserializeOwned + Serialize + HasCorpus + HasSolutions, + S: DeserializeOwned + Serialize + HasCorpus + HasSolutions, MT: Debug, { // We start ourself as child process to actually fuzz @@ -498,7 +536,6 @@ pub mod pybind { use crate::{ events::{pybind::PythonEventManager, SimpleEventManager}, - inputs::BytesInput, monitors::pybind::PythonMonitor, state::pybind::PythonStdState, }; @@ -508,7 +545,7 @@ pub mod pybind { /// Python class for SimpleEventManager pub struct PythonSimpleEventManager { /// Rust wrapped SimpleEventManager object - pub inner: SimpleEventManager, + pub inner: SimpleEventManager, } #[pymethods] diff --git a/libafl/src/executors/combined.rs b/libafl/src/executors/combined.rs index d41f83040b..708baa8c7f 100644 --- a/libafl/src/executors/combined.rs +++ b/libafl/src/executors/combined.rs @@ -5,25 +5,26 @@ use core::fmt::Debug; use crate::{ executors::{Executor, ExitKind, HasObservers}, - inputs::Input, - observers::ObserversTuple, + observers::UsesObservers, + state::UsesState, Error, }; /// A [`CombinedExecutor`] wraps a primary executor, forwarding its methods, and a secondary one #[derive(Debug)] -pub struct CombinedExecutor { +pub struct CombinedExecutor { primary: A, secondary: B, } -impl CombinedExecutor { +impl CombinedExecutor { /// Create a new `CombinedExecutor`, wrapping the given `executor`s. - pub fn new(primary: A, secondary: B) -> Self + pub fn new(primary: A, secondary: B) -> Self where - A: Executor, - B: Executor, - I: Input, + A: Executor, + B: Executor, + EM: UsesState, + Z: UsesState, { Self { primary, secondary } } @@ -39,18 +40,19 @@ impl CombinedExecutor { } } -impl Executor for CombinedExecutor +impl Executor for CombinedExecutor where - A: Executor, - B: Executor, - I: Input, + A: Executor, + B: Executor, + EM: UsesState, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { let ret = self.primary.run_target(fuzzer, state, mgr, input); self.primary.post_run_reset(); @@ -59,19 +61,31 @@ where } } -impl HasObservers for CombinedExecutor +impl UsesState for CombinedExecutor where - A: HasObservers, - B: Debug, - OT: ObserversTuple, + A: UsesState, +{ + type State = A::State; +} + +impl UsesObservers for CombinedExecutor +where + A: UsesObservers, +{ + type Observers = A::Observers; +} + +impl HasObservers for CombinedExecutor +where + A: HasObservers, { #[inline] - fn observers(&self) -> &OT { + fn observers(&self) -> &Self::Observers { self.primary.observers() } #[inline] - fn observers_mut(&mut self) -> &mut OT { + fn observers_mut(&mut self) -> &mut Self::Observers { self.primary.observers_mut() } } diff --git a/libafl/src/executors/command.rs b/libafl/src/executors/command.rs index 9e269ccaad..f58514927d 100644 --- a/libafl/src/executors/command.rs +++ b/libafl/src/executors/command.rs @@ -26,8 +26,9 @@ use crate::{ tuples::MatchName, AsSlice, }, - inputs::HasTargetBytes, - observers::ObserversTuple, + inputs::{HasTargetBytes, UsesInput}, + observers::{ObserversTuple, UsesObservers}, + state::UsesState, std::borrow::ToOwned, }; #[cfg(feature = "std")] @@ -149,20 +150,16 @@ impl CommandConfigurator for StdCommandConfigurator { /// A `CommandExecutor` is a wrapper around [`std::process::Command`] to execute a target as a child process. /// Construct a `CommandExecutor` by implementing [`CommandConfigurator`] for a type of your choice and calling [`CommandConfigurator::into_executor`] on it. -/// Instead, you can also use [`CommandExecutor::builder()`] to construct a [`CommandExecutor`] backed by a [`StdCommandConfigurator`]. -pub struct CommandExecutor -where - T: Debug, - OT: Debug, -{ - /// The wrapped command configurer +/// Instead, you can use [`CommandExecutor::builder()`] to construct a [`CommandExecutor`] backed by a [`StdCommandConfigurator`]. +pub struct CommandExecutor { + /// The wrapped comand configurer configurer: T, - /// The obsevers used by this executor + /// The observers used by this executor observers: OT, - phantom: PhantomData<(EM, I, S, Z)>, + phantom: PhantomData<(EM, S, Z)>, } -impl CommandExecutor<(), (), (), (), (), ()> { +impl CommandExecutor<(), (), (), (), ()> { /// Creates a builder for a new [`CommandExecutor`], /// backed by a [`StdCommandConfigurator`] /// This is usually the easiest way to construct a [`CommandExecutor`]. @@ -181,7 +178,7 @@ impl CommandExecutor<(), (), (), (), (), ()> { } } -impl Debug for CommandExecutor +impl Debug for CommandExecutor where T: Debug, OT: Debug, @@ -194,7 +191,7 @@ where } } -impl CommandExecutor +impl CommandExecutor where T: Debug, OT: Debug, @@ -205,9 +202,10 @@ where } } -impl CommandExecutor +impl CommandExecutor where - OT: MatchName + Debug + ObserversTuple, + OT: MatchName + Debug + ObserversTuple, + S: UsesInput, { /// Creates a new `CommandExecutor`. /// Instead of parsing the Command for `@@`, it will @@ -295,19 +293,21 @@ where // this only works on unix because of the reliance on checking the process signal for detecting OOM #[cfg(all(feature = "std", unix))] -impl Executor for CommandExecutor +impl Executor for CommandExecutor where - I: Input + HasTargetBytes, - T: CommandConfigurator, - OT: Debug + MatchName + ObserversTuple, - T: Debug, + EM: UsesState, + S: UsesInput, + S::Input: HasTargetBytes, + T: CommandConfigurator + Debug, + OT: Debug + MatchName + ObserversTuple, + Z: UsesState, { fn run_target( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut Self::State, _mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { use std::os::unix::prelude::ExitStatusExt; @@ -357,8 +357,26 @@ where } } -impl, S, T: Debug, Z> HasObservers - for CommandExecutor +impl UsesState for CommandExecutor +where + S: UsesInput, +{ + type State = S; +} + +impl UsesObservers for CommandExecutor +where + OT: ObserversTuple, + S: UsesInput, +{ + type Observers = OT; +} + +impl HasObservers for CommandExecutor +where + S: UsesInput, + T: Debug, + OT: ObserversTuple, { fn observers(&self) -> &OT { &self.observers @@ -508,13 +526,14 @@ impl CommandExecutorBuilder { self } - /// Builds the `CommandExecutor`. - pub fn build( + /// Builds the `ComandExecutor` + pub fn build( &self, mut observers: OT, - ) -> Result, Error> + ) -> Result, Error> where - OT: Debug + MatchName + ObserversTuple, + OT: Debug + MatchName + ObserversTuple, + S: UsesInput, { let program = if let Some(program) = &self.program { program @@ -560,7 +579,7 @@ impl CommandExecutorBuilder { input_location: self.input_location.clone(), command, }; - Ok(configurator.into_executor::(observers)) + Ok(configurator.into_executor::(observers)) } } @@ -569,7 +588,7 @@ impl CommandExecutorBuilder { #[cfg_attr(all(feature = "std", unix), doc = " ```")] #[cfg_attr(not(all(feature = "std", unix)), doc = " ```ignore")] /// use std::{io::Write, process::{Stdio, Command, Child}}; -/// use libafl::{Error, bolts::AsSlice, inputs::{Input, HasTargetBytes}, executors::{Executor, command::CommandConfigurator}}; +/// use libafl::{Error, bolts::AsSlice, inputs::{HasTargetBytes, Input, UsesInput}, executors::{Executor, command::CommandConfigurator}, state::UsesState}; /// #[derive(Debug)] /// struct MyExecutor; /// @@ -591,8 +610,14 @@ impl CommandExecutorBuilder { /// } /// } /// -/// fn make_executor() -> impl Executor { -/// MyExecutor.into_executor(()) +/// fn make_executor() -> impl Executor +/// where +/// EM: UsesState, +/// Z: UsesState, +/// EM::State: UsesInput, +/// EM::Input: HasTargetBytes +/// { +/// MyExecutor.into_executor((), None, None, None) /// } /// ``` @@ -604,8 +629,7 @@ pub trait CommandConfigurator: Sized + Debug { I: Input + HasTargetBytes; /// Create an `Executor` from this `CommandConfigurator`. - /// It will observe the outputs with the respective given observer name. - fn into_executor(self, observers: OT) -> CommandExecutor + fn into_executor(self, observers: OT) -> CommandExecutor where OT: Debug + MatchName, { @@ -627,12 +651,14 @@ mod tests { }, inputs::BytesInput, monitors::SimpleMonitor, + state::NopState, + NopFuzzer, }; #[test] #[cfg(unix)] fn test_builder() { - let mut mgr = SimpleEventManager::::new(SimpleMonitor::new(|status| { + let mut mgr = SimpleEventManager::new(SimpleMonitor::new(|status| { println!("{status}"); })); @@ -645,8 +671,8 @@ mod tests { executor .run_target( - &mut (), - &mut (), + &mut NopFuzzer::new(), + &mut NopState::new(), &mut mgr, &BytesInput::new(b"test".to_vec()), ) @@ -657,7 +683,8 @@ mod tests { #[cfg(unix)] fn test_parse_afl_cmdline() { use alloc::string::ToString; - let mut mgr = SimpleEventManager::::new(SimpleMonitor::new(|status| { + + let mut mgr = SimpleEventManager::new(SimpleMonitor::new(|status| { println!("{status}"); })); @@ -666,8 +693,8 @@ mod tests { .unwrap(); executor .run_target( - &mut (), - &mut (), + &mut NopFuzzer::new(), + &mut NopState::new(), &mut mgr, &BytesInput::new(b"test".to_vec()), ) diff --git a/libafl/src/executors/differential.rs b/libafl/src/executors/differential.rs index dba1c7cef9..a46bd9b9fa 100644 --- a/libafl/src/executors/differential.rs +++ b/libafl/src/executors/differential.rs @@ -1,5 +1,5 @@ //! Executor for differential fuzzing. -//! It wraps two exeutors that will be run after each other with the same input. +//! It wraps two executors that will be run after each other with the same input. //! In comparison to the [`crate::executors::CombinedExecutor`] it also runs the secondary executor in `run_target`. //! use core::{cell::UnsafeCell, fmt::Debug}; @@ -9,38 +9,28 @@ use serde::{Deserialize, Serialize}; use crate::{ bolts::{ownedref::OwnedPtrMut, tuples::MatchName}, executors::{Executor, ExitKind, HasObservers}, - inputs::Input, - observers::ObserversTuple, + inputs::UsesInput, + observers::{ObserversTuple, UsesObservers}, + state::UsesState, Error, }; /// A [`DiffExecutor`] wraps a primary executor, forwarding its methods, and a secondary one #[derive(Debug)] -pub struct DiffExecutor -where - A: Debug, - B: Debug, - OTA: Debug, - OTB: Debug, -{ +pub struct DiffExecutor { primary: A, secondary: B, observers: UnsafeCell>, } -impl DiffExecutor -where - A: Debug, - B: Debug, - OTA: Debug, - OTB: Debug, -{ +impl DiffExecutor { /// Create a new `DiffExecutor`, wrapping the given `executor`s. - pub fn new(primary: A, secondary: B) -> Self + pub fn new(primary: A, secondary: B) -> Self where - A: Executor, - B: Executor, - I: Input, + A: Executor, + B: Executor, + EM: UsesState, + Z: UsesState, { Self { primary, @@ -63,20 +53,21 @@ where } } -impl Executor for DiffExecutor +impl Executor for DiffExecutor where - A: Executor, - B: Executor, - I: Input, + A: Executor, + B: Executor, + EM: UsesState, OTA: Debug, OTB: Debug, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { let ret1 = self.primary.run_target(fuzzer, state, mgr, input)?; self.primary.post_run_reset(); @@ -104,12 +95,13 @@ pub struct ProxyObserversTuple { secondary: OwnedPtrMut, } -impl ObserversTuple for ProxyObserversTuple +impl ObserversTuple for ProxyObserversTuple where - A: ObserversTuple, - B: ObserversTuple, + A: ObserversTuple, + B: ObserversTuple, + S: UsesInput, { - fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { self.primary.as_mut().pre_exec_all(state, input)?; self.secondary.as_mut().pre_exec_all(state, input) } @@ -117,7 +109,7 @@ where fn post_exec_all( &mut self, state: &mut S, - input: &I, + input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error> { self.primary @@ -128,7 +120,7 @@ where .post_exec_all(state, input, exit_kind) } - fn pre_exec_child_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { self.primary.as_mut().pre_exec_child_all(state, input)?; self.secondary.as_mut().pre_exec_child_all(state, input) } @@ -136,7 +128,7 @@ where fn post_exec_child_all( &mut self, state: &mut S, - input: &I, + input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error> { self.primary @@ -197,13 +189,30 @@ impl ProxyObserversTuple { } } -impl HasObservers, S> - for DiffExecutor +impl UsesObservers for DiffExecutor where - A: HasObservers, - B: HasObservers, - OTA: ObserversTuple, - OTB: ObserversTuple, + A: HasObservers, + B: HasObservers, + OTA: ObserversTuple, + OTB: ObserversTuple, +{ + type Observers = ProxyObserversTuple; +} + +impl UsesState for DiffExecutor +where + A: UsesState, + B: UsesState, +{ + type State = A::State; +} + +impl HasObservers for DiffExecutor +where + A: HasObservers, + B: HasObservers, + OTA: ObserversTuple, + OTB: ObserversTuple, { #[inline] fn observers(&self) -> &ProxyObserversTuple { diff --git a/libafl/src/executors/forkserver.rs b/libafl/src/executors/forkserver.rs index 8a6c8ea800..86e9102a25 100644 --- a/libafl/src/executors/forkserver.rs +++ b/libafl/src/executors/forkserver.rs @@ -31,9 +31,12 @@ use crate::{ AsMutSlice, AsSlice, }, executors::{Executor, ExitKind, HasObservers}, - inputs::{HasTargetBytes, Input}, + inputs::{HasTargetBytes, Input, UsesInput}, mutators::Tokens, - observers::{get_asan_runtime_flags_with_log_path, AsanBacktraceObserver, ObserversTuple}, + observers::{ + get_asan_runtime_flags_with_log_path, AsanBacktraceObserver, ObserversTuple, UsesObservers, + }, + state::UsesState, Error, }; @@ -370,13 +373,13 @@ pub trait HasForkserver { /// The timeout forkserver executor that wraps around the standard forkserver executor and sets a timeout before each run. #[derive(Debug)] -pub struct TimeoutForkserverExecutor { +pub struct TimeoutForkserverExecutor { executor: E, timeout: TimeSpec, signal: Signal, } -impl TimeoutForkserverExecutor { +impl TimeoutForkserverExecutor { /// Create a new [`TimeoutForkserverExecutor`] pub fn new(executor: E, exec_tmout: Duration) -> Result { let signal = Signal::SIGKILL; @@ -395,18 +398,20 @@ impl TimeoutForkserverExecutor { } } -impl Executor for TimeoutForkserverExecutor +impl Executor for TimeoutForkserverExecutor where - I: Input + HasTargetBytes, - E: Executor + HasForkserver, + E: Executor + HasForkserver + Debug, + E::Input: HasTargetBytes, + EM: UsesState, + Z: UsesState, { #[inline] fn run_target( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut Self::State, _mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { let mut exit_kind = ExitKind::Ok; @@ -491,9 +496,8 @@ where /// This [`Executor`] can run binaries compiled for AFL/AFL++ that make use of a forkserver. /// Shared memory feature is also available, but you have to set things up in your code. /// Please refer to AFL++'s docs. -pub struct ForkserverExecutor +pub struct ForkserverExecutor where - OT: Debug, SP: ShMemProvider, { target: OsString, @@ -502,12 +506,12 @@ where forkserver: Forkserver, observers: OT, map: Option, - phantom: PhantomData<(I, S)>, + phantom: PhantomData, /// Cache that indicates if we have a `ASan` observer registered. has_asan_observer: Option, } -impl Debug for ForkserverExecutor +impl Debug for ForkserverExecutor where OT: Debug, SP: ShMemProvider, @@ -524,7 +528,7 @@ where } } -impl ForkserverExecutor<(), (), (), StdShMemProvider> { +impl ForkserverExecutor<(), (), StdShMemProvider> { /// Builder for `ForkserverExecutor` #[must_use] pub fn builder() -> ForkserverExecutorBuilder<'static, StdShMemProvider> { @@ -532,10 +536,10 @@ impl ForkserverExecutor<(), (), (), StdShMemProvider> { } } -impl ForkserverExecutor +impl ForkserverExecutor where - I: Input + HasTargetBytes, - OT: ObserversTuple, + OT: ObserversTuple, + S: UsesState, SP: ShMemProvider, { /// The `target` binary that's going to run. @@ -578,13 +582,11 @@ pub struct ForkserverExecutorBuilder<'a, SP> { impl<'a, SP> ForkserverExecutorBuilder<'a, SP> { /// Builds `ForkserverExecutor`. #[allow(clippy::pedantic)] - pub fn build( - &mut self, - observers: OT, - ) -> Result, Error> + pub fn build(&mut self, observers: OT) -> Result, Error> where - I: Input + HasTargetBytes, - OT: ObserversTuple, + OT: ObserversTuple, + S: UsesInput, + S::Input: Input + HasTargetBytes, SP: ShMemProvider, { let input_filename = match &self.input_filename { @@ -895,19 +897,22 @@ impl<'a> Default for ForkserverExecutorBuilder<'a, StdShMemProvider> { } } -impl Executor for ForkserverExecutor +impl Executor for ForkserverExecutor where - I: Input + HasTargetBytes, - OT: ObserversTuple, + OT: ObserversTuple, SP: ShMemProvider, + S: UsesInput, + S::Input: HasTargetBytes, + EM: UsesState, + Z: UsesState, { #[inline] fn run_target( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut Self::State, _mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { let mut exit_kind = ExitKind::Ok; @@ -984,10 +989,27 @@ where } } -impl HasObservers for ForkserverExecutor +impl UsesState for ForkserverExecutor where - I: Input + HasTargetBytes, - OT: ObserversTuple, + S: UsesInput, + SP: ShMemProvider, +{ + type State = S; +} + +impl UsesObservers for ForkserverExecutor +where + OT: ObserversTuple, + S: UsesInput, + SP: ShMemProvider, +{ + type Observers = OT; +} + +impl HasObservers for ForkserverExecutor +where + OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, { #[inline] @@ -1001,10 +1023,11 @@ where } } -impl HasForkserver for ForkserverExecutor +impl HasForkserver for ForkserverExecutor where - I: Input + HasTargetBytes, - OT: ObserversTuple, + OT: ObserversTuple, + S: UsesInput, + S::Input: Input + HasTargetBytes, SP: ShMemProvider, { type SP = SP; @@ -1040,18 +1063,31 @@ where } } -impl HasObservers for TimeoutForkserverExecutor +impl UsesState for TimeoutForkserverExecutor where - E: HasObservers, - OT: ObserversTuple, + E: UsesState, +{ + type State = E::State; +} + +impl UsesObservers for TimeoutForkserverExecutor +where + E: UsesObservers, +{ + type Observers = E::Observers; +} + +impl HasObservers for TimeoutForkserverExecutor +where + E: HasObservers, { #[inline] - fn observers(&self) -> &OT { + fn observers(&self) -> &Self::Observers { self.executor.observers() } #[inline] - fn observers_mut(&mut self) -> &mut OT { + fn observers_mut(&mut self) -> &mut Self::Observers { self.executor.observers_mut() } } @@ -1069,10 +1105,10 @@ mod tests { AsMutSlice, }, executors::forkserver::ForkserverExecutorBuilder, - inputs::NopInput, observers::{ConstMapObserver, HitcountsMapObserver}, Error, }; + #[test] #[serial] fn test_forkserver() { @@ -1096,7 +1132,7 @@ mod tests { .args(&args) .debug_child(false) .shmem_provider(&mut shmem_provider) - .build::(tuple_list!(edges_observer)); + .build::<_, ()>(tuple_list!(edges_observer)); // Since /usr/bin/echo is not a instrumented binary file, the test will just check if the forkserver has failed at the initial handshake let result = match executor { diff --git a/libafl/src/executors/inprocess.rs b/libafl/src/executors/inprocess.rs index b04a38a355..ac71636d3f 100644 --- a/libafl/src/executors/inprocess.rs +++ b/libafl/src/executors/inprocess.rs @@ -46,27 +46,31 @@ use crate::{ executors::{Executor, ExitKind, HasObservers}, feedbacks::Feedback, fuzzer::HasObjective, - inputs::Input, - observers::ObserversTuple, - state::{HasClientPerfMonitor, HasSolutions}, + inputs::UsesInput, + observers::{ObserversTuple, UsesObservers}, + state::{HasClientPerfMonitor, HasSolutions, UsesState}, Error, }; /// The process executor simply calls a target function, as mutable reference to a closure -pub type InProcessExecutor<'a, H, I, OT, S> = GenericInProcessExecutor; +pub type InProcessExecutor<'a, H, OT, S> = GenericInProcessExecutor; /// The process executor simply calls a target function, as boxed `FnMut` trait object -pub type OwnedInProcessExecutor = - GenericInProcessExecutor ExitKind, Box ExitKind>, I, OT, S>; +pub type OwnedInProcessExecutor = GenericInProcessExecutor< + dyn FnMut(&::Input) -> ExitKind, + Box::Input) -> ExitKind>, + OT, + S, +>; /// The inmem executor simply calls a target function, then returns afterwards. #[allow(dead_code)] -pub struct GenericInProcessExecutor +pub struct GenericInProcessExecutor where - H: FnMut(&I) -> ExitKind + ?Sized, + H: FnMut(&S::Input) -> ExitKind + ?Sized, HB: BorrowMut, - I: Input, - OT: ObserversTuple, + OT: ObserversTuple, + S: UsesInput, { /// The harness function, being executed for each fuzzing loop execution harness_fn: HB, @@ -74,15 +78,15 @@ where observers: OT, // Crash and timeout hah handlers: InProcessHandlers, - phantom: PhantomData<(I, S, *const H)>, + phantom: PhantomData<(S, *const H)>, } -impl Debug for GenericInProcessExecutor +impl Debug for GenericInProcessExecutor where - H: FnMut(&I) -> ExitKind + ?Sized, + H: FnMut(&S::Input) -> ExitKind + ?Sized, HB: BorrowMut, - I: Input, - OT: ObserversTuple, + OT: ObserversTuple, + S: UsesInput, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("GenericInProcessExecutor") @@ -92,19 +96,41 @@ where } } -impl Executor for GenericInProcessExecutor +impl UsesState for GenericInProcessExecutor where - H: FnMut(&I) -> ExitKind + ?Sized, + H: ?Sized + FnMut(&S::Input) -> ExitKind, HB: BorrowMut, - I: Input, - OT: ObserversTuple, + OT: ObserversTuple, + S: UsesInput, +{ + type State = S; +} + +impl UsesObservers for GenericInProcessExecutor +where + H: ?Sized + FnMut(&S::Input) -> ExitKind, + HB: BorrowMut, + OT: ObserversTuple, + S: UsesInput, +{ + type Observers = OT; +} + +impl Executor for GenericInProcessExecutor +where + H: FnMut(&S::Input) -> ExitKind + ?Sized, + HB: BorrowMut, + EM: UsesState, + OT: ObserversTuple, + S: UsesInput, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { self.handlers .pre_run_target(self, fuzzer, state, mgr, input); @@ -116,12 +142,12 @@ where } } -impl HasObservers for GenericInProcessExecutor +impl HasObservers for GenericInProcessExecutor where - H: FnMut(&I) -> ExitKind + ?Sized, + H: FnMut(&S::Input) -> ExitKind + ?Sized, HB: BorrowMut, - I: Input, - OT: ObserversTuple, + OT: ObserversTuple, + S: UsesInput, { #[inline] fn observers(&self) -> &OT { @@ -134,12 +160,12 @@ where } } -impl GenericInProcessExecutor +impl GenericInProcessExecutor where - H: FnMut(&I) -> ExitKind + ?Sized, + H: FnMut(&::Input) -> ExitKind + ?Sized, HB: BorrowMut, - I: Input, - OT: ObserversTuple, + OT: ObserversTuple, + S: HasSolutions + HasClientPerfMonitor, { /// Create a new in mem executor. /// Caution: crash and restart in one of them will lead to odd behavior if multiple are used, @@ -155,12 +181,12 @@ where _event_mgr: &mut EM, ) -> Result where - EM: EventFirer + EventRestarter, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + Self: Executor, + EM: EventFirer + EventRestarter, + OF: Feedback, + Z: HasObjective, { - let handlers = InProcessHandlers::new::()?; + let handlers = InProcessHandlers::new::()?; #[cfg(windows)] unsafe { /* @@ -217,11 +243,11 @@ pub trait HasInProcessHandlers { } #[cfg(windows)] -impl<'a, H, I, OT, S> HasInProcessHandlers for InProcessExecutor<'a, H, I, OT, S> +impl<'a, H, OT, S> HasInProcessHandlers for InProcessExecutor<'a, H, OT, S> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + S: UsesInput, { /// the timeout handler #[inline] @@ -310,28 +336,26 @@ impl InProcessHandlers { } /// Create new [`InProcessHandlers`]. - pub fn new() -> Result + pub fn new() -> Result where - I: Input, - E: Executor + HasObservers, - OT: ObserversTuple, - EM: EventFirer + EventRestarter, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, - H: FnMut(&I) -> ExitKind + ?Sized, + E: Executor + HasObservers, + EM: EventFirer + EventRestarter, + OF: Feedback, + E::State: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, + H: FnMut(&::Input) -> ExitKind + ?Sized, { #[cfg(unix)] unsafe { let data = &mut GLOBAL_STATE; #[cfg(feature = "std")] - unix_signal_handler::setup_panic_hook::(); + unix_signal_handler::setup_panic_hook::(); setup_signal_handler(data)?; compiler_fence(Ordering::SeqCst); Ok(Self { - crash_handler: unix_signal_handler::inproc_crash_handler:: + crash_handler: unix_signal_handler::inproc_crash_handler:: as *const c_void, - timeout_handler: unix_signal_handler::inproc_timeout_handler:: + timeout_handler: unix_signal_handler::inproc_timeout_handler:: as *const _, }) } @@ -339,29 +363,15 @@ impl InProcessHandlers { unsafe { let data = &mut GLOBAL_STATE; #[cfg(feature = "std")] - windows_exception_handler::setup_panic_hook::(); + windows_exception_handler::setup_panic_hook::(); setup_exception_handler(data)?; compiler_fence(Ordering::SeqCst); Ok(Self { - crash_handler: windows_exception_handler::inproc_crash_handler::< - E, - EM, - I, - OF, - OT, - S, - Z, - > as *const _, - timeout_handler: windows_exception_handler::inproc_timeout_handler::< - E, - EM, - I, - OF, - OT, - S, - Z, - > as *const c_void, + crash_handler: windows_exception_handler::inproc_crash_handler:: + as *const _, + timeout_handler: windows_exception_handler::inproc_timeout_handler:: + as *const c_void, }) } #[cfg(not(any(unix, feature = "std")))] @@ -510,7 +520,7 @@ pub fn inprocess_get_executor<'a, E>() -> Option<&'a mut E> { unsafe { (GLOBAL_STATE.executor_ptr as *mut E).as_mut() } } -/// Gets the inprocess [`Input`] +/// Gets the inprocess input #[must_use] pub fn inprocess_get_input<'a, I>() -> Option<&'a I> { unsafe { (GLOBAL_STATE.current_input_ptr as *const I).as_ref() } @@ -530,6 +540,8 @@ mod unix_signal_handler { use libc::siginfo_t; + #[cfg(feature = "std")] + use crate::inputs::Input; use crate::{ bolts::os::unix_signals::{ucontext_t, Handler, Signal}, corpus::{Corpus, Testcase}, @@ -540,7 +552,7 @@ mod unix_signal_handler { }, feedbacks::Feedback, fuzzer::HasObjective, - inputs::Input, + inputs::UsesInput, observers::ObserversTuple, state::{HasClientPerfMonitor, HasMetadata, HasSolutions}, }; @@ -596,15 +608,13 @@ mod unix_signal_handler { /// invokes the `post_exec` hook on all observer in case of panic #[cfg(feature = "std")] - pub fn setup_panic_hook() + pub fn setup_panic_hook() where - E: HasObservers, - EM: EventFirer + EventRestarter, - OT: ObserversTuple, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - I: Input, - Z: HasObjective, + E: HasObservers, + EM: EventFirer + EventRestarter, + OF: Feedback, + E::State: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { let old_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| { @@ -614,8 +624,8 @@ mod unix_signal_handler { // We are fuzzing! let executor = data.executor_mut::(); let observers = executor.observers_mut(); - let state = data.state_mut::(); - let input = data.current_input::(); + let state = data.state_mut::(); + let input = data.current_input::<::Input>(); let fuzzer = data.fuzzer_mut::(); let event_mgr = data.event_mgr_mut::(); @@ -667,19 +677,17 @@ mod unix_signal_handler { } #[cfg(unix)] - pub(crate) unsafe fn inproc_timeout_handler( + pub(crate) unsafe fn inproc_timeout_handler( _signal: Signal, _info: siginfo_t, _context: &mut ucontext_t, data: &mut InProcessExecutorHandlerData, ) where - E: HasObservers, - EM: EventFirer + EventRestarter, - OT: ObserversTuple, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - I: Input, - Z: HasObjective, + E: HasObservers, + EM: EventFirer + EventRestarter, + OF: Feedback, + E::State: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { if !data.is_valid() { #[cfg(feature = "std")] @@ -689,11 +697,11 @@ mod unix_signal_handler { let executor = data.executor_mut::(); let observers = executor.observers_mut(); - let state = data.state_mut::(); + let state = data.state_mut::(); let fuzzer = data.fuzzer_mut::(); let event_mgr = data.event_mgr_mut::(); - let input = data.take_current_input::(); + let input = data.take_current_input::<::Input>(); #[cfg(feature = "std")] println!("Timeout in fuzz run."); @@ -747,19 +755,17 @@ mod unix_signal_handler { /// Will be used for signal handling. /// It will store the current State to shmem, then exit. #[allow(clippy::too_many_lines)] - pub(crate) unsafe fn inproc_crash_handler( + pub(crate) unsafe fn inproc_crash_handler( signal: Signal, _info: siginfo_t, _context: &mut ucontext_t, data: &mut InProcessExecutorHandlerData, ) where - E: Executor + HasObservers, - EM: EventFirer + EventRestarter, - OT: ObserversTuple, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - I: Input, - Z: HasObjective, + E: Executor + HasObservers, + EM: EventFirer + EventRestarter, + OF: Feedback, + E::State: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { #[cfg(all(target_os = "android", target_arch = "aarch64"))] let _context = &mut *(((_context as *mut _ as *mut libc::c_void as usize) + 128) @@ -772,11 +778,11 @@ mod unix_signal_handler { // disarms timeout in case of TimeoutExecutor executor.post_run_reset(); let observers = executor.observers_mut(); - let state = data.state_mut::(); + let state = data.state_mut::(); let fuzzer = data.fuzzer_mut::(); let event_mgr = data.event_mgr_mut::(); - let input = data.take_current_input::(); + let input = data.take_current_input::<::Input>(); observers .post_exec_all(state, input, &ExitKind::Crash) @@ -898,7 +904,6 @@ mod windows_exception_handler { }, feedbacks::Feedback, fuzzer::HasObjective, - inputs::Input, observers::ObserversTuple, state::{HasClientPerfMonitor, HasMetadata, HasSolutions}, }; @@ -934,17 +939,17 @@ mod windows_exception_handler { EnterCriticalSection, LeaveCriticalSection, RTL_CRITICAL_SECTION, }; + use crate::inputs::UsesInput; + /// invokes the `post_exec` hook on all observer in case of panic #[cfg(feature = "std")] - pub fn setup_panic_hook() + pub fn setup_panic_hook() where - E: HasObservers, - EM: EventFirer + EventRestarter, - OT: ObserversTuple, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - I: Input, - Z: HasObjective, + E: HasObservers, + EM: EventFirer + EventRestarter, + OF: Feedback, + E::State: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { let old_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| { @@ -971,11 +976,11 @@ mod windows_exception_handler { // We are fuzzing! let executor = data.executor_mut::(); let observers = executor.observers_mut(); - let state = data.state_mut::(); + let state = data.state_mut::(); let fuzzer = data.fuzzer_mut::(); let event_mgr = data.event_mgr_mut::(); - let input = data.take_current_input::(); + let input = data.take_current_input::<::Input>(); observers .post_exec_all(state, input, &ExitKind::Crash) @@ -1025,18 +1030,16 @@ mod windows_exception_handler { })); } - pub unsafe extern "system" fn inproc_timeout_handler( + pub unsafe extern "system" fn inproc_timeout_handler( _p0: *mut u8, global_state: *mut c_void, _p1: *mut u8, ) where - E: HasObservers, - EM: EventFirer + EventRestarter, - OT: ObserversTuple, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - I: Input, - Z: HasObjective, + E: HasObservers, + EM: EventFirer + EventRestarter, + OF: Feedback, + E::State: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { let data: &mut InProcessExecutorHandlerData = &mut *(global_state as *mut InProcessExecutorHandlerData); @@ -1050,7 +1053,7 @@ mod windows_exception_handler { if data.in_target == 1 { let executor = data.executor_mut::(); - let state = data.state_mut::(); + let state = data.state_mut::(); let fuzzer = data.fuzzer_mut::(); let event_mgr = data.event_mgr_mut::(); let observers = executor.observers_mut(); @@ -1064,7 +1067,9 @@ mod windows_exception_handler { #[cfg(feature = "std")] let _res = stdout().flush(); - let input = (data.timeout_input_ptr as *const I).as_ref().unwrap(); + let input = (data.timeout_input_ptr as *const ::Input) + .as_ref() + .unwrap(); data.timeout_input_ptr = ptr::null_mut(); observers @@ -1122,17 +1127,15 @@ mod windows_exception_handler { } #[allow(clippy::too_many_lines)] - pub(crate) unsafe fn inproc_crash_handler( + pub(crate) unsafe fn inproc_crash_handler( exception_pointers: *mut EXCEPTION_POINTERS, data: &mut InProcessExecutorHandlerData, ) where - E: Executor + HasObservers, - EM: EventFirer + EventRestarter, - OT: ObserversTuple, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - I: Input, - Z: HasObjective, + E: Executor + HasObservers, + EM: EventFirer + EventRestarter, + OF: Feedback, + E::State: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { // Have we set a timer_before? if !(data.tp_timer as *mut windows::Win32::System::Threading::TP_TIMER).is_null() { @@ -1199,7 +1202,7 @@ mod windows_exception_handler { data.tp_timer = ptr::null_mut(); } - let state = data.state_mut::(); + let state = data.state_mut::(); let fuzzer = data.fuzzer_mut::(); let event_mgr = data.event_mgr_mut::(); let observers = executor.observers_mut(); @@ -1210,7 +1213,7 @@ mod windows_exception_handler { drop(stdout().flush()); // Make sure we don't crash in the crash handler forever. - let input = data.take_current_input::(); + let input = data.take_current_input::<::Input>(); #[cfg(feature = "std")] eprintln!("Child crashed!"); @@ -1297,11 +1300,9 @@ impl InChildProcessHandlers { } /// Create new [`InChildProcessHandlers`]. - pub fn new() -> Result + pub fn new() -> Result where - I: Input, - E: HasObservers, - OT: ObserversTuple, + E: HasObservers, { unsafe { let data = &mut FORK_EXECUTOR_GLOBAL_DATA; @@ -1309,19 +1310,16 @@ impl InChildProcessHandlers { setup_signal_handler(data)?; compiler_fence(Ordering::SeqCst); Ok(Self { - crash_handler: child_signal_handlers::child_crash_handler:: - as *const c_void, + crash_handler: child_signal_handlers::child_crash_handler:: as *const c_void, timeout_handler: ptr::null(), }) } } /// Create new [`InChildProcessHandlers`]. - pub fn with_timeout() -> Result + pub fn with_timeout() -> Result where - I: Input, - E: HasObservers, - OT: ObserversTuple, + E: HasObservers, { unsafe { let data = &mut FORK_EXECUTOR_GLOBAL_DATA; @@ -1329,10 +1327,8 @@ impl InChildProcessHandlers { setup_signal_handler(data)?; compiler_fence(Ordering::SeqCst); Ok(Self { - crash_handler: child_signal_handlers::child_crash_handler:: - as *const c_void, - timeout_handler: child_signal_handlers::child_timeout_handler:: - as *const c_void, + crash_handler: child_signal_handlers::child_crash_handler:: as *const c_void, + timeout_handler: child_signal_handlers::child_timeout_handler:: as *const c_void, }) } } @@ -1442,27 +1438,27 @@ impl Handler for InProcessForkExecutorGlobalData { /// [`InProcessForkExecutor`] is an executor that forks the current process before each execution. #[cfg(all(feature = "std", unix))] -pub struct InProcessForkExecutor<'a, H, I, OT, S, SP> +pub struct InProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, { harness_fn: &'a mut H, shmem_provider: SP, observers: OT, handlers: InChildProcessHandlers, - phantom: PhantomData<(I, S)>, + phantom: PhantomData, } /// Timeout executor for [`InProcessForkExecutor`] #[cfg(all(feature = "std", target_os = "linux"))] -pub struct TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP> +pub struct TimeoutInProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, { harness_fn: &'a mut H, @@ -1470,15 +1466,15 @@ where observers: OT, handlers: InChildProcessHandlers, itimerspec: libc::itimerspec, - phantom: PhantomData<(I, S)>, + phantom: PhantomData, } #[cfg(all(feature = "std", unix))] -impl<'a, H, I, OT, S, SP> Debug for InProcessForkExecutor<'a, H, I, OT, S, SP> +impl<'a, H, OT, S, SP> Debug for InProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -1490,11 +1486,11 @@ where } #[cfg(all(feature = "std", target_os = "linux"))] -impl<'a, H, I, OT, S, SP> Debug for TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP> +impl<'a, H, OT, S, SP> Debug for TimeoutInProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -1507,22 +1503,45 @@ where } #[cfg(all(feature = "std", unix))] -impl<'a, EM, H, I, OT, S, SP, Z> Executor - for InProcessForkExecutor<'a, H, I, OT, S, SP> +impl<'a, H, OT, S, SP> UsesState for InProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: ?Sized + FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, +{ + type State = S; +} + +#[cfg(all(feature = "std", target_os = "linux"))] +impl<'a, H, OT, S, SP> UsesState for TimeoutInProcessForkExecutor<'a, H, OT, S, SP> +where + H: ?Sized + FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + S: UsesInput, + SP: ShMemProvider, +{ + type State = S; +} + +#[cfg(all(feature = "std", unix))] +impl<'a, EM, H, OT, S, SP, Z> Executor for InProcessForkExecutor<'a, H, OT, S, SP> +where + EM: UsesState, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: UsesInput, + SP: ShMemProvider, + Z: UsesState, { #[allow(unreachable_code)] #[inline] fn run_target( &mut self, _fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, _mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { unsafe { self.shmem_provider.pre_fork()?; @@ -1574,22 +1593,23 @@ where } #[cfg(all(feature = "std", target_os = "linux"))] -impl<'a, EM, H, I, OT, S, SP, Z> Executor - for TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP> +impl<'a, EM, H, OT, S, SP, Z> Executor for TimeoutInProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + EM: UsesState, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, + Z: UsesState, { #[allow(unreachable_code)] #[inline] fn run_target( &mut self, _fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, _mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { unsafe { self.shmem_provider.pre_fork()?; @@ -1661,11 +1681,11 @@ where } #[cfg(all(feature = "std", unix))] -impl<'a, H, I, OT, S, SP> InProcessForkExecutor<'a, H, I, OT, S, SP> +impl<'a, H, OT, S, SP> InProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + OT: ObserversTuple, + S: UsesInput, SP: ShMemProvider, { /// Creates a new [`InProcessForkExecutor`] @@ -1678,12 +1698,12 @@ where shmem_provider: SP, ) -> Result where - EM: EventFirer + EventRestarter, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + EM: EventFirer + EventRestarter, + OF: Feedback, + S: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { - let handlers = InChildProcessHandlers::new::()?; + let handlers = InChildProcessHandlers::new::()?; Ok(Self { harness_fn, shmem_provider, @@ -1707,11 +1727,11 @@ where } #[cfg(all(feature = "std", target_os = "linux"))] -impl<'a, H, I, OT, S, SP> TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP> +impl<'a, H, OT, S, SP> TimeoutInProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + S: UsesInput, + OT: ObserversTuple, SP: ShMemProvider, { /// Creates a new [`TimeoutInProcessForkExecutor`] @@ -1725,12 +1745,12 @@ where shmem_provider: SP, ) -> Result where - EM: EventFirer + EventRestarter, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + EM: EventFirer + EventRestarter, + OF: Feedback, + S: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { - let handlers = InChildProcessHandlers::with_timeout::()?; + let handlers = InChildProcessHandlers::with_timeout::()?; let milli_sec = timeout.as_millis(); let it_value = libc::timespec { tv_sec: (milli_sec / 1000) as _, @@ -1769,11 +1789,33 @@ where } #[cfg(all(feature = "std", unix))] -impl<'a, H, I, OT, S, SP> HasObservers for InProcessForkExecutor<'a, H, I, OT, S, SP> +impl<'a, H, OT, S, SP> UsesObservers for InProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: ?Sized + FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + S: UsesInput, + SP: ShMemProvider, +{ + type Observers = OT; +} + +#[cfg(all(feature = "std", target_os = "linux"))] +impl<'a, H, OT, S, SP> UsesObservers for TimeoutInProcessForkExecutor<'a, H, OT, S, SP> +where + H: ?Sized + FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + S: UsesInput, + SP: ShMemProvider, +{ + type Observers = OT; +} + +#[cfg(all(feature = "std", unix))] +impl<'a, H, OT, S, SP> HasObservers for InProcessForkExecutor<'a, H, OT, S, SP> +where + H: FnMut(&S::Input) -> ExitKind + ?Sized, + S: UsesInput, + OT: ObserversTuple, SP: ShMemProvider, { #[inline] @@ -1788,12 +1830,11 @@ where } #[cfg(all(feature = "std", target_os = "linux"))] -impl<'a, H, I, OT, S, SP> HasObservers - for TimeoutInProcessForkExecutor<'a, H, I, OT, S, SP> +impl<'a, H, OT, S, SP> HasObservers for TimeoutInProcessForkExecutor<'a, H, OT, S, SP> where - H: FnMut(&I) -> ExitKind + ?Sized, - I: Input, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind + ?Sized, + S: UsesInput, + OT: ObserversTuple, SP: ShMemProvider, { #[inline] @@ -1819,16 +1860,14 @@ pub mod child_signal_handlers { use crate::{ bolts::os::unix_signals::{ucontext_t, Signal}, executors::{ExitKind, HasObservers}, - inputs::Input, + inputs::UsesInput, observers::ObserversTuple, }; /// invokes the `post_exec_child` hook on all observer in case the child process panics - pub fn setup_child_panic_hook() + pub fn setup_child_panic_hook() where - E: HasObservers, - OT: ObserversTuple, - I: Input, + E: HasObservers, { let old_hook = panic::take_hook(); panic::set_hook(Box::new(move |panic_info| { @@ -1837,9 +1876,9 @@ pub mod child_signal_handlers { if data.is_valid() { let executor = data.executor_mut::(); let observers = executor.observers_mut(); - let state = data.state_mut::(); + let state = data.state_mut::(); // Invalidate data to not execute again the observer hooks in the crash handler - let input = data.take_current_input::(); + let input = data.take_current_input::<::Input>(); observers .post_exec_child_all(state, input, &ExitKind::Crash) .expect("Failed to run post_exec on observers"); @@ -1856,21 +1895,19 @@ pub mod child_signal_handlers { /// The function should only be called from a child crash handler. /// It will dereference the `data` pointer and assume it's valid. #[cfg(unix)] - pub(crate) unsafe fn child_crash_handler( + pub(crate) unsafe fn child_crash_handler( _signal: Signal, _info: siginfo_t, _context: &mut ucontext_t, data: &mut InProcessForkExecutorGlobalData, ) where - E: HasObservers, - OT: ObserversTuple, - I: Input, + E: HasObservers, { if data.is_valid() { let executor = data.executor_mut::(); let observers = executor.observers_mut(); - let state = data.state_mut::(); - let input = data.take_current_input::(); + let state = data.state_mut::(); + let input = data.take_current_input::<::Input>(); observers .post_exec_child_all(state, input, &ExitKind::Crash) .expect("Failed to run post_exec on observers"); @@ -1880,21 +1917,19 @@ pub mod child_signal_handlers { } #[cfg(unix)] - pub(crate) unsafe fn child_timeout_handler( + pub(crate) unsafe fn child_timeout_handler( _signal: Signal, _info: siginfo_t, _context: &mut ucontext_t, data: &mut InProcessForkExecutorGlobalData, ) where - E: HasObservers, - OT: ObserversTuple, - I: Input, + E: HasObservers, { if data.is_valid() { let executor = data.executor_mut::(); let observers = executor.observers_mut(); - let state = data.state_mut::(); - let input = data.take_current_input::(); + let state = data.state_mut::(); + let input = data.take_current_input::<::Input>(); observers .post_exec_child_all(state, input, &ExitKind::Timeout) .expect("Failed to run post_exec on observers"); @@ -1910,22 +1945,24 @@ mod tests { #[cfg(all(feature = "std", feature = "fork", unix))] use serial_test::serial; - #[cfg(all(feature = "std", feature = "fork", unix))] - use crate::{ - bolts::shmem::{ShMemProvider, StdShMemProvider}, - executors::InProcessForkExecutor, - }; use crate::{ bolts::tuples::tuple_list, + events::NopEventManager, executors::{inprocess::InProcessHandlers, Executor, ExitKind, InProcessExecutor}, - inputs::NopInput, + inputs::{NopInput, UsesInput}, + state::NopState, + NopFuzzer, }; + impl UsesInput for () { + type Input = NopInput; + } + #[test] fn test_inmem_exec() { let mut harness = |_buf: &NopInput| ExitKind::Ok; - let mut in_process_executor = InProcessExecutor::<_, NopInput, (), ()> { + let mut in_process_executor = InProcessExecutor::<_, _, _> { harness_fn: &mut harness, observers: tuple_list!(), handlers: InProcessHandlers::nop(), @@ -1933,7 +1970,12 @@ mod tests { }; let input = NopInput {}; in_process_executor - .run_target(&mut (), &mut (), &mut (), &input) + .run_target( + &mut NopFuzzer::new(), + &mut NopState::new(), + &mut NopEventManager::new(), + &input, + ) .unwrap(); } @@ -1941,12 +1983,18 @@ mod tests { #[serial] #[cfg(all(feature = "std", feature = "fork", unix))] fn test_inprocessfork_exec() { - use crate::executors::inprocess::InChildProcessHandlers; + use crate::{ + bolts::shmem::{ShMemProvider, StdShMemProvider}, + events::SimpleEventManager, + executors::{inprocess::InChildProcessHandlers, InProcessForkExecutor}, + state::NopState, + NopFuzzer, + }; let provider = StdShMemProvider::new().unwrap(); let mut harness = |_buf: &NopInput| ExitKind::Ok; - let mut in_process_fork_executor = InProcessForkExecutor::<_, NopInput, (), (), _> { + let mut in_process_fork_executor = InProcessForkExecutor::<_, (), _, _> { harness_fn: &mut harness, shmem_provider: provider, observers: tuple_list!(), @@ -1954,8 +2002,11 @@ mod tests { phantom: PhantomData, }; let input = NopInput {}; + let mut fuzzer = NopFuzzer::new(); + let mut state = NopState::new(); + let mut mgr = SimpleEventManager::printing(); in_process_fork_executor - .run_target(&mut (), &mut (), &mut (), &input) + .run_target(&mut fuzzer, &mut state, &mut mgr, &input) .unwrap(); } } @@ -1982,7 +2033,7 @@ pub mod pybind { /// Python class for OwnedInProcessExecutor (i.e. InProcessExecutor with owned harness) pub struct PythonOwnedInProcessExecutor { /// Rust wrapped OwnedInProcessExecutor object - pub inner: OwnedInProcessExecutor, + pub inner: OwnedInProcessExecutor, } #[pymethods] diff --git a/libafl/src/executors/mod.rs b/libafl/src/executors/mod.rs index dd151fb37c..bf4e5e44b4 100644 --- a/libafl/src/executors/mod.rs +++ b/libafl/src/executors/mod.rs @@ -31,7 +31,7 @@ pub use with_observers::WithObservers; #[cfg(all(feature = "std", any(unix, doc)))] pub mod command; -use core::fmt::Debug; +use core::{fmt::Debug, marker::PhantomData}; #[cfg(all(feature = "std", any(unix, doc)))] pub use command::CommandExecutor; @@ -39,8 +39,9 @@ use serde::{Deserialize, Serialize}; use crate::{ bolts::AsSlice, - inputs::{HasTargetBytes, Input}, - observers::ObserversTuple, + inputs::{HasTargetBytes, UsesInput}, + observers::{ObserversTuple, UsesObservers}, + state::UsesState, Error, }; @@ -100,29 +101,27 @@ impl From for DiffExitKind { crate::impl_serdeany!(DiffExitKind); /// Holds a tuple of Observers -pub trait HasObservers: Debug -where - OT: ObserversTuple, -{ +pub trait HasObservers: UsesObservers { /// Get the linked observers - fn observers(&self) -> &OT; + fn observers(&self) -> &Self::Observers; /// Get the linked observers (mutable) - fn observers_mut(&mut self) -> &mut OT; + fn observers_mut(&mut self) -> &mut Self::Observers; } /// An executor takes the given inputs, and runs the harness/target. -pub trait Executor: Debug +pub trait Executor: UsesState + Debug where - I: Input, + EM: UsesState, + Z: UsesState, { /// Instruct the target about the input and run fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result; /// Wraps this Executor with the given [`ObserversTuple`] to implement [`HasObservers`]. @@ -132,7 +131,7 @@ where fn with_observers(self, observers: OT) -> WithObservers where Self: Sized, - OT: ObserversTuple, + OT: ObserversTuple, { WithObservers::new(self, observers) } @@ -145,18 +144,30 @@ where /// A simple executor that does nothing. /// If intput len is 0, `run_target` will return Err #[derive(Debug)] -struct NopExecutor {} +struct NopExecutor { + phantom: PhantomData, +} -impl Executor for NopExecutor +impl UsesState for NopExecutor where - I: Input + HasTargetBytes, + S: UsesInput, +{ + type State = S; +} + +impl Executor for NopExecutor +where + EM: UsesState, + S: UsesInput + Debug, + S::Input: HasTargetBytes, + Z: UsesState, { fn run_target( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut Self::State, _mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { if input.target_bytes().as_slice().is_empty() { Err(Error::empty("Input Empty")) @@ -168,19 +179,37 @@ where #[cfg(test)] mod test { + use core::marker::PhantomData; + use super::{Executor, NopExecutor}; - use crate::inputs::BytesInput; + use crate::{events::NopEventManager, inputs::BytesInput, state::NopState, NopFuzzer}; #[test] fn nop_executor() { let empty_input = BytesInput::new(vec![]); let nonempty_input = BytesInput::new(vec![1u8]); - let mut executor = NopExecutor {}; + let mut executor = NopExecutor { + phantom: PhantomData, + }; + let mut fuzzer = NopFuzzer::new(); + + let mut state = NopState::new(); + executor - .run_target(&mut (), &mut (), &mut (), &empty_input) + .run_target( + &mut fuzzer, + &mut state, + &mut NopEventManager::new(), + &empty_input, + ) .unwrap_err(); executor - .run_target(&mut (), &mut (), &mut (), &nonempty_input) + .run_target( + &mut fuzzer, + &mut state, + &mut NopEventManager::new(), + &nonempty_input, + ) .unwrap(); } } @@ -198,9 +227,12 @@ pub mod pybind { inprocess::pybind::PythonOwnedInProcessExecutor, Executor, ExitKind, HasObservers, }, fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper}, - inputs::{BytesInput, HasBytesVec}, - observers::pybind::PythonObserversTuple, - state::pybind::{PythonStdState, PythonStdStateWrapper}, + inputs::HasBytesVec, + observers::{pybind::PythonObserversTuple, UsesObservers}, + state::{ + pybind::{PythonStdState, PythonStdStateWrapper}, + UsesState, + }, Error, }; @@ -293,7 +325,15 @@ pub mod pybind { } } - impl HasObservers for PyObjectExecutor { + impl UsesState for PyObjectExecutor { + type State = PythonStdState; + } + + impl UsesObservers for PyObjectExecutor { + type Observers = PythonObserversTuple; + } + + impl HasObservers for PyObjectExecutor { #[inline] fn observers(&self) -> &PythonObserversTuple { &self.tuple @@ -305,16 +345,14 @@ pub mod pybind { } } - impl Executor - for PyObjectExecutor - { + impl Executor for PyObjectExecutor { #[inline] fn run_target( &mut self, fuzzer: &mut PythonStdFuzzer, - state: &mut PythonStdState, + state: &mut Self::State, mgr: &mut PythonEventManager, - input: &BytesInput, + input: &Self::Input, ) -> Result { let ek = Python::with_gil(|py| -> PyResult<_> { let ek: PythonExitKind = self @@ -344,7 +382,7 @@ pub mod pybind { #[pyclass(unsendable, name = "Executor")] #[derive(Clone, Debug)] - /// Executor + HasObservers Trait binding + /// Executor + HasObservers Trait binding pub struct PythonExecutor { wrapper: PythonExecutorWrapper, } @@ -404,7 +442,15 @@ pub mod pybind { } } - impl HasObservers for PythonExecutor { + impl UsesState for PythonExecutor { + type State = PythonStdState; + } + + impl UsesObservers for PythonExecutor { + type Observers = PythonObserversTuple; + } + + impl HasObservers for PythonExecutor { #[inline] fn observers(&self) -> &PythonObserversTuple { let ptr = unwrap_me!(self.wrapper, e, { @@ -422,14 +468,14 @@ pub mod pybind { } } - impl Executor for PythonExecutor { + impl Executor for PythonExecutor { #[inline] fn run_target( &mut self, fuzzer: &mut PythonStdFuzzer, - state: &mut PythonStdState, + state: &mut Self::State, mgr: &mut PythonEventManager, - input: &BytesInput, + input: &Self::Input, ) -> Result { unwrap_me_mut!(self.wrapper, e, { e.run_target(fuzzer, state, mgr, input) }) } diff --git a/libafl/src/executors/shadow.rs b/libafl/src/executors/shadow.rs index fcff96d608..bf749268c7 100644 --- a/libafl/src/executors/shadow.rs +++ b/libafl/src/executors/shadow.rs @@ -1,28 +1,27 @@ //! A `ShadowExecutor` wraps an executor to have shadow observer that will not be considered by the feedbacks and the manager -use core::{ - fmt::{self, Debug, Formatter}, - marker::PhantomData, -}; +use core::fmt::{self, Debug, Formatter}; use crate::{ executors::{Executor, ExitKind, HasObservers}, - inputs::Input, - observers::ObserversTuple, + observers::{ObserversTuple, UsesObservers}, + state::UsesState, Error, }; /// A [`ShadowExecutor`] wraps an executor and a set of shadow observers -pub struct ShadowExecutor { +pub struct ShadowExecutor { /// The wrapped executor executor: E, /// The shadow observers shadow_observers: SOT, - /// phantom data - phantom: PhantomData<(I, S)>, } -impl Debug for ShadowExecutor { +impl Debug for ShadowExecutor +where + E: UsesState + Debug, + SOT: ObserversTuple + Debug, +{ fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("ShadowExecutor") .field("executor", &self.executor) @@ -31,16 +30,16 @@ impl Debug for ShadowExecutor { } } -impl ShadowExecutor +impl ShadowExecutor where - SOT: ObserversTuple, + E: HasObservers + Debug, + SOT: ObserversTuple + Debug, { /// Create a new `ShadowExecutor`, wrapping the given `executor`. pub fn new(executor: E, shadow_observers: SOT) -> Self { Self { executor, shadow_observers, - phantom: PhantomData, } } @@ -57,38 +56,50 @@ where } } -impl Executor for ShadowExecutor +impl Executor for ShadowExecutor where - E: Executor, - I: Input, - SOT: ObserversTuple, + E: Executor + HasObservers, + SOT: ObserversTuple, + EM: UsesState, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { self.executor.run_target(fuzzer, state, mgr, input) } } -impl HasObservers for ShadowExecutor +impl UsesState for ShadowExecutor where - I: Debug, - S: Debug, - E: HasObservers, - OT: ObserversTuple, - SOT: ObserversTuple, + E: UsesState, +{ + type State = E::State; +} + +impl UsesObservers for ShadowExecutor +where + E: UsesObservers, +{ + type Observers = E::Observers; +} + +impl HasObservers for ShadowExecutor +where + E: HasObservers, + SOT: ObserversTuple, { #[inline] - fn observers(&self) -> &OT { + fn observers(&self) -> &Self::Observers { self.executor.observers() } #[inline] - fn observers_mut(&mut self) -> &mut OT { + fn observers_mut(&mut self) -> &mut Self::Observers { self.executor.observers_mut() } } diff --git a/libafl/src/executors/timeout.rs b/libafl/src/executors/timeout.rs index 2d48439e9f..4ba73df54b 100644 --- a/libafl/src/executors/timeout.rs +++ b/libafl/src/executors/timeout.rs @@ -33,8 +33,8 @@ use windows::Win32::{ use crate::executors::inprocess::{HasInProcessHandlers, GLOBAL_STATE}; use crate::{ executors::{Executor, ExitKind, HasObservers}, - inputs::Input, - observers::ObserversTuple, + observers::UsesObservers, + state::UsesState, Error, }; @@ -77,6 +77,7 @@ const ITIMER_REAL: c_int = 0; /// The timeout executor is a wrapper that sets a timeout before each run pub struct TimeoutExecutor { + /// The wrapped [`Executor`] executor: E, #[cfg(target_os = "linux")] itimerspec: libc::itimerspec, @@ -263,18 +264,19 @@ impl TimeoutExecutor { } #[cfg(windows)] -impl Executor for TimeoutExecutor +impl Executor for TimeoutExecutor where - E: Executor + HasInProcessHandlers, - I: Input, + E: Executor + HasInProcessHandlers, + EM: UsesState, + Z: UsesState, { #[allow(clippy::cast_sign_loss)] fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { unsafe { let data = &mut GLOBAL_STATE; @@ -333,17 +335,18 @@ where } #[cfg(target_os = "linux")] -impl Executor for TimeoutExecutor +impl Executor for TimeoutExecutor where - E: Executor, - I: Input, + E: Executor, + EM: UsesState, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { unsafe { libc::timer_settime(self.timerid, 0, addr_of_mut!(self.itimerspec), null_mut()); @@ -364,17 +367,18 @@ where } #[cfg(all(unix, not(target_os = "linux")))] -impl Executor for TimeoutExecutor +impl Executor for TimeoutExecutor where - E: Executor, - I: Input, + E: Executor, + EM: UsesState, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { unsafe { setitimer(ITIMER_REAL, &mut self.itimerval, null_mut()); @@ -393,18 +397,31 @@ where } } -impl HasObservers for TimeoutExecutor +impl UsesState for TimeoutExecutor where - E: HasObservers, - OT: ObserversTuple, + E: UsesState, +{ + type State = E::State; +} + +impl UsesObservers for TimeoutExecutor +where + E: UsesObservers, +{ + type Observers = E::Observers; +} + +impl HasObservers for TimeoutExecutor +where + E: HasObservers, { #[inline] - fn observers(&self) -> &OT { + fn observers(&self) -> &Self::Observers { self.executor.observers() } #[inline] - fn observers_mut(&mut self) -> &mut OT { + fn observers_mut(&mut self) -> &mut Self::Observers { self.executor.observers_mut() } } diff --git a/libafl/src/executors/with_observers.rs b/libafl/src/executors/with_observers.rs index da4b95f847..e36e8e8130 100644 --- a/libafl/src/executors/with_observers.rs +++ b/libafl/src/executors/with_observers.rs @@ -4,39 +4,55 @@ use core::fmt::Debug; use crate::{ executors::{Executor, ExitKind, HasObservers}, - inputs::Input, - observers::ObserversTuple, + observers::{ObserversTuple, UsesObservers}, + state::UsesState, Error, }; /// A wrapper for any [`Executor`] to make it implement [`HasObservers`] using a given [`ObserversTuple`]. #[derive(Debug)] -pub struct WithObservers { +pub struct WithObservers { executor: E, observers: OT, } -impl Executor for WithObservers +impl Executor for WithObservers where - I: Input, - E: Executor, + E: Executor + Debug, OT: Debug, + EM: UsesState, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { self.executor.run_target(fuzzer, state, mgr, input) } } -impl HasObservers for WithObservers +impl UsesState for WithObservers where - I: Input, - OT: ObserversTuple, + E: UsesState, +{ + type State = E::State; +} + +impl UsesObservers for WithObservers +where + E: UsesState, + OT: ObserversTuple, +{ + type Observers = OT; +} + +impl HasObservers for WithObservers +where + E: HasObservers + Debug, + OT: ObserversTuple + Debug, { fn observers(&self) -> &OT { &self.observers diff --git a/libafl/src/feedbacks/concolic.rs b/libafl/src/feedbacks/concolic.rs index 967756c48b..4e0d0f182f 100644 --- a/libafl/src/feedbacks/concolic.rs +++ b/libafl/src/feedbacks/concolic.rs @@ -4,6 +4,7 @@ //! to be not interesting. //! Requires a [`ConcolicObserver`] to observe the concolic trace. use alloc::{borrow::ToOwned, string::String}; +use core::{fmt::Debug, marker::PhantomData}; use crate::{ bolts::tuples::Named, @@ -11,7 +12,7 @@ use crate::{ events::EventFirer, executors::ExitKind, feedbacks::Feedback, - inputs::Input, + inputs::UsesInput, observers::{ concolic::{ConcolicMetadata, ConcolicObserver}, ObserversTuple, @@ -25,12 +26,13 @@ use crate::{ /// to be not interesting. /// Requires a [`ConcolicObserver`] to observe the concolic trace. #[derive(Debug)] -pub struct ConcolicFeedback { +pub struct ConcolicFeedback { name: String, metadata: Option, + phantom: PhantomData, } -impl ConcolicFeedback { +impl ConcolicFeedback { /// Creates a concolic feedback from an observer #[allow(unused)] #[must_use] @@ -38,33 +40,33 @@ impl ConcolicFeedback { Self { name: observer.name().to_owned(), metadata: None, + phantom: PhantomData, } } } -impl Named for ConcolicFeedback { +impl Named for ConcolicFeedback { fn name(&self) -> &str { &self.name } } -impl Feedback for ConcolicFeedback +impl Feedback for ConcolicFeedback where - I: Input, - S: HasClientPerfMonitor, + S: UsesInput + Debug + HasClientPerfMonitor, { #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { self.metadata = observers .match_name::(&self.name) @@ -75,7 +77,7 @@ where fn append_metadata( &mut self, _state: &mut S, - _testcase: &mut Testcase, + _testcase: &mut Testcase<::Input>, ) -> Result<(), Error> { if let Some(metadata) = self.metadata.take() { _testcase.metadata_mut().insert(metadata); @@ -83,7 +85,11 @@ where Ok(()) } - fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn discard_metadata( + &mut self, + _state: &mut S, + _input: &::Input, + ) -> Result<(), Error> { Ok(()) } } diff --git a/libafl/src/feedbacks/differential.rs b/libafl/src/feedbacks/differential.rs index fc674493c7..36b2d0dd94 100644 --- a/libafl/src/feedbacks/differential.rs +++ b/libafl/src/feedbacks/differential.rs @@ -16,7 +16,7 @@ use crate::{ feedbacks::Feedback, inputs::Input, observers::{Observer, ObserversTuple}, - state::{HasClientPerfMonitor, HasMetadata}, + state::{HasClientPerfMonitor, HasMetadata, State}, Error, }; @@ -48,7 +48,7 @@ impl DiffResult { /// A [`DiffFeedback`] compares the content of two [`Observer`]s using the given compare function. #[derive(Serialize, Deserialize)] -pub struct DiffFeedback +pub struct DiffFeedback where F: FnMut(&O1, &O2) -> DiffResult, { @@ -60,10 +60,10 @@ where o2_name: String, /// The function used to compare the two observers compare_fn: F, - phantomm: PhantomData<(O1, O2)>, + phantomm: PhantomData<(O1, O2, I, S)>, } -impl DiffFeedback +impl DiffFeedback where F: FnMut(&O1, &O2) -> DiffResult, O1: Named, @@ -90,7 +90,7 @@ where } } -impl Named for DiffFeedback +impl Named for DiffFeedback where F: FnMut(&O1, &O2) -> DiffResult, O1: Named, @@ -101,7 +101,7 @@ where } } -impl Debug for DiffFeedback +impl Debug for DiffFeedback where F: FnMut(&O1, &O2) -> DiffResult, O1: Named, @@ -116,13 +116,13 @@ where } } -impl Feedback for DiffFeedback +impl Feedback for DiffFeedback where F: FnMut(&O1, &O2) -> DiffResult, I: Input, - S: HasMetadata + HasClientPerfMonitor, - O1: Observer + PartialEq, - O2: Observer, + S: HasMetadata + HasClientPerfMonitor + State, + O1: Observer + PartialEq, + O2: Observer, { #[allow(clippy::wrong_self_convention)] fn is_interesting( @@ -134,8 +134,8 @@ where _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple + MatchName, + EM: EventFirer, + OT: ObserversTuple + MatchName, { fn err(name: &str) -> Error { Error::illegal_argument(format!("DiffFeedback: observer {name} not found")) @@ -154,19 +154,16 @@ where #[cfg(test)] mod tests { use alloc::string::{String, ToString}; + use core::marker::PhantomData; use crate::{ - bolts::{ - serdeany::SerdeAnyMap, - tuples::{tuple_list, Named}, - }, + bolts::tuples::{tuple_list, Named}, events::EventFirer, executors::ExitKind, feedbacks::{differential::DiffResult, DiffFeedback, Feedback}, - inputs::{BytesInput, Input}, - monitors::ClientPerfMonitor, + inputs::{BytesInput, UsesInput}, observers::Observer, - state::{HasClientPerfMonitor, HasMetadata}, + state::{NopState, UsesState}, }; #[derive(Debug)] @@ -182,7 +179,7 @@ mod tests { } } } - impl Observer for NopObserver {} + impl Observer for NopObserver where S: UsesInput {} impl PartialEq for NopObserver { fn eq(&self, other: &Self) -> bool { self.value == other.value @@ -194,39 +191,30 @@ mod tests { } } - struct NopEventFirer; - impl EventFirer for NopEventFirer { - fn fire( + struct NopEventFirer { + phantom: PhantomData, + } + impl UsesState for NopEventFirer + where + S: UsesInput, + { + type State = S; + } + impl EventFirer for NopEventFirer + where + S: UsesInput, + { + fn fire( &mut self, _state: &mut S, - _event: crate::events::Event, + _event: crate::events::Event, ) -> Result<(), crate::Error> { Ok(()) } } - struct NopState; - impl HasMetadata for NopState { - fn metadata(&self) -> &SerdeAnyMap { - unimplemented!() - } - - fn metadata_mut(&mut self) -> &mut SerdeAnyMap { - unimplemented!() - } - } - impl HasClientPerfMonitor for NopState { - fn introspection_monitor(&self) -> &ClientPerfMonitor { - unimplemented!() - } - - fn introspection_monitor_mut(&mut self) -> &mut ClientPerfMonitor { - unimplemented!() - } - } - fn test_diff(should_equal: bool) { - let mut nop_state = NopState; + let mut nop_state = NopState::new(); let o1 = NopObserver::new("o1", true); let o2 = NopObserver::new("o2", should_equal); @@ -245,7 +233,9 @@ mod tests { diff_feedback .is_interesting( &mut nop_state, - &mut NopEventFirer {}, + &mut NopEventFirer { + phantom: PhantomData + }, &BytesInput::new(vec![0]), &observers, &ExitKind::Ok diff --git a/libafl/src/feedbacks/map.rs b/libafl/src/feedbacks/map.rs index 9458003ed3..a2dd29f57c 100644 --- a/libafl/src/feedbacks/map.rs +++ b/libafl/src/feedbacks/map.rs @@ -21,7 +21,7 @@ use crate::{ events::{Event, EventFirer}, executors::ExitKind, feedbacks::{Feedback, HasObserverName}, - inputs::Input, + inputs::UsesInput, monitors::UserStats, observers::{MapObserver, ObserversTuple}, state::{HasClientPerfMonitor, HasMetadata, HasNamedMetadata}, @@ -32,20 +32,19 @@ use crate::{ pub const MAPFEEDBACK_PREFIX: &str = "mapfeedback_metadata_"; /// A [`MapFeedback`] that implements the AFL algorithm using an [`OrReducer`] combining the bits for the history map and the bit from ``HitcountsMapObserver``. -pub type AflMapFeedback = MapFeedback; +pub type AflMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents. -pub type MaxMapFeedback = MapFeedback; +pub type MaxMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to minimize the map contents. -pub type MinMapFeedback = MapFeedback; +pub type MinMapFeedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents, /// but only, if a value is larger than `pow2` of the previous. -pub type MaxMapPow2Feedback = MapFeedback; +pub type MaxMapPow2Feedback = MapFeedback; /// A [`MapFeedback`] that strives to maximize the map contents, /// but only, if a value is larger than `pow2` of the previous. -pub type MaxMapOneOrFilledFeedback = - MapFeedback; +pub type MaxMapOneOrFilledFeedback = MapFeedback; /// A `Reducer` function is used to aggregate values for the novelty search pub trait Reducer: 'static + Debug @@ -333,15 +332,7 @@ where /// The most common AFL-like feedback type #[derive(Clone, Debug)] -pub struct MapFeedback -where - T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, - R: Reducer, - O: MapObserver, - for<'it> O: AsIter<'it, Item = T>, - N: IsNovel, - S: HasNamedMetadata, -{ +pub struct MapFeedback { /// Indexes used in the last observation indexes: Option>, /// New indexes observed in the last observation @@ -353,18 +344,16 @@ where /// Name of the feedback as shown in the `UserStats` stats_name: String, /// Phantom Data of Reducer - phantom: PhantomData<(I, N, S, R, O, T)>, + phantom: PhantomData<(N, O, R, S, T)>, } -impl Feedback for MapFeedback +impl Feedback for MapFeedback where - T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, - R: Reducer, - O: MapObserver, - for<'it> O: AsIter<'it, Item = T>, - N: IsNovel, - I: Input, - S: HasNamedMetadata + HasClientPerfMonitor + Debug, + N: IsNovel + Debug, + O: MapObserver + for<'it> AsIter<'it, Item = T> + Debug, + R: Reducer + Debug, + S: UsesInput + HasClientPerfMonitor + HasNamedMetadata + Debug, + T: Default + Copy + Serialize + for<'de> Deserialize<'de> + PartialEq + Debug + 'static, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { // Initialize `MapFeedbackMetadata` with an empty vector and add it to the state. @@ -378,13 +367,13 @@ where &mut self, state: &mut S, manager: &mut EM, - input: &I, + input: &::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { self.is_interesting_default(state, manager, input, observers, exit_kind) } @@ -394,18 +383,22 @@ where &mut self, state: &mut S, manager: &mut EM, - input: &I, + input: &::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { self.is_interesting_default(state, manager, input, observers, exit_kind) } - fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase) -> Result<(), Error> { + fn append_metadata( + &mut self, + _state: &mut S, + testcase: &mut Testcase<::Input>, + ) -> Result<(), Error> { if let Some(v) = self.indexes.as_mut() { let meta = MapIndexesMetadata::new(core::mem::take(v)); testcase.add_metadata(meta); @@ -418,7 +411,11 @@ where } /// Discard the stored metadata in case that the testcase is not added to the corpus - fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn discard_metadata( + &mut self, + _state: &mut S, + _input: &::Input, + ) -> Result<(), Error> { if let Some(v) = self.indexes.as_mut() { v.clear(); } @@ -431,12 +428,11 @@ where /// Specialize for the common coverage map size, maximization of u8s #[rustversion::nightly] -impl Feedback for MapFeedback +impl Feedback for MapFeedback where O: MapObserver + AsSlice, for<'it> O: AsIter<'it, Item = u8>, - I: Input, - S: HasNamedMetadata + HasClientPerfMonitor + Debug, + S: UsesInput + HasNamedMetadata + HasClientPerfMonitor + Debug, { #[allow(clippy::wrong_self_convention)] #[allow(clippy::needless_range_loop)] @@ -444,13 +440,13 @@ where &mut self, state: &mut S, manager: &mut EM, - _input: &I, + _input: &::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // 128 bits vectors type VectorType = core::simd::u8x16; @@ -550,22 +546,14 @@ where } } -impl Named for MapFeedback -where - T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, - R: Reducer, - N: IsNovel, - O: MapObserver, - for<'it> O: AsIter<'it, Item = T>, - S: HasNamedMetadata, -{ +impl Named for MapFeedback { #[inline] fn name(&self) -> &str { self.name.as_str() } } -impl HasObserverName for MapFeedback +impl HasObserverName for MapFeedback where T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, R: Reducer, @@ -584,15 +572,14 @@ fn create_stats_name(name: &str) -> String { name.to_lowercase() } -impl MapFeedback +impl MapFeedback where T: PartialEq + Default + Copy + 'static + Serialize + DeserializeOwned + Debug, R: Reducer, O: MapObserver, for<'it> O: AsIter<'it, Item = T>, N: IsNovel, - I: Input, - S: HasNamedMetadata + HasClientPerfMonitor + Debug, + S: UsesInput + HasNamedMetadata + HasClientPerfMonitor + Debug, { /// Create new `MapFeedback` #[must_use] @@ -673,13 +660,13 @@ where &mut self, state: &mut S, manager: &mut EM, - _input: &I, + _input: &S::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { let mut interesting = false; // TODO Replace with match_name_type when stable @@ -735,13 +722,13 @@ where /// A [`ReachabilityFeedback`] reports if a target has been reached. #[derive(Clone, Debug)] -pub struct ReachabilityFeedback { +pub struct ReachabilityFeedback { name: String, target_idx: Vec, - phantom: PhantomData, + phantom: PhantomData<(O, S)>, } -impl ReachabilityFeedback +impl ReachabilityFeedback where O: MapObserver, for<'it> O: AsIter<'it, Item = usize>, @@ -767,25 +754,24 @@ where } } -impl Feedback for ReachabilityFeedback +impl Feedback for ReachabilityFeedback where - I: Input, + S: UsesInput + Debug + HasClientPerfMonitor, O: MapObserver, for<'it> O: AsIter<'it, Item = usize>, - S: HasClientPerfMonitor, { #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // TODO Replace with match_name_type when stable let observer = observers.match_name::(&self.name).unwrap(); @@ -804,7 +790,11 @@ where } } - fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase) -> Result<(), Error> { + fn append_metadata( + &mut self, + _state: &mut S, + testcase: &mut Testcase<::Input>, + ) -> Result<(), Error> { if !self.target_idx.is_empty() { let meta = MapIndexesMetadata::new(core::mem::take(self.target_idx.as_mut())); testcase.add_metadata(meta); @@ -812,13 +802,17 @@ where Ok(()) } - fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn discard_metadata( + &mut self, + _state: &mut S, + _input: &::Input, + ) -> Result<(), Error> { self.target_idx.clear(); Ok(()) } } -impl Named for ReachabilityFeedback +impl Named for ReachabilityFeedback where O: MapObserver, for<'it> O: AsIter<'it, Item = usize>, @@ -862,9 +856,7 @@ pub mod pybind { use pyo3::prelude::*; use super::{Debug, HasObserverName, MaxMapFeedback}; - use crate::{ - feedbacks::pybind::PythonFeedback, inputs::BytesInput, state::pybind::PythonStdState, - }; + use crate::{feedbacks::pybind::PythonFeedback, state::pybind::PythonStdState}; macro_rules! define_python_map_feedback { ($struct_name:ident, $py_name:tt, $datatype:ty, $map_observer_type_name: ident, $my_std_state_type_name: ident) => { @@ -876,7 +868,6 @@ pub mod pybind { pub struct $struct_name { /// Rust wrapped MaxMapFeedback object pub inner: MaxMapFeedback< - BytesInput, $map_observer_type_name, /* PythonMapObserverI8 */ $my_std_state_type_name, $datatype, diff --git a/libafl/src/feedbacks/mod.rs b/libafl/src/feedbacks/mod.rs index 66b4dfc6e8..60e646747e 100644 --- a/libafl/src/feedbacks/mod.rs +++ b/libafl/src/feedbacks/mod.rs @@ -1,5 +1,7 @@ //! The feedbacks reduce observer state after each run to a single `is_interesting`-value. //! If a testcase is interesting, it may be added to a Corpus. +//! +//! TODO: make S of Feedback an associated type when specialisation + AT is stable pub mod map; pub use map::*; @@ -36,7 +38,7 @@ use crate::{ corpus::Testcase, events::EventFirer, executors::ExitKind, - inputs::Input, + inputs::UsesInput, observers::{ListObserver, ObserversTuple, TimeObserver}, state::HasClientPerfMonitor, Error, @@ -45,10 +47,9 @@ use crate::{ /// Feedbacks evaluate the observers. /// Basically, they reduce the information provided by an observer to a value, /// indicating the "interestingness" of the last run. -pub trait Feedback: Named + Debug +pub trait Feedback: Named + Debug where - I: Input, - S: HasClientPerfMonitor, + S: UsesInput + HasClientPerfMonitor, { /// Initializes the feedback state. /// This method is called after that the `State` is created. @@ -62,13 +63,13 @@ where &mut self, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple; + EM: EventFirer, + OT: ObserversTuple; /// Returns if the result of a run is interesting and the value input should be stored in a corpus. /// It also keeps track of introspection stats. @@ -79,13 +80,13 @@ where &mut self, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // Start a timer for this feedback let start_time = crate::bolts::cpu::read_time_counter(); @@ -109,14 +110,14 @@ where fn append_metadata( &mut self, _state: &mut S, - _testcase: &mut Testcase, + _testcase: &mut Testcase, ) -> Result<(), Error> { Ok(()) } /// Discard the stored metadata in case that the testcase is not added to the corpus #[inline] - fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { Ok(()) } } @@ -129,42 +130,39 @@ pub trait HasObserverName { /// A combined feedback consisting of multiple [`Feedback`]s #[derive(Debug)] -pub struct CombinedFeedback +pub struct CombinedFeedback where - A: Feedback, - B: Feedback, - FL: FeedbackLogic, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + B: Feedback, + FL: FeedbackLogic, + S: UsesInput + HasClientPerfMonitor, { /// First [`Feedback`] pub first: A, /// Second [`Feedback`] pub second: B, name: String, - phantom: PhantomData<(I, S, FL)>, + phantom: PhantomData<(S, FL)>, } -impl Named for CombinedFeedback +impl Named for CombinedFeedback where - A: Feedback, - B: Feedback, - FL: FeedbackLogic, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + B: Feedback, + FL: FeedbackLogic, + S: UsesInput + HasClientPerfMonitor, { fn name(&self) -> &str { self.name.as_ref() } } -impl CombinedFeedback +impl CombinedFeedback where - A: Feedback, - B: Feedback, - FL: FeedbackLogic, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + B: Feedback, + FL: FeedbackLogic, + S: UsesInput + HasClientPerfMonitor, { /// Create a new combined feedback pub fn new(first: A, second: B) -> Self { @@ -178,13 +176,12 @@ where } } -impl Feedback for CombinedFeedback +impl Feedback for CombinedFeedback where - A: Feedback, - B: Feedback, - FL: FeedbackLogic, - I: Input, - S: HasClientPerfMonitor + Debug, + A: Feedback, + B: Feedback, + FL: FeedbackLogic, + S: UsesInput + HasClientPerfMonitor + Debug, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { self.first.init_state(state)?; @@ -197,13 +194,13 @@ where &mut self, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { FL::is_pair_interesting( &mut self.first, @@ -222,13 +219,13 @@ where &mut self, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { FL::is_pair_interesting_introspection( &mut self.first, @@ -242,25 +239,28 @@ where } #[inline] - fn append_metadata(&mut self, state: &mut S, testcase: &mut Testcase) -> Result<(), Error> { + fn append_metadata( + &mut self, + state: &mut S, + testcase: &mut Testcase, + ) -> Result<(), Error> { self.first.append_metadata(state, testcase)?; self.second.append_metadata(state, testcase) } #[inline] - fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { self.first.discard_metadata(state, input)?; self.second.discard_metadata(state, input) } } /// Logical combination of two feedbacks -pub trait FeedbackLogic: 'static + Debug +pub trait FeedbackLogic: 'static + Debug where - A: Feedback, - B: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + B: Feedback, + S: UsesInput + HasClientPerfMonitor, { /// The name of this combination fn name() -> &'static str; @@ -271,13 +271,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple; + EM: EventFirer, + OT: ObserversTuple; /// If this pair is interesting (with introspection features enabled) #[cfg(feature = "introspection")] @@ -287,33 +287,31 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple; + EM: EventFirer, + OT: ObserversTuple; } /// Factory for feedbacks which should be sensitive to an existing context, e.g. observer(s) from a /// specific execution -pub trait FeedbackFactory +pub trait FeedbackFactory where - F: Feedback, - I: Input, - S: HasClientPerfMonitor, + F: Feedback, + S: UsesInput + HasClientPerfMonitor, { /// Create the feedback from the provided context fn create_feedback(&self, ctx: &T) -> F; } -impl FeedbackFactory for FU +impl FeedbackFactory for FU where FU: Fn(&T) -> FE, - FE: Feedback, - I: Input, - S: HasClientPerfMonitor, + FE: Feedback, + S: UsesInput + HasClientPerfMonitor, { fn create_feedback(&self, ctx: &T) -> FE { self(ctx) @@ -340,11 +338,10 @@ where } } -impl FeedbackFactory for DefaultFeedbackFactory +impl FeedbackFactory for DefaultFeedbackFactory where - F: Feedback + Default, - I: Input, - S: HasClientPerfMonitor, + F: Feedback + Default, + S: UsesInput + HasClientPerfMonitor, { fn create_feedback(&self, _ctx: &T) -> F { F::default() @@ -367,12 +364,11 @@ pub struct LogicEagerAnd {} #[derive(Debug, Clone)] pub struct LogicFastAnd {} -impl FeedbackLogic for LogicEagerOr +impl FeedbackLogic for LogicEagerOr where - A: Feedback, - B: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + B: Feedback, + S: UsesInput + HasClientPerfMonitor, { fn name() -> &'static str { "Eager OR" @@ -383,13 +379,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let b = second.is_interesting(state, manager, input, observers, exit_kind)?; @@ -402,13 +398,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // Execute this feedback let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; @@ -418,12 +414,11 @@ where } } -impl FeedbackLogic for LogicFastOr +impl FeedbackLogic for LogicFastOr where - A: Feedback, - B: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + B: Feedback, + S: UsesInput + HasClientPerfMonitor, { fn name() -> &'static str { "Fast OR" @@ -434,13 +429,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { let a = first.is_interesting(state, manager, input, observers, exit_kind)?; if a { @@ -456,13 +451,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // Execute this feedback let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; @@ -475,12 +470,11 @@ where } } -impl FeedbackLogic for LogicEagerAnd +impl FeedbackLogic for LogicEagerAnd where - A: Feedback, - B: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + B: Feedback, + S: UsesInput + HasClientPerfMonitor, { fn name() -> &'static str { "Eager AND" @@ -491,13 +485,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { let a = first.is_interesting(state, manager, input, observers, exit_kind)?; let b = second.is_interesting(state, manager, input, observers, exit_kind)?; @@ -510,13 +504,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // Execute this feedback let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; @@ -526,12 +520,11 @@ where } } -impl FeedbackLogic for LogicFastAnd +impl FeedbackLogic for LogicFastAnd where - A: Feedback, - B: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + B: Feedback, + S: UsesInput + HasClientPerfMonitor, { fn name() -> &'static str { "Fast AND" @@ -542,13 +535,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { let a = first.is_interesting(state, manager, input, observers, exit_kind)?; if !a { @@ -564,13 +557,13 @@ where second: &mut B, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // Execute this feedback let a = first.is_interesting_introspection(state, manager, input, observers, exit_kind)?; @@ -585,42 +578,40 @@ where /// Combine two feedbacks with an eager AND operation, /// will call all feedbacks functions even if not necessary to conclude the result -pub type EagerAndFeedback = CombinedFeedback; +pub type EagerAndFeedback = CombinedFeedback; /// Combine two feedbacks with an fast AND operation, /// might skip calling feedbacks functions if not necessary to conclude the result -pub type FastAndFeedback = CombinedFeedback; +pub type FastAndFeedback = CombinedFeedback; /// Combine two feedbacks with an eager OR operation, /// will call all feedbacks functions even if not necessary to conclude the result -pub type EagerOrFeedback = CombinedFeedback; +pub type EagerOrFeedback = CombinedFeedback; /// Combine two feedbacks with an fast OR operation, /// might skip calling feedbacks functions if not necessary to conclude the result. /// This means any feedback that is not first might be skipped, use caution when using with /// `TimeFeedback` -pub type FastOrFeedback = CombinedFeedback; +pub type FastOrFeedback = CombinedFeedback; /// Compose feedbacks with an `NOT` operation #[derive(Clone)] -pub struct NotFeedback +pub struct NotFeedback where - A: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + S: UsesInput + HasClientPerfMonitor, { /// The feedback to invert pub first: A, /// The name name: String, - phantom: PhantomData<(I, S)>, + phantom: PhantomData, } -impl Debug for NotFeedback +impl Debug for NotFeedback where - A: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + S: UsesInput + HasClientPerfMonitor, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("NotFeedback") @@ -630,11 +621,10 @@ where } } -impl Feedback for NotFeedback +impl Feedback for NotFeedback where - A: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + S: UsesInput + HasClientPerfMonitor, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { self.first.init_state(state) @@ -645,13 +635,13 @@ where &mut self, state: &mut S, manager: &mut EM, - input: &I, + input: &S::Input, observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { Ok(!self .first @@ -659,21 +649,24 @@ where } #[inline] - fn append_metadata(&mut self, state: &mut S, testcase: &mut Testcase) -> Result<(), Error> { + fn append_metadata( + &mut self, + state: &mut S, + testcase: &mut Testcase, + ) -> Result<(), Error> { self.first.append_metadata(state, testcase) } #[inline] - fn discard_metadata(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn discard_metadata(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { self.first.discard_metadata(state, input) } } -impl Named for NotFeedback +impl Named for NotFeedback where - A: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + S: UsesInput + HasClientPerfMonitor, { #[inline] fn name(&self) -> &str { @@ -681,11 +674,10 @@ where } } -impl NotFeedback +impl NotFeedback where - A: Feedback, - I: Input, - S: HasClientPerfMonitor, + A: Feedback, + S: UsesInput + HasClientPerfMonitor, { /// Creates a new [`NotFeedback`]. pub fn new(first: A) -> Self { @@ -751,23 +743,22 @@ macro_rules! feedback_not { } /// Hack to use () as empty Feedback -impl Feedback for () +impl Feedback for () where - I: Input, - S: HasClientPerfMonitor, + S: UsesInput + HasClientPerfMonitor, { #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &S::Input, _observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { Ok(false) } @@ -784,23 +775,22 @@ impl Named for () { #[derive(Serialize, Deserialize, Clone, Debug)] pub struct CrashFeedback {} -impl Feedback for CrashFeedback +impl Feedback for CrashFeedback where - I: Input, - S: HasClientPerfMonitor, + S: UsesInput + HasClientPerfMonitor, { #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &S::Input, _observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { if let ExitKind::Crash = exit_kind { Ok(true) @@ -838,23 +828,22 @@ pub type CrashFeedbackFactory = DefaultFeedbackFactory; #[derive(Serialize, Deserialize, Clone, Debug)] pub struct TimeoutFeedback {} -impl Feedback for TimeoutFeedback +impl Feedback for TimeoutFeedback where - I: Input, - S: HasClientPerfMonitor, + S: UsesInput + HasClientPerfMonitor, { #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &S::Input, _observers: &OT, exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { if let ExitKind::Timeout = exit_kind { Ok(true) @@ -897,23 +886,22 @@ pub struct TimeFeedback { name: String, } -impl Feedback for TimeFeedback +impl Feedback for TimeFeedback where - I: Input, - S: HasClientPerfMonitor, + S: UsesInput + HasClientPerfMonitor, { #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &S::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // TODO Replace with match_name_type when stable let observer = observers.match_name::(self.name()).unwrap(); @@ -923,7 +911,11 @@ where /// Append to the testcase the generated metadata in case of a new corpus item #[inline] - fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase) -> Result<(), Error> { + fn append_metadata( + &mut self, + _state: &mut S, + testcase: &mut Testcase, + ) -> Result<(), Error> { *testcase.exec_time_mut() = self.exec_time; self.exec_time = None; Ok(()) @@ -931,7 +923,7 @@ where /// Discard the stored metadata in case that the testcase is not added to the corpus #[inline] - fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.exec_time = None; Ok(()) } @@ -974,10 +966,9 @@ where phantom: PhantomData, } -impl Feedback for ListFeedback +impl Feedback for ListFeedback where - I: Input, - S: HasClientPerfMonitor, + S: UsesInput + HasClientPerfMonitor, T: Debug + Serialize + serde::de::DeserializeOwned, { #[allow(clippy::wrong_self_convention)] @@ -985,13 +976,13 @@ where &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &S::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // TODO Replace with match_name_type when stable let observer = observers @@ -1045,10 +1036,9 @@ pub enum ConstFeedback { False, } -impl Feedback for ConstFeedback +impl Feedback for ConstFeedback where - I: Input, - S: HasClientPerfMonitor, + S: UsesInput + HasClientPerfMonitor, { #[inline] #[allow(clippy::wrong_self_convention)] @@ -1056,13 +1046,13 @@ where &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &S::Input, _observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { Ok(match self { ConstFeedback::True => true, @@ -1168,7 +1158,7 @@ pub mod pybind { } } - impl Feedback for PyObjectFeedback { + impl Feedback for PyObjectFeedback { fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> { Python::with_gil(|py| -> PyResult<()> { self.inner @@ -1187,8 +1177,8 @@ pub mod pybind { exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { // SAFETY: We use this observer in Python ony when the ObserverTuple is PythonObserversTuple let dont_look_at_this: &PythonObserversTuple = @@ -1295,7 +1285,7 @@ pub mod pybind { #[derive(Debug)] #[pyclass(unsendable, name = "NotFeedback")] pub struct PythonNotFeedback { - pub inner: NotFeedback, + pub inner: NotFeedback, } #[pymethods] @@ -1318,7 +1308,7 @@ pub mod pybind { #[derive(Debug)] #[pyclass(unsendable, name = $pystring)] pub struct $pyname { - pub inner: $feed, + pub inner: $feed, } #[pymethods] @@ -1624,10 +1614,10 @@ pub mod pybind { } } - impl Feedback for PythonFeedback { + impl Feedback for PythonFeedback { fn init_state(&mut self, state: &mut PythonStdState) -> Result<(), Error> { unwrap_me_mut!(self.wrapper, f, { - Feedback::::init_state(f, state) + Feedback::::init_state(f, state) }) } @@ -1640,8 +1630,8 @@ pub mod pybind { exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { unwrap_me_mut!(self.wrapper, f, { f.is_interesting(state, manager, input, observers, exit_kind) diff --git a/libafl/src/feedbacks/nautilus.rs b/libafl/src/feedbacks/nautilus.rs index cef6355a58..8f68abed85 100644 --- a/libafl/src/feedbacks/nautilus.rs +++ b/libafl/src/feedbacks/nautilus.rs @@ -1,6 +1,6 @@ //! Nautilus grammar mutator, see use alloc::string::String; -use core::fmt::Debug; +use core::{fmt::Debug, marker::PhantomData}; use std::fs::create_dir_all; use grammartec::{chunkstore::ChunkStore, context::Context}; @@ -16,6 +16,7 @@ use crate::{ generators::NautilusContext, inputs::NautilusInput, observers::ObserversTuple, + prelude::UsesInput, state::{HasClientPerfMonitor, HasMetadata}, Error, }; @@ -52,33 +53,37 @@ impl NautilusChunksMetadata { } /// A nautilus feedback for grammar fuzzing -pub struct NautilusFeedback<'a> { +pub struct NautilusFeedback<'a, S> { ctx: &'a Context, + phantom: PhantomData, } -impl Debug for NautilusFeedback<'_> { +impl Debug for NautilusFeedback<'_, S> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { write!(f, "NautilusFeedback {{}}") } } -impl<'a> NautilusFeedback<'a> { +impl<'a, S> NautilusFeedback<'a, S> { /// Create a new [`NautilusFeedback`] #[must_use] pub fn new(context: &'a NautilusContext) -> Self { - Self { ctx: &context.ctx } + Self { + ctx: &context.ctx, + phantom: PhantomData, + } } } -impl<'a> Named for NautilusFeedback<'a> { +impl<'a, S> Named for NautilusFeedback<'a, S> { fn name(&self) -> &str { "NautilusFeedback" } } -impl<'a, S> Feedback for NautilusFeedback<'a> +impl<'a, S> Feedback for NautilusFeedback<'a, S> where - S: HasMetadata + HasClientPerfMonitor, + S: HasMetadata + HasClientPerfMonitor + UsesInput, { #[allow(clippy::wrong_self_convention)] fn is_interesting( @@ -90,8 +95,8 @@ where _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { Ok(false) } diff --git a/libafl/src/feedbacks/new_hash_feedback.rs b/libafl/src/feedbacks/new_hash_feedback.rs index e6dc825fbc..dcbe6df5b2 100644 --- a/libafl/src/feedbacks/new_hash_feedback.rs +++ b/libafl/src/feedbacks/new_hash_feedback.rs @@ -11,7 +11,7 @@ use crate::{ events::EventFirer, executors::ExitKind, feedbacks::{Feedback, HasObserverName}, - inputs::Input, + inputs::UsesInput, observers::{ObserverWithHashField, ObserversTuple}, state::{HasClientPerfMonitor, HasNamedMetadata}, Error, @@ -68,17 +68,16 @@ impl HashSetState for NewHashFeedbackMetadata { /// A [`NewHashFeedback`] maintains a hashset of already seen stacktraces and considers interesting unseen ones #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct NewHashFeedback { +pub struct NewHashFeedback { name: String, observer_name: String, - o_type: PhantomData, + o_type: PhantomData<(O, S)>, } -impl Feedback for NewHashFeedback +impl Feedback for NewHashFeedback where - I: Input, - S: HasClientPerfMonitor + HasNamedMetadata, O: ObserverWithHashField + Named + Debug, + S: UsesInput + Debug + HasNamedMetadata + HasClientPerfMonitor, { fn init_state(&mut self, state: &mut S) -> Result<(), Error> { state.add_named_metadata(NewHashFeedbackMetadata::default(), &self.name); @@ -90,13 +89,13 @@ where &mut self, state: &mut S, _manager: &mut EM, - _input: &I, + _input: &::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { let observer = observers .match_name::(&self.observer_name) @@ -122,21 +121,21 @@ where } } -impl Named for NewHashFeedback { +impl Named for NewHashFeedback { #[inline] fn name(&self) -> &str { &self.name } } -impl HasObserverName for NewHashFeedback { +impl HasObserverName for NewHashFeedback { #[inline] fn observer_name(&self) -> &str { &self.observer_name } } -impl NewHashFeedback +impl NewHashFeedback where O: ObserverWithHashField + Named + Debug, { diff --git a/libafl/src/fuzzer/mod.rs b/libafl/src/fuzzer/mod.rs index 050ae1e339..8d1cee3646 100644 --- a/libafl/src/fuzzer/mod.rs +++ b/libafl/src/fuzzer/mod.rs @@ -1,23 +1,29 @@ //! The `Fuzzer` is the main struct for a fuzz campaign. use alloc::string::ToString; -use core::{marker::PhantomData, time::Duration}; +use core::{fmt::Debug, marker::PhantomData, time::Duration}; +use serde::{de::DeserializeOwned, Serialize}; + +#[cfg(test)] +use crate::inputs::Input; #[cfg(feature = "introspection")] use crate::monitors::PerfFeature; +#[cfg(test)] +use crate::state::NopState; use crate::{ bolts::current_time, corpus::{Corpus, Testcase}, - events::{Event, EventConfig, EventFirer, EventManager, ProgressReporter}, + events::{Event, EventConfig, EventFirer, EventProcessor, ProgressReporter}, executors::{Executor, ExitKind, HasObservers}, feedbacks::Feedback, - inputs::Input, + inputs::UsesInput, mark_feature_time, observers::ObserversTuple, schedulers::Scheduler, stages::StagesTuple, start_timer, - state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasSolutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasSolutions, UsesState}, Error, }; @@ -25,10 +31,9 @@ use crate::{ const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15); /// Holds a scheduler -pub trait HasScheduler +pub trait HasScheduler: UsesState where - CS: Scheduler, - I: Input, + CS: Scheduler, { /// The scheduler fn scheduler(&self) -> &CS; @@ -38,11 +43,10 @@ where } /// Holds an feedback -pub trait HasFeedback +pub trait HasFeedback: UsesState where - F: Feedback, - I: Input, - S: HasClientPerfMonitor, + F: Feedback, + Self::State: HasClientPerfMonitor, { /// The feedback fn feedback(&self) -> &F; @@ -52,11 +56,10 @@ where } /// Holds an objective feedback -pub trait HasObjective +pub trait HasObjective: UsesState where - OF: Feedback, - I: Input, - S: HasClientPerfMonitor, + OF: Feedback, + Self::State: HasClientPerfMonitor, { /// The objective feedback fn objective(&self) -> &OF; @@ -66,56 +69,53 @@ where } /// Evaluate if an input is interesting using the feedback -pub trait ExecutionProcessor -where - OT: ObserversTuple, - I: Input, -{ +pub trait ExecutionProcessor: UsesState { /// Evaluate if a set of observation channels has an interesting state fn process_execution( &mut self, - state: &mut S, + state: &mut Self::State, manager: &mut EM, - input: I, + input: ::Input, observers: &OT, exit_kind: &ExitKind, send_events: bool, ) -> Result<(ExecuteInputResult, Option), Error> where - EM: EventFirer; + EM: EventFirer; } /// Evaluate an input modifying the state of the fuzzer -pub trait EvaluatorObservers: Sized -where - I: Input, - OT: ObserversTuple, -{ +pub trait EvaluatorObservers: UsesState + Sized { /// Runs the input and triggers observers and feedback, - /// returns if is interesting an (option) the index of the new testcase in the corpus + /// returns if is interesting an (option) the index of the new + /// [`crate::corpus::Testcase`] in the [`crate::corpus::Corpus`] fn evaluate_input_with_observers( &mut self, - state: &mut S, + state: &mut Self::State, executor: &mut E, manager: &mut EM, - input: I, + input: ::Input, send_events: bool, ) -> Result<(ExecuteInputResult, Option), Error> where - E: Executor + HasObservers, - EM: EventManager; + E: Executor + HasObservers, + EM: EventFirer; } /// Evaluate an input modifying the state of the fuzzer -pub trait Evaluator { +pub trait Evaluator: UsesState +where + E: UsesState, + EM: UsesState, +{ /// Runs the input and triggers observers and feedback, - /// returns if is interesting an (option) the index of the new testcase in the corpus + /// returns if is interesting an (option) the index of the new [`crate::corpus::Testcase`] in the corpus fn evaluate_input( &mut self, - state: &mut S, + state: &mut Self::State, executor: &mut E, manager: &mut EM, - input: I, + input: ::Input, ) -> Result<(ExecuteInputResult, Option), Error> { self.evaluate_input_events(state, executor, manager, input, true) } @@ -125,10 +125,10 @@ pub trait Evaluator { /// This version has a boolean to decide if send events to the manager. fn evaluate_input_events( &mut self, - state: &mut S, + state: &mut Self::State, executor: &mut E, manager: &mut EM, - input: I, + input: ::Input, send_events: bool, ) -> Result<(ExecuteInputResult, Option), Error>; @@ -138,20 +138,20 @@ pub trait Evaluator { /// Usually, you want to use [`Evaluator::evaluate_input`], unless you know what you are doing. fn add_input( &mut self, - state: &mut S, + state: &mut Self::State, executor: &mut E, manager: &mut EM, - input: I, + input: ::Input, ) -> Result; } /// The main fuzzer trait. -pub trait Fuzzer +pub trait Fuzzer: Sized + UsesState where - I: Input, - EM: ProgressReporter, - S: HasExecutions + HasClientPerfMonitor + HasMetadata, - ST: ?Sized, + Self::State: HasClientPerfMonitor + HasMetadata + HasExecutions, + E: UsesState, + EM: ProgressReporter, + ST: StagesTuple, { /// Fuzz for a single iteration. /// Returns the index of the last fuzzed corpus item. @@ -166,7 +166,7 @@ where &mut self, stages: &mut ST, executor: &mut E, - state: &mut S, + state: &mut EM::State, manager: &mut EM, ) -> Result; @@ -175,7 +175,7 @@ where &mut self, stages: &mut ST, executor: &mut E, - state: &mut S, + state: &mut EM::State, manager: &mut EM, ) -> Result { let mut last = current_time(); @@ -199,7 +199,7 @@ where &mut self, stages: &mut ST, executor: &mut E, - state: &mut S, + state: &mut EM::State, manager: &mut EM, iters: u64, ) -> Result { @@ -240,27 +240,35 @@ pub enum ExecuteInputResult { /// Your default fuzzer instance, for everyday use. #[derive(Debug)] -pub struct StdFuzzer +pub struct StdFuzzer where - CS: Scheduler, - F: Feedback, - I: Input, - OF: Feedback, - S: HasClientPerfMonitor, + CS: Scheduler, + F: Feedback, + OF: Feedback, + CS::State: HasClientPerfMonitor, { scheduler: CS, feedback: F, objective: OF, - phantom: PhantomData<(I, OT, S)>, + phantom: PhantomData, } -impl HasScheduler for StdFuzzer +impl UsesState for StdFuzzer where - CS: Scheduler, - F: Feedback, - I: Input, - OF: Feedback, - S: HasClientPerfMonitor, + CS: Scheduler, + F: Feedback, + OF: Feedback, + CS::State: HasClientPerfMonitor, +{ + type State = CS::State; +} + +impl HasScheduler for StdFuzzer +where + CS: Scheduler, + F: Feedback, + OF: Feedback, + CS::State: HasClientPerfMonitor, { fn scheduler(&self) -> &CS { &self.scheduler @@ -271,13 +279,12 @@ where } } -impl HasFeedback for StdFuzzer +impl HasFeedback for StdFuzzer where - CS: Scheduler, - F: Feedback, - I: Input, - OF: Feedback, - S: HasClientPerfMonitor, + CS: Scheduler, + F: Feedback, + OF: Feedback, + CS::State: HasClientPerfMonitor, { fn feedback(&self) -> &F { &self.feedback @@ -288,13 +295,12 @@ where } } -impl HasObjective for StdFuzzer +impl HasObjective for StdFuzzer where - CS: Scheduler, - F: Feedback, - I: Input, - OF: Feedback, - S: HasClientPerfMonitor, + CS: Scheduler, + F: Feedback, + OF: Feedback, + CS::State: HasClientPerfMonitor, { fn objective(&self) -> &OF { &self.objective @@ -305,27 +311,26 @@ where } } -impl ExecutionProcessor for StdFuzzer +impl ExecutionProcessor for StdFuzzer where - CS: Scheduler, - F: Feedback, - I: Input, - OF: Feedback, - OT: ObserversTuple + serde::Serialize + serde::de::DeserializeOwned, - S: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, + CS: Scheduler, + F: Feedback, + OF: Feedback, + OT: ObserversTuple + Serialize + DeserializeOwned, + CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, { /// Evaluate if a set of observation channels has an interesting state fn process_execution( &mut self, - state: &mut S, + state: &mut CS::State, manager: &mut EM, - input: I, + input: ::Input, observers: &OT, exit_kind: &ExitKind, send_events: bool, ) -> Result<(ExecuteInputResult, Option), Error> where - EM: EventFirer, + EM: EventFirer, { let mut res = ExecuteInputResult::None; @@ -378,7 +383,7 @@ where let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique { None } else { - Some(manager.serialize_observers(observers)?) + Some(manager.serialize_observers::(observers)?) }; manager.fire( state, @@ -419,28 +424,27 @@ where } } -impl EvaluatorObservers for StdFuzzer +impl EvaluatorObservers for StdFuzzer where - CS: Scheduler, - OT: ObserversTuple + serde::Serialize + serde::de::DeserializeOwned, - F: Feedback, - I: Input, - OF: Feedback, - S: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, + CS: Scheduler, + OT: ObserversTuple + Serialize + DeserializeOwned, + F: Feedback, + OF: Feedback, + CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, { - /// Process one input, adding to the respective corpuses if needed and firing the right events + /// Process one input, adding to the respective corpora if needed and firing the right events #[inline] fn evaluate_input_with_observers( &mut self, - state: &mut S, + state: &mut Self::State, executor: &mut E, manager: &mut EM, - input: I, + input: ::Input, send_events: bool, ) -> Result<(ExecuteInputResult, Option), Error> where - E: Executor + HasObservers, - EM: EventManager, + E: Executor + HasObservers, + EM: EventFirer, { let exit_kind = self.execute_input(state, executor, manager, &input)?; let observers = executor.observers(); @@ -448,37 +452,36 @@ where } } -impl Evaluator for StdFuzzer +impl Evaluator for StdFuzzer where - CS: Scheduler, - E: Executor + HasObservers, - OT: ObserversTuple + serde::Serialize + serde::de::DeserializeOwned, - EM: EventManager, - F: Feedback, - I: Input, - OF: Feedback, - S: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, + CS: Scheduler, + E: HasObservers + Executor, + EM: EventFirer, + F: Feedback, + OF: Feedback, + OT: ObserversTuple + Serialize + DeserializeOwned, + CS::State: HasCorpus + HasSolutions + HasClientPerfMonitor + HasExecutions, { - /// Process one input, adding to the respective corpuses if needed and firing the right events + /// Process one input, adding to the respective corpora if needed and firing the right events #[inline] fn evaluate_input_events( &mut self, - state: &mut S, + state: &mut CS::State, executor: &mut E, manager: &mut EM, - input: I, + input: ::Input, send_events: bool, ) -> Result<(ExecuteInputResult, Option), Error> { self.evaluate_input_with_observers(state, executor, manager, input, send_events) } - /// Adds an input, even if it's not conisered `interesting` by any of the executors + /// Adds an input, even if it's not considered `interesting` by any of the executors fn add_input( &mut self, - state: &mut S, + state: &mut CS::State, executor: &mut E, manager: &mut EM, - input: I, + input: ::Input, ) -> Result { let exit_kind = self.execute_input(state, executor, manager, &input)?; let observers = executor.observers(); @@ -496,7 +499,7 @@ where let observers_buf = if manager.configuration() == EventConfig::AlwaysUnique { None } else { - Some(manager.serialize_observers(observers)?) + Some(manager.serialize_observers::(observers)?) }; manager.fire( state, @@ -514,21 +517,21 @@ where } } -impl Fuzzer for StdFuzzer +impl Fuzzer for StdFuzzer where - CS: Scheduler, - EM: EventManager, - F: Feedback, - I: Input, - S: HasClientPerfMonitor + HasExecutions + HasMetadata, - OF: Feedback, - ST: StagesTuple + ?Sized, + CS: Scheduler, + E: UsesState, + EM: ProgressReporter + EventProcessor, + F: Feedback, + OF: Feedback, + CS::State: HasClientPerfMonitor + HasExecutions + HasMetadata, + ST: StagesTuple, { fn fuzz_one( &mut self, stages: &mut ST, executor: &mut E, - state: &mut S, + state: &mut CS::State, manager: &mut EM, ) -> Result { // Init timer for scheduler @@ -564,13 +567,12 @@ where } } -impl StdFuzzer +impl StdFuzzer where - CS: Scheduler, - F: Feedback, - I: Input, - OF: Feedback, - S: HasExecutions + HasClientPerfMonitor, + CS: Scheduler, + F: Feedback, + OF: Feedback, + CS::State: UsesInput + HasExecutions + HasClientPerfMonitor, { /// Create a new `StdFuzzer` with standard behavior. pub fn new(scheduler: CS, feedback: F, objective: OF) -> Self { @@ -585,14 +587,15 @@ where /// Runs the input and triggers observers and feedback pub fn execute_input( &mut self, - state: &mut S, + state: &mut CS::State, executor: &mut E, event_mgr: &mut EM, - input: &I, + input: &::Input, ) -> Result where - E: Executor + HasObservers, - OT: ObserversTuple, + E: Executor + HasObservers, + EM: UsesState, + OT: ObserversTuple, { start_timer!(state); executor.observers_mut().pre_exec_all(state, input)?; @@ -614,46 +617,39 @@ where } } -/// Structs with this trait will execute an [`Input`] -pub trait ExecutesInput +/// Structs with this trait will execute an input +pub trait ExecutesInput: UsesState where - I: Input, - OT: ObserversTuple, + E: UsesState, + EM: UsesState, { /// Runs the input and triggers observers and feedback - fn execute_input( + fn execute_input( &mut self, - state: &mut S, + state: &mut Self::State, executor: &mut E, event_mgr: &mut EM, - input: &I, - ) -> Result - where - E: Executor + HasObservers, - OT: ObserversTuple; + input: &::Input, + ) -> Result; } -impl ExecutesInput for StdFuzzer +impl ExecutesInput for StdFuzzer where - CS: Scheduler, - F: Feedback, - I: Input, - OT: ObserversTuple, - OF: Feedback, - S: HasExecutions + HasClientPerfMonitor, + CS: Scheduler, + F: Feedback, + OF: Feedback, + E: Executor + HasObservers, + EM: UsesState, + CS::State: UsesInput + HasExecutions + HasClientPerfMonitor, { /// Runs the input and triggers observers and feedback - fn execute_input( + fn execute_input( &mut self, - state: &mut S, + state: &mut CS::State, executor: &mut E, event_mgr: &mut EM, - input: &I, - ) -> Result - where - E: Executor + HasObservers, - OT: ObserversTuple, - { + input: &::Input, + ) -> Result { start_timer!(state); executor.observers_mut().pre_exec_all(state, input)?; mark_feature_time!(state, PerfFeature::PreExecObservers); @@ -674,6 +670,48 @@ where } } +#[cfg(test)] +#[derive(Clone, Debug, Default)] +pub(crate) struct NopFuzzer { + phantom: PhantomData, +} + +#[cfg(test)] +impl NopFuzzer { + pub fn new() -> Self { + Self { + phantom: PhantomData, + } + } +} + +#[cfg(test)] +impl UsesState for NopFuzzer +where + I: Input, +{ + type State = NopState; +} + +#[cfg(test)] +impl Fuzzer for NopFuzzer +where + E: UsesState>, + EM: ProgressReporter>, + I: Input, + ST: StagesTuple, Self>, +{ + fn fuzz_one( + &mut self, + _stages: &mut ST, + _executor: &mut E, + _state: &mut EM::State, + _manager: &mut EM, + ) -> Result { + unimplemented!() + } +} + #[cfg(feature = "python")] #[allow(missing_docs)] /// `Fuzzer` Python bindings @@ -697,12 +735,10 @@ pub mod pybind { /// `StdFuzzer` with fixed generics pub type PythonStdFuzzer = StdFuzzer< - QueueScheduler, + QueueScheduler, PythonFeedback, - BytesInput, PythonFeedback, PythonObserversTuple, - PythonStdState, >; /// Python class for StdFuzzer diff --git a/libafl/src/inputs/mod.rs b/libafl/src/inputs/mod.rs index f7c4811039..aae307ea5f 100644 --- a/libafl/src/inputs/mod.rs +++ b/libafl/src/inputs/mod.rs @@ -109,3 +109,10 @@ pub trait HasBytesVec { /// The internal bytes map (as mutable borrow) fn bytes_mut(&mut self) -> &mut Vec; } + +/// Defines the input type shared across traits of the type. +/// Needed for consistency across HasCorpus/HasSolutions and friends. +pub trait UsesInput { + /// Type which will be used throughout this state. + type Input: Input; +} diff --git a/libafl/src/lib.rs b/libafl/src/lib.rs index ab5d8bacbd..11af428f9a 100644 --- a/libafl/src/lib.rs +++ b/libafl/src/lib.rs @@ -453,19 +453,21 @@ pub mod prelude { #[cfg(feature = "std")] #[cfg(test)] mod tests { - #[cfg(feature = "std")] - use crate::events::SimpleEventManager; + use crate::{ bolts::{rands::StdRand, tuples::tuple_list}, corpus::{Corpus, InMemoryCorpus, Testcase}, + events::NopEventManager, executors::{ExitKind, InProcessExecutor}, + feedbacks::ConstFeedback, + fuzzer::Fuzzer, inputs::BytesInput, monitors::SimpleMonitor, mutators::{mutations::BitFlipMutator, StdScheduledMutator}, schedulers::RandScheduler, stages::StdMutationalStage, state::{HasCorpus, StdState}, - Fuzzer, StdFuzzer, + StdFuzzer, }; #[test] @@ -474,25 +476,31 @@ mod tests { let rand = StdRand::with_seed(0); let mut corpus = InMemoryCorpus::::new(); - let testcase = Testcase::new(vec![0; 4]); + let testcase = Testcase::new(vec![0; 4].into()); corpus.add(testcase).unwrap(); + let mut feedback = ConstFeedback::new(false); + let mut objective = ConstFeedback::new(false); + let mut state = StdState::new( rand, corpus, InMemoryCorpus::::new(), - &mut (), - &mut (), + &mut feedback, + &mut objective, ) .unwrap(); - let monitor = SimpleMonitor::new(|s| { + let _monitor = SimpleMonitor::new(|s| { println!("{s}"); }); - let mut event_manager = SimpleEventManager::new(monitor); + let mut event_manager = NopEventManager::new(); + + let feedback = ConstFeedback::new(false); + let objective = ConstFeedback::new(false); let scheduler = RandScheduler::new(); - let mut fuzzer = StdFuzzer::new(scheduler, (), ()); + let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective); let mut harness = |_buf: &BytesInput| ExitKind::Ok; let mut executor = InProcessExecutor::new( @@ -515,8 +523,8 @@ mod tests { let state_serialized = postcard::to_allocvec(&state).unwrap(); let state_deserialized: StdState< + _, InMemoryCorpus, - BytesInput, StdRand, InMemoryCorpus, > = postcard::from_bytes(state_serialized.as_slice()).unwrap(); diff --git a/libafl/src/monitors/mod.rs b/libafl/src/monitors/mod.rs index c54d0f0b76..4ed73cee7e 100644 --- a/libafl/src/monitors/mod.rs +++ b/libafl/src/monitors/mod.rs @@ -277,6 +277,67 @@ impl Default for NopMonitor { } } +#[cfg(feature = "std")] +/// Tracking monitor during fuzzing that just prints to `stdout`. +#[derive(Debug, Clone, Default)] +pub struct SimplePrintingMonitor { + start_time: Duration, + client_stats: Vec, +} + +#[cfg(feature = "std")] +impl SimplePrintingMonitor { + /// Create a new [`SimplePrintingMonitor`] + #[must_use] + pub fn new() -> Self { + Self::default() + } +} + +#[cfg(feature = "std")] +impl Monitor for SimplePrintingMonitor { + /// the client monitor, mutable + fn client_stats_mut(&mut self) -> &mut Vec { + &mut self.client_stats + } + + /// the client monitor + fn client_stats(&self) -> &[ClientStats] { + &self.client_stats + } + + /// Time this fuzzing run stated + fn start_time(&mut self) -> Duration { + self.start_time + } + + fn display(&mut self, event_msg: String, sender_id: u32) { + println!( + "[{} #{}] run time: {}, clients: {}, corpus: {}, objectives: {}, executions: {}, exec/sec: {}", + event_msg, + sender_id, + format_duration_hms(&(current_time() - self.start_time)), + self.client_stats().len(), + self.corpus_size(), + self.objective_size(), + self.total_execs(), + self.execs_per_sec() + ); + + // Only print perf monitor if the feature is enabled + #[cfg(feature = "introspection")] + { + // Print the client performance monitor. + println!( + "Client {:03}:\n{}", + sender_id, self.client_stats[sender_id as usize].introspection_monitor + ); + // Separate the spacing just a bit + println!(); + } + } +} + /// Tracking monitor during fuzzing. #[derive(Clone)] pub struct SimpleMonitor diff --git a/libafl/src/mutators/encoded_mutations.rs b/libafl/src/mutators/encoded_mutations.rs index 89ef123dde..74429ae5f7 100644 --- a/libafl/src/mutators/encoded_mutations.rs +++ b/libafl/src/mutators/encoded_mutations.rs @@ -9,7 +9,7 @@ use crate::{ tuples::{tuple_list, tuple_list_type}, }, corpus::Corpus, - inputs::EncodedInput, + inputs::{EncodedInput, UsesInput}, mutators::{ mutations::{buffer_copy, buffer_self_copy, ARITH_MAX}, MutationResult, Mutator, Named, @@ -22,7 +22,7 @@ use crate::{ #[derive(Debug, Default)] pub struct EncodedRandMutator; -impl Mutator for EncodedRandMutator { +impl> Mutator for EncodedRandMutator { fn mutate( &mut self, state: &mut S, @@ -57,7 +57,7 @@ impl EncodedRandMutator { #[derive(Debug, Default)] pub struct EncodedIncMutator; -impl Mutator for EncodedIncMutator { +impl> Mutator for EncodedIncMutator { fn mutate( &mut self, state: &mut S, @@ -92,7 +92,7 @@ impl EncodedIncMutator { #[derive(Debug, Default)] pub struct EncodedDecMutator; -impl Mutator for EncodedDecMutator { +impl> Mutator for EncodedDecMutator { fn mutate( &mut self, state: &mut S, @@ -127,7 +127,7 @@ impl EncodedDecMutator { #[derive(Debug, Default)] pub struct EncodedAddMutator; -impl Mutator for EncodedAddMutator { +impl> Mutator for EncodedAddMutator { fn mutate( &mut self, state: &mut S, @@ -166,7 +166,7 @@ impl EncodedAddMutator { #[derive(Debug, Default)] pub struct EncodedDeleteMutator; -impl Mutator for EncodedDeleteMutator { +impl> Mutator for EncodedDeleteMutator { fn mutate( &mut self, state: &mut S, @@ -206,9 +206,9 @@ pub struct EncodedInsertCopyMutator { tmp_buf: Vec, } -impl Mutator for EncodedInsertCopyMutator +impl Mutator for EncodedInsertCopyMutator where - S: HasRand + HasMaxSize, + S: UsesInput + HasRand + HasMaxSize, { fn mutate( &mut self, @@ -267,7 +267,7 @@ impl EncodedInsertCopyMutator { #[derive(Debug, Default)] pub struct EncodedCopyMutator; -impl Mutator for EncodedCopyMutator { +impl + HasRand> Mutator for EncodedCopyMutator { fn mutate( &mut self, state: &mut S, @@ -307,9 +307,9 @@ impl EncodedCopyMutator { #[derive(Debug, Default)] pub struct EncodedCrossoverInsertMutator; -impl Mutator for EncodedCrossoverInsertMutator +impl Mutator for EncodedCrossoverInsertMutator where - S: HasRand + HasCorpus + HasMaxSize, + S: UsesInput + HasRand + HasCorpus + HasMaxSize, { fn mutate( &mut self, @@ -381,9 +381,9 @@ impl EncodedCrossoverInsertMutator { #[derive(Debug, Default)] pub struct EncodedCrossoverReplaceMutator; -impl Mutator for EncodedCrossoverReplaceMutator +impl Mutator for EncodedCrossoverReplaceMutator where - S: HasRand + HasCorpus, + S: UsesInput + HasRand + HasCorpus, { fn mutate( &mut self, diff --git a/libafl/src/mutators/gramatron.rs b/libafl/src/mutators/gramatron.rs index a58668983a..01ec4fa289 100644 --- a/libafl/src/mutators/gramatron.rs +++ b/libafl/src/mutators/gramatron.rs @@ -10,7 +10,7 @@ use crate::{ bolts::{rands::Rand, tuples::Named}, corpus::Corpus, generators::GramatronGenerator, - inputs::{GramatronInput, Terminal}, + inputs::{GramatronInput, Terminal, UsesInput}, mutators::{MutationResult, Mutator}, state::{HasCorpus, HasMetadata, HasRand}, Error, @@ -27,9 +27,9 @@ where generator: &'a GramatronGenerator<'a, S>, } -impl<'a, S> Mutator for GramatronRandomMutator<'a, S> +impl<'a, S> Mutator for GramatronRandomMutator<'a, S> where - S: HasRand + HasMetadata, + S: UsesInput + HasRand + HasMetadata, { fn mutate( &mut self, @@ -96,9 +96,9 @@ impl GramatronIdxMapMetadata { #[derive(Default, Debug)] pub struct GramatronSpliceMutator; -impl Mutator for GramatronSpliceMutator +impl Mutator for GramatronSpliceMutator where - S: HasRand + HasCorpus + HasMetadata, + S: UsesInput + HasRand + HasCorpus + HasMetadata, { fn mutate( &mut self, @@ -169,9 +169,9 @@ pub struct GramatronRecursionMutator { feature: Vec, } -impl Mutator for GramatronRecursionMutator +impl Mutator for GramatronRecursionMutator where - S: HasRand + HasMetadata, + S: UsesInput + HasRand + HasMetadata, { fn mutate( &mut self, diff --git a/libafl/src/mutators/grimoire.rs b/libafl/src/mutators/grimoire.rs index 0c2e2fb9d4..b9c58211a0 100644 --- a/libafl/src/mutators/grimoire.rs +++ b/libafl/src/mutators/grimoire.rs @@ -7,7 +7,7 @@ use core::cmp::{max, min}; use crate::{ bolts::{rands::Rand, tuples::Named}, corpus::Corpus, - inputs::{GeneralizedInput, GeneralizedItem}, + inputs::{GeneralizedInput, GeneralizedItem, UsesInput}, mutators::{token_mutations::Tokens, MutationResult, Mutator}, stages::generalization::GeneralizedIndexesMetadata, state::{HasCorpus, HasMetadata, HasRand}, @@ -24,7 +24,7 @@ fn extend_with_random_generalized( gap_indices: &mut Vec, ) -> Result<(), Error> where - S: HasMetadata + HasRand + HasCorpus, + S: HasMetadata + HasRand + HasCorpus, { let rand_idx = state.rand_mut().next() as usize; @@ -128,9 +128,9 @@ pub struct GrimoireExtensionMutator { gap_indices: Vec, } -impl Mutator for GrimoireExtensionMutator +impl Mutator for GrimoireExtensionMutator where - S: HasMetadata + HasRand + HasCorpus, + S: UsesInput + HasMetadata + HasRand + HasCorpus, { fn mutate( &mut self, @@ -176,9 +176,9 @@ pub struct GrimoireRecursiveReplacementMutator { gap_indices: Vec, } -impl Mutator for GrimoireRecursiveReplacementMutator +impl Mutator for GrimoireRecursiveReplacementMutator where - S: HasMetadata + HasRand + HasCorpus, + S: UsesInput + HasMetadata + HasRand + HasCorpus, { fn mutate( &mut self, @@ -247,9 +247,9 @@ impl GrimoireRecursiveReplacementMutator { #[derive(Debug, Default)] pub struct GrimoireStringReplacementMutator {} -impl Mutator for GrimoireStringReplacementMutator +impl Mutator for GrimoireStringReplacementMutator where - S: HasMetadata + HasRand, + S: UsesInput + HasMetadata + HasRand, { fn mutate( &mut self, @@ -355,9 +355,9 @@ pub struct GrimoireRandomDeleteMutator { gap_indices: Vec, } -impl Mutator for GrimoireRandomDeleteMutator +impl Mutator for GrimoireRandomDeleteMutator where - S: HasMetadata + HasRand + HasCorpus, + S: UsesInput + HasMetadata + HasRand + HasCorpus, { fn mutate( &mut self, diff --git a/libafl/src/mutators/mod.rs b/libafl/src/mutators/mod.rs index e8acd5421c..f04163a1f7 100644 --- a/libafl/src/mutators/mod.rs +++ b/libafl/src/mutators/mod.rs @@ -22,7 +22,7 @@ pub use nautilus::*; use crate::{ bolts::tuples::{HasConstLen, Named}, - inputs::Input, + inputs::UsesInput, Error, }; @@ -42,15 +42,15 @@ pub enum MutationResult { /// A mutator takes input, and mutates it. /// Simple as that. -pub trait Mutator +pub trait Mutator where - I: Input, + S: UsesInput, { /// Mutate a given input fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result; @@ -66,15 +66,15 @@ where } /// A `Tuple` of `Mutators` that can execute multiple `Mutators` in a row. -pub trait MutatorsTuple: HasConstLen +pub trait MutatorsTuple: HasConstLen where - I: Input, + S: UsesInput, { /// Runs the `mutate` function on all `Mutators` in this `Tuple`. fn mutate_all( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result; @@ -91,7 +91,7 @@ where &mut self, index: usize, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result; @@ -105,14 +105,14 @@ where ) -> Result<(), Error>; } -impl MutatorsTuple for () +impl MutatorsTuple for () where - I: Input, + S: UsesInput, { fn mutate_all( &mut self, _state: &mut S, - _input: &mut I, + _input: &mut S::Input, _stage_idx: i32, ) -> Result { Ok(MutationResult::Skipped) @@ -131,7 +131,7 @@ where &mut self, _index: usize, _state: &mut S, - _input: &mut I, + _input: &mut S::Input, _stage_idx: i32, ) -> Result { Ok(MutationResult::Skipped) @@ -148,16 +148,16 @@ where } } -impl MutatorsTuple for (Head, Tail) +impl MutatorsTuple for (Head, Tail) where - Head: Mutator + Named, - Tail: MutatorsTuple, - I: Input, + Head: Mutator + Named, + Tail: MutatorsTuple, + S: UsesInput, { fn mutate_all( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result { let r = self.0.mutate(state, input, stage_idx)?; @@ -182,7 +182,7 @@ where &mut self, index: usize, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result { if index == 0 { @@ -234,7 +234,7 @@ pub mod pybind { } } - impl Mutator for PyObjectMutator { + impl Mutator for PyObjectMutator { fn mutate( &mut self, state: &mut PythonStdState, @@ -329,7 +329,7 @@ pub mod pybind { } } - impl Mutator for PythonMutator { + impl Mutator for PythonMutator { fn mutate( &mut self, state: &mut PythonStdState, diff --git a/libafl/src/mutators/mopt_mutator.rs b/libafl/src/mutators/mopt_mutator.rs index 273c27ba77..2f943a5504 100644 --- a/libafl/src/mutators/mopt_mutator.rs +++ b/libafl/src/mutators/mopt_mutator.rs @@ -13,7 +13,6 @@ use crate::{ rands::{Rand, StdRand}, }, corpus::Corpus, - inputs::Input, mutators::{ComposedByMutations, MutationResult, Mutator, MutatorsTuple, ScheduledMutator}, state::{HasCorpus, HasMetadata, HasRand, HasSolutions}, Error, @@ -363,46 +362,43 @@ pub enum MOptMode { /// This is the main struct of `MOpt`, an `AFL` mutator. /// See the original `MOpt` implementation in -pub struct StdMOptMutator +pub struct StdMOptMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, + MT: MutatorsTuple, + S: HasRand + HasMetadata + HasCorpus + HasSolutions, { mode: MOptMode, finds_before: usize, mutations: MT, max_stack_pow: u64, - phantom: PhantomData<(I, S)>, + phantom: PhantomData, } -impl Debug for StdMOptMutator +impl Debug for StdMOptMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, + MT: MutatorsTuple, + S: HasRand + HasMetadata + HasCorpus + HasSolutions, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "StdMOptMutator with {} mutations for Input type {}", self.mutations.len(), - core::any::type_name::() + core::any::type_name::() ) } } -impl Mutator for StdMOptMutator +impl Mutator for StdMOptMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, + MT: MutatorsTuple, + S: HasRand + HasMetadata + HasCorpus + HasSolutions, { #[inline] fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result { self.finds_before = state.corpus().count() + state.solutions().count(); @@ -528,11 +524,10 @@ where } } -impl StdMOptMutator +impl StdMOptMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, + MT: MutatorsTuple, + S: HasRand + HasMetadata + HasCorpus + HasSolutions, { /// Create a new [`StdMOptMutator`]. pub fn new( @@ -555,7 +550,7 @@ where fn core_mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result { let mut r = MutationResult::Skipped; @@ -585,7 +580,7 @@ where fn pilot_mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result { let mut r = MutationResult::Skipped; @@ -620,11 +615,10 @@ where } } -impl ComposedByMutations for StdMOptMutator +impl ComposedByMutations for StdMOptMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, + MT: MutatorsTuple, + S: HasRand + HasMetadata + HasCorpus + HasSolutions, { /// Get the mutations #[inline] @@ -639,19 +633,18 @@ where } } -impl ScheduledMutator for StdMOptMutator +impl ScheduledMutator for StdMOptMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand + HasMetadata + HasCorpus + HasSolutions, + MT: MutatorsTuple, + S: HasRand + HasMetadata + HasCorpus + HasSolutions, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &I) -> u64 { + fn iterations(&self, state: &mut S, _: &S::Input) -> u64 { 1 << (1 + state.rand_mut().below(self.max_stack_pow)) } /// Get the next mutation to apply - fn schedule(&self, state: &mut S, _: &I) -> usize { + fn schedule(&self, state: &mut S, _: &S::Input) -> usize { state .metadata_mut() .get_mut::() @@ -663,7 +656,7 @@ where fn scheduled_mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result { let mode = self.mode; diff --git a/libafl/src/mutators/mutations.rs b/libafl/src/mutators/mutations.rs index 748c7e4b23..3a2a612df4 100644 --- a/libafl/src/mutators/mutations.rs +++ b/libafl/src/mutators/mutations.rs @@ -9,7 +9,7 @@ use core::{ use crate::{ bolts::{rands::Rand, tuples::Named}, corpus::Corpus, - inputs::{HasBytesVec, Input}, + inputs::{HasBytesVec, UsesInput}, mutators::{MutationResult, Mutator}, state::{HasCorpus, HasMaxSize, HasRand}, Error, @@ -100,15 +100,15 @@ pub const INTERESTING_32: [i32; 27] = [ #[derive(Default, Debug)] pub struct BitFlipMutator; -impl Mutator for BitFlipMutator +impl Mutator for BitFlipMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut ::Input, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -140,15 +140,15 @@ impl BitFlipMutator { #[derive(Default, Debug)] pub struct ByteFlipMutator; -impl Mutator for ByteFlipMutator +impl Mutator for ByteFlipMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -178,15 +178,15 @@ impl ByteFlipMutator { #[derive(Default, Debug)] pub struct ByteIncMutator; -impl Mutator for ByteIncMutator +impl Mutator for ByteIncMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -217,15 +217,15 @@ impl ByteIncMutator { #[derive(Default, Debug)] pub struct ByteDecMutator; -impl Mutator for ByteDecMutator +impl Mutator for ByteDecMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -256,15 +256,15 @@ impl ByteDecMutator { #[derive(Default, Debug)] pub struct ByteNegMutator; -impl Mutator for ByteNegMutator +impl Mutator for ByteNegMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -295,15 +295,15 @@ impl ByteNegMutator { #[derive(Default, Debug)] pub struct ByteRandMutator; -impl Mutator for ByteRandMutator +impl Mutator for ByteRandMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { if input.bytes().is_empty() { @@ -339,15 +339,15 @@ macro_rules! add_mutator_impl { pub struct $name; #[allow(trivial_numeric_casts)] - impl Mutator for $name + impl Mutator for $name where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { if input.bytes().len() < size_of::<$size>() { @@ -405,16 +405,16 @@ macro_rules! interesting_mutator_impl { #[derive(Default, Debug)] pub struct $name; - impl Mutator for $name + impl Mutator for $name where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { #[allow(clippy::cast_sign_loss)] fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { if input.bytes().len() < size_of::<$size>() { @@ -458,15 +458,15 @@ interesting_mutator_impl!(DwordInterestingMutator, u32, INTERESTING_32); #[derive(Default, Debug)] pub struct BytesDeleteMutator; -impl Mutator for BytesDeleteMutator +impl Mutator for BytesDeleteMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -500,15 +500,15 @@ impl BytesDeleteMutator { #[derive(Default, Debug)] pub struct BytesExpandMutator; -impl Mutator for BytesExpandMutator +impl Mutator for BytesExpandMutator where - I: Input + HasBytesVec, - S: HasRand + HasMaxSize, + S: UsesInput + HasRand + HasMaxSize, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -549,15 +549,15 @@ impl BytesExpandMutator { #[derive(Default, Debug)] pub struct BytesInsertMutator; -impl Mutator for BytesInsertMutator +impl Mutator for BytesInsertMutator where - I: Input + HasBytesVec, - S: HasRand + HasMaxSize, + S: UsesInput + HasRand + HasMaxSize, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -604,15 +604,15 @@ impl BytesInsertMutator { #[derive(Default, Debug)] pub struct BytesRandInsertMutator; -impl Mutator for BytesRandInsertMutator +impl Mutator for BytesRandInsertMutator where - I: Input + HasBytesVec, - S: HasRand + HasMaxSize, + S: UsesInput + HasRand + HasMaxSize, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -656,15 +656,15 @@ impl BytesRandInsertMutator { #[derive(Default, Debug)] pub struct BytesSetMutator; -impl Mutator for BytesSetMutator +impl Mutator for BytesSetMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -700,15 +700,15 @@ impl BytesSetMutator { #[derive(Default, Debug)] pub struct BytesRandSetMutator; -impl Mutator for BytesRandSetMutator +impl Mutator for BytesRandSetMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -744,15 +744,15 @@ impl BytesRandSetMutator { #[derive(Default, Debug)] pub struct BytesCopyMutator; -impl Mutator for BytesCopyMutator +impl Mutator for BytesCopyMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -790,15 +790,15 @@ pub struct BytesInsertCopyMutator { tmp_buf: Vec, } -impl Mutator for BytesInsertCopyMutator +impl Mutator for BytesInsertCopyMutator where - I: Input + HasBytesVec, - S: HasRand + HasMaxSize, + S: UsesInput + HasRand + HasMaxSize, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -852,15 +852,15 @@ impl BytesInsertCopyMutator { #[derive(Debug, Default)] pub struct BytesSwapMutator; -impl Mutator for BytesSwapMutator +impl Mutator for BytesSwapMutator where - I: Input + HasBytesVec, - S: HasRand, + S: UsesInput + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -898,15 +898,15 @@ impl BytesSwapMutator { #[derive(Debug, Default)] pub struct CrossoverInsertMutator; -impl Mutator for CrossoverInsertMutator +impl Mutator for CrossoverInsertMutator where - I: Input + HasBytesVec, - S: HasRand + HasCorpus + HasMaxSize, + S: HasCorpus + HasRand + HasMaxSize, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -973,15 +973,15 @@ impl CrossoverInsertMutator { #[derive(Debug, Default)] pub struct CrossoverReplaceMutator; -impl Mutator for CrossoverReplaceMutator +impl Mutator for CrossoverReplaceMutator where - I: Input + HasBytesVec, - S: HasRand + HasCorpus, + S: HasCorpus + HasRand, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -1056,16 +1056,16 @@ fn locate_diffs(this: &[u8], other: &[u8]) -> (i64, i64) { #[derive(Debug, Default)] pub struct SpliceMutator; -impl Mutator for SpliceMutator +impl Mutator for SpliceMutator where - I: Input + HasBytesVec, - S: HasRand + HasCorpus, + S: HasCorpus + HasRand, + S::Input: HasBytesVec, { #[allow(clippy::cast_sign_loss)] fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { // We don't want to use the testcase we're already using for splicing @@ -1173,15 +1173,16 @@ mod tests { tuples::{tuple_list, HasConstLen}, }, corpus::{Corpus, InMemoryCorpus}, + feedbacks::ConstFeedback, inputs::BytesInput, mutators::MutatorsTuple, state::{HasMetadata, StdState}, }; - fn test_mutations() -> impl MutatorsTuple + fn test_mutations() -> impl MutatorsTuple where - I: Input + HasBytesVec, - S: HasRand + HasCorpus + HasMetadata + HasMaxSize, + S: HasRand + HasCorpus + HasMetadata + HasMaxSize, + S::Input: HasBytesVec, { tuple_list!( BitFlipMutator::new(), @@ -1226,12 +1227,21 @@ mod tests { let rand = StdRand::with_seed(1337); let mut corpus = InMemoryCorpus::new(); + let mut feedback = ConstFeedback::new(false); + let mut objective = ConstFeedback::new(false); + corpus .add(BytesInput::new(vec![0x42; 0x1337]).into()) .unwrap(); - let mut state = - StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); + let mut state = StdState::new( + rand, + corpus, + InMemoryCorpus::new(), + &mut feedback, + &mut objective, + ) + .unwrap(); let mut mutations = test_mutations(); for _ in 0..2 { diff --git a/libafl/src/mutators/nautilus.rs b/libafl/src/mutators/nautilus.rs index 640bdb3097..9f866dc140 100644 --- a/libafl/src/mutators/nautilus.rs +++ b/libafl/src/mutators/nautilus.rs @@ -14,6 +14,7 @@ use crate::{ generators::nautilus::NautilusContext, inputs::nautilus::NautilusInput, mutators::{MutationResult, Mutator}, + prelude::UsesInput, state::{HasCorpus, HasMetadata}, Error, }; @@ -30,7 +31,10 @@ impl Debug for NautilusRandomMutator<'_> { } } -impl Mutator for NautilusRandomMutator<'_> { +impl Mutator for NautilusRandomMutator<'_> +where + S: UsesInput, +{ fn mutate( &mut self, _state: &mut S, @@ -91,7 +95,10 @@ impl Debug for NautilusRecursionMutator<'_> { } } -impl Mutator for NautilusRecursionMutator<'_> { +impl Mutator for NautilusRecursionMutator<'_> +where + S: UsesInput, +{ fn mutate( &mut self, _state: &mut S, @@ -154,9 +161,9 @@ impl Debug for NautilusSpliceMutator<'_> { } } -impl Mutator for NautilusSpliceMutator<'_> +impl Mutator for NautilusSpliceMutator<'_> where - S: HasCorpus + HasMetadata, + S: HasCorpus + HasMetadata + UsesInput, { fn mutate( &mut self, diff --git a/libafl/src/mutators/scheduled.rs b/libafl/src/mutators/scheduled.rs index 359382405d..cf97985495 100644 --- a/libafl/src/mutators/scheduled.rs +++ b/libafl/src/mutators/scheduled.rs @@ -16,9 +16,9 @@ use crate::{ AsMutSlice, AsSlice, }, corpus::Corpus, - inputs::Input, + inputs::UsesInput, mutators::{MutationResult, Mutator, MutatorsTuple}, - state::{HasCorpus, HasMetadata, HasRand}, + state::{HasCorpus, HasMetadata, HasRand, State}, Error, }; @@ -53,10 +53,10 @@ impl LogMutationMetadata { } /// A [`Mutator`] that composes multiple mutations into one. -pub trait ComposedByMutations +pub trait ComposedByMutations where - I: Input, - MT: MutatorsTuple, + MT: MutatorsTuple, + S: UsesInput, { /// Get the mutations fn mutations(&self) -> &MT; @@ -66,23 +66,23 @@ where } /// A [`Mutator`] scheduling multiple [`Mutator`]s for an input. -pub trait ScheduledMutator: ComposedByMutations + Mutator +pub trait ScheduledMutator: ComposedByMutations + Mutator where - I: Input, - MT: MutatorsTuple, + MT: MutatorsTuple, + S: UsesInput, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, input: &I) -> u64; + fn iterations(&self, state: &mut S, input: &S::Input) -> u64; /// Get the next mutation to apply - fn schedule(&self, state: &mut S, input: &I) -> usize; + fn schedule(&self, state: &mut S, input: &S::Input) -> usize; /// New default implementation for mutate. /// Implementations must forward mutate() to this method fn scheduled_mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result { let mut r = MutationResult::Skipped; @@ -101,55 +101,51 @@ where } /// A [`Mutator`] that schedules one of the embedded mutations on each call. -pub struct StdScheduledMutator +pub struct StdScheduledMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand, + MT: MutatorsTuple, + S: State + HasRand, { mutations: MT, max_stack_pow: u64, - phantom: PhantomData<(I, S)>, + phantom: PhantomData, } -impl Debug for StdScheduledMutator +impl Debug for StdScheduledMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand, + MT: MutatorsTuple, + S: State + HasRand, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "StdScheduledMutator with {} mutations for Input type {}", self.mutations.len(), - core::any::type_name::() + core::any::type_name::() ) } } -impl Mutator for StdScheduledMutator +impl Mutator for StdScheduledMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand, + MT: MutatorsTuple, + S: State + HasRand, { #[inline] fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, stage_idx: i32, ) -> Result { self.scheduled_mutate(state, input, stage_idx) } } -impl ComposedByMutations for StdScheduledMutator +impl ComposedByMutations for StdScheduledMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand, + MT: MutatorsTuple, + S: State + HasRand, { /// Get the mutations #[inline] @@ -164,29 +160,27 @@ where } } -impl ScheduledMutator for StdScheduledMutator +impl ScheduledMutator for StdScheduledMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand, + MT: MutatorsTuple, + S: State + HasRand, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &I) -> u64 { + fn iterations(&self, state: &mut S, _: &S::Input) -> u64 { 1 << (1 + state.rand_mut().below(self.max_stack_pow)) } /// Get the next mutation to apply - fn schedule(&self, state: &mut S, _: &I) -> usize { + fn schedule(&self, state: &mut S, _: &S::Input) -> usize { debug_assert!(!self.mutations().is_empty()); state.rand_mut().below(self.mutations().len() as u64) as usize } } -impl StdScheduledMutator +impl StdScheduledMutator where - I: Input, - MT: MutatorsTuple, - S: HasRand, + MT: MutatorsTuple, + S: State + HasRand, { /// Create a new [`StdScheduledMutator`] instance specifying mutations pub fn new(mutations: MT) -> Self { @@ -279,46 +273,43 @@ pub fn tokens_mutations() -> tuple_list_type!(TokenInsert, TokenReplace) { } /// A logging [`Mutator`] that wraps around a [`StdScheduledMutator`]. -pub struct LoggerScheduledMutator +pub struct LoggerScheduledMutator where - I: Input, - MT: MutatorsTuple + NamedTuple, - S: HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: UsesInput + HasRand + HasCorpus, + SM: ScheduledMutator, { scheduled: SM, mutation_log: Vec, - phantom: PhantomData<(I, MT, S)>, + phantom: PhantomData<(MT, S)>, } -impl Debug for LoggerScheduledMutator +impl Debug for LoggerScheduledMutator where - I: Input, - MT: MutatorsTuple + NamedTuple, - S: HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: UsesInput + HasRand + HasCorpus, + SM: ScheduledMutator, { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!( f, "LoggerScheduledMutator with {} mutations for Input type {}", self.scheduled.mutations().len(), - core::any::type_name::() + core::any::type_name::<::Input>() ) } } -impl Mutator for LoggerScheduledMutator +impl Mutator for LoggerScheduledMutator where - I: Input, - MT: MutatorsTuple + NamedTuple, - S: HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: State + HasRand + HasCorpus, + SM: ScheduledMutator, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut ::Input, stage_idx: i32, ) -> Result { self.scheduled_mutate(state, input, stage_idx) @@ -346,12 +337,11 @@ where } } -impl ComposedByMutations for LoggerScheduledMutator +impl ComposedByMutations for LoggerScheduledMutator where - I: Input, - MT: MutatorsTuple + NamedTuple, - S: HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: State + HasRand + HasCorpus, + SM: ScheduledMutator, { #[inline] fn mutations(&self) -> &MT { @@ -364,20 +354,19 @@ where } } -impl ScheduledMutator for LoggerScheduledMutator +impl ScheduledMutator for LoggerScheduledMutator where - I: Input, - MT: MutatorsTuple + NamedTuple, - S: HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: State + HasRand + HasCorpus, + SM: ScheduledMutator, { /// Compute the number of iterations used to apply stacked mutations - fn iterations(&self, state: &mut S, _: &I) -> u64 { + fn iterations(&self, state: &mut S, _: &::Input) -> u64 { 1 << (1 + state.rand_mut().below(6)) } /// Get the next mutation to apply - fn schedule(&self, state: &mut S, _: &I) -> usize { + fn schedule(&self, state: &mut S, _: &::Input) -> usize { debug_assert!(!self.scheduled.mutations().is_empty()); state .rand_mut() @@ -387,7 +376,7 @@ where fn scheduled_mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut ::Input, stage_idx: i32, ) -> Result { let mut r = MutationResult::Skipped; @@ -407,12 +396,11 @@ where } } -impl LoggerScheduledMutator +impl LoggerScheduledMutator where - I: Input, - MT: MutatorsTuple + NamedTuple, - S: HasRand + HasCorpus, - SM: ScheduledMutator, + MT: MutatorsTuple + NamedTuple, + S: State + HasRand + HasCorpus, + SM: ScheduledMutator, { /// Create a new [`StdScheduledMutator`] instance without mutations and corpus pub fn new(scheduled: SM) -> Self { @@ -429,6 +417,7 @@ mod tests { use crate::{ bolts::rands::{Rand, StdRand, XkcdRand}, corpus::{Corpus, InMemoryCorpus, Testcase}, + feedbacks::ConstFeedback, inputs::{BytesInput, HasBytesVec}, mutators::{ mutations::SpliceMutator, @@ -443,14 +432,27 @@ mod tests { // With the current impl, seed of 1 will result in a split at pos 2. let mut rand = XkcdRand::with_seed(5); let mut corpus: InMemoryCorpus = InMemoryCorpus::new(); - corpus.add(Testcase::new(vec![b'a', b'b', b'c'])).unwrap(); - corpus.add(Testcase::new(vec![b'd', b'e', b'f'])).unwrap(); + corpus + .add(Testcase::new(vec![b'a', b'b', b'c'].into())) + .unwrap(); + corpus + .add(Testcase::new(vec![b'd', b'e', b'f'].into())) + .unwrap(); let testcase = corpus.get(0).expect("Corpus did not contain entries"); let mut input = testcase.borrow_mut().load_input().unwrap().clone(); - let mut state = - StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); + let mut feedback = ConstFeedback::new(false); + let mut objective = ConstFeedback::new(false); + + let mut state = StdState::new( + rand, + corpus, + InMemoryCorpus::new(), + &mut feedback, + &mut objective, + ) + .unwrap(); rand.set_seed(5); @@ -470,15 +472,28 @@ mod tests { // With the current impl, seed of 1 will result in a split at pos 2. let rand = StdRand::with_seed(0x1337); let mut corpus: InMemoryCorpus = InMemoryCorpus::new(); - corpus.add(Testcase::new(vec![b'a', b'b', b'c'])).unwrap(); - corpus.add(Testcase::new(vec![b'd', b'e', b'f'])).unwrap(); + corpus + .add(Testcase::new(vec![b'a', b'b', b'c'].into())) + .unwrap(); + corpus + .add(Testcase::new(vec![b'd', b'e', b'f'].into())) + .unwrap(); let testcase = corpus.get(0).expect("Corpus did not contain entries"); let mut input = testcase.borrow_mut().load_input().unwrap().clone(); let input_prior = input.clone(); - let mut state = - StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); + let mut feedback = ConstFeedback::new(false); + let mut objective = ConstFeedback::new(false); + + let mut state = StdState::new( + rand, + corpus, + InMemoryCorpus::new(), + &mut feedback, + &mut objective, + ) + .unwrap(); let mut havoc = StdScheduledMutator::new(havoc_mutations()); @@ -507,16 +522,14 @@ pub mod pybind { use pyo3::prelude::*; use super::{havoc_mutations, Debug, HavocMutationsType, StdScheduledMutator}; - use crate::{ - inputs::BytesInput, mutators::pybind::PythonMutator, state::pybind::PythonStdState, - }; + use crate::{mutators::pybind::PythonMutator, state::pybind::PythonStdState}; #[pyclass(unsendable, name = "StdHavocMutator")] #[derive(Debug)] /// Python class for StdHavocMutator pub struct PythonStdHavocMutator { /// Rust wrapped StdHavocMutator object - pub inner: StdScheduledMutator, + pub inner: StdScheduledMutator, } #[pymethods] diff --git a/libafl/src/mutators/token_mutations.rs b/libafl/src/mutators/token_mutations.rs index 448ad68639..725ccfec47 100644 --- a/libafl/src/mutators/token_mutations.rs +++ b/libafl/src/mutators/token_mutations.rs @@ -22,7 +22,7 @@ use serde::{Deserialize, Serialize}; use crate::mutators::str_decode; use crate::{ bolts::{rands::Rand, AsSlice}, - inputs::{HasBytesVec, Input}, + inputs::{HasBytesVec, UsesInput}, mutators::{buffer_self_copy, mutations::buffer_copy, MutationResult, Mutator, Named}, observers::cmp::{CmpValues, CmpValuesMetadata}, state::{HasMaxSize, HasMetadata, HasRand}, @@ -295,15 +295,15 @@ impl<'it> IntoIterator for &'it Tokens { #[derive(Debug, Default)] pub struct TokenInsert; -impl Mutator for TokenInsert +impl Mutator for TokenInsert where - I: Input + HasBytesVec, - S: HasMetadata + HasRand + HasMaxSize, + S: UsesInput + HasMetadata + HasRand + HasMaxSize, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let max_size = state.max_size(); @@ -361,15 +361,15 @@ impl TokenInsert { #[derive(Debug, Default)] pub struct TokenReplace; -impl Mutator for TokenReplace +impl Mutator for TokenReplace where - I: Input + HasBytesVec, - S: HasMetadata + HasRand + HasMaxSize, + S: UsesInput + HasMetadata + HasRand + HasMaxSize, + S::Input: HasBytesVec, { fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); @@ -423,16 +423,16 @@ impl TokenReplace { #[derive(Debug, Default)] pub struct I2SRandReplace; -impl Mutator for I2SRandReplace +impl Mutator for I2SRandReplace where - I: Input + HasBytesVec, - S: HasMetadata + HasRand + HasMaxSize, + S: UsesInput + HasMetadata + HasRand + HasMaxSize, + S::Input: HasBytesVec, { #[allow(clippy::too_many_lines)] fn mutate( &mut self, state: &mut S, - input: &mut I, + input: &mut S::Input, _stage_idx: i32, ) -> Result { let size = input.bytes().len(); diff --git a/libafl/src/observers/cmp.rs b/libafl/src/observers/cmp.rs index f40b59cc62..7ce3e6fdb1 100644 --- a/libafl/src/observers/cmp.rs +++ b/libafl/src/observers/cmp.rs @@ -4,12 +4,13 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -use core::fmt::Debug; +use core::{fmt::Debug, marker::PhantomData}; use serde::{de::DeserializeOwned, Deserialize, Serialize}; use crate::{ bolts::{ownedref::OwnedRefMut, tuples::Named, AsMutSlice, AsSlice}, + inputs::UsesInput, observers::Observer, state::HasMetadata, Error, @@ -111,9 +112,10 @@ pub trait CmpMap: Debug { } /// A [`CmpObserver`] observes the traced comparisons during the current execution using a [`CmpMap`] -pub trait CmpObserver: Observer +pub trait CmpObserver: Observer where CM: CmpMap, + S: UsesInput, { /// Get the number of usable cmps (all by default) fn usable_count(&self) -> usize; @@ -194,18 +196,21 @@ where /// A standard [`CmpObserver`] observer #[derive(Serialize, Deserialize, Debug)] #[serde(bound = "CM: serde::de::DeserializeOwned")] -pub struct StdCmpObserver<'a, CM> +pub struct StdCmpObserver<'a, CM, S> where CM: CmpMap + Serialize, + S: UsesInput, { cmp_map: OwnedRefMut<'a, CM>, size: Option>, name: String, + phantom: PhantomData, } -impl<'a, CM, I, S> CmpObserver for StdCmpObserver<'a, CM> +impl<'a, CM, S> CmpObserver for StdCmpObserver<'a, CM, S> where CM: CmpMap + Serialize + DeserializeOwned, + S: UsesInput + Debug, { /// Get the number of usable cmps (all by default) fn usable_count(&self) -> usize { @@ -224,28 +229,31 @@ where } } -impl<'a, CM, I, S> Observer for StdCmpObserver<'a, CM> +impl<'a, CM, S> Observer for StdCmpObserver<'a, CM, S> where CM: CmpMap + Serialize + DeserializeOwned, + S: UsesInput + Debug, { - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.cmp_map.as_mut().reset()?; Ok(()) } } -impl<'a, CM> Named for StdCmpObserver<'a, CM> +impl<'a, CM, S> Named for StdCmpObserver<'a, CM, S> where CM: CmpMap + Serialize + DeserializeOwned, + S: UsesInput, { fn name(&self) -> &str { &self.name } } -impl<'a, CM> StdCmpObserver<'a, CM> +impl<'a, CM, S> StdCmpObserver<'a, CM, S> where CM: CmpMap + Serialize + DeserializeOwned, + S: UsesInput, { /// Creates a new [`StdCmpObserver`] with the given name and map. #[must_use] @@ -254,6 +262,7 @@ where name: name.to_string(), size: None, cmp_map: OwnedRefMut::Ref(map), + phantom: PhantomData, } } @@ -264,6 +273,7 @@ where name: name.to_string(), size: Some(OwnedRefMut::Ref(size)), cmp_map: OwnedRefMut::Ref(map), + phantom: PhantomData, } } } diff --git a/libafl/src/observers/concolic/observer.rs b/libafl/src/observers/concolic/observer.rs index 4bc63b36af..7f95cb227e 100644 --- a/libafl/src/observers/concolic/observer.rs +++ b/libafl/src/observers/concolic/observer.rs @@ -4,6 +4,7 @@ use serde::{Deserialize, Serialize}; use crate::{ bolts::tuples::Named, + inputs::UsesInput, observers::{ concolic::{serialization_format::MessageFileReader, ConcolicMetadata}, Observer, @@ -18,7 +19,7 @@ pub struct ConcolicObserver<'map> { name: String, } -impl<'map, I, S> Observer for ConcolicObserver<'map> {} +impl<'map, S> Observer for ConcolicObserver<'map> where S: UsesInput {} impl<'map> ConcolicObserver<'map> { /// Create the concolic observer metadata for this run diff --git a/libafl/src/observers/map.rs b/libafl/src/observers/map.rs index 5afea59d9f..8bb5a55c29 100644 --- a/libafl/src/observers/map.rs +++ b/libafl/src/observers/map.rs @@ -24,6 +24,7 @@ use crate::{ AsIter, AsIterMut, AsMutSlice, AsSlice, HasLen, }, executors::ExitKind, + inputs::UsesInput, observers::Observer, Error, }; @@ -198,8 +199,9 @@ where name: String, } -impl<'a, I, S, T> Observer for StdMapObserver<'a, T> +impl<'a, S, T> Observer for StdMapObserver<'a, T> where + S: UsesInput, T: Bounded + PartialEq + Default @@ -210,7 +212,7 @@ where + Debug, { #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.reset_map() } } @@ -499,13 +501,14 @@ where name: String, } -impl<'a, I, S, T, const N: usize> Observer for ConstMapObserver<'a, T, N> +impl<'a, S, T, const N: usize> Observer for ConstMapObserver<'a, T, N> where + S: UsesInput, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, Self: MapObserver, { #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.reset_map() } } @@ -770,13 +773,14 @@ where name: String, } -impl<'a, I, S, T> Observer for VariableMapObserver<'a, T> +impl<'a, S, T> Observer for VariableMapObserver<'a, T> where + S: UsesInput, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, Self: MapObserver, { #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.reset_map() } } @@ -1038,18 +1042,24 @@ where base: M, } -impl Observer for HitcountsMapObserver +impl Observer for HitcountsMapObserver where - M: MapObserver + Observer + AsMutSlice, + M: MapObserver + Observer + AsMutSlice, + S: UsesInput, { #[inline] - fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { self.base.pre_exec(state, input) } #[inline] #[allow(clippy::cast_ptr_alignment)] - fn post_exec(&mut self, state: &mut S, input: &I, exit_kind: &ExitKind) -> Result<(), Error> { + fn post_exec( + &mut self, + state: &mut S, + input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { let map = self.as_mut_slice(); let len = map.len(); if (len & 1) != 0 { @@ -1237,19 +1247,25 @@ where base: M, } -impl Observer for HitcountsIterableMapObserver +impl Observer for HitcountsIterableMapObserver where - M: MapObserver + Observer, + M: MapObserver + Observer, for<'it> M: AsIterMut<'it, Item = u8>, + S: UsesInput, { #[inline] - fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { self.base.pre_exec(state, input) } #[inline] #[allow(clippy::cast_ptr_alignment)] - fn post_exec(&mut self, state: &mut S, input: &I, exit_kind: &ExitKind) -> Result<(), Error> { + fn post_exec( + &mut self, + state: &mut S, + input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { for item in self.as_iter_mut() { *item = unsafe { *COUNT_CLASS_LOOKUP.get_unchecked((*item) as usize) }; } @@ -1429,13 +1445,14 @@ where iter_idx: usize, } -impl<'a, I, S, T> Observer for MultiMapObserver<'a, T> +impl<'a, S, T> Observer for MultiMapObserver<'a, T> where + S: UsesInput, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, Self: MapObserver, { #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.reset_map() } } @@ -1685,13 +1702,14 @@ where name: String, } -impl Observer for OwnedMapObserver +impl Observer for OwnedMapObserver where + S: UsesInput, T: Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, Self: MapObserver, { #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.reset_map() } } @@ -1904,7 +1922,7 @@ pub mod pybind { AsIter, AsIterMut, AsMutSlice, AsSlice, Debug, Error, HasLen, Iter, IterMut, MapObserver, Named, Observer, OwnedMapObserver, StdMapObserver, String, Vec, }; - use crate::observers::pybind::PythonObserver; + use crate::{inputs::UsesInput, observers::pybind::PythonObserver}; #[macro_export] macro_rules! mapob_unwrap_me { @@ -2240,12 +2258,13 @@ pub mod pybind { } } - impl Observer for $struct_name_trait + impl Observer for $struct_name_trait where Self: MapObserver, + S: UsesInput, { #[inline] - fn pre_exec(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { mapob_unwrap_me_mut!($wrapper_name, self.wrapper, m, { m.pre_exec(state, input) }) } } diff --git a/libafl/src/observers/mod.rs b/libafl/src/observers/mod.rs index b5e6fad90d..3eaedc1bdb 100644 --- a/libafl/src/observers/mod.rs +++ b/libafl/src/observers/mod.rs @@ -39,12 +39,17 @@ use crate::{ tuples::{MatchName, Named}, }, executors::ExitKind, + inputs::UsesInput, + state::UsesState, Error, }; /// Observers observe different information about the target. /// They can then be used by various sorts of feedback. -pub trait Observer: Named + Debug { +pub trait Observer: Named + Debug +where + S: UsesInput, +{ /// The testcase finished execution, calculate any changes. /// Reserved for future use. #[inline] @@ -54,7 +59,7 @@ pub trait Observer: Named + Debug { /// Called right before execution starts. #[inline] - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { Ok(()) } @@ -63,7 +68,7 @@ pub trait Observer: Named + Debug { fn post_exec( &mut self, _state: &mut S, - _input: &I, + _input: &S::Input, _exit_kind: &ExitKind, ) -> Result<(), Error> { Ok(()) @@ -71,7 +76,7 @@ pub trait Observer: Named + Debug { /// Called right before execution starts in the child process, if any. #[inline] - fn pre_exec_child(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec_child(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { Ok(()) } @@ -80,7 +85,7 @@ pub trait Observer: Named + Debug { fn post_exec_child( &mut self, _state: &mut S, - _input: &I, + _input: &S::Input, _exit_kind: &ExitKind, ) -> Result<(), Error> { Ok(()) @@ -109,27 +114,37 @@ pub trait Observer: Named + Debug { fn observe_stderr(&mut self, stderr: &str) {} } +/// Defines the observer type shared across traits of the type. +/// Needed for consistency across HasCorpus/HasSolutions and friends. +pub trait UsesObservers: UsesState { + /// The observers type + type Observers: ObserversTuple; +} + /// A haskell-style tuple of observers -pub trait ObserversTuple: MatchName + Debug { +pub trait ObserversTuple: MatchName + Debug +where + S: UsesInput, +{ /// This is called right before the next execution. - fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error>; + fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error>; /// This is called right after the last execution fn post_exec_all( &mut self, state: &mut S, - input: &I, + input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error>; /// This is called right before the next execution in the child process, if any. - fn pre_exec_child_all(&mut self, state: &mut S, input: &I) -> Result<(), Error>; + fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error>; /// This is called right after the last execution in the child process, if any. fn post_exec_child_all( &mut self, state: &mut S, - input: &I, + input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error>; @@ -144,28 +159,31 @@ pub trait ObserversTuple: MatchName + Debug { fn observe_stderr(&mut self, stderr: &str); } -impl ObserversTuple for () { - fn pre_exec_all(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { +impl ObserversTuple for () +where + S: UsesInput, +{ + fn pre_exec_all(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { Ok(()) } fn post_exec_all( &mut self, _state: &mut S, - _input: &I, + _input: &S::Input, _exit_kind: &ExitKind, ) -> Result<(), Error> { Ok(()) } - fn pre_exec_child_all(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec_child_all(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { Ok(()) } fn post_exec_child_all( &mut self, _state: &mut S, - _input: &I, + _input: &S::Input, _exit_kind: &ExitKind, ) -> Result<(), Error> { Ok(()) @@ -192,12 +210,13 @@ impl ObserversTuple for () { fn observe_stderr(&mut self, stderr: &str) {} } -impl ObserversTuple for (Head, Tail) +impl ObserversTuple for (Head, Tail) where - Head: Observer, - Tail: ObserversTuple, + Head: Observer, + Tail: ObserversTuple, + S: UsesInput, { - fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn pre_exec_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { self.0.pre_exec(state, input)?; self.1.pre_exec_all(state, input) } @@ -205,14 +224,14 @@ where fn post_exec_all( &mut self, state: &mut S, - input: &I, + input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error> { self.0.post_exec(state, input, exit_kind)?; self.1.post_exec_all(state, input, exit_kind) } - fn pre_exec_child_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { + fn pre_exec_child_all(&mut self, state: &mut S, input: &S::Input) -> Result<(), Error> { self.0.pre_exec_child(state, input)?; self.1.pre_exec_child_all(state, input) } @@ -220,7 +239,7 @@ where fn post_exec_child_all( &mut self, state: &mut S, - input: &I, + input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error> { self.0.post_exec_child(state, input, exit_kind)?; @@ -286,8 +305,11 @@ impl TimeObserver { } } -impl Observer for TimeObserver { - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { +impl Observer for TimeObserver +where + S: UsesInput, +{ + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.last_runtime = None; self.start_time = current_time(); Ok(()) @@ -296,7 +318,7 @@ impl Observer for TimeObserver { fn post_exec( &mut self, _state: &mut S, - _input: &I, + _input: &S::Input, _exit_kind: &ExitKind, ) -> Result<(), Error> { self.last_runtime = current_time().checked_sub(self.start_time); @@ -348,11 +370,12 @@ where } } -impl<'a, I, S, T> Observer for ListObserver<'a, T> +impl<'a, S, T> Observer for ListObserver<'a, T> where + S: UsesInput, T: Debug + Serialize + serde::de::DeserializeOwned, { - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.list.as_mut().clear(); Ok(()) } @@ -433,7 +456,7 @@ pub mod pybind { } } - impl Observer for PyObjectObserver { + impl Observer for PyObjectObserver { fn flush(&mut self) -> Result<(), Error> { Python::with_gil(|py| -> PyResult<()> { self.inner.call_method0(py, "flush")?; @@ -827,11 +850,9 @@ pub mod pybind { } } - impl Observer for PythonObserver { + impl Observer for PythonObserver { fn flush(&mut self) -> Result<(), Error> { - unwrap_me_mut!(self.wrapper, o, { - Observer::::flush(o) - }) + unwrap_me_mut!(self.wrapper, o, { Observer::::flush(o) }) } fn pre_exec( @@ -904,7 +925,7 @@ pub mod pybind { } } - impl ObserversTuple for PythonObserversTuple { + impl ObserversTuple for PythonObserversTuple { fn pre_exec_all( &mut self, state: &mut PythonStdState, diff --git a/libafl/src/observers/owned.rs b/libafl/src/observers/owned.rs index 9b2e8bc331..7e336c86e2 100644 --- a/libafl/src/observers/owned.rs +++ b/libafl/src/observers/owned.rs @@ -67,7 +67,7 @@ impl<'de, I: 'static + Debug, S: 'static + Debug> Deserialize<'de> for Observers } } -impl ObserversTuple for ObserversOwnedMap { +impl ObserversTuple for ObserversOwnedMap { fn pre_exec_all(&mut self, state: &mut S, input: &I) -> Result<(), Error> { self.map .for_each_mut(&mut |_, ob| ob.pre_exec(state, input)) diff --git a/libafl/src/observers/stacktrace.rs b/libafl/src/observers/stacktrace.rs index b1365ab6af..e3585648ff 100644 --- a/libafl/src/observers/stacktrace.rs +++ b/libafl/src/observers/stacktrace.rs @@ -17,7 +17,7 @@ use super::ObserverWithHashField; use crate::{ bolts::{ownedref::OwnedRefMut, tuples::Named}, executors::ExitKind, - inputs::Input, + inputs::UsesInput, observers::Observer, Error, }; @@ -97,11 +97,16 @@ impl<'a> ObserverWithHashField for BacktraceObserver<'a> { } } -impl<'a, I, S> Observer for BacktraceObserver<'a> +impl<'a, S> Observer for BacktraceObserver<'a> where - I: Input + Debug, + S: UsesInput, { - fn post_exec(&mut self, _state: &mut S, _input: &I, exit_kind: &ExitKind) -> Result<(), Error> { + fn post_exec( + &mut self, + _state: &mut S, + _input: &S::Input, + exit_kind: &ExitKind, + ) -> Result<(), Error> { if self.harness_type == HarnessType::InProcess { if exit_kind == &ExitKind::Crash { self.update_hash(collect_backtrace()); @@ -115,7 +120,7 @@ where fn post_exec_child( &mut self, _state: &mut S, - _input: &I, + _input: &S::Input, exit_kind: &ExitKind, ) -> Result<(), Error> { if self.harness_type == HarnessType::Child { @@ -240,18 +245,18 @@ impl Default for AsanBacktraceObserver { } } -impl Observer for AsanBacktraceObserver +impl Observer for AsanBacktraceObserver where - I: Debug, + S: UsesInput, { - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { Ok(()) } fn post_exec( &mut self, _state: &mut S, - _input: &I, + _input: &S::Input, _exit_kind: &ExitKind, ) -> Result<(), Error> { Ok(()) diff --git a/libafl/src/observers/stdio.rs b/libafl/src/observers/stdio.rs index 074a73d346..7ef35003a7 100644 --- a/libafl/src/observers/stdio.rs +++ b/libafl/src/observers/stdio.rs @@ -6,7 +6,7 @@ use alloc::string::String; use serde::{Deserialize, Serialize}; -use crate::{bolts::tuples::Named, observers::Observer}; +use crate::{bolts::tuples::Named, inputs::UsesInput, observers::Observer}; /// An observer that captures stdout of a target. /// Only works for supported executors. @@ -27,7 +27,10 @@ impl StdOutObserver { } } -impl Observer for StdOutObserver { +impl Observer for StdOutObserver +where + S: UsesInput, +{ #[inline] fn observes_stdout(&mut self) -> bool { true @@ -63,7 +66,10 @@ impl StdErrObserver { } } -impl Observer for StdErrObserver { +impl Observer for StdErrObserver +where + S: UsesInput, +{ #[inline] fn observes_stderr(&mut self) -> bool { true diff --git a/libafl/src/schedulers/accounting.rs b/libafl/src/schedulers/accounting.rs index eec2dd0133..ceb25690df 100644 --- a/libafl/src/schedulers/accounting.rs +++ b/libafl/src/schedulers/accounting.rs @@ -1,6 +1,7 @@ //! Coverage accounting corpus scheduler, more details at use alloc::vec::Vec; +use core::fmt::Debug; use hashbrown::HashMap; use serde::{Deserialize, Serialize}; @@ -9,12 +10,12 @@ use crate::{ bolts::{rands::Rand, AsMutSlice, AsSlice, HasLen, HasRefCnt}, corpus::{Corpus, Testcase}, feedbacks::MapIndexesMetadata, - inputs::Input, + inputs::UsesInput, schedulers::{ minimizer::{IsFavoredMetadata, MinimizerScheduler, DEFAULT_SKIP_NON_FAVORED_PROB}, LenTimeMulTestcaseScore, Scheduler, }, - state::{HasCorpus, HasMetadata, HasRand}, + state::{HasCorpus, HasMetadata, HasRand, UsesState}, Error, }; @@ -93,42 +94,58 @@ impl TopAccountingMetadata { /// A minimizer scheduler using coverage accounting #[derive(Debug)] -pub struct CoverageAccountingScheduler<'a, CS, I, S> +pub struct CoverageAccountingScheduler<'a, CS> where - CS: Scheduler, - I: Input + HasLen, - S: HasCorpus + HasMetadata + HasRand, + CS: UsesState, + CS::State: Debug, { accounting_map: &'a [u32], skip_non_favored_prob: u64, - inner: MinimizerScheduler, I, MapIndexesMetadata, S>, + inner: MinimizerScheduler< + CS, + LenTimeMulTestcaseScore<::State>, + MapIndexesMetadata, + >, } -impl<'a, CS, I, S> Scheduler for CoverageAccountingScheduler<'a, CS, I, S> +impl<'a, CS> UsesState for CoverageAccountingScheduler<'a, CS> where - CS: Scheduler, - I: Input + HasLen, - S: HasCorpus + HasMetadata + HasRand, + CS: UsesState, + CS::State: Debug, { - fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { + type State = CS::State; +} + +impl<'a, CS> Scheduler for CoverageAccountingScheduler<'a, CS> +where + CS: Scheduler, + CS::State: HasCorpus + HasMetadata + HasRand + Debug, + ::Input: HasLen, +{ + fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> { self.update_accounting_score(state, idx)?; self.inner.on_add(state, idx) } - fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> { + fn on_replace( + &self, + state: &mut Self::State, + idx: usize, + testcase: &Testcase<::Input>, + ) -> Result<(), Error> { self.inner.on_replace(state, idx, testcase) } fn on_remove( &self, - state: &mut S, + state: &mut Self::State, idx: usize, - testcase: &Option>, + testcase: &Option::Input>>, ) -> Result<(), Error> { self.inner.on_remove(state, idx, testcase) } - fn next(&self, state: &mut S) -> Result { + fn next(&self, state: &mut Self::State) -> Result { if state .metadata() .get::() @@ -154,16 +171,16 @@ where } } -impl<'a, CS, I, S> CoverageAccountingScheduler<'a, CS, I, S> +impl<'a, CS> CoverageAccountingScheduler<'a, CS> where - CS: Scheduler, - I: Input + HasLen, - S: HasCorpus + HasMetadata + HasRand, + CS: Scheduler, + CS::State: HasCorpus + HasMetadata + HasRand + Debug, + ::Input: HasLen, { /// Update the `Corpus` score #[allow(clippy::unused_self)] #[allow(clippy::cast_possible_wrap)] - pub fn update_accounting_score(&self, state: &mut S, idx: usize) -> Result<(), Error> { + pub fn update_accounting_score(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> { let mut indexes = vec![]; let mut new_favoreds = vec![]; { @@ -243,7 +260,7 @@ where /// Cull the `Corpus` #[allow(clippy::unused_self)] - pub fn accounting_cull(&self, state: &mut S) -> Result<(), Error> { + pub fn accounting_cull(&self, state: &mut CS::State) -> Result<(), Error> { let top_rated = match state.metadata().get::() { None => return Ok(()), Some(val) => val, @@ -263,7 +280,7 @@ where /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// and has a default probability to skip non-faved [`Testcase`]s of [`DEFAULT_SKIP_NON_FAVORED_PROB`]. - pub fn new(state: &mut S, base: CS, accounting_map: &'a [u32]) -> Self { + pub fn new(state: &mut CS::State, base: CS, accounting_map: &'a [u32]) -> Self { match state.metadata().get::() { Some(meta) => { if meta.max_accounting.len() != accounting_map.len() { @@ -284,7 +301,7 @@ where /// Creates a new [`CoverageAccountingScheduler`] that wraps a `base` [`Scheduler`] /// and has a non-default probability to skip non-faved [`Testcase`]s using (`skip_non_favored_prob`). pub fn with_skip_prob( - state: &mut S, + state: &mut CS::State, base: CS, skip_non_favored_prob: u64, accounting_map: &'a [u32], diff --git a/libafl/src/schedulers/minimizer.rs b/libafl/src/schedulers/minimizer.rs index c82512b191..6c171c1628 100644 --- a/libafl/src/schedulers/minimizer.rs +++ b/libafl/src/schedulers/minimizer.rs @@ -11,9 +11,9 @@ use crate::{ bolts::{rands::Rand, serdeany::SerdeAny, AsSlice, HasRefCnt}, corpus::{Corpus, Testcase}, feedbacks::MapIndexesMetadata, - inputs::Input, + inputs::UsesInput, schedulers::{LenTimeMulTestcaseScore, Scheduler, TestcaseScore}, - state::{HasCorpus, HasMetadata, HasRand}, + state::{HasCorpus, HasMetadata, HasRand, UsesState}, Error, }; @@ -61,44 +61,48 @@ impl Default for TopRatedsMetadata { /// corpus that exercise all the requested features (e.g. all the coverage seen so far) /// prioritizing [`Testcase`]`s` using [`TestcaseScore`] #[derive(Debug, Clone)] -pub struct MinimizerScheduler -where - CS: Scheduler, - F: TestcaseScore, - I: Input, - M: AsSlice + SerdeAny + HasRefCnt, - S: HasCorpus + HasMetadata, -{ +pub struct MinimizerScheduler { base: CS, skip_non_favored_prob: u64, - phantom: PhantomData<(F, I, M, S)>, + phantom: PhantomData<(F, M)>, } -impl Scheduler for MinimizerScheduler +impl UsesState for MinimizerScheduler where - CS: Scheduler, - F: TestcaseScore, - I: Input, + CS: UsesState, +{ + type State = CS::State; +} + +impl Scheduler for MinimizerScheduler +where + CS: Scheduler, + F: TestcaseScore, M: AsSlice + SerdeAny + HasRefCnt, - S: HasCorpus + HasMetadata + HasRand, + CS::State: HasCorpus + HasMetadata + HasRand, { /// Add an entry to the corpus and return its index - fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { + fn on_add(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> { self.update_score(state, idx)?; self.base.on_add(state, idx) } /// Replaces the testcase at the given idx - fn on_replace(&self, state: &mut S, idx: usize, testcase: &Testcase) -> Result<(), Error> { + fn on_replace( + &self, + state: &mut CS::State, + idx: usize, + testcase: &Testcase<::Input>, + ) -> Result<(), Error> { self.base.on_replace(state, idx, testcase) } /// Removes an entry from the corpus, returning M if M was present. fn on_remove( &self, - state: &mut S, + state: &mut CS::State, idx: usize, - testcase: &Option>, + testcase: &Option::Input>>, ) -> Result<(), Error> { self.base.on_remove(state, idx, testcase)?; let mut entries = if let Some(meta) = state.metadata_mut().get_mut::() { @@ -164,7 +168,7 @@ where } /// Gets the next entry - fn next(&self, state: &mut S) -> Result { + fn next(&self, state: &mut CS::State) -> Result { self.cull(state)?; let mut idx = self.base.next(state)?; while { @@ -182,18 +186,17 @@ where } } -impl MinimizerScheduler +impl MinimizerScheduler where - CS: Scheduler, - F: TestcaseScore, - I: Input, + CS: Scheduler, + F: TestcaseScore, M: AsSlice + SerdeAny + HasRefCnt, - S: HasCorpus + HasMetadata + HasRand, + CS::State: HasCorpus + HasMetadata + HasRand, { /// Update the `Corpus` score using the `MinimizerScheduler` #[allow(clippy::unused_self)] #[allow(clippy::cast_possible_wrap)] - pub fn update_score(&self, state: &mut S, idx: usize) -> Result<(), Error> { + pub fn update_score(&self, state: &mut CS::State, idx: usize) -> Result<(), Error> { // Create a new top rated meta if not existing if state.metadata().get::().is_none() { state.add_metadata(TopRatedsMetadata::new()); @@ -269,7 +272,7 @@ where /// Cull the `Corpus` using the `MinimizerScheduler` #[allow(clippy::unused_self)] - pub fn cull(&self, state: &mut S) -> Result<(), Error> { + pub fn cull(&self, state: &mut CS::State) -> Result<(), Error> { let top_rated = match state.metadata().get::() { None => return Ok(()), Some(val) => val, @@ -324,10 +327,10 @@ where } /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s`. -pub type LenTimeMinimizerScheduler = - MinimizerScheduler, I, M, S>; +pub type LenTimeMinimizerScheduler = + MinimizerScheduler::State>, M>; /// A [`MinimizerScheduler`] with [`LenTimeMulTestcaseScore`] to prioritize quick and small [`Testcase`]`s` /// that exercise all the entries registered in the [`MapIndexesMetadata`]. -pub type IndexesLenTimeMinimizerScheduler = - MinimizerScheduler, I, MapIndexesMetadata, S>; +pub type IndexesLenTimeMinimizerScheduler = + MinimizerScheduler::State>, MapIndexesMetadata>; diff --git a/libafl/src/schedulers/mod.rs b/libafl/src/schedulers/mod.rs index 0f072f7fd0..238bd03d09 100644 --- a/libafl/src/schedulers/mod.rs +++ b/libafl/src/schedulers/mod.rs @@ -1,6 +1,8 @@ //! Schedule the access to the Corpus. pub mod queue; +use core::marker::PhantomData; + pub use queue::QueueScheduler; pub mod probabilistic_sampling; @@ -28,52 +30,62 @@ pub use powersched::PowerQueueScheduler; use crate::{ bolts::rands::Rand, corpus::{Corpus, Testcase}, - inputs::Input, - state::{HasCorpus, HasRand}, + inputs::UsesInput, + state::{HasCorpus, HasRand, UsesState}, Error, }; /// The scheduler define how the fuzzer requests a testcase from the corpus. /// It has hooks to corpus add/replace/remove to allow complex scheduling algorithms to collect data. -pub trait Scheduler -where - I: Input, -{ +pub trait Scheduler: UsesState { /// Added an entry to the corpus at the given index - fn on_add(&self, _state: &mut S, _idx: usize) -> Result<(), Error> { + fn on_add(&self, _state: &mut Self::State, _idx: usize) -> Result<(), Error> { Ok(()) } /// Replaced the given testcase at the given idx - fn on_replace(&self, _state: &mut S, _idx: usize, _prev: &Testcase) -> Result<(), Error> { + fn on_replace( + &self, + _state: &mut Self::State, + _idx: usize, + _prev: &Testcase<::Input>, + ) -> Result<(), Error> { Ok(()) } /// Removed the given entry from the corpus at the given index fn on_remove( &self, - _state: &mut S, + _state: &mut Self::State, _idx: usize, - _testcase: &Option>, + _testcase: &Option::Input>>, ) -> Result<(), Error> { Ok(()) } /// Gets the next entry - fn next(&self, state: &mut S) -> Result; + fn next(&self, state: &mut Self::State) -> Result; } -/// Feed the fuzzer simpply with a random testcase on request +/// Feed the fuzzer simply with a random testcase on request #[derive(Debug, Clone)] -pub struct RandScheduler; +pub struct RandScheduler { + phantom: PhantomData, +} -impl Scheduler for RandScheduler +impl UsesState for RandScheduler where - S: HasCorpus + HasRand, - I: Input, + S: UsesInput, +{ + type State = S; +} + +impl Scheduler for RandScheduler +where + S: HasCorpus + HasRand, { /// Gets the next entry at random - fn next(&self, state: &mut S) -> Result { + fn next(&self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { Err(Error::empty("No entries in corpus".to_owned())) } else { @@ -85,15 +97,17 @@ where } } -impl RandScheduler { +impl RandScheduler { /// Create a new [`RandScheduler`] that just schedules randomly. #[must_use] pub fn new() -> Self { - Self + Self { + phantom: PhantomData, + } } } -impl Default for RandScheduler { +impl Default for RandScheduler { fn default() -> Self { Self::new() } @@ -101,4 +115,4 @@ impl Default for RandScheduler { /// A [`StdScheduler`] uses the default scheduler in `LibAFL` to schedule [`Testcase`]s. /// The current `Std` is a [`RandScheduler`], although this may change in the future, if another [`Scheduler`] delivers better results. -pub type StdScheduler = RandScheduler; +pub type StdScheduler = RandScheduler; diff --git a/libafl/src/schedulers/powersched.rs b/libafl/src/schedulers/powersched.rs index 7d45413935..819ecd92a3 100644 --- a/libafl/src/schedulers/powersched.rs +++ b/libafl/src/schedulers/powersched.rs @@ -4,17 +4,18 @@ use alloc::{ string::{String, ToString}, vec::Vec, }; -use core::time::Duration; +use core::{marker::PhantomData, time::Duration}; use serde::{Deserialize, Serialize}; use crate::{ corpus::{Corpus, SchedulerTestcaseMetaData}, - inputs::Input, + inputs::UsesInput, schedulers::Scheduler, - state::{HasCorpus, HasMetadata}, + state::{HasCorpus, HasMetadata, UsesState}, Error, }; + /// The n fuzz size pub const N_FUZZ_SIZE: usize = 1 << 21; @@ -148,17 +149,24 @@ pub enum PowerSchedule { /// A corpus scheduler using power schedules #[derive(Clone, Debug)] -pub struct PowerQueueScheduler { +pub struct PowerQueueScheduler { strat: PowerSchedule, + phantom: PhantomData, } -impl Scheduler for PowerQueueScheduler +impl UsesState for PowerQueueScheduler where - S: HasCorpus + HasMetadata, - I: Input, + S: UsesInput, +{ + type State = S; +} + +impl Scheduler for PowerQueueScheduler +where + S: HasCorpus + HasMetadata, { /// Add an entry to the corpus and return its index - fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { + fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> { if !state.has_metadata::() { state.add_metadata::(SchedulerMetadata::new(Some(self.strat))); } @@ -189,7 +197,7 @@ where Ok(()) } - fn next(&self, state: &mut S) -> Result { + fn next(&self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { Err(Error::empty(String::from("No entries in corpus"))) } else { @@ -232,10 +240,13 @@ where } } -impl PowerQueueScheduler { +impl PowerQueueScheduler { /// Create a new [`PowerQueueScheduler`] #[must_use] pub fn new(strat: PowerSchedule) -> Self { - PowerQueueScheduler { strat } + PowerQueueScheduler { + strat, + phantom: PhantomData, + } } } diff --git a/libafl/src/schedulers/probabilistic_sampling.rs b/libafl/src/schedulers/probabilistic_sampling.rs index 7385b04096..fd17758a9c 100644 --- a/libafl/src/schedulers/probabilistic_sampling.rs +++ b/libafl/src/schedulers/probabilistic_sampling.rs @@ -10,21 +10,19 @@ use serde::{Deserialize, Serialize}; use crate::{ bolts::rands::Rand, corpus::Corpus, - inputs::Input, + inputs::UsesInput, schedulers::{Scheduler, TestcaseScore}, - state::{HasCorpus, HasMetadata, HasRand}, + state::{HasCorpus, HasMetadata, HasRand, UsesState}, Error, }; /// Conduct reservoir sampling (probabilistic sampling) over all corpus elements. #[derive(Debug, Clone)] -pub struct ProbabilitySamplingScheduler +pub struct ProbabilitySamplingScheduler where - F: TestcaseScore, - I: Input, - S: HasCorpus + HasMetadata + HasRand, + S: UsesInput, { - phantom: PhantomData<(F, I, S)>, + phantom: PhantomData<(F, S)>, } /// A state metadata holding a map of probability of corpus elements. @@ -55,11 +53,10 @@ impl Default for ProbabilityMetadata { } } -impl ProbabilitySamplingScheduler +impl ProbabilitySamplingScheduler where - F: TestcaseScore, - I: Input, - S: HasCorpus + HasMetadata + HasRand, + F: TestcaseScore, + S: HasCorpus + HasMetadata + HasRand, { /// Creates a new [`struct@ProbabilitySamplingScheduler`] #[must_use] @@ -90,13 +87,19 @@ where } } -impl Scheduler for ProbabilitySamplingScheduler +impl UsesState for ProbabilitySamplingScheduler where - F: TestcaseScore, - I: Input, - S: HasCorpus + HasMetadata + HasRand, + S: UsesInput, { - fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { + type State = S; +} + +impl Scheduler for ProbabilitySamplingScheduler +where + F: TestcaseScore, + S: HasCorpus + HasMetadata + HasRand, +{ + fn on_add(&self, state: &mut Self::State, idx: usize) -> Result<(), Error> { if state.metadata().get::().is_none() { state.add_metadata(ProbabilityMetadata::new()); } @@ -105,7 +108,7 @@ where /// Gets the next entry #[allow(clippy::cast_precision_loss)] - fn next(&self, state: &mut S) -> Result { + fn next(&self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { Err(Error::empty(String::from("No entries in corpus"))) } else { @@ -127,11 +130,10 @@ where } } -impl Default for ProbabilitySamplingScheduler +impl Default for ProbabilitySamplingScheduler where - F: TestcaseScore, - I: Input, - S: HasCorpus + HasMetadata + HasRand, + F: TestcaseScore, + S: HasCorpus + HasMetadata + HasRand, { fn default() -> Self { Self::new() @@ -146,7 +148,8 @@ mod tests { use crate::{ bolts::rands::StdRand, corpus::{Corpus, InMemoryCorpus, Testcase}, - inputs::{bytes::BytesInput, Input}, + feedbacks::ConstFeedback, + inputs::{bytes::BytesInput, Input, UsesInput}, schedulers::{ProbabilitySamplingScheduler, Scheduler, TestcaseScore}, state::{HasCorpus, HasMetadata, StdState}, Error, @@ -162,18 +165,17 @@ mod tests { phantom: PhantomData, } - impl TestcaseScore for UniformDistribution + impl TestcaseScore for UniformDistribution where - I: Input, - S: HasMetadata + HasCorpus, + S: HasMetadata + HasCorpus, { - fn compute(_: &mut Testcase, _state: &S) -> Result { + fn compute(_: &mut Testcase, _state: &S) -> Result { Ok(FACTOR) } } - pub type UniformProbabilitySamplingScheduler = - ProbabilitySamplingScheduler, I, S>; + pub type UniformProbabilitySamplingScheduler = + ProbabilitySamplingScheduler::Input>, S>; #[test] fn test_prob_sampling() { @@ -182,6 +184,9 @@ mod tests { let scheduler = UniformProbabilitySamplingScheduler::new(); + let mut feedback = ConstFeedback::new(false); + let mut objective = ConstFeedback::new(false); + let mut corpus = InMemoryCorpus::new(); let t1 = Testcase::with_filename(BytesInput::new(vec![0_u8; 4]), "1".into()); let t2 = Testcase::with_filename(BytesInput::new(vec![1_u8; 4]), "2".into()); @@ -189,8 +194,14 @@ mod tests { let idx1 = corpus.add(t1).unwrap(); let idx2 = corpus.add(t2).unwrap(); - let mut state = - StdState::new(rand, corpus, InMemoryCorpus::new(), &mut (), &mut ()).unwrap(); + let mut state = StdState::new( + rand, + corpus, + InMemoryCorpus::new(), + &mut feedback, + &mut objective, + ) + .unwrap(); scheduler.on_add(state.borrow_mut(), idx1).unwrap(); scheduler.on_add(state.borrow_mut(), idx2).unwrap(); let next_idx1 = scheduler.next(&mut state).unwrap(); diff --git a/libafl/src/schedulers/queue.rs b/libafl/src/schedulers/queue.rs index 61605c84aa..4f0cd0fb81 100644 --- a/libafl/src/schedulers/queue.rs +++ b/libafl/src/schedulers/queue.rs @@ -1,20 +1,35 @@ //! The queue corpus scheduler implements an AFL-like queue mechanism use alloc::borrow::ToOwned; +use core::marker::PhantomData; -use crate::{corpus::Corpus, inputs::Input, schedulers::Scheduler, state::HasCorpus, Error}; +use crate::{ + corpus::Corpus, + inputs::UsesInput, + schedulers::Scheduler, + state::{HasCorpus, UsesState}, + Error, +}; /// Walk the corpus in a queue-like fashion #[derive(Debug, Clone)] -pub struct QueueScheduler; +pub struct QueueScheduler { + phantom: PhantomData, +} -impl Scheduler for QueueScheduler +impl UsesState for QueueScheduler where - S: HasCorpus, - I: Input, + S: UsesInput, +{ + type State = S; +} + +impl Scheduler for QueueScheduler +where + S: HasCorpus, { /// Gets the next entry in the queue - fn next(&self, state: &mut S) -> Result { + fn next(&self, state: &mut Self::State) -> Result { if state.corpus().count() == 0 { Err(Error::empty("No entries in corpus".to_owned())) } else { @@ -34,15 +49,17 @@ where } } -impl QueueScheduler { +impl QueueScheduler { /// Creates a new `QueueScheduler` #[must_use] pub fn new() -> Self { - Self + Self { + phantom: PhantomData, + } } } -impl Default for QueueScheduler { +impl Default for QueueScheduler { fn default() -> Self { Self::new() } @@ -57,6 +74,7 @@ mod tests { use crate::{ bolts::rands::StdRand, corpus::{Corpus, OnDiskCorpus, Testcase}, + feedbacks::ConstFeedback, inputs::bytes::BytesInput, schedulers::{QueueScheduler, Scheduler}, state::{HasCorpus, StdState}, @@ -79,7 +97,10 @@ mod tests { OnDiskCorpus::::new(PathBuf::from("target/.test/fancy/objective/path")) .unwrap(); - let mut state = StdState::new(rand, q, objective_q, &mut (), &mut ()).unwrap(); + let mut feedback = ConstFeedback::new(false); + let mut objective = ConstFeedback::new(false); + + let mut state = StdState::new(rand, q, objective_q, &mut feedback, &mut objective).unwrap(); let next_idx = scheduler.next(&mut state).unwrap(); let filename = state diff --git a/libafl/src/schedulers/testcase_score.rs b/libafl/src/schedulers/testcase_score.rs index 1c043033f6..9ad4c39b11 100644 --- a/libafl/src/schedulers/testcase_score.rs +++ b/libafl/src/schedulers/testcase_score.rs @@ -6,7 +6,6 @@ use crate::{ bolts::{HasLen, HasRefCnt}, corpus::{Corpus, SchedulerTestcaseMetaData, Testcase}, feedbacks::MapIndexesMetadata, - inputs::Input, schedulers::{ minimizer::{IsFavoredMetadata, TopRatedsMetadata}, powersched::{PowerSchedule, SchedulerMetadata}, @@ -16,33 +15,28 @@ use crate::{ }; /// Compute the favor factor of a [`Testcase`]. Lower is better. -pub trait TestcaseScore +pub trait TestcaseScore where - I: Input, - S: HasMetadata + HasCorpus, + S: HasMetadata + HasCorpus, { /// Computes the favor factor of a [`Testcase`]. Lower is better. - fn compute(entry: &mut Testcase, state: &S) -> Result; + fn compute(entry: &mut Testcase, state: &S) -> Result; } /// Multiply the testcase size with the execution time. /// This favors small and quick testcases. #[derive(Debug, Clone)] -pub struct LenTimeMulTestcaseScore -where - I: Input + HasLen, - S: HasMetadata + HasCorpus, -{ - phantom: PhantomData<(I, S)>, +pub struct LenTimeMulTestcaseScore { + phantom: PhantomData, } -impl TestcaseScore for LenTimeMulTestcaseScore +impl TestcaseScore for LenTimeMulTestcaseScore where - I: Input + HasLen, - S: HasMetadata + HasCorpus, + S: HasCorpus + HasMetadata, + S::Input: HasLen, { #[allow(clippy::cast_precision_loss, clippy::cast_lossless)] - fn compute(entry: &mut Testcase, _state: &S) -> Result { + fn compute(entry: &mut Testcase, _state: &S) -> Result { // TODO maybe enforce entry.exec_time().is_some() Ok(entry.exec_time().map_or(1, |d| d.as_millis()) as f64 * entry.cached_len()? as f64) } @@ -56,18 +50,13 @@ const HAVOC_MAX_MULT: f64 = 64.0; /// The power assigned to each corpus entry /// This result is used for power scheduling #[derive(Debug, Clone)] -pub struct CorpusPowerTestcaseScore -where - I: Input + HasLen, - S: HasMetadata + HasCorpus, -{ - phantom: PhantomData<(I, S)>, +pub struct CorpusPowerTestcaseScore { + phantom: PhantomData, } -impl TestcaseScore for CorpusPowerTestcaseScore +impl TestcaseScore for CorpusPowerTestcaseScore where - I: Input + HasLen, - S: HasMetadata + HasCorpus, + S: HasCorpus + HasMetadata, { /// Compute the `power` we assign to each corpus entry #[allow( @@ -76,7 +65,7 @@ where clippy::cast_sign_loss, clippy::cast_lossless )] - fn compute(entry: &mut Testcase, state: &S) -> Result { + fn compute(entry: &mut Testcase, state: &S) -> Result { let psmeta = state .metadata() .get::() @@ -294,22 +283,17 @@ where /// The weight for each corpus entry /// This result is used for corpus scheduling #[derive(Debug, Clone)] -pub struct CorpusWeightTestcaseScore -where - I: Input + HasLen, - S: HasMetadata + HasCorpus, -{ - phantom: PhantomData<(I, S)>, +pub struct CorpusWeightTestcaseScore { + phantom: PhantomData, } -impl TestcaseScore for CorpusWeightTestcaseScore +impl TestcaseScore for CorpusWeightTestcaseScore where - I: Input + HasLen, - S: HasMetadata + HasCorpus, + S: HasCorpus + HasMetadata, { /// Compute the `weight` used in weighted corpus entry selection algo #[allow(clippy::cast_precision_loss, clippy::cast_lossless)] - fn compute(entry: &mut Testcase, state: &S) -> Result { + fn compute(entry: &mut Testcase, state: &S) -> Result { let mut weight = 1.0; let psmeta = state .metadata() diff --git a/libafl/src/schedulers/weighted.rs b/libafl/src/schedulers/weighted.rs index 878f2db1f5..4efed1dd96 100644 --- a/libafl/src/schedulers/weighted.rs +++ b/libafl/src/schedulers/weighted.rs @@ -12,13 +12,13 @@ use serde::{Deserialize, Serialize}; use crate::{ bolts::rands::Rand, corpus::{Corpus, SchedulerTestcaseMetaData, Testcase}, - inputs::Input, + inputs::UsesInput, schedulers::{ powersched::{PowerSchedule, SchedulerMetadata}, testcase_score::{CorpusWeightTestcaseScore, TestcaseScore}, Scheduler, }, - state::{HasCorpus, HasMetadata, HasRand}, + state::{HasCorpus, HasMetadata, HasRand, UsesState}, Error, }; @@ -89,27 +89,25 @@ crate::impl_serdeany!(WeightedScheduleMetadata); /// A corpus scheduler using power schedules with weighted queue item selection algo. #[derive(Clone, Debug)] -pub struct WeightedScheduler { +pub struct WeightedScheduler { strat: Option, - phantom: PhantomData<(F, I, S)>, + phantom: PhantomData<(F, S)>, } -impl Default for WeightedScheduler +impl Default for WeightedScheduler where - F: TestcaseScore, - I: Input, - S: HasCorpus + HasMetadata + HasRand, + F: TestcaseScore, + S: HasCorpus + HasMetadata + HasRand, { fn default() -> Self { Self::new() } } -impl WeightedScheduler +impl WeightedScheduler where - F: TestcaseScore, - I: Input, - S: HasCorpus + HasMetadata + HasRand, + F: TestcaseScore, + S: HasCorpus + HasMetadata + HasRand, { /// Create a new [`WeightedScheduler`] without any scheduling strategy #[must_use] @@ -219,11 +217,17 @@ where } } -impl Scheduler for WeightedScheduler +impl UsesState for WeightedScheduler where - F: TestcaseScore, - S: HasCorpus + HasMetadata + HasRand, - I: Input, + S: UsesInput, +{ + type State = S; +} + +impl Scheduler for WeightedScheduler +where + F: TestcaseScore, + S: HasCorpus + HasMetadata + HasRand, { /// Add an entry to the corpus and return its index fn on_add(&self, state: &mut S, idx: usize) -> Result<(), Error> { @@ -264,7 +268,12 @@ where Ok(()) } - fn on_replace(&self, state: &mut S, idx: usize, _testcase: &Testcase) -> Result<(), Error> { + fn on_replace( + &self, + state: &mut S, + idx: usize, + _testcase: &Testcase, + ) -> Result<(), Error> { // Recreate the alias table self.on_add(state, idx) } @@ -273,7 +282,7 @@ where &self, state: &mut S, _idx: usize, - _testcase: &Option>, + _testcase: &Option>, ) -> Result<(), Error> { // Recreate the alias table self.create_alias_table(state)?; @@ -343,4 +352,4 @@ where } /// The standard corpus weight, same as aflpp -pub type StdWeightedScheduler = WeightedScheduler, I, S>; +pub type StdWeightedScheduler = WeightedScheduler, S>; diff --git a/libafl/src/stages/calibrate.rs b/libafl/src/stages/calibrate.rs index 5741c61a2a..2cfab0e3ef 100644 --- a/libafl/src/stages/calibrate.rs +++ b/libafl/src/stages/calibrate.rs @@ -20,11 +20,11 @@ use crate::{ HasObserverName, }, fuzzer::Evaluator, - inputs::Input, + inputs::UsesInput, observers::{MapObserver, ObserversTuple}, schedulers::powersched::SchedulerMetadata, stages::Stage, - state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasNamedMetadata}, + state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasNamedMetadata, UsesState}, Error, }; @@ -63,33 +63,33 @@ impl UnstableEntriesMetadata { /// The calibration stage will measure the average exec time and the target's stability for this input. #[derive(Clone, Debug)] -pub struct CalibrationStage -where - I: Input, - O: MapObserver, - OT: ObserversTuple, - S: HasCorpus + HasMetadata + HasNamedMetadata, -{ +pub struct CalibrationStage { map_observer_name: String, map_name: String, stage_max: usize, track_stability: bool, - phantom: PhantomData<(I, O, OT, S)>, + phantom: PhantomData<(O, OT, S)>, } const CAL_STAGE_START: usize = 4; // AFL++'s CAL_CYCLES_FAST + 1 const CAL_STAGE_MAX: usize = 8; // AFL++'s CAL_CYCLES + 1 -impl Stage for CalibrationStage +impl UsesState for CalibrationStage where - E: Executor + HasObservers, - EM: EventFirer, - I: Input, + S: UsesInput, +{ + type State = S; +} + +impl Stage for CalibrationStage +where + E: Executor + HasObservers, + EM: EventFirer, O: MapObserver, for<'de> ::Entry: Serialize + Deserialize<'de> + 'static, - OT: ObserversTuple, - S: HasCorpus + HasMetadata + HasClientPerfMonitor + HasNamedMetadata, - Z: Evaluator, + OT: ObserversTuple, + E::State: HasCorpus + HasMetadata + HasClientPerfMonitor + HasNamedMetadata, + Z: Evaluator, { #[inline] #[allow(clippy::let_and_return, clippy::too_many_lines)] @@ -97,7 +97,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut E::State, mgr: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -285,16 +285,15 @@ where } } -impl CalibrationStage +impl CalibrationStage where - I: Input, O: MapObserver, - OT: ObserversTuple, - S: HasCorpus + HasMetadata + HasNamedMetadata, + OT: ObserversTuple, + S: HasCorpus + HasMetadata + HasNamedMetadata, { /// Create a new [`CalibrationStage`]. #[must_use] - pub fn new(map_feedback: &MapFeedback) -> Self + pub fn new(map_feedback: &MapFeedback) -> Self where O::Entry: PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, @@ -313,7 +312,7 @@ where /// Create a new [`CalibrationStage`], but without checking stability. #[must_use] - pub fn ignore_stability(map_feedback: &MapFeedback) -> Self + pub fn ignore_stability(map_feedback: &MapFeedback) -> Self where O::Entry: PartialEq + Default + Copy + 'static + Serialize + serde::de::DeserializeOwned + Debug, diff --git a/libafl/src/stages/concolic.rs b/libafl/src/stages/concolic.rs index 7cdb4eb3de..e711f21ab2 100644 --- a/libafl/src/stages/concolic.rs +++ b/libafl/src/stages/concolic.rs @@ -11,38 +11,39 @@ use super::{Stage, TracingStage}; use crate::{ corpus::Corpus, executors::{Executor, HasObservers}, - inputs::Input, - observers::{concolic::ConcolicObserver, ObserversTuple}, + observers::concolic::ConcolicObserver, state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata}, Error, }; /// Wraps a [`TracingStage`] to add concolic observing. #[derive(Clone, Debug)] -pub struct ConcolicTracingStage -where - I: Input, - TE: Executor + HasObservers, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, -{ - inner: TracingStage, +pub struct ConcolicTracingStage { + inner: TracingStage, observer_name: String, } -impl Stage for ConcolicTracingStage +impl UsesState for ConcolicTracingStage where - I: Input, - TE: Executor + HasObservers, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, + TE: UsesState, +{ + type State = TE::State; +} + +impl Stage for ConcolicTracingStage +where + E: UsesState, + EM: UsesState, + TE: Executor + HasObservers, + TE::State: HasClientPerfMonitor + HasExecutions + HasCorpus, + Z: UsesState, { #[inline] fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut TE::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -67,15 +68,9 @@ where } } -impl ConcolicTracingStage -where - I: Input, - TE: Executor + HasObservers, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, -{ +impl ConcolicTracingStage { /// Creates a new default tracing stage using the given [`Executor`], observing traces from a [`ConcolicObserver`] with the given name. - pub fn new(inner: TracingStage, observer_name: String) -> Self { + pub fn new(inner: TracingStage, observer_name: String) -> Self { Self { inner, observer_name, @@ -85,6 +80,7 @@ where #[cfg(all(feature = "concolic_mutation", feature = "introspection"))] use crate::monitors::PerfFeature; +use crate::{bolts::tuples::MatchName, state::UsesState}; #[cfg(feature = "concolic_mutation")] use crate::{ inputs::HasBytesVec, @@ -340,27 +336,33 @@ fn generate_mutations(iter: impl Iterator) -> Vec< /// A mutational stage that uses Z3 to solve concolic constraints attached to the [`crate::corpus::Testcase`] by the [`ConcolicTracingStage`]. #[derive(Clone, Debug)] -pub struct SimpleConcolicMutationalStage -where - I: Input, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, -{ - _phantom: PhantomData<(EM, I, S, Z)>, +pub struct SimpleConcolicMutationalStage { + _phantom: PhantomData, } #[cfg(feature = "concolic_mutation")] -impl Stage for SimpleConcolicMutationalStage +impl UsesState for SimpleConcolicMutationalStage where - I: Input + HasBytesVec, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, - Z: Evaluator, + Z: UsesState, +{ + type State = Z::State; +} + +#[cfg(feature = "concolic_mutation")] +impl Stage for SimpleConcolicMutationalStage +where + E: UsesState, + EM: UsesState, + Z: Evaluator, + Z::Input: HasBytesVec, + Z::State: HasClientPerfMonitor + HasExecutions + HasCorpus, { #[inline] fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut Z::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -392,11 +394,7 @@ where } } -impl Default for SimpleConcolicMutationalStage -where - I: Input, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, -{ +impl Default for SimpleConcolicMutationalStage { fn default() -> Self { Self { _phantom: PhantomData, diff --git a/libafl/src/stages/generalization.rs b/libafl/src/stages/generalization.rs index edd9f6e3ad..4dd779d69a 100644 --- a/libafl/src/stages/generalization.rs +++ b/libafl/src/stages/generalization.rs @@ -1,4 +1,4 @@ -//! The tracing stage can trace the target and enrich a testcase with metadata, for example for `CmpLog`. +//! The tracing stage can trace the target and enrich a [`crate::corpus::Testcase`] with metadata, for example for `CmpLog`. use alloc::{ string::{String, ToString}, @@ -16,12 +16,12 @@ use crate::{ corpus::Corpus, executors::{Executor, HasObservers}, feedbacks::map::MapNoveltiesMetadata, - inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec}, + inputs::{GeneralizedInput, GeneralizedItem, HasBytesVec, UsesInput}, mark_feature_time, observers::{MapObserver, ObserversTuple}, stages::Stage, start_timer, - state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, UsesState}, Error, }; @@ -60,23 +60,32 @@ fn find_next_char(list: &[Option], mut idx: usize, ch: u8) -> usize { /// A stage that runs a tracer executor #[derive(Clone, Debug)] -pub struct GeneralizationStage -where - O: MapObserver, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasMetadata + HasCorpus, -{ +pub struct GeneralizationStage { map_observer_name: String, #[allow(clippy::type_complexity)] - phantom: PhantomData<(EM, O, OT, S, Z)>, + phantom: PhantomData<(EM, O, OT, Z)>, } -impl Stage for GeneralizationStage +impl UsesState for GeneralizationStage +where + EM: UsesState, + EM::State: UsesInput, +{ + type State = EM::State; +} + +impl Stage for GeneralizationStage where O: MapObserver, - E: Executor + HasObservers, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasMetadata + HasCorpus, + E: Executor + HasObservers, + E::Observers: ObserversTuple, + E::State: UsesInput + + HasClientPerfMonitor + + HasExecutions + + HasMetadata + + HasCorpus, + EM: UsesState, + Z: UsesState, { #[inline] #[allow(clippy::too_many_lines)] @@ -84,7 +93,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut E::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -347,11 +356,16 @@ where } } -impl GeneralizationStage +impl GeneralizationStage where + EM: UsesState, O: MapObserver, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasMetadata + HasCorpus, + OT: ObserversTuple, + EM::State: UsesInput + + HasClientPerfMonitor + + HasExecutions + + HasMetadata + + HasCorpus, { /// Create a new [`GeneralizationStage`]. #[must_use] @@ -375,13 +389,14 @@ where &self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut EM::State, manager: &mut EM, novelties: &[usize], input: &GeneralizedInput, ) -> Result where - E: Executor + HasObservers, + E: Executor + HasObservers, + Z: UsesState, { start_timer!(state); executor.observers_mut().pre_exec_all(state, input)?; @@ -418,7 +433,7 @@ where &self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut EM::State, manager: &mut EM, payload: &mut Vec>, novelties: &[usize], @@ -426,7 +441,8 @@ where split_char: u8, ) -> Result<(), Error> where - E: Executor + HasObservers, + E: Executor + HasObservers, + Z: UsesState, { let mut start = 0; while start < payload.len() { @@ -460,7 +476,7 @@ where &self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut EM::State, manager: &mut EM, payload: &mut Vec>, novelties: &[usize], @@ -468,7 +484,8 @@ where closing_char: u8, ) -> Result<(), Error> where - E: Executor + HasObservers, + E: Executor + HasObservers, + Z: UsesState, { let mut index = 0; while index < payload.len() { diff --git a/libafl/src/stages/mod.rs b/libafl/src/stages/mod.rs index d174bd46c0..8db1e0702f 100644 --- a/libafl/src/stages/mod.rs +++ b/libafl/src/stages/mod.rs @@ -48,29 +48,40 @@ use self::push::PushStage; use crate::{ events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, executors::{Executor, HasObservers}, - inputs::Input, + inputs::UsesInput, observers::ObserversTuple, schedulers::Scheduler, - state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasRand}, + state::{HasClientPerfMonitor, HasExecutions, HasMetadata, HasRand, UsesState}, Error, EvaluatorObservers, ExecutesInput, ExecutionProcessor, HasScheduler, }; /// A stage is one step in the fuzzing process. /// Multiple stages will be scheduled one by one for each input. -pub trait Stage { +pub trait Stage: UsesState +where + E: UsesState, + EM: UsesState, + Z: UsesState, +{ /// Run the stage fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut Self::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error>; } /// A tuple holding all `Stages` used for fuzzing. -pub trait StagesTuple { +pub trait StagesTuple +where + E: UsesState, + EM: UsesState, + Z: UsesState, + S: UsesInput, +{ /// Performs all `Stages` in this tuple fn perform_all( &mut self, @@ -82,7 +93,13 @@ pub trait StagesTuple { ) -> Result<(), Error>; } -impl StagesTuple for () { +impl StagesTuple for () +where + E: UsesState, + EM: UsesState, + Z: UsesState, + S: UsesInput, +{ fn perform_all( &mut self, _: &mut Z, @@ -95,16 +112,19 @@ impl StagesTuple for () { } } -impl StagesTuple for (Head, Tail) +impl StagesTuple for (Head, Tail) where - Head: Stage, - Tail: StagesTuple, + Head: Stage, + Tail: StagesTuple, + E: UsesState, + EM: UsesState, + Z: UsesState, { fn perform_all( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut Head::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -120,23 +140,35 @@ where /// A [`Stage`] that will call a closure #[derive(Debug)] -pub struct ClosureStage +pub struct ClosureStage where - CB: FnMut(&mut Z, &mut E, &mut S, &mut EM, usize) -> Result<(), Error>, + CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>, + E: UsesState, { closure: CB, - phantom: PhantomData<(E, EM, S, Z)>, + phantom: PhantomData<(E, EM, Z)>, } -impl Stage for ClosureStage +impl UsesState for ClosureStage where - CB: FnMut(&mut Z, &mut E, &mut S, &mut EM, usize) -> Result<(), Error>, + CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>, + E: UsesState, +{ + type State = E::State; +} + +impl Stage for ClosureStage +where + CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>, + E: UsesState, + EM: UsesState, + Z: UsesState, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut E::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -145,9 +177,10 @@ where } /// A stage that takes a closure -impl ClosureStage +impl ClosureStage where - CB: FnMut(&mut Z, &mut E, &mut S, &mut EM, usize) -> Result<(), Error>, + CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>, + E: UsesState, { /// Create a new [`ClosureStage`] #[must_use] @@ -159,9 +192,10 @@ where } } -impl From for ClosureStage +impl From for ClosureStage where - CB: FnMut(&mut Z, &mut E, &mut S, &mut EM, usize) -> Result<(), Error>, + CB: FnMut(&mut Z, &mut E, &mut E::State, &mut EM, usize) -> Result<(), Error>, + E: UsesState, { #[must_use] fn from(closure: CB) -> Self { @@ -172,30 +206,12 @@ where /// Allows us to use a [`push::PushStage`] as a normal [`Stage`] #[allow(clippy::type_complexity)] #[derive(Debug)] -pub struct PushStageAdapter -where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - I: Input, - OT: ObserversTuple, - PS: PushStage, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, -{ +pub struct PushStageAdapter { push_stage: PS, - phantom: PhantomData<(CS, EM, I, OT, S, Z)>, + phantom: PhantomData<(CS, EM, OT, Z)>, } -impl PushStageAdapter -where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - I: Input, - OT: ObserversTuple, - PS: PushStage, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, -{ +impl PushStageAdapter { /// Create a new [`PushStageAdapter`], wrapping the given [`PushStage`] /// to be used as a normal [`Stage`] #[must_use] @@ -207,25 +223,34 @@ where } } -impl Stage for PushStageAdapter +impl UsesState for PushStageAdapter where - CS: Scheduler, - E: Executor + HasObservers, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - I: Input, - OT: ObserversTuple, - PS: PushStage, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata, - Z: ExecutesInput - + ExecutionProcessor - + EvaluatorObservers - + HasScheduler, + CS: UsesState, +{ + type State = CS::State; +} + +impl Stage for PushStageAdapter +where + CS: Scheduler, + CS::State: HasClientPerfMonitor + HasExecutions + HasMetadata + HasRand, + E: Executor + HasObservers, + EM: EventFirer + + EventRestarter + + HasEventManagerId + + ProgressReporter, + OT: ObserversTuple, + PS: PushStage, + Z: ExecutesInput + + ExecutionProcessor + + EvaluatorObservers + + HasScheduler, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut CS::State, event_mgr: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -281,20 +306,19 @@ impl From for SkippableStageDecision { /// The [`SkippableStage`] wraps any [`Stage`] so that it can be skipped, according to a condition. #[derive(Debug, Clone)] -pub struct SkippableStage -where - CD: FnMut(&mut S) -> SkippableStageDecision, - ST: Stage, -{ +pub struct SkippableStage { wrapped_stage: ST, condition: CD, - phantom: PhantomData<(E, EM, S, Z)>, + phantom: PhantomData<(E, EM, Z)>, } -impl SkippableStage +impl SkippableStage where - CD: FnMut(&mut S) -> SkippableStageDecision, - ST: Stage, + CD: FnMut(&mut ST::State) -> SkippableStageDecision, + ST: Stage, + E: UsesState, + EM: UsesState, + Z: UsesState, { /// Create a new [`SkippableStage`] pub fn new(wrapped_stage: ST, condition: CD) -> Self { @@ -306,10 +330,24 @@ where } } -impl Stage for SkippableStage +impl UsesState for SkippableStage where - CD: FnMut(&mut S) -> SkippableStageDecision, - ST: Stage, + CD: FnMut(&mut ST::State) -> SkippableStageDecision, + ST: Stage, + E: UsesState, + EM: UsesState, + Z: UsesState, +{ + type State = ST::State; +} + +impl Stage for SkippableStage +where + CD: FnMut(&mut ST::State) -> SkippableStageDecision, + ST: Stage, + E: UsesState, + EM: UsesState, + Z: UsesState, { /// Run the stage #[inline] @@ -317,7 +355,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut ST::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -344,7 +382,10 @@ pub mod pybind { executors::pybind::PythonExecutor, fuzzer::pybind::{PythonStdFuzzer, PythonStdFuzzerWrapper}, stages::{mutational::pybind::PythonStdMutationalStage, Stage, StagesTuple}, - state::pybind::{PythonStdState, PythonStdStateWrapper}, + state::{ + pybind::{PythonStdState, PythonStdStateWrapper}, + UsesState, + }, Error, }; @@ -360,7 +401,11 @@ pub mod pybind { } } - impl Stage for PyObjectStage { + impl UsesState for PyObjectStage { + type State = PythonStdState; + } + + impl Stage for PyObjectStage { #[inline] fn perform( &mut self, @@ -444,7 +489,11 @@ pub mod pybind { } } - impl Stage for PythonStage { + impl UsesState for PythonStage { + type State = PythonStdState; + } + + impl Stage for PythonStage { #[inline] #[allow(clippy::let_and_return)] fn perform( diff --git a/libafl/src/stages/mutational.rs b/libafl/src/stages/mutational.rs index 5f8b9041f3..578baed5a8 100644 --- a/libafl/src/stages/mutational.rs +++ b/libafl/src/stages/mutational.rs @@ -9,12 +9,11 @@ use crate::{ bolts::rands::Rand, corpus::Corpus, fuzzer::Evaluator, - inputs::Input, mark_feature_time, mutators::Mutator, stages::Stage, start_timer, - state::{HasClientPerfMonitor, HasCorpus, HasRand}, + state::{HasClientPerfMonitor, HasCorpus, HasRand, UsesState}, Error, }; @@ -23,12 +22,13 @@ use crate::{ /// 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 MutationalStage: Stage +pub trait MutationalStage: Stage where - M: Mutator, - I: Input, - S: HasClientPerfMonitor + HasCorpus, - Z: Evaluator, + E: UsesState, + M: Mutator, + EM: UsesState, + Z: Evaluator, + Self::State: HasClientPerfMonitor + HasCorpus, { /// The mutator registered for this stage fn mutator(&self) -> &M; @@ -37,7 +37,7 @@ where fn mutator_mut(&mut self) -> &mut M; /// Gets the number of iterations this mutator should run for. - fn iterations(&self, state: &mut S, corpus_idx: usize) -> Result; + fn iterations(&self, state: &mut Z::State, corpus_idx: usize) -> Result; /// Runs this (mutational) stage for the given testcase #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... @@ -45,7 +45,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut Z::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -82,24 +82,19 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128; /// The default mutational stage #[derive(Clone, Debug)] -pub struct StdMutationalStage -where - M: Mutator, - I: Input, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: Evaluator, -{ +pub struct StdMutationalStage { mutator: M, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, I, S, Z)>, + phantom: PhantomData<(E, EM, Z)>, } -impl MutationalStage for StdMutationalStage +impl MutationalStage for StdMutationalStage where - M: Mutator, - I: Input, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: Evaluator, + E: UsesState, + EM: UsesState, + M: Mutator, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand, { /// The mutator, added to this stage #[inline] @@ -114,17 +109,29 @@ where } /// Gets the number of iterations as a random number - fn iterations(&self, state: &mut S, _corpus_idx: usize) -> Result { + fn iterations(&self, state: &mut Z::State, _corpus_idx: usize) -> Result { Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize) } } -impl Stage for StdMutationalStage +impl UsesState for StdMutationalStage where - M: Mutator, - I: Input, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: Evaluator, + E: UsesState, + EM: UsesState, + M: Mutator, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand, +{ + type State = Z::State; +} + +impl Stage for StdMutationalStage +where + E: UsesState, + EM: UsesState, + M: Mutator, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand, { #[inline] #[allow(clippy::let_and_return)] @@ -132,7 +139,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut Z::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -145,12 +152,13 @@ where } } -impl StdMutationalStage +impl StdMutationalStage where - M: Mutator, - I: Input, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: Evaluator, + E: UsesState, + EM: UsesState, + M: Mutator, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand, { /// Creates a new default mutational stage pub fn new(mutator: M) -> Self { @@ -171,10 +179,8 @@ pub mod pybind { events::pybind::PythonEventManager, executors::pybind::PythonExecutor, fuzzer::pybind::PythonStdFuzzer, - inputs::BytesInput, mutators::pybind::PythonMutator, stages::{pybind::PythonStage, StdMutationalStage}, - state::pybind::PythonStdState, }; #[pyclass(unsendable, name = "StdMutationalStage")] @@ -182,14 +188,8 @@ pub mod pybind { /// Python class for StdMutationalStage pub struct PythonStdMutationalStage { /// Rust wrapped StdMutationalStage object - pub inner: StdMutationalStage< - PythonExecutor, - PythonEventManager, - BytesInput, - PythonMutator, - PythonStdState, - PythonStdFuzzer, - >, + pub inner: + StdMutationalStage, } #[pymethods] diff --git a/libafl/src/stages/owned.rs b/libafl/src/stages/owned.rs index efa4f5841b..11e335bf1c 100644 --- a/libafl/src/stages/owned.rs +++ b/libafl/src/stages/owned.rs @@ -5,26 +5,42 @@ use alloc::{boxed::Box, vec::Vec}; use crate::{ bolts::anymap::AsAny, stages::{Stage, StagesTuple}, + state::UsesState, Error, }; /// Combine `Stage` and `AsAny` -pub trait AnyStage: Stage + AsAny {} +pub trait AnyStage: Stage + AsAny +where + E: UsesState, + EM: UsesState, + Z: UsesState, +{ +} /// An owned list of `Observer` trait objects #[derive(Default)] #[allow(missing_debug_implementations)] -pub struct StagesOwnedList { +pub struct StagesOwnedList +where + E: UsesState, +{ /// The named trait objects map - pub list: Vec>>, + #[allow(clippy::type_complexity)] + pub list: Vec>>, } -impl StagesTuple for StagesOwnedList { +impl StagesTuple for StagesOwnedList +where + E: UsesState, + EM: UsesState, + Z: UsesState, +{ fn perform_all( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut E::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -35,10 +51,14 @@ impl StagesTuple for StagesOwnedList { } } -impl StagesOwnedList { +impl StagesOwnedList +where + E: UsesState, +{ /// Create a new instance #[must_use] - pub fn new(list: Vec>>) -> Self { + #[allow(clippy::type_complexity)] + pub fn new(list: Vec>>) -> Self { Self { list } } } diff --git a/libafl/src/stages/power.rs b/libafl/src/stages/power.rs index 4b0fa8ad5b..b8e00fcf71 100644 --- a/libafl/src/stages/power.rs +++ b/libafl/src/stages/power.rs @@ -4,49 +4,45 @@ use alloc::string::{String, ToString}; use core::{fmt::Debug, marker::PhantomData}; use crate::{ + bolts::tuples::MatchName, corpus::{Corpus, SchedulerTestcaseMetaData}, executors::{Executor, HasObservers}, fuzzer::Evaluator, - inputs::Input, mutators::Mutator, - observers::{MapObserver, ObserversTuple}, + observers::MapObserver, schedulers::{ powersched::SchedulerMetadata, testcase_score::CorpusPowerTestcaseScore, TestcaseScore, }, stages::{MutationalStage, Stage}, - state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand}, + state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState}, Error, }; + /// The mutational stage using power schedules #[derive(Clone, Debug)] -pub struct PowerMutationalStage -where - E: Executor + HasObservers, - F: TestcaseScore, - I: Input, - M: Mutator, - O: MapObserver, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasMetadata, - Z: Evaluator, -{ +pub struct PowerMutationalStage { map_observer_name: String, mutator: M, #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, F, EM, I, O, OT, S, Z)>, + phantom: PhantomData<(E, F, EM, O, Z)>, } -impl MutationalStage - for PowerMutationalStage +impl UsesState for PowerMutationalStage where - E: Executor + HasObservers, - F: TestcaseScore, - I: Input, - M: Mutator, + E: UsesState, +{ + type State = E::State; +} + +impl MutationalStage for PowerMutationalStage +where + E: Executor + HasObservers, + EM: UsesState, + F: TestcaseScore, + M: Mutator, O: MapObserver, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, - Z: Evaluator, + E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, + Z: Evaluator, { /// The mutator, added to this stage #[inline] @@ -62,7 +58,7 @@ where /// Gets the number of iterations as a random number #[allow(clippy::cast_sign_loss)] - fn iterations(&self, state: &mut S, corpus_idx: usize) -> Result { + fn iterations(&self, state: &mut E::State, corpus_idx: usize) -> Result { // Update handicap let mut testcase = state.corpus().get(corpus_idx)?.borrow_mut(); let score = F::compute(&mut *testcase, state)? as usize; @@ -75,7 +71,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut E::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -129,17 +125,15 @@ where } } -impl Stage - for PowerMutationalStage +impl Stage for PowerMutationalStage where - E: Executor + HasObservers, - F: TestcaseScore, - I: Input, - M: Mutator, + E: Executor + HasObservers, + EM: UsesState, + F: TestcaseScore, + M: Mutator, O: MapObserver, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, - Z: Evaluator, + E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, + Z: Evaluator, { #[inline] #[allow(clippy::let_and_return)] @@ -147,7 +141,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut E::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -156,16 +150,15 @@ where } } -impl PowerMutationalStage +impl PowerMutationalStage where - E: Executor + HasObservers, - F: TestcaseScore, - I: Input, - M: Mutator, + E: Executor + HasObservers, + EM: UsesState, + F: TestcaseScore, + M: Mutator, O: MapObserver, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasMetadata, - Z: Evaluator, + E::State: HasClientPerfMonitor + HasCorpus + HasMetadata + HasRand, + Z: Evaluator, { /// Creates a new [`PowerMutationalStage`] pub fn new(mutator: M, map_observer_name: &O) -> Self { @@ -178,5 +171,5 @@ where } /// The standard powerscheduling stage -pub type StdPowerMutationalStage = - PowerMutationalStage, EM, I, M, O, OT, S, Z>; +pub type StdPowerMutationalStage = + PowerMutationalStage::State>, EM, M, O, Z>; diff --git a/libafl/src/stages/push/mod.rs b/libafl/src/stages/push/mod.rs index b53dffb2e6..add7aa0370 100644 --- a/libafl/src/stages/push/mod.rs +++ b/libafl/src/stages/push/mod.rs @@ -19,10 +19,10 @@ use crate::{ bolts::current_time, events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, executors::ExitKind, - inputs::Input, + inputs::UsesInput, observers::ObserversTuple, schedulers::Scheduler, - state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMetadata, HasRand}, + state::{HasClientPerfMonitor, HasExecutions, HasMetadata, HasRand}, Error, EvaluatorObservers, ExecutionProcessor, HasScheduler, }; @@ -32,38 +32,36 @@ const STATS_TIMEOUT_DEFAULT: Duration = Duration::from_secs(15); // The shared state for all [`PushStage`]s /// Should be stored inside a `[Rc>`] #[derive(Clone, Debug)] -pub struct PushStageSharedState +pub struct PushStageSharedState where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - I: Input, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId, + OT: ObserversTuple, + CS::State: HasClientPerfMonitor + HasRand, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// The [`crate::state::State`] - pub state: S, + pub state: CS::State, /// The [`crate::fuzzer::Fuzzer`] instance pub fuzzer: Z, /// The [`crate::events::EventManager`] pub event_mgr: EM, /// The [`crate::observers::ObserversTuple`] pub observers: OT, - phantom: PhantomData<(CS, I, OT, S, Z)>, + phantom: PhantomData<(CS, Z)>, } -impl PushStageSharedState +impl PushStageSharedState where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - I: Input, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId, + OT: ObserversTuple, + CS::State: HasClientPerfMonitor + HasRand, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Create a new `PushStageSharedState` that can be used by all [`PushStage`]s #[must_use] - pub fn new(fuzzer: Z, state: S, observers: OT, event_mgr: EM) -> Self { + pub fn new(fuzzer: Z, state: CS::State, observers: OT, event_mgr: EM) -> Self { Self { state, fuzzer, @@ -76,14 +74,13 @@ where /// Helper class for the [`PushStage`] trait, taking care of borrowing the shared state #[derive(Clone, Debug)] -pub struct PushStageHelper +pub struct PushStageHelper where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - I: Input, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId, + OT: ObserversTuple, + CS::State: HasClientPerfMonitor + HasRand, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// If this stage has already been initalized. /// This gets reset to `false` after one iteration of the stage is done. @@ -92,7 +89,7 @@ where pub last_monitor_time: Duration, /// The shared state, keeping track of the corpus and the fuzzer #[allow(clippy::type_complexity)] - pub shared_state: Rc>>>, + pub shared_state: Rc>>>, /// If the last iteration failed pub errored: bool, @@ -100,27 +97,26 @@ where pub current_corpus_idx: Option, /// The input we just ran - pub current_input: Option, // Todo: Get rid of copy + pub current_input: Option<::Input>, // Todo: Get rid of copy #[allow(clippy::type_complexity)] - phantom: PhantomData<(CS, (), EM, I, OT, S, Z)>, + phantom: PhantomData<(CS, EM, OT, Z)>, exit_kind: Rc>>, } -impl PushStageHelper +impl PushStageHelper where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - I: Input, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId, + OT: ObserversTuple, + CS::State: HasClientPerfMonitor + HasRand, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Create a new [`PushStageHelper`] #[must_use] #[allow(clippy::type_complexity)] pub fn new( - shared_state: Rc>>>, + shared_state: Rc>>>, exit_kind_ref: Rc>>, ) -> Self { Self { @@ -137,14 +133,14 @@ where /// Sets the shared state for this helper (and all other helpers owning the same [`RefCell`]) #[inline] - pub fn set_shared_state(&mut self, shared_state: PushStageSharedState) { + pub fn set_shared_state(&mut self, shared_state: PushStageSharedState) { (*self.shared_state.borrow_mut()).replace(shared_state); } /// Takes the shared state from this helper, replacing it with `None` #[inline] #[allow(clippy::type_complexity)] - pub fn take_shared_state(&mut self) -> Option> { + pub fn take_shared_state(&mut self) -> Option> { let shared_state_ref = &mut (*self.shared_state).borrow_mut(); shared_state_ref.take() } @@ -163,11 +159,7 @@ where } /// Resets this state after a full stage iter. - fn end_of_iter( - &mut self, - shared_state: PushStageSharedState, - errored: bool, - ) { + fn end_of_iter(&mut self, shared_state: PushStageSharedState, errored: bool) { self.set_shared_state(shared_state); self.errored = errored; self.current_corpus_idx = None; @@ -180,19 +172,18 @@ where /// A push stage is a generator that returns a single testcase for each call. /// It's an iterator so we can chain it. /// After it has finished once, we will call it agan for the next fuzzer round. -pub trait PushStage: Iterator +pub trait PushStage: Iterator where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - I: Input, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + CS::State: HasClientPerfMonitor + HasRand + HasExecutions + HasMetadata, + EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, + OT: ObserversTuple, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Gets the [`PushStageHelper`] - fn push_stage_helper(&self) -> &PushStageHelper; + fn push_stage_helper(&self) -> &PushStageHelper; /// Gets the [`PushStageHelper`] (mutable) - fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper; + fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper; /// Set the current corpus index this stage works on fn set_current_corpus_idx(&mut self, corpus_idx: usize) { @@ -206,7 +197,7 @@ where fn init( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut CS::State, _event_mgr: &mut EM, _observers: &mut OT, ) -> Result<(), Error> { @@ -219,20 +210,20 @@ where fn pre_exec( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut CS::State, _event_mgr: &mut EM, _observers: &mut OT, - ) -> Option>; + ) -> Option::Input, Error>>; /// Called after the execution of a testcase finished. #[inline] fn post_exec( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut CS::State, _event_mgr: &mut EM, _observers: &mut OT, - _input: I, + _input: ::Input, _exit_kind: ExitKind, ) -> Result<(), Error> { Ok(()) @@ -243,7 +234,7 @@ where fn deinit( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut CS::State, _event_mgr: &mut EM, _observers: &mut OT, ) -> Result<(), Error> { @@ -251,7 +242,7 @@ where } /// This is the default implementation for `next` for this stage - fn next_std(&mut self) -> Option> { + fn next_std(&mut self) -> Option::Input, Error>> { let mut shared_state = { let shared_state_ref = &mut (*self.push_stage_helper_mut().shared_state).borrow_mut(); shared_state_ref.take().unwrap() diff --git a/libafl/src/stages/push/mutational.rs b/libafl/src/stages/push/mutational.rs index edcc4192a6..62907ca4e5 100644 --- a/libafl/src/stages/push/mutational.rs +++ b/libafl/src/stages/push/mutational.rs @@ -2,7 +2,10 @@ //! For the current input, it will perform a range of random mutations, and then run them in the executor. use alloc::rc::Rc; -use core::cell::{Cell, RefCell}; +use core::{ + cell::{Cell, RefCell}, + fmt::Debug, +}; use super::{PushStage, PushStageHelper, PushStageSharedState}; #[cfg(feature = "introspection")] @@ -12,7 +15,7 @@ use crate::{ corpus::Corpus, events::{EventFirer, EventRestarter, HasEventManagerId, ProgressReporter}, executors::ExitKind, - inputs::Input, + inputs::UsesInput, mark_feature_time, mutators::Mutator, observers::ObserversTuple, @@ -34,15 +37,14 @@ pub static DEFAULT_MUTATIONAL_MAX_ITERATIONS: u64 = 128; /// /// The default mutational push stage #[derive(Clone, Debug)] -pub struct StdMutationalPushStage +pub struct StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - I: Input, - M: Mutator, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId, + M: Mutator, + OT: ObserversTuple, + CS::State: HasClientPerfMonitor + HasRand + Clone + Debug, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { current_corpus_idx: Option, testcases_to_do: usize, @@ -52,22 +54,21 @@ where mutator: M, - psh: PushStageHelper, + psh: PushStageHelper, } -impl StdMutationalPushStage +impl StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - I: Input, - M: Mutator, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId, + M: Mutator, + OT: ObserversTuple, + CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Gets the number of iterations as a random number #[allow(clippy::unused_self, clippy::unnecessary_wraps)] // TODO: we should put this function into a trait later - fn iterations(&self, state: &mut S, _corpus_idx: usize) -> Result { + fn iterations(&self, state: &mut CS::State, _corpus_idx: usize) -> Result { Ok(1 + state.rand_mut().below(DEFAULT_MUTATIONAL_MAX_ITERATIONS) as usize) } @@ -77,22 +78,31 @@ where } } -impl PushStage - for StdMutationalPushStage +impl PushStage for StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - I: Input, - M: Mutator, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, + M: Mutator, + OT: ObserversTuple, + CS::State: + HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { + #[inline] + fn push_stage_helper(&self) -> &PushStageHelper { + &self.psh + } + + #[inline] + fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper { + &mut self.psh + } + /// Creates a new default mutational stage fn init( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut CS::State, _event_mgr: &mut EM, _observers: &mut OT, ) -> Result<(), Error> { @@ -108,25 +118,13 @@ where Ok(()) } - #[inline] - fn deinit( - &mut self, - _fuzzer: &mut Z, - _state: &mut S, - _event_mgr: &mut EM, - _observers: &mut OT, - ) -> Result<(), Error> { - self.current_corpus_idx = None; - Ok(()) - } - fn pre_exec( &mut self, _fuzzer: &mut Z, - state: &mut S, + state: &mut CS::State, _event_mgr: &mut EM, _observers: &mut OT, - ) -> Option> { + ) -> Option::Input, Error>> { if self.testcases_done >= self.testcases_to_do { // finished with this cicle. return None; @@ -159,10 +157,10 @@ where fn post_exec( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut CS::State, event_mgr: &mut EM, observers: &mut OT, - last_input: I, + last_input: ::Input, exit_kind: ExitKind, ) -> Result<(), Error> { // todo: isintersting, etc. @@ -179,49 +177,50 @@ where } #[inline] - fn push_stage_helper(&self) -> &PushStageHelper { - &self.psh - } - - #[inline] - fn push_stage_helper_mut(&mut self) -> &mut PushStageHelper { - &mut self.psh + fn deinit( + &mut self, + _fuzzer: &mut Z, + _state: &mut CS::State, + _event_mgr: &mut EM, + _observers: &mut OT, + ) -> Result<(), Error> { + self.current_corpus_idx = None; + Ok(()) } } -impl Iterator for StdMutationalPushStage +impl Iterator for StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, - I: Input, - M: Mutator, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId + ProgressReporter, + M: Mutator, + OT: ObserversTuple, + CS::State: + HasClientPerfMonitor + HasCorpus + HasRand + HasExecutions + HasMetadata + Clone + Debug, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { - type Item = Result; + type Item = Result<::Input, Error>; - fn next(&mut self) -> Option> { + fn next(&mut self) -> Option::Input, Error>> { self.next_std() } } -impl StdMutationalPushStage +impl StdMutationalPushStage where - CS: Scheduler, - EM: EventFirer + EventRestarter + HasEventManagerId, - I: Input, - M: Mutator, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasRand, - Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, + CS: Scheduler, + EM: EventFirer + EventRestarter + HasEventManagerId, + M: Mutator, + OT: ObserversTuple, + CS::State: HasClientPerfMonitor + HasCorpus + HasRand + Clone + Debug, + Z: ExecutionProcessor + EvaluatorObservers + HasScheduler, { /// Creates a new default mutational stage #[must_use] #[allow(clippy::type_complexity)] pub fn new( mutator: M, - shared_state: Rc>>>, + shared_state: Rc>>>, exit_kind: Rc>>, stage_idx: i32, ) -> Self { diff --git a/libafl/src/stages/sync.rs b/libafl/src/stages/sync.rs index bb72417abd..567b1daf7b 100644 --- a/libafl/src/stages/sync.rs +++ b/libafl/src/stages/sync.rs @@ -12,9 +12,9 @@ use serde::{Deserialize, Serialize}; use crate::{ fuzzer::Evaluator, - inputs::Input, + inputs::{Input, UsesInput}, stages::Stage, - state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand}, + state::{HasClientPerfMonitor, HasCorpus, HasMetadata, HasRand, UsesState}, Error, }; @@ -37,32 +37,33 @@ impl SyncFromDiskMetadata { /// A stage that loads testcases from disk to sync with other fuzzers such as AFL++ #[derive(Debug)] -pub struct SyncFromDiskStage -where - CB: FnMut(&mut Z, &mut S, &Path) -> Result, - I: Input, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, - Z: Evaluator, -{ +pub struct SyncFromDiskStage { sync_dir: PathBuf, load_callback: CB, - #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, I, S, Z)>, + phantom: PhantomData<(E, EM, Z)>, } -impl Stage for SyncFromDiskStage +impl UsesState for SyncFromDiskStage where - CB: FnMut(&mut Z, &mut S, &Path) -> Result, - I: Input, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, - Z: Evaluator, + E: UsesState, +{ + type State = E::State; +} + +impl Stage for SyncFromDiskStage +where + CB: FnMut(&mut Z, &mut Z::State, &Path) -> Result<::Input, Error>, + E: UsesState, + EM: UsesState, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, { #[inline] fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut Z::State, manager: &mut EM, _corpus_idx: usize, ) -> Result<(), Error> { @@ -94,12 +95,13 @@ where } } -impl SyncFromDiskStage +impl SyncFromDiskStage where - CB: FnMut(&mut Z, &mut S, &Path) -> Result, - I: Input, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, - Z: Evaluator, + CB: FnMut(&mut Z, &mut Z::State, &Path) -> Result<::Input, Error>, + E: UsesState, + EM: UsesState, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, { /// Creates a new [`SyncFromDiskStage`] #[must_use] @@ -117,7 +119,7 @@ where last: &Option, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut Z::State, manager: &mut EM, ) -> Result, Error> { let mut max_time = None; @@ -157,23 +159,29 @@ where } /// Function type when the callback in `SyncFromDiskStage` is not a lambda -pub type SyncFromDiskFunction = fn(&mut Z, &mut S, &Path) -> Result; +pub type SyncFromDiskFunction = + fn(&mut Z, &mut S, &Path) -> Result<::Input, Error>; -impl SyncFromDiskStage, E, EM, I, S, Z> +impl SyncFromDiskStage, E, EM, Z> where - I: Input, - S: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, - Z: Evaluator, + E: UsesState, + EM: UsesState, + Z: Evaluator, + Z::State: HasClientPerfMonitor + HasCorpus + HasRand + HasMetadata, { /// Creates a new [`SyncFromDiskStage`] invoking `Input::from_file` to load inputs #[must_use] pub fn with_from_file(sync_dir: PathBuf) -> Self { - fn load_callback(_: &mut Z, _: &mut S, p: &Path) -> Result { - I::from_file(p) + fn load_callback( + _: &mut Z, + _: &mut S, + p: &Path, + ) -> Result { + Input::from_file(p) } Self { sync_dir, - load_callback: load_callback::<_, _, I>, + load_callback: load_callback::<_, _>, phantom: PhantomData, } } diff --git a/libafl/src/stages/tmin.rs b/libafl/src/stages/tmin.rs index ead937aed6..dfd4e3639b 100644 --- a/libafl/src/stages/tmin.rs +++ b/libafl/src/stages/tmin.rs @@ -17,36 +17,36 @@ use crate::{ events::EventFirer, executors::{Executor, ExitKind, HasObservers}, feedbacks::{Feedback, FeedbackFactory, HasObserverName}, - inputs::Input, + inputs::UsesInput, mark_feature_time, mutators::Mutator, observers::{MapObserver, ObserversTuple}, schedulers::Scheduler, stages::Stage, start_timer, - state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMaxSize}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasMaxSize, UsesState}, Error, ExecutesInput, ExecutionProcessor, HasFeedback, HasScheduler, }; /// Mutational stage which minimizes corpus entries. /// /// You must provide at least one mutator that actually reduces size. -pub trait TMinMutationalStage: - Stage + FeedbackFactory +pub trait TMinMutationalStage: + Stage + FeedbackFactory where - CS: Scheduler, - E: Executor + HasObservers, - EM: EventFirer, - F1: Feedback, - F2: Feedback, - I: Input + Hash + HasLen, - M: Mutator, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize, - Z: ExecutionProcessor - + ExecutesInput - + HasFeedback - + HasScheduler, + Self::State: HasCorpus + HasExecutions + HasMaxSize + HasClientPerfMonitor, + ::Input: HasLen + Hash, + CS: Scheduler, + E: Executor + HasObservers, + EM: EventFirer, + F1: Feedback, + F2: Feedback, + M: Mutator, + OT: ObserversTuple, + Z: ExecutionProcessor + + ExecutesInput + + HasFeedback + + HasScheduler, { /// The mutator registered for this stage fn mutator(&self) -> &M; @@ -55,7 +55,7 @@ where fn mutator_mut(&mut self) -> &mut M; /// Gets the number of iterations this mutator should run for. - fn iterations(&self, state: &mut S, corpus_idx: usize) -> Result; + fn iterations(&self, state: &mut CS::State, corpus_idx: usize) -> Result; /// Runs this (mutational) stage for new objectives #[allow(clippy::cast_possible_wrap)] // more than i32 stages on 32 bit system - highly unlikely... @@ -63,7 +63,7 @@ where &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut CS::State, manager: &mut EM, base_corpus_idx: usize, ) -> Result<(), Error> { @@ -165,41 +165,47 @@ where /// The default corpus entry minimising mutational stage #[derive(Clone, Debug)] -pub struct StdTMinMutationalStage -where - I: Input + HasLen, - M: Mutator, -{ +pub struct StdTMinMutationalStage { mutator: M, factory: FF, runs: usize, #[allow(clippy::type_complexity)] - phantom: PhantomData<(CS, E, EM, F1, F2, I, S, T, Z)>, + phantom: PhantomData<(CS, E, EM, F1, F2, OT, Z)>, } -impl Stage - for StdTMinMutationalStage +impl UsesState + for StdTMinMutationalStage where - CS: Scheduler, - E: Executor + HasObservers, - EM: EventFirer, - F1: Feedback, - F2: Feedback, - FF: FeedbackFactory, - I: Input + Hash + HasLen, - M: Mutator, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize, - Z: ExecutionProcessor - + ExecutesInput - + HasFeedback - + HasScheduler, + CS: Scheduler, + M: Mutator, + Z: ExecutionProcessor, +{ + type State = CS::State; +} + +impl Stage + for StdTMinMutationalStage +where + CS: Scheduler, + CS::State: HasCorpus + HasExecutions + HasMaxSize + HasClientPerfMonitor, + ::Input: HasLen + Hash, + E: Executor + HasObservers, + EM: EventFirer, + F1: Feedback, + F2: Feedback, + FF: FeedbackFactory, + M: Mutator, + OT: ObserversTuple, + Z: ExecutionProcessor + + ExecutesInput + + HasFeedback + + HasScheduler, { fn perform( &mut self, fuzzer: &mut Z, executor: &mut E, - state: &mut S, + state: &mut CS::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -212,37 +218,36 @@ where } } -impl FeedbackFactory - for StdTMinMutationalStage +impl FeedbackFactory + for StdTMinMutationalStage where - F2: Feedback, - FF: FeedbackFactory, - I: Input + HasLen, - M: Mutator, - S: HasClientPerfMonitor, + F2: Feedback, + FF: FeedbackFactory, + Z: UsesState, + Z::State: HasClientPerfMonitor, { - fn create_feedback(&self, ctx: &T) -> F2 { + fn create_feedback(&self, ctx: &OT) -> F2 { self.factory.create_feedback(ctx) } } -impl TMinMutationalStage - for StdTMinMutationalStage +impl TMinMutationalStage + for StdTMinMutationalStage where - CS: Scheduler, - E: HasObservers + Executor, - EM: EventFirer, - F1: Feedback, - F2: Feedback, - FF: FeedbackFactory, - I: Input + HasLen + Hash, - M: Mutator, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize, - Z: ExecutionProcessor - + ExecutesInput - + HasFeedback - + HasScheduler, + CS: Scheduler, + E: HasObservers + Executor, + EM: EventFirer, + F1: Feedback, + F2: Feedback, + FF: FeedbackFactory, + ::Input: HasLen + Hash, + M: Mutator, + OT: ObserversTuple, + CS::State: HasClientPerfMonitor + HasCorpus + HasExecutions + HasMaxSize, + Z: ExecutionProcessor + + ExecutesInput + + HasFeedback + + HasScheduler, { /// The mutator, added to this stage #[inline] @@ -257,16 +262,16 @@ where } /// Gets the number of iterations from a fixed number of runs - fn iterations(&self, _state: &mut S, _corpus_idx: usize) -> Result { + fn iterations(&self, _state: &mut CS::State, _corpus_idx: usize) -> Result { Ok(self.runs) } } -impl - StdTMinMutationalStage +impl StdTMinMutationalStage where - I: Input + HasLen, - M: Mutator, + CS: Scheduler, + M: Mutator, + Z: ExecutionProcessor, { /// Creates a new minimising mutational stage that will minimize provided corpus entries pub fn new(mutator: M, factory: FF, runs: usize) -> Self { @@ -282,14 +287,14 @@ where /// A feedback which checks if the hash of the currently observed map is equal to the original hash /// provided #[derive(Clone, Debug)] -pub struct MapEqualityFeedback { +pub struct MapEqualityFeedback { name: String, obs_name: String, orig_hash: u64, - phantom: PhantomData, + phantom: PhantomData<(M, S)>, } -impl MapEqualityFeedback { +impl MapEqualityFeedback { /// Create a new map equality feedback -- can be used with feedback logic #[must_use] pub fn new(name: &str, obs_name: &str, orig_hash: u64) -> Self { @@ -302,35 +307,34 @@ impl MapEqualityFeedback { } } -impl Named for MapEqualityFeedback { +impl Named for MapEqualityFeedback { fn name(&self) -> &str { &self.name } } -impl HasObserverName for MapEqualityFeedback { +impl HasObserverName for MapEqualityFeedback { fn observer_name(&self) -> &str { &self.obs_name } } -impl Feedback for MapEqualityFeedback +impl Feedback for MapEqualityFeedback where - I: Input, - M: MapObserver, - S: HasClientPerfMonitor, + M: MapObserver + Debug, + S: UsesInput + HasClientPerfMonitor + Debug, { fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { let obs = observers .match_name::(self.observer_name()) @@ -341,12 +345,12 @@ where /// A feedback factory for ensuring that the maps for minimized inputs are the same #[derive(Debug, Clone)] -pub struct MapEqualityFactory { +pub struct MapEqualityFactory { obs_name: String, - phantom: PhantomData, + phantom: PhantomData<(M, S)>, } -impl MapEqualityFactory +impl MapEqualityFactory where M: MapObserver, { @@ -359,20 +363,19 @@ where } } -impl HasObserverName for MapEqualityFactory { +impl HasObserverName for MapEqualityFactory { fn observer_name(&self) -> &str { &self.obs_name } } -impl FeedbackFactory, I, S, OT> for MapEqualityFactory +impl FeedbackFactory, S, OT> for MapEqualityFactory where - I: Input, M: MapObserver, - OT: ObserversTuple, - S: HasClientPerfMonitor, + OT: ObserversTuple, + S: UsesInput + HasClientPerfMonitor + Debug, { - fn create_feedback(&self, observers: &OT) -> MapEqualityFeedback { + fn create_feedback(&self, observers: &OT) -> MapEqualityFeedback { let obs = observers .match_name::(self.observer_name()) .expect("Should have been provided valid observer name."); diff --git a/libafl/src/stages/tracing.rs b/libafl/src/stages/tracing.rs index e15de9c839..725354048d 100644 --- a/libafl/src/stages/tracing.rs +++ b/libafl/src/stages/tracing.rs @@ -7,42 +7,43 @@ use crate::monitors::PerfFeature; use crate::{ corpus::Corpus, executors::{Executor, HasObservers, ShadowExecutor}, - inputs::Input, mark_feature_time, observers::ObserversTuple, stages::Stage, start_timer, - state::{HasClientPerfMonitor, HasCorpus, HasExecutions}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, State, UsesState}, Error, }; /// A stage that runs a tracer executor #[derive(Clone, Debug)] -pub struct TracingStage -where - I: Input, - TE: Executor + HasObservers, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, -{ +pub struct TracingStage { tracer_executor: TE, #[allow(clippy::type_complexity)] - phantom: PhantomData<(EM, I, OT, S, TE, Z)>, + phantom: PhantomData<(EM, TE, Z)>, } -impl Stage for TracingStage +impl UsesState for TracingStage where - I: Input, - TE: Executor + HasObservers, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, + TE: UsesState, +{ + type State = TE::State; +} + +impl Stage for TracingStage +where + E: UsesState, + TE: Executor + HasObservers, + TE::State: HasClientPerfMonitor + HasExecutions + HasCorpus, + EM: UsesState, + Z: UsesState, { #[inline] fn perform( &mut self, fuzzer: &mut Z, _executor: &mut E, - state: &mut S, + state: &mut TE::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -79,13 +80,7 @@ where } } -impl TracingStage -where - I: Input, - TE: Executor + HasObservers, - OT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, -{ +impl TracingStage { /// Creates a new default stage pub fn new(tracer_executor: TE) -> Self { Self { @@ -102,26 +97,32 @@ where /// A stage that runs the shadow executor using also the shadow observers #[derive(Clone, Debug)] -pub struct ShadowTracingStage { +pub struct ShadowTracingStage { #[allow(clippy::type_complexity)] - phantom: PhantomData<(E, EM, I, OT, S, SOT, Z)>, + phantom: PhantomData<(E, EM, SOT, Z)>, } -impl Stage, EM, S, Z> - for ShadowTracingStage +impl UsesState for ShadowTracingStage where - I: Input, - E: Executor + HasObservers, - OT: ObserversTuple, - SOT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasCorpus + Debug, + E: UsesState, +{ + type State = E::State; +} + +impl Stage, EM, Z> for ShadowTracingStage +where + E: Executor + HasObservers, + EM: UsesState, + SOT: ObserversTuple, + Z: UsesState, + E::State: State + HasClientPerfMonitor + HasExecutions + HasCorpus + Debug, { #[inline] fn perform( &mut self, fuzzer: &mut Z, - executor: &mut ShadowExecutor, - state: &mut S, + executor: &mut ShadowExecutor, + state: &mut E::State, manager: &mut EM, corpus_idx: usize, ) -> Result<(), Error> { @@ -160,16 +161,16 @@ where } } -impl ShadowTracingStage +impl ShadowTracingStage where - I: Input, - E: Executor + HasObservers, - OT: ObserversTuple, - SOT: ObserversTuple, - S: HasClientPerfMonitor + HasExecutions + HasCorpus, + E: Executor + HasObservers, + E::State: State + HasClientPerfMonitor + HasExecutions + HasCorpus, + EM: UsesState, + SOT: ObserversTuple, + Z: UsesState, { /// Creates a new default stage - pub fn new(_executor: &mut ShadowExecutor) -> Self { + pub fn new(_executor: &mut ShadowExecutor) -> Self { Self { phantom: PhantomData, } diff --git a/libafl/src/state/mod.rs b/libafl/src/state/mod.rs index f9cca8a193..240620c5a6 100644 --- a/libafl/src/state/mod.rs +++ b/libafl/src/state/mod.rs @@ -19,7 +19,7 @@ use crate::{ feedbacks::Feedback, fuzzer::{Evaluator, ExecuteInputResult}, generators::Generator, - inputs::Input, + inputs::{Input, UsesInput}, monitors::ClientPerfMonitor, Error, }; @@ -29,13 +29,28 @@ pub const DEFAULT_MAX_SIZE: usize = 1_048_576; /// The [`State`] of the fuzzer. /// Contains all important information about the current run. -/// Will be used to restart the fuzzing process at any timme. -pub trait State: Serialize + DeserializeOwned {} +/// Will be used to restart the fuzzing process at any time. +pub trait State: UsesInput + Serialize + DeserializeOwned {} + +/// Structs which implement this trait are aware of the state. This is used for type enforcement. +pub trait UsesState: UsesInput::Input> { + /// The state known by this type. + type State: UsesInput; +} + +// blanket impl which automatically defines UsesInput for anything that implements UsesState +impl UsesInput for KS +where + KS: UsesState, +{ + type Input = ::Input; +} /// Trait for elements offering a corpus -pub trait HasCorpus { +pub trait HasCorpus: UsesInput { /// The associated type implementing [`Corpus`]. - type Corpus: Corpus; + type Corpus: Corpus::Input>; + /// The testcase corpus fn corpus(&self) -> &Self::Corpus; /// The testcase corpus (mutable) @@ -51,9 +66,10 @@ pub trait HasMaxSize { } /// Trait for elements offering a corpus of solutions -pub trait HasSolutions { +pub trait HasSolutions: UsesInput { /// The associated type implementing [`Corpus`] for solutions - type Solutions: Corpus; + type Solutions: Corpus::Input>; + /// The solutions corpus fn solutions(&self) -> &Self::Solutions; /// The solutions corpus (mutable) @@ -151,14 +167,12 @@ pub trait HasStartTime { /// The state a fuzz run. #[derive(Serialize, Deserialize, Clone, Debug)] -#[serde(bound = "C: serde::Serialize + for<'a> serde::Deserialize<'a>")] -pub struct StdState -where - C: Corpus, - I: Input, - R: Rand, - SC: Corpus, -{ +#[serde(bound = " + C: serde::Serialize + for<'a> serde::Deserialize<'a>, + SC: serde::Serialize + for<'a> serde::Deserialize<'a>, + R: serde::Serialize + for<'a> serde::Deserialize<'a> + ")] +pub struct StdState { /// RNG instance rand: R, /// How many times the executor ran the harness/target @@ -178,25 +192,28 @@ where /// Performance statistics for this fuzzer #[cfg(feature = "introspection")] introspection_monitor: ClientPerfMonitor, - phantom: PhantomData, } -impl State for StdState +impl UsesInput for StdState where - C: Corpus, I: Input, +{ + type Input = I; +} + +impl State for StdState +where + C: Corpus, R: Rand, - SC: Corpus, + SC: Corpus, + Self: UsesInput, { } -impl HasRand for StdState +impl HasRand for StdState where - C: Corpus, - I: Input, R: Rand, - SC: Corpus, { type Rand = R; @@ -213,34 +230,31 @@ where } } -impl HasCorpus for StdState +impl HasCorpus for StdState where - C: Corpus, I: Input, + C: Corpus::Input>, R: Rand, - SC: Corpus, { type Corpus = C; /// Returns the corpus #[inline] - fn corpus(&self) -> &C { + fn corpus(&self) -> &Self::Corpus { &self.corpus } /// Returns the mutable corpus #[inline] - fn corpus_mut(&mut self) -> &mut C { + fn corpus_mut(&mut self) -> &mut Self::Corpus { &mut self.corpus } } -impl HasSolutions for StdState +impl HasSolutions for StdState where - C: Corpus, I: Input, - R: Rand, - SC: Corpus, + SC: Corpus::Input>, { type Solutions = SC; @@ -257,13 +271,7 @@ where } } -impl HasMetadata for StdState -where - C: Corpus, - I: Input, - R: Rand, - SC: Corpus, -{ +impl HasMetadata for StdState { /// Get all the metadata into an [`hashbrown::HashMap`] #[inline] fn metadata(&self) -> &SerdeAnyMap { @@ -277,13 +285,7 @@ where } } -impl HasNamedMetadata for StdState -where - C: Corpus, - I: Input, - R: Rand, - SC: Corpus, -{ +impl HasNamedMetadata for StdState { /// Get all the metadata into an [`hashbrown::HashMap`] #[inline] fn named_metadata(&self) -> &NamedSerdeAnyMap { @@ -297,13 +299,7 @@ where } } -impl HasExecutions for StdState -where - C: Corpus, - I: Input, - R: Rand, - SC: Corpus, -{ +impl HasExecutions for StdState { /// The executions counter #[inline] fn executions(&self) -> &usize { @@ -317,13 +313,7 @@ where } } -impl HasMaxSize for StdState -where - C: Corpus, - I: Input, - R: Rand, - SC: Corpus, -{ +impl HasMaxSize for StdState { fn max_size(&self) -> usize { self.max_size } @@ -333,13 +323,7 @@ where } } -impl HasStartTime for StdState -where - C: Corpus, - I: Input, - R: Rand, - SC: Corpus, -{ +impl HasStartTime for StdState { /// The starting time #[inline] fn start_time(&self) -> &Duration { @@ -354,12 +338,12 @@ where } #[cfg(feature = "std")] -impl StdState +impl StdState where - C: Corpus, I: Input, + C: Corpus::Input>, R: Rand, - SC: Corpus, + SC: Corpus::Input>, { /// Loads inputs from a directory. /// If `forced` is `true`, the value will be loaded, @@ -374,7 +358,9 @@ where loader: &mut dyn FnMut(&mut Z, &mut Self, &Path) -> Result, ) -> Result<(), Error> where - Z: Evaluator, + E: UsesState, + EM: UsesState, + Z: Evaluator, { for entry in fs::read_dir(in_dir)? { let entry = entry?; @@ -417,8 +403,9 @@ where forced: bool, ) -> Result<(), Error> where - Z: Evaluator, - EM: EventFirer, + E: UsesState, + EM: EventFirer, + Z: Evaluator, { for in_dir in in_dirs { self.load_from_directory( @@ -435,7 +422,7 @@ where Event::Log { severity_level: LogSeverity::Debug, message: format!("Loaded {} initial testcases.", self.corpus().count()), // get corpus count - phantom: PhantomData, + phantom: PhantomData::, }, )?; Ok(()) @@ -452,8 +439,9 @@ where in_dirs: &[PathBuf], ) -> Result<(), Error> where - Z: Evaluator, - EM: EventFirer, + E: UsesState, + EM: EventFirer, + Z: Evaluator, { self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, true) } @@ -467,19 +455,20 @@ where in_dirs: &[PathBuf], ) -> Result<(), Error> where - Z: Evaluator, - EM: EventFirer, + E: UsesState, + EM: EventFirer, + Z: Evaluator, { self.load_initial_inputs_internal(fuzzer, executor, manager, in_dirs, false) } } -impl StdState +impl StdState where - C: Corpus, I: Input, + C: Corpus::Input>, R: Rand, - SC: Corpus, + SC: Corpus::Input>, { fn generate_initial_internal( &mut self, @@ -491,9 +480,10 @@ where forced: bool, ) -> Result<(), Error> where - G: Generator, - Z: Evaluator, - EM: EventFirer, + E: UsesState, + EM: EventFirer, + G: Generator<::Input, Self>, + Z: Evaluator, { let mut added = 0; for _ in 0..num { @@ -529,9 +519,10 @@ where num: usize, ) -> Result<(), Error> where - G: Generator, - Z: Evaluator, - EM: EventFirer, + E: UsesState, + EM: EventFirer, + G: Generator<::Input, Self>, + Z: Evaluator, { self.generate_initial_internal(fuzzer, executor, generator, manager, num, true) } @@ -546,9 +537,10 @@ where num: usize, ) -> Result<(), Error> where - G: Generator, - Z: Evaluator, - EM: EventFirer, + E: UsesState, + EM: EventFirer, + G: Generator<::Input, Self>, + Z: Evaluator, { self.generate_initial_internal(fuzzer, executor, generator, manager, num, false) } @@ -562,8 +554,8 @@ where objective: &mut O, ) -> Result where - F: Feedback, - O: Feedback, + F: Feedback, + O: Feedback, { let mut state = Self { rand, @@ -585,13 +577,7 @@ where } #[cfg(feature = "introspection")] -impl HasClientPerfMonitor for StdState -where - C: Corpus, - I: Input, - R: Rand, - SC: Corpus, -{ +impl HasClientPerfMonitor for StdState { fn introspection_monitor(&self) -> &ClientPerfMonitor { &self.introspection_monitor } @@ -602,13 +588,7 @@ where } #[cfg(not(feature = "introspection"))] -impl HasClientPerfMonitor for StdState -where - C: Corpus, - I: Input, - R: Rand, - SC: Corpus, -{ +impl HasClientPerfMonitor for StdState { fn introspection_monitor(&self) -> &ClientPerfMonitor { unimplemented!() } @@ -618,6 +598,67 @@ where } } +#[cfg(test)] +#[derive(Debug, Serialize, Deserialize, Default)] +pub struct NopState { + phantom: PhantomData, +} + +#[cfg(test)] +impl NopState { + /// Create a new State that does nothing (for tests) + #[must_use] + pub fn new() -> Self { + NopState { + phantom: PhantomData, + } + } +} + +#[cfg(test)] +impl UsesInput for NopState +where + I: Input, +{ + type Input = I; +} + +#[cfg(test)] +impl HasExecutions for NopState { + fn executions(&self) -> &usize { + unimplemented!() + } + + fn executions_mut(&mut self) -> &mut usize { + unimplemented!() + } +} + +#[cfg(test)] +impl HasMetadata for NopState { + fn metadata(&self) -> &SerdeAnyMap { + unimplemented!() + } + + fn metadata_mut(&mut self) -> &mut SerdeAnyMap { + unimplemented!() + } +} + +#[cfg(test)] +impl HasClientPerfMonitor for NopState { + fn introspection_monitor(&self) -> &ClientPerfMonitor { + unimplemented!() + } + + fn introspection_monitor_mut(&mut self) -> &mut ClientPerfMonitor { + unimplemented!() + } +} + +#[cfg(test)] +impl State for NopState where I: Input {} + #[cfg(feature = "python")] #[allow(missing_docs)] /// `State` Python bindings @@ -643,7 +684,7 @@ pub mod pybind { }; /// `StdState` with fixed generics - pub type PythonStdState = StdState; + pub type PythonStdState = StdState; #[pyclass(unsendable, name = "StdState")] #[derive(Debug)] diff --git a/libafl_frida/src/asan/errors.rs b/libafl_frida/src/asan/errors.rs index 3621455e57..e9846b0d39 100644 --- a/libafl_frida/src/asan/errors.rs +++ b/libafl_frida/src/asan/errors.rs @@ -1,5 +1,5 @@ //! Errors that can be caught by the `libafl_frida` address sanitizer. -use std::io::Write; +use std::{fmt::Debug, io::Write, marker::PhantomData}; use backtrace::Backtrace; use capstone::{arch::BuildsCapstone, Capstone}; @@ -13,7 +13,7 @@ use libafl::{ events::EventFirer, executors::ExitKind, feedbacks::Feedback, - inputs::{HasTargetBytes, Input}, + inputs::{HasTargetBytes, UsesInput}, observers::{Observer, ObserversTuple}, state::{HasClientPerfMonitor, HasMetadata}, Error, SerdeAny, @@ -551,8 +551,11 @@ pub struct AsanErrorsObserver { errors: OwnedPtr>, } -impl Observer for AsanErrorsObserver { - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { +impl Observer for AsanErrorsObserver +where + S: UsesInput, +{ + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { unsafe { if ASAN_ERRORS.is_some() { ASAN_ERRORS.as_mut().unwrap().clear(); @@ -607,27 +610,28 @@ impl AsanErrorsObserver { /// A feedback reporting potential [`struct@AsanErrors`] from an `AsanErrorsObserver` #[derive(Serialize, Deserialize, Clone, Debug)] -pub struct AsanErrorsFeedback { +pub struct AsanErrorsFeedback { errors: Option, + phantom: PhantomData, } -impl Feedback for AsanErrorsFeedback +impl Feedback for AsanErrorsFeedback where - I: Input + HasTargetBytes, - S: HasClientPerfMonitor, + S: UsesInput + Debug + HasClientPerfMonitor, + S::Input: HasTargetBytes, { #[allow(clippy::wrong_self_convention)] fn is_interesting( &mut self, _state: &mut S, _manager: &mut EM, - _input: &I, + _input: &S::Input, observers: &OT, _exit_kind: &ExitKind, ) -> Result where - EM: EventFirer, - OT: ObserversTuple, + EM: EventFirer, + OT: ObserversTuple, { let observer = observers .match_name::("AsanErrors") @@ -645,7 +649,11 @@ where } } - fn append_metadata(&mut self, _state: &mut S, testcase: &mut Testcase) -> Result<(), Error> { + fn append_metadata( + &mut self, + _state: &mut S, + testcase: &mut Testcase, + ) -> Result<(), Error> { if let Some(errors) = &self.errors { testcase.add_metadata(errors.clone()); } @@ -653,28 +661,31 @@ where Ok(()) } - fn discard_metadata(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn discard_metadata(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.errors = None; Ok(()) } } -impl Named for AsanErrorsFeedback { +impl Named for AsanErrorsFeedback { #[inline] fn name(&self) -> &str { "AsanErrors" } } -impl AsanErrorsFeedback { +impl AsanErrorsFeedback { /// Create a new `AsanErrorsFeedback` #[must_use] pub fn new() -> Self { - Self { errors: None } + Self { + errors: None, + phantom: PhantomData, + } } } -impl Default for AsanErrorsFeedback { +impl Default for AsanErrorsFeedback { fn default() -> Self { Self::new() } diff --git a/libafl_frida/src/executor.rs b/libafl_frida/src/executor.rs index d9e4fa4b67..e572b73ba0 100644 --- a/libafl_frida/src/executor.rs +++ b/libafl_frida/src/executor.rs @@ -6,11 +6,15 @@ use frida_gum::{ Gum, MemoryRange, NativePointer, }; #[cfg(windows)] -use libafl::executors::inprocess::{HasInProcessHandlers, InProcessHandlers}; +use libafl::{ + executors::inprocess::{HasInProcessHandlers, InProcessHandlers}, + state::{HasClientPerfMonitor, HasSolutions}, +}; use libafl::{ executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, - inputs::{HasTargetBytes, Input}, - observers::ObserversTuple, + inputs::{HasTargetBytes, UsesInput}, + observers::{ObserversTuple, UsesObservers}, + state::UsesState, Error, }; @@ -21,13 +25,14 @@ use crate::helper::{FridaInstrumentationHelper, FridaRuntimeTuple}; use crate::windows_hooks::initialize; /// The [`FridaInProcessExecutor`] is an [`Executor`] that executes the target in the same process, usinig [`frida`](https://frida.re/) for binary-only instrumentation. -pub struct FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> +pub struct FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> where - H: FnMut(&I) -> ExitKind, - I: Input + HasTargetBytes, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind, + S::Input: HasTargetBytes, + S: UsesInput, + OT: ObserversTuple, { - base: InProcessExecutor<'a, H, I, OT, S>, + base: InProcessExecutor<'a, H, OT, S>, /// Frida's dynamic rewriting engine stalker: Stalker<'a>, /// User provided callback for instrumentation @@ -36,11 +41,12 @@ where _phantom: PhantomData<&'b u8>, } -impl<'a, 'b, 'c, H, I, OT, RT, S> Debug for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> +impl<'a, 'b, 'c, H, OT, RT, S> Debug for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> where - H: FnMut(&I) -> ExitKind, - I: Input + HasTargetBytes, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + S::Input: HasTargetBytes, + OT: ObserversTuple, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("FridaInProcessExecutor") @@ -51,22 +57,25 @@ where } } -impl<'a, 'b, 'c, EM, H, I, OT, RT, S, Z> Executor - for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> +impl<'a, 'b, 'c, EM, H, OT, RT, S, Z> Executor + for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> where - H: FnMut(&I) -> ExitKind, - I: Input + HasTargetBytes, - OT: ObserversTuple, + EM: UsesState, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + S::Input: HasTargetBytes, + OT: ObserversTuple, RT: FridaRuntimeTuple, + Z: UsesState, { /// Instruct the target about the input and run #[inline] fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { self.helper.pre_exec(input)?; if self.helper.stalker_enabled() { @@ -94,12 +103,32 @@ where } } -impl<'a, 'b, 'c, H, I, OT, RT, S> HasObservers - for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> +impl<'a, 'b, 'c, H, OT, RT, S> UsesObservers for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> where - H: FnMut(&I) -> ExitKind, - I: Input + HasTargetBytes, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + S: UsesInput, + S::Input: HasTargetBytes, +{ + type Observers = OT; +} + +impl<'a, 'b, 'c, H, OT, RT, S> UsesState for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> +where + H: FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + S: UsesInput, + S::Input: HasTargetBytes, +{ + type State = S; +} + +impl<'a, 'b, 'c, H, OT, RT, S> HasObservers for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> +where + H: FnMut(&S::Input) -> ExitKind, + S::Input: HasTargetBytes, + S: UsesInput, + OT: ObserversTuple, { #[inline] fn observers(&self) -> &OT { @@ -112,17 +141,18 @@ where } } -impl<'a, 'b, 'c, H, I, OT, S, RT> FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> +impl<'a, 'b, 'c, H, OT, S, RT> FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> where - H: FnMut(&I) -> ExitKind, - I: Input + HasTargetBytes, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + S::Input: HasTargetBytes, + OT: ObserversTuple, RT: FridaRuntimeTuple, { /// Creates a new [`FridaInProcessExecutor`] pub fn new( gum: &'a Gum, - base: InProcessExecutor<'a, H, I, OT, S>, + base: InProcessExecutor<'a, H, OT, S>, helper: &'c mut FridaInstrumentationHelper<'b, RT>, ) -> Self { let mut stalker = Stalker::new(gum); @@ -162,12 +192,13 @@ where } #[cfg(windows)] -impl<'a, 'b, 'c, H, I, OT, RT, S> HasInProcessHandlers - for FridaInProcessExecutor<'a, 'b, 'c, H, I, OT, RT, S> +impl<'a, 'b, 'c, H, OT, RT, S> HasInProcessHandlers + for FridaInProcessExecutor<'a, 'b, 'c, H, OT, RT, S> where - H: FnMut(&I) -> ExitKind, - I: Input + HasTargetBytes, - OT: ObserversTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput + HasClientPerfMonitor + HasSolutions, + S::Input: HasTargetBytes, + OT: ObserversTuple, RT: FridaRuntimeTuple, { /// the timeout handler diff --git a/libafl_nyx/src/executor.rs b/libafl_nyx/src/executor.rs index b75e477274..8f756cb104 100644 --- a/libafl_nyx/src/executor.rs +++ b/libafl_nyx/src/executor.rs @@ -3,8 +3,9 @@ use std::{fmt::Debug, marker::PhantomData}; use libafl::{ bolts::AsSlice, executors::{Executor, ExitKind, HasObservers}, - inputs::{HasTargetBytes, Input}, - observers::ObserversTuple, + inputs::{HasTargetBytes, UsesInput}, + observers::{ObserversTuple, UsesObservers}, + state::{State, UsesState}, Error, }; use libnyx::NyxReturnValue; @@ -12,16 +13,16 @@ use libnyx::NyxReturnValue; use crate::helper::NyxHelper; /// executor for nyx standalone mode -pub struct NyxExecutor<'a, I, S, OT> { +pub struct NyxExecutor<'a, S, OT> { /// implement nyx function pub helper: &'a mut NyxHelper, /// observers observers: OT, /// phantom data to keep generic type - phantom: PhantomData<(I, S)>, + phantom: PhantomData, } -impl<'a, I, S, OT> Debug for NyxExecutor<'a, I, S, OT> { +impl<'a, S, OT> Debug for NyxExecutor<'a, S, OT> { fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { f.debug_struct("NyxInprocessExecutor") .field("helper", &self.helper) @@ -29,17 +30,35 @@ impl<'a, I, S, OT> Debug for NyxExecutor<'a, I, S, OT> { } } -impl<'a, EM, I, S, Z, OT> Executor for NyxExecutor<'a, I, S, OT> +impl<'a, S, OT> UsesState for NyxExecutor<'a, S, OT> where - I: Input + HasTargetBytes, + S: UsesInput, +{ + type State = S; +} + +impl<'a, S, OT> UsesObservers for NyxExecutor<'a, S, OT> +where + OT: ObserversTuple, + S: UsesInput, +{ + type Observers = OT; +} + +impl<'a, EM, S, Z, OT> Executor for NyxExecutor<'a, S, OT> +where + EM: UsesState, + S: UsesInput, + S::Input: HasTargetBytes, + Z: UsesState, { fn run_target( &mut self, _fuzzer: &mut Z, - _state: &mut S, + _state: &mut Self::State, _mgr: &mut EM, - input: &I, - ) -> Result { + input: &Self::Input, + ) -> Result { let input_owned = input.target_bytes(); let input = input_owned.as_slice(); self.helper.nyx_process.set_input(input, input.len() as u32); @@ -68,7 +87,7 @@ where } } -impl<'a, I, S, OT> NyxExecutor<'a, I, S, OT> { +impl<'a, S, OT> NyxExecutor<'a, S, OT> { pub fn new(helper: &'a mut NyxHelper, observers: OT) -> Result { Ok(Self { helper, @@ -83,10 +102,10 @@ impl<'a, I, S, OT> NyxExecutor<'a, I, S, OT> { } } -impl<'a, I, S, OT> HasObservers for NyxExecutor<'a, I, S, OT> +impl<'a, S, OT> HasObservers for NyxExecutor<'a, S, OT> where - I: Input, - OT: ObserversTuple, + S: State, + OT: ObserversTuple, { fn observers(&self) -> &OT { &self.observers diff --git a/libafl_qemu/src/asan.rs b/libafl_qemu/src/asan.rs index 4f3607e4bb..28c0070bb4 100644 --- a/libafl_qemu/src/asan.rs +++ b/libafl_qemu/src/asan.rs @@ -1,6 +1,6 @@ use std::{env, fs, ptr}; -use libafl::{inputs::Input, state::HasMetadata}; +use libafl::{inputs::UsesInput, state::HasMetadata}; use num_enum::{IntoPrimitive, TryFromPrimitive}; use crate::{ @@ -407,52 +407,51 @@ impl Default for QemuAsanHelper { } } -impl QemuHelper for QemuAsanHelper +impl QemuHelper for QemuAsanHelper where - I: Input, - S: HasMetadata, + S: UsesInput + HasMetadata, { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn init_hooks(&self, hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { hooks.reads( - Some(gen_readwrite_asan::), - Some(trace_read1_asan::), - Some(trace_read2_asan::), - Some(trace_read4_asan::), - Some(trace_read8_asan::), - Some(trace_read_n_asan::), + Some(gen_readwrite_asan::), + Some(trace_read1_asan::), + Some(trace_read2_asan::), + Some(trace_read4_asan::), + Some(trace_read8_asan::), + Some(trace_read_n_asan::), ); hooks.writes( - Some(gen_readwrite_asan::), - Some(trace_write1_asan::), - Some(trace_write2_asan::), - Some(trace_write4_asan::), - Some(trace_write8_asan::), - Some(trace_write_n_asan::), + Some(gen_readwrite_asan::), + Some(trace_write1_asan::), + Some(trace_write2_asan::), + Some(trace_write4_asan::), + Some(trace_write8_asan::), + Some(trace_write_n_asan::), ); - hooks.syscalls(qasan_fake_syscall::); + hooks.syscalls(qasan_fake_syscall::); } - fn post_exec(&mut self, _emulator: &Emulator, _input: &I) { + fn post_exec(&mut self, _emulator: &Emulator, _input: &S::Input) { self.reset(); } } -pub fn gen_readwrite_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn gen_readwrite_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr, _size: usize, ) -> Option where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let h = hooks.match_helper_mut::().unwrap(); if h.must_instrument(pc.into()) { @@ -461,142 +460,142 @@ where None } } -pub fn trace_read1_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_read1_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.read_1(&emulator, addr); } -pub fn trace_read2_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_read2_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.read_2(&emulator, addr); } -pub fn trace_read4_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_read4_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.read_4(&emulator, addr); } -pub fn trace_read8_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_read8_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.read_8(&emulator, addr); } -pub fn trace_read_n_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_read_n_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, size: usize, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.read_n(&emulator, addr, size); } -pub fn trace_write1_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write1_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.write_1(&emulator, addr); } -pub fn trace_write2_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write2_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.write_2(&emulator, addr); } -pub fn trace_write4_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write4_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.write_4(&emulator, addr); } -pub fn trace_write8_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write8_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); h.write_8(&emulator, addr); } -pub fn trace_write_n_asan( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write_n_asan( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, size: usize, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emulator = hooks.emulator().clone(); let h = hooks.match_helper_mut::().unwrap(); @@ -604,8 +603,8 @@ pub fn trace_write_n_asan( } #[allow(clippy::too_many_arguments)] -pub fn qasan_fake_syscall( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn qasan_fake_syscall( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, sys_num: i32, a0: u64, @@ -618,8 +617,8 @@ pub fn qasan_fake_syscall( _a7: u64, ) -> SyscallHookResult where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { if sys_num == QASAN_FAKESYS_NR { let emulator = hooks.emulator().clone(); diff --git a/libafl_qemu/src/calls.rs b/libafl_qemu/src/calls.rs index 239e17e108..e187518206 100644 --- a/libafl_qemu/src/calls.rs +++ b/libafl_qemu/src/calls.rs @@ -1,5 +1,5 @@ use capstone::prelude::*; -use libafl::inputs::Input; +use libafl::inputs::UsesInput; use crate::{ capstone, @@ -46,33 +46,33 @@ impl Default for QemuCallTracerHelper { } } -impl QemuHelper for QemuCallTracerHelper +impl QemuHelper for QemuCallTracerHelper where - I: Input, + S: UsesInput, { - fn init_hooks<'a, QT>(&self, hooks: &QemuHooks<'a, I, QT, S>) + fn init_hooks<'a, QT>(&self, hooks: &QemuHooks<'a, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { - hooks.blocks(Some(gen_blocks_calls::), None); + hooks.blocks(Some(gen_blocks_calls::), None); } - fn pre_exec(&mut self, _emulator: &Emulator, _input: &I) { + fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) { self.reset(); } } -/*pub fn on_call(hooks: &mut QemuHooks<'_, I, QT, S>, _state: Option<&mut S>, pc: GuestAddr) +/*pub fn on_call(hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr) where - I: Input, - QT: QemuHelperTuple, + + QT: QemuHelperTuple, { }*/ -pub fn on_ret(hooks: &mut QemuHooks<'_, I, QT, S>, _state: Option<&mut S>, _pc: GuestAddr) +pub fn on_ret(hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _pc: GuestAddr) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { #[cfg(cpu_target = "x86_64")] let ret_addr = { @@ -113,14 +113,14 @@ where } } -pub fn gen_blocks_calls( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn gen_blocks_calls( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr, ) -> Option where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let emu = hooks.emulator(); if let Some(h) = hooks.helpers().match_first_type::() { @@ -155,7 +155,7 @@ where capstone::InsnGroupType::CS_GRP_CALL => { // hooks.instruction_closure(insn.address() as GuestAddr, on_call, false); let call_len = insn.bytes().len() as GuestAddr; - let call_cb = move |hooks: &mut QemuHooks<'_, I, QT, S>, _, pc| { + let call_cb = move |hooks: &mut QemuHooks<'_, QT, S>, _, pc| { // eprintln!("CALL @ 0x{:#x}", pc + call_len); if let Some(h) = hooks .helpers_mut() diff --git a/libafl_qemu/src/cmplog.rs b/libafl_qemu/src/cmplog.rs index 84f36f3332..7c72aa1092 100644 --- a/libafl_qemu/src/cmplog.rs +++ b/libafl_qemu/src/cmplog.rs @@ -1,5 +1,5 @@ use hashbrown::HashMap; -use libafl::{inputs::Input, state::HasMetadata}; +use libafl::{inputs::UsesInput, state::HasMetadata}; pub use libafl_targets::{ cmplog::__libafl_targets_cmplog_instructions, CmpLogMap, CmpLogObserver, CMPLOG_MAP, CMPLOG_MAP_H, CMPLOG_MAP_PTR, CMPLOG_MAP_SIZE, CMPLOG_MAP_W, @@ -53,17 +53,16 @@ impl Default for QemuCmpLogHelper { } } -impl QemuHelper for QemuCmpLogHelper +impl QemuHelper for QemuCmpLogHelper where - I: Input, - S: HasMetadata, + S: UsesInput + HasMetadata, { - fn init_hooks(&self, hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { hooks.cmps_raw( - Some(gen_unique_cmp_ids::), + Some(gen_unique_cmp_ids::), Some(trace_cmp1_cmplog), Some(trace_cmp2_cmplog), Some(trace_cmp4_cmplog), @@ -95,19 +94,19 @@ impl Default for QemuCmpLogChildHelper { } } -impl QemuHelper for QemuCmpLogChildHelper +impl QemuHelper for QemuCmpLogChildHelper where - I: Input, + S: UsesInput, S: HasMetadata, { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn init_hooks(&self, hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { hooks.cmps_raw( - Some(gen_hashed_cmp_ids::), + Some(gen_hashed_cmp_ids::), Some(trace_cmp1_cmplog), Some(trace_cmp2_cmplog), Some(trace_cmp4_cmplog), @@ -116,16 +115,16 @@ where } } -pub fn gen_unique_cmp_ids( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn gen_unique_cmp_ids( + hooks: &mut QemuHooks<'_, QT, S>, state: Option<&mut S>, pc: GuestAddr, _size: usize, ) -> Option where S: HasMetadata, - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { if let Some(h) = hooks.match_helper_mut::() { if !h.must_instrument(pc.into()) { @@ -148,16 +147,16 @@ where })) } -pub fn gen_hashed_cmp_ids( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn gen_hashed_cmp_ids( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr, _size: usize, ) -> Option where S: HasMetadata, - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { if let Some(h) = hooks.match_helper_mut::() { if !h.must_instrument(pc.into()) { diff --git a/libafl_qemu/src/edges.rs b/libafl_qemu/src/edges.rs index b7485d8e44..84e85e87bd 100644 --- a/libafl_qemu/src/edges.rs +++ b/libafl_qemu/src/edges.rs @@ -1,7 +1,7 @@ use std::{cell::UnsafeCell, cmp::max}; use hashbrown::{hash_map::Entry, HashMap}; -use libafl::{inputs::Input, state::HasMetadata}; +use libafl::{inputs::UsesInput, state::HasMetadata}; pub use libafl_targets::{ edges_max_num, EDGES_MAP, EDGES_MAP_PTR, EDGES_MAP_PTR_SIZE, EDGES_MAP_SIZE, MAX_EDGES_NUM, }; @@ -66,25 +66,21 @@ impl Default for QemuEdgeCoverageHelper { } } -impl QemuHelper for QemuEdgeCoverageHelper +impl QemuHelper for QemuEdgeCoverageHelper where - I: Input, - S: HasMetadata, + S: UsesInput + HasMetadata, { - fn init_hooks(&self, hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { if self.use_hitcounts { hooks.edges_raw( - Some(gen_unique_edge_ids::), + Some(gen_unique_edge_ids::), Some(trace_edge_hitcount), ); } else { - hooks.edges_raw( - Some(gen_unique_edge_ids::), - Some(trace_edge_single), - ); + hooks.edges_raw(Some(gen_unique_edge_ids::), Some(trace_edge_single)); } } } @@ -126,25 +122,25 @@ impl Default for QemuEdgeCoverageChildHelper { } } -impl QemuHelper for QemuEdgeCoverageChildHelper +impl QemuHelper for QemuEdgeCoverageChildHelper where - I: Input, + S: UsesInput, S: HasMetadata, { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn init_hooks(&self, hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { if self.use_hitcounts { hooks.edges_raw( - Some(gen_hashed_edge_ids::), + Some(gen_hashed_edge_ids::), Some(trace_edge_hitcount_ptr), ); } else { hooks.edges_raw( - Some(gen_hashed_edge_ids::), + Some(gen_hashed_edge_ids::), Some(trace_edge_single_ptr), ); } @@ -153,16 +149,16 @@ where thread_local!(static PREV_LOC : UnsafeCell = UnsafeCell::new(0)); -pub fn gen_unique_edge_ids( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn gen_unique_edge_ids( + hooks: &mut QemuHooks<'_, QT, S>, state: Option<&mut S>, src: GuestAddr, dest: GuestAddr, ) -> Option where S: HasMetadata, - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { if let Some(h) = hooks.helpers().match_first_type::() { if !h.must_instrument(src.into()) && !h.must_instrument(dest.into()) { @@ -213,15 +209,15 @@ pub extern "C" fn trace_edge_single(id: u64, _data: u64) { } } -pub fn gen_hashed_edge_ids( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn gen_hashed_edge_ids( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, src: GuestAddr, dest: GuestAddr, ) -> Option where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { if let Some(h) = hooks .helpers() @@ -250,28 +246,28 @@ pub extern "C" fn trace_edge_single_ptr(id: u64, _data: u64) { } } -pub fn gen_addr_block_ids( - _hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn gen_addr_block_ids( + _hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr, ) -> Option where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { // GuestAddress is u32 for 32 bit guests #[allow(clippy::unnecessary_cast)] Some(pc as u64) } -pub fn gen_hashed_block_ids( - _hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn gen_hashed_block_ids( + _hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, pc: GuestAddr, ) -> Option where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { // GuestAddress is u32 for 32 bit guests #[allow(clippy::unnecessary_cast)] diff --git a/libafl_qemu/src/emu.rs b/libafl_qemu/src/emu.rs index c608edea83..fa6c236013 100644 --- a/libafl_qemu/src/emu.rs +++ b/libafl_qemu/src/emu.rs @@ -244,8 +244,10 @@ extern "C" { static mut libafl_start_vcpu: extern "C" fn(cpu: CPUStatePtr); + /* fn libafl_save_qemu_snapshot(name: *const u8); fn libafl_load_qemu_snapshot(name: *const u8); + */ } #[cfg(not(feature = "usermode"))] diff --git a/libafl_qemu/src/executor.rs b/libafl_qemu/src/executor.rs index ab59ef32de..caa6eaddcb 100644 --- a/libafl_qemu/src/executor.rs +++ b/libafl_qemu/src/executor.rs @@ -2,40 +2,41 @@ use core::fmt::{self, Debug, Formatter}; #[cfg(feature = "fork")] -use libafl::bolts::shmem::ShMemProvider; -#[cfg(feature = "fork")] -use libafl::executors::InProcessForkExecutor; +use libafl::{ + bolts::shmem::ShMemProvider, events::EventManager, executors::InProcessForkExecutor, + state::HasMetadata, +}; use libafl::{ events::{EventFirer, EventRestarter}, executors::{Executor, ExitKind, HasObservers, InProcessExecutor}, feedbacks::Feedback, fuzzer::HasObjective, - inputs::Input, - observers::ObserversTuple, - state::{HasClientPerfMonitor, HasSolutions}, + inputs::UsesInput, + observers::{ObserversTuple, UsesObservers}, + state::{HasClientPerfMonitor, HasCorpus, HasExecutions, HasSolutions, State, UsesState}, Error, }; pub use crate::emu::SyscallHookResult; use crate::{emu::Emulator, helper::QemuHelperTuple, hooks::QemuHooks}; -pub struct QemuExecutor<'a, H, I, OT, QT, S> +pub struct QemuExecutor<'a, H, OT, QT, S> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, { - hooks: &'a mut QemuHooks<'a, I, QT, S>, - inner: InProcessExecutor<'a, H, I, OT, S>, + hooks: &'a mut QemuHooks<'a, QT, S>, + inner: InProcessExecutor<'a, H, OT, S>, } -impl<'a, H, I, OT, QT, S> Debug for QemuExecutor<'a, H, I, OT, QT, S> +impl<'a, H, OT, QT, S> Debug for QemuExecutor<'a, H, OT, QT, S> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("QemuExecutor") @@ -45,15 +46,15 @@ where } } -impl<'a, H, I, OT, QT, S> QemuExecutor<'a, H, I, OT, QT, S> +impl<'a, H, OT, QT, S> QemuExecutor<'a, H, OT, QT, S> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, { pub fn new( - hooks: &'a mut QemuHooks<'a, I, QT, S>, + hooks: &'a mut QemuHooks<'a, QT, S>, harness_fn: &'a mut H, observers: OT, fuzzer: &mut Z, @@ -61,10 +62,10 @@ where event_mgr: &mut EM, ) -> Result where - EM: EventFirer + EventRestarter, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + EM: EventFirer + EventRestarter, + OF: Feedback, + S: State + HasExecutions + HasCorpus + HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { Ok(Self { hooks, @@ -72,19 +73,19 @@ where }) } - pub fn inner(&self) -> &InProcessExecutor<'a, H, I, OT, S> { + pub fn inner(&self) -> &InProcessExecutor<'a, H, OT, S> { &self.inner } - pub fn inner_mut(&mut self) -> &mut InProcessExecutor<'a, H, I, OT, S> { + pub fn inner_mut(&mut self) -> &mut InProcessExecutor<'a, H, OT, S> { &mut self.inner } - pub fn hooks(&self) -> &QemuHooks<'a, I, QT, S> { + pub fn hooks(&self) -> &QemuHooks<'a, QT, S> { self.hooks } - pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, I, QT, S> { + pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, QT, S> { self.hooks } @@ -93,19 +94,21 @@ where } } -impl<'a, EM, H, I, OT, QT, S, Z> Executor for QemuExecutor<'a, H, I, OT, QT, S> +impl<'a, EM, H, OT, QT, S, Z> Executor for QemuExecutor<'a, H, OT, QT, S> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + EM: UsesState, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { let emu = Emulator::new_empty(); self.hooks.helpers_mut().pre_exec_all(&emu, input); @@ -115,12 +118,32 @@ where } } -impl<'a, H, I, OT, QT, S> HasObservers for QemuExecutor<'a, H, I, OT, QT, S> +impl<'a, H, OT, QT, S> UsesState for QemuExecutor<'a, H, OT, QT, S> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + H: FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + QT: QemuHelperTuple, + S: UsesInput, +{ + type State = S; +} + +impl<'a, H, OT, QT, S> UsesObservers for QemuExecutor<'a, H, OT, QT, S> +where + H: FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + QT: QemuHelperTuple, + S: UsesInput, +{ + type Observers = OT; +} + +impl<'a, H, OT, QT, S> HasObservers for QemuExecutor<'a, H, OT, QT, S> +where + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, { #[inline] fn observers(&self) -> &OT { @@ -134,25 +157,25 @@ where } #[cfg(feature = "fork")] -pub struct QemuForkExecutor<'a, H, I, OT, QT, S, SP> +pub struct QemuForkExecutor<'a, H, OT, QT, S, SP> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, SP: ShMemProvider, { - hooks: &'a mut QemuHooks<'a, I, QT, S>, - inner: InProcessForkExecutor<'a, H, I, OT, S, SP>, + hooks: &'a mut QemuHooks<'a, QT, S>, + inner: InProcessForkExecutor<'a, H, OT, S, SP>, } #[cfg(feature = "fork")] -impl<'a, H, I, OT, QT, S, SP> Debug for QemuForkExecutor<'a, H, I, OT, QT, S, SP> +impl<'a, H, OT, QT, S, SP> Debug for QemuForkExecutor<'a, H, OT, QT, S, SP> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, SP: ShMemProvider, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { @@ -164,16 +187,16 @@ where } #[cfg(feature = "fork")] -impl<'a, H, I, OT, QT, S, SP> QemuForkExecutor<'a, H, I, OT, QT, S, SP> +impl<'a, H, OT, QT, S, SP> QemuForkExecutor<'a, H, OT, QT, S, SP> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, SP: ShMemProvider, { pub fn new( - hooks: &'a mut QemuHooks<'a, I, QT, S>, + hooks: &'a mut QemuHooks<'a, QT, S>, harness_fn: &'a mut H, observers: OT, fuzzer: &mut Z, @@ -182,10 +205,10 @@ where shmem_provider: SP, ) -> Result where - EM: EventFirer + EventRestarter, - OF: Feedback, - S: HasSolutions + HasClientPerfMonitor, - Z: HasObjective, + EM: EventFirer + EventRestarter, + OF: Feedback, + S: HasSolutions + HasClientPerfMonitor, + Z: HasObjective, { assert!(!QT::HOOKS_DO_SIDE_EFFECTS, "When using QemuForkExecutor, the hooks must not do any side effect as they will happen in the child process and then discarded"); @@ -202,19 +225,19 @@ where }) } - pub fn inner(&self) -> &InProcessForkExecutor<'a, H, I, OT, S, SP> { + pub fn inner(&self) -> &InProcessForkExecutor<'a, H, OT, S, SP> { &self.inner } - pub fn inner_mut(&mut self) -> &mut InProcessForkExecutor<'a, H, I, OT, S, SP> { + pub fn inner_mut(&mut self) -> &mut InProcessForkExecutor<'a, H, OT, S, SP> { &mut self.inner } - pub fn hooks(&self) -> &QemuHooks<'a, I, QT, S> { + pub fn hooks(&self) -> &QemuHooks<'a, QT, S> { self.hooks } - pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, I, QT, S> { + pub fn hooks_mut(&mut self) -> &mut QemuHooks<'a, QT, S> { self.hooks } @@ -224,21 +247,22 @@ where } #[cfg(feature = "fork")] -impl<'a, EM, H, I, OT, QT, S, Z, SP> Executor - for QemuForkExecutor<'a, H, I, OT, QT, S, SP> +impl<'a, EM, H, OT, QT, S, Z, SP> Executor for QemuForkExecutor<'a, H, OT, QT, S, SP> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + EM: EventManager, Z, State = S>, + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput + HasClientPerfMonitor + HasMetadata + HasExecutions, + OT: ObserversTuple, + QT: QemuHelperTuple, SP: ShMemProvider, + Z: UsesState, { fn run_target( &mut self, fuzzer: &mut Z, - state: &mut S, + state: &mut Self::State, mgr: &mut EM, - input: &I, + input: &Self::Input, ) -> Result { let emu = Emulator::new_empty(); self.hooks.helpers_mut().pre_exec_all(&emu, input); @@ -249,12 +273,36 @@ where } #[cfg(feature = "fork")] -impl<'a, H, I, OT, QT, S, SP> HasObservers for QemuForkExecutor<'a, H, I, OT, QT, S, SP> +impl<'a, H, OT, QT, S, SP> UsesObservers for QemuForkExecutor<'a, H, OT, QT, S, SP> where - H: FnMut(&I) -> ExitKind, - I: Input, - OT: ObserversTuple, - QT: QemuHelperTuple, + H: FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + QT: QemuHelperTuple, + S: UsesInput, + SP: ShMemProvider, +{ + type Observers = OT; +} + +#[cfg(feature = "fork")] +impl<'a, H, OT, QT, S, SP> UsesState for QemuForkExecutor<'a, H, OT, QT, S, SP> +where + H: FnMut(&S::Input) -> ExitKind, + OT: ObserversTuple, + QT: QemuHelperTuple, + S: UsesInput, + SP: ShMemProvider, +{ + type State = S; +} + +#[cfg(feature = "fork")] +impl<'a, H, OT, QT, S, SP> HasObservers for QemuForkExecutor<'a, H, OT, QT, S, SP> +where + H: FnMut(&S::Input) -> ExitKind, + S: UsesInput, + OT: ObserversTuple, + QT: QemuHelperTuple, SP: ShMemProvider, { #[inline] diff --git a/libafl_qemu/src/helper.rs b/libafl_qemu/src/helper.rs index 8ce48a9ccd..b12b03fdb8 100644 --- a/libafl_qemu/src/helper.rs +++ b/libafl_qemu/src/helper.rs @@ -1,82 +1,82 @@ use core::{fmt::Debug, ops::Range}; -use libafl::{bolts::tuples::MatchFirstType, inputs::Input}; +use libafl::{bolts::tuples::MatchFirstType, inputs::UsesInput}; use crate::{emu::Emulator, hooks::QemuHooks}; /// A helper for `libafl_qemu`. // TODO remove 'static when specialization will be stable -pub trait QemuHelper: 'static + Debug +pub trait QemuHelper: 'static + Debug where - I: Input, + S: UsesInput, { const HOOKS_DO_SIDE_EFFECTS: bool = true; - fn init_hooks(&self, _hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks(&self, _hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { } - fn pre_exec(&mut self, _emulator: &Emulator, _input: &I) {} + fn pre_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {} - fn post_exec(&mut self, _emulator: &Emulator, _input: &I) {} + fn post_exec(&mut self, _emulator: &Emulator, _input: &S::Input) {} } -pub trait QemuHelperTuple: MatchFirstType + Debug +pub trait QemuHelperTuple: MatchFirstType + Debug where - I: Input, + S: UsesInput, { const HOOKS_DO_SIDE_EFFECTS: bool; - fn init_hooks_all(&self, hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks_all(&self, hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple; + QT: QemuHelperTuple; - fn pre_exec_all(&mut self, _emulator: &Emulator, input: &I); + fn pre_exec_all(&mut self, _emulator: &Emulator, input: &S::Input); - fn post_exec_all(&mut self, _emulator: &Emulator, input: &I); + fn post_exec_all(&mut self, _emulator: &Emulator, input: &S::Input); } -impl QemuHelperTuple for () +impl QemuHelperTuple for () where - I: Input, + S: UsesInput, { const HOOKS_DO_SIDE_EFFECTS: bool = false; - fn init_hooks_all(&self, _hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks_all(&self, _hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { } - fn pre_exec_all(&mut self, _emulator: &Emulator, _input: &I) {} + fn pre_exec_all(&mut self, _emulator: &Emulator, _input: &S::Input) {} - fn post_exec_all(&mut self, _emulator: &Emulator, _input: &I) {} + fn post_exec_all(&mut self, _emulator: &Emulator, _input: &S::Input) {} } -impl QemuHelperTuple for (Head, Tail) +impl QemuHelperTuple for (Head, Tail) where - Head: QemuHelper, - Tail: QemuHelperTuple, - I: Input, + Head: QemuHelper, + Tail: QemuHelperTuple, + S: UsesInput, { const HOOKS_DO_SIDE_EFFECTS: bool = Head::HOOKS_DO_SIDE_EFFECTS || Tail::HOOKS_DO_SIDE_EFFECTS; - fn init_hooks_all(&self, hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks_all(&self, hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { self.0.init_hooks(hooks); self.1.init_hooks_all(hooks); } - fn pre_exec_all(&mut self, emulator: &Emulator, input: &I) { + fn pre_exec_all(&mut self, emulator: &Emulator, input: &S::Input) { self.0.pre_exec(emulator, input); self.1.pre_exec_all(emulator, input); } - fn post_exec_all(&mut self, emulator: &Emulator, input: &I) { + fn post_exec_all(&mut self, emulator: &Emulator, input: &S::Input) { self.0.post_exec(emulator, input); self.1.post_exec_all(emulator, input); } diff --git a/libafl_qemu/src/hooks.rs b/libafl_qemu/src/hooks.rs index 4c0e04a6f3..643be274b5 100644 --- a/libafl_qemu/src/hooks.rs +++ b/libafl_qemu/src/hooks.rs @@ -9,7 +9,7 @@ use core::{ ptr::{self, addr_of}, }; -use libafl::{executors::inprocess::inprocess_get_state, inputs::Input}; +use libafl::{executors::inprocess::inprocess_get_state, inputs::UsesInput}; pub use crate::emu::SyscallHookResult; use crate::{ @@ -40,35 +40,35 @@ type DynamicLenHookCl = */ static mut QEMU_HOOKS_PTR: *const c_void = ptr::null(); -unsafe fn get_qemu_hooks<'a, I, QT, S>() -> &'a mut QemuHooks<'a, I, QT, S> +unsafe fn get_qemu_hooks<'a, QT, S>() -> &'a mut QemuHooks<'a, QT, S> where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { - (QEMU_HOOKS_PTR as *mut QemuHooks<'a, I, QT, S>) + (QEMU_HOOKS_PTR as *mut QemuHooks<'a, QT, S>) .as_mut() .expect("A high-level hook is installed but QemuHooks is not initialized") } static mut GENERIC_HOOKS: Vec = vec![]; -extern "C" fn generic_hook_wrapper(pc: GuestAddr, index: u64) +extern "C" fn generic_hook_wrapper(pc: GuestAddr, index: u64) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let hook = &mut GENERIC_HOOKS[index as usize]; match hook { Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, GuestAddr) = + let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) = transmute(*ptr); (func)(hooks, inprocess_get_state::(), pc); } Hook::Closure(ptr) => { let func: &mut Box< - dyn FnMut(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, GuestAddr), + dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr), > = transmute(ptr); (func)(hooks, inprocess_get_state::(), pc); } @@ -79,18 +79,18 @@ where static mut EDGE_HOOKS: Vec<(Hook, Hook)> = vec![]; -extern "C" fn gen_edge_hook_wrapper(src: GuestAddr, dst: GuestAddr, index: u64) -> u64 +extern "C" fn gen_edge_hook_wrapper(src: GuestAddr, dst: GuestAddr, index: u64) -> u64 where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let (gen, _) = &mut EDGE_HOOKS[index as usize]; match gen { Hook::Function(ptr) => { let func: fn( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, GuestAddr, @@ -100,7 +100,7 @@ where Hook::Closure(ptr) => { let func: &mut Box< dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, GuestAddr, @@ -113,21 +113,21 @@ where } } -extern "C" fn exec_edge_hook_wrapper(id: u64, index: u64) +extern "C" fn exec_edge_hook_wrapper(id: u64, index: u64) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let (_, exec) = &mut EDGE_HOOKS[index as usize]; match exec { Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64) = transmute(*ptr); + let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64) = transmute(*ptr); (func)(hooks, inprocess_get_state::(), id); } Hook::Closure(ptr) => { - let func: &mut Box, Option<&mut S>, u64)> = + let func: &mut Box, Option<&mut S>, u64)> = transmute(ptr); (func)(hooks, inprocess_get_state::(), id); } @@ -138,30 +138,23 @@ where static mut BLOCK_HOOKS: Vec<(Hook, Hook)> = vec![]; -extern "C" fn gen_block_hook_wrapper(pc: GuestAddr, index: u64) -> u64 +extern "C" fn gen_block_hook_wrapper(pc: GuestAddr, index: u64) -> u64 where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let (gen, _) = &mut BLOCK_HOOKS[index as usize]; match gen { Hook::Function(ptr) => { - let func: fn( - &mut QemuHooks<'_, I, QT, S>, - Option<&mut S>, - GuestAddr, - ) -> Option = transmute(*ptr); + let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) -> Option = + transmute(*ptr); (func)(hooks, inprocess_get_state::(), pc).map_or(SKIP_EXEC_HOOK, |id| id) } Hook::Closure(ptr) => { let func: &mut Box< - dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, - Option<&mut S>, - GuestAddr, - ) -> Option, + dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr) -> Option, > = transmute(ptr); (func)(hooks, inprocess_get_state::(), pc).map_or(SKIP_EXEC_HOOK, |id| id) } @@ -170,21 +163,21 @@ where } } -extern "C" fn exec_block_hook_wrapper(id: u64, index: u64) +extern "C" fn exec_block_hook_wrapper(id: u64, index: u64) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let (_, exec) = &mut BLOCK_HOOKS[index as usize]; match exec { Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64) = transmute(*ptr); + let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64) = transmute(*ptr); (func)(hooks, inprocess_get_state::(), id); } Hook::Closure(ptr) => { - let func: &mut Box, Option<&mut S>, u64)> = + let func: &mut Box, Option<&mut S>, u64)> = transmute(ptr); (func)(hooks, inprocess_get_state::(), id); } @@ -196,18 +189,18 @@ where static mut READ_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook, Hook)> = vec![]; static mut WRITE_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook, Hook)> = vec![]; -extern "C" fn gen_read_hook_wrapper(pc: GuestAddr, size: usize, index: u64) -> u64 +extern "C" fn gen_read_hook_wrapper(pc: GuestAddr, size: usize, index: u64) -> u64 where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let (gen, _, _, _, _, _) = &mut READ_HOOKS[index as usize]; match gen { Hook::Function(ptr) => { let func: fn( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, usize, @@ -217,7 +210,7 @@ where Hook::Closure(ptr) => { let func: &mut Box< dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, usize, @@ -230,18 +223,18 @@ where } } -extern "C" fn gen_write_hook_wrapper(pc: GuestAddr, size: usize, index: u64) -> u64 +extern "C" fn gen_write_hook_wrapper(pc: GuestAddr, size: usize, index: u64) -> u64 where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let (gen, _, _, _, _, _) = &mut WRITE_HOOKS[index as usize]; match gen { Hook::Function(ptr) => { let func: fn( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, usize, @@ -251,7 +244,7 @@ where Hook::Closure(ptr) => { let func: &mut Box< dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, usize, @@ -266,23 +259,23 @@ where macro_rules! define_rw_exec_hook { ($name:ident, $field:tt, $global:ident) => { - extern "C" fn $name(id: u64, addr: GuestAddr, index: u64) + extern "C" fn $name(id: u64, addr: GuestAddr, index: u64) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let exec = &mut $global[index as usize].$field; match exec { Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64, GuestAddr) = + let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, GuestAddr) = transmute(*ptr); (func)(hooks, inprocess_get_state::(), id, addr); } Hook::Closure(ptr) => { let func: &mut Box< - dyn FnMut(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u64, GuestAddr), + dyn FnMut(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, GuestAddr), > = transmute(ptr); (func)(hooks, inprocess_get_state::(), id, addr); } @@ -295,18 +288,18 @@ macro_rules! define_rw_exec_hook { macro_rules! define_rw_exec_hook_n { ($name:ident, $field:tt, $global:ident) => { - extern "C" fn $name(id: u64, addr: GuestAddr, size: usize, index: u64) + extern "C" fn $name(id: u64, addr: GuestAddr, size: usize, index: u64) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let exec = &mut $global[index as usize].$field; match exec { Hook::Function(ptr) => { let func: fn( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, GuestAddr, @@ -317,7 +310,7 @@ macro_rules! define_rw_exec_hook_n { Hook::Closure(ptr) => { let func: &mut Box< dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, GuestAddr, @@ -347,18 +340,18 @@ define_rw_exec_hook_n!(exec_write_n_hook_wrapper, 5, WRITE_HOOKS); static mut CMP_HOOKS: Vec<(Hook, Hook, Hook, Hook, Hook)> = vec![]; -extern "C" fn gen_cmp_hook_wrapper(pc: GuestAddr, size: usize, index: u64) -> u64 +extern "C" fn gen_cmp_hook_wrapper(pc: GuestAddr, size: usize, index: u64) -> u64 where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let (gen, _, _, _, _) = &mut CMP_HOOKS[index as usize]; match gen { Hook::Function(ptr) => { let func: fn( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, usize, @@ -368,7 +361,7 @@ where Hook::Closure(ptr) => { let func: &mut Box< dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, GuestAddr, usize, @@ -383,18 +376,18 @@ where macro_rules! define_cmp_exec_hook { ($name:ident, $field:tt, $itype:ty) => { - extern "C" fn $name(id: u64, v0: $itype, v1: $itype, index: u64) + extern "C" fn $name(id: u64, v0: $itype, v1: $itype, index: u64) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let exec = &mut CMP_HOOKS[index as usize].$field; match exec { Hook::Function(ptr) => { let func: fn( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, $itype, @@ -405,7 +398,7 @@ macro_rules! define_cmp_exec_hook { Hook::Closure(ptr) => { let func: &mut Box< dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, $itype, @@ -429,31 +422,29 @@ define_cmp_exec_hook!(exec_cmp8_hook_wrapper, 4, u64); #[cfg(feature = "usermode")] static mut ON_THREAD_HOOKS: Vec = vec![]; #[cfg(feature = "usermode")] -extern "C" fn on_thread_hooks_wrapper(tid: u32) +extern "C" fn on_thread_hooks_wrapper(tid: u32) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { for hook in &mut ON_THREAD_HOOKS { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); match hook { Hook::Function(ptr) => { - let func: fn(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u32) = - transmute(*ptr); + let func: fn(&mut QemuHooks<'_, QT, S>, Option<&mut S>, u32) = transmute(*ptr); (func)(hooks, inprocess_get_state::(), tid); } Hook::Closure(ptr) => { - let mut func: Box< - dyn FnMut(&mut QemuHooks<'_, I, QT, S>, Option<&mut S>, u32), - > = transmute(*ptr); + let mut func: Box, Option<&mut S>, u32)> = + transmute(*ptr); (func)(hooks, inprocess_get_state::(), tid); // Forget the closure so that drop is not called on captured variables. core::mem::forget(func); } Hook::Once(ptr) => { - let func: Box, Option<&mut S>, u32)> = + let func: Box, Option<&mut S>, u32)> = transmute(*ptr); (func)(hooks, inprocess_get_state::(), tid); *hook = Hook::Empty; @@ -467,7 +458,7 @@ where #[cfg(feature = "usermode")] static mut SYSCALL_HOOKS: Vec = vec![]; #[cfg(feature = "usermode")] -extern "C" fn syscall_hooks_wrapper( +extern "C" fn syscall_hooks_wrapper( sys_num: i32, a0: u64, a1: u64, @@ -479,18 +470,18 @@ extern "C" fn syscall_hooks_wrapper( a7: u64, ) -> SyscallHookResult where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let mut res = SyscallHookResult::new(None); for hook in &SYSCALL_HOOKS { match hook { Hook::Function(ptr) => { #[allow(clippy::type_complexity)] let func: fn( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, i32, u64, @@ -524,7 +515,7 @@ where #[allow(clippy::type_complexity)] let mut func: Box< dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, i32, u64, @@ -569,7 +560,7 @@ where #[cfg(feature = "usermode")] static mut SYSCALL_POST_HOOKS: Vec = vec![]; #[cfg(feature = "usermode")] -extern "C" fn syscall_after_hooks_wrapper( +extern "C" fn syscall_after_hooks_wrapper( result: u64, sys_num: i32, a0: u64, @@ -582,18 +573,18 @@ extern "C" fn syscall_after_hooks_wrapper( a7: u64, ) -> u64 where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { unsafe { - let hooks = get_qemu_hooks::(); + let hooks = get_qemu_hooks::(); let mut res = result; for hook in &SYSCALL_POST_HOOKS { match hook { Hook::Function(ptr) => { #[allow(clippy::type_complexity)] let func: fn( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, i32, @@ -625,7 +616,7 @@ where #[allow(clippy::type_complexity)] let mut func: Box< dyn FnMut( - &mut QemuHooks<'_, I, QT, S>, + &mut QemuHooks<'_, QT, S>, Option<&mut S>, u64, i32, @@ -666,20 +657,20 @@ where static mut HOOKS_IS_INITIALIZED: bool = false; -pub struct QemuHooks<'a, I, QT, S> +pub struct QemuHooks<'a, QT, S> where - QT: QemuHelperTuple, - I: Input, + QT: QemuHelperTuple, + S: UsesInput, { helpers: QT, emulator: &'a Emulator, - phantom: PhantomData<(I, S)>, + phantom: PhantomData, } -impl<'a, I, QT, S> Debug for QemuHooks<'a, I, QT, S> +impl<'a, QT, S> Debug for QemuHooks<'a, QT, S> where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { fn fmt(&self, f: &mut Formatter<'_>) -> fmt::Result { f.debug_struct("QemuHooks") @@ -689,10 +680,10 @@ where } } -impl<'a, I, QT, S> QemuHooks<'a, I, QT, S> +impl<'a, QT, S> QemuHooks<'a, QT, S> where - QT: QemuHelperTuple, - I: Input, + QT: QemuHelperTuple, + S: UsesInput, { pub fn new(emulator: &'a Emulator, helpers: QT) -> Box { unsafe { @@ -754,7 +745,7 @@ where let index = GENERIC_HOOKS.len(); self.emulator.set_hook( addr, - generic_hook_wrapper::, + generic_hook_wrapper::, index as u64, invalidate_block, ); @@ -771,7 +762,7 @@ where let index = GENERIC_HOOKS.len(); self.emulator.set_hook( addr, - generic_hook_wrapper::, + generic_hook_wrapper::, index as u64, invalidate_block, ); @@ -791,12 +782,12 @@ where if generation_hook.is_none() { None } else { - Some(gen_edge_hook_wrapper::) + Some(gen_edge_hook_wrapper::) }, if execution_hook.is_none() { None } else { - Some(exec_edge_hook_wrapper::) + Some(exec_edge_hook_wrapper::) }, index as u64, ); @@ -823,12 +814,12 @@ where if generation_hook.is_none() { None } else { - Some(gen_edge_hook_wrapper::) + Some(gen_edge_hook_wrapper::) }, if execution_hook.is_none() { None } else { - Some(exec_edge_hook_wrapper::) + Some(exec_edge_hook_wrapper::) }, index as u64, ); @@ -851,7 +842,7 @@ where if generation_hook.is_none() { None } else { - Some(gen_edge_hook_wrapper::) + Some(gen_edge_hook_wrapper::) }, execution_hook, index as u64, @@ -876,12 +867,12 @@ where if generation_hook.is_none() { None } else { - Some(gen_block_hook_wrapper::) + Some(gen_block_hook_wrapper::) }, if execution_hook.is_none() { None } else { - Some(exec_block_hook_wrapper::) + Some(exec_block_hook_wrapper::) }, index as u64, ); @@ -908,12 +899,12 @@ where if generation_hook.is_none() { None } else { - Some(gen_block_hook_wrapper::) + Some(gen_block_hook_wrapper::) }, if execution_hook.is_none() { None } else { - Some(exec_block_hook_wrapper::) + Some(exec_block_hook_wrapper::) }, index as u64, ); @@ -934,7 +925,7 @@ where if generation_hook.is_none() { None } else { - Some(gen_block_hook_wrapper::) + Some(gen_block_hook_wrapper::) }, execution_hook, index as u64, @@ -967,32 +958,32 @@ where if generation_hook.is_none() { None } else { - Some(gen_read_hook_wrapper::) + Some(gen_read_hook_wrapper::) }, if execution_hook1.is_none() { None } else { - Some(exec_read1_hook_wrapper::) + Some(exec_read1_hook_wrapper::) }, if execution_hook2.is_none() { None } else { - Some(exec_read2_hook_wrapper::) + Some(exec_read2_hook_wrapper::) }, if execution_hook4.is_none() { None } else { - Some(exec_read4_hook_wrapper::) + Some(exec_read4_hook_wrapper::) }, if execution_hook8.is_none() { None } else { - Some(exec_read8_hook_wrapper::) + Some(exec_read8_hook_wrapper::) }, if execution_hook_n.is_none() { None } else { - Some(exec_read_n_hook_wrapper::) + Some(exec_read_n_hook_wrapper::) }, index as u64, ); @@ -1037,32 +1028,32 @@ where if generation_hook.is_none() { None } else { - Some(gen_read_hook_wrapper::) + Some(gen_read_hook_wrapper::) }, if execution_hook1.is_none() { None } else { - Some(exec_read1_hook_wrapper::) + Some(exec_read1_hook_wrapper::) }, if execution_hook2.is_none() { None } else { - Some(exec_read2_hook_wrapper::) + Some(exec_read2_hook_wrapper::) }, if execution_hook4.is_none() { None } else { - Some(exec_read4_hook_wrapper::) + Some(exec_read4_hook_wrapper::) }, if execution_hook8.is_none() { None } else { - Some(exec_read8_hook_wrapper::) + Some(exec_read8_hook_wrapper::) }, if execution_hook_n.is_none() { None } else { - Some(exec_read_n_hook_wrapper::) + Some(exec_read_n_hook_wrapper::) }, index as u64, ); @@ -1093,7 +1084,7 @@ where if generation_hook.is_none() { None } else { - Some(gen_read_hook_wrapper::) + Some(gen_read_hook_wrapper::) }, execution_hook1, execution_hook2, @@ -1134,32 +1125,32 @@ where if generation_hook.is_none() { None } else { - Some(gen_write_hook_wrapper::) + Some(gen_write_hook_wrapper::) }, if execution_hook1.is_none() { None } else { - Some(exec_write1_hook_wrapper::) + Some(exec_write1_hook_wrapper::) }, if execution_hook2.is_none() { None } else { - Some(exec_write2_hook_wrapper::) + Some(exec_write2_hook_wrapper::) }, if execution_hook4.is_none() { None } else { - Some(exec_write4_hook_wrapper::) + Some(exec_write4_hook_wrapper::) }, if execution_hook8.is_none() { None } else { - Some(exec_write8_hook_wrapper::) + Some(exec_write8_hook_wrapper::) }, if execution_hook_n.is_none() { None } else { - Some(exec_write_n_hook_wrapper::) + Some(exec_write_n_hook_wrapper::) }, index as u64, ); @@ -1204,32 +1195,32 @@ where if generation_hook.is_none() { None } else { - Some(gen_write_hook_wrapper::) + Some(gen_write_hook_wrapper::) }, if execution_hook1.is_none() { None } else { - Some(exec_write1_hook_wrapper::) + Some(exec_write1_hook_wrapper::) }, if execution_hook2.is_none() { None } else { - Some(exec_write2_hook_wrapper::) + Some(exec_write2_hook_wrapper::) }, if execution_hook4.is_none() { None } else { - Some(exec_write4_hook_wrapper::) + Some(exec_write4_hook_wrapper::) }, if execution_hook8.is_none() { None } else { - Some(exec_write8_hook_wrapper::) + Some(exec_write8_hook_wrapper::) }, if execution_hook_n.is_none() { None } else { - Some(exec_write_n_hook_wrapper::) + Some(exec_write_n_hook_wrapper::) }, index as u64, ); @@ -1260,7 +1251,7 @@ where if generation_hook.is_none() { None } else { - Some(gen_write_hook_wrapper::) + Some(gen_write_hook_wrapper::) }, execution_hook1, execution_hook2, @@ -1298,27 +1289,27 @@ where if generation_hook.is_none() { None } else { - Some(gen_cmp_hook_wrapper::) + Some(gen_cmp_hook_wrapper::) }, if execution_hook1.is_none() { None } else { - Some(exec_cmp1_hook_wrapper::) + Some(exec_cmp1_hook_wrapper::) }, if execution_hook2.is_none() { None } else { - Some(exec_cmp2_hook_wrapper::) + Some(exec_cmp2_hook_wrapper::) }, if execution_hook4.is_none() { None } else { - Some(exec_cmp4_hook_wrapper::) + Some(exec_cmp4_hook_wrapper::) }, if execution_hook8.is_none() { None } else { - Some(exec_cmp8_hook_wrapper::) + Some(exec_cmp8_hook_wrapper::) }, index as u64, ); @@ -1357,27 +1348,27 @@ where if generation_hook.is_none() { None } else { - Some(gen_cmp_hook_wrapper::) + Some(gen_cmp_hook_wrapper::) }, if execution_hook1.is_none() { None } else { - Some(exec_cmp1_hook_wrapper::) + Some(exec_cmp1_hook_wrapper::) }, if execution_hook2.is_none() { None } else { - Some(exec_cmp2_hook_wrapper::) + Some(exec_cmp2_hook_wrapper::) }, if execution_hook4.is_none() { None } else { - Some(exec_cmp4_hook_wrapper::) + Some(exec_cmp4_hook_wrapper::) }, if execution_hook8.is_none() { None } else { - Some(exec_cmp8_hook_wrapper::) + Some(exec_cmp8_hook_wrapper::) }, index as u64, ); @@ -1406,7 +1397,7 @@ where if generation_hook.is_none() { None } else { - Some(gen_cmp_hook_wrapper::) + Some(gen_cmp_hook_wrapper::) }, execution_hook1, execution_hook2, @@ -1432,7 +1423,7 @@ where ON_THREAD_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator - .set_on_thread_hook(on_thread_hooks_wrapper::); + .set_on_thread_hook(on_thread_hooks_wrapper::); } #[cfg(feature = "usermode")] @@ -1444,7 +1435,7 @@ where ON_THREAD_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator - .set_on_thread_hook(on_thread_hooks_wrapper::); + .set_on_thread_hook(on_thread_hooks_wrapper::); } #[cfg(feature = "usermode")] @@ -1453,7 +1444,7 @@ where ON_THREAD_HOOKS.push(Hook::Once(transmute(hook))); } self.emulator - .set_on_thread_hook(on_thread_hooks_wrapper::); + .set_on_thread_hook(on_thread_hooks_wrapper::); } #[cfg(feature = "usermode")] @@ -1478,7 +1469,7 @@ where SYSCALL_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator - .set_pre_syscall_hook(syscall_hooks_wrapper::); + .set_pre_syscall_hook(syscall_hooks_wrapper::); } #[cfg(feature = "usermode")] @@ -1505,7 +1496,7 @@ where SYSCALL_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator - .set_pre_syscall_hook(syscall_hooks_wrapper::); + .set_pre_syscall_hook(syscall_hooks_wrapper::); } #[cfg(feature = "usermode")] @@ -1531,7 +1522,7 @@ where SYSCALL_POST_HOOKS.push(Hook::Function(hook as *const libc::c_void)); } self.emulator - .set_post_syscall_hook(syscall_after_hooks_wrapper::); + .set_post_syscall_hook(syscall_after_hooks_wrapper::); } #[cfg(feature = "usermode")] @@ -1559,6 +1550,6 @@ where SYSCALL_POST_HOOKS.push(Hook::Closure(transmute(hook))); } self.emulator - .set_post_syscall_hook(syscall_after_hooks_wrapper::); + .set_post_syscall_hook(syscall_after_hooks_wrapper::); } } diff --git a/libafl_qemu/src/snapshot.rs b/libafl_qemu/src/snapshot.rs index d859b443b7..8c82a3dca2 100644 --- a/libafl_qemu/src/snapshot.rs +++ b/libafl_qemu/src/snapshot.rs @@ -4,7 +4,7 @@ use std::{ sync::Mutex, }; -use libafl::{inputs::Input, state::HasMetadata}; +use libafl::{inputs::UsesInput, state::HasMetadata}; use meminterval::{Interval, IntervalTree}; use thread_local::ThreadLocal; @@ -468,31 +468,30 @@ impl Default for QemuSnapshotHelper { } } -impl QemuHelper for QemuSnapshotHelper +impl QemuHelper for QemuSnapshotHelper where - I: Input, - S: HasMetadata, + S: UsesInput + HasMetadata, { - fn init_hooks(&self, hooks: &QemuHooks<'_, I, QT, S>) + fn init_hooks(&self, hooks: &QemuHooks<'_, QT, S>) where - QT: QemuHelperTuple, + QT: QemuHelperTuple, { hooks.writes( None, - Some(trace_write1_snapshot::), - Some(trace_write2_snapshot::), - Some(trace_write4_snapshot::), - Some(trace_write8_snapshot::), - Some(trace_write_n_snapshot::), + Some(trace_write1_snapshot::), + Some(trace_write2_snapshot::), + Some(trace_write4_snapshot::), + Some(trace_write8_snapshot::), + Some(trace_write_n_snapshot::), ); if !self.accurate_unmap { - hooks.syscalls(filter_mmap_snapshot::); + hooks.syscalls(filter_mmap_snapshot::); } - hooks.after_syscalls(trace_mmap_snapshot::); + hooks.after_syscalls(trace_mmap_snapshot::); } - fn pre_exec(&mut self, emulator: &Emulator, _input: &I) { + fn pre_exec(&mut self, emulator: &Emulator, _input: &S::Input) { if self.empty { self.snapshot(emulator); } else { @@ -501,67 +500,67 @@ where } } -pub fn trace_write1_snapshot( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write1_snapshot( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let h = hooks.match_helper_mut::().unwrap(); h.access(addr, 1); } -pub fn trace_write2_snapshot( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write2_snapshot( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let h = hooks.match_helper_mut::().unwrap(); h.access(addr, 2); } -pub fn trace_write4_snapshot( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write4_snapshot( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let h = hooks.match_helper_mut::().unwrap(); h.access(addr, 4); } -pub fn trace_write8_snapshot( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write8_snapshot( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let h = hooks.match_helper_mut::().unwrap(); h.access(addr, 8); } -pub fn trace_write_n_snapshot( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_write_n_snapshot( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, _id: u64, addr: GuestAddr, size: usize, ) where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { let h = hooks.match_helper_mut::().unwrap(); h.access(addr, size); @@ -569,8 +568,8 @@ pub fn trace_write_n_snapshot( #[allow(clippy::too_many_arguments)] #[allow(non_upper_case_globals)] -pub fn filter_mmap_snapshot( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn filter_mmap_snapshot( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, sys_num: i32, a0: u64, @@ -583,8 +582,8 @@ pub fn filter_mmap_snapshot( _a7: u64, ) -> SyscallHookResult where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { if i64::from(sys_num) == SYS_munmap { let h = hooks.match_helper_mut::().unwrap(); @@ -597,8 +596,8 @@ where #[allow(clippy::too_many_arguments)] #[allow(non_upper_case_globals)] -pub fn trace_mmap_snapshot( - hooks: &mut QemuHooks<'_, I, QT, S>, +pub fn trace_mmap_snapshot( + hooks: &mut QemuHooks<'_, QT, S>, _state: Option<&mut S>, result: u64, sys_num: i32, @@ -612,8 +611,8 @@ pub fn trace_mmap_snapshot( _a7: u64, ) -> u64 where - I: Input, - QT: QemuHelperTuple, + S: UsesInput, + QT: QemuHelperTuple, { // NOT A COMPLETE LIST OF MEMORY EFFECTS match i64::from(sys_num) { diff --git a/libafl_sugar/src/forkserver.rs b/libafl_sugar/src/forkserver.rs index 79444ce0c8..4c27e84349 100644 --- a/libafl_sugar/src/forkserver.rs +++ b/libafl_sugar/src/forkserver.rs @@ -114,7 +114,7 @@ impl<'a, const MAP_SIZE: usize> ForkserverBytesCoverageSugar<'a, MAP_SIZE> { let monitor = MultiMonitor::new(|s| println!("{s}")); let mut run_client = |state: Option<_>, - mut mgr: LlmpRestartingEventManager<_, _, _, _>, + mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { // Coverage map shared between target and fuzzer let mut shmem = shmem_provider_client.new_shmem(MAP_SIZE).unwrap(); diff --git a/libafl_sugar/src/inmemory.rs b/libafl_sugar/src/inmemory.rs index 9856905532..894bfd8b4f 100644 --- a/libafl_sugar/src/inmemory.rs +++ b/libafl_sugar/src/inmemory.rs @@ -140,7 +140,7 @@ where let monitor = MultiMonitor::new(|s| println!("{s}")); let mut run_client = |state: Option<_>, - mut mgr: LlmpRestartingEventManager<_, _, _, _>, + mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { // Create an observation channel using the coverage map let edges = unsafe { &mut EDGES_MAP[0..MAX_EDGES_NUM] }; diff --git a/libafl_sugar/src/qemu.rs b/libafl_sugar/src/qemu.rs index 7c8b1036a0..faab0482fb 100644 --- a/libafl_sugar/src/qemu.rs +++ b/libafl_sugar/src/qemu.rs @@ -144,7 +144,7 @@ where let monitor = MultiMonitor::new(|s| println!("{s}")); let mut run_client = |state: Option<_>, - mut mgr: LlmpRestartingEventManager<_, _, _, _>, + mut mgr: LlmpRestartingEventManager<_, _>, _core_id| { // Create an observation channel using the coverage map let edges = unsafe { &mut edges::EDGES_MAP }; diff --git a/libafl_targets/src/cmplog.rs b/libafl_targets/src/cmplog.rs index 381129c257..dee1162105 100644 --- a/libafl_targets/src/cmplog.rs +++ b/libafl_targets/src/cmplog.rs @@ -8,6 +8,7 @@ use core::fmt::{self, Debug, Formatter}; use libafl::{ bolts::{ownedref::OwnedRefMut, tuples::Named}, executors::ExitKind, + inputs::UsesInput, observers::{CmpMap, CmpObserver, CmpValues, Observer}, state::HasMetadata, Error, @@ -184,9 +185,9 @@ pub struct CmpLogObserver<'a> { name: String, } -impl<'a, I, S> CmpObserver for CmpLogObserver<'a> +impl<'a, S> CmpObserver for CmpLogObserver<'a> where - S: HasMetadata, + S: UsesInput + HasMetadata, { /// Get the number of usable cmps (all by default) fn usable_count(&self) -> usize { @@ -205,12 +206,12 @@ where } } -impl<'a, I, S> Observer for CmpLogObserver<'a> +impl<'a, S> Observer for CmpLogObserver<'a> where - S: HasMetadata, - Self: CmpObserver, + S: UsesInput + HasMetadata, + Self: CmpObserver, { - fn pre_exec(&mut self, _state: &mut S, _input: &I) -> Result<(), Error> { + fn pre_exec(&mut self, _state: &mut S, _input: &S::Input) -> Result<(), Error> { self.map.as_mut().reset()?; unsafe { CMPLOG_ENABLED = 1; @@ -218,7 +219,12 @@ where Ok(()) } - fn post_exec(&mut self, state: &mut S, _input: &I, _exit_kind: &ExitKind) -> Result<(), Error> { + fn post_exec( + &mut self, + state: &mut S, + _input: &S::Input, + _exit_kind: &ExitKind, + ) -> Result<(), Error> { unsafe { CMPLOG_ENABLED = 0; }