Skip to content

Commit

Permalink
improve how libafl_libfuzzer emits solution data, and exit when not i…
Browse files Browse the repository at this point in the history
…gnoring
  • Loading branch information
addisoncrump committed Feb 20, 2023
1 parent 3e62846 commit 566253d
Show file tree
Hide file tree
Showing 7 changed files with 165 additions and 44 deletions.
3 changes: 2 additions & 1 deletion libafl_libfuzzer/libafl_libfuzzer_runtime/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -17,11 +17,12 @@ path = "src/lib.rs"
crate-type = ["staticlib", "rlib"]

[dependencies]
rand = "0.8.5"
libafl = { path = "../../libafl", default-features = false, features = ["std", "derive", "llmp_compression", "rand_trait", "fork", "errors_backtrace"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_8bit", "sancov_cmplog", "libfuzzer", "libfuzzer_oom"] }
libc = "0.2.139"
mimalloc = { version = "0.1.34", default-features = false }
rand = "0.8.5"
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # serialization lib

# for identifying if we can grimoire-ify
utf8-chars = "2.0.3"
Expand Down
111 changes: 109 additions & 2 deletions libafl_libfuzzer/libafl_libfuzzer_runtime/src/feedbacks.rs
Original file line number Diff line number Diff line change
Expand Up @@ -2,9 +2,20 @@ use alloc::rc::Rc;
use core::{cell::RefCell, fmt::Debug};

use libafl::{
alloc, bolts::tuples::Named, events::EventFirer, executors::ExitKind, feedbacks::Feedback,
inputs::UsesInput, observers::ObserversTuple, state::HasClientPerfMonitor, Error,
alloc,
bolts::tuples::Named,
corpus::Testcase,
events::EventFirer,
executors::ExitKind,
feedbacks::Feedback,
impl_serdeany,
inputs::UsesInput,
observers::ObserversTuple,
state::{HasClientPerfMonitor, HasMetadata},
Error,
};
use libafl_targets::OOMFeedback;
use serde::{Deserialize, Serialize};

#[derive(Debug)]
pub struct LibfuzzerKeepFeedback {
Expand Down Expand Up @@ -48,3 +59,99 @@ where
Ok(*self.keep.borrow())
}
}

#[derive(Deserialize, Serialize, Debug)]
pub struct LibfuzzerCrashCauseMetadata {
kind: ExitKind,
}

impl_serdeany!(LibfuzzerCrashCauseMetadata);

impl LibfuzzerCrashCauseMetadata {
pub fn kind(&self) -> ExitKind {
self.kind
}
}

#[derive(Debug)]
pub struct LibfuzzerCrashCauseFeedback {
exit_kind: ExitKind,
}

impl LibfuzzerCrashCauseFeedback {
pub fn new() -> Self {
Self {
exit_kind: ExitKind::Ok,
}
}
}

impl Named for LibfuzzerCrashCauseFeedback {
fn name(&self) -> &str {
"crash-cause"
}
}

impl<S> Feedback<S> for LibfuzzerCrashCauseFeedback
where
S: UsesInput + HasClientPerfMonitor,
{
fn is_interesting<EM, OT>(
&mut self,
_state: &mut S,
_manager: &mut EM,
_input: &S::Input,
_observers: &OT,
exit_kind: &ExitKind,
) -> Result<bool, Error>
where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
self.exit_kind = *exit_kind;
Ok(false)
}

fn append_metadata<OT>(
&mut self,
_state: &mut S,
_observers: &OT,
testcase: &mut Testcase<S::Input>,
) -> Result<(), Error>
where
OT: ObserversTuple<S>,
{
match self.exit_kind {
ExitKind::Crash | ExitKind::Oom if OOMFeedback::oomed() => {
if let Some(filename) = testcase.filename_mut() {
*filename = format!("oom-{}", filename);
}
testcase.metadata_mut().insert(LibfuzzerCrashCauseMetadata {
kind: ExitKind::Oom,
});
}
ExitKind::Crash | ExitKind::Oom => {
if let Some(filename) = testcase.filename_mut() {
*filename = format!("crash-{}", filename);
}
testcase.metadata_mut().insert(LibfuzzerCrashCauseMetadata {
kind: ExitKind::Crash,
});
}
ExitKind::Timeout => {
if let Some(filename) = testcase.filename_mut() {
*filename = format!("timeout-{}", filename);
}
testcase.metadata_mut().insert(LibfuzzerCrashCauseMetadata {
kind: ExitKind::Timeout,
});
}
_ => {
testcase.metadata_mut().insert(LibfuzzerCrashCauseMetadata {
kind: self.exit_kind,
});
}
}
Ok(())
}
}
31 changes: 28 additions & 3 deletions libafl_libfuzzer/libafl_libfuzzer_runtime/src/fuzz.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,17 +7,20 @@ use libafl::{
launcher::Launcher,
shmem::{ShMemProvider, StdShMemProvider},
},
corpus::Corpus,
events::{EventConfig, ProgressReporter, SimpleEventManager, SimpleRestartingEventManager},
executors::ExitKind,
inputs::UsesInput,
monitors::{tui::TuiMonitor, SimpleMonitor},
stages::StagesTuple,
state::{HasClientPerfMonitor, HasExecutions, HasMetadata, UsesState},
state::{HasClientPerfMonitor, HasExecutions, HasMetadata, HasSolutions, UsesState},
Error, Fuzzer,
};

