working edges feedback

This commit is contained in:
Andrea Fioraldi 2020-11-20 15:14:19 +01:00
parent d4e3668c48
commit a88f3d6dd2
6 changed files with 188 additions and 25 deletions

View File

@ -32,6 +32,8 @@ def cc_mode():
args = common_opts()
args += sys.argv[1:]
args += ["-fsanitize-coverage=trace-pc-guard,trace-cmp"]
if os.getenv("AFL_USE_ASAN"):
args += ["-fsanitize=address"]
if os.getenv("AFL_USE_MSAN"):
@ -54,6 +56,8 @@ def ld_mode():
os.path.join(script_dir, "target", "release", "liblibfuzzer.a"),
]
args += ["-fsanitize-coverage=trace-pc-guard,trace-cmp"]
if os.getenv("AFL_USE_ASAN"):
args += ["-fsanitize=address"]
if os.getenv("AFL_USE_MSAN"):

View File

@ -1,4 +1,123 @@
#include <stdint.h>
#define MAP_SIZE 65536
uint8_t __lafl_dummy_map[MAP_SIZE];
uint8_t *__lafl_edges_map = __lafl_dummy_map;
uint8_t *__lafl_cmp_map = __lafl_dummy_map;
uint32_t __lafl_max_edges_size = 0;
void __sanitizer_cov_trace_pc_guard(uint32_t *guard) {
__lafl_edges_map[*guard]++;
}
void __sanitizer_cov_trace_pc_guard_init(uint32_t *start, uint32_t *stop) {
if (start == stop || *start) return;
*(start++) = (++__lafl_max_edges_size) & (MAP_SIZE -1);
while (start < stop) {
*start = (++__lafl_max_edges_size) & (MAP_SIZE -1);
start++;
}
}
#define MAX(a, b) \
({ \
\
__typeof__(a) _a = (a); \
__typeof__(b) _b = (b); \
_a > _b ? _a : _b; \
\
})
#if defined(__APPLE__)
#pragma weak __sanitizer_cov_trace_const_cmp1 = __sanitizer_cov_trace_cmp1
#pragma weak __sanitizer_cov_trace_const_cmp2 = __sanitizer_cov_trace_cmp2
#pragma weak __sanitizer_cov_trace_const_cmp4 = __sanitizer_cov_trace_cmp4
#pragma weak __sanitizer_cov_trace_const_cmp8 = __sanitizer_cov_trace_cmp8
#else
void __sanitizer_cov_trace_const_cmp1(uint8_t arg1, uint8_t arg2) __attribute__((alias("__sanitizer_cov_trace_cmp1")));
void __sanitizer_cov_trace_const_cmp2(uint16_t arg1, uint16_t arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp2")));
void __sanitizer_cov_trace_const_cmp4(uint32_t arg1, uint32_t arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp4")));
void __sanitizer_cov_trace_const_cmp8(uint64_t arg1, uint64_t arg2)
__attribute__((alias("__sanitizer_cov_trace_cmp8")));
#endif
void __sanitizer_cov_trace_cmp1(uint8_t arg1, uint8_t arg2) {
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
}
void __sanitizer_cov_trace_cmp2(uint16_t arg1, uint16_t arg2) {
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
}
void __sanitizer_cov_trace_cmp4(uint32_t arg1, uint32_t arg2) {
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcount(~(arg1 ^ arg2))));
}
void __sanitizer_cov_trace_cmp8(uint64_t arg1, uint64_t arg2) {
uintptr_t k = (uintptr_t)__builtin_return_address(0);
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcountll(~(arg1 ^ arg2))));
}
void __sanitizer_cov_trace_switch(uint64_t val, uint64_t *cases) {
uintptr_t rt = (uintptr_t)__builtin_return_address(0);
if (cases[1] == 64) {
for (uint64_t i = 0; i < cases[0]; i++) {
uintptr_t k = rt + i;
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcountll(~(val ^ cases[i + 2]))));
}
} else {
for (uint64_t i = 0; i < cases[0]; i++) {
uintptr_t k = rt + i;
k = (k >> 4) ^ (k << 8);
k &= MAP_SIZE - 1;
__lafl_cmp_map[k] = MAX(__lafl_cmp_map[k], (__builtin_popcount(~(val ^ cases[i + 2]))));
}
}
}
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);

