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"]
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)
injections = ["libafl_qemu/injections"]

View File

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

View File

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

View File

@ -1,14 +1,19 @@
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::{
corpus::{Corpus, InMemoryOnDiskCorpus, OnDiskCorpus},
events::{EventRestarter, LlmpRestartingEventManager},
events::EventRestarter,
executors::ShadowExecutor,
feedback_or, feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Evaluator, Fuzzer, StdFuzzer},
inputs::BytesInput,
monitors::Monitor,
mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens,
@ -24,11 +29,12 @@ use libafl::{
state::{HasCorpus, HasMetadata, StdState, UsesState},
Error,
};
#[cfg(not(feature = "simplemgr"))]
use libafl_bolts::shmem::StdShMemProvider;
use libafl_bolts::{
core_affinity::CoreId,
current_nanos,
rands::StdRand,
shmem::StdShMemProvider,
tuples::{tuple_list, Merge},
};
use libafl_qemu::{
@ -44,18 +50,24 @@ use crate::{harness::Harness, options::FuzzerOptions};
pub type ClientState =
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)]
pub struct Instance<'a> {
pub struct Instance<'a, M: Monitor> {
options: &'a FuzzerOptions,
emu: &'a Emulator,
mgr: ClientMgr,
mgr: ClientMgr<M>,
core_id: CoreId,
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>
where
QT: QemuHelperTuple<ClientState>,
@ -207,11 +219,11 @@ impl<'a> Instance<'a> {
stages: &mut ST,
) -> Result<(), Error>
where
Z: Fuzzer<E, ClientMgr, ST>
Z: Fuzzer<E, ClientMgr<M>, ST>
+ UsesState<State = ClientState>
+ Evaluator<E, ClientMgr, State = ClientState>,
+ Evaluator<E, ClientMgr<M>, 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()];

View File

@ -521,16 +521,16 @@ where
// If we are measuring scalability stuff..
#[cfg(feature = "scalability_introspection")]
{
let received_with_observer = state.scalability_monitor().testcase_with_observers;
let received_without_observer = state.scalability_monitor().testcase_without_observers;
let imported_with_observer = state.scalability_monitor().testcase_with_observers;
let imported_without_observer = state.scalability_monitor().testcase_without_observers;
self.fire(
state,
Event::UpdateUserStats {
name: "total received".to_string(),
name: "total imported".to_string(),
value: UserStats::new(
UserStatsValue::Number(
(received_with_observer + received_without_observer) as u64,
(imported_with_observer + imported_without_observer) as u64,
),
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)]
mod tests {