use crate::{fuzz_with, options::LibfuzzerOptions};
use crate::{feedbacks::LibfuzzerCrashCauseMetadata, fuzz_with, options::LibfuzzerOptions};

fn do_fuzz<F, ST, E, S, EM>(
options: &LibfuzzerOptions,
fuzzer: &mut F,
stages: &mut ST,
executor: &mut E,
Expand All @@ -26,11 +29,33 @@ fn do_fuzz<F, ST, E, S, EM>(
) -> Result<(), Error>
where
F: Fuzzer<E, EM, ST, State = S>,
S: HasClientPerfMonitor + HasMetadata + HasExecutions + UsesInput,
S: HasClientPerfMonitor + HasMetadata + HasExecutions + UsesInput + HasSolutions,
E: UsesState<State = S>,
EM: ProgressReporter<State = S>,
ST: StagesTuple<E, EM, S, F>,
{
if let Some(solution) = state.solutions().last() {
let kind = state
.solutions()
.get(solution)
.expect("Last solution was not available")
.borrow()
.metadata()
.get::<LibfuzzerCrashCauseMetadata>()
.expect("Crash cause not attached to solution")
.kind();
let mut halt = false;
match kind {
ExitKind::Oom if !options.ignore_ooms() => halt = true,
ExitKind::Crash if !options.ignore_crashes() => halt = true,
ExitKind::Timeout if !options.ignore_timeouts() => halt = true,
_ => {}
}
if halt {
eprintln!("Halting; the error on the next line is actually okay. :)");
return Err(Error::shutting_down());
}
}
fuzzer.fuzz_loop(stages, executor, state, mgr)?;
Ok(())
}
Expand Down
53 changes: 17 additions & 36 deletions libafl_libfuzzer/libafl_libfuzzer_runtime/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -5,7 +5,6 @@ use libafl::{
inputs::{BytesInput, HasTargetBytes, Input},
Error,
};
use libafl_targets::libafl_cmplog_enabled;

use crate::options::{LibfuzzerMode, LibfuzzerOptions};

Expand Down Expand Up @@ -62,7 +61,7 @@ macro_rules! fuzz_with {
corpus::{CachedOnDiskCorpus, Corpus, OnDiskCorpus},
executors::{ExitKind, InProcessExecutor, TimeoutExecutor},
feedback_and_fast, feedback_not, feedback_or, feedback_or_fast,
feedbacks::{ConstFeedback, CrashFeedback, MaxMapFeedback, NewHashFeedback, TimeFeedback, TimeoutFeedback},
feedbacks::{CrashFeedback, MaxMapFeedback, NewHashFeedback, TimeFeedback, TimeoutFeedback},
generators::RandBytesGenerator,
inputs::{BytesInput, HasTargetBytes},
mutators::{
Expand All @@ -88,7 +87,7 @@ macro_rules! fuzz_with {

use crate::CustomMutationStatus;
use crate::BACKTRACE;
use crate::feedbacks::LibfuzzerKeepFeedback;
use crate::feedbacks::{LibfuzzerCrashCauseFeedback, LibfuzzerKeepFeedback};

let edge_maker = &$edge_maker;

Expand Down Expand Up @@ -137,10 +136,6 @@ macro_rules! fuzz_with {

let edges_observer = edge_maker();

let crashes = $options.forks().is_none() || !$options.ignore_crashes();
let ooms = $options.forks().is_none() || !$options.ignore_ooms();
let timeouts = $options.forks().is_none() || !$options.ignore_timeouts();

let keep_observer = LibfuzzerKeepFeedback::new();
let keep = keep_observer.keep();

Expand Down Expand Up @@ -176,11 +171,7 @@ macro_rules! fuzz_with {
// This one is composed by two Feedbacks in OR
let mut feedback = feedback_and_fast!(
feedback_not!(
feedback_or_fast!(
OOMFeedback,
CrashFeedback::new(),
TimeoutFeedback::new()
)
CrashFeedback::new()
),
keep_observer,
feedback_or!(
Expand All @@ -192,12 +183,13 @@ macro_rules! fuzz_with {

// A feedback to choose if an input is a solution or not
let mut objective = feedback_or_fast!(
feedback_and_fast!(ConstFeedback::new(ooms), OOMFeedback),
LibfuzzerCrashCauseFeedback::new(),
OOMFeedback,
feedback_and_fast!(
feedback_and_fast!(ConstFeedback::new(crashes), feedback_not!(OOMFeedback), CrashFeedback::new()),
CrashFeedback::new(),
NewHashFeedback::new(&backtrace_observer)
),
feedback_and_fast!(ConstFeedback::new(timeouts), TimeoutFeedback::new())
TimeoutFeedback::new()
);

let corpus_dir = if let Some(main) = $options.dirs().first() {
Expand Down Expand Up @@ -444,7 +436,7 @@ macro_rules! fuzz_with {
grimoire,
);

$operation(&mut fuzzer, &mut stages, &mut executor, &mut state, &mut mgr)
$operation(&$options, &mut fuzzer, &mut stages, &mut executor, &mut state, &mut mgr)
};

$and_then(closure)
Expand Down Expand Up @@ -496,11 +488,6 @@ extern "C" {
fn libafl_targets_libfuzzer_init(argc: *mut c_int, argv: *mut *mut *const c_char) -> i32;
}

unsafe extern "C" fn libafl_libfuzzer_asan_death_callback() {
libafl_cmplog_enabled = 0;
panic!("Received ASAN crash, time to go!");
}

#[allow(non_snake_case)]
#[no_mangle]
pub extern "C" fn LLVMFuzzerRunDriver(
Expand All @@ -512,12 +499,6 @@ pub extern "C" fn LLVMFuzzerRunDriver(
.as_ref()
.expect("Illegal harness provided to libafl.");

unsafe {
libafl_targets::sanitizer_ifaces::__sanitizer_set_death_callback(Some(
libafl_libfuzzer_asan_death_callback,
))
}

unsafe {
// it appears that no one, not even libfuzzer, uses this return value
// https://github.com/llvm/llvm-project/blob/llvmorg-15.0.7/compiler-rt/lib/fuzzer/FuzzerDriver.cpp#L648
Expand Down Expand Up @@ -551,14 +532,14 @@ pub extern "C" fn LLVMFuzzerRunDriver(
LibfuzzerMode::Cmin => unimplemented!(),
LibfuzzerMode::Report => report::report(options, harness),
};
if res.is_err() {
let err = res.unwrap_err();
eprintln!(
"Encountered error while performing libfuzzer shimming: {}",
err
);
1
} else {
0
match res {
Ok(()) | Err(Error::ShuttingDown) => 0,
Err(err) => {
eprintln!(
"Encountered error while performing libfuzzer shimming: {}",
err
);
1
}
}
}
1 change: 1 addition & 0 deletions libafl_libfuzzer/libafl_libfuzzer_runtime/src/report.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,6 +14,7 @@ use libafl::{
use crate::{fuzz_with, options::LibfuzzerOptions};

fn do_report<F, ST, E, S, EM>(
_options: &LibfuzzerOptions,
_fuzzer: &mut F,
_stages: &mut ST,
_executor: &mut E,
Expand Down
2 changes: 1 addition & 1 deletion libafl_targets/Cargo.toml
Original file line number Diff line number Diff line change
Expand Up @@ -39,5 +39,5 @@ log = "0.4.17"
libc = "0.2"

rangemap = "1.0"
serde = { version = "1.0", default-features = false, features = ["alloc"] } # serialization lib
serde = { version = "1.0", default-features = false, features = ["alloc", "derive"] } # serialization lib
# serde-big-array = "0.3.2"
8 changes: 7 additions & 1 deletion libafl_targets/src/libfuzzer/observers/oom.rs
Original file line number Diff line number Diff line change
Expand Up @@ -120,6 +120,12 @@ where
#[derive(Debug, Serialize, Deserialize, Copy, Clone, Default)]
pub struct OOMFeedback;

impl OOMFeedback {
pub fn oomed() -> bool {
OOMED.load(Ordering::Relaxed)
}
}

impl Named for OOMFeedback {
fn name(&self) -> &str {
"oom"
Expand All @@ -142,6 +148,6 @@ where
EM: EventFirer<State = S>,
OT: ObserversTuple<S>,
{
Ok(OOMED.load(Ordering::Relaxed))
Ok(Self::oomed())
}
}

0 comments on commit 566253d

Please sign in to comment.