working on restarts

This commit is contained in:
Dominik Maier 2021-02-10 12:12:03 +01:00
parent e628bf1806
commit 13fd3776fd
4 changed files with 56 additions and 35 deletions

View File

@ -858,7 +858,13 @@ where
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn setup_restarting_state<I, C, FT, R, SH, ST>( pub fn setup_restarting_state<I, C, FT, R, SH, ST>(
mgr: &mut LlmpEventManager<I, SH, ST>, mgr: &mut LlmpEventManager<I, SH, ST>,
) -> Result<(Option<State<C, I, R, FT>>, LlmpRestartingEventManager<I, SH, ST>), AflError> ) -> Result<
(
Option<State<C, I, R, FT>>,
LlmpRestartingEventManager<I, SH, ST>,
),
AflError,
>
where where
I: Input, I: Input,
C: Corpus<I, R>, C: Corpus<I, R>,
@ -908,15 +914,17 @@ where
None => { None => {
println!("First run. Let's set it all up"); println!("First run. Let's set it all up");
// Mgr to send and receive msgs from/to all other fuzzer instances // Mgr to send and receive msgs from/to all other fuzzer instances
let client_mgr = let client_mgr = LlmpEventManager::<I, SH, ST>::existing_client_from_env(
LlmpEventManager::<I, SH, ST>::existing_client_from_env(ENV_FUZZER_BROKER_CLIENT_INITIAL)?; ENV_FUZZER_BROKER_CLIENT_INITIAL,
)?;
(None, LlmpRestartingEventManager::new(client_mgr, sender)) (None, LlmpRestartingEventManager::new(client_mgr, sender))
} }
// Restoring from a previous run, deserialize state and corpus. // Restoring from a previous run, deserialize state and corpus.
Some((_sender, _tag, msg)) => { Some((_sender, _tag, msg)) => {
println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len()); println!("Subsequent run. Let's load all data from shmem (received {} bytes from previous instance)", msg.len());
let (state, mgr): (State<C, I, R, FT>, LlmpEventManager<I, SH, ST>) = deserialize_state_mgr(&msg)?; let (state, mgr): (State<C, I, R, FT>, LlmpEventManager<I, SH, ST>) =
deserialize_state_mgr(&msg)?;
(Some(state), LlmpRestartingEventManager::new(mgr, sender)) (Some(state), LlmpRestartingEventManager::new(mgr, sender))
} }

View File

