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"]
|
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"]
|
||||||
|
|
||||||
|
@ -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()?;
|
||||||
|
@ -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)
|
||||||
|
@ -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()];
|
||||||
|
|
||||||
|
@ -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 {
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user