tracker map feedback

This commit is contained in:
Andrea Fioraldi 2020-11-23 16:47:40 +01:00
parent 42257f3ffb
commit acee52ddfb
5 changed files with 223 additions and 27 deletions

9
README.md Normal file
View File

@ -0,0 +1,9 @@
How to perf:
```
perf record -e task-clock ./PROGRAM
perf report --stdio --dsos=PROGRAM
rm perf.data
```

View File

@ -126,7 +126,7 @@ where
fitness += feedback.is_interesting(&input)?; fitness += feedback.is_interesting(&input)?;
} }
if fitness >= 25 { if fitness > 0 {
let testcase: Rc<RefCell<_>> = Testcase::new(input).into(); let testcase: Rc<RefCell<_>> = Testcase::new(input).into();
for feedback in self.feedbacks_mut() { for feedback in self.feedbacks_mut() {
feedback.append_metadata(testcase.clone())?; feedback.append_metadata(testcase.clone())?;

View File

@ -6,7 +6,7 @@ use core::cell::RefCell;
use core::marker::PhantomData; use core::marker::PhantomData;
use num::Integer; use num::Integer;
use crate::corpus::Testcase; use crate::corpus::{Testcase, TestcaseMetadata};
use crate::inputs::Input; use crate::inputs::Input;
use crate::observers::MapObserver; use crate::observers::MapObserver;
use crate::AflError; use crate::AflError;
@ -77,6 +77,16 @@ where
} }
} }
/// Returns a usable history map of the given size
pub fn create_history_map<T>(map_size: usize) -> Rc<RefCell<Vec<T>>>
where
T: Default + Clone,
{
{
Rc::new(RefCell::new(vec![T::default(); map_size]))
}
}
/// The most common AFL-like feedback type /// The most common AFL-like feedback type
pub struct MapFeedback<T, R, O> pub struct MapFeedback<T, R, O>
where where
@ -102,26 +112,40 @@ where
fn is_interesting(&mut self, _input: &I) -> Result<u32, AflError> { fn is_interesting(&mut self, _input: &I) -> Result<u32, AflError> {
let mut interesting = 0; let mut interesting = 0;
// TODO: impl. correctly, optimize // TODO optimize
for (history, map) in self let size = self.map_observer.borrow().map().len();
.history_map let mut history_map = self.history_map.borrow_mut();
.borrow_mut() let observer = self.map_observer.borrow();
.iter_mut() for i in 0..size {
.zip(self.map_observer.borrow().map().iter()) let history = history_map[i];
{ let item = observer.map()[i];
let reduced = R::reduce(*history, *map); let reduced = R::reduce(history, item);
if *history != reduced { if history != reduced {
*history = reduced; history_map[i] = reduced;
interesting += 25; interesting += 1;
if interesting >= 250 {
return Ok(255);
}
} }
} }
Ok(interesting) Ok(interesting)
} }
} }
impl<T, R, O> MapFeedback<T, R, O>
where
T: Integer + Copy + Default + 'static,
R: Reducer<T>,
O: MapObserver<T>,
{
/// Create new MapFeedback using a map observer
pub fn new(map_observer: Rc<RefCell<O>>, map_size: usize) -> Self {
MapFeedback {
map_observer: map_observer,
history_map: create_history_map::<T>(map_size),
phantom: PhantomData,
}
}
}
impl<T, R, O> MapFeedback<T, R, O> impl<T, R, O> MapFeedback<T, R, O>
where where
T: Integer + Copy + 'static, T: Integer + Copy + 'static,
@ -130,7 +154,10 @@ where
{ {
/// Create new MapFeedback using a map observer, and a map. /// Create new MapFeedback using a map observer, and a map.
/// The map can be shared. /// The map can be shared.
pub fn new(map_observer: Rc<RefCell<O>>, history_map: Rc<RefCell<Vec<T>>>) -> Self { pub fn with_history_map(
map_observer: Rc<RefCell<O>>,
history_map: Rc<RefCell<Vec<T>>>,
) -> Self {
MapFeedback { MapFeedback {
map_observer: map_observer, map_observer: map_observer,
history_map: history_map, history_map: history_map,
@ -139,15 +166,126 @@ where
} }
} }
/// Returns a usable history map of the given size pub struct MapNoveltiesMetadata {
pub fn create_history_map<T>(map_size: usize) -> Rc<RefCell<Vec<T>>> novelties: Vec<usize>,
}
impl TestcaseMetadata for MapNoveltiesMetadata {
fn name(&self) -> &'static str {
"MapNoveltiesMetadata"
}
}
impl MapNoveltiesMetadata {
pub fn novelties(&self) -> &[usize] {
&self.novelties
}
pub fn new(novelties: Vec<usize>) -> Self {
MapNoveltiesMetadata {
novelties: novelties,
}
}
}
/// The most common AFL-like feedback type that adds metadata about newly discovered entries
pub struct MapTrackerFeedback<T, R, O>
where where
T: Default + Clone, T: Integer + Copy + 'static,
R: Reducer<T>,
O: MapObserver<T>,
{ {
{ /// Contains information about untouched entries
Rc::new(RefCell::new(vec![T::default(); map_size])) history_map: Rc<RefCell<Vec<T>>>,
/// The observer this feedback struct observes
map_observer: Rc<RefCell<O>>,
/// Phantom Data of Reducer
phantom: PhantomData<R>,
/// Track novel entries indexes
novelties: Vec<usize>,
}
impl<T, R, O, I> Feedback<I> for MapTrackerFeedback<T, R, O>
where
T: Integer + Copy + 'static,
R: Reducer<T>,
O: MapObserver<T>,
I: Input,
{
fn is_interesting(&mut self, _input: &I) -> Result<u32, AflError> {
let mut interesting = 0;
// TODO optimize
let size = self.map_observer.borrow().map().len();
let mut history_map = self.history_map.borrow_mut();
let observer = self.map_observer.borrow();
for i in 0..size {
let history = history_map[i];
let item = observer.map()[i];
let reduced = R::reduce(history, item);
if history != reduced {
history_map[i] = reduced;
interesting += 1;
self.novelties.push(i);
}
}
Ok(interesting)
}
fn append_metadata(&mut self, testcase: Rc<RefCell<Testcase<I>>>) -> Result<(), AflError> {
let meta = Box::new(MapNoveltiesMetadata::new(core::mem::take(
&mut self.novelties,
)));
testcase.borrow_mut().add_metadata(meta);
Ok(())
}
/// Discard the stored metadata in case that the testcase is not added to the corpus
fn discard_metadata(&mut self) -> Result<(), AflError> {
self.novelties.clear();
Ok(())
}
}
impl<T, R, O> MapTrackerFeedback<T, R, O>
where
T: Integer + Copy + Default + 'static,
R: Reducer<T>,
O: MapObserver<T>,
{
/// Create new MapFeedback using a map observer
pub fn new(map_observer: Rc<RefCell<O>>, map_size: usize) -> Self {
MapTrackerFeedback {
map_observer: map_observer,
history_map: create_history_map::<T>(map_size),
phantom: PhantomData,
novelties: vec![],
}
}
}
impl<T, R, O> MapTrackerFeedback<T, R, O>
where
T: Integer + Copy + 'static,
R: Reducer<T>,
O: MapObserver<T>,
{
/// Create new MapFeedback using a map observer, and a map.
/// The map can be shared.
pub fn with_history_map(
map_observer: Rc<RefCell<O>>,
history_map: Rc<RefCell<Vec<T>>>,
) -> Self {
MapTrackerFeedback {
map_observer: map_observer,
history_map: history_map,
phantom: PhantomData,
novelties: vec![],
}
} }
} }
pub type MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>; pub type MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>; pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
pub type MaxMapTrackerFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
pub type MinMapTrackerFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;

