Add SimpleMgr feature to qemu_launcher (#1790)
This commit is contained in:
parent
0cb7b25f39
commit
6a0ba7b647
@ -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"]
|
||||
|
||||
|
@ -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()?;
|
||||
|
@ -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)
|
||||
|
@ -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()];
|
||||
|
||||
|
@ -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 {
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user