working edges feedback
This commit is contained in:
parent
d4e3668c48
commit
a88f3d6dd2
@ -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"):
|
||||
|
@ -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);
|
||||
|
||||
|
@ -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);
|
||||
|
@ -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
|
||||
}
|
||||
|
||||
|
@ -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>;
|
||||
|
@ -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))
|
||||
}
|
||||
}
|
||||
|
Loading…
x
Reference in New Issue
Block a user