View File

@ -1,17 +1,28 @@
use std::boxed::Box;
use std::cell::RefCell;
use std::rc::Rc;
use afl::corpus::{Corpus, InMemoryCorpus, Testcase};
use afl::engines::{DefaultEngine, DefaultState, Engine};
use afl::engines::{DefaultEngine, DefaultState, Engine, State};
use afl::executors::inmemory::InMemoryExecutor;
use afl::executors::{Executor, ExitKind};
use afl::feedbacks::{create_history_map, MaxMapFeedback};
use afl::inputs::bytes::BytesInput;
use afl::mutators::scheduled::{mutation_bitflip, ComposedByMutations, DefaultScheduledMutator};
use afl::observers::DefaultMapObserver;
use afl::stages::mutational::DefaultMutationalStage;
use afl::utils::DefaultRand;
const MAP_SIZE: usize = 65536;
#[no_mangle]
extern "C" {
/// int LLVMFuzzerTestOneInput(const uint8_t *Data, size_t Size)
fn LLVMFuzzerTestOneInput(data: *const u8, size: usize) -> i32;
static __lafl_edges_map: *mut u8;
static __lafl_cmp_map: *mut u8;
static __lafl_max_edges_size: u32;
}
fn harness<I>(_executor: &dyn Executor<I>, buf: &[u8]) -> ExitKind {
@ -29,8 +40,17 @@ pub extern "C" fn afl_libfuzzer_main() {
let testcase = Testcase::new(vec![0; 4]).into();
corpus.add(testcase);
let edges_observer = Rc::new(RefCell::new(DefaultMapObserver::new_from_ptr(
unsafe { __lafl_edges_map },
unsafe { __lafl_max_edges_size as usize },
)));
let edges_history_map = create_history_map::<u8>(MAP_SIZE);
let edges_feedback = MaxMapFeedback::new(edges_observer.clone(), edges_history_map);
let executor = InMemoryExecutor::<BytesInput>::new(harness);
let mut state = DefaultState::new(corpus, executor);
state.add_observer(edges_observer);
state.add_feedback(Box::new(edges_feedback));
let mut engine = DefaultEngine::new();
let mut mutator = DefaultScheduledMutator::new(&rand);

View File

@ -20,29 +20,29 @@ where
I: Input,
{
/// Get the linked observers
fn observers(&self) -> &[Box<dyn Observer>];
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>];
/// Get the linked observers
fn observers_mut(&mut self) -> &mut Vec<Box<dyn Observer>>;
fn observers_mut(&mut self) -> &mut Vec<Rc<RefCell<dyn Observer>>>;
/// Add a linked observer
fn add_observer(&mut self, observer: Box<dyn Observer>) {
fn add_observer(&mut self, observer: Rc<RefCell<dyn Observer>>) {
self.observers_mut().push(observer);
}
/// Reset the state of all the observes linked to this executor
fn reset_observers(&mut self) -> Result<(), AflError> {
for observer in self.observers_mut() {
observer.reset()?;
for observer in self.observers() {
observer.borrow_mut().reset()?;
}
Ok(())
}
/// Run the post exec hook for all the observes linked to this executor
fn post_exec_observers(&mut self) -> Result<(), AflError> {
self.observers_mut()
.iter_mut()
.map(|x| x.post_exec())
self.observers()
.iter()
.map(|x| x.borrow_mut().post_exec())
.fold(Ok(()), |acc, x| if x.is_err() { x } else { acc })
}
@ -101,7 +101,7 @@ where
E: Executor<I>,
I: Input,
{
observers: Vec<Box<dyn Observer>>,
observers: Vec<Rc<RefCell<dyn Observer>>>,
feedbacks: Vec<Box<dyn Feedback<I>>>,
corpus: C,
executor: E,
@ -113,11 +113,11 @@ where
E: Executor<I>,
I: Input,
{
fn observers(&self) -> &[Box<dyn Observer>] {
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>] {
&self.observers
}
fn observers_mut(&mut self) -> &mut Vec<Box<dyn Observer>> {
fn observers_mut(&mut self) -> &mut Vec<Rc<RefCell<dyn Observer>>> {
&mut self.observers
}

View File

@ -78,21 +78,21 @@ where
}
/// The most common AFL-like feedback type
pub struct MapFeedback<'a, T, R, O>
pub struct MapFeedback<T, R, O>
where
T: Integer + Copy + 'static,
R: Reducer<T>,
O: MapObserver<T>,
{
/// Contains information about untouched entries
history_map: &'a RefCell<Vec<T>>,
history_map: Rc<RefCell<Vec<T>>>,
/// The observer this feedback struct observes
map_observer: &'a RefCell<O>,
map_observer: Rc<RefCell<O>>,
/// Phantom Data of Reducer
phantom: PhantomData<R>,
}
impl<'a, T, R, O, I> Feedback<I> for MapFeedback<'a, T, R, O>
impl<T, R, O, I> Feedback<I> for MapFeedback<T, R, O>
where
T: Integer + Copy + 'static,
R: Reducer<T>,
@ -122,7 +122,7 @@ where
}
}
impl<'a, T, R, O> MapFeedback<'a, T, R, O>
impl<T, R, O> MapFeedback<T, R, O>
where
T: Integer + Copy + 'static,
R: Reducer<T>,
@ -130,7 +130,7 @@ where
{
/// Create new MapFeedback using a map observer, and a map.
/// The map can be shared.
pub fn new(map_observer: &'a RefCell<O>, history_map: &'a RefCell<Vec<T>>) -> Self {
pub fn new(map_observer: Rc<RefCell<O>>, history_map: Rc<RefCell<Vec<T>>>) -> Self {
MapFeedback {
map_observer: map_observer,
history_map: history_map,
@ -140,14 +140,14 @@ where
}
/// Returns a usable history map of the given size
pub fn create_history_map<T>(map_size: usize) -> RefCell<Vec<T>>
pub fn create_history_map<T>(map_size: usize) -> Rc<RefCell<Vec<T>>>
where
T: Default + Clone,
{
{
RefCell::new(vec![T::default(); map_size])
Rc::new(RefCell::new(vec![T::default(); map_size]))
}
}
pub type MaxMapFeedback<'a, T, O> = MapFeedback<'a, T, MaxReducer<T>, O>;
pub type MinMapFeedback<'a, T, O> = MapFeedback<'a, T, MinReducer<T>, O>;
pub type MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;

View File

@ -1,5 +1,7 @@
extern crate num;
use alloc::rc::Rc;
use core::cell::RefCell;
use core::slice::from_raw_parts_mut;
use num::Integer;
@ -57,13 +59,19 @@ where
initial: T,
}
impl<'a, T: Integer + Copy> Observer for DefaultMapObserver<'a, T> {
impl<'a, T> Observer for DefaultMapObserver<'a, T>
where
T: Integer + Copy,
{
fn reset(&mut self) -> Result<(), AflError> {
self.reset_map()
}
}
impl<'a, T: Integer + Copy> MapObserver<T> for DefaultMapObserver<'a, T> {
impl<'a, T> MapObserver<T> for DefaultMapObserver<'a, T>
where
T: Integer + Copy,
{
fn map(&self) -> &[T] {
&self.map
}
@ -85,7 +93,10 @@ impl<'a, T: Integer + Copy> MapObserver<T> for DefaultMapObserver<'a, T> {
}
}
impl<'a, T: Integer + Copy> DefaultMapObserver<'a, T> {
impl<'a, T> DefaultMapObserver<'a, T>
where
T: Integer + Copy,
{
/// Creates a new MapObserver
pub fn new(map: &'a mut [T]) -> Self {
let initial = if map.len() > 0 { map[0] } else { T::zero() };
@ -106,3 +117,12 @@ impl<'a, T: Integer + Copy> DefaultMapObserver<'a, T> {
}
}
}
impl<'a, T> Into<Rc<RefCell<Self>>> for DefaultMapObserver<'a, T>
where
T: Integer + Copy,
{
fn into(self) -> Rc<RefCell<Self>> {
Rc::new(RefCell::new(self))
}
}