Add SimpleMgr feature to qemu_launcher (#1790)

This commit is contained in:
Dominik Maier 2024-01-24 17:54:52 +01:00 committed by GitHub
parent 0cb7b25f39
commit 6a0ba7b647
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 205 additions and 27 deletions

View File

@ -8,6 +8,9 @@ edition = "2021"
default = ["std", "injections"] default = ["std", "injections"]
std = [] std = []
## Build with a simple event manager instead of Launcher - don't fork, and crash after the first bug.
simplemgr = []
## Enable fuzzing for injections (where supported) ## Enable fuzzing for injections (where supported)
injections = ["libafl_qemu/injections"] injections = ["libafl_qemu/injections"]

View File

@ -2,14 +2,12 @@ use std::{env, ops::Range};
use libafl::{ use libafl::{
corpus::{InMemoryOnDiskCorpus, OnDiskCorpus}, corpus::{InMemoryOnDiskCorpus, OnDiskCorpus},
events::LlmpRestartingEventManager,
inputs::BytesInput, inputs::BytesInput,
monitors::Monitor,
state::StdState, state::StdState,
Error, Error,
}; };
use libafl_bolts::{ use libafl_bolts::{core_affinity::CoreId, rands::StdRand, tuples::tuple_list};
core_affinity::CoreId, rands::StdRand, shmem::StdShMemProvider, tuples::tuple_list,
};
#[cfg(feature = "injections")] #[cfg(feature = "injections")]
use libafl_qemu::injections::QemuInjectionHelper; use libafl_qemu::injections::QemuInjectionHelper;
use libafl_qemu::{ use libafl_qemu::{
@ -20,7 +18,10 @@ use libafl_qemu::{
ArchExtras, Emulator, GuestAddr, QemuInstrumentationAddressRangeFilter, ArchExtras, Emulator, GuestAddr, QemuInstrumentationAddressRangeFilter,
}; };
use crate::{instance::Instance, options::FuzzerOptions}; use crate::{
instance::{ClientMgr, Instance},
options::FuzzerOptions,
};
#[allow(clippy::module_name_repetitions)] #[allow(clippy::module_name_repetitions)]
pub type ClientState = pub type ClientState =
@ -100,10 +101,10 @@ impl<'a> Client<'a> {
} }
} }
pub fn run( pub fn run<M: Monitor>(
&self, &self,
state: Option<ClientState>, state: Option<ClientState>,
mgr: LlmpRestartingEventManager<ClientState, StdShMemProvider>, mgr: ClientMgr<M>,
core_id: CoreId, core_id: CoreId,
) -> Result<(), Error> { ) -> Result<(), Error> {
let mut args = self.args()?; let mut args = self.args()?;

View File

@ -5,18 +5,22 @@ use std::{
}; };
use clap::Parser; use clap::Parser;
#[cfg(feature = "simplemgr")]
use libafl::events::SimpleEventManager;
#[cfg(not(feature = "simplemgr"))]
use libafl::events::{EventConfig, Launcher, MonitorTypedEventManager};
use libafl::{ use libafl::{
events::{EventConfig, Launcher},
monitors::{ monitors::{
tui::{ui::TuiUI, TuiMonitor}, tui::{ui::TuiUI, TuiMonitor},
Monitor, MultiMonitor, Monitor, MultiMonitor,
}, },
Error, Error,
}; };
use libafl_bolts::{ #[cfg(feature = "simplemgr")]
current_time, use libafl_bolts::core_affinity::CoreId;
shmem::{ShMemProvider, StdShMemProvider}, use libafl_bolts::current_time;
}; #[cfg(not(feature = "simplemgr"))]
use libafl_bolts::shmem::{ShMemProvider, StdShMemProvider};
#[cfg(unix)] #[cfg(unix)]
use { use {
nix::unistd::dup, nix::unistd::dup,
@ -78,9 +82,11 @@ impl Fuzzer {
M: Monitor + Clone, M: Monitor + Clone,
{ {
// The shared memory allocator // The shared memory allocator
#[cfg(not(feature = "simplemgr"))]
let 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 */ /* 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 { let stdout = if self.options.verbose {
None None
} else { } else {
@ -89,13 +95,17 @@ impl Fuzzer {
let client = Client::new(&self.options); let client = Client::new(&self.options);
#[cfg(feature = "simplemgr")]
return client.run(None, SimpleEventManager::new(monitor), CoreId(0));
// Build and run a Launcher // Build and run a Launcher
#[cfg(not(feature = "simplemgr"))]
match Launcher::builder() match Launcher::builder()
.shmem_provider(shmem_provider) .shmem_provider(shmem_provider)
.broker_port(self.options.port) .broker_port(self.options.port)
.configuration(EventConfig::from_build_id()) .configuration(EventConfig::from_build_id())
.monitor(monitor) .monitor(monitor)
.run_client(|s, m, c| client.run(s, m, c)) .run_client(|s, m, c| client.run(s, MonitorTypedEventManager::<_, M>::new(m), c))
.cores(&self.options.cores) .cores(&self.options.cores)
.stdout_file(stdout) .stdout_file(stdout)
.stderr_file(stdout) .stderr_file(stdout)

View File

@ -1,14 +1,19 @@
use core::ptr::addr_of_mut; use core::ptr::addr_of_mut;
use std::process; use std::{marker::PhantomData, process};
#[cfg(feature = "simplemgr")]
use libafl::events::SimpleEventManager;
#[cfg(not(feature = "simplemgr"))]
use libafl::events::{LlmpRestartingEventManager, MonitorTypedEventManager};
use libafl::{ use libafl::{
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus}, corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
events::{EventRestarter, LlmpRestartingEventManager}, events::EventRestarter,
executors::ShadowExecutor, executors::ShadowExecutor,
feedback_or, feedback_or_fast, feedback_or, feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback}, feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Evaluator, Fuzzer, StdFuzzer}, fuzzer::{Evaluator, Fuzzer, StdFuzzer},
inputs::BytesInput, inputs::BytesInput,
monitors::Monitor,
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens, StdMOptMutator, StdScheduledMutator, Tokens,
@ -24,11 +29,12 @@ use libafl::{
state::{HasCorpus, HasMetadata, StdState, UsesState}, state::{HasCorpus, HasMetadata, StdState, UsesState},
Error, Error,
}; };
#[cfg(not(feature = "simplemgr"))]
use libafl_bolts::shmem::StdShMemProvider;
use libafl_bolts::{ use libafl_bolts::{
core_affinity::CoreId, core_affinity::CoreId,
current_nanos, current_nanos,
rands::StdRand, rands::StdRand,
shmem::StdShMemProvider,
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
}; };
use libafl_qemu::{ use libafl_qemu::{
@ -44,18 +50,24 @@ use crate::{harness::Harness, options::FuzzerOptions};
pub type ClientState = pub type ClientState =
StdState<BytesInput, InMemoryOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>; StdState<BytesInput, InMemoryOnDiskCorpus<BytesInput>, StdRand, OnDiskCorpus<BytesInput>>;
pub type ClientMgr = LlmpRestartingEventManager<ClientState, StdShMemProvider>; #[cfg(feature = "simplemgr")]
pub type ClientMgr<M> = SimpleEventManager<M, ClientState>;
#[cfg(not(feature = "simplemgr"))]
pub type ClientMgr<M> =
MonitorTypedEventManager<LlmpRestartingEventManager<ClientState, StdShMemProvider>, M>;
#[derive(TypedBuilder)] #[derive(TypedBuilder)]
pub struct Instance<'a> { pub struct Instance<'a, M: Monitor> {
options: &'a FuzzerOptions, options: &'a FuzzerOptions,
emu: &'a Emulator, emu: &'a Emulator,
mgr: ClientMgr, mgr: ClientMgr<M>,
core_id: CoreId, core_id: CoreId,
extra_tokens: Option<Vec<String>>, extra_tokens: Option<Vec<String>>,
#[builder(default=PhantomData)]
phantom: PhantomData<M>,
} }
impl<'a> Instance<'a> { impl<'a, M: Monitor> Instance<'a, M> {
pub fn run<QT>(&mut self, helpers: QT, state: Option<ClientState>) -> Result<(), Error> pub fn run<QT>(&mut self, helpers: QT, state: Option<ClientState>) -> Result<(), Error>
where where
QT: QemuHelperTuple<ClientState>, QT: QemuHelperTuple<ClientState>,
@ -207,11 +219,11 @@ impl<'a> Instance<'a> {
stages: &mut ST, stages: &mut ST,
) -> Result<(), Error> ) -> Result<(), Error>
where where
Z: Fuzzer<E, ClientMgr, ST> Z: Fuzzer<E, ClientMgr<M>, ST>
+ UsesState<State = ClientState> + UsesState<State = ClientState>
+ Evaluator<E, ClientMgr, State = ClientState>, + Evaluator<E, ClientMgr<M>, State = ClientState>,
E: UsesState<State = ClientState>, E: UsesState<State = ClientState>,
ST: StagesTuple<E, ClientMgr, ClientState, Z>, ST: StagesTuple<E, ClientMgr<M>, ClientState, Z>,
{ {
let corpus_dirs = [self.options.input_dir()]; let corpus_dirs = [self.options.input_dir()];

View File

@ -521,16 +521,16 @@ where
// If we are measuring scalability stuff.. // If we are measuring scalability stuff..
#[cfg(feature = "scalability_introspection")] #[cfg(feature = "scalability_introspection")]
{ {
let received_with_observer = state.scalability_monitor().testcase_with_observers; let imported_with_observer = state.scalability_monitor().testcase_with_observers;
let received_without_observer = state.scalability_monitor().testcase_without_observers; let imported_without_observer = state.scalability_monitor().testcase_without_observers;
self.fire( self.fire(
state, state,
Event::UpdateUserStats { Event::UpdateUserStats {
name: "total received".to_string(), name: "total imported".to_string(),
value: UserStats::new( value: UserStats::new(
UserStatsValue::Number( UserStatsValue::Number(
(received_with_observer + received_without_observer) as u64, (imported_with_observer + imported_without_observer) as u64,
), ),
AggregatorOps::Avg, AggregatorOps::Avg,
), ),
@ -694,6 +694,158 @@ impl<S> HasEventManagerId for NopEventManager<S> {
} }
} }
/// 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<EM, M> {
inner: EM,
phantom: PhantomData<M>,
}
impl<EM, M> MonitorTypedEventManager<EM, M> {
/// 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<EM, M> UsesState for MonitorTypedEventManager<EM, M>
where
EM: UsesState,
{
type State = EM::State;
}
impl<EM, M> EventFirer for MonitorTypedEventManager<EM, M>
where
EM: EventFirer,
{
#[inline]
fn fire(
&mut self,
state: &mut Self::State,
event: Event<<Self::State as UsesInput>::Input>,
) -> Result<(), Error> {
self.inner.fire(state, event)
}
#[inline]
fn log(
&mut self,
state: &mut Self::State,
severity_level: LogSeverity,
message: String,
) -> Result<(), Error> {
self.inner.log(state, severity_level, message)
}
#[inline]
fn serialize_observers<OT>(&mut self, observers: &OT) -> Result<Option<Vec<u8>>, Error>
where
OT: ObserversTuple<Self::State> + Serialize,
{
self.inner.serialize_observers(observers)
}
#[inline]
fn configuration(&self) -> EventConfig {
self.inner.configuration()
}
}
impl<EM, M> EventRestarter for MonitorTypedEventManager<EM, M>
where
EM: EventRestarter,
{
#[inline]
fn on_restart(&mut self, state: &mut Self::State) -> Result<(), Error> {
self.inner.on_restart(state)
}
#[inline]
fn send_exiting(&mut self) -> Result<(), Error> {
self.inner.send_exiting()
}
#[inline]
fn await_restart_safe(&mut self) {
self.inner.await_restart_safe();
}
}
impl<E, EM, M, Z> EventProcessor<E, Z> for MonitorTypedEventManager<EM, M>
where
EM: EventProcessor<E, Z>,
{
#[inline]
fn process(
&mut self,
fuzzer: &mut Z,
state: &mut Self::State,
executor: &mut E,
) -> Result<usize, Error> {
self.inner.process(fuzzer, state, executor)
}
}
impl<E, EM, M, Z> EventManager<E, Z> for MonitorTypedEventManager<EM, M>
where
EM: EventManager<E, Z>,
EM::State: HasLastReportTime + HasExecutions + HasMetadata,
{
}
impl<EM, M> HasCustomBufHandlers for MonitorTypedEventManager<EM, M>
where
Self: UsesState,
EM: HasCustomBufHandlers<State = Self::State>,
{
#[inline]
fn add_custom_buf_handler(
&mut self,
handler: Box<
dyn FnMut(&mut Self::State, &String, &[u8]) -> Result<CustomBufEventResult, Error>,
>,
) {
self.inner.add_custom_buf_handler(handler);
}
}
impl<EM, M> ProgressReporter for MonitorTypedEventManager<EM, M>
where
Self: UsesState,
EM: ProgressReporter<State = Self::State>,
EM::State: HasLastReportTime + HasExecutions + HasMetadata,
{
#[inline]
fn maybe_report_progress(
&mut self,
state: &mut Self::State,
monitor_timeout: Duration,
) -> Result<(), Error> {
self.inner.maybe_report_progress(state, monitor_timeout)
}
#[inline]
fn report_progress(&mut self, state: &mut Self::State) -> Result<(), Error> {
self.inner.report_progress(state)
}
}
impl<EM, M> HasEventManagerId for MonitorTypedEventManager<EM, M>
where
EM: HasEventManagerId,
{
#[inline]
fn mgr_id(&self) -> EventManagerId {
self.inner.mgr_id()
}
}
#[cfg(test)] #[cfg(test)]
mod tests { mod tests {