fuzzer parallelization

This commit is contained in:
Alwin Berger 2022-02-11 15:13:34 +01:00
parent 5c5f1f77bd
commit 1713824c3b
2 changed files with 89 additions and 89 deletions

View File

@ -18,9 +18,11 @@ use std::{
use libafl::{ use libafl::{
bolts::{ bolts::{
current_nanos, current_time, current_nanos, current_time,
os::dup2, os::{dup2,Cores},
rands::StdRand, rands::StdRand,
tuples::{tuple_list, Merge}, tuples::{tuple_list, Merge},
shmem::{ShMemProvider,StdShMemProvider},
launcher::Launcher,
}, },
corpus::{ corpus::{
Corpus, OnDiskCorpus, PowerQueueCorpusScheduler, Corpus, OnDiskCorpus, PowerQueueCorpusScheduler,
@ -30,7 +32,7 @@ use libafl::{
feedbacks::{MapFeedbackState, MaxMapFeedback}, feedbacks::{MapFeedbackState, MaxMapFeedback},
fuzzer::{Fuzzer, StdFuzzer}, fuzzer::{Fuzzer, StdFuzzer},
inputs::{BytesInput, HasTargetBytes}, inputs::{BytesInput, HasTargetBytes},
monitors::SimpleMonitor, monitors::{MultiMonitor,SimpleMonitor},
mutators::{ mutators::{
scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations, scheduled::havoc_mutations, token_mutations::I2SRandReplace, tokens_mutations,
StdMOptMutator, StdScheduledMutator, Tokens, StdMOptMutator, StdScheduledMutator, Tokens,
@ -42,7 +44,8 @@ use libafl::{
ShadowTracingStage, StdMutationalStage, ShadowTracingStage, StdMutationalStage,
}, },
state::{HasCorpus, HasMetadata, StdState}, state::{HasCorpus, HasMetadata, StdState},
events::SimpleEventManager, events::{SimpleEventManager,EventConfig},
generators::RandBytesGenerator,
Error, Error,
}; };
use libafl_qemu::{ use libafl_qemu::{
@ -61,7 +64,7 @@ use libafl_qemu::{
clock::ClockFeedback, clock::ClockFeedback,
clock::QemuClockIncreaseFeedback clock::QemuClockIncreaseFeedback
}; };
use wcet_qemu_sys::worst::{HitFeedback,HitcountsMapObserver,HitImprovingFeedback,LenTimeMaximizerCorpusScheduler}; use wcet_qemu_sys::worst::{SortedFeedback,HitFeedback,HitcountsMapObserver,HitImprovingFeedback,LenTimeMaximizerCorpusScheduler};
/// The fuzzer main /// The fuzzer main
@ -214,7 +217,27 @@ fn fuzz(
) -> Result<(), Error> { ) -> Result<(), Error> {
env::remove_var("LD_LIBRARY_PATH"); env::remove_var("LD_LIBRARY_PATH");
//=========== Initialize the Emulator //=========== Analyze the binary to find the target function address
let mut elf_buffer = Vec::new();
let elf = EasyElf::from_file(&kernel, &mut elf_buffer)?;
let input_addr = elf
.resolve_symbol("FUZZ_INPUT", 0)
.expect("Symbol FUZZ_INPUT not found");
let input_addr = virt2phys(input_addr,&elf.goblin());
println!("FUZZ_INPUT @ {:#x}", input_addr);
let test_length_ptr = elf
.resolve_symbol("FUZZ_LENGTH", 0)
.expect("Symbol FUZZ_LENGTH not found");
let test_length_ptr = virt2phys(test_length_ptr,&elf.goblin());
println!("FUZZ_LENGTH @ {:#x}", test_length_ptr);
let check_breakpoint = elf
.resolve_symbol("trigger_Qemu_break", 0)
.expect("Symbol trigger_Qemu_break not found");
let check_breakpoint = virt2phys(check_breakpoint,&elf.goblin());
println!("Breakpoint at {:#x}", check_breakpoint);
//=========== Prepare Emulator Args
let args: Vec<String> = vec![ let args: Vec<String> = vec![
"qemu-system-arm", "qemu-system-arm",
"-machine","mps2-an385", "-machine","mps2-an385",
@ -228,36 +251,8 @@ fn fuzz(
"-S" "-S"
].iter().map(|x| x.to_string()).collect(); ].iter().map(|x| x.to_string()).collect();
let env: Vec<(String, String)> = env::vars().collect(); let env: Vec<(String, String)> = env::vars().collect();
let emu = Emulator::new(&args, &env);
//=========== Analyze the binary to find the target function address
let mut elf_buffer = Vec::new();
let bin_path=kernel;
let elf = EasyElf::from_file(bin_path, &mut elf_buffer)?;
let test_one_input_ptr = elf
.resolve_symbol("FUZZ_INPUT", 0)
.expect("Symbol FUZZ_INPUT not found");
let test_one_input_ptr = virt2phys(test_one_input_ptr,&elf.goblin());
println!("FUZZ_INPUT @ {:#x}", test_one_input_ptr);
let test_length_ptr = elf
.resolve_symbol("FUZZ_LENGTH", 0)
.expect("Symbol FUZZ_LENGTH not found");
let test_length_ptr = virt2phys(test_length_ptr,&elf.goblin());
println!("FUZZ_LENGTH @ {:#x}", test_length_ptr);
let check_breakpoint = elf
.resolve_symbol("trigger_Qemu_break", 0)
.expect("Symbol trigger_Qemu_break not found");
let check_breakpoint = virt2phys(check_breakpoint,&elf.goblin());
println!("Breakpoint at {:#x}", check_breakpoint);
//====== Note the input field
let input_addr = test_one_input_ptr;
println!("Placing input at {:#x}", input_addr);
emu.set_breakpoint(check_breakpoint); // trigger_Qemu_break
//====== Setup log and stdout
let log = RefCell::new( let log = RefCell::new(
OpenOptions::new() OpenOptions::new()
.append(true) .append(true)
@ -265,30 +260,18 @@ fn fuzz(
.open(&logfile)?, .open(&logfile)?,
); );
#[cfg(unix)] let shmem_provider = StdShMemProvider::new().expect("Failed to init shared memory");
let mut stdout_cpy = unsafe { let monitor = MultiMonitor::new(|s| {
let new_fd = dup(io::stdout().as_raw_fd())?; println!("{}",s);
File::from_raw_fd(new_fd) writeln!(log.borrow_mut(), "{}",s).unwrap();
};
#[cfg(unix)]
let file_null = File::open("/dev/null")?;
//====== Create the most simple status display and managers.
// 'While the stats are state, they are usually used in the broker - which is likely never restarted
let monitor = SimpleMonitor::new(|s| {
#[cfg(unix)]
writeln!(&mut stdout_cpy, "{}", s).unwrap();
#[cfg(windows)]
println!("{}", s);
writeln!(log.borrow_mut(), "{:?} {}", current_time(), s).unwrap();
}); });
// let mut shmem_provider = StdShMemProvider::new()?; //====== Child Function
let mut run_client = |state: Option<StdState<_, _, _, _, _>>, mut mgr, _core_id| {
//====== Create the most simple status display and managers.
let mut mgr = SimpleEventManager::new(monitor);
//====== Set up Emu and termination-point
let emu = Emulator::new(&args, &env);
emu.set_breakpoint(check_breakpoint); // trigger_Qemu_break
// Create an observation channel using the coverage map // Create an observation channel using the coverage map
let edges = unsafe { &mut edges::EDGES_MAP }; let edges = unsafe { &mut edges::EDGES_MAP };
let edges_counter = unsafe { &mut edges::MAX_EDGES_NUM }; let edges_counter = unsafe { &mut edges::MAX_EDGES_NUM };
@ -316,37 +299,32 @@ fn fuzz(
}, },
}; };
let feedback = feedback_or!( let feedback = feedback_or!(
// New maximization map feedback linked to the edges observer and the feedback state
MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false), MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false),
HitImprovingFeedback::new(target_map.clone()), // HitImprovingFeedback::new(target_map.clone()),
QemuClockIncreaseFeedback::default(), QemuClockIncreaseFeedback::default(),
ClockFeedback::new_with_observer(&clock_observer) ClockFeedback::new_with_observer(&clock_observer)
); );
// let feedback = feedback_or!(
// // New maximization map feedback linked to the edges observer and the feedback state
// MaxMapFeedback::new_tracking(&feedback_state, &edges_observer, true, false),
// MapHitIncreaseFeedback::new(),
// // Time feedback, this one does not need a feedback state
// TimeFeedback::new_with_observer(&time_observer)
// );
// A feedback to choose if an input is a solution or not // A feedback to choose if an input is a solution or not
let objective = HitFeedback::new(target_map,0.0); // let objective = HitFeedback::new(target_map,0.0);
let objective = SortedFeedback::new();
// create a State from scratch // create a State from scratch
let mut state = { let mut state = state.unwrap_or_else(||{
StdState::new( StdState::new(
// RNG // RNG
StdRand::with_seed(current_nanos()), StdRand::with_seed(current_nanos()),
// Corpus that will be evolved, we keep it in memory for performance // Corpus that will be evolved
OnDiskCorpus::new(corpus_dir).unwrap(), OnDiskCorpus::new(&corpus_dir).unwrap(),
// Corpus in which we store solutions (crashes in this example), // Corpus in which we store solutions (crashes in this example),
// on disk so the user can get them after stopping the fuzzer // on disk so the user can get them after stopping the fuzzer
OnDiskCorpus::new(objective_dir).unwrap(), OnDiskCorpus::new(&objective_dir).unwrap(),
// States of the feedbacks. // States of the feedbacks.
// They are the data related to the feedbacks that you want to persist in the State. // They are the data related to the feedbacks that you want to persist in the State.
tuple_list!(feedback_state,clock::MaxIcountMetadata::default()), tuple_list!(feedback_state,clock::MaxIcountMetadata::default()),
) )
}; });
let calibration = CalibrationStage::new(&mut state, &edges_observer); let calibration = CalibrationStage::new(&mut state, &edges_observer);
@ -407,20 +385,27 @@ fn fuzz(
let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer)); let mut executor = ShadowExecutor::new(executor, tuple_list!(cmplog_observer));
// Read tokens // Read tokens
if let Some(tokenfile) = tokenfile { if let Some(tokenfile) = &tokenfile {
if state.metadata().get::<Tokens>().is_none() { if state.metadata().get::<Tokens>().is_none() {
state.add_metadata(Tokens::from_tokens_file(tokenfile)?); state.add_metadata(Tokens::from_tokens_file(&tokenfile)?);
} }
} }
if state.corpus().count() < 1 { if state.corpus().count() < 1 {
state if _core_id == 0 && state.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[seed_dir.clone()]).is_ok() {
.load_initial_inputs(&mut fuzzer, &mut executor, &mut mgr, &[seed_dir.clone()]) // println!("We imported {} inputs from disk.", state.corpus().count());
.unwrap_or_else(|_| { } else {
println!("Failed to load initial corpus at {:?}", &seed_dir); let mut generator = RandBytesGenerator::new(32);
process::exit(0); state
}); .generate_initial_inputs(
println!("We imported {} inputs from disk.", state.corpus().count()); &mut fuzzer,
&mut executor,
&mut generator,
&mut mgr,
8,
)
.expect("Failed to generate the initial corpus");
}
} }
let tracing = ShadowTracingStage::new(&mut executor); let tracing = ShadowTracingStage::new(&mut executor);
@ -430,18 +415,13 @@ fn fuzz(
// Remove target ouput (logs still survive) // Remove target ouput (logs still survive)
#[cfg(unix)] #[cfg(unix)]
let file_null = File::open("/dev/null")?;
#[cfg(unix)]
{ {
let null_fd = file_null.as_raw_fd(); let null_fd = file_null.as_raw_fd();
dup2(null_fd, io::stdout().as_raw_fd())?; dup2(null_fd, io::stdout().as_raw_fd())?;
dup2(null_fd, io::stderr().as_raw_fd())?; dup2(null_fd, io::stderr().as_raw_fd())?;
} }
// reopen file to make sure we're at the end
log.replace(
OpenOptions::new()
.append(true)
.create(true)
.open(&logfile)?,
);
fuzzer fuzzer
.fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr) .fuzz_loop(&mut stages, &mut executor, &mut state, &mut mgr)
@ -449,4 +429,23 @@ fn fuzz(
// Never reached // Never reached
Ok(()) Ok(())
};
match Launcher::builder()
.shmem_provider(shmem_provider)
.configuration(EventConfig::AlwaysUnique)
.monitor(monitor)
.run_client(&mut run_client)
.cores(&Cores::from_cmdline("all").unwrap())
// .broker_port(1337)
// .remote_broker_addr(remote_broker_addr)
//.stdout_file(Some("/dev/null"))
.build()
.launch()
{
Ok(_) | Err(Error::ShuttingDown) => (),
Err(e) => panic!("{:?}", e),
};
Ok(())
} }

View File

@ -2219,11 +2219,12 @@ where
loop { loop {
match listener.accept() { match listener.accept() {
ListenerStream::Tcp(mut stream, addr) => { ListenerStream::Tcp(mut stream, addr) => {
eprintln!( // For some reason stderr is not avalible in child
"New connection: {:?}/{:?}", // eprintln!(
addr, // "New connection: {:?}/{:?}",
stream.peer_addr().unwrap() // addr,
); // stream.peer_addr().unwrap()
// );
// Send initial information, without anyone asking. // Send initial information, without anyone asking.
// This makes it a tiny bit easier to map the broker map for new Clients. // This makes it a tiny bit easier to map the broker map for new Clients.