@ -80,15 +80,13 @@ where
R: Rand, R: Rand,
FT: FeedbacksTuple<BytesInput>, FT: FeedbacksTuple<BytesInput>,
{ {
pub fn load_from_directory<G, E, OT, EM>( pub fn load_from_directory<E, OT, EM>(
&mut self, &mut self,
executor: &mut E, executor: &mut E,
generator: &mut G,
manager: &mut EM, manager: &mut EM,
in_dir: &Path, in_dir: &Path,
) -> Result<(), AflError> ) -> Result<(), AflError>
where where
G: Generator<BytesInput, R>,
C: Corpus<BytesInput, R>, C: Corpus<BytesInput, R>,
E: Executor<BytesInput> + HasObservers<OT>, E: Executor<BytesInput> + HasObservers<OT>,
OT: ObserversTuple, OT: ObserversTuple,
@ -114,29 +112,27 @@ where
println!("File {:?} was not interesting, skipped.", &path); println!("File {:?} was not interesting, skipped.", &path);
} }
} else if attr.is_dir() { } else if attr.is_dir() {
self.load_from_directory(executor, generator, manager, &path)?; self.load_from_directory(executor, manager, &path)?;
} }
} }
Ok(()) Ok(())
} }
pub fn load_initial_inputs<G, E, OT, EM>( pub fn load_initial_inputs<E, OT, EM>(
&mut self, &mut self,
executor: &mut E, executor: &mut E,
generator: &mut G,
manager: &mut EM, manager: &mut EM,
in_dirs: &[PathBuf], in_dirs: &[PathBuf],
) -> Result<(), AflError> ) -> Result<(), AflError>
where where
G: Generator<BytesInput, R>,
C: Corpus<BytesInput, R>, C: Corpus<BytesInput, R>,
E: Executor<BytesInput> + HasObservers<OT>, E: Executor<BytesInput> + HasObservers<OT>,
OT: ObserversTuple, OT: ObserversTuple,
EM: EventManager<BytesInput>, EM: EventManager<BytesInput>,
{ {
for in_dir in in_dirs { for in_dir in in_dirs {
self.load_from_directory(executor, generator, manager, in_dir)?; self.load_from_directory(executor, manager, in_dir)?;
} }
manager.fire( manager.fire(
self, self,

View File

@ -20,6 +20,8 @@
#include <vector> #include <vector>
#define HAS_BUG 1
#define PNG_INTERNAL #define PNG_INTERNAL
#include "png.h" #include "png.h"

View File

@ -1,3 +1,6 @@
//! A libfuzzer-like fuzzer with llmp-multithreading support and restarts
//! The example harness is built for libpng.
#[macro_use] #[macro_use]
extern crate clap; extern crate clap;
@ -6,6 +9,7 @@ use std::{env, path::PathBuf, process::Command};
use afl::{ use afl::{
corpus::{Corpus, InMemoryCorpus}, corpus::{Corpus, InMemoryCorpus},
events::setup_restarting_state,
events::{LlmpEventManager, SimpleStats}, events::{LlmpEventManager, SimpleStats},
executors::{inprocess::InProcessExecutor, Executor, ExitKind}, executors::{inprocess::InProcessExecutor, Executor, ExitKind},
feedbacks::MaxMapFeedback, feedbacks::MaxMapFeedback,
@ -17,8 +21,7 @@ use afl::{
stages::mutational::StdMutationalStage, stages::mutational::StdMutationalStage,
state::{HasCorpus, State}, state::{HasCorpus, State},
tuples::tuple_list, tuples::tuple_list,
utils::{ StdRand}, utils::StdRand,
events::setup_restarting_state,
AflError, Fuzzer, StdFuzzer, AflError, Fuzzer, StdFuzzer,
}; };
@ -116,7 +119,7 @@ pub fn main() {
/// The actual fuzzer /// The actual fuzzer
fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> { fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
let mut rand = StdRand::new(0); let mut rand = StdRand::new(0);
let mut generator = RandPrintablesGenerator::new(32); /// TODO: Don't the stats need to be serialized, too?
let stats = SimpleStats::new(|s| println!("{}", s)); let stats = SimpleStats::new(|s| println!("{}", s));
let mut mgr = LlmpEventManager::new_on_port_std(stats, broker_port)?; let mut mgr = LlmpEventManager::new_on_port_std(stats, broker_port)?;
@ -126,27 +129,33 @@ fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
mgr.broker_loop()?; mgr.broker_loop()?;
} }
println!("We're a client, let's fuzz :)");
// Call LLVMFUzzerInitialize() if present.
unsafe {
if afl_libfuzzer_init() == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1")
}
}
let edges_observer = let edges_observer =
StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe { StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe {
__lafl_max_edges_size as usize __lafl_max_edges_size as usize
}); });
let (state_opt, mut restarting_mgr) = setup_restarting_state(&mut mgr).expect("Failed to setup the restarter".into()); let mut mutator = HavocBytesMutator::new_default();
mutator.set_max_size(4096);
let stage = StdMutationalStage::new(mutator);
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
// The restarting state will spawn the same process again as child, then restartet it each time it crashes.
let (state_opt, mut restarting_mgr) =
setup_restarting_state(&mut mgr).expect("Failed to setup the restarter".into());
let mut state = match state_opt { let mut state = match state_opt {
Some(s) => s, Some(s) => s,
None => State::new(InMemoryCorpus::new(), tuple_list!(MaxMapFeedback::new_with_observer(&NAME_COV_MAP, &edges_observer))) None => State::new(
InMemoryCorpus::new(),
tuple_list!(MaxMapFeedback::new_with_observer(
&NAME_COV_MAP,
&edges_observer
)),
),
}; };
// Create the engine println!("We're a client, let's fuzz :)");
// Create the executor
let mut executor = InProcessExecutor::new( let mut executor = InProcessExecutor::new(
"Libfuzzer", "Libfuzzer",
harness, harness,
@ -155,29 +164,35 @@ fn fuzz(input: Option<Vec<PathBuf>>, broker_port: u16) -> Result<(), AflError> {
&mut restarting_mgr, &mut restarting_mgr,
); );
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
unsafe {
if afl_libfuzzer_init() == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1")
}
}
// in case the corpus is empty (on first run), reset // in case the corpus is empty (on first run), reset
if state.corpus().count() < 1 { if state.corpus().count() < 1 {
match input { match input {
Some(x) => state Some(x) => state
.load_initial_inputs(&mut executor, &mut generator, &mut restarting_mgr, &x) .load_initial_inputs(&mut executor, &mut restarting_mgr, &x)
.expect(&format!("Failed to load initial corpus at {:?}", &x)), .expect(&format!("Failed to load initial corpus at {:?}", &x)),
None => (), None => (),
} }
println!("We imported {} inputs from disk.", state.corpus().count()); println!("We imported {} inputs from disk.", state.corpus().count());
} }
/*
if state.corpus().count() < 1 { if state.corpus().count() < 1 {
println!("Generating random inputs"); println!("Generating random inputs");
let mut generator = RandPrintablesGenerator::new(32);
state state
.generate_initial_inputs(&mut rand, &mut executor, &mut generator, &mut restarting_mgr, 4) .generate_initial_inputs(&mut rand, &mut executor, &mut generator, &mut restarting_mgr, 4)
.expect("Failed to generate initial inputs"); .expect("Failed to generate initial inputs");
println!("We generated {} inputs.", state.corpus().count()); println!("We generated {} inputs.", state.corpus().count());
} }
*/
let mut mutator = HavocBytesMutator::new_default();
mutator.set_max_size(4096);
let stage = StdMutationalStage::new(mutator);
let mut fuzzer = StdFuzzer::new(tuple_list!(stage));
fuzzer.fuzz_loop(&mut rand, &mut executor, &mut state, &mut restarting_mgr) fuzzer.fuzz_loop(&mut rand, &mut executor, &mut state, &mut restarting_mgr)
} }