first steps towards respawning
This commit is contained in:
parent
669cb1c96b
commit
27a68fa30d
@ -400,6 +400,19 @@ impl<SH> LlmpSender<SH>
|
|||||||
where
|
where
|
||||||
SH: ShMem,
|
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.
|
/// Reattach to a vacant out_map, to with a previous sender stored the information in an env before.
|
||||||
#[cfg(feature = "std")]
|
#[cfg(feature = "std")]
|
||||||
pub fn on_existing_from_env(env_name: &str) -> Result<Self, AflError> {
|
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]
|
#[inline]
|
||||||
pub fn recv_buf_blocking(&mut self) -> Result<(u32, u32, &[u8]), AflError> {
|
pub fn recv_buf_blocking(&mut self) -> Result<(u32, u32, &[u8]), AflError> {
|
||||||
unsafe {
|
unsafe {
|
||||||
@ -912,7 +925,7 @@ where
|
|||||||
{
|
{
|
||||||
/// Shmem containg the actual (unsafe) page,
|
/// Shmem containg the actual (unsafe) page,
|
||||||
/// shared between one LlmpSender and one LlmpReceiver
|
/// shared between one LlmpSender and one LlmpReceiver
|
||||||
shmem: SH,
|
pub shmem: SH,
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: May be obsolete
|
// TODO: May be obsolete
|
||||||
|
@ -118,7 +118,7 @@ pub trait Stats {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
#[derive(Debug)]
|
#[derive(Clone, Debug)]
|
||||||
pub struct SimpleStats<F>
|
pub struct SimpleStats<F>
|
||||||
where
|
where
|
||||||
F: FnMut(String),
|
F: FnMut(String),
|
||||||
@ -743,6 +743,12 @@ where
|
|||||||
phantom: PhantomData,
|
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>
|
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
|
/// A client on an existing map
|
||||||
pub fn for_client(client: LlmpClient<SH>, stats: ST) -> Self {
|
pub fn for_client(client: LlmpClient<SH>, stats: ST) -> Self {
|
||||||
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
|
/// Returns if we are the broker
|
||||||
pub fn is_broker(&self) -> bool {
|
pub fn is_broker(&self) -> bool {
|
||||||
match self.llmp {
|
match self.llmp {
|
||||||
|
@ -60,6 +60,14 @@ struct shmid_ds {
|
|||||||
|
|
||||||
/// A Shared map
|
/// A Shared map
|
||||||
pub trait ShMem: Sized + Debug {
|
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.
|
/// 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)
|
fn existing_from_shm_slice(map_str_bytes: &[u8; 20], map_size: usize)
|
||||||
-> Result<Self, AflError>;
|
-> Result<Self, AflError>;
|
||||||
@ -73,9 +81,6 @@ pub trait ShMem: Sized + Debug {
|
|||||||
Self::existing_from_shm_slice(&slice, map_size)
|
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
|
/// The string to identify this shm
|
||||||
fn shm_str(&self) -> String {
|
fn shm_str(&self) -> String {
|
||||||
let bytes = self.shm_slice();
|
let bytes = self.shm_slice();
|
||||||
|
@ -20,9 +20,16 @@ where
|
|||||||
I: Input + HasTargetBytes,
|
I: Input + HasTargetBytes,
|
||||||
OT: ObserversTuple,
|
OT: ObserversTuple,
|
||||||
{
|
{
|
||||||
harness: HarnessFunction<I>,
|
/// The name of this executor instance, to address it from other components
|
||||||
observers: OT,
|
|
||||||
name: &'static str,
|
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>
|
impl<I, OT> Executor<I> for InMemoryExecutor<I, OT>
|
||||||
@ -75,11 +82,22 @@ where
|
|||||||
I: Input + HasTargetBytes,
|
I: Input + HasTargetBytes,
|
||||||
OT: ObserversTuple,
|
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 {
|
Self {
|
||||||
harness: harness_fn,
|
harness: harness_fn,
|
||||||
observers: observers,
|
//on_crash_fn,
|
||||||
name: name,
|
observers,
|
||||||
|
name,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,31 +1,37 @@
|
|||||||
#![cfg_attr(not(feature = "std"), no_std)]
|
|
||||||
|
|
||||||
#[macro_use]
|
#[macro_use]
|
||||||
extern crate clap;
|
extern crate clap;
|
||||||
extern crate alloc;
|
|
||||||
|
|
||||||
use clap::{App, Arg};
|
use clap::{App, Arg};
|
||||||
use std::env;
|
use std::{env, path::PathBuf, process::Command};
|
||||||
use std::path::PathBuf;
|
|
||||||
|
|
||||||
use afl::corpus::Corpus;
|
use afl::{
|
||||||
use afl::corpus::InMemoryCorpus;
|
corpus::{Corpus, InMemoryCorpus},
|
||||||
use afl::engines::Engine;
|
engines::{Engine, Fuzzer, State, StdFuzzer},
|
||||||
use afl::engines::Fuzzer;
|
events::{
|
||||||
use afl::engines::State;
|
llmp::LlmpReceiver,
|
||||||
use afl::engines::StdFuzzer;
|
llmp::LlmpSender,
|
||||||
use afl::events::{LlmpEventManager, SimpleStats};
|
shmem::{AflShmem, ShMem},
|
||||||
use afl::executors::inmemory::InMemoryExecutor;
|
LlmpEventManager, SimpleStats,
|
||||||
use afl::executors::{Executor, ExitKind};
|
},
|
||||||
use afl::feedbacks::MaxMapFeedback;
|
executors::{inmemory::InMemoryExecutor, Executor, ExitKind},
|
||||||
use afl::generators::RandPrintablesGenerator;
|
feedbacks::MaxMapFeedback,
|
||||||
use afl::mutators::scheduled::HavocBytesMutator;
|
generators::RandPrintablesGenerator,
|
||||||
use afl::mutators::HasMaxSize;
|
mutators::{scheduled::HavocBytesMutator, HasMaxSize},
|
||||||
use afl::observers::StdMapObserver;
|
observers::StdMapObserver,
|
||||||
use afl::stages::mutational::StdMutationalStage;
|
stages::mutational::StdMutationalStage,
|
||||||
use afl::tuples::tuple_list;
|
tuples::tuple_list,
|
||||||
use afl::utils::StdRand;
|
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" {
|
extern "C" {
|
||||||
/// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
|
/// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
|
||||||
fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32;
|
fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32;
|
||||||
@ -38,6 +44,7 @@ extern "C" {
|
|||||||
static __lafl_max_edges_size: u32;
|
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 {
|
fn harness<I>(_executor: &dyn Executor<I>, buf: &[u8]) -> ExitKind {
|
||||||
unsafe {
|
unsafe {
|
||||||
LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len());
|
LLVMFuzzerTestOneInput(buf.as_ptr(), buf.len());
|
||||||
@ -45,8 +52,6 @@ fn harness<I>(_executor: &dyn Executor<I>, buf: &[u8]) -> ExitKind {
|
|||||||
ExitKind::Ok
|
ExitKind::Ok
|
||||||
}
|
}
|
||||||
|
|
||||||
const NAME_COV_MAP: &str = "cov_map";
|
|
||||||
|
|
||||||
pub fn main() {
|
pub fn main() {
|
||||||
let matches = App::new("libAFLrs fuzzer harness")
|
let matches = App::new("libAFLrs fuzzer harness")
|
||||||
.about("libAFLrs fuzzer harness help options.")
|
.about("libAFLrs fuzzer harness help options.")
|
||||||
@ -109,15 +114,57 @@ pub fn main() {
|
|||||||
let mut corpus = InMemoryCorpus::new();
|
let mut corpus = InMemoryCorpus::new();
|
||||||
let mut generator = RandPrintablesGenerator::new(32);
|
let mut generator = RandPrintablesGenerator::new(32);
|
||||||
let stats = SimpleStats::new(|s| println!("{}", s));
|
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() {
|
// We start ourself as child process to actually fuzz
|
||||||
println!("Doing broker things. Run this tool again to start fuzzing in a client.");
|
if std::env::var(ENV_FUZZER_PARENT_SENDER).is_err() {
|
||||||
mgr.broker_loop().unwrap();
|
// 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 :)");
|
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 =
|
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
|
||||||
@ -168,6 +215,4 @@ pub fn main() {
|
|||||||
fuzzer
|
fuzzer
|
||||||
.fuzz_loop(&mut rand, &mut state, &mut corpus, &mut engine, &mut mgr)
|
.fuzz_loop(&mut rand, &mut state, &mut corpus, &mut engine, &mut mgr)
|
||||||
.expect("Fuzzer fatal error");
|
.expect("Fuzzer fatal error");
|
||||||
#[cfg(feature = "std")]
|
|
||||||
println!("OK");
|
|
||||||
}
|
}
|
||||||
|
@ -3,12 +3,12 @@
|
|||||||
cargo build --release || exit 1
|
cargo build --release || exit 1
|
||||||
cp ./target/release/libfuzzer ./.libfuzzer_test.elf
|
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 && {
|
test "$!" -gt 0 && {
|
||||||
|
|
||||||
usleep 250
|
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
|
cargo build --release || exit 1
|
||||||
cp ./target/release/libfuzzer ./.libfuzzer_test.elf
|
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 && {
|
test "$!" -gt 0 && {
|
||||||
|
|
||||||
usleep 250
|
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