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 *.bin
*.dll *.dll
*.exe *.exe
*.dylib
*.dSYM *.dSYM
*.obj *.obj

View File

@ -33,7 +33,7 @@ crate-type = ["staticlib", "rlib"]
[dependencies] [dependencies]
libafl = { path = "../../libafl", default-features = false, features = ["std", "derive", "llmp_compression", "rand_trait", "regex", "errors_backtrace", "serdeany_autoreg", "tui_monitor", "unicode"] } 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_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 } ahash = { version = "0.8.3", default-features = false }
libc = "0.2.1" libc = "0.2.1"

View File

@ -17,28 +17,37 @@ if ! cargo +nightly --version >& /dev/null; then
exit 1 exit 1
fi fi
RUSTC_BIN="$(cargo +nightly rustc -Zunstable-options --print target-libdir)/../bin"
RUST_LLD="${RUSTC_BIN}/rust-lld"
RUST_AR="${RUSTC_BIN}/llvm-ar"
if ! [ -f "${RUST_LLD}" ] && [ -f "${RUST_AR}" ]; then
echo -e "You must install the llvm-tools component: \`rustup component add llvm-tools'"
exit 1
fi
cargo +nightly build --profile "$profile" cargo +nightly build --profile "$profile"
tmpdir="" 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"
cleanup() { if ! [ -f "${RUST_LLD}" ] && [ -f "${RUST_AR}" ]; then
echo -e "You must install the llvm-tools component: \`rustup component add llvm-tools'"
exit 1
fi
tmpdir=""
cleanup() {
rm -rf "${tmpdir}" rm -rf "${tmpdir}"
exit exit
} }
trap cleanup INT TERM trap cleanup INT TERM
tmpdir="$(mktemp -d)" tmpdir="$(mktemp -d)"
"${RUST_LLD}" -flavor gnu -r --whole-archive target/release/libafl_libfuzzer_runtime.a -o "${tmpdir}/libFuzzer.o" "${RUST_LLD}" -flavor gnu -r --whole-archive target/release/libafl_libfuzzer_runtime.a -o "${tmpdir}/libFuzzer.o"
"${RUST_AR}" cr libFuzzer.a "${tmpdir}/libFuzzer.o" "${RUST_AR}" cr libFuzzer.a "${tmpdir}/libFuzzer.o"
echo "Done! Wrote the runtime to \`${SCRIPT_DIR}/libFuzzer.a'"
cleanup
fi
echo "Done! Wrote the runtime to \`${SCRIPT_DIR}/libFuzzer.a'"
cleanup

View File

@ -139,7 +139,7 @@ impl CustomMutationStatus {
} }
macro_rules! fuzz_with { 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::{ use libafl_bolts::{
rands::StdRand, rands::StdRand,
tuples::{Merge, tuple_list}, tuples::{Merge, tuple_list},
@ -169,7 +169,7 @@ macro_rules! fuzz_with {
state::{HasCorpus, StdState}, state::{HasCorpus, StdState},
StdFuzzer, StdFuzzer,
}; };
use libafl_targets::{CmpLogObserver, LLVMCustomMutator, OomFeedback, OomObserver}; use libafl_targets::{CmpLogObserver, LLVMCustomMutator, OomFeedback, OomObserver, CMP_MAP};
use rand::{thread_rng, RngCore}; use rand::{thread_rng, RngCore};
use std::{env::temp_dir, fs::create_dir, path::PathBuf}; use std::{env::temp_dir, fs::create_dir, path::PathBuf};
@ -203,6 +203,9 @@ macro_rules! fuzz_with {
// Create the Cmp observer // Create the Cmp observer
let cmplog_observer = CmpLogObserver::new("cmplog", true); 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 // Create a stacktrace observer
let backtrace_observer = BacktraceObserver::owned( let backtrace_observer = BacktraceObserver::owned(
"BacktraceObserver", "BacktraceObserver",
@ -213,14 +216,27 @@ macro_rules! fuzz_with {
let map_feedback = MaxMapFeedback::new(&edges_observer); let map_feedback = MaxMapFeedback::new(&edges_observer);
let shrinking_map_feedback = ShrinkMapFeedback::new(&size_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 // Set up a generalization stage for grimoire
let generalization = GeneralizationStage::new(&edges_observer); let generalization = GeneralizationStage::new(&edges_observer);
let generalization = IfStage::new(|_, _, _, _| Ok(grimoire.into()), tuple_list!(generalization)); let generalization = IfStage::new(|_, _, _, _| Ok(grimoire.into()), tuple_list!(generalization));
let calibration = CalibrationStage::new(&map_feedback); 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 // Feedback to rate the interestingness of an input
// This one is composed by two Feedbacks in OR
let mut feedback = feedback_and_fast!( let mut feedback = feedback_and_fast!(
feedback_not!( feedback_not!(
feedback_or_fast!( feedback_or_fast!(
@ -230,12 +246,7 @@ macro_rules! fuzz_with {
) )
), ),
keep_observer, keep_observer,
feedback_or!( coverage_feedback
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)
)
); );
// A feedback to choose if an input is a solution or not // 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 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 // 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( let mut executor = InProcessExecutor::with_timeout(
&mut harness, &mut harness,
tuple_list!(edges_observer, size_edges_observer, time_observer, backtrace_observer, oom_observer), observers,
&mut fuzzer, &mut fuzzer,
&mut state, &mut state,
&mut mgr, &mut mgr,
@ -466,7 +483,6 @@ macro_rules! fuzz_with {
} }
} }
// Setup a tracing stage in which we log comparisons // Setup a tracing stage in which we log comparisons
let tracing = IfStage::new(|_, _, _, _| Ok(!$options.skip_tracing()), (TracingStage::new(InProcessExecutor::new( let tracing = IfStage::new(|_, _, _, _| Ok(!$options.skip_tracing()), (TracingStage::new(InProcessExecutor::new(
&mut tracing_harness, &mut tracing_harness,
@ -500,6 +516,21 @@ macro_rules! fuzz_with {
$and_then(closure) $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) => {{ ($options:ident, $harness:ident, $operation:expr, $and_then:expr) => {{
use libafl::observers::{ use libafl::observers::{
HitcountsIterableMapObserver, HitcountsMapObserver, MultiMapObserver, StdMapObserver, HitcountsIterableMapObserver, HitcountsMapObserver, MultiMapObserver, StdMapObserver,

View File

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