Fix missing -use_value_profile flag in libafl_libfuzzer (#2363)

* Add -use_value_profile to libafl_libfuzzer

* clippy
This commit is contained in:
Andrea Fioraldi 2024-07-05 14:09:07 +02:00 committed by GitHub
parent d7b5d55408
commit 2356ba5754
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
5 changed files with 83 additions and 32 deletions

1
.gitignore vendored
View File

@ -18,6 +18,7 @@ vendor
*.bin
*.dll
*.exe
*.dylib
*.dSYM
*.obj

View File

@ -33,7 +33,7 @@ crate-type = ["staticlib", "rlib"]
[dependencies]
libafl = { path = "../../libafl", default-features = false, features = ["std", "derive", "llmp_compression", "rand_trait", "regex", "errors_backtrace", "serdeany_autoreg", "tui_monitor", "unicode"] }
libafl_bolts = { path = "../../libafl_bolts", default-features = false, features = ["std", "derive", "llmp_compression", "rand_trait", "serdeany_autoreg", "errors_backtrace"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_8bit", "sancov_cmplog", "sancov_pcguard", "libfuzzer", "libfuzzer_oom", "libfuzzer_define_run_driver", "libfuzzer_interceptors", "sanitizers_flags", "whole_archive", "sanitizer_interfaces"] }
libafl_targets = { path = "../../libafl_targets", features = ["sancov_8bit", "sancov_cmplog", "sancov_value_profile", "sancov_pcguard", "libfuzzer", "libfuzzer_oom", "libfuzzer_define_run_driver", "libfuzzer_interceptors", "sanitizers_flags", "whole_archive", "sanitizer_interfaces"] }
ahash = { version = "0.8.3", default-features = false }
libc = "0.2.1"

View File

@ -17,6 +17,15 @@ if ! cargo +nightly --version >& /dev/null; then
exit 1
fi
cargo +nightly build --profile "$profile"
if [[ "$OSTYPE" == "darwin"* ]]; then
# MacOS and iOS
"${CXX:-clang++}" -dynamiclib -Wl,-force_load target/release/libafl_libfuzzer_runtime.a \
-Wl,-U,_LLVMFuzzerInitialize -Wl,-U,_LLVMFuzzerCustomMutator -Wl,-U,_LLVMFuzzerCustomCrossOver -Wl,-U,_libafl_main \
-o libafl_libfuzzer_runtime.dylib
else
# Linux and *BSD
RUSTC_BIN="$(cargo +nightly rustc -Zunstable-options --print target-libdir)/../bin"
RUST_LLD="${RUSTC_BIN}/rust-lld"
RUST_AR="${RUSTC_BIN}/llvm-ar"
@ -26,8 +35,6 @@ if ! [ -f "${RUST_LLD}" ] && [ -f "${RUST_AR}" ]; then
exit 1
fi
cargo +nightly build --profile "$profile"
tmpdir=""
cleanup() {
@ -42,3 +49,5 @@ tmpdir="$(mktemp -d)"
echo "Done! Wrote the runtime to \`${SCRIPT_DIR}/libFuzzer.a'"
cleanup
fi

View File

@ -139,7 +139,7 @@ impl CustomMutationStatus {
}
macro_rules! fuzz_with {
($options:ident, $harness:ident, $operation:expr, $and_then:expr, $edge_maker:expr) => {{
($options:ident, $harness:ident, $operation:expr, $and_then:expr, $edge_maker:expr, $extra_feedback:expr, $extra_obsv:expr) => {{
use libafl_bolts::{
rands::StdRand,
tuples::{Merge, tuple_list},
@ -169,7 +169,7 @@ macro_rules! fuzz_with {
state::{HasCorpus, StdState},
StdFuzzer,
};
use libafl_targets::{CmpLogObserver, LLVMCustomMutator, OomFeedback, OomObserver};
use libafl_targets::{CmpLogObserver, LLVMCustomMutator, OomFeedback, OomObserver, CMP_MAP};
use rand::{thread_rng, RngCore};
use std::{env::temp_dir, fs::create_dir, path::PathBuf};
@ -203,6 +203,9 @@ macro_rules! fuzz_with {
// Create the Cmp observer
let cmplog_observer = CmpLogObserver::new("cmplog", true);
// Create an observer using the cmp map for value profile
let value_profile_observer = unsafe { StdMapObserver::from_mut_ptr("cmps", CMP_MAP.as_mut_ptr(), CMP_MAP.len()) };
// Create a stacktrace observer
let backtrace_observer = BacktraceObserver::owned(
"BacktraceObserver",
@ -213,14 +216,27 @@ macro_rules! fuzz_with {
let map_feedback = MaxMapFeedback::new(&edges_observer);
let shrinking_map_feedback = ShrinkMapFeedback::new(&size_edges_observer);
// Value profile maximization feedback
let value_profile_feedback = MaxMapFeedback::new(&value_profile_observer);
// Set up a generalization stage for grimoire
let generalization = GeneralizationStage::new(&edges_observer);
let generalization = IfStage::new(|_, _, _, _| Ok(grimoire.into()), tuple_list!(generalization));
let calibration = CalibrationStage::new(&map_feedback);
let add_extra_feedback = $extra_feedback;
let coverage_feedback = add_extra_feedback(
feedback_or!(
map_feedback,
feedback_and_fast!(ConstFeedback::new($options.shrink()), shrinking_map_feedback),
// Time feedback, this one does not need a feedback state
TimeFeedback::new(&time_observer)
),
value_profile_feedback
);
// Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
let mut feedback = feedback_and_fast!(
feedback_not!(
feedback_or_fast!(
@ -230,12 +246,7 @@ macro_rules! fuzz_with {
)
),
keep_observer,
feedback_or!(
map_feedback,
feedback_and_fast!(ConstFeedback::new($options.shrink()), shrinking_map_feedback),
// Time feedback, this one does not need a feedback state
TimeFeedback::new(&time_observer)
)
coverage_feedback
);
// A feedback to choose if an input is a solution or not
@ -424,10 +435,16 @@ macro_rules! fuzz_with {
let mut tracing_harness = harness;
let add_extra_observer = $extra_obsv;
let observers = add_extra_observer(
tuple_list!(edges_observer, size_edges_observer, time_observer, backtrace_observer, oom_observer),
value_profile_observer
);
// Create the executor for an in-process function with one observer for edge coverage and one for the execution time
let mut executor = InProcessExecutor::with_timeout(
&mut harness,
tuple_list!(edges_observer, size_edges_observer, time_observer, backtrace_observer, oom_observer),
observers,
&mut fuzzer,
&mut state,
&mut mgr,
@ -466,7 +483,6 @@ macro_rules! fuzz_with {
}
}
// Setup a tracing stage in which we log comparisons
let tracing = IfStage::new(|_, _, _, _| Ok(!$options.skip_tracing()), (TracingStage::new(InProcessExecutor::new(
&mut tracing_harness,
@ -500,6 +516,21 @@ macro_rules! fuzz_with {
$and_then(closure)
}};
($options:ident, $harness:ident, $operation:expr, $and_then:expr, $edge_maker:expr) => {{
if $options.use_value_profile() {
fuzz_with!($options, $harness, $operation, $and_then, $edge_maker,
|feedback, value_profile_feedback| {
feedback_or!(feedback, value_profile_feedback)
},
|observers, value_profile_observer| {
(value_profile_observer, observers) // Prepend the value profile observer in the tuple list
}
)
} else {
fuzz_with!($options, $harness, $operation, $and_then, $edge_maker, |feedback, _| feedback, |observers, _| observers)
}
}};
($options:ident, $harness:ident, $operation:expr, $and_then:expr) => {{
use libafl::observers::{
HitcountsIterableMapObserver, HitcountsMapObserver, MultiMapObserver, StdMapObserver,

View File

@ -107,6 +107,7 @@ pub struct LibfuzzerOptions {
artifact_prefix: ArtifactPrefix,
timeout: Duration,
grimoire: Option<bool>,
use_value_profile: bool,
unicode: bool,
forks: Option<usize>,
dict: Option<Tokens>,
@ -163,6 +164,10 @@ impl LibfuzzerOptions {
self.grimoire
}
pub fn use_value_profile(&self) -> bool {
self.use_value_profile
}
pub fn unicode(&self) -> bool {
self.unicode
}
@ -235,6 +240,7 @@ struct LibfuzzerOptionsBuilder<'a> {
artifact_prefix: Option<&'a str>,
timeout: Option<Duration>,
grimoire: Option<bool>,
use_value_profile: Option<bool>,
unicode: Option<bool>,
forks: Option<usize>,
dict: Option<&'a str>,
@ -298,6 +304,9 @@ impl<'a> LibfuzzerOptionsBuilder<'a> {
}
}
"grimoire" => self.grimoire = Some(parse_or_bail!(name, value, u64) > 0),
"use_value_profile" => {
self.use_value_profile = Some(parse_or_bail!(name, value, u64) > 0);
}
"unicode" => self.unicode = Some(parse_or_bail!(name, value, u64) > 0),
"artifact_prefix" => {
self.artifact_prefix = Some(value);
@ -371,6 +380,7 @@ impl<'a> LibfuzzerOptionsBuilder<'a> {
.unwrap_or_default(),
timeout: self.timeout.unwrap_or(Duration::from_secs(1200)),
grimoire: self.grimoire,
use_value_profile: self.use_value_profile.unwrap_or(false),
unicode: self.unicode.unwrap_or(true),
forks: self.forks,
dict: self.dict.map(|path| {