first steps towards respawning
This commit is contained in:
parent
669cb1c96b
commit
27a68fa30d
@ -400,6 +400,19 @@ impl<SH> LlmpSender<SH>
|
||||
where
|
||||
SH: ShMem,
|
||||
{
|
||||
pub fn new(id: u32, keep_pages_forever: bool) -> Result<Self, AflError> {
|
||||
Ok(Self {
|
||||
id,
|
||||
last_msg_sent: 0 as *mut LlmpMsg,
|
||||
out_maps: vec![LlmpSharedMap::new(
|
||||
0,
|
||||
SH::new_map(new_map_size(LLMP_PREF_INITIAL_MAP_SIZE))?,
|
||||
)],
|
||||
// drop pages to the broker if it already read them
|
||||
keep_pages_forever,
|
||||
})
|
||||
}
|
||||
|
||||
/// Reattach to a vacant out_map, to with a previous sender stored the information in an env before.
|
||||
#[cfg(feature = "std")]
|
||||
pub fn on_existing_from_env(env_name: &str) -> Result<Self, AflError> {
|
||||
@ -890,7 +903,7 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns the next message, tag, buf, looping until it becomes available
|
||||
/// Returns the next sender, tag, buf, looping until it becomes available
|
||||
#[inline]
|
||||
pub fn recv_buf_blocking(&mut self) -> Result<(u32, u32, &[u8]), AflError> {
|
||||
unsafe {
|
||||
@ -912,7 +925,7 @@ where
|
||||
{
|
||||
/// Shmem containg the actual (unsafe) page,
|
||||
/// shared between one LlmpSender and one LlmpReceiver
|
||||
shmem: SH,
|
||||
pub shmem: SH,
|
||||
}
|
||||
|
||||
// TODO: May be obsolete
|
||||
|
@ -118,7 +118,7 @@ pub trait Stats {
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Debug)]
|
||||
#[derive(Clone, Debug)]
|
||||
pub struct SimpleStats<F>
|
||||
where
|
||||
F: FnMut(String),
|
||||
@ -743,6 +743,12 @@ where
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// If a client respawns, it may reuse the existing connection, previously stored by LlmpClient::to_env
|
||||
/// Std uses AflShmem.
|
||||
pub fn existing_client_from_env_std(env_name: &str, stats: ST) -> Result<Self, AflError> {
|
||||
Self::existing_client_from_env(env_name, stats)
|
||||
}
|
||||
}
|
||||
|
||||
impl<C, E, OT, FT, I, R, SH, ST> LlmpEventManager<C, E, OT, FT, I, R, SH, ST>
|
||||
@ -768,6 +774,19 @@ where
|
||||
})
|
||||
}
|
||||
|
||||
/// If a client respawns, it may reuse the existing connection, previously stored by LlmpClient::to_env
|
||||
pub fn existing_client_from_env(env_name: &str, stats: ST) -> Result<Self, AflError> {
|
||||
Ok(Self {
|
||||
llmp: llmp::LlmpConnection::IsClient {
|
||||
client: LlmpClient::on_existing_from_env(env_name)?,
|
||||
},
|
||||
// Inserting a nop-stats element here so rust won't complain.
|
||||
// In any case, the client won't currently use it.
|
||||
stats: stats,
|
||||
phantom: PhantomData,
|
||||
})
|
||||
}
|
||||
|
||||
/// A client on an existing map
|
||||
pub fn for_client(client: LlmpClient<SH>, stats: ST) -> Self {
|
||||
Self {
|
||||
@ -777,6 +796,17 @@ where
|
||||
}
|
||||
}
|
||||
|
||||
#[cfg(feature = "std")]
|
||||
/// Write the config for a client eventmgr to env vars, a new client can reattach using existing_client_from_env
|
||||
pub fn to_env(&self, env_name: &str) {
|
||||
match &self.llmp {
|
||||
llmp::LlmpConnection::IsBroker { broker: _ } => {
|
||||
todo!("There is probably no use storing the broker to env. Client only for now")
|
||||
}
|
||||
llmp::LlmpConnection::IsClient { client } => client.to_env(env_name).unwrap(),
|
||||
}
|
||||
}
|
||||
|
||||
/// Returns if we are the broker
|
||||
pub fn is_broker(&self) -> bool {
|
||||
match self.llmp {
|
||||
|
@ -60,6 +60,14 @@ struct shmid_ds {
|
||||
|
||||
/// A Shared map
|
||||
pub trait ShMem: Sized + Debug {
|
||||
/// Creates a new map with the given size
|
||||
fn new_map(map_size: usize) -> Result<Self, AflError>;
|
||||
|
||||
/// Creates a new reference to the same map
|
||||
fn clone_ref(old_ref: &Self) -> Result<Self, AflError> {
|
||||
Self::existing_from_shm_slice(old_ref.shm_slice(), old_ref.map().len())
|
||||
}
|
||||
|
||||
/// Creates a nes variable with the given name, strigified to 20 bytes.
|
||||
fn existing_from_shm_slice(map_str_bytes: &[u8; 20], map_size: usize)
|
||||
-> Result<Self, AflError>;
|
||||
@ -73,9 +81,6 @@ pub trait ShMem: Sized + Debug {
|
||||
Self::existing_from_shm_slice(&slice, map_size)
|
||||
}
|
||||
|
||||
/// Creates a new map with the given size
|
||||
fn new_map(map_size: usize) -> Result<Self, AflError>;
|
||||
|
||||
/// The string to identify this shm
|
||||
fn shm_str(&self) -> String {
|
||||
let bytes = self.shm_slice();
|
||||
|
@ -20,9 +20,16 @@ where
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
harness: HarnessFunction<I>,
|
||||
observers: OT,
|
||||
/// The name of this executor instance, to address it from other components
|
||||
name: &'static str,
|
||||
/// The harness function, being executed for each fuzzing loop execution
|
||||
harness: HarnessFunction<I>,
|
||||
/// The observers, observing each run
|
||||
observers: OT,
|
||||
/*
|
||||
/// A special function being called right before the process crashes. It may save state to restore fuzzing after respawn.
|
||||
on_crash_fn: Option<Box<dyn FnOnce(ExitKind)>>,
|
||||
*/
|
||||
}
|
||||
|
||||
impl<I, OT> Executor<I> for InMemoryExecutor<I, OT>
|
||||
@ -75,11 +82,22 @@ where
|
||||
I: Input + HasTargetBytes,
|
||||
OT: ObserversTuple,
|
||||
{
|
||||
pub fn new(name: &'static str, harness_fn: HarnessFunction<I>, observers: OT) -> Self {
|
||||
/// Create a new in mem executor.
|
||||
/// * `name` - the name of this executor (to address it along the way)
|
||||
/// * `harness_fn` - the harness, executiong the function
|
||||
/// * `on_crash_fn` - When an in-mem harness crashes, it may safe some state to continue fuzzing later.
|
||||
/// Do that that in this function. The program will crash afterwards.
|
||||
/// * `observers` - the observers observing the target during execution
|
||||
pub fn new(
|
||||
name: &'static str,
|
||||
harness_fn: HarnessFunction<I>,
|
||||
observers: OT, /*on_crash_fn: Option<Box<dyn FnOnce(ExitKind)>*/
|
||||
) -> Self {
|
||||
Self {
|
||||
harness: harness_fn,
|
||||
observers: observers,
|
||||
name: name,
|
||||
//on_crash_fn,
|
||||
observers,
|
||||
name,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -1,31 +1,37 @@
|
||||
#![cfg_attr(not(feature = "std"), no_std)]
|
||||
|
||||
#[macro_use]
|
||||
extern crate clap;
|
||||
extern crate alloc;
|
||||
|
||||
use clap::{App, Arg};
|
||||
use std::env;
|
||||
use std::path::PathBuf;
|
||||
use std::{env, path::PathBuf, process::Command};
|
||||
|
||||
use afl::corpus::Corpus;
|
||||
use afl::corpus::InMemoryCorpus;
|
||||
use afl::engines::Engine;
|
||||
use afl::engines::Fuzzer;
|
||||
use afl::engines::State;
|
||||
use afl::engines::StdFuzzer;
|
||||
use afl::events::{LlmpEventManager, SimpleStats};
|
||||
use afl::executors::inmemory::InMemoryExecutor;
|
||||
use afl::executors::{Executor, ExitKind};
|
||||
use afl::feedbacks::MaxMapFeedback;
|
||||
use afl::generators::RandPrintablesGenerator;
|
||||
use afl::mutators::scheduled::HavocBytesMutator;
|
||||
use afl::mutators::HasMaxSize;
|
||||
use afl::observers::StdMapObserver;
|
||||
use afl::stages::mutational::StdMutationalStage;
|
||||
use afl::tuples::tuple_list;
|
||||
use afl::utils::StdRand;
|
||||
use afl::{
|
||||
corpus::{Corpus, InMemoryCorpus},
|
||||
engines::{Engine, Fuzzer, State, StdFuzzer},
|
||||
events::{
|
||||
llmp::LlmpReceiver,
|
||||
llmp::LlmpSender,
|
||||
shmem::{AflShmem, ShMem},
|
||||
LlmpEventManager, SimpleStats,
|
||||
},
|
||||
executors::{inmemory::InMemoryExecutor, Executor, ExitKind},
|
||||
feedbacks::MaxMapFeedback,
|
||||
generators::RandPrintablesGenerator,
|
||||
mutators::{scheduled::HavocBytesMutator, HasMaxSize},
|
||||
observers::StdMapObserver,
|
||||
stages::mutational::StdMutationalStage,
|
||||
tuples::tuple_list,
|
||||
utils::StdRand,
|
||||
};
|
||||
|
||||
/// The llmp connection from the actual fuzzer to the process supervising it
|
||||
const ENV_FUZZER_PARENT_SENDER: &str = &"_AFL_ENV_FUZZER_PARENT_SENDER";
|
||||
/// The llmp (2 way) connection from a fuzzer to the broker (broadcasting all other fuzzer messages)
|
||||
const ENV_FUZZER_BROKER_CLIENT: &str = &"_AFL_ENV_FUZZER_BROKER_CLIENT";
|
||||
|
||||
/// The name of the coverage map observer, to find it again in the observer list
|
||||
const NAME_COV_MAP: &str = "cov_map";
|
||||
|
||||
/// We will interact with a c++ target, so use external c functionality
|
||||
extern "C" {
|
||||
/// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
|
||||
fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32;
|
||||
@ -38,6 +44,7 @@ extern "C" {
|
||||
static __lafl_max_edges_size: u32;
|
||||
}
|
||||
|
||||
/// The wrapped harness function, calling out to the llvm-style libfuzzer harness
|
||||
fn harness<I>(_executor: &dyn Executor<I>, buf: &[u8]) -> ExitKind {
|
||||
unsafe {
|
||||
LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len());
|
||||
@ -45,8 +52,6 @@ fn harness<I>(_executor: &dyn Executor<I>, buf: &[u8]) -> ExitKind {
|
||||
ExitKind::Ok
|
||||
}
|
||||
|
||||
const NAME_COV_MAP: &str = "cov_map";
|
||||
|
||||
pub fn main() {
|
||||
let matches = App::new("libAFLrs fuzzer harness")
|
||||
.about("libAFLrs fuzzer harness help options.")
|
||||
@ -109,15 +114,57 @@ pub fn main() {
|
||||
let mut corpus = InMemoryCorpus::new();
|
||||
let mut generator = RandPrintablesGenerator::new(32);
|
||||
let stats = SimpleStats::new(|s| println!("{}", s));
|
||||
let mut mgr = LlmpEventManager::new_on_port_std(broker_port, stats).unwrap();
|
||||
let mut mgr;
|
||||
|
||||
if mgr.is_broker() {
|
||||
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
|
||||
mgr.broker_loop().unwrap();
|
||||
// We start ourself as child process to actually fuzz
|
||||
if std::env::var(ENV_FUZZER_PARENT_SENDER).is_err() {
|
||||
// We are either the broker, or the parent of the fuzzing instance
|
||||
mgr = LlmpEventManager::new_on_port_std(broker_port, stats.clone()).unwrap();
|
||||
if mgr.is_broker() {
|
||||
// Yep, broker. Just loop here.
|
||||
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
|
||||
mgr.broker_loop().unwrap();
|
||||
} else {
|
||||
// we are one of the fuzzing instances. Let's launch the fuzzer.
|
||||
|
||||
// First, store the mgr to an env so the client can use it
|
||||
mgr.to_env(ENV_FUZZER_BROKER_CLIENT);
|
||||
|
||||
// First, create a channel from the fuzzer (sender) to us (receiver) to report its state for restarts.
|
||||
let sender = LlmpSender::new(0, false).unwrap();
|
||||
let mut receiver = LlmpReceiver::on_existing_map(
|
||||
AflShmem::clone_ref(&sender.out_maps.last().unwrap().shmem).unwrap(),
|
||||
None,
|
||||
)
|
||||
.unwrap();
|
||||
// Store the information to a map.
|
||||
sender.to_env(ENV_FUZZER_PARENT_SENDER).unwrap();
|
||||
|
||||
loop {
|
||||
dbg!("Spawning next client");
|
||||
Command::new(env::current_exe().unwrap())
|
||||
.current_dir(env::current_dir().unwrap())
|
||||
.args(env::args())
|
||||
.status()
|
||||
.unwrap();
|
||||
|
||||
match receiver.recv_buf().unwrap() {
|
||||
None => panic!("Fuzzer process exited without giving us its result."),
|
||||
Some((sender, tag, msg)) => {
|
||||
todo!("Restore this: {}, {}, {:?}", sender, tag, msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
println!("We're a client, let's fuzz :)");
|
||||
|
||||
// We are the fuzzing instance
|
||||
mgr = LlmpEventManager::existing_client_from_env_std(ENV_FUZZER_BROKER_CLIENT, stats).unwrap();
|
||||
let channel_sender =
|
||||
LlmpSender::<AflShmem>::on_existing_from_env(ENV_FUZZER_PARENT_SENDER).unwrap();
|
||||
|
||||
let edges_observer =
|
||||
StdMapObserver::new_from_ptr(&NAME_COV_MAP, unsafe { __lafl_edges_map }, unsafe {
|
||||
__lafl_max_edges_size as usize
|
||||
@ -168,6 +215,4 @@ pub fn main() {
|
||||
fuzzer
|
||||
.fuzz_loop(&mut rand, &mut state, &mut corpus, &mut engine, &mut mgr)
|
||||
.expect("Fuzzer fatal error");
|
||||
#[cfg(feature = "std")]
|
||||
println!("OK");
|
||||
}
|
||||
|
@ -3,12 +3,12 @@
|
||||
cargo build --release || exit 1
|
||||
cp ./target/release/libfuzzer ./.libfuzzer_test.elf
|
||||
|
||||
RUST_BACKTRACE=1 taskset -c 0 ./.libfuzzer_test.elf &
|
||||
RUST_BACKTRACE=full taskset -c 0 ./.libfuzzer_test.elf &
|
||||
|
||||
test "$!" -gt 0 && {
|
||||
|
||||
usleep 250
|
||||
RUST_BACKTRACE=1 taskset -c 1 ./.libfuzzer_test.elf &
|
||||
RUST_BACKTRACE=full taskset -c 1 ./.libfuzzer_test.elf &
|
||||
|
||||
}
|
||||
|
||||
|
@ -3,12 +3,12 @@
|
||||
cargo build --release || exit 1
|
||||
cp ./target/release/libfuzzer ./.libfuzzer_test.elf
|
||||
|
||||
RUST_BACKTRACE=1 taskset -c 0 ./.libfuzzer_test.elf &
|
||||
RUST_BACKTRACE=full taskset -c 0 ./.libfuzzer_test.elf &
|
||||
|
||||
test "$!" -gt 0 && {
|
||||
|
||||
usleep 250
|
||||
RUST_BACKTRACE=1 taskset -c 1 ./.libfuzzer_test.elf -x a -x b -T5 in1 in2 &
|
||||
RUST_BACKTRACE=full taskset -c 1 ./.libfuzzer_test.elf -x a -x b -T5 in1 in2 &
|
||||
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user