From 390008e1d549e308346ef0b9c0e36df20c9a6e78 Mon Sep 17 00:00:00 2001 From: "Dongjia \"toka\" Zhang" Date: Mon, 12 May 2025 15:12:20 +0200 Subject: [PATCH] fix qemu launcher bug (#3206) * no more shellscript * metadatas * clp * clippo * fix bug * taplo * Merge branch 'qemu_launcher_insane' of github.com:AFLplusplus/LibAFL into qemu_launcher_insane * fix wrong code --- .../binary_only/qemu_launcher/src/client.rs | 24 ++-- .../binary_only/qemu_launcher/src/fuzzer.rs | 52 +------ .../binary_only/qemu_launcher/src/instance.rs | 42 +++--- .../full_system/nyx_launcher/src/client.rs | 25 ++-- .../full_system/nyx_launcher/src/fuzzer.rs | 37 ++--- .../full_system/nyx_launcher/src/instance.rs | 30 ++-- libafl/src/events/mod.rs | 131 ------------------ 7 files changed, 78 insertions(+), 263 deletions(-) diff --git a/fuzzers/binary_only/qemu_launcher/src/client.rs b/fuzzers/binary_only/qemu_launcher/src/client.rs index b3ab792a9b..0516d7468a 100644 --- a/fuzzers/binary_only/qemu_launcher/src/client.rs +++ b/fuzzers/binary_only/qemu_launcher/src/client.rs @@ -2,9 +2,10 @@ use std::env; use libafl::{ corpus::{InMemoryOnDiskCorpus, OnDiskCorpus}, - events::ClientDescription, + events::{ + ClientDescription, EventFirer, EventReceiver, EventRestarter, ProgressReporter, SendExiting, + }, inputs::BytesInput, - monitors::Monitor, state::StdState, Error, }; @@ -14,11 +15,7 @@ use libafl_qemu::modules::{ utils::filters::StdAddressFilter, DrCovModule, InjectionModule, }; -use crate::{ - harness::Harness, - instance::{ClientMgr, Instance}, - options::FuzzerOptions, -}; +use crate::{harness::Harness, instance::Instance, options::FuzzerOptions}; #[expect(clippy::module_name_repetitions)] pub type ClientState = @@ -51,12 +48,19 @@ impl Client<'_> { } #[expect(clippy::too_many_lines)] - pub fn run( + pub fn run( &self, state: Option, - mgr: ClientMgr, + mgr: EM, client_description: ClientDescription, - ) -> Result<(), Error> { + ) -> Result<(), Error> + where + EM: EventFirer + + EventRestarter + + ProgressReporter + + SendExiting + + EventReceiver, + { let core_id = client_description.core_id(); let mut args = self.args()?; Harness::edit_args(&mut args); diff --git a/fuzzers/binary_only/qemu_launcher/src/fuzzer.rs b/fuzzers/binary_only/qemu_launcher/src/fuzzer.rs index 0f4eef3a18..d9e18833b3 100644 --- a/fuzzers/binary_only/qemu_launcher/src/fuzzer.rs +++ b/fuzzers/binary_only/qemu_launcher/src/fuzzer.rs @@ -5,20 +5,16 @@ use std::{ }; use clap::Parser; -#[cfg(feature = "simplemgr")] -use libafl::events::SimpleEventManager; #[cfg(not(feature = "simplemgr"))] -use libafl::events::{EventConfig, Launcher, LlmpEventManagerBuilder, MonitorTypedEventManager}; +use libafl::events::{EventConfig, Launcher}; use libafl::{ - events::ClientDescription, + events::{ClientDescription, SimpleEventManager}, monitors::{tui::TuiMonitor, Monitor, MultiMonitor}, Error, }; #[cfg(not(feature = "simplemgr"))] use libafl_bolts::shmem::{ShMemProvider, StdShMemProvider}; use libafl_bolts::{core_affinity::CoreId, current_time}; -#[cfg(not(feature = "simplemgr"))] -use libafl_bolts::{llmp::LlmpBroker, staterestore::StateRestorer, tuples::tuple_list}; #[cfg(unix)] use { nix::unistd::dup, @@ -84,7 +80,8 @@ impl Fuzzer { { // The shared memory allocator #[cfg(not(feature = "simplemgr"))] - let mut shmem_provider = StdShMemProvider::new()?; + let shmem_provider = StdShMemProvider::new()?; + /* If we are running in verbose, don't provide a replacement stdout, otherwise, use /dev/null */ #[cfg(not(feature = "simplemgr"))] let stdout = if self.options.verbose { @@ -95,45 +92,10 @@ impl Fuzzer { let client = Client::new(&self.options); - #[cfg(not(feature = "simplemgr"))] - if self.options.rerun_input.is_some() { - // If we want to rerun a single input but we use a restarting mgr, we'll have to create a fake restarting mgr that doesn't actually restart. - // It's not pretty but better than recompiling with simplemgr. - - // Just a random number, let's hope it's free :) - let broker_port = 13120; - let _fake_broker = LlmpBroker::create_attach_to_tcp( - shmem_provider.clone(), - tuple_list!(), - broker_port, - ) - .unwrap(); - - // To rerun an input, instead of using a launcher, we create dummy parameters and run the client directly. - // NOTE: This is a hack for debugging that that will only work for non-crashing inputs. - return client.run( - None, - MonitorTypedEventManager::<_, M>::new( - LlmpEventManagerBuilder::builder() - .build_on_port( - shmem_provider.clone(), - broker_port, - EventConfig::AlwaysUnique, - Some(StateRestorer::new( - shmem_provider.new_shmem(0x1000).unwrap(), - )), - ) - .unwrap(), - ), - ClientDescription::new(0, 0, CoreId(0)), - ); - } - - #[cfg(feature = "simplemgr")] if self.options.rerun_input.is_some() { return client.run( None, - SimpleEventManager::new(monitor), + SimpleEventManager::new(monitor.clone()), ClientDescription::new(0, 0, CoreId(0)), ); } @@ -141,7 +103,7 @@ impl Fuzzer { #[cfg(feature = "simplemgr")] return client.run( None, - SimpleEventManager::new(monitor), + SimpleEventManager::new(monitor.clone()), ClientDescription::new(0, 0, CoreId(0)), ); @@ -152,7 +114,7 @@ impl Fuzzer { .broker_port(self.options.port) .configuration(EventConfig::from_build_id()) .monitor(monitor) - .run_client(|s, m, c| client.run(s, MonitorTypedEventManager::<_, M>::new(m), c)) + .run_client(|s, m, c| client.run(s, m, c)) .cores(&self.options.cores) .stdout_file(stdout) .stderr_file(stdout) diff --git a/fuzzers/binary_only/qemu_launcher/src/instance.rs b/fuzzers/binary_only/qemu_launcher/src/instance.rs index b01d8bef13..479bdd09d6 100644 --- a/fuzzers/binary_only/qemu_launcher/src/instance.rs +++ b/fuzzers/binary_only/qemu_launcher/src/instance.rs @@ -1,19 +1,16 @@ use core::fmt::Debug; -use std::{fs, marker::PhantomData, ops::Range, process}; +use std::{fs, ops::Range, process}; -#[cfg(feature = "simplemgr")] -use libafl::events::SimpleEventManager; -#[cfg(not(feature = "simplemgr"))] -use libafl::events::{LlmpRestartingEventManager, MonitorTypedEventManager}; use libafl::{ corpus::{Corpus, HasCurrentCorpusId, InMemoryOnDiskCorpus, OnDiskCorpus}, - events::{ClientDescription, EventRestarter}, + events::{ + ClientDescription, EventFirer, EventReceiver, EventRestarter, ProgressReporter, SendExiting, + }, executors::{Executor, ExitKind, ShadowExecutor}, feedback_and_fast, feedback_or, feedback_or_fast, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Evaluator, Fuzzer, StdFuzzer}, inputs::{BytesInput, Input}, - monitors::Monitor, mutators::{ havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, HavocScheduledMutator, StdMOptMutator, Tokens, @@ -31,8 +28,6 @@ use libafl::{ state::{HasCorpus, HasExecutions, HasSolutions, StdState}, Error, HasMetadata, }; -#[cfg(not(feature = "simplemgr"))] -use libafl_bolts::shmem::{StdShMem, StdShMemProvider}; use libafl_bolts::{ ownedref::OwnedMutSlice, rands::StdRand, @@ -57,14 +52,6 @@ use crate::{harness::Harness, options::FuzzerOptions}; pub type ClientState = StdState, BytesInput, StdRand, OnDiskCorpus>; -#[cfg(feature = "simplemgr")] -pub type ClientMgr = SimpleEventManager; -#[cfg(not(feature = "simplemgr"))] -pub type ClientMgr = MonitorTypedEventManager< - LlmpRestartingEventManager<(), BytesInput, ClientState, StdShMem, StdShMemProvider>, - M, ->; - /* * The snapshot and iterations options interact as follows: * @@ -87,17 +74,22 @@ pub type ClientMgr = MonitorTypedEventManager< */ #[derive(TypedBuilder)] -pub struct Instance<'a, M: Monitor> { +pub struct Instance<'a, EM> { options: &'a FuzzerOptions, - mgr: ClientMgr, + mgr: EM, client_description: ClientDescription, #[builder(default)] extra_tokens: Vec, - #[builder(default=PhantomData)] - phantom: PhantomData, } -impl Instance<'_, M> { +impl Instance<'_, MTEM> +where + MTEM: EventFirer + + EventRestarter + + ProgressReporter + + SendExiting + + EventReceiver, +{ fn coverage_filter(&self, qemu: Qemu) -> Result { /* Conversion is required on 32-bit targets, but not on 64-bit ones */ if let Some(includes) = &self.options.include { @@ -438,10 +430,10 @@ impl Instance<'_, M> { stages: &mut ST, ) -> Result<(), Error> where - ST: StagesTuple, ClientState, Z>, + ST: StagesTuple, RSM: Fn(&mut E, Qemu), - Z: Fuzzer, BytesInput, ClientState, ST> - + Evaluator, BytesInput, ClientState>, + Z: Fuzzer + + Evaluator, { if state.must_load_initial_inputs() { let corpus_dirs = [self.options.input_dir()]; diff --git a/fuzzers/full_system/nyx_launcher/src/client.rs b/fuzzers/full_system/nyx_launcher/src/client.rs index 625dbf169c..01fe18df0a 100644 --- a/fuzzers/full_system/nyx_launcher/src/client.rs +++ b/fuzzers/full_system/nyx_launcher/src/client.rs @@ -1,6 +1,10 @@ +use core::marker::PhantomData; + use libafl::{ corpus::{InMemoryOnDiskCorpus, OnDiskCorpus}, - events::ClientDescription, + events::{ + ClientDescription, EventFirer, EventReceiver, EventRestarter, ProgressReporter, SendExiting, + }, inputs::BytesInput, monitors::Monitor, state::StdState, @@ -8,11 +12,7 @@ use libafl::{ }; use libafl_bolts::rands::StdRand; -use crate::{ - instance::{ClientMgr, Instance}, - options::FuzzerOptions, -}; - +use crate::{instance::Instance, options::FuzzerOptions}; #[allow(clippy::module_name_repetitions)] pub type ClientState = StdState, BytesInput, StdRand, OnDiskCorpus>; @@ -26,12 +26,19 @@ impl Client<'_> { Client { options } } - pub fn run( + pub fn run( &self, state: Option, - mgr: ClientMgr, + mgr: EM, client_description: ClientDescription, - ) -> Result<(), Error> { + ) -> Result<(), Error> + where + EM: EventFirer + + EventRestarter + + ProgressReporter + + SendExiting + + EventReceiver, + { let instance = Instance::builder() .options(self.options) .mgr(mgr) diff --git a/fuzzers/full_system/nyx_launcher/src/fuzzer.rs b/fuzzers/full_system/nyx_launcher/src/fuzzer.rs index 6fc38d02ec..8861146261 100644 --- a/fuzzers/full_system/nyx_launcher/src/fuzzer.rs +++ b/fuzzers/full_system/nyx_launcher/src/fuzzer.rs @@ -7,7 +7,7 @@ use std::{ use clap::Parser; use libafl::{ events::{ - ClientDescription, EventConfig, Launcher, LlmpEventManagerBuilder, MonitorTypedEventManager, + ClientDescription, EventConfig, Launcher, LlmpEventManagerBuilder, SimpleEventManager, }, monitors::{tui::TuiMonitor, Monitor, MultiMonitor}, Error, @@ -83,7 +83,7 @@ impl Fuzzer { M: Monitor + Clone, { // The shared memory allocator - let mut shmem_provider = StdShMemProvider::new()?; + let shmem_provider = StdShMemProvider::new()?; /* If we are running in verbose, don't provide a replacement stdout, otherwise, use /dev/null */ let stdout = if self.options.verbose { @@ -95,45 +95,28 @@ impl Fuzzer { let client = Client::new(&self.options); if self.options.rerun_input.is_some() { - // If we want to rerun a single input but we use a restarting mgr, we'll have to create a fake restarting mgr that doesn't actually restart. - // It's not pretty but better than recompiling with simplemgr. - - // Just a random number, let's hope it's free :) - let broker_port = 13120; - let _fake_broker = LlmpBroker::create_attach_to_tcp( - shmem_provider.clone(), - tuple_list!(), - broker_port, - ) - .unwrap(); - - // To rerun an input, instead of using a launcher, we create dummy parameters and run the client directly. return client.run( None, - MonitorTypedEventManager::<_, M>::new( - LlmpEventManagerBuilder::builder().build_on_port( - shmem_provider.clone(), - broker_port, - EventConfig::AlwaysUnique, - Some(StateRestorer::new( - shmem_provider.new_shmem(0x1000).unwrap(), - )), - )?, - ), + SimpleEventManager::new(monitor.clone()), ClientDescription::new(0, 0, CoreId(0)), ); } #[cfg(feature = "simplemgr")] - return client.run(None, SimpleEventManager::new(monitor), CoreId(0)); + return client.run( + None, + SimpleEventManager::new(monitor.clone()), + ClientDescription::new(0, 0, CoreId(0)), + ); // Build and run a Launcher + #[cfg(not(feature = "simplemgr"))] match Launcher::builder() .shmem_provider(shmem_provider) .broker_port(self.options.port) .configuration(EventConfig::from_build_id()) .monitor(monitor) - .run_client(|s, m, c| client.run(s, MonitorTypedEventManager::<_, M>::new(m), c)) + .run_client(|s, m, c| client.run(s, m, c)) .cores(&self.options.cores) .stdout_file(stdout) .stderr_file(stdout) diff --git a/fuzzers/full_system/nyx_launcher/src/instance.rs b/fuzzers/full_system/nyx_launcher/src/instance.rs index 1aeeecea6f..2805ba2347 100644 --- a/fuzzers/full_system/nyx_launcher/src/instance.rs +++ b/fuzzers/full_system/nyx_launcher/src/instance.rs @@ -3,15 +3,14 @@ use std::{marker::PhantomData, process}; use libafl::{ corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus}, events::{ - ClientDescription, EventRestarter, LlmpRestartingEventManager, MonitorTypedEventManager, - NopEventManager, + ClientDescription, EventFirer, EventReceiver, EventRestarter, LlmpRestartingEventManager, + NopEventManager, ProgressReporter, SendExiting, }, executors::{Executor, ShadowExecutor}, feedback_and_fast, feedback_or, feedback_or_fast, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, fuzzer::{Evaluator, Fuzzer, StdFuzzer}, inputs::BytesInput, - monitors::Monitor, mutators::{ havoc_mutations, tokens_mutations, HavocScheduledMutator, I2SRandReplace, StdMOptMutator, Tokens, @@ -43,22 +42,22 @@ use crate::options::FuzzerOptions; pub type ClientState = StdState, BytesInput, StdRand, OnDiskCorpus>; -pub type ClientMgr = MonitorTypedEventManager< - LlmpRestartingEventManager<(), BytesInput, ClientState, StdShMem, StdShMemProvider>, - M, ->; - #[derive(TypedBuilder)] -pub struct Instance<'a, M: Monitor> { +pub struct Instance<'a, EM> { options: &'a FuzzerOptions, /// The harness. We create it before forking, then `take()` it inside the client. - mgr: ClientMgr, + mgr: EM, client_description: ClientDescription, - #[builder(default=PhantomData)] - phantom: PhantomData, } -impl Instance<'_, M> { +impl Instance<'_, EM> +where + EM: EventFirer + + EventRestarter + + ProgressReporter + + SendExiting + + EventReceiver, +{ pub fn run(mut self, state: Option) -> Result<(), Error> { let parent_cpu_id = self .options @@ -229,9 +228,8 @@ impl Instance<'_, M> { stages: &mut ST, ) -> Result<(), Error> where - Z: Fuzzer, BytesInput, ClientState, ST> - + Evaluator, BytesInput, ClientState>, - ST: StagesTuple, ClientState, Z>, + Z: Fuzzer + Evaluator, + ST: StagesTuple, { let corpus_dirs = [self.options.input_dir()]; diff --git a/libafl/src/events/mod.rs b/libafl/src/events/mod.rs index 24be141f9f..555d6dd77f 100644 --- a/libafl/src/events/mod.rs +++ b/libafl/src/events/mod.rs @@ -697,137 +697,6 @@ impl HasEventManagerId for NopEventManager { } } -/// An `EventManager` type that wraps another manager, but captures a `monitor` type as well. -/// This is useful to keep the same API between managers with and without an internal `monitor`. -#[derive(Copy, Clone, Debug)] -pub struct MonitorTypedEventManager { - inner: EM, - phantom: PhantomData, -} - -impl MonitorTypedEventManager { - /// Creates a new `EventManager` that wraps another manager, but captures a `monitor` type as well. - #[must_use] - pub fn new(inner: EM) -> Self { - MonitorTypedEventManager { - inner, - phantom: PhantomData, - } - } -} - -impl EventFirer for MonitorTypedEventManager -where - EM: EventFirer, -{ - fn should_send(&self) -> bool { - true - } - - #[inline] - fn fire(&mut self, state: &mut S, event: EventWithStats) -> Result<(), Error> { - self.inner.fire(state, event) - } - - #[inline] - fn log( - &mut self, - state: &mut S, - severity_level: LogSeverity, - message: String, - ) -> Result<(), Error> - where - S: HasExecutions, - { - self.inner.log(state, severity_level, message) - } - - #[inline] - fn configuration(&self) -> EventConfig { - self.inner.configuration() - } -} - -impl EventRestarter for MonitorTypedEventManager -where - EM: EventRestarter, -{ - #[inline] - fn on_restart(&mut self, state: &mut S) -> Result<(), Error> { - self.inner.on_restart(state) - } -} - -impl SendExiting for MonitorTypedEventManager -where - EM: SendExiting, -{ - #[inline] - fn send_exiting(&mut self) -> Result<(), Error> { - self.inner.send_exiting() - } - - fn on_shutdown(&mut self) -> Result<(), Error> { - self.inner.on_shutdown() - } -} - -impl AwaitRestartSafe for MonitorTypedEventManager -where - EM: AwaitRestartSafe, -{ - #[inline] - fn await_restart_safe(&mut self) { - self.inner.await_restart_safe(); - } -} - -impl EventReceiver for MonitorTypedEventManager -where - EM: EventReceiver, -{ - #[inline] - fn try_receive(&mut self, state: &mut S) -> Result, bool)>, Error> { - self.inner.try_receive(state) - } - fn on_interesting( - &mut self, - _state: &mut S, - _event_vec: EventWithStats, - ) -> Result<(), Error> { - Ok(()) - } -} - -impl ProgressReporter for MonitorTypedEventManager -where - EM: ProgressReporter, -{ - #[inline] - fn maybe_report_progress( - &mut self, - state: &mut S, - monitor_timeout: Duration, - ) -> Result<(), Error> { - self.inner.maybe_report_progress(state, monitor_timeout) - } - - #[inline] - fn report_progress(&mut self, state: &mut S) -> Result<(), Error> { - self.inner.report_progress(state) - } -} - -impl HasEventManagerId for MonitorTypedEventManager -where - EM: HasEventManagerId, -{ - #[inline] - fn mgr_id(&self) -> EventManagerId { - self.inner.mgr_id() - } -} - #[cfg(test)] mod tests {