View File

@ -175,7 +175,7 @@ pub struct XorShift64Rand {
impl Rand for XorShift64Rand { impl Rand for XorShift64Rand {
fn set_seed(&mut self, seed: u64) { fn set_seed(&mut self, seed: u64) {
self.rand_seed = seed; self.rand_seed = seed ^ 0x1234567890abcdef;
self.seeded = true; self.seeded = true;
} }
@ -219,6 +219,56 @@ impl XorShift64Rand {
} }
} }
/// XXH3 Based, hopefully speedy, rnd implementation
///
#[derive(Copy, Clone, Debug, Default)]
pub struct Lehmer64Rand {
rand_seed: u128,
seeded: bool,
}
impl Rand for Lehmer64Rand {
fn set_seed(&mut self, seed: u64) {
self.rand_seed = (seed as u128) ^ 0x1234567890abcdef;
self.seeded = true;
}
fn next(&mut self) -> u64 {
self.rand_seed *= 0xda942042e4dd58b5;
return (self.rand_seed >> 64) as u64;
}
}
impl Into<Rc<RefCell<Self>>> for Lehmer64Rand {
fn into(self) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(self))
}
}
impl Lehmer64Rand {
/// Creates a new Xoshiro rand with the given seed
pub fn new(seed: u64) -> Self {
let mut ret: Self = Default::default();
ret.set_seed(seed); // TODO: Proper random seed?
ret
}
pub fn to_rc_refcell(self) -> Rc<RefCell<Self>> {
self.into()
}
/// Creates a rand instance, pre-seeded with the current time in nanoseconds.
/// Needs stdlib timer
#[cfg(feature = "std")]
pub fn preseeded() -> Self {
let seed = SystemTime::now()
.duration_since(UNIX_EPOCH)
.unwrap()
.as_nanos() as u64;
Self::new(seed)
}
}
#[cfg(feature = "std")] #[cfg(feature = "std")]
pub fn current_milliseconds() -> u64 { pub fn current_milliseconds() -> u64 {
SystemTime::now() SystemTime::now()

View File

@ -8,7 +8,7 @@ use afl::engines::{generate_initial_inputs, Engine, State, StdEngine, StdState};
use afl::events::LoggerEventManager; use afl::events::LoggerEventManager;
use afl::executors::inmemory::InMemoryExecutor; use afl::executors::inmemory::InMemoryExecutor;
use afl::executors::{Executor, ExitKind}; use afl::executors::{Executor, ExitKind};
use afl::feedbacks::{create_history_map, MaxMapFeedback}; use afl::feedbacks::MaxMapTrackerFeedback;
use afl::generators::RandPrintablesGenerator; use afl::generators::RandPrintablesGenerator;
use afl::mutators::scheduled::HavocBytesMutator; use afl::mutators::scheduled::HavocBytesMutator;
use afl::observers::StdMapObserver; use afl::observers::StdMapObserver;
@ -39,15 +39,14 @@ pub extern "C" fn afl_libfuzzer_main() {
let mut rand = StdRand::new(0); let mut rand = StdRand::new(0);
let corpus = InMemoryCorpus::new(); let corpus = InMemoryCorpus::new();
let mut generator = RandPrintablesGenerator::new(1); let mut generator = RandPrintablesGenerator::new(32);
let mut events = LoggerEventManager::new(stderr()); let mut events = LoggerEventManager::new(stderr());
let edges_observer = Rc::new(RefCell::new(StdMapObserver::new_from_ptr( let edges_observer = Rc::new(RefCell::new(StdMapObserver::new_from_ptr(
unsafe { __lafl_edges_map }, unsafe { __lafl_edges_map },
unsafe { __lafl_max_edges_size as usize }, unsafe { __lafl_max_edges_size as usize },
))); )));
let edges_history_map = create_history_map::<u8>(MAP_SIZE); let edges_feedback = MaxMapTrackerFeedback::new(edges_observer.clone(), MAP_SIZE);
let edges_feedback = MaxMapFeedback::new(edges_observer.clone(), edges_history_map);
let executor = InMemoryExecutor::new(harness); let executor = InMemoryExecutor::new(harness);
let mut state = StdState::new(corpus, executor); let mut state = StdState::new(corpus, executor);