Addison Crump 28c43b332f
Match by Ref fix (#2105)
* match by ref fix

* impl Named for Reference

* rename

* magic indexing

* whoops

* docs, clippy

* some additional CI complaints

* other libafl_qemu fixes

* missed an alloc feature

* a smattering of fixes

* use from not direct construction

* tinyinst fix

* horrible double-mutability things

* fixup nyx

* from not new

* forkserver_simple fixes

* dogfood: forkserver

* mmmm yummy dogfood

* round one CI fixes

* clippy appeasement

* deref generic impl to simplify usage

* adaptive serialization (ouch)

* remaining clippy items

* I am tired

* new not with

* fixup: aflpp tracing was not actually constructable

* fix tmin

* reduce complexity of map feedback now that we do not need to constrain

* frida fixes

* fix concolic

* type_ref => reference
2024-04-27 18:08:09 +02:00

182 lines
6.6 KiB
Rust

use core::time::Duration;
use std::{env, path::PathBuf};
use libafl::{
corpus::{Corpus, InMemoryCorpus, OnDiskCorpus},
events::{setup_restarting_mgr_std, EventConfig, EventRestarter},
executors::{inprocess::InProcessExecutor, ExitKind},
feedback_or, feedback_or_fast,
feedbacks::{CrashFeedback, MaxMapFeedback, TimeFeedback, TimeoutFeedback},
fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes},
monitors::MultiMonitor,
mutators::scheduled::{havoc_mutations, tokens_mutations, StdScheduledMutator},
observers::{CanTrack, HitcountsMapObserver, TimeObserver},
schedulers::{
powersched::PowerSchedule, IndexesLenTimeMinimizerScheduler, StdWeightedScheduler,
},
stages::{calibrate::CalibrationStage, power::StdPowerMutationalStage},
state::{HasCorpus, StdState},
Error,
};
use libafl_bolts::{
current_nanos,
rands::StdRand,
tuples::{tuple_list, Merge},
AsSlice,
};
use libafl_targets::{libfuzzer_initialize, libfuzzer_test_one_input, std_edges_map_observer};
#[no_mangle]
pub extern "C" fn libafl_main() {
println!(
"Workdir: {:?}",
env::current_dir().unwrap().to_string_lossy().to_string()
);
fuzz(
&[PathBuf::from("./corpus")],
PathBuf::from("./crashes"),
1337,
)
.expect("An error occurred while fuzzing");
}
/// The actual fuzzer
#[cfg(not(test))]
fn fuzz(corpus_dirs: &[PathBuf], objective_dir: PathBuf, broker_port: u16) -> Result<(), Error> {
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
let monitor = MultiMonitor::new(|s| println!("{}", s));
// The restarting state will spawn the same process again as child, then restarted it each time it crashes.
let (state, mut restarting_mgr) =
match setup_restarting_mgr_std(monitor, broker_port, EventConfig::AlwaysUnique) {
Ok(res) => res,
Err(err) => match err {
Error::ShuttingDown => {
return Ok(());
}
_ => {
panic!("Failed to setup the restarter: {}", err);
}
},
};
// Create an observation channel using the coverage map
let edges_observer =
unsafe { HitcountsMapObserver::new(std_edges_map_observer("edges")).track_indices() };
// Create an observation channel to keep track of the execution time
let time_observer = TimeObserver::new("time");
let map_feedback = MaxMapFeedback::new(&edges_observer);
let calibration = CalibrationStage::new(&map_feedback);
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
let mut feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state
map_feedback,
// Time feedback, this one does not need a feedback state
TimeFeedback::new(&time_observer)
);
// A feedback to choose if an input is a solution or not
let mut objective = feedback_or_fast!(CrashFeedback::new(), TimeoutFeedback::new());
// If not restarting, create a State from scratch
let mut state = state.unwrap_or_else(|| {
StdState::new(
// RNG
StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance
InMemoryCorpus::new(),
// Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(objective_dir).unwrap(),
// States of the feedbacks.
// The feedbacks can report the data that should persist in the State.
&mut feedback,
// Same for objective feedbacks
&mut objective,
)
.unwrap()
});
println!("We're a client, let's fuzz :)");
// Setup a basic mutator with a mutational stage
let mutator = StdScheduledMutator::new(havoc_mutations().merge(tokens_mutations()));
let power = StdPowerMutationalStage::new(mutator);
let mut stages = tuple_list!(calibration, power);
// A minimization+queue policy to get testcasess from the corpus
let scheduler = IndexesLenTimeMinimizerScheduler::new(
&edges_observer,
StdWeightedScheduler::with_schedule(&mut state, &edges_observer, Some(PowerSchedule::FAST)),
);
// A fuzzer with feedbacks and a corpus scheduler
let mut fuzzer = StdFuzzer::new(scheduler, feedback, objective);
// The wrapped harness function, calling out to the LLVM-style harness
let mut harness = |input: &BytesInput| {
let target = input.target_bytes();
let buf = target.as_slice();
libfuzzer_test_one_input(buf);
ExitKind::Ok
};
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
tuple_list!(edges_observer, time_observer),
&mut fuzzer,
&mut state,
&mut restarting_mgr,
Duration::new(10, 0),
)?;
// Initialize ASAN, call this before any ASAN crashes can occur (directly after initializing executor e.g.)
#[cfg(windows)]
unsafe {
libafl_targets::setup_asan_callback(&executor, &restarting_mgr, &fuzzer);
}
// The actual target run starts here.
// Call LLVMFUzzerInitialize() if present.
let args: Vec<String> = env::args().collect();
if libfuzzer_initialize(&args) == -1 {
println!("Warning: LLVMFuzzerInitialize failed with -1");
}
// In case the corpus is empty (on first run), reset
if state.must_load_initial_inputs() {
state
.load_initial_inputs(&mut fuzzer, &mut executor, &mut restarting_mgr, corpus_dirs)
.unwrap_or_else(|_| panic!("Failed to load initial corpus at {:?}", &corpus_dirs));
println!("We imported {} inputs from disk.", state.corpus().count());
}
// This fuzzer restarts after 1 mio `fuzz_one` executions.
// Each fuzz_one will internally do many executions of the target.
// If your target is very instable, setting a low count here may help.
// However, you will lose a lot of performance that way.
let iters = 1_000_000;
fuzzer.fuzz_loop_for(
&mut stages,
&mut executor,
&mut state,
&mut restarting_mgr,
iters,
)?;
// It's important, that we store the state before restarting!
// Else, the parent will not respawn a new child and quit.
restarting_mgr.on_restart(&mut state)?;
Ok(())
}