working edges feedback
This commit is contained in:
parent
d4e3668c48
commit
a88f3d6dd2
@ -32,6 +32,8 @@ def cc_mode():
|
|||||||
args = common_opts()
|
args = common_opts()
|
||||||
args += sys.argv[1:]
|
args += sys.argv[1:]
|
||||||
|
|
||||||
|
args += ["-fsanitize-coverage=trace-pc-guard,trace-cmp"]
|
||||||
|
|
||||||
if os.getenv("AFL_USE_ASAN"):
|
if os.getenv("AFL_USE_ASAN"):
|
||||||
args += ["-fsanitize=address"]
|
args += ["-fsanitize=address"]
|
||||||
if os.getenv("AFL_USE_MSAN"):
|
if os.getenv("AFL_USE_MSAN"):
|
||||||
@ -54,6 +56,8 @@ def ld_mode():
|
|||||||
os.path.join(script_dir, "target", "release", "liblibfuzzer.a"),
|
os.path.join(script_dir, "target", "release", "liblibfuzzer.a"),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
args += ["-fsanitize-coverage=trace-pc-guard,trace-cmp"]
|
||||||
|
|
||||||
if os.getenv("AFL_USE_ASAN"):
|
if os.getenv("AFL_USE_ASAN"):
|
||||||
args += ["-fsanitize=address"]
|
args += ["-fsanitize=address"]
|
||||||
if os.getenv("AFL_USE_MSAN"):
|
if os.getenv("AFL_USE_MSAN"):
|
||||||
|
@ -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);
|
__attribute__((weak)) int LLVMFuzzerInitialize(int *argc, char ***argv);
|
||||||
|
|
||||||
|
@ -1,17 +1,28 @@
|
|||||||
use std::boxed::Box;
|
use std::boxed::Box;
|
||||||
|
use std::cell::RefCell;
|
||||||
|
use std::rc::Rc;
|
||||||
|
|
||||||
use afl::corpus::{Corpus, InMemoryCorpus, Testcase};
|
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::inmemory::InMemoryExecutor;
|
||||||
use afl::executors::{Executor, ExitKind};
|
use afl::executors::{Executor, ExitKind};
|
||||||
|
use afl::feedbacks::{create_history_map, MaxMapFeedback};
|
||||||
use afl::inputs::bytes::BytesInput;
|
use afl::inputs::bytes::BytesInput;
|
||||||
use afl::mutators::scheduled::{mutation_bitflip, ComposedByMutations, DefaultScheduledMutator};
|
use afl::mutators::scheduled::{mutation_bitflip, ComposedByMutations, DefaultScheduledMutator};
|
||||||
|
use afl::observers::DefaultMapObserver;
|
||||||
use afl::stages::mutational::DefaultMutationalStage;
|
use afl::stages::mutational::DefaultMutationalStage;
|
||||||
use afl::utils::DefaultRand;
|
use afl::utils::DefaultRand;
|
||||||
|
|
||||||
|
const MAP_SIZE: usize = 65536;
|
||||||
|
|
||||||
|
#[no_mangle]
|
||||||
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;
|
||||||
|
|
||||||
|
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 {
|
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();
|
let testcase = Testcase::new(vec![0; 4]).into();
|
||||||
corpus.add(testcase);
|
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 executor = InMemoryExecutor::<BytesInput>::new(harness);
|
||||||
let mut state = DefaultState::new(corpus, executor);
|
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 engine = DefaultEngine::new();
|
||||||
let mut mutator = DefaultScheduledMutator::new(&rand);
|
let mut mutator = DefaultScheduledMutator::new(&rand);
|
||||||
|
@ -20,29 +20,29 @@ where
|
|||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
/// Get the linked observers
|
/// Get the linked observers
|
||||||
fn observers(&self) -> &[Box<dyn Observer>];
|
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>];
|
||||||
|
|
||||||
/// Get the linked observers
|
/// 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
|
/// 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);
|
self.observers_mut().push(observer);
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reset the state of all the observes linked to this executor
|
/// Reset the state of all the observes linked to this executor
|
||||||
fn reset_observers(&mut self) -> Result<(), AflError> {
|
fn reset_observers(&mut self) -> Result<(), AflError> {
|
||||||
for observer in self.observers_mut() {
|
for observer in self.observers() {
|
||||||
observer.reset()?;
|
observer.borrow_mut().reset()?;
|
||||||
}
|
}
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Run the post exec hook for all the observes linked to this executor
|
/// Run the post exec hook for all the observes linked to this executor
|
||||||
fn post_exec_observers(&mut self) -> Result<(), AflError> {
|
fn post_exec_observers(&mut self) -> Result<(), AflError> {
|
||||||
self.observers_mut()
|
self.observers()
|
||||||
.iter_mut()
|
.iter()
|
||||||
.map(|x| x.post_exec())
|
.map(|x| x.borrow_mut().post_exec())
|
||||||
.fold(Ok(()), |acc, x| if x.is_err() { x } else { acc })
|
.fold(Ok(()), |acc, x| if x.is_err() { x } else { acc })
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -101,7 +101,7 @@ where
|
|||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
observers: Vec<Box<dyn Observer>>,
|
observers: Vec<Rc<RefCell<dyn Observer>>>,
|
||||||
feedbacks: Vec<Box<dyn Feedback<I>>>,
|
feedbacks: Vec<Box<dyn Feedback<I>>>,
|
||||||
corpus: C,
|
corpus: C,
|
||||||
executor: E,
|
executor: E,
|
||||||
@ -113,11 +113,11 @@ where
|
|||||||
E: Executor<I>,
|
E: Executor<I>,
|
||||||
I: Input,
|
I: Input,
|
||||||
{
|
{
|
||||||
fn observers(&self) -> &[Box<dyn Observer>] {
|
fn observers(&self) -> &[Rc<RefCell<dyn Observer>>] {
|
||||||
&self.observers
|
&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
|
&mut self.observers
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -78,21 +78,21 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// The most common AFL-like feedback type
|
/// The most common AFL-like feedback type
|
||||||
pub struct MapFeedback<'a, T, R, O>
|
pub struct MapFeedback<T, R, O>
|
||||||
where
|
where
|
||||||
T: Integer + Copy + 'static,
|
T: Integer + Copy + 'static,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
O: MapObserver<T>,
|
O: MapObserver<T>,
|
||||||
{
|
{
|
||||||
/// Contains information about untouched entries
|
/// Contains information about untouched entries
|
||||||
history_map: &'a RefCell<Vec<T>>,
|
history_map: Rc<RefCell<Vec<T>>>,
|
||||||
/// The observer this feedback struct observes
|
/// The observer this feedback struct observes
|
||||||
map_observer: &'a RefCell<O>,
|
map_observer: Rc<RefCell<O>>,
|
||||||
/// Phantom Data of Reducer
|
/// Phantom Data of Reducer
|
||||||
phantom: PhantomData<R>,
|
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
|
where
|
||||||
T: Integer + Copy + 'static,
|
T: Integer + Copy + 'static,
|
||||||
R: Reducer<T>,
|
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
|
where
|
||||||
T: Integer + Copy + 'static,
|
T: Integer + Copy + 'static,
|
||||||
R: Reducer<T>,
|
R: Reducer<T>,
|
||||||
@ -130,7 +130,7 @@ 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: &'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 {
|
MapFeedback {
|
||||||
map_observer: map_observer,
|
map_observer: map_observer,
|
||||||
history_map: history_map,
|
history_map: history_map,
|
||||||
@ -140,14 +140,14 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Returns a usable history map of the given size
|
/// 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
|
where
|
||||||
T: Default + Clone,
|
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 MaxMapFeedback<T, O> = MapFeedback<T, MaxReducer<T>, O>;
|
||||||
pub type MinMapFeedback<'a, T, O> = MapFeedback<'a, T, MinReducer<T>, O>;
|
pub type MinMapFeedback<T, O> = MapFeedback<T, MinReducer<T>, O>;
|
||||||
|
@ -1,5 +1,7 @@
|
|||||||
extern crate num;
|
extern crate num;
|
||||||
|
|
||||||
|
use alloc::rc::Rc;
|
||||||
|
use core::cell::RefCell;
|
||||||
use core::slice::from_raw_parts_mut;
|
use core::slice::from_raw_parts_mut;
|
||||||
use num::Integer;
|
use num::Integer;
|
||||||
|
|
||||||
@ -57,13 +59,19 @@ where
|
|||||||
initial: T,
|
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> {
|
fn reset(&mut self) -> Result<(), AflError> {
|
||||||
self.reset_map()
|
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] {
|
fn map(&self) -> &[T] {
|
||||||
&self.map
|
&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
|
/// Creates a new MapObserver
|
||||||
pub fn new(map: &'a mut [T]) -> Self {
|
pub fn new(map: &'a mut [T]) -> Self {
|
||||||
let initial = if map.len() > 0 { map[0] } else { T::zero() };
|
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))
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Loading…
x
Reference in New Issue
